From f43e935bef5987d202b59ab82e41e6fdc5cab3b1 Mon Sep 17 00:00:00 2001 From: bertolds Date: Mon, 15 Jun 2015 13:00:03 -0400 Subject: [PATCH] Issues #275, #363 - individual Timeline items editable or readonly Timeline will check for the property 'editable' on individual items. if editable === true ignore timeline option 'editable' allow item to be edited else if editable === false ignore timeline option 'editable' do not allow item to be edited else use timeline option 'editable' If two items are selected and one is not editable, only the editable item is draggable. This change required the css class .vis-editable be moved from the item set to the individual item containers to maintain proper styling. --- docs/timeline/index.html | 19 +++++++++++-- lib/timeline/component/ItemSet.js | 35 ++++++++++++++++++------ lib/timeline/component/css/item.css | 2 +- lib/timeline/component/item/BoxItem.js | 8 +++++- lib/timeline/component/item/Item.js | 17 +++++++++++- lib/timeline/component/item/PointItem.js | 8 +++++- lib/timeline/component/item/RangeItem.js | 8 +++++- 7 files changed, 81 insertions(+), 16 deletions(-) diff --git a/docs/timeline/index.html b/docs/timeline/index.html index eaa79b60..81af2829 100644 --- a/docs/timeline/index.html +++ b/docs/timeline/index.html @@ -203,8 +203,8 @@ The Timeline uses regular Arrays and Objects as data format. Data items can contain the properties start, end (optional), content, - group (optional), className (optional), - and style (optional). + group (optional), className (optional), + editable (optional), and style (optional).

@@ -325,6 +325,11 @@ var items = [ Types 'box' and 'point' need a start date, the types 'range' and 'background' needs both a start and end date. + + editable + Boolean + no + Override the editable option of the timeline for a specific item.

Groups

@@ -1323,6 +1328,16 @@ var options = { } }; +

+ Editing can be enabled/disabled for specific items. Setting the property editable to true or false on a data item will override the timeline option. +

+ +
+var items = new vis.DataSet([
+  {id: 1, content: 'read-only item', start: '2013-04-20', editable: false},
+  {id: 2, content: 'editable item', start: '2013-04-14'}
+]);
+

One can specify callback functions to validate changes made by the user. There are a number of callback functions for this purpose: diff --git a/lib/timeline/component/ItemSet.js b/lib/timeline/component/ItemSet.js index 43c27871..3bdb5895 100644 --- a/lib/timeline/component/ItemSet.js +++ b/lib/timeline/component/ItemSet.js @@ -508,15 +508,14 @@ ItemSet.prototype.redraw = function() { options = this.options, orientation = options.orientation.item, resized = false, - frame = this.dom.frame, - editable = options.editable.updateTime || options.editable.updateGroup; + frame = this.dom.frame; // recalculate absolute position (before redrawing groups) this.props.top = this.body.domProps.top.height + this.body.domProps.border.top; this.props.left = this.body.domProps.left.width + this.body.domProps.border.left; // update class name - frame.className = 'vis-itemset' + (editable ? ' vis-editable' : ''); + frame.className = 'vis-itemset'; // reorder the groups (if needed) resized = this._orderGroups() || resized; @@ -1116,15 +1115,23 @@ ItemSet.prototype._onTouch = function (event) { * @private */ ItemSet.prototype._onDragStart = function (event) { - if (!this.options.editable.updateTime && !this.options.editable.updateGroup) { - return; - } - var item = this.touchParams.item || null; var me = this; var props; if (item && item.selected) { + + if (!this.options.editable.updateTime && + !this.options.editable.updateGroup && + !item.editable) { + return; + } + + // override options.editable + if (item.editable === false) { + return; + } + var dragLeftItem = this.touchParams.dragLeftItem; var dragRightItem = this.touchParams.dragRightItem; @@ -1239,7 +1246,14 @@ ItemSet.prototype._onDrag = function (event) { var itemData = util.extend({}, props.item.data); // clone the data - if (me.options.editable.updateTime) { + if (props.item.editable === false) { + return; + } + + var updateTimeAllowed = me.options.editable.updateTime || + props.item.editable === true; + + if (updateTimeAllowed) { if (props.dragLeft) { // drag left side of a range item if (itemData.start != undefined) { @@ -1276,7 +1290,10 @@ ItemSet.prototype._onDrag = function (event) { } } - if (me.options.editable.updateGroup && (!props.dragLeft && !props.dragRight)) { + var updateGroupAllowed = me.options.editable.updateGroup || + props.item.editable === true; + + if (updateGroupAllowed && (!props.dragLeft && !props.dragRight)) { if (itemData.group != undefined) { // drag from one group to another var group = me.groupFromTarget(event); diff --git a/lib/timeline/component/css/item.css b/lib/timeline/component/css/item.css index 7d33e68a..e843e1e0 100644 --- a/lib/timeline/component/css/item.css +++ b/lib/timeline/component/css/item.css @@ -17,7 +17,7 @@ z-index: 2; } -.vis-editable .vis-item.vis-selected { +.vis-editable.vis-selected { cursor: move; } diff --git a/lib/timeline/component/item/BoxItem.js b/lib/timeline/component/item/BoxItem.js index efc15f85..9af67992 100644 --- a/lib/timeline/component/item/BoxItem.js +++ b/lib/timeline/component/item/BoxItem.js @@ -110,9 +110,15 @@ BoxItem.prototype.redraw = function() { this._updateDataAttributes(this.dom.box); this._updateStyle(this.dom.box); + var editable = (this.options.editable.updateTime || + this.options.editable.updateGroup || + this.editable === true) && + this.editable !== false; + // update class var className = (this.data.className? ' ' + this.data.className : '') + - (this.selected ? ' vis-selected' : ''); + (this.selected ? ' vis-selected' : '') + + (editable ? ' vis-editable' : ''); dom.box.className = 'vis-item vis-box' + className; dom.line.className = 'vis-item vis-line' + className; dom.dot.className = 'vis-item vis-dot' + className; diff --git a/lib/timeline/component/item/Item.js b/lib/timeline/component/item/Item.js index b940160c..d25fcb43 100644 --- a/lib/timeline/component/item/Item.js +++ b/lib/timeline/component/item/Item.js @@ -26,6 +26,13 @@ function Item (data, conversion, options) { this.left = null; this.width = null; this.height = null; + + this.editable = null; + if (this.data && + this.data.hasOwnProperty('editable') && + typeof this.data.editable === 'boolean') { + this.editable = data.editable; + } } Item.prototype.stack = true; @@ -59,6 +66,10 @@ Item.prototype.setData = function(data) { this.parent.itemSet._moveToGroup(this, data.group); } + if (data.hasOwnProperty('editable') && typeof data.editable === 'boolean') { + this.editable = data.editable; + } + this.data = data; this.dirty = true; if (this.displayed) this.redraw(); @@ -134,7 +145,11 @@ Item.prototype.repositionY = function() { * @protected */ Item.prototype._repaintDeleteButton = function (anchor) { - if (this.selected && this.options.editable.remove && !this.dom.deleteButton) { + var editable = (this.options.editable.remove || + this.data.editable === true) && + this.data.editable !== false; + + if (this.selected && editable && !this.dom.deleteButton) { // create and show button var me = this; diff --git a/lib/timeline/component/item/PointItem.js b/lib/timeline/component/item/PointItem.js index 7c6bd6d4..230895c2 100644 --- a/lib/timeline/component/item/PointItem.js +++ b/lib/timeline/component/item/PointItem.js @@ -99,9 +99,15 @@ PointItem.prototype.redraw = function() { this._updateDataAttributes(this.dom.point); this._updateStyle(this.dom.point); + var editable = (this.options.editable.updateTime || + this.options.editable.updateGroup || + this.editable === true) && + this.editable !== false; + // update class var className = (this.data.className ? ' ' + this.data.className : '') + - (this.selected ? ' vis-selected' : ''); + (this.selected ? ' vis-selected' : '') + + (editable ? ' vis-editable' : ''); dom.point.className = 'vis-item vis-point' + className; dom.dot.className = 'vis-item vis-dot' + className; diff --git a/lib/timeline/component/item/RangeItem.js b/lib/timeline/component/item/RangeItem.js index 64b80a97..d2e7b763 100644 --- a/lib/timeline/component/item/RangeItem.js +++ b/lib/timeline/component/item/RangeItem.js @@ -99,9 +99,15 @@ RangeItem.prototype.redraw = function() { this._updateDataAttributes(this.dom.box); this._updateStyle(this.dom.box); + var editable = (this.options.editable.updateTime || + this.options.editable.updateGroup || + this.editable === true) && + this.editable !== false; + // update class var className = (this.data.className ? (' ' + this.data.className) : '') + - (this.selected ? ' vis-selected' : ''); + (this.selected ? ' vis-selected' : '') + + (editable ? ' vis-editable' : ''); dom.box.className = this.baseClassName + className; // determine from css whether this box has overflow