checklists.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. function initSorting(items) {
  2. items.sortable({
  3. tolerance: 'pointer',
  4. helper: 'clone',
  5. items: '.js-checklist-item:not(.placeholder)',
  6. axis: 'y',
  7. distance: 7,
  8. placeholder: 'placeholder',
  9. scroll: false,
  10. start(evt, ui) {
  11. ui.placeholder.height(ui.helper.height());
  12. EscapeActions.executeUpTo('popup-close');
  13. },
  14. stop(evt, ui) {
  15. const parent = ui.item.parents('.js-checklist-items');
  16. const orderedItems = [];
  17. parent.find('.js-checklist-item').each(function(i, item) {
  18. const checklistItem = Blaze.getData(item).item;
  19. orderedItems.push(checklistItem._id);
  20. });
  21. items.sortable('cancel');
  22. const formerParent = ui.item.parents('.js-checklist-items');
  23. const checklist = Blaze.getData(parent.get(0)).checklist;
  24. const oldChecklist = Blaze.getData(formerParent.get(0)).checklist;
  25. if (oldChecklist._id !== checklist._id) {
  26. const currentItem = Blaze.getData(ui.item.get(0)).item;
  27. for (let i = 0; i < orderedItems.length; i++) {
  28. const itemId = orderedItems[i];
  29. if (itemId !== currentItem._id) continue;
  30. const newItem = {
  31. _id: checklist.getNewItemId(),
  32. title: currentItem.title,
  33. sort: i,
  34. isFinished: currentItem.isFinished,
  35. };
  36. checklist.addFullItem(newItem);
  37. orderedItems[i] = currentItem._id;
  38. oldChecklist.removeItem(itemId);
  39. }
  40. } else {
  41. checklist.sortItems(orderedItems);
  42. }
  43. },
  44. });
  45. }
  46. Template.checklists.onRendered(function () {
  47. const self = BlazeComponent.getComponentForElement(this.firstNode);
  48. self.itemsDom = this.$('.card-checklist-items');
  49. initSorting(self.itemsDom);
  50. self.itemsDom.mousedown(function(evt) {
  51. evt.stopPropagation();
  52. });
  53. function userIsMember() {
  54. return Meteor.user() && Meteor.user().isBoardMember();
  55. }
  56. // Disable sorting if the current user is not a board member
  57. self.autorun(() => {
  58. const $itemsDom = $(self.itemsDom);
  59. if ($itemsDom.data('sortable')) {
  60. $(self.itemsDom).sortable('option', 'disabled', !userIsMember());
  61. }
  62. });
  63. });
  64. BlazeComponent.extendComponent({
  65. addChecklist(event) {
  66. event.preventDefault();
  67. const textarea = this.find('textarea.js-add-checklist-item');
  68. const title = textarea.value.trim();
  69. const cardId = this.currentData().cardId;
  70. const card = Cards.findOne(cardId);
  71. if (title) {
  72. Checklists.insert({
  73. cardId,
  74. title,
  75. sort: card.checklists().count(),
  76. });
  77. setTimeout(() => {
  78. this.$('.add-checklist-item').last().click();
  79. }, 100);
  80. }
  81. textarea.value = '';
  82. textarea.focus();
  83. },
  84. addChecklistItem(event) {
  85. event.preventDefault();
  86. const textarea = this.find('textarea.js-add-checklist-item');
  87. const title = textarea.value.trim();
  88. const checklist = this.currentData().checklist;
  89. if (title) {
  90. checklist.addItem(title);
  91. }
  92. // We keep the form opened, empty it.
  93. textarea.value = '';
  94. textarea.focus();
  95. },
  96. editChecklist(event) {
  97. event.preventDefault();
  98. const textarea = this.find('textarea.js-edit-checklist-item');
  99. const title = textarea.value.trim();
  100. const checklist = this.currentData().checklist;
  101. checklist.setTitle(title);
  102. },
  103. canModifyCard() {
  104. return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
  105. },
  106. editChecklistItem(event) {
  107. event.preventDefault();
  108. const textarea = this.find('textarea.js-edit-checklist-item');
  109. const title = textarea.value.trim();
  110. const itemId = this.currentData().item._id;
  111. const checklist = this.currentData().checklist;
  112. checklist.editItem(itemId, title);
  113. },
  114. deleteItem() {
  115. const checklist = this.currentData().checklist;
  116. const item = this.currentData().item;
  117. if (checklist && item && item._id) {
  118. checklist.removeItem(item._id);
  119. }
  120. },
  121. deleteChecklist() {
  122. const checklist = this.currentData().checklist;
  123. if (checklist && checklist._id) {
  124. Checklists.remove(checklist._id);
  125. }
  126. },
  127. pressKey(event) {
  128. //If user press enter key inside a form, submit it, so user doesn't have to leave keyboard to submit a form.
  129. if (event.keyCode === 13) {
  130. event.preventDefault();
  131. const $form = $(event.currentTarget).closest('form');
  132. $form.find('button[type=submit]').click();
  133. }
  134. },
  135. events() {
  136. return [{
  137. 'submit .js-add-checklist': this.addChecklist,
  138. 'submit .js-edit-checklist-title': this.editChecklist,
  139. 'submit .js-add-checklist-item': this.addChecklistItem,
  140. 'submit .js-edit-checklist-item': this.editChecklistItem,
  141. 'click .js-delete-checklist-item': this.deleteItem,
  142. 'click .js-delete-checklist': this.deleteChecklist,
  143. keydown: this.pressKey,
  144. }];
  145. },
  146. }).register('checklists');
  147. Template.itemDetail.helpers({
  148. canModifyCard() {
  149. return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
  150. },
  151. });
  152. BlazeComponent.extendComponent({
  153. toggleItem() {
  154. const checklist = this.currentData().checklist;
  155. const item = this.currentData().item;
  156. if (checklist && item && item._id) {
  157. checklist.toggleItem(item._id);
  158. }
  159. },
  160. events() {
  161. return [{
  162. 'click .item .check-box': this.toggleItem,
  163. }];
  164. },
  165. }).register('itemDetail');