swimlaneHeader.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import { ReactiveCache } from '/imports/reactiveCache';
  2. const { calculateIndexData } = Utils;
  3. let swimlaneColors;
  4. Meteor.startup(() => {
  5. swimlaneColors = Swimlanes.simpleSchema()._schema.color.allowedValues;
  6. });
  7. BlazeComponent.extendComponent({
  8. editTitle(event) {
  9. event.preventDefault();
  10. const newTitle = this.childComponents('inlinedForm')[0]
  11. .getValue()
  12. .trim();
  13. const swimlane = this.currentData();
  14. if (newTitle) {
  15. swimlane.rename(newTitle.trim());
  16. }
  17. },
  18. events() {
  19. return [
  20. {
  21. 'click .js-open-swimlane-menu': Popup.open('swimlaneAction'),
  22. 'click .js-open-add-swimlane-menu': Popup.open('swimlaneAdd'),
  23. submit: this.editTitle,
  24. },
  25. ];
  26. },
  27. }).register('swimlaneHeader');
  28. Template.swimlaneFixedHeader.helpers({
  29. isBoardAdmin() {
  30. return ReactiveCache.getCurrentUser().isBoardAdmin();
  31. },
  32. });
  33. Template.swimlaneActionPopup.events({
  34. 'click .js-set-swimlane-color': Popup.open('setSwimlaneColor'),
  35. 'click .js-set-swimlane-height': Popup.open('setSwimlaneHeight'),
  36. 'click .js-close-swimlane'(event) {
  37. event.preventDefault();
  38. this.archive();
  39. Popup.back();
  40. },
  41. 'click .js-move-swimlane': Popup.open('moveSwimlane'),
  42. 'click .js-copy-swimlane': Popup.open('copySwimlane'),
  43. });
  44. Template.swimlaneActionPopup.events({
  45. isCommentOnly() {
  46. return ReactiveCache.getCurrentUser().isCommentOnly();
  47. },
  48. });
  49. BlazeComponent.extendComponent({
  50. onCreated() {
  51. this.currentSwimlane = this.currentData();
  52. },
  53. events() {
  54. return [
  55. {
  56. submit(event) {
  57. event.preventDefault();
  58. const currentBoard = Utils.getCurrentBoard();
  59. const nextSwimlane = currentBoard.nextSwimlane(this.currentSwimlane);
  60. const titleInput = this.find('.swimlane-name-input');
  61. const title = titleInput.value.trim();
  62. const sortValue = calculateIndexData(
  63. this.currentSwimlane,
  64. nextSwimlane,
  65. 1,
  66. );
  67. const swimlaneType = currentBoard.isTemplatesBoard()
  68. ? 'template-swimlane'
  69. : 'swimlane';
  70. if (title) {
  71. Swimlanes.insert({
  72. title,
  73. boardId: Session.get('currentBoard'),
  74. sort: sortValue.base,
  75. type: swimlaneType,
  76. });
  77. titleInput.value = '';
  78. titleInput.focus();
  79. }
  80. // XXX ideally, we should move the popup to the newly
  81. // created swimlane so a user can add more than one swimlane
  82. // with a minimum of interactions
  83. Popup.back();
  84. },
  85. 'click .js-swimlane-template': Popup.open('searchElement'),
  86. },
  87. ];
  88. },
  89. }).register('swimlaneAddPopup');
  90. BlazeComponent.extendComponent({
  91. onCreated() {
  92. this.currentSwimlane = this.currentData();
  93. this.currentColor = new ReactiveVar(this.currentSwimlane.color);
  94. },
  95. colors() {
  96. return swimlaneColors.map(color => ({ color, name: '' }));
  97. },
  98. isSelected(color) {
  99. return this.currentColor.get() === color;
  100. },
  101. events() {
  102. return [
  103. {
  104. 'click .js-palette-color'() {
  105. this.currentColor.set(this.currentData().color);
  106. },
  107. 'click .js-submit'() {
  108. this.currentSwimlane.setColor(this.currentColor.get());
  109. Popup.back();
  110. },
  111. 'click .js-remove-color'() {
  112. this.currentSwimlane.setColor(null);
  113. Popup.back();
  114. },
  115. },
  116. ];
  117. },
  118. }).register('setSwimlaneColorPopup');
  119. BlazeComponent.extendComponent({
  120. onCreated() {
  121. this.currentSwimlane = this.currentData();
  122. },
  123. applySwimlaneHeight() {
  124. const swimlane = this.currentData();
  125. const board = swimlane.boardId;
  126. const height = parseInt(
  127. Template.instance()
  128. .$('.swimlane-height-value')
  129. .val(),
  130. 10,
  131. );
  132. // FIXME(mark-i-m): where do we put constants?
  133. // also in imports/i18n/data/en.i18n.json
  134. if (height != -1 && (height < 100 || !height)) {
  135. Template.instance()
  136. .$('.swimlane-height-error')
  137. .click();
  138. } else {
  139. Meteor.call('applySwimlaneHeight', board, swimlane._id, height);
  140. Popup.back();
  141. }
  142. },
  143. swimlaneHeightValue() {
  144. const swimlane = this.currentData();
  145. const board = swimlane.boardId;
  146. return Meteor.user().getSwimlaneHeight(board, swimlane._id);
  147. },
  148. events() {
  149. return [
  150. {
  151. 'click .swimlane-height-apply': this.applySwimlaneHeight,
  152. 'click .swimlane-height-error': Popup.open('swimlaneHeightError'),
  153. },
  154. ];
  155. },
  156. }).register('setSwimlaneHeightPopup');