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