this.__apply__ = function(_op, options) { //console.log("Graph.__apply__", op); // Note: we apply compounds eagerly... i.e., all listeners will be updated after // each atomic change. Operator.Helpers.each(_op, function(op) { if (!(op instanceof Operator.ObjectOperation)) { op = Operator.ObjectOperation.fromJSON(op); } op.apply(this.objectAdapter); this.updated_at = new Date(); this._internalUpdates(op); _.each(this.indexes, function(index) { // Treating indexes as first class listeners for graph changes index.onGraphChange(op); }, this); // And all regular listeners in second line this.trigger('operation:applied', op, this, options); }, this); };
this.__apply__ = function(_op, options) { //console.log("Graph.__apply__", op); // Note: we apply compounds eagerly... i.e., all listeners will be updated after // each atomic change. Operator.Helpers.each(_op, function(op) { if (!(op instanceof Operator.ObjectOperation)) { op = Operator.ObjectOperation.fromJSON(op); } op.apply(this.objectAdapter); this.updated_at = new Date(); this._internalUpdates(op); _.each(this.indexes, function(index) { // Treating indexes as first class listeners for graph changes index.onGraphChange(op); }, this); // provide the target node which is affected by this operation var target; if (op.type === "create" || op.type === "delete") { target = op.val; } else { target = this.get(op.path[0]); } // And all regular listeners in second line this.trigger('operation:applied', op, this, target, options); }, this); };
this._internalUpdates = function(op) { // Treating indexes as first class listeners for graph changes Operator.Helpers.each(op, function(_op) { _.each(this.indexes, function(index) { index.onGraphChange(_op); }, this); }, this); };
this.getChangePosition = function(op) { if (op.path[1] === "content") { var lastChange = Operator.Helpers.last(op.diff); if (lastChange.isInsert()) { return lastChange.pos+lastChange.length(); } else if (lastChange.isDelete()) { return lastChange.pos; } } return -1; };
this.cotransform = function(adapter, op) { if (op.type === "create") { adapter.create(op.val); } else if (op.type === "delete") { adapter.delete(op.val); } // type = 'update' or 'set' else { var prop = this.resolve(op.path); if (prop === undefined) { throw new Error("Key error: could not find element for path " + JSON.stringify(op.path)); } var value = prop.get(); var oldValue; // Attention: this happens when updates and deletions are within one compound // The operation gets applied, finally the node is deleted. // Listeners are triggered afterwards, so they can not rely on the node being there // anymore. // However, this is not a problem. We can ignore this update as there will come // a deletion anyways. if (value === undefined) { return; } if (op.type === "set") { oldValue = op.original; } else { var invertedDiff = Operator.Helpers.invert(op.diff, prop.baseType); oldValue = invertedDiff.apply(_.clone(value)); } adapter.update(prop.node, prop.key, value, oldValue); } };
var _triggerPropertyUpdate = function(path, diff) { Operator.Helpers.each(diff, function(op) { this.trigger('property:updated', path, op, this); }, this); };