123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- const { calculateIndex, enableClickOnTouch } = Utils;
- function currentListIsInThisSwimlane(swimlaneId) {
- const currentList = Lists.findOne(Session.get('currentList'));
- return (
- currentList &&
- (currentList.swimlaneId === swimlaneId || currentList.swimlaneId === '')
- );
- }
- function currentCardIsInThisList(listId, swimlaneId) {
- const currentCard = Cards.findOne(Session.get('currentCard'));
- const currentUser = Meteor.user();
- if (
- currentUser &&
- currentUser.profile &&
- currentUser.profile.boardView === 'board-view-swimlanes'
- )
- return (
- currentCard &&
- currentCard.listId === listId &&
- currentCard.swimlaneId === swimlaneId
- );
- // Default view: board-view-lists
- else return currentCard && currentCard.listId === listId;
- // https://github.com/wekan/wekan/issues/1623
- // https://github.com/ChronikEwok/wekan/commit/cad9b20451bb6149bfb527a99b5001873b06c3de
- // TODO: In public board, if you would like to switch between List/Swimlane view, you could
- // 1) If there is no view cookie, save to cookie board-view-lists
- // board-view-lists / board-view-swimlanes / board-view-cal
- // 2) If public user changes clicks board-view-lists then change view and
- // then change view and save cookie with view value
- // without using currentuser above, because currentuser is null.
- }
- function initSortable(boardComponent, $listsDom) {
- // We want to animate the card details window closing. We rely on CSS
- // transition for the actual animation.
- $listsDom._uihooks = {
- removeElement(node) {
- const removeNode = _.once(() => {
- node.parentNode.removeChild(node);
- });
- if ($(node).hasClass('js-card-details')) {
- $(node).css({
- flexBasis: 0,
- padding: 0,
- });
- $listsDom.one(CSSEvents.transitionend, removeNode);
- } else {
- removeNode();
- }
- },
- };
- $listsDom.sortable({
- tolerance: 'pointer',
- helper: 'clone',
- handle: '.js-list-header',
- items: '.js-list:not(.js-list-composer)',
- placeholder: 'list placeholder',
- distance: 7,
- start(evt, ui) {
- ui.placeholder.height(ui.helper.height());
- EscapeActions.executeUpTo('popup-close');
- boardComponent.setIsDragging(true);
- },
- stop(evt, ui) {
- // To attribute the new index number, we need to get the DOM element
- // of the previous and the following card -- if any.
- const prevListDom = ui.item.prev('.js-list').get(0);
- const nextListDom = ui.item.next('.js-list').get(0);
- const sortIndex = calculateIndex(prevListDom, nextListDom, 1);
- $listsDom.sortable('cancel');
- const listDomElement = ui.item.get(0);
- const list = Blaze.getData(listDomElement);
- Lists.update(list._id, {
- $set: {
- sort: sortIndex.base,
- },
- });
- boardComponent.setIsDragging(false);
- },
- });
- // ugly touch event hotfix
- enableClickOnTouch('.js-list:not(.js-list-composer)');
- function userIsMember() {
- return (
- Meteor.user() &&
- Meteor.user().isBoardMember() &&
- !Meteor.user().isCommentOnly()
- );
- }
- // Disable drag-dropping while in multi-selection mode, or if the current user
- // is not a board member
- boardComponent.autorun(() => {
- const $listDom = $listsDom;
- if ($listDom.data('sortable')) {
- $listsDom.sortable(
- 'option',
- 'disabled',
- MultiSelection.isActive() || !userIsMember(),
- );
- }
- });
- }
- BlazeComponent.extendComponent({
- onRendered() {
- const boardComponent = this.parentComponent();
- const $listsDom = this.$('.js-lists');
- if (!Session.get('currentCard')) {
- boardComponent.scrollLeft();
- }
- initSortable(boardComponent, $listsDom);
- },
- onCreated() {
- this.draggingActive = new ReactiveVar(false);
- this._isDragging = false;
- this._lastDragPositionX = 0;
- },
- id() {
- return this._id;
- },
- currentCardIsInThisList(listId, swimlaneId) {
- return currentCardIsInThisList(listId, swimlaneId);
- },
- currentListIsInThisSwimlane(swimlaneId) {
- return currentListIsInThisSwimlane(swimlaneId);
- },
- events() {
- return [
- {
- // Click-and-drag action
- 'mousedown .board-canvas'(evt) {
- // Translating the board canvas using the click-and-drag action can
- // conflict with the build-in browser mechanism to select text. We
- // define a list of elements in which we disable the dragging because
- // the user will legitimately expect to be able to select some text with
- // his mouse.
- const noDragInside = [
- 'a',
- 'input',
- 'textarea',
- 'p',
- '.js-list-header',
- ];
- if (
- $(evt.target).closest(noDragInside.join(',')).length === 0 &&
- this.$('.swimlane').prop('clientHeight') > evt.offsetY
- ) {
- this._isDragging = true;
- this._lastDragPositionX = evt.clientX;
- }
- },
- mouseup() {
- if (this._isDragging) {
- this._isDragging = false;
- }
- },
- mousemove(evt) {
- if (this._isDragging) {
- // Update the canvas position
- this.listsDom.scrollLeft -= evt.clientX - this._lastDragPositionX;
- this._lastDragPositionX = evt.clientX;
- // Disable browser text selection while dragging
- evt.stopPropagation();
- evt.preventDefault();
- // Don't close opened card or inlined form at the end of the
- // click-and-drag.
- EscapeActions.executeUpTo('popup-close');
- EscapeActions.preventNextClick();
- }
- },
- },
- ];
- },
- }).register('swimlane');
- BlazeComponent.extendComponent({
- onCreated() {
- this.currentBoard = Boards.findOne(Session.get('currentBoard'));
- this.isListTemplatesSwimlane =
- this.currentBoard.isTemplatesBoard() &&
- this.currentData().isListTemplatesSwimlane();
- this.currentSwimlane = this.currentData();
- },
- // Proxy
- open() {
- this.childComponents('inlinedForm')[0].open();
- },
- events() {
- return [
- {
- submit(evt) {
- evt.preventDefault();
- const titleInput = this.find('.list-name-input');
- const title = titleInput.value.trim();
- if (title) {
- Lists.insert({
- title,
- boardId: Session.get('currentBoard'),
- sort: $('.list').length,
- type: this.isListTemplatesSwimlane ? 'template-list' : 'list',
- swimlaneId: this.currentBoard.isTemplatesBoard()
- ? this.currentSwimlane._id
- : '',
- });
- titleInput.value = '';
- titleInput.focus();
- }
- },
- 'click .js-list-template': Popup.open('searchElement'),
- },
- ];
- },
- }).register('addListForm');
- Template.swimlane.helpers({
- canSeeAddList() {
- return (
- Meteor.user() &&
- Meteor.user().isBoardMember() &&
- !Meteor.user().isCommentOnly()
- );
- },
- });
- BlazeComponent.extendComponent({
- currentCardIsInThisList(listId, swimlaneId) {
- return currentCardIsInThisList(listId, swimlaneId);
- },
- visible(list) {
- if (list.archived) {
- // Show archived list only when filter archive is on or archive is selected
- if (!(Filter.archive.isSelected() || archivedRequested)) {
- return false;
- }
- }
- if (Filter.hideEmpty.isSelected()) {
- const swimlaneId = this.parentComponent()
- .parentComponent()
- .data()._id;
- const cards = list.cards(swimlaneId);
- if (cards.count() === 0) {
- return false;
- }
- }
- return true;
- },
- onRendered() {
- const boardComponent = this.parentComponent();
- const $listsDom = this.$('.js-lists');
- if (!Session.get('currentCard')) {
- boardComponent.scrollLeft();
- }
- initSortable(boardComponent, $listsDom);
- },
- }).register('listsGroup');
|