diff --git a/lib/timeline/component/ItemSet.js b/lib/timeline/component/ItemSet.js index 52d5ded3..46af2ec9 100644 --- a/lib/timeline/component/ItemSet.js +++ b/lib/timeline/component/ItemSet.js @@ -35,13 +35,21 @@ function ItemSet(body, options) { align: 'auto', // alignment of box items stack: true, groupsDraggable: false, - groupOrder: function(a,b) { - if (a.order != undefined && b.order != undefined) { - return (a.order - b.order); - } else { - return 0; - } + moveBefore: function(draggedGroup, targetGroup, groups) { + var targetOrder = targetGroup.order; + targetGroup.order = draggedGroup.order; + draggedGroup.order = targetOrder; + groups.update(draggedGroup); + groups.update(targetGroup); }, +// groupOrder: function(a,b) { +// if (a.order != undefined && b.order != undefined) { +// return (a.order - b.order); +// } else { +// return 0; +// } +// }, + groupOrder: 'order', selectable: true, multiselect: false, @@ -53,6 +61,12 @@ function ItemSet(body, options) { remove: false }, + groupEditable: { + order: false, + add: false, + remove: false + }, + snap: TimeStep.snap, onAdd: function (item, callback) { @@ -294,7 +308,7 @@ ItemSet.prototype._create = function(){ ItemSet.prototype.setOptions = function(options) { if (options) { // copy all options that we know - var fields = ['type', 'align', 'order', 'stack', 'selectable', 'multiselect', 'groupOrder', 'dataAttributes', 'template', 'groupTemplate', 'hide', 'snap', 'groupsDraggable']; + var fields = ['type', 'align', 'order', 'stack', 'selectable', 'multiselect', 'groupOrder', 'dataAttributes', 'template', 'groupTemplate', 'hide', 'snap', 'moveBefore']; util.selectiveExtend(fields, this.options, options); if ('orientation' in options) { @@ -337,6 +351,17 @@ ItemSet.prototype.setOptions = function(options) { util.selectiveExtend(['updateTime', 'updateGroup', 'add', 'remove'], this.options.editable, options.editable); } } + + if ('groupEditable' in options) { + if (typeof options.groupEditable === 'boolean') { + this.options.groupEditable.order = options.groupEditable; + this.options.groupEditable.add = options.groupEditable; + this.options.groupEditable.remove = options.groupEditable; + } + else if (typeof options.groupEditable === 'object') { + util.selectiveExtend(['order', 'add', 'remove'], this.options.groupEditable, options.groupEditable); + } + } // callback functions var addCallback = (function (name) { @@ -1404,38 +1429,151 @@ ItemSet.prototype._onDragEnd = function (event) { }; ItemSet.prototype._onGroupDragStart = function (event) { - if (this.options.groupsDraggable) { + if (this.options.groupEditable.order) { this.groupTouchParams.group = this.groupFromTarget(event); + if (this.groupTouchParams.group) { event.stopPropagation(); + + this.groupTouchParams.originalOrder = this.groupsData.getIds({ + order: this.options.groupOrder + }); } } } ItemSet.prototype._onGroupDrag = function (event) { - if (this.options.groupsDraggable && this.groupTouchParams.group) { + if (this.options.groupEditable.order && this.groupTouchParams.group) { event.stopPropagation(); // drag from one group to another var group = this.groupFromTarget(event); if (group && group != this.groupTouchParams.group) { var groupsData = this.groupsData; - var draggedGroup = groupsData.get(this.groupTouchParams.group.groupId); var targetGroup = groupsData.get(group.groupId); + var draggedGroup = groupsData.get(this.groupTouchParams.group.groupId); if (draggedGroup && targetGroup) { - var targetOrder = targetGroup.order; - targetGroup.order = draggedGroup.order; - groupsData.update(targetGroup); - draggedGroup.order = targetOrder; - groupsData.update(draggedGroup); + this.options.moveBefore(draggedGroup, targetGroup, this.groupsData); } + + var newOrder = this.groupsData.getIds({ + order: this.options.groupOrder + }); + + if (!util.equalArray(newOrder, this.groupTouchParams.originalOrder)) { + var groupsData = this.groupsData; + var origOrder = this.groupTouchParams.originalOrder; + var draggedId = this.groupTouchParams.group.groupId; + var numGroups = Math.min(origOrder.length, newOrder.length); + var curPos = 0; + var newOffset = 0; + var orgOffset = 0; + while (curPos < numGroups) { + // as long as the groups are where they should be step down along the groups order + while ((curPos+newOffset) < numGroups + && (curPos+orgOffset) < numGroups + && newOrder[curPos+newOffset] == origOrder[curPos+orgOffset]) { + curPos++; + } + + // all ok + if (curPos+newOffset >= numGroups) { + break; + } + + // not all ok -> since we start from the first group, did we reach the dragged group? + if (newOrder[curPos+newOffset] == draggedId) { + newOffset = 1; + continue; + } else if (origOrder[curPos+orgOffset] == draggedId) { + orgOffset = 1; + continue; + } else { + var slippedPosition = newOrder.indexOf(origOrder[curPos+orgOffset]) + var switchGroup = groupsData.get(newOrder[curPos+newOffset]); + var shouldBeGroup = groupsData.get(origOrder[curPos+orgOffset]); + this.options.moveBefore(switchGroup, shouldBeGroup, groupsData); + + var switchGroupId = newOrder[curPos+newOffset]; + newOrder[curPos+newOffset] = origOrder[curPos+orgOffset]; + newOrder[slippedPosition] = switchGroupId; + + curPos++; + } + } + } + } } } ItemSet.prototype._onGroupDragEnd = function (event) { - if (this.options.groupsDraggable) { + if (this.options.groupEditable.order && this.groupTouchParams.group) { + event.stopPropagation(); + + var newOrder = this.groupsData.getIds({ + order: this.options.groupOrder + }); + + if (!util.equalArray(newOrder, this.groupTouchParams.originalOrder)) { + var groupsData = this.groupsData; + var origOrder = this.groupTouchParams.originalOrder; + var draggedId = this.groupTouchParams.group.groupId; + var numGroups = Math.min(origOrder.length, newOrder.length); + var curPos = 0; + var newOffset = 0; + var orgOffset = 0; + while (curPos < numGroups) { + // as long as the groups are where they should be step down along the groups order + while ((curPos+newOffset) < numGroups + && (curPos+orgOffset) < numGroups + && newOrder[curPos+newOffset] == origOrder[curPos+orgOffset]) { + curPos++; + } + + // all ok + if (curPos+newOffset >= numGroups) { + break; + } + + // not all ok -> since we start from the first group, did we reach the dragged group? + if (newOrder[curPos+newOffset] == draggedId) { + newOffset = 1; + continue; + } else if (origOrder[curPos+orgOffset] == draggedId) { + orgOffset = 1; + continue; + } else { + var slippedPosition = newOrder.indexOf(origOrder[curPos+orgOffset]) + var switchGroup = groupsData.get(newOrder[curPos+newOffset]); + var shouldBeGroup = groupsData.get(origOrder[curPos+orgOffset]); + this.options.moveBefore(switchGroup, shouldBeGroup, groupsData); + + var switchGroupId = newOrder[curPos+newOffset]; + newOrder[curPos+newOffset] = origOrder[curPos+orgOffset]; + newOrder[slippedPosition] = switchGroupId; + + curPos++; + } + } + } + + +// // drag from one group to another +// var group = this.groupFromTarget(event); +// if (group && group != this.groupTouchParams.group) { +// var draggedGroup = groupsData.get(this.groupTouchParams.group.groupId); +// var targetGroup = groupsData.get(group.groupId); +// +// if (draggedGroup && targetGroup) { +// var targetOrder = targetGroup.order; +// targetGroup.order = draggedGroup.order; +// groupsData.update(targetGroup); +// draggedGroup.order = targetOrder; +// groupsData.update(draggedGroup); +// } +// } this.body.emitter.emit('groupDragged'); } } diff --git a/lib/timeline/optionsTimeline.js b/lib/timeline/optionsTimeline.js index 12644c2a..5d588d3b 100644 --- a/lib/timeline/optionsTimeline.js +++ b/lib/timeline/optionsTimeline.js @@ -63,7 +63,13 @@ let allOptions = { __type__: {object} }, groupOrder: {string, 'function': 'function'}, - groupsDraggable: {boolean}, + groupEditable: { + add: {boolean, 'undefined': 'undefined'}, + remove: {boolean, 'undefined': 'undefined'}, + order: {boolean, 'undefined': 'undefined'}, + __type__: {boolean, object} + }, + moveBefore: {'function': 'function'}, height: {string, number}, hiddenDates: {object, array}, locale:{string},