swimlaneHeader.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. import { TAPi18n } from '/imports/i18n';
  2. import { ReactiveCache } from '/imports/reactiveCache';
  3. const { calculateIndexData } = Utils;
  4. let swimlaneColors;
  5. Meteor.startup(() => {
  6. swimlaneColors = Swimlanes.simpleSchema()._schema.color.allowedValues;
  7. });
  8. BlazeComponent.extendComponent({
  9. editTitle(event) {
  10. event.preventDefault();
  11. const newTitle = this.childComponents('inlinedForm')[0]
  12. .getValue()
  13. .trim();
  14. const swimlane = this.currentData();
  15. if (newTitle) {
  16. swimlane.rename(newTitle.trim());
  17. }
  18. },
  19. events() {
  20. return [
  21. {
  22. 'click .js-open-swimlane-menu': Popup.open('swimlaneAction'),
  23. 'click .js-open-add-swimlane-menu': Popup.open('swimlaneAdd'),
  24. submit: this.editTitle,
  25. },
  26. ];
  27. },
  28. }).register('swimlaneHeader');
  29. Template.swimlaneFixedHeader.helpers({
  30. isBoardAdmin() {
  31. return ReactiveCache.getCurrentUser().isBoardAdmin();
  32. },
  33. isTitleDefault(title) {
  34. // https://github.com/wekan/wekan/issues/4763
  35. // https://github.com/wekan/wekan/issues/4742
  36. // Translation text for "default" does not work, it returns an object.
  37. // When that happens, try use translation "defaultdefault" that has same content of default, or return text "Default".
  38. // This can happen, if swimlane does not have name.
  39. // Yes, this is fixing the symptom (Swimlane title does not have title)
  40. // instead of fixing the problem (Add Swimlane title when creating swimlane)
  41. // because there could be thousands of swimlanes, adding name Default to all of them
  42. // would be very slow.
  43. if (title.startsWith("key 'default") && title.endsWith('returned an object instead of string.')) {
  44. if (`${TAPi18n.__('defaultdefault')}`.startsWith("key 'default") && `${TAPi18n.__('defaultdefault')}`.endsWith('returned an object instead of string.')) {
  45. return 'Default';
  46. } else {
  47. return `${TAPi18n.__('defaultdefault')}`;
  48. }
  49. } else if (title === 'Default') {
  50. return `${TAPi18n.__('defaultdefault')}`;
  51. } else {
  52. return title;
  53. }
  54. },
  55. });
  56. Template.editSwimlaneTitleForm.helpers({
  57. isTitleDefault(title) {
  58. // https://github.com/wekan/wekan/issues/4763
  59. // https://github.com/wekan/wekan/issues/4742
  60. // Translation text for "default" does not work, it returns an object.
  61. // When that happens, try use translation "defaultdefault" that has same content of default, or return text "Default".
  62. // This can happen, if swimlane does not have name.
  63. // Yes, this is fixing the symptom (Swimlane title does not have title)
  64. // instead of fixing the problem (Add Swimlane title when creating swimlane)
  65. // because there could be thousands of swimlanes, adding name Default to all of them
  66. // would be very slow.
  67. if (title.startsWith("key 'default") && title.endsWith('returned an object instead of string.')) {
  68. if (`${TAPi18n.__('defaultdefault')}`.startsWith("key 'default") && `${TAPi18n.__('defaultdefault')}`.endsWith('returned an object instead of string.')) {
  69. return 'Default';
  70. } else {
  71. return `${TAPi18n.__('defaultdefault')}`;
  72. }
  73. } else if (title === 'Default') {
  74. return `${TAPi18n.__('defaultdefault')}`;
  75. } else {
  76. return title;
  77. }
  78. },
  79. });
  80. Template.swimlaneActionPopup.events({
  81. 'click .js-set-swimlane-color': Popup.open('setSwimlaneColor'),
  82. 'click .js-set-swimlane-height': Popup.open('setSwimlaneHeight'),
  83. 'click .js-close-swimlane'(event) {
  84. event.preventDefault();
  85. this.archive();
  86. Popup.back();
  87. },
  88. 'click .js-move-swimlane': Popup.open('moveSwimlane'),
  89. 'click .js-copy-swimlane': Popup.open('copySwimlane'),
  90. });
  91. Template.swimlaneActionPopup.events({
  92. isCommentOnly() {
  93. return ReactiveCache.getCurrentUser().isCommentOnly();
  94. },
  95. });
  96. BlazeComponent.extendComponent({
  97. onCreated() {
  98. this.currentSwimlane = this.currentData();
  99. },
  100. events() {
  101. return [
  102. {
  103. submit(event) {
  104. event.preventDefault();
  105. const currentBoard = Utils.getCurrentBoard();
  106. const nextSwimlane = currentBoard.nextSwimlane(this.currentSwimlane);
  107. const titleInput = this.find('.swimlane-name-input');
  108. const title = titleInput.value.trim();
  109. const sortValue = calculateIndexData(
  110. this.currentSwimlane,
  111. nextSwimlane,
  112. 1,
  113. );
  114. const swimlaneType = currentBoard.isTemplatesBoard()
  115. ? 'template-swimlane'
  116. : 'swimlane';
  117. if (title) {
  118. Swimlanes.insert({
  119. title,
  120. boardId: Session.get('currentBoard'),
  121. sort: sortValue.base,
  122. type: swimlaneType,
  123. });
  124. titleInput.value = '';
  125. titleInput.focus();
  126. }
  127. // XXX ideally, we should move the popup to the newly
  128. // created swimlane so a user can add more than one swimlane
  129. // with a minimum of interactions
  130. Popup.back();
  131. },
  132. 'click .js-swimlane-template': Popup.open('searchElement'),
  133. },
  134. ];
  135. },
  136. }).register('swimlaneAddPopup');
  137. BlazeComponent.extendComponent({
  138. onCreated() {
  139. this.currentSwimlane = this.currentData();
  140. this.currentColor = new ReactiveVar(this.currentSwimlane.color);
  141. },
  142. colors() {
  143. return swimlaneColors.map(color => ({ color, name: '' }));
  144. },
  145. isSelected(color) {
  146. return this.currentColor.get() === color;
  147. },
  148. events() {
  149. return [
  150. {
  151. 'click .js-palette-color'() {
  152. this.currentColor.set(this.currentData().color);
  153. },
  154. 'click .js-submit'() {
  155. this.currentSwimlane.setColor(this.currentColor.get());
  156. Popup.back();
  157. },
  158. 'click .js-remove-color'() {
  159. this.currentSwimlane.setColor(null);
  160. Popup.back();
  161. },
  162. },
  163. ];
  164. },
  165. }).register('setSwimlaneColorPopup');
  166. BlazeComponent.extendComponent({
  167. onCreated() {
  168. this.currentSwimlane = this.currentData();
  169. },
  170. applySwimlaneHeight() {
  171. const swimlane = this.currentData();
  172. const board = swimlane.boardId;
  173. const height = parseInt(
  174. Template.instance()
  175. .$('.swimlane-height-value')
  176. .val(),
  177. 10,
  178. );
  179. // FIXME(mark-i-m): where do we put constants?
  180. // also in imports/i18n/data/en.i18n.json
  181. if (height != -1 && (height < 100 || !height)) {
  182. Template.instance()
  183. .$('.swimlane-height-error')
  184. .click();
  185. } else {
  186. Meteor.call('applySwimlaneHeight', board, swimlane._id, height);
  187. Popup.back();
  188. }
  189. },
  190. swimlaneHeightValue() {
  191. const swimlane = this.currentData();
  192. const board = swimlane.boardId;
  193. return Meteor.user().getSwimlaneHeight(board, swimlane._id);
  194. },
  195. events() {
  196. return [
  197. {
  198. 'click .swimlane-height-apply': this.applySwimlaneHeight,
  199. 'click .swimlane-height-error': Popup.open('swimlaneHeightError'),
  200. },
  201. ];
  202. },
  203. }).register('setSwimlaneHeightPopup');