sidebar.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. Sidebar = null;
  2. var defaultView = 'home';
  3. var viewTitles = {
  4. filter: 'filter-cards',
  5. multiselection: 'multi-selection'
  6. };
  7. BlazeComponent.extendComponent({
  8. template: function() {
  9. return 'sidebar';
  10. },
  11. mixins: function() {
  12. return [Mixins.InfiniteScrolling, Mixins.PerfectScrollbar];
  13. },
  14. onCreated: function() {
  15. this._isOpen = new ReactiveVar(! Session.get('currentCard'));
  16. this._view = new ReactiveVar(defaultView);
  17. Sidebar = this;
  18. },
  19. onDestroyed: function() {
  20. Sidebar = null;
  21. },
  22. isOpen: function() {
  23. return this._isOpen.get();
  24. },
  25. open: function() {
  26. if (! this._isOpen.get()) {
  27. this._isOpen.set(true);
  28. }
  29. },
  30. hide: function() {
  31. if (this._isOpen.get()) {
  32. this._isOpen.set(false);
  33. }
  34. },
  35. toogle: function() {
  36. this._isOpen.set(! this._isOpen.get());
  37. },
  38. calculateNextPeak: function() {
  39. var altitude = this.find('.js-board-sidebar-content').scrollHeight;
  40. this.callFirstWith(this, 'setNextPeak', altitude);
  41. },
  42. reachNextPeak: function() {
  43. var activitiesComponent = this.componentChildren('activities')[0];
  44. activitiesComponent.loadNextPage();
  45. },
  46. isTongueHidden: function() {
  47. return this.isOpen() && this.getView() !== defaultView;
  48. },
  49. getView: function() {
  50. return this._view.get();
  51. },
  52. setView: function(view) {
  53. view = _.isString(view) ? view : defaultView;
  54. this._view.set(view);
  55. this.open();
  56. },
  57. isDefaultView: function() {
  58. return this.getView() === defaultView;
  59. },
  60. getViewTemplate: function() {
  61. return this.getView() + 'Sidebar';
  62. },
  63. getViewTitle: function() {
  64. return TAPi18n.__(viewTitles[this.getView()]);
  65. },
  66. // Board members can assign people or labels by drag-dropping elements from
  67. // the sidebar to the cards on the board. In order to re-initialize the
  68. // jquery-ui plugin any time a draggable member or label is modified or
  69. // removed we use a autorun function and register a dependency on the both
  70. // members and labels fields of the current board document.
  71. onRendered: function() {
  72. var self = this;
  73. if (! Meteor.userId() || ! Meteor.user().isBoardMember())
  74. return;
  75. self.autorun(function() {
  76. var currentBoardId = Tracker.nonreactive(function() {
  77. return Session.get('currentBoard');
  78. });
  79. Boards.findOne(currentBoardId, {
  80. fields: {
  81. members: 1,
  82. labels: 1
  83. }
  84. });
  85. Tracker.afterFlush(function() {
  86. self.$('.js-member,.js-label').draggable({
  87. appendTo: 'body',
  88. helper: 'clone',
  89. revert: 'invalid',
  90. revertDuration: 150,
  91. snap: false,
  92. snapMode: 'both',
  93. start: function() {
  94. EscapeActions.executeLowerThan('popup');
  95. }
  96. });
  97. });
  98. });
  99. },
  100. events: function() {
  101. // XXX Hacky, we need some kind of `super`
  102. var mixinEvents = this.getMixin(Mixins.InfiniteScrolling).events();
  103. return mixinEvents.concat([{
  104. 'click .js-toogle-sidebar': this.toogle,
  105. 'click .js-back-home': this.setView
  106. }]);
  107. }
  108. }).register('sidebar');
  109. EscapeActions.register('sidebarView',
  110. function() { Sidebar.setView(defaultView); },
  111. function() { return Sidebar && Sidebar.getView() !== defaultView; }
  112. );
  113. var getMemberIndex = function(board, searchId) {
  114. for (var i = 0; i < board.members.length; i++) {
  115. if (board.members[i].userId === searchId)
  116. return i;
  117. }
  118. throw new Meteor.Error('Member not found');
  119. };
  120. Template.memberPopup.helpers({
  121. user: function() {
  122. return Users.findOne(this.userId);
  123. },
  124. memberType: function() {
  125. var type = Users.findOne(this.userId).isBoardAdmin() ? 'admin' : 'normal';
  126. return TAPi18n.__(type).toLowerCase();
  127. }
  128. });
  129. Template.memberPopup.events({
  130. 'click .js-filter-member': function() {
  131. Filter.members.toogle(this.userId);
  132. Popup.close();
  133. },
  134. 'click .js-change-role': Popup.open('changePermissions'),
  135. 'click .js-remove-member': Popup.afterConfirm('removeMember', function() {
  136. var currentBoard = Boards.findOne(Session.get('currentBoard'));
  137. var memberIndex = getMemberIndex(currentBoard, this.userId);
  138. var setQuery = {};
  139. setQuery[['members', memberIndex, 'isActive'].join('.')] = false;
  140. Boards.update(currentBoard._id, { $set: setQuery });
  141. Popup.close();
  142. }),
  143. 'click .js-leave-member': function() {
  144. // XXX Not implemented
  145. Popup.close();
  146. }
  147. });
  148. Template.membersWidget.events({
  149. 'click .js-member': Popup.open('member'),
  150. 'click .js-manage-board-members': Popup.open('addMember')
  151. });
  152. Template.labelsWidget.events({
  153. 'click .js-label': Popup.open('editLabel'),
  154. 'click .js-add-label': Popup.open('createLabel')
  155. });
  156. Template.addMemberPopup.helpers({
  157. isBoardMember: function() {
  158. var user = Users.findOne(this._id);
  159. return user && user.isBoardMember();
  160. }
  161. });
  162. Template.addMemberPopup.events({
  163. 'click .pop-over-member-list li:not(.disabled)': function() {
  164. var userId = this._id;
  165. var currentBoard = Boards.findOne(Session.get('currentBoard'));
  166. var currentMembersIds = _.pluck(currentBoard.members, 'userId');
  167. if (currentMembersIds.indexOf(userId) === -1) {
  168. Boards.update(currentBoard._id, {
  169. $push: {
  170. members: {
  171. userId: userId,
  172. isAdmin: false,
  173. isActive: true
  174. }
  175. }
  176. });
  177. } else {
  178. var memberIndex = getMemberIndex(currentBoard, userId);
  179. var setQuery = {};
  180. setQuery[['members', memberIndex, 'isActive'].join('.')] = true;
  181. Boards.update(currentBoard._id, { $set: setQuery });
  182. }
  183. Popup.close();
  184. }
  185. });
  186. Template.addMemberPopup.onRendered(function() {
  187. this.find('.js-search-member input').focus();
  188. });
  189. Template.changePermissionsPopup.events({
  190. 'click .js-set-admin, click .js-set-normal': function(event) {
  191. var currentBoard = Boards.findOne(Session.get('currentBoard'));
  192. var memberIndex = getMemberIndex(currentBoard, this.user._id);
  193. var isAdmin = $(event.currentTarget).hasClass('js-set-admin');
  194. var setQuery = {};
  195. setQuery[['members', memberIndex, 'isAdmin'].join('.')] = isAdmin;
  196. Boards.update(currentBoard._id, {
  197. $set: setQuery
  198. });
  199. Popup.back(1);
  200. }
  201. });
  202. Template.changePermissionsPopup.helpers({
  203. isAdmin: function() {
  204. return this.user.isBoardAdmin();
  205. },
  206. isLastAdmin: function() {
  207. if (! this.user.isBoardAdmin())
  208. return false;
  209. var currentBoard = Boards.findOne(Session.get('currentBoard'));
  210. var nbAdmins = _.where(currentBoard.members, { isAdmin: true }).length;
  211. return nbAdmins === 1;
  212. }
  213. });