cryptpad/www/kanban/jkanban.js

1854 lines
76 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(function e(t, n, r) {
function s(o, u) {
if (!n[o]) {
if (!t[o]) {
var a = typeof require == "function" && require;
if (!u && a) return a(o, !0);
if (i) return i(o, !0);
var f = new Error("Cannot find module '" + o + "'");
throw f.code = "MODULE_NOT_FOUND", f
}
var l = n[o] = {
exports: {}
};
t[o][0].call(l.exports, function (e) {
var n = t[o][1][e];
return s(n ? n : e)
}, l, l.exports, e, t, n, r)
}
return n[o].exports
}
var i = typeof require == "function" && require;
for (var o = 0; o < r.length; o++) s(r[o]);
return s
})({
1: [function (require, module, exports) {
/**
* jKanban
* Vanilla Javascript plugin for manage kanban boards
*
* @site: http://www.riccardotartaglia.it/jkanban/
* @author: Riccardo Tartaglia
*/
//Require dragula
var dragula = require('dragula');
(function () {
this.jKanban = function () {
var self = this;
this.element = '';
this.container = '';
this.boardContainer = [];
this.dragula = dragula;
this.drake = '';
this.drakeBoard = '';
this.addItemButton = false;
this.cache = {};
defaults = {
element: '',
gutter: '15px',
widthBoard: '250px',
responsive: '700',
responsivePercentage: false,
boards: {
data: {},
items: {},
list: []
},
getAvatar: function () {},
openLink: function () {},
getTags: function () {},
getTextColor: function () { return '#000'; },
cursors: {},
tags: [],
dragBoards: true,
addItemButton: false,
readOnly: false,
dragEl: function (el, source) {},
dragendEl: function (el) {},
dropEl: function (el, target, source, sibling) {},
dragcancelEl: function (el, boardId) {},
dragBoard: function (el, source) {},
dragendBoard: function (el) {},
dropBoard: function (el, target, source, sibling) {},
click: function (el) {},
boardTitleclick: function (el, boardId) {},
addItemClick: function (el, boardId) {},
renderMd: function (md) {},
refresh: function () {},
onChange: function () {}
};
if (arguments[0] && typeof arguments[0] === "object") {
this.options = __extendDefaults(defaults, arguments[0]);
}
var checkCache = function (boards) {
Object.keys(self.cache).forEach(function (id) {
if (boards.items[id]) { return; }
delete self.cache[id];
});
};
var removeUnusedTags = function (boards) {
var tags = self.options.getTags(boards);
var filter = self.options.tags || [];
var toClean = [];
filter.forEach(function (tag) {
if (tags.indexOf(tag) === -1) { toClean.push(tag); }
});
toClean.forEach(function (t) {
var idx = filter.indexOf(t);
if (idx === -1) { return; }
filter.splice(idx, 1);
});
// If all the tags have bene remove, make sure we show everything again
if (!filter.length) {
$('.kanban-item-hidden').removeClass('kanban-item-hidden');
}
};
this.init = function () {
// set initial boards
__setBoard();
// Scroll on drag
var $el = $(self.element)
var $inner = $el.find('.kanban-container');
var leftRegion = $el.position().left + 10;
var rightRegion = $(window).width() - 10;
var activeBoard;
var $aB;
var setActiveDrag = function (board) {
activeBoard = undefined;
if (!board) { return; }
if (!board.classList.contains('kanban-drag')) { return; }
activeBoard = board;
$aB = $(activeBoard);
};
var onMouseMove = function (isItem) {
return function (e) {
if (e.which !== 1) { return; } // left click
var distance = 20;
// If this is an item drag, check scroll
if (isItem && activeBoard) {
var rect = activeBoard.getBoundingClientRect();
if (e.pageX > rect.left && e.pageX < rect.right) {
if (e.pageY < (rect.top + 10)) {
distance *= -1;
$aB.scrollTop(distance + $aB.scrollTop()) ;
} else if (e.pageY > (rect.bottom - 10)) {
$aB.scrollTop(distance + $aB.scrollTop()) ;
}
}
}
// Itme or board: horizontal scroll if needed
if (e.pageX < leftRegion) {
distance *= -1;
$el.scrollLeft(distance + $el.scrollLeft()) ;
} else if (e.pageX >= rightRegion) {
$el.scrollLeft(distance + $el.scrollLeft()) ;
}
};
};
//set drag with dragula
if (window.innerWidth > self.options.responsive) {
//Init Drag Board
self.drakeBoard = self.dragula([self.container, self.trashContainer], {
moves: function (el, source, handle, sibling) {
if (self.options.readOnly) { return false; }
if (!self.options.dragBoards) { return false; }
return (handle.classList.contains('kanban-board-header') || handle.classList.contains('kanban-title-board'));
},
accepts: function (el, target, source, sibling) {
if (self.options.readOnly) { return false; }
if (sibling && sibling.getAttribute('id') === "kanban-addboard") { return false; }
return target.classList.contains('kanban-container') ||
target.classList.contains('kanban-trash');
},
revertOnSpill: true,
direction: 'horizontal',
})
.on('drag', function (el, source) {
el.classList.add('is-moving');
self.options.dragBoard(el, source);
if (typeof (el.dragfn) === 'function') {
el.dragfn(el, source);
}
$('.kanban-trash').addClass('kanban-trash-suggest');
$(document).on('mousemove', onMouseMove());
})
.on('dragend', function (el) {
el.classList.remove('is-moving');
self.options.dragendBoard(el);
$(document).off('mousemove');
$('.kanban-trash').removeClass('kanban-trash-suggest');
if (typeof (el.dragendfn) === 'function')
el.dragendfn(el);
})
.on('over', function (el, target, source) {
if (!target.classList.contains('kanban-trash')) { return false; }
$('.kanban-trash').addClass('kanban-trash-active');
$('.kanban-trash').removeClass('kanban-trash-suggest');
})
.on('out', function (el, target) {
if (!target.classList.contains('kanban-trash')) { return false; }
$('.kanban-trash').removeClass('kanban-trash-active');
$('.kanban-trash').addClass('kanban-trash-suggest');
})
.on('drop', function (el, target, source, sibling) {
el.classList.remove('is-moving');
self.options.dropBoard(el, target, source, sibling);
if (typeof (el.dropfn) === 'function') {
el.dropfn(el, target, source, sibling);
}
var id = Number($(el).attr('data-id'));
var list = self.options.boards.list || [];
var index1 = list.indexOf(id);
if (index1 === -1) { return; }
// Move to trash?
if (target.classList.contains('kanban-trash')) {
list.splice(index1, 1);
delete self.options.boards.data[id];
self.onChange();
return;
}
var index2;
var id2 = Number($(sibling).attr("data-id"));
if (sibling && id2) {
index2 = list.indexOf(id2);
}
// If we can't find the drop position, drop at the end
if (typeof(index2) === "undefined" || index2 === -1) {
index2 = list.length;
}
console.log("Switch " + index1 + " and " + index2);
if (index1 < index2) {
index2 = index2 - 1;
}
list.splice(index1, 1);
list.splice(index2, 0, id);
// send event that board has changed
self.onChange();
self.setBoards(self.options.boards);
});
//Init Drag Item
self.drake = self.dragula(self.boardContainer, {
moves: function (el, source, handle, sibling) {
if (self.options.readOnly) { return false; }
if (el.classList.contains('new-item')) { return false; }
return el.classList.contains('kanban-item');
},
accepts: function (el, target, source, sibling) {
if (self.options.readOnly) { return false; }
return true;
},
revertOnSpill: true
})
.on('cancel', function(el, container, source) {
self.enableAllBoards();
})
.on('drag', function (el, source) {
// we need to calculate the position before starting to drag
self.dragItemPos = self.findElementPosition(el);
setActiveDrag();
el.classList.add('is-moving');
$(document).on('mousemove', onMouseMove(el));
$('.kanban-trash').addClass('kanban-trash-suggest');
self.options.dragEl(el, source);
if (el !== null && typeof (el.dragfn) === 'function') {
el.dragfn(el, source);
}
})
.on('dragend', function (el) {
console.log("In dragend");
el.classList.remove('is-moving');
self.options.dragendEl(el);
$('.kanban-trash').removeClass('kanban-trash-suggest');
$(document).off('mousemove');
if (el !== null && typeof (el.dragendfn) === 'function') {
el.dragendfn(el);
}
})
.on('cancel', function (el, container, source) {
console.log("In cancel");
el.classList.remove('is-moving');
var boardId = $(source).closest('kanban-board').data('id');
self.options.dragcancelEl(el, boardId);
})
.on('over', function (el, target, source) {
setActiveDrag(target);
if (!target.classList.contains('kanban-trash')) { return false; }
target.classList.remove('kanban-trash-suggest');
target.classList.add('kanban-trash-active');
})
.on('out', function (el, target) {
setActiveDrag();
if (!target.classList.contains('kanban-trash')) { return false; }
target.classList.remove('kanban-trash-active');
target.classList.add('kanban-trash-suggest');
})
.on('drop', function(el, target, source, sibling) {
self.enableAllBoards();
el.classList.remove('is-moving');
console.log("In drop");
var id1 = Number($(el).attr('data-eid'));
// Move to trash?
if (target.classList.contains('kanban-trash')) {
self.moveItem(id1);
self.onChange();
return;
}
// Find the new board
var targetId = Number($(target).closest('.kanban-board').data('id'));
if (!targetId) { return; }
var board2 = __findBoardJSON(targetId);
var id2 = $(sibling).attr('data-eid');
if (id2) { id2 = Number(id2); }
var pos2 = id2 ? board2.item.indexOf(id2) : board2.item.length;
if (pos2 === -1) { pos2 = board2.item.length; }
// Remove the "move" effect
if (el !== null) {
el.classList.remove('is-moving');
}
// Move the item
self.moveItem(id1, board2, pos2);
// send event that board has changed
self.onChange();
self.setBoards(self.options.boards);
})
}
};
var findItem = function (eid) {
var boards = self.options.boards;
var list = boards.list || [];
var res = [];
list.forEach(function (id) {
var b = boards.data[id];
if (!b) { return; }
var items = b.item || [];
var idx = items.indexOf(eid);
if (idx === -1) { return; }
// This board contains our item...
res.push({
board: b,
pos: idx
});
});
return res;
};
this.moveItem = function (eid, board, pos) {
var boards = self.options.boards;
var list = boards.list || [];
var from = [];
var same = -1;
var from = findItem(eid);
// Remove the item from its board
from.forEach(function (obj) {
obj.board.item.splice(obj.pos, 1);
if (obj.board === board) { same = obj.pos; }
});
// If it's a deletion, remove the item data
if (!board) {
delete boards.items[eid];
delete self.cache[eid];
removeUnusedTags(boards);
self.options.refresh();
return;
}
// If it's moved to the same board at a bigger index, decrement the index by one
// (we just removed one element)
if (same !== -1 && same < pos) {
pos = pos - 1;
}
board.item.splice(pos, 0, eid);
};
this.enableAllBoards = function() {
var allB = document.querySelectorAll('.kanban-board');
if (allB.length > 0 && allB !== undefined) {
for (var i = 0; i < allB.length; i++) {
allB[i].classList.remove('disabled-board');
}
}
};
var getElementNode = function (element) {
var nodeItem = document.createElement('div');
nodeItem.classList.add('kanban-item');
nodeItem.dataset.eid = element.id;
if (element.color) {
if (/color/.test(element.color)) {
// Palette color
nodeItem.classList.add('cp-kanban-palette-'+element.color);
} else {
// Hex color code
var textColor = self.options.getTextColor(element.color);
nodeItem.setAttribute('style', 'background-color:#'+element.color+';color:'+textColor+';');
}
}
var nodeCursors = document.createElement('div');
nodeCursors.classList.add('cp-kanban-cursors');
Object.keys(self.options.cursors).forEach(function (id) {
var c = self.options.cursors[id];
if (Number(c.item) !== Number(element.id)) { return; }
var el = self.options.getAvatar(c);
nodeCursors.appendChild(el);
});
var nodeItemText = document.createElement('div');
nodeItemText.classList.add('kanban-item-text');
nodeItemText.dataset.eid = element.id;
nodeItemText.innerText = element.title;
nodeItem.appendChild(nodeItemText);
// Check if this card is filtered out
if (Array.isArray(self.options.tags) && self.options.tags.length) {
var hide = !Array.isArray(element.tags) ||
!element.tags.some(function (tag) {
return self.options.tags.indexOf(tag) !== -1;
});
if (hide) {
nodeItem.classList.add('kanban-item-hidden');
}
}
if (element.body) {
var html;
if (self.cache[element.id] && self.cache[element.id].body === element.body) {
html = self.cache[element.id].html;
} else {
html = self.renderMd(element.body);
self.cache[element.id] = {
body: element.body,
html: html
};
}
var nodeBody = document.createElement('div');
nodeBody.classList.add('kanban-item-body');
$(nodeBody).on('click', 'a', function (e) {
e.preventDefault();
var a = e.target;
if (!a.href) { return; }
var href = a.getAttribute('href');
self.options.openLink(href);
});
nodeBody.onclick = function (e) {
e.preventDefault();
};
nodeBody.innerHTML = html;
nodeItem.appendChild(nodeBody);
}
if (Array.isArray(element.tags)) {
var nodeTags = document.createElement('div');
nodeTags.classList.add('kanban-item-tags');
element.tags.forEach(function (_tag) {
var tag = document.createElement('span');
tag.innerText = _tag;
nodeTags.appendChild(tag);
});
nodeItem.appendChild(nodeTags);
}
nodeItem.appendChild(nodeCursors);
//add function
nodeItem.clickfn = element.click;
nodeItem.dragfn = element.drag;
nodeItem.dragendfn = element.dragend;
nodeItem.dropfn = element.drop;
__onclickHandler(nodeItemText);
return nodeItem;
};
this.addElement = function (boardID, element) {
// add Element to JSON
var boardJSON = __findBoardJSON(boardID);
boardJSON.item.push(element.id);
self.options.boards.items = self.options.boards.items || {};
self.options.boards.items[element.id] = element;
var board = self.element.querySelector('[data-id="' + boardID + '"] .kanban-drag');
board.appendChild(getElementNode(element));
// send event that board has changed
self.onChange();
return self;
};
this.addForm = function (boardID, formItem) {
var board = self.element.querySelector('[data-id="' + boardID + '"] .kanban-drag');
board.appendChild(formItem);
return self;
};
var getBoardNode = function (board) {
var boards = self.options.boards;
var boardWidth = self.options.widthBoard;
//create node
var boardNode = document.createElement('div');
boardNode.dataset.id = board.id;
boardNode.classList.add('kanban-board');
var boardNodeInner = document.createElement('div');
boardNodeInner.classList.add('kanban-board-inner');
//set style
if (self.options.responsivePercentage) {
boardNode.style.width = boardWidth + '%';
} else {
boardNode.style.width = boardWidth;
}
boardNode.style.marginLeft = self.options.gutter;
boardNode.style.marginRight = self.options.gutter;
// header board
var headerBoard = document.createElement('header');
if (board.class !== '' && board.class !== undefined) {
var allClasses = board.class.split(",");
} else {
allClasses = [];
}
headerBoard.classList.add('kanban-board-header');
allClasses.map(function (value) {
headerBoard.classList.add(value);
});
if (board.color !== '' && board.color !== undefined) {
if (/color/.test(board.color)) {
// Palette color
headerBoard.classList.add('cp-kanban-palette-'+board.color);
boardNodeInner.classList.add('cp-kanban-palette-'+board.color);
} else if (!/^[0-9a-f]{6}$/.test(board.color)) {
// "string" color (red, blue, etc.)
headerBoard.classList.add("kanban-header-" + board.color);
} else {
// Hex color code
var textColor = self.options.getTextColor(board.color);
headerBoard.setAttribute('style', 'background-color:#'+board.color+';color:'+textColor+';');
}
}
titleBoard = document.createElement('div');
titleBoard.classList.add('kanban-title-board');
titleBoard.innerText = board.title;
titleBoard.clickfn = board.boardTitleClick;
__onboardTitleClickHandler(titleBoard);
headerBoard.appendChild(titleBoard);
var nodeCursors = document.createElement('div');
nodeCursors.classList.add('cp-kanban-cursors');
Object.keys(self.options.cursors).forEach(function (id) {
var c = self.options.cursors[id];
if (Number(c.board) !== Number(board.id)) { return; }
var el = self.options.getAvatar(c);
nodeCursors.appendChild(el);
});
headerBoard.appendChild(nodeCursors);
//content board
var contentBoard = document.createElement('main');
contentBoard.classList.add('kanban-drag');
//add drag to array for dragula
self.boardContainer.push(contentBoard);
(board.item || []).forEach(function (itemkey) {
//create item
var itemKanban = boards.items[itemkey];
if (!itemKanban) {
var idx = board.item.indexOf(itemkey);
if (idx > -1) { board.item.splice(idx, 1); }
return;
}
var nodeItem = getElementNode(itemKanban);
contentBoard.appendChild(nodeItem);
});
//footer board
var footerBoard = document.createElement('footer');
footerBoard.classList.add('kanban-board-footer');
//add button
var addBoardItem = document.createElement('span');
addBoardItem.classList.add('kanban-title-button');
addBoardItem.innerText = '+';
footerBoard.appendChild(addBoardItem);
__onAddItemClickHandler(addBoardItem);
//board assembly
boardNode.appendChild(boardNodeInner);
boardNodeInner.appendChild(headerBoard);
boardNodeInner.appendChild(contentBoard);
boardNodeInner.appendChild(footerBoard);
return boardNode;
};
this.addBoard = function (board) {
if (!board || !board.id) { return; }
var boards = self.options.boards;
boards.data = boards.data || {};
boards.list = boards.list || [];
// If it already there, abort
boards.data[board.id] = board;
if (boards.list.indexOf(board.id) !== -1) { return; }
boards.list.push(board.id);
var boardNode = getBoardNode(board);
self.container.appendChild(boardNode);
};
this.addBoards = function() {
//for on all the boards
var boards = self.options.boards;
boards.list = boards.list || [];
boards.data = boards.data || {};
var toRemove = [];
boards.list.forEach(function (boardkey) {
// single board
var board = boards.data[boardkey];
if (!board) {
toRemove.push(boardkey);
return;
}
var boardNode = getBoardNode(board);
//board add
self.container.appendChild(boardNode);
});
toRemove.forEach(function (id) {
var idx = boards.list.indexOf(id);
if (idx > -1) { boards.list.splice(idx, 1); }
});
// send event that board has changed
self.onChange();
return self;
}
this.setBoards = function (boards) {
var scroll = {};
// Fix the tags
checkCache(boards);
removeUnusedTags(boards);
// Get horizontal scroll
var $el = $(self.element);
var scrollLeft = $el.scrollLeft();
// Remove all boards
for (var i in this.options.boards.list) {
var boardkey = this.options.boards.list[i];
scroll[boardkey] = $('.kanban-board[data-id="'+boardkey+'"] .kanban-drag').scrollTop();
this.removeBoard(boardkey);
}
this.options.boards = boards;
// Add all new boards
this.addBoards();
self.options.refresh();
// Preserve scroll
this.options.boards.list.forEach(function (id) {
if (!scroll[id]) { return; }
$('.kanban-board[data-id="'+id+'"] .kanban-drag').scrollTop(scroll[id]);
});
$el.scrollLeft(scrollLeft);
}
this.findBoard = function (id) {
var el = self.element.querySelector('[data-id="' + id + '"]');
return el;
}
this.findElement = function (id) {
var el = self.element.querySelector('[data-eid="' + id + '"]');
return el;
}
this.findElementPosition = function (el) {
// we are looking at the element position in the child array
return $(el.parentNode.children).index(el);
}
this.getBoardElements = function (id) {
var board = self.element.querySelector('[data-id="' + id + '"] .kanban-drag');
return (board.childNodes);
}
this.removeElement = function (el) {
if (typeof (el) === 'string')
el = self.element.querySelector('[data-eid="' + el + '"]');
el.remove();
// send event that board has changed
self.onChange();
return self;
};
this.removeBoard = function (board) {
var id;
if (typeof (board) === 'string' || typeof (board) === "number") {
id = board;
board = self.element.querySelector('[data-id="' + board + '"]');
} else if (board) {
id = board.id;
}
if (board) {
board.remove();
// send event that board has changed
self.onChange();
}
// Remove duplicates
if (id) { $(self.element).find('.kanban-board[data-id="' + board + '"]').remove(); }
return self;
}
this.renderMd = function (md) {
return self.options.renderMd(md);
}
this.onChange = function () {
self.options.onChange();
}
this.getBoardsJSON = function (id) {
return self.options.boards;
}
this.getBoardJSON = function (id) {
return __findBoardJSON(id);
}
this.getItemJSON = function (id) {
return (self.options.boards.items || {})[id];
};
//PRIVATE FUNCTION
function __extendDefaults(source, properties) {
var property;
for (property in properties) {
if (properties.hasOwnProperty(property)) {
source[property] = properties[property];
}
}
return source;
}
function __setBoard() {
self.element = document.querySelector(self.options.element);
//create container
var boardContainerOuter = document.createElement('div');
boardContainerOuter.classList.add('kanban-container-outer');
var boardContainer = document.createElement('div');
boardContainer.classList.add('kanban-container');
boardContainerOuter.appendChild(boardContainer);
var addBoard = document.createElement('div');
addBoard.id = 'kanban-addboard';
addBoard.innerText = '+';
boardContainer.appendChild(addBoard);
var trash = self.trashContainer = document.createElement('div');
trash.setAttribute('id', 'kanban-trash');
trash.setAttribute('class', 'kanban-trash');
var trashBg = document.createElement('div');
var trashIcon = document.createElement('i');
trashIcon.setAttribute('class', 'fa fa-trash');
trash.appendChild(trashIcon);
trash.appendChild(trashBg);
self.boardContainer.push(trash);
self.container = boardContainer;
//add boards
self.addBoards();
//appends to container
self.element.appendChild(boardContainerOuter);
self.element.appendChild(trash);
// send event that board has changed
self.onChange();
};
function __onclickHandler(nodeItem, clickfn) {
nodeItem.addEventListener('click', function (e) {
e.preventDefault;
e.stopPropagation();
self.options.click(this);
if (typeof (this.clickfn) === 'function')
this.clickfn(this);
});
}
function __onboardTitleClickHandler(nodeItem, clickfn) {
nodeItem.addEventListener('click', function (e) {
e.preventDefault;
self.options.boardTitleClick(this, e);
if (typeof (this.clickfn) === 'function')
this.clickfn(this);
});
}
function __onAddItemClickHandler(nodeItem, clickfn) {
nodeItem.addEventListener('click', function (e) {
e.preventDefault;
e.stopPropagation();
self.options.addItemClick(this);
if (typeof (this.clickfn) === 'function')
this.clickfn(this);
});
}
function __findBoardJSON(id) {
return (self.options.boards.data || {})[id];
}
//init plugin
this.init();
};
}());
}, {
"dragula": 9
}],
2: [function (require, module, exports) {
module.exports = function atoa(a, n) {
return Array.prototype.slice.call(a, n);
}
}, {}],
3: [function (require, module, exports) {
'use strict';
var ticky = require('ticky');
module.exports = function debounce(fn, args, ctx) {
if (!fn) {
return;
}
ticky(function run() {
fn.apply(ctx || null, args || []);
});
};
}, {
"ticky": 10
}],
4: [function (require, module, exports) {
'use strict';
var atoa = require('atoa');
var debounce = require('./debounce');
module.exports = function emitter(thing, options) {
var opts = options || {};
var evt = {};
if (thing === undefined) {
thing = {};
}
thing.on = function (type, fn) {
if (!evt[type]) {
evt[type] = [fn];
} else {
evt[type].push(fn);
}
return thing;
};
thing.once = function (type, fn) {
fn._once = true; // thing.off(fn) still works!
thing.on(type, fn);
return thing;
};
thing.off = function (type, fn) {
var c = arguments.length;
if (c === 1) {
delete evt[type];
} else if (c === 0) {
evt = {};
} else {
var et = evt[type];
if (!et) {
return thing;
}
et.splice(et.indexOf(fn), 1);
}
return thing;
};
thing.emit = function () {
var args = atoa(arguments);
return thing.emitterSnapshot(args.shift()).apply(this, args);
};
thing.emitterSnapshot = function (type) {
var et = (evt[type] || []).slice(0);
return function () {
var args = atoa(arguments);
var ctx = this || thing;
if (type === 'error' && opts.throws !== false && !et.length) {
throw args.length === 1 ? args[0] : args;
}
et.forEach(function emitter(listen) {
if (opts.async) {
debounce(listen, args, ctx);
} else {
listen.apply(ctx, args);
}
if (listen._once) {
thing.off(type, listen);
}
});
return thing;
};
};
return thing;
};
}, {
"./debounce": 3,
"atoa": 2
}],
5: [function (require, module, exports) {
(function (global) {
'use strict';
var customEvent = require('custom-event');
var eventmap = require('./eventmap');
var doc = global.document;
var addEvent = addEventEasy;
var removeEvent = removeEventEasy;
var hardCache = [];
if (!global.addEventListener) {
addEvent = addEventHard;
removeEvent = removeEventHard;
}
module.exports = {
add: addEvent,
remove: removeEvent,
fabricate: fabricateEvent
};
function addEventEasy(el, type, fn, capturing) {
return el.addEventListener(type, fn, capturing);
}
function addEventHard(el, type, fn) {
return el.attachEvent('on' + type, wrap(el, type, fn));
}
function removeEventEasy(el, type, fn, capturing) {
return el.removeEventListener(type, fn, capturing);
}
function removeEventHard(el, type, fn) {
var listener = unwrap(el, type, fn);
if (listener) {
return el.detachEvent('on' + type, listener);
}
}
function fabricateEvent(el, type, model) {
var e = eventmap.indexOf(type) === -1 ? makeCustomEvent() : makeClassicEvent();
if (el.dispatchEvent) {
el.dispatchEvent(e);
} else {
el.fireEvent('on' + type, e);
}
function makeClassicEvent() {
var e;
if (doc.createEvent) {
e = doc.createEvent('Event');
e.initEvent(type, true, true);
} else if (doc.createEventObject) {
e = doc.createEventObject();
}
return e;
}
function makeCustomEvent() {
return new customEvent(type, {
detail: model
});
}
}
function wrapperFactory(el, type, fn) {
return function wrapper(originalEvent) {
var e = originalEvent || global.event;
e.target = e.target || e.srcElement;
e.preventDefault = e.preventDefault || function preventDefault() {
e.returnValue = false;
};
e.stopPropagation = e.stopPropagation || function stopPropagation() {
e.cancelBubble = true;
};
e.which = e.which || e.keyCode;
fn.call(el, e);
};
}
function wrap(el, type, fn) {
var wrapper = unwrap(el, type, fn) || wrapperFactory(el, type, fn);
hardCache.push({
wrapper: wrapper,
element: el,
type: type,
fn: fn
});
return wrapper;
}
function unwrap(el, type, fn) {
var i = find(el, type, fn);
if (i) {
var wrapper = hardCache[i].wrapper;
hardCache.splice(i, 1); // free up a tad of memory
return wrapper;
}
}
function find(el, type, fn) {
var i, item;
for (i = 0; i < hardCache.length; i++) {
item = hardCache[i];
if (item.element === el && item.type === type && item.fn === fn) {
return i;
}
}
}
}).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
}, {
"./eventmap": 6,
"custom-event": 7
}],
6: [function (require, module, exports) {
(function (global) {
'use strict';
var eventmap = [];
var eventname = '';
var ron = /^on/;
for (eventname in global) {
if (ron.test(eventname)) {
eventmap.push(eventname.slice(2));
}
}
module.exports = eventmap;
}).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
}, {}],
7: [function (require, module, exports) {
(function (global) {
var NativeCustomEvent = global.CustomEvent;
function useNative() {
try {
var p = new NativeCustomEvent('cat', {
detail: {
foo: 'bar'
}
});
return 'cat' === p.type && 'bar' === p.detail.foo;
} catch (e) {}
return false;
}
/**
* Cross-browser `CustomEvent` constructor.
*
* https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent.CustomEvent
*
* @public
*/
module.exports = useNative() ? NativeCustomEvent :
// IE >= 9
'function' === typeof document.createEvent ? function CustomEvent(type, params) {
var e = document.createEvent('CustomEvent');
if (params) {
e.initCustomEvent(type, params.bubbles, params.cancelable, params.detail);
} else {
e.initCustomEvent(type, false, false, void 0);
}
return e;
} :
// IE <= 8
function CustomEvent(type, params) {
var e = document.createEventObject();
e.type = type;
if (params) {
e.bubbles = Boolean(params.bubbles);
e.cancelable = Boolean(params.cancelable);
e.detail = params.detail;
} else {
e.bubbles = false;
e.cancelable = false;
e.detail = void 0;
}
return e;
}
}).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
}, {}],
8: [function (require, module, exports) {
'use strict';
var cache = {};
var start = '(?:^|\\s)';
var end = '(?:\\s|$)';
function lookupClass(className) {
var cached = cache[className];
if (cached) {
cached.lastIndex = 0;
} else {
cache[className] = cached = new RegExp(start + className + end, 'g');
}
return cached;
}
function addClass(el, className) {
var current = el.className;
if (!current.length) {
el.className = className;
} else if (!lookupClass(className).test(current)) {
el.className += ' ' + className;
}
}
function rmClass(el, className) {
el.className = el.className.replace(lookupClass(className), ' ').trim();
}
module.exports = {
add: addClass,
rm: rmClass
};
}, {}],
9: [function (require, module, exports) {
(function (global) {
'use strict';
var emitter = require('contra/emitter');
var crossvent = require('crossvent');
var classes = require('./classes');
var doc = document;
var documentElement = doc.documentElement;
function dragula(initialContainers, options) {
var len = arguments.length;
if (len === 1 && Array.isArray(initialContainers) === false) {
options = initialContainers;
initialContainers = [];
}
var _mirror; // mirror image
var _source; // source container
var _item; // item being dragged
var _offsetX; // reference x
var _offsetY; // reference y
var _moveX; // reference move x
var _moveY; // reference move y
var _initialSibling; // reference sibling when grabbed
var _currentSibling; // reference sibling now
var _copy; // item used for copying
var _renderTimer; // timer for setTimeout renderMirrorImage
var _lastDropTarget = null; // last container item was over
var _grabbed; // holds mousedown context until first mousemove
var o = options || {};
if (o.moves === void 0) {
o.moves = always;
}
if (o.accepts === void 0) {
o.accepts = always;
}
if (o.invalid === void 0) {
o.invalid = invalidTarget;
}
if (o.containers === void 0) {
o.containers = initialContainers || [];
}
if (o.isContainer === void 0) {
o.isContainer = never;
}
if (o.copy === void 0) {
o.copy = false;
}
if (o.copySortSource === void 0) {
o.copySortSource = false;
}
if (o.revertOnSpill === void 0) {
o.revertOnSpill = false;
}
if (o.removeOnSpill === void 0) {
o.removeOnSpill = false;
}
if (o.direction === void 0) {
o.direction = 'vertical';
}
if (o.ignoreInputTextSelection === void 0) {
o.ignoreInputTextSelection = true;
}
if (o.mirrorContainer === void 0) {
o.mirrorContainer = doc.body;
}
var drake = emitter({
containers: o.containers,
start: manualStart,
end: end,
cancel: cancel,
remove: remove,
destroy: destroy,
canMove: canMove,
dragging: false
});
if (o.removeOnSpill === true) {
drake.on('over', spillOver).on('out', spillOut);
}
events();
return drake;
function isContainer(el) {
return drake.containers.indexOf(el) !== -1 || o.isContainer(el);
}
function events(remove) {
var op = remove ? 'remove' : 'add';
touchy(documentElement, op, 'mousedown', grab);
touchy(documentElement, op, 'mouseup', release);
}
function eventualMovements(remove) {
var op = remove ? 'remove' : 'add';
touchy(documentElement, op, 'mousemove', startBecauseMouseMoved);
}
function movements(remove) {
var op = remove ? 'remove' : 'add';
crossvent[op](documentElement, 'selectstart', preventGrabbed); // IE8
crossvent[op](documentElement, 'click', preventGrabbed);
}
function destroy() {
events(true);
release({});
}
function preventGrabbed(e) {
if (_grabbed) {
e.preventDefault();
}
}
function grab(e) {
_moveX = e.clientX;
_moveY = e.clientY;
var ignore = whichMouseButton(e) !== 1 || e.metaKey || e.ctrlKey;
if (ignore) {
return; // we only care about honest-to-god left clicks and touch events
}
var item = e.target;
var context = canStart(item);
if (!context) {
return;
}
_grabbed = context;
eventualMovements();
if (e.type === 'mousedown') {
if (isInput(item)) { // see also: https://github.com/bevacqua/dragula/issues/208
item.focus(); // fixes https://github.com/bevacqua/dragula/issues/176
} else {
e.preventDefault(); // fixes https://github.com/bevacqua/dragula/issues/155
}
}
}
function startBecauseMouseMoved(e) {
if (!_grabbed) {
return;
}
if (whichMouseButton(e) === 0) {
release({});
return; // when text is selected on an input and then dragged, mouseup doesn't fire. this is our only hope
}
// truthy check fixes #239, equality fixes #207
if (e.clientX !== void 0 && e.clientX === _moveX && e.clientY !== void 0 && e.clientY === _moveY) {
return;
}
if (o.ignoreInputTextSelection) {
var clientX = getCoord('clientX', e);
var clientY = getCoord('clientY', e);
var elementBehindCursor = doc.elementFromPoint(clientX, clientY);
if (isInput(elementBehindCursor)) {
return;
}
}
var grabbed = _grabbed; // call to end() unsets _grabbed
eventualMovements(true);
movements();
end();
start(grabbed);
var offset = getOffset(_item);
_offsetX = getCoord('pageX', e) - offset.left;
_offsetY = getCoord('pageY', e) - offset.top;
classes.add(_copy || _item, 'gu-transit');
renderMirrorImage();
drag(e);
}
function canStart(item) {
if (drake.dragging && _mirror) {
return;
}
if (isContainer(item)) {
return; // don't drag container itself
}
var handle = item;
while (getParent(item) && isContainer(getParent(item)) === false) {
if (o.invalid(item, handle)) {
return;
}
item = getParent(item); // drag target should be a top element
if (!item) {
return;
}
}
var source = getParent(item);
if (!source) {
return;
}
if (o.invalid(item, handle)) {
return;
}
var movable = o.moves(item, source, handle, nextEl(item));
if (!movable) {
return;
}
return {
item: item,
source: source
};
}
function canMove(item) {
return !!canStart(item);
}
function manualStart(item) {
var context = canStart(item);
if (context) {
start(context);
}
}
function start(context) {
if (isCopy(context.item, context.source)) {
_copy = context.item.cloneNode(true);
drake.emit('cloned', _copy, context.item, 'copy');
}
_source = context.source;
_item = context.item;
_initialSibling = _currentSibling = nextEl(context.item);
drake.dragging = true;
drake.emit('drag', _item, _source);
}
function invalidTarget() {
return false;
}
function end() {
if (!drake.dragging) {
return;
}
var item = _copy || _item;
drop(item, getParent(item));
}
function ungrab() {
_grabbed = false;
eventualMovements(true);
movements(true);
}
function release(e) {
ungrab();
if (!drake.dragging) {
return;
}
var item = _copy || _item;
var clientX = getCoord('clientX', e);
var clientY = getCoord('clientY', e);
var elementBehindCursor = getElementBehindPoint(_mirror, clientX, clientY);
var dropTarget = findDropTarget(elementBehindCursor, clientX, clientY);
if (dropTarget && ((_copy && o.copySortSource) || (!_copy || dropTarget !== _source))) {
drop(item, dropTarget);
} else if (o.removeOnSpill) {
remove();
} else {
cancel();
}
}
function drop(item, target) {
var parent = getParent(item);
if (_copy && o.copySortSource && target === _source) {
parent.removeChild(_item);
}
if (isInitialPlacement(target)) {
drake.emit('cancel', item, _source, _source);
} else {
drake.emit('drop', item, target, _source, _currentSibling);
}
cleanup();
}
function remove() {
if (!drake.dragging) {
return;
}
var item = _copy || _item;
var parent = getParent(item);
if (parent) {
parent.removeChild(item);
}
drake.emit(_copy ? 'cancel' : 'remove', item, parent, _source);
cleanup();
}
function cancel(revert) {
if (!drake.dragging) {
return;
}
var reverts = arguments.length > 0 ? revert : o.revertOnSpill;
var item = _copy || _item;
var parent = getParent(item);
var initial = isInitialPlacement(parent);
if (initial === false && reverts) {
if (_copy) {
if (parent) {
parent.removeChild(_copy);
}
} else {
_source.insertBefore(item, _initialSibling);
}
}
if (initial || reverts) {
drake.emit('cancel', item, _source, _source);
} else {
drake.emit('drop', item, parent, _source, _currentSibling);
}
cleanup();
}
function cleanup() {
var item = _copy || _item;
ungrab();
removeMirrorImage();
if (item) {
classes.rm(item, 'gu-transit');
}
if (_renderTimer) {
clearTimeout(_renderTimer);
}
drake.dragging = false;
if (_lastDropTarget) {
drake.emit('out', item, _lastDropTarget, _source);
}
drake.emit('dragend', item);
_source = _item = _copy = _initialSibling = _currentSibling = _renderTimer = _lastDropTarget = null;
}
function isInitialPlacement(target, s) {
var sibling;
if (s !== void 0) {
sibling = s;
} else if (_mirror) {
sibling = _currentSibling;
} else {
sibling = nextEl(_copy || _item);
}
return target === _source && sibling === _initialSibling;
}
function findDropTarget(elementBehindCursor, clientX, clientY) {
var target = elementBehindCursor;
while (target && !accepted()) {
target = getParent(target);
}
return target;
function accepted() {
var droppable = isContainer(target);
if (droppable === false) {
return false;
}
var immediate = getImmediateChild(target, elementBehindCursor);
var reference = getReference(target, immediate, clientX, clientY);
var initial = isInitialPlacement(target, reference);
if (initial) {
return true; // should always be able to drop it right back where it was
}
return o.accepts(_item, target, _source, reference);
}
}
function drag(e) {
if (!_mirror) {
return;
}
e.preventDefault();
var clientX = getCoord('clientX', e);
var clientY = getCoord('clientY', e);
var x = clientX - _offsetX;
var y = clientY - _offsetY;
_mirror.style.left = x + 'px';
_mirror.style.top = y + 'px';
var item = _copy || _item;
var elementBehindCursor = getElementBehindPoint(_mirror, clientX, clientY);
var dropTarget = findDropTarget(elementBehindCursor, clientX, clientY);
var changed = dropTarget !== null && dropTarget !== _lastDropTarget;
if (changed || dropTarget === null) {
out();
_lastDropTarget = dropTarget;
over();
}
var parent = getParent(item);
if (dropTarget === _source && _copy && !o.copySortSource) {
if (parent) {
parent.removeChild(item);
}
return;
}
var reference;
var immediate = getImmediateChild(dropTarget, elementBehindCursor);
if (immediate !== null) {
reference = getReference(dropTarget, immediate, clientX, clientY);
} else if (o.revertOnSpill === true && !_copy) {
reference = _initialSibling;
dropTarget = _source;
} else {
if (_copy && parent) {
parent.removeChild(item);
}
return;
}
if (
(reference === null && changed) ||
reference !== item &&
reference !== nextEl(item)
) {
_currentSibling = reference;
dropTarget.insertBefore(item, reference);
drake.emit('shadow', item, dropTarget, _source);
}
function moved(type) {
drake.emit(type, item, _lastDropTarget, _source);
}
function over() {
if (changed) {
moved('over');
}
}
function out() {
if (_lastDropTarget) {
moved('out');
}
}
}
function spillOver(el) {
classes.rm(el, 'gu-hide');
}
function spillOut(el) {
if (drake.dragging) {
classes.add(el, 'gu-hide');
}
}
function renderMirrorImage() {
if (_mirror) {
return;
}
var rect = _item.getBoundingClientRect();
_mirror = _item.cloneNode(true);
_mirror.style.width = getRectWidth(rect) + 'px';
_mirror.style.height = getRectHeight(rect) + 'px';
classes.rm(_mirror, 'gu-transit');
classes.add(_mirror, 'gu-mirror');
o.mirrorContainer.appendChild(_mirror);
touchy(documentElement, 'add', 'mousemove', drag);
classes.add(o.mirrorContainer, 'gu-unselectable');
drake.emit('cloned', _mirror, _item, 'mirror');
}
function removeMirrorImage() {
if (_mirror) {
classes.rm(o.mirrorContainer, 'gu-unselectable');
touchy(documentElement, 'remove', 'mousemove', drag);
getParent(_mirror).removeChild(_mirror);
_mirror = null;
}
}
function getImmediateChild(dropTarget, target) {
var immediate = target;
while (immediate !== dropTarget && getParent(immediate) !== dropTarget) {
immediate = getParent(immediate);
}
if (immediate === documentElement) {
return null;
}
return immediate;
}
function getReference(dropTarget, target, x, y) {
var horizontal = o.direction === 'horizontal';
var reference = target !== dropTarget ? inside() : outside();
return reference;
function outside() { // slower, but able to figure out any position
var len = dropTarget.children.length;
var i;
var el;
var rect;
for (i = 0; i < len; i++) {
el = dropTarget.children[i];
rect = el.getBoundingClientRect();
if (horizontal && (rect.left + rect.width / 2) > x) {
return el;
}
if (!horizontal && (rect.top + rect.height / 2) > y) {
return el;
}
}
return null;
}
function inside() { // faster, but only available if dropped inside a child element
var rect = target.getBoundingClientRect();
if (horizontal) {
return resolve(x > rect.left + getRectWidth(rect) / 2);
}
return resolve(y > rect.top + getRectHeight(rect) / 2);
}
function resolve(after) {
return after ? nextEl(target) : target;
}
}
function isCopy(item, container) {
return typeof o.copy === 'boolean' ? o.copy : o.copy(item, container);
}
}
function touchy(el, op, type, fn) {
var touch = {
mouseup: 'touchend',
mousedown: 'touchstart',
mousemove: 'touchmove'
};
var pointers = {
mouseup: 'pointerup',
mousedown: 'pointerdown',
mousemove: 'pointermove'
};
var microsoft = {
mouseup: 'MSPointerUp',
mousedown: 'MSPointerDown',
mousemove: 'MSPointerMove'
};
if (global.navigator.pointerEnabled) {
crossvent[op](el, pointers[type], fn);
} else if (global.navigator.msPointerEnabled) {
crossvent[op](el, microsoft[type], fn);
} else {
crossvent[op](el, touch[type], fn);
crossvent[op](el, type, fn);
}
}
function whichMouseButton(e) {
if (e.touches !== void 0) {
return e.touches.length;
}
if (e.which !== void 0 && e.which !== 0) {
return e.which;
} // see https://github.com/bevacqua/dragula/issues/261
if (e.buttons !== void 0) {
return e.buttons;
}
var button = e.button;
if (button !== void 0) { // see https://github.com/jquery/jquery/blob/99e8ff1baa7ae341e94bb89c3e84570c7c3ad9ea/src/event.js#L573-L575
return button & 1 ? 1 : button & 2 ? 3 : (button & 4 ? 2 : 0);
}
}
function getOffset(el) {
var rect = el.getBoundingClientRect();
return {
left: rect.left + getScroll('scrollLeft', 'pageXOffset'),
top: rect.top + getScroll('scrollTop', 'pageYOffset')
};
}
function getScroll(scrollProp, offsetProp) {
if (typeof global[offsetProp] !== 'undefined') {
return global[offsetProp];
}
if (documentElement.clientHeight) {
return documentElement[scrollProp];
}
return doc.body[scrollProp];
}
function getElementBehindPoint(point, x, y) {
var p = point || {};
var state = p.className;
var el;
p.className += ' gu-hide';
el = doc.elementFromPoint(x, y);
p.className = state;
return el;
}
function never() {
return false;
}
function always() {
return true;
}
function getRectWidth(rect) {
return rect.width || (rect.right - rect.left);
}
function getRectHeight(rect) {
return rect.height || (rect.bottom - rect.top);
}
function getParent(el) {
return el.parentNode === doc ? null : el.parentNode;
}
function isInput(el) {
return el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' || el.tagName === 'SELECT' || isEditable(el);
}
function isEditable(el) {
if (!el) {
return false;
} // no parents were editable
if (el.contentEditable === 'false') {
return false;
} // stop the lookup
if (el.contentEditable === 'true') {
return true;
} // found a contentEditable element in the chain
return isEditable(getParent(el)); // contentEditable is set to 'inherit'
}
function nextEl(el) {
return el.nextElementSibling || manually();
function manually() {
var sibling = el;
do {
sibling = sibling.nextSibling;
} while (sibling && sibling.nodeType !== 1);
return sibling;
}
}
function getEventHost(e) {
// on touchend event, we have to use `e.changedTouches`
// see http://stackoverflow.com/questions/7192563/touchend-event-properties
// see https://github.com/bevacqua/dragula/issues/34
if (e.targetTouches && e.targetTouches.length) {
return e.targetTouches[0];
}
if (e.changedTouches && e.changedTouches.length) {
return e.changedTouches[0];
}
return e;
}
function getCoord(coord, e) {
var host = getEventHost(e);
var missMap = {
pageX: 'clientX', // IE8
pageY: 'clientY' // IE8
};
if (coord in missMap && !(coord in host) && missMap[coord] in host) {
coord = missMap[coord];
}
return host[coord];
}
module.exports = dragula;
}).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
}, {
"./classes": 8,
"contra/emitter": 4,
"crossvent": 5
}],
10: [function (require, module, exports) {
var si = typeof setImmediate === 'function',
tick;
if (si) {
tick = function (fn) {
setImmediate(fn);
};
} else {
tick = function (fn) {
setTimeout(fn, 0);
};
}
module.exports = tick;
}, {}]
}, {}, [1]);