const { calculateIndex } = Utils ;
function currentCardIsInThisList ( listId , swimlaneId ) {
const currentCard = Cards . findOne ( Session . get ( 'currentCard' ) ) ;
const currentBoardId = Session . get ( 'currentBoard' ) ;
const board = Boards . findOne ( currentBoardId ) ;
if ( board . view === 'board-view-lists' )
return currentCard && currentCard . listId === listId ;
else if ( board . view === 'board-view-swimlanes' )
return currentCard && currentCard . listId === listId && currentCard . swimlaneId === swimlaneId ;
else
return false ;
} ;
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 ) ;
} ,
} ) ;
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 ) ;
} ,
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 ( {
// 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 ,
} ) ;
titleInput . value = '' ;
titleInput . focus ( ) ;
}
} ,
} ] ;
} ,
} ) . register ( 'addListForm' ) ;
BlazeComponent . extendComponent ( {
// Proxy
open ( ) {
this . childComponents ( 'inlinedForm' ) [ 0 ] . open ( ) ;
} ,
events ( ) {
return [ {
submit ( evt ) {
evt . preventDefault ( ) ;
let titleInput = this . find ( '.list-name-input' ) ;
if ( titleInput ) {
const title = titleInput . value . trim ( ) ;
if ( title ) {
Lists . insert ( {
title ,
boardId : Session . get ( 'currentBoard' ) ,
sort : $ ( '.list' ) . length ,
} ) ;
titleInput . value = '' ;
titleInput . focus ( ) ;
}
} else {
titleInput = this . find ( '.swimlane-name-input' ) ;
const title = titleInput . value . trim ( ) ;
if ( title ) {
Swimlanes . insert ( {
title ,
boardId : Session . get ( 'currentBoard' ) ,
sort : $ ( '.swimlane' ) . length ,
} ) ;
titleInput . value = '' ;
titleInput . focus ( ) ;
}
}
} ,
} ] ;
} ,
} ) . register ( 'addListAndSwimlaneForm' ) ;
Template . swimlane . helpers ( {
canSeeAddList ( ) {
return Meteor . user ( ) && Meteor . user ( ) . isBoardMember ( ) && ! Meteor . user ( ) . isCommentOnly ( ) ;
} ,
} ) ;
BlazeComponent . extendComponent ( {
currentCardIsInThisList ( listId , swimlaneId ) {
return currentCardIsInThisList ( listId , swimlaneId ) ;
} ,
onRendered ( ) {
const boardComponent = this . parentComponent ( ) ;
const $listsDom = this . $ ( '.js-lists' ) ;
if ( ! Session . get ( 'currentCard' ) ) {
boardComponent . scrollLeft ( ) ;
}
initSortable ( boardComponent , $listsDom ) ;
} ,
} ) . register ( 'listsGroup' ) ;