function(spec) { if (spec) { Util.Log.Info("Found clone spec", spec); } var cloneKids = clone.value.children(); if (self.children.length != cloneKids.length) { Util.Log.Error("Trying to clone CTS node that is out of sync with dom"); } // We use THIS to set i var kidPromises = []; for (var i = 0; i < cloneKids.length; i++) { var $child = Util.$(cloneKids[i]); kidPromises.push(self.children[i]._subclass_beginClone($child)); } if (kidPromises.length == 0) { d.resolve(clone); } else { Util.Promise.all(kidPromises).then( function(kids) { for (var i = 0; i < kids.length; i++) { kids[i].parentNode = clone; clone.children.push(kids[i]); } d.resolve(clone); }, function(reason) { d.reject(reason); } ); } },
_onTreeValueChanged: function(evt) { Util.Log.Info("Forrest caught tree value change"); var node = evt.sourceNode; var tree = evt.sourceTree; if (node._subclass_shouldRunCtsOnInsertion()) { var links = node._subclass_getTreesheetLinks(); var promises = self.parseAndAddSpecsFromLinks(ctsLinks); Util.Promise.all(promises).then( function() { // Creae the CTS tree for this region. Util.Log.Info("Running onChildInserted", prnt); var node = prnt._onChildInserted($node); }, function(errors) { Util.Log.Error("Couldn't add CTS blocks from inserted dom node", errors); } ).done(); } // If the tree is the main tree, we might run some CTS. // If the tree is the main tree, we want to possibly run any CTS var self = this; if (typeof evt.ctsHandled == 'undefined') { var node = tree.getCtsNode(evt.node); if (node == null) { if (! evt.node.hasClass("cts-ignore")) { Util.Log.Info("Insertion", evt.node); // Get the parent var $prnt = evt.node.parent(); var prnt = tree.getCtsNode($prnt); if (prnt == null) { // Util.Log.Error("Node inserted into yet unmapped region of tree", prnt); } else { // First see if any CTS blocks live in this region var ctsLinks = Util.Helper.getTreesheetLinks(evt.node); var promises = self.parseAndAddSpecsFromLinks(ctsLinks); Util.Promise.all(promises).then( function() { // Create the CTS tree for this region. Util.Log.Info("Running onChildInserted", prnt); var node = prnt._onChildInserted(evt.node); }, function(errors) { Util.Log.Error("Couldn't add CTS blocks from inserted dom node", errors); } ).done(); } } } evt.ctsHandled = true; } }
function(clone) { if (typeof clone == 'undefined') { Util.Log.Fatal("Subclass did not clone itself when asked."); deferred.reject("Subclass did not clone itself when asked"); } else { if (clone.relations.length > 0) { Util.Log.Error("Clone shouldn't have relations yet, but does", clone); } clone.parentNode = self.parentNode; // Note that we DON'T wire up any parent-child relationships // because that would result in more than just cloning the node // but also modifying other structures, such as the tree which // contained the source. if (cloneRelations || moveRelationsForSubtree) { self.recursivelyCloneRelations(clone, moveRelationsForSubtree, filterFn); } // For the love of god, make the asynchronicity stop if (runBeforeAnyPersistenceFn) { if (clone._subclass_endClone) { runBeforeAnyPersistenceFn(clone).then( function() { clone._subclass_endClone().then( function() { deferred.resolve(clone) }, function(reason) { deferred.reject(reason); } ).done(); }, function(reason) { deferred.reject(reason); } ).done(); } else { runBeforeAnyPersistenceFn(clone).then( function() { deferred.resolve(clone) }, function(reason) { deferred.reject(reason); } ).done(); } } else { if (clone._subclass_endClone) { clone._subclass_endClone().then( function() { deferred.resolve(clone) }, function(reason) { deferred.reject(reason); } ).done(); } else { deferred.resolve(clone); } } } },
function(gdata) { Util.Log.Debug("Got cell feed worksheet", gdata); self.gdata = gdata; for (var rowName in gdata.rows) { var columns = gdata.rows[rowName]; var child = new GColumnNode(rowName, columns, self.tree, self.opts); child.parentNode = self; self.children.push(child); } Util.Log.Debug("Resolving Worksheet Kids"); deferred.resolve(); },
realizeChildren: function() { var deferred = Util.Promise.defer(); if (this.children.length != 0) { Util.Log.Fatal("Trying to realize children when already have some.", this); deferred.reject("Trying to realize when children > 0"); } var self = this; var sc = this._subclass_realizeChildren(); sc.then( function() { var promises = Util._.map(self.children, function(child) { return child.realizeChildren(); }); Util.Promise.all(promises).then( function() { deferred.resolve(); }, function(reason) { deferred.reject(reason); } ).done(); }, function(reason) { deferred.reject(reason); } ).done(); return deferred.promise; },
listenForNodeInsertionsOnTree: function(treeName, new_val) { // CURRENT STATUS var tree = this.trees[treeName]; var listening = (treeName in this.insertionListeners); var self = this; // ERROR if (typeof tree == 'undefined'){ Util.Log.Error("listenForNodeInsertion (" + new_val + "):" + "Tree " + treeName + " not present."); return false; } // GET if (typeof new_val == 'undefined') { return listening; } // SET if (new_val == true) { tree.root.toggleThrowDataEvents(true); tree.on('ValueChanged', this._onTreeValueChanged, this); return true; } else if (new_val == false) { tree.root.toggleThrowDataEvents(false); tree.off('ValueChanged', this._onTreeValueChanged, this); delete this.insertionListeners[treeName]; } },
recursivelyCloneRelations: function(to, moveRelationsForSubtree, filterFn) { if (typeof to == 'undefined') { debugger; } var r = this.getRelations(); if (to.relations && (to.relations.length > 0)) { Util.Log.Error("Clone relations to non-empty relation container. Blowing away"); while (to.relations.length > 0) { to.relations[0].destroy(); } } for (var i = 0; i < r.length; i++) { if ((! filterFn) || filterFn(r[i])) { var n1 = r[i].node1; var n2 = r[i].node2; var other; if (n1 == this) { n1 = to; other = n2; } else if (n2 == this) { n2 = to; other = n1; } else { Util.Log.Fatal("Clone failed. Found relation not attached to cloning node."); } var relationClone = r[i].clone(n1, n2); if (moveRelationsForSubtree) { if (other.equals(moveRelationsForSubtree) || other.isDescendantOf(moveRelationsForSubtree)) { // Remove the original! r[i].destroy(); } } } }; for (var j = 0; j < this.getChildren().length; j++) { var myKid = this.children[j]; var otherKid = to.children[j]; if (typeof otherKid == 'undefined') { Util.Log.Error("Cloned children out of sync with origin children."); } myKid.recursivelyCloneRelations(otherKid, moveRelationsForSubtree, filterFn); } },
find: function(selectorString) { var spec = Parser.parseSelectorString(selectorString); if (typeof this.trees[spec.treeName] != 'undefined') { return new Selection(this.trees[spec.treeName].find(spec)); } else { Util.Log.Warn("No tree named: " + spec.treeName); return new Selection([]); } },
addRelationSpecs: function(someRelationSpecs) { for (var i = 0; i < someRelationSpecs.length; i++) { // Faster than .push() if (typeof this.relationSpecs == 'undefined') { Util.Log.Error("relation undefined"); } this.relationSpecs.push(someRelationSpecs[i]); } },
_subclass_realizeChildren: function() { Util.Log.Debug("GColumn Realize Children"); this.children = []; for (var rowName in this.columns) { var spec = this.columns[rowName]; var child = new GColumnCellNode(rowName, spec, this.tree, this.opts); child.parentNode = this; this.children.push(child); } return Util.Promise.resolve(); },
find: function(selector, ret) { if (typeof ret == 'undefined') { ret = []; } if (this.value.is(selector)) { if (typeof ret == 'undefined') { Util.Log.Error("push"); } ret.push(this); } for (var i = 0; i < this.children.length; i++) { if (this.children[i] == null) { Util.Log.Error("Error: Child " + i + " of me is null (find:" + selector + ")", this); } else { if (typeof this.children[i] == 'undefined') { Util.Log.Error("Undefined child"); } this.children[i].find(selector, ret); } } return ret; },
getProvenance: function() { if (this.provenance == null) { if (this.parentNode == null) { // We're the root of a tree. This is an error: the root should always know where it // came from. Util.Log.Error("Root of tree has no provenance information"); return null; } else { return this.parentNode.getProvenance(); } } else { return this.provenance; } },
parseInlineRelationSpecs: function() { var deferred = Util.Promise.defer(); var self = this; // Already added if (this.parsedInlineRelationSpecs === true) { Util.Log.Warn("Not registering inline relations: have already done so."); deferred.resolve(); return deferred.promise; } self.parsedInlineRelationSpecs = true; var specStr = this._subclass_getInlineRelationSpecString(); // No inline spec if (! specStr) { deferred.resolve(); return deferred.promise; } if (typeof this.tree == 'undefined') { deferred.reject("Undefined tree"); return deferred.promise; } if (typeof this.tree.forrest == 'undefined') { deferred.reject("Undefined forrest"); return deferred.promise; } var self = this; Parser.parseInlineSpecs(specStr, self, self.tree.forrest, true).then( function(forrestSpecs) { Util._.each(forrestSpecs, function(forrestSpec) { if (typeof forrestSpec.relationSpecs != 'undefined') { self.inlineRelationSpecs = forrestSpec.relationSpecs; } }); deferred.resolve(); }, function(reason) { deferred.reject(reason); } ).done(); return deferred.promise; },
setValue: function(value, opts) { this.value = value; var self = this; Util.Log.Info("Column Cell setting to ", value, this); var promise = GSheetUtil.modifyCell( this.getSpreadsheetKey(), this.getWorksheetKey(), this.getRowNum(), this.getColNum(), value).then( function() { self.parentNode.parentNode.updateComputedNodes(); }, function(reason) { Util.Log.Error("Cell update failed", reason); } ).done(); },
function(tree) { // Realize relations again Util.Log.Info("Re-Realized tree", name); for (var i = 0; i < self.relationSpecs.length; i++) { var spec = self.relationSpecs[i]; if ((spec.selectionSpec1.treeName == name) || (spec.selectionSpec2.treeName == name)) { self.realizeRelation(spec); } } if (render) { self.trees[name].root._processIncoming(); // Resume listening maybe self.listenForNodeInsertionsOnTree(name, listenValue); deferred.resolve(); } else { // Resume listening maybe self.listenForNodeInsertionsOnTree(name, listenValue); deferred.resolve(); } },
function() { if (ws) { Util.Log.Info("Looking for worksheed named ", ws); var found = false; for (var i = 0; i < ss.children.length; i++) { var child = ss.children[i]; if ((! found) && (child.name == treespec.worksheet)) { tree.root = child; found = true; if (treespec.receiveEvents) { tree.toggleReceiveRelationEvents(true); } promise.resolve(tree); } } if (! found) { promise.reject("Couldn't find worksheet named: " + treespec.worksheet); } } else { tree.root = ss; promise.resolve(tree); } },
var promises = Util._.map(links, function(block) { var deferred = Util.Promise.defer(); if (block.type == 'link') { Util.Net.fetchString(block).then( function(content) { var url = block.url; self.parseAndAddSpec(content, block.format, url).then( function() { deferred.resolve(); }, function(reason) { Util.Log.Error("Could not parse and add spec", content, block); deferred.resolve(); } ).done(); }, function(reason) { Util.Log.Error("Could not fetch CTS link:", block); deferred.resolve(); }); } else if (block.type == 'block') { var url = window.location; self.parseAndAddSpec(block.content, block.format, url).then( function() { deferred.resolve(); }, function(reason) { Util.Log.Error("Could not parse and add spec", content, block); deferred.resolve(); } ).done(); } else { Util.Log.Error("Could not load CTS: did not understand block type", block.block, block); deferred.resolve(); } return deferred.promise; });
_maybeThrowDataEvent: function(evt) { if (this.shouldThrowEvents) { if (evt.ctsNode) { evt.newValue = evt.ctsNode.getValue(); if (evt.eventName == 'ValueChanged') { // Maybe squash if we're in an echo chamber. if (this._lastValueChangedValue == evt.newValue) { // An echo! Stop it here. Util.Log.Info("Suppressing event echo", this, evt); this._lastValueChangedValue = null; return; } else { this._lastValueChangedValue = evt.newValue; evt.sourceNode = this; evt.sourceTree = this.tree; this.trigger(evt.eventName, evt); if (this.tree && this.tree.trigger) { this.tree.trigger(evt.eventName, evt); // Throw it for the tree, too. } } } } } },
CreateFromSpec: function(node1, node2, spec) { if (spec.name == 'is') { return new Is(node1, node2, spec); } else if (spec.name == 'are') { return new Are(node1, node2, spec); } else if (spec.name == 'creates') { return new Creates(node1, node2, spec); } else if (spec.name == 'updates') { return new Updates(node1, node2, spec); } else if (spec.name == 'graft') { return new Graft(node1, node2, spec); } else if (spec.name == 'if-exist') { spec.opts.negate = false; return new If(node1, node2, spec); } else if (spec.name == 'if-nexist') { spec.opts.negate = true; return new If(node1, node2, spec); } else if (spec.name == 'if') { return new If(node1, node2, spec); } else { Util.Log.Fatal("Unsure what kind of relation this is:", spec.name); return null; } }
_onChildInserted: function(child) { Util.Log.Error("onChildInserted called (impossibly) on GListFeedItem Node"); },
function(reason) { Util.Log.Error("Could not fetch CTS link:", block); deferred.resolve(); });
startListening: function() { Util.Log.Info("Start Listening"); this.listenForNodeInsertionsOnTree('body', true); },
_subclass_insertChild: function(child, afterIndex) { Util.Log.Error("insertChild called (impossibly) on GListFeedItem"); },
function() { // Create the CTS tree for this region. Util.Log.Info("Running onChildInserted", prnt); var node = prnt._onChildInserted(evt.node); }, function(errors) {
}, function(errors) { Util.Log.Error("Couldn't add CTS blocks from inserted dom node", errors); }
addSpec: function(forrestSpec) { var self = this; if (typeof this.forrestSpecs == 'undefined') { Util.Log.Error("forrest spec undef"); } this.forrestSpecs.push(forrestSpec); var initial = Util.Promise.defer(); var last = initial.promise; var i, j; // Load all the dependency specs if (typeof forrestSpec.dependencySpecs != 'undefined') { for (dep in forrestSpec.dependencySpecs) { forrestSpec.dependencySpecs[dep].load(); } } // Load all the relation specs if (typeof forrestSpec.relationSpecs != 'undefined') { for (j = 0; j < forrestSpec.relationSpecs.length; j++) { self.addRelationSpec(forrestSpec.relationSpecs[j]); } } // Load AND REALIZE all the tree specs if (typeof forrestSpec.treeSpecs != 'undefined') { var promises = Util._.map(forrestSpec.treeSpecs, function(treeSpec) { self.addTreeSpec(treeSpec); return self.realizeTree(treeSpec); }); Util.Promise.all(promises).then(function() { initial.resolve(); }); // Why were we doing this? // for (i = 0; i < forrestSpec.treeSpecs.length; i++) { // (function(treeSpec) { // var treeSpec = forrestSpec.treeSpecs[i]; // self.addTreeSpec(treeSpec); // var next = Q.defer(); // last.then( // function() { // self.realizeTree(treeSpec).then( // function() { // next.resolve(); // }, // function(reason) { // next.reject(reason); // } // ); // }, // function(reason) { // next.reject(reason); // } // ); // last = next.promise; // })(forrestSpec.treeSpecs[i]) // } } //initial.resolve(); return last; },
function(reason) { Util.Log.Error("Could not parse and add spec", content, block); deferred.resolve(); }
realizeRelation: function(spec, subtree, filterFn) { if (typeof subtree == 'undefined') { subtree = false; } var s1 = spec.selectionSpec1; var s2 = spec.selectionSpec2; if (typeof s1 == 'undefined') { Util.Log.Error("S1 is undefined", spec); return; } if (typeof s2 == 'undefined') { Util.Log.Error("S2 is undefined", spec); return; } // Note: at this point we assume that all trees are loaded. if (! this.containsTree(s1.treeName)) { s1.treeName = this.remapTreeName(s1.treeName); if (! this.containsTree(s1.treeName)) { Util.Log.Error("Can not realize RelationSpec becasue one or more trees are not available", s1.treeName); return; } } if (! this.containsTree(s2.treeName)) { s2.treeName = this.remapTreeName(s2.treeName); if (! this.containsTree(s2.treeName)) { Util.Log.Error("Can not realize RelationSpec becasue one or more trees are not available", s2.treeName); return; } } if (typeof filterFn == 'undefined') { filterFn = false; } // Here we're guaranteed that the trees are available. // Now we find all the nodes that this spec matches on each side and // take the cross product of all combinations. var tree1 = this.trees[s1.treeName]; var tree2 = this.trees[s2.treeName]; if (subtree && (subtree.tree != tree1) && (subtree.tree != tree2)) { // not relevant to us. return; } var nodes1 = tree1.find(s1); var nodes2 = tree2.find(s2); if (nodes1.length == 0) { nodes1 = [NonexistentNode]; //Util.Log.Info("empty selection -> NonExistantNode!", s1); } if (nodes2.length == 0) { nodes2 = [NonexistentNode]; //Util.Log.Info("empty selection -> NonExistantNode!", s2); } for (var i = 0; i < nodes1.length; i++) { for (var j = 0; j < nodes2.length; j++) { // Realize a relation between i and j. Creating the relation adds // a pointer back to the nodes. if ((!subtree) || ((nodes1[i].isDescendantOf(subtree) || nodes1[i] == subtree)) || ((nodes2[j].isDescendantOf(subtree) || nodes2[j] == subtree))) { var node1 = nodes1[i]; var node2 = nodes2[j]; if ((!filterFn) || (filterFn({node1: node1, node2: node2}))) { if (filterFn) { if (! window.passed) { window.passed = []; } window.passed.push([node1, node2, node1.relations.length, node2.relations.length]); } var relation = this.factory.Relation(node1, node2, spec); // This is necessary but I can't remember why. But it's necessary here. node1.realizedInlineRelationSpecs = true; node2.realizedInlineRelationSpecs = true; // Add the relation to the forrest if (typeof this.relations == 'undefined') { Util.Log.Error("relations undefined"); } this.relations.push(relation); } } } } },
Util._.each(this.treeSpecs, function(treeSpec, name, list) { if (! Util._.has(this.trees, name)) { Util.Log.Info("Promising to realize tree", treeSpec); promises.push(this.realizeTree(treeSpec)); } }, this);
addRelationSpec: function(relationSpec) { if (typeof this.relationSpecs == 'undefined') { Util.Log.Error("rel spc undef"); } this.relationSpecs.push(relationSpec); },