/** * Returns all edges stored in a given tiddler. Any edge stored in a * tiddler is orginally an outgoing edge. Depending on how the user * changes the arrow head (by manipulating the Visjs edge-type style), * the edge may change its orientation and become an incoming edge or * bi-directional. Therefore, the edges retrieved may be incoming, * outgoing or both! * * Returned edges may be of the following type: * * - Edges stored in the tiddler text (=links). * - Edges stored in fields denoted by magic edge-types. * - TiddlyMap edges stored in a json format * * @param {Tiddler} tiddler - A tiddler reference or object from * which to retrieve the edges. * @param {Hashmap<TiddlerReference, boolean>} [toWL] * A hashmap on which basis it is decided, whether to include * an edge that leads to a certain tiddler in the result or not. * In this case, all edges stored in the tiddler are treated as * outgoing and the arrow head is ignored. If not specified, * all edges are included. * @param {Hashmap<string, boolean>} [typeWL] * A hashmap on which basis it is decided, whether to include * an edge of a given type in the result or not. If not * specified, all edges are included. */ getEdges(tiddler, toWL, typeWL) { const tObj = utils.getTiddler(tiddler); if (!tObj || utils.isSystemOrDraft(tObj)) { return; } const { allETy } = this.indeces; const edges = utils.makeHashMap(); const eTySubscribers = this.edgeTypeSubscriberRegistry.getAll(); for (let i = 0, l = eTySubscribers.length; i < l; i++) { Object.assign(edges, (eTySubscribers[i]).loadEdges(tObj, toWL, typeWL)); } for (let id in edges) { const edge = edges[id]; // check exists for historical reasons... if (!edge.from || !edge.to) { continue; } const type = allETy[edge.type] || EdgeType.getInstance(edge.type); addStyleToEdge(edges[id], type); edges[id] = edge; } return edges; }
Adapter.prototype.selectEdgesByType = function(type) { var typeWL = utils.makeHashMap(); typeWL[new EdgeType(type).id] = true; return this.getEdgesForSet(this.getAllPotentialNodes(), null, typeWL); };
/** * Select all edges of a given type. * * @param {string|EdgeType} type - Either the edge type id (name) or an EdgeType object. */ selectEdgesByType(type) { const typeWL = utils.makeHashMap({ [EdgeType.getInstance(type).id]: true, }); return this.getEdgesForSet(this.getAllPotentialNodes(), null, typeWL); }
/** * The method will return all outgoing edges for a subset of tiddlers. * * @param {Array<Tiddler>} tiddlers - The set of tiddlers to consider. * @param toWL * @param typeWL * @return {Hashmap<Id, Edge>} An edge collection. */ getEdgesForSet(tiddlers, toWL, typeWL) { const edges = utils.makeHashMap(); for (let i = tiddlers.length; i--;) { Object.assign(edges, this.getEdges(tiddlers[i], toWL, typeWL)); } return edges; }
Adapter.prototype.getEdgesForSet = function(tiddlers, toWL, typeWL) { var edges = utils.makeHashMap(); for(var i = tiddlers.length; i--;) { $tw.utils.extend(edges, this.getEdges(tiddlers[i], toWL, typeWL)); } return edges; };
Adapter.prototype.getEdges = function(tiddler, toWL, typeWL) { var tObj = utils.getTiddler(tiddler); if(!tObj || utils.isSystemOrDraft(tObj)) return; var edges = utils.makeHashMap(); this._addTmapEdges(edges, tObj, toWL, typeWL); this._addBodyAndFieldEdges(edges, tObj, toWL, typeWL); return edges; };
const filter = $tw.wiki.getCacheForTiddler(this.nodeFilterTRef, "tmap-nodeFilter", () => { let filter = utils.makeHashMap(); const tObj = $tw.wiki.getTiddler(this.nodeFilterTRef); filter.raw = (tObj && tObj.fields.filter) || ''; filter.pretty = utils.getPrettyFilter(filter.raw); filter.compiled = $tw.wiki.compileFilter(filter.raw); return filter; });
/** * @inheritDoc */ constructor(allEdgeTypes, options) { super(allEdgeTypes, options); // later used for edge retrieval to identify those fields that hold connections this.edgeTypesByFieldName = utils.makeHashMap(); for (let id in allEdgeTypes) { const edgeType = allEdgeTypes[id]; if (this.canHandle(edgeType)) { this.edgeTypesByFieldName[edgeType.name] = edgeType; } } }
/** * Returns a set of nodes that corresponds to a set of tiddlers. * * @param {TiddlerCollection} tiddlers - A collection of tiddlers. * @param {Hashmap} [addProperties] - a hashmap * @param {CollectionTypeString} [outputType='dataset'] - The result type. * * @return {NodeCollection} A collection of a type specified in the options. */ selectNodesByReferences(tiddlers, { addProperties, outputType } = {}) { const result = utils.makeHashMap(); const keys = Object.keys(tiddlers); for (let i = keys.length; i--;) { const node = this.makeNode(tiddlers[keys[i]], addProperties); if (node) { result[node.id] = node; } } return utils.convert(result, outputType); }
Adapter.prototype.selectNodesByReferences = function(tiddlers, options) { options = options || {}; var protoNode = options.addProperties; var result = utils.makeHashMap(); var keys = Object.keys(tiddlers); for(var i = keys.length; i--;) { var node = this.makeNode(tiddlers[keys[i]], protoNode); if(node) { result[node.id] = node; } // ATTENTION: edges may be obsolete } return utils.convert(result, options.outputType); };
/** * @inheritDoc */ getReferences(tObj, toWL, typeWL) { const refsGroupedByType = utils.makeHashMap(); const fieldNames = tObj.fields; for (let fieldName in fieldNames) { const type = this.edgeTypesByFieldName[fieldName]; if (!type || (typeWL && !typeWL[type.id])) continue; const toRefs = this.getReferencesFromField(tObj, fieldName, toWL); if (toRefs && toRefs.length) { refsGroupedByType[type.id] = toRefs; } } return refsGroupedByType; }
/** * This function will return all neighbours of a graph denoted by * a set of tiddlers. * * @todo parts of this code may be outsourced into a function to * prevent repeating code. * * @param {Array<TiddlerReference>} matches - The original set that * defines the starting point for the neighbourhood discovery * @param {Hashmap} [opts] - An optional options object. * @param {Hashmap} [opts.typeWL] - A whitelist lookup-table * that restricts which edges are travelled to reach a neighbour. * @param {Hashmap} [opts.edges] - An initial set of edges that is * used in the first step to reach immediate neighbours, if no * set of edges is specified, all exsisting edges will be considered. * @param {number} [opts.steps] - An integer value that specifies * the scope of the neighbourhood. A node is considered a neighbour * if it can be reached within the given number of steps starting * from original set of tiddlers returned by the node filter. * @param {Hashmap} [opts.addProperties] - a hashmap * containing properties to be added to each node. * For example: * { * group: 'g1', * color: 'red' * } * @return {Object} An object of the form: * { * nodes: { *all neighbouring nodes* }, * edges: { *all edges connected to neighbours* }, * } */ getNeighbours(matches, opts = {}) { $tm.start('Get neighbours'); const { addProperties, toWL, typeWL, steps } = opts; const { allETy } = this.indeces; // index of all tiddlers have already are been visited, either by // having been included in the original set, or by having been // recorded as neighbour during the discovery. const visited = utils.getArrayValuesAsHashmapKeys(matches); const view = ViewAbstraction.exists(opts.view) ? new ViewAbstraction(opts.view) : null; const allEdgesLeadingToNeighbours = utils.makeHashMap(); const allNeighbours = utils.makeHashMap(); const maxSteps = (parseInt(steps) > 0 ? steps : 1); const direction = (opts.direction || (view && view.getConfig('neighbourhood_directions'))); const isWalkBoth = (!direction || direction === 'both'); const isWalkIn = (isWalkBoth || direction === 'in'); const isWalkOut = (isWalkBoth || direction === 'out'); // in order to apply the node-filter also to neighbours we need to make it // include all tiddlers in the filter's source (e.g. a tiddler and a few neighbours) // and then apply the filter – which now has the chance to take away tiddlers // a few filters from the set const neighFilter = view && `[all[]] ${view.getNodeFilter('raw')}`; // adjacency receives whitelists through opts const adjList = this.getAdjacencyList('to', opts); const addAsNeighbour = (edge, role, neighboursOfThisStep) => { allEdgesLeadingToNeighbours[edge.id] = edge; const tRef = this.getTiddlerById(edge[role]); if ( view && utils.isTrue($tm.config.sys.nodeFilterNeighbours) && !utils.isMatch(tRef, neighFilter)) { return; } if (!visited[tRef]) { visited[tRef] = true; const node = this.makeNode(tRef, addProperties); if (node) { // saveguard against obsolete edges or other problems // record node allNeighbours[node.id] = node; neighboursOfThisStep.push(tRef); } } }; // needed later let step; // loop if still steps to be taken and we have a non-empty starting set for (step = 0; step < maxSteps && matches.length; step++) { // neighbours that are discovered in the current step; // starting off from the current set of matches; const neighboursOfThisStep = []; // loop over all nodes in the original set for (let i = matches.length; i--;) { if (utils.isSystemOrDraft(matches[i])) { // = this might happen if the user manually created edges // that link to a system/draft tiddler or if the original // set contained system/draft tiddlers. continue; } // get all outgoing edges // = edges originating from the starting set and point outwards const outgoing = this.getEdges(matches[i], toWL, typeWL); for (let id in outgoing) { const t = allETy[outgoing[id].type]; if (isWalkBoth || isWalkOut && t.toArrow || isWalkIn && t.invertedArrow) { addAsNeighbour(outgoing[id], 'to', neighboursOfThisStep); } } // get all incoming edges // = edges originating from outside pointing to the starting set const incoming = adjList[this.getId(matches[i])]; if (!incoming) { continue; } for (let j = incoming.length; j--;) { const t = allETy[incoming[j].type]; if (isWalkBoth || isWalkIn && t.toArrow || isWalkOut && t.invertedArrow) { addAsNeighbour(incoming[j], 'from', neighboursOfThisStep); } } } // the current set of newly discovered neighbours forms the // starting point for the next discovery matches = neighboursOfThisStep; } const neighbourhood = { nodes: allNeighbours, edges: allEdgesLeadingToNeighbours }; $tm.logger('debug', 'Retrieved neighbourhood', neighbourhood, 'steps', step); $tm.stop('Get neighbours'); return neighbourhood; }
Adapter.prototype.getNeighbours = function(matches, opts) { $tm.start("Get neighbours"); opts = opts || {}; // index of all tiddlers have already are been visited, either by // having been included in the original set, or by having been // recorded as neighbour during the discovery. var visited = utils.getArrayValuesAsHashmapKeys(matches); var view = new ViewAbstraction(opts.view); var protoNode = opts.addProperties; var allEdgesLeadingToNeighbours = utils.makeHashMap(); var allETy = $tm.indeces.allETy; var allNeighbours = utils.makeHashMap(); var toWL = opts.toWL; var typeWL = opts.typeWL; var tById = $tm.indeces.tById; var idByT = $tm.indeces.idByT; var maxSteps = (parseInt(opts.steps) > 0 ? opts.steps : 1); var direction = (opts.direction || (view.exists() && view.getConfig("neighbourhood_directions"))); var isWalkBoth = (!direction || direction === "both"); var isWalkIn = (isWalkBoth || direction === "in"); var isWalkOut = (isWalkBoth || direction === "out"); // adjacency receives whitelists through opts var adjList = this.getAdjacencyList("to", opts); var addAsNeighbour = function(edge, role) { allEdgesLeadingToNeighbours[edge.id] = edge; var tRef = tById[edge[role]]; if(!visited[tRef]) { visited[tRef] = true; var node = this.makeNode(tRef, protoNode); if(node) { // saveguard against obsolete edges or other problems // record node allNeighbours[node.id] = node; neighboursOfThisStep.push(tRef); } } }.bind(this); // loop if still steps to be taken and we have a non-empty starting set for(var step = 0; step < maxSteps && matches.length; step++) { // neighbours that are discovered in the current step; // starting off from the current set of matches; var neighboursOfThisStep = []; // loop over all nodes in the original set for(var i = matches.length; i--;) { if(utils.isSystemOrDraft(matches[i])) { // = this might happen if the user manually created edges // that link to a system/draft tiddler or if the original // set contained system/draft tiddlers. continue; } // get all outgoing edges // = edges originating from the starting set and point outwards var outgoing = this.getEdges(matches[i], toWL, typeWL); for(var id in outgoing) { var t = allETy[outgoing[id].type]; if(isWalkBoth || isWalkOut && t.toArrow || isWalkIn && t.invertedArrow) { addAsNeighbour(outgoing[id], "to"); } } // get all incoming edges // = edges originating from outside pointing to the starting set var incoming = adjList[idByT[matches[i]]]; if(!incoming) continue; for(var j = incoming.length; j--;) { var t = allETy[incoming[j].type]; if(isWalkBoth || isWalkIn && t.toArrow || isWalkOut && t.invertedArrow) { addAsNeighbour(incoming[j], "from"); } } } // the current set of newly discovered neighbours forms the // starting point for the next discovery matches = neighboursOfThisStep; } var neighbourhood = { nodes: allNeighbours, edges: allEdgesLeadingToNeighbours }; $tm.logger("debug", "Retrieved neighbourhood", neighbourhood, "steps", step); $tm.stop("Get neighbours"); return neighbourhood; };
"use strict";module.exports=Adapter;var ViewAbstraction=require("$:/plugins/felixhayashi/tiddlymap/js/ViewAbstraction");var EdgeType=require("$:/plugins/felixhayashi/tiddlymap/js/EdgeType");var NodeType=require("$:/plugins/felixhayashi/tiddlymap/js/NodeType");var utils=require("$:/plugins/felixhayashi/tiddlymap/js/utils");var vis=require("$:/plugins/felixhayashi/vis/vis.js");var getContrastColour=require("$:/core/modules/macros/contrastcolour.js").run;function Adapter(){this.visShapesWithTextInside=utils.getLookupTable(["ellipse","circle","database","box","text"]);this.isTransTypeEnabled=typeof $tw.wiki.getTiddlerTranscludes==="function"}Adapter.prototype.deleteEdge=function(e){return this._processEdge(e,"delete")};Adapter.prototype.deleteEdges=function(e){e=utils.convert(e,"array");for(var t=e.length;t--;){this.deleteEdge(e[t])}};Adapter.prototype.insertEdge=function(e){return this._processEdge(e,"insert")};Adapter.prototype._processEdge=function(e,t){$tm.logger("debug","Edge",t,e);if(typeof e!=="object"||!t||!e.from)return;if(t==="insert"&&!e.to)return;var i=$tm.indeces.tById[e.from];if(!i||!utils.tiddlerExists(i))return;var r=new EdgeType(e.type);var s=utils.getTiddler(i);var a=r.namespace;if(a==="tw-list"){if(!e.to)return;return this._processListEdge(s,e,r,t)}else if(a==="tw-field"){if(!e.to)return;return this._processFieldEdge(s,e,r,t)}else if(a==="tw-body"){return null}else{return this._processTmapEdge(s,e,r,t)}return e};Adapter.prototype._processTmapEdge=function(e,t,i,r){if(r==="delete"&&!t.id)return;var s=utils.parseFieldData(e,"tmap.edges",{});if(r==="insert"){t.id=t.id||utils.genUUID();s[t.id]={to:t.to,type:i.id};if(!i.exists()){i.save()}}else{delete s[t.id]}utils.writeFieldData(e,"tmap.edges",s);return t};Adapter.prototype._processListEdge=function(e,t,i,r){var s=i.name;var a=utils.getTiddler(e);var o=$tw.utils.parseStringArray(e.fields[s]);o=(o||[]).slice();var d=$tm.indeces.tById[t.to];if(r==="insert"){o.push(d);if(!i.exists()){i.save()}}else{var n=o.indexOf(d);if(n>-1){o.splice(n,1)}}utils.setField(a,s,$tw.utils.stringifyList(o));return t};Adapter.prototype._processFieldEdge=function(e,t,i,r){var s=$tm.indeces.tById[t.to];if(s==null)return;var a=r==="insert"?s:"";utils.setField(e,i.name,a);if(!i.exists()){i.save()}return t};Adapter.prototype.getAdjacencyList=function(e,t){$tm.start("Creating adjacency list");t=t||{};if(!t.edges){var i=utils.getMatches($tm.selector.allPotentialNodes);t.edges=this.getEdgesForSet(i,t.toWL,t.typeWL)}var r=utils.groupByProperty(t.edges,e||"to");$tm.stop("Creating adjacency list");return r};Adapter.prototype.getNeighbours=function(e,t){$tm.start("Get neighbours");t=t||{};var i=utils.getArrayValuesAsHashmapKeys(e);var r=new ViewAbstraction(t.view);var s=t.addProperties;var a=utils.makeHashMap();var o=$tm.indeces.allETy;var d=utils.makeHashMap();var n=t.toWL;var l=t.typeWL;var p=$tm.indeces.tById;var u=$tm.indeces.idByT;var f=parseInt(t.steps)>0?t.steps:1;var g=t.direction||r.exists()&&r.getConfig("neighbourhood_directions");var c=!g||g==="both";var v=c||g==="in";var y=c||g==="out";var h=this.getAdjacencyList("to",t);var m=function(e,t){a[e.id]=e;var r=p[e[t]];if(!i[r]){i[r]=true;var o=this.makeNode(r,s);if(o){d[o.id]=o;A.push(r)}}}.bind(this);for(var w=0;w<f&&e.length;w++){var A=[];for(var b=e.length;b--;){if(utils.isSystemOrDraft(e[b])){continue}var T=this.getEdges(e[b],n,l);for(var $ in T){var E=o[T[$].type];if(c||y&&E.toArrow||v&&E.invertedArrow){m(T[$],"to")}}var N=h[u[e[b]]];if(!N)continue;for(var x=N.length;x--;){var E=o[N[x].type];if(c||v&&E.toArrow||y&&E.invertedArrow){m(N[x],"from")}}}e=A}var k={nodes:d,edges:a};$tm.logger("debug","Retrieved neighbourhood",k,"steps",w);$tm.stop("Get neighbours");return k};Adapter.prototype.getGraph=function(e){$tm.start("Assembling Graph");e=e||{};var t=new ViewAbstraction(e.view);var i=utils.getMatches(e.filter||t.exists()&&t.getNodeFilter("compiled"));var r=utils.getArrayValuesAsHashmapKeys(i);var s=e.edgeTypeWL||t.exists()&&t.getEdgeTypeFilter("whitelist");var a=parseInt(e.neighbourhoodScope||t.exists()&&t.getConfig("neighbourhood_scope"));var o={edges:this.getEdgesForSet(i,r,s),nodes:this.selectNodesByReferences(i,{view:t,outputType:"hashmap"})};if(a){var d=this.getNeighbours(i,{steps:a,view:t,typeWL:s,addProperties:{group:"tmap:neighbour"}});utils.merge(o,d);if(t.exists()&&t.isEnabled("show_inter_neighbour_edges")){var n=this.getTiddlersById(d.nodes);var r=utils.getArrayValuesAsHashmapKeys(n);$tw.utils.extend(o.edges,this.getEdgesForSet(n,r))}}this._removeObsoleteViewData(o.nodes,t);this.attachStylesToNodes(o.nodes,t);$tm.stop("Assembling Graph");$tm.logger("debug","Assembled graph:",o);return o};Adapter.prototype.getEdges=function(e,t,i){var r=utils.getTiddler(e);if(!r||utils.isSystemOrDraft(r))return;var s=utils.makeHashMap();this._addTmapEdges(s,r,t,i);this._addBodyAndFieldEdges(s,r,t,i);return s};Adapter.prototype._addBodyAndFieldEdges=function(e,t,i,r){var s=t.fields;var a=utils.getTiddlerRef(t);var o=$tm.indeces;var d=o.maETyFiNa;var n=utils.makeHashMap();if(!r||r["tw-body:link"]){n["tw-body:link"]=$tw.wiki.getTiddlerLinks(a)}if(this.isTransTypeEnabled&&(!r||r["tw-body:transclude"])){n["tw-body:transclude"]=$tw.wiki.getTiddlerTranscludes(a)}for(var l in s){var p=d[l];if(!p||r&&!r[p.id])continue;if(p.namespace==="tw-field"){n[p.id]=[s[l]]}else if(p.namespace==="tw-list"){n[p.id]=$tw.utils.parseStringArray(s[l])}else if(p.namespace==="tw-filter"){var u=s[l];n[p.id]=utils.getMatches(u,i)}}if(!n)return;var f=t.fields["tmap.id"];var g=o.idByT;var c=o.allETy;for(var v in n){var y=n[v];if(!y)continue;var p=c[v];for(var h=y.length;h--;){var m=y[h];if(!m||!$tw.wiki.tiddlerExists(m)||utils.isSystemOrDraft(m)||i&&!i[m])continue;var w=p.id+$tw.utils.hashString(a+m);var A=this.makeEdge(f,g[m],p,w);if(A){e[A.id]=A}}}};Adapter.prototype._addTmapEdges=function(e,t,i,r){var s=utils.parseFieldData(t,"tmap.edges");if(!s)return;var a=$tm.indeces.tById;var o=t.fields["tmap.id"];for(var d in s){var n=s[d];var l=a[n.to];if(l&&(!i||i[l])&&(!r||r[n.type])){var p=this.makeEdge(o,n.to,n.type,d);if(p){e[d]=p}}}};Adapter.prototype.getEdgesForSet=function(e,t,i){var r=utils.makeHashMap();for(var s=e.length;s--;){$tw.utils.extend(r,this.getEdges(e[s],t,i))}return r};Adapter.prototype.selectEdgesByType=function(e){var t=utils.makeHashMap();t[new EdgeType(e).id]=true;return this.getEdgesForSet(this.getAllPotentialNodes(),null,t)};Adapter.prototype.getAllPotentialNodes=function(){return utils.getMatches($tm.selector.allPotentialNodes)};Adapter.prototype._processEdgesWithType=function(e,t){e=new EdgeType(e);$tm.logger("debug","Processing edges",e,t);var i=this.selectEdgesByType(e);if(t.action==="rename"){var r=new EdgeType(t.newName);r.load(e);r.save()}for(var s in i){this._processEdge(i[s],"delete");if(t.action==="rename"){i[s].type=t.newName;this._processEdge(i[s],"insert")}}$tw.wiki.deleteTiddler(e.fullPath)};Adapter.prototype.selectNodesByFilter=function(e,t){var i=utils.getMatches(e);return this.selectNodesByReferences(i,t)};Adapter.prototype.selectNodesByReferences=function(e,t){t=t||{};var i=t.addProperties;var r=utils.makeHashMap();var s=Object.keys(e);for(var a=s.length;a--;){var o=this.makeNode(e[s[a]],i);if(o){r[o.id]=o}}return utils.convert(r,t.outputType)};Adapter.prototype.selectNodesByIds=function(e,t){var i=this.getTiddlersById(e);return this.selectNodesByReferences(i,t)};Adapter.prototype.selectNodeById=function(e,t){t=utils.merge(t,{outputType:"hashmap"});var i=this.selectNodesByIds([e],t);return i[e]};Adapter.prototype.makeEdge=function(e,t,i,r){if(!e||!t)return;if(e instanceof $tw.Tiddler){e=e.fields["tmap.id"]}else if(typeof e==="object"){e=e.id}i=$tm.indeces.allETy[i]||new EdgeType(i);var s=i.getLabel();var a={id:r||utils.genUUID(),from:e,to:t,type:i.id};if(utils.isTrue(i["show-label"],true)){a.label=s}a=$tw.utils.extend(a,i.style);return a};Adapter.prototype.removeNodeType=function(e){var e=new NodeType(e);$tw.wiki.deleteTiddler(e.fullPath)};Adapter.prototype.makeNode=function(e,t){var i=utils.getTiddler(e);if(!i||utils.isSystemOrDraft(i))return;var r=utils.merge({},t);r.id=this.assignId(i);var s=i.fields[$tm.field.nodeLabel];r.label=s&&$tm.field.nodeLabel!=="title"?$tw.wiki.renderText("text/plain","text/vnd-tiddlywiki",s):i.fields.title;return r};Adapter.prototype.getInheritedNodeStyles=function(e){var t=this.getTiddlersById(e);var i={};var r=$tm.indeces.glNTy;for(var s=r.length;s--;){var a=r[s];if(a.id==="tmap:neighbour"){var o=$tm.indeces.tById;var d=[];for(var n in e){if(e[n].group==="tmap:neighbour"){d.push(o[n])}}}else{var d=a.getInheritors(t)}for(var l=d.length;l--;){var p=d[l];var u=i[p]=i[p]||{};u.style=utils.merge(u.style||{},a.style);if(a["fa-icon"]){u["fa-icon"]=a["fa-icon"]}else if(a["tw-icon"]){u["tw-icon"]=a["tw-icon"]}}}return i};Adapter.prototype.attachStylesToEdges=function(e,t){};Adapter.prototype._removeObsoleteViewData=function(e,t){t=new ViewAbstraction(t);if(!t.exists()||!e)return;var i=t.getNodeData();var r=0;for(var s in i){if(e[s]===undefined&&i[s]!=null){i[s]=undefined;r++}}if(r){$tm.logger("debug","[Cleanup]","Removed obsolete node data:",t.getLabel(),r);t.saveNodeData(i)}};Adapter.prototype.attachStylesToNodes=function(e,t){t=new ViewAbstraction(t);var i=this.getInheritedNodeStyles(e);var r=t.exists()?t.getNodeData():utils.makeHashMap();var s=t.exists()&&!t.isEnabled("physics_mode");var a=$tm.field.nodeIcon;var o=$tm.indeces.tById;for(var d in e){var n=o[d];var l=$tw.wiki.getTiddler(n);var p=l.fields;var u=e[d];var f=null;var g=null;if(i[n]){if(i[n].style){utils.merge(u,i[n].style)}f=i[n]["fa-icon"];g=i[n]["tw-icon"]}if(p.color){u.color=p.color}if(p["tmap.style"]){utils.merge(u,utils.parseJSON(p["tmap.style"]))}f=p["tmap.fa-icon"]||f;g=p["icon"]||g;if(r[d]){utils.merge(u,r[d]);if(s){u.fixed={x:u.x!=null,y:u.y!=null}}f=r[d]["fa-icon"]||f;g=r[d]["tw-icon"]||g}var c=u.color!==null&&typeof u.color==="object";var v=c?u.color.background:u.color;u.color={background:v,border:c?u.color.border:undefined};this._addNodeIcon(u,f,g);u.font=u.font||{};if(u.shape&&!this.visShapesWithTextInside[u.shape]){u.font.color="black"}else if(!u.font.color&&v){u.font.color=getContrastColour(v,v,"black","white")}if(u.shape==="icon"&&typeof u.icon==="object"){u.icon.color=v}}};Adapter.prototype.deleteNode=function(e){if(!e)return;var t=typeof e==="object"?e.id:e;var i=$tm.indeces.tById[t];if(i){utils.deleteTiddlers([i])}var r=utils.getMatches($tm.selector.allViews);for(var s=r.length;s--;){var a=new ViewAbstraction(r[s]);a.removeNode(t);if(a.getNodeData(t)){a.saveNodeData(t,null)}}var o=this.getNeighbours([i]);this.deleteEdges(o.edges)};Adapter.prototype.deleteNodes=function(e){e=utils.convert(e,"array");for(var t=e.length;t--;){this.deleteNode(e[t])}};Adapter.prototype.storePositions=function(e,t){t=new ViewAbstraction(t);if(!t.exists())return;t.saveNodeData(e)};Adapter.prototype.assignId=function(e,t){var i=utils.getTiddler(e,true);if(!i)return;var r=i.fields["tmap.id"];if(!r||t){r=utils.genUUID();utils.setField(i,"tmap.id",r);$tm.logger("info","Assigning new id to",i.fields.title)}$tm.indeces.tById[r]=i.fields.title;$tm.indeces.idByT[i.fields.title]=r;return r};Adapter.prototype.insertNode=function(e,t,i){i=i||{};e=e||{};var r={"tmap.id":null};if(!i.fields||!i.fields.text){r.text=""}var s=$tw.wiki.generateNewTitle(e.label||utils.getRandomLabel());e.label=r.title=s;var a=new $tw.Tiddler(i.fields,r,$tw.wiki.getModificationFields(),$tw.wiki.getCreationFields());$tw.wiki.addTiddler(a);e=this.makeNode(a,e);var t=new ViewAbstraction(t);if(t.exists()){t.addNode(e)}return e};Adapter.prototype._getFAdigits=function(e){return e.length===4?e:e.substr(3,4)};Adapter.prototype.getTiddlersById=function(e){if(Array.isArray(e)){e=utils.getArrayValuesAsHashmapKeys(e)}else if(e instanceof vis.DataSet){e=utils.getLookupTable(e,"id")}var t=[];var i=$tm.indeces.tById;for(var r in e){if(i[r])t.push(i[r])}return t};Adapter.prototype.getId=function(e){return $tm.indeces.idByT[utils.getTiddlerRef(e)]};Adapter.prototype._addNodeIcon=function(e,t,i){if(t){e.shape="icon";e.icon={shape:"icon",face:"FontAwesome",color:e.color,code:String.fromCharCode("0x"+this._getFAdigits(t))};return}if(!i)return;var r=utils.getTiddler(i);if(!r)return;if(r.fields["_canonical_uri"]){e.image=r.fields["_canonical_uri"];e.shape="image";return}if(r.fields.text){e.image=utils.getDataUri(r);e.shape="image";return}};
Adapter.prototype.attachStylesToNodes = function(nodes, view) { view = new ViewAbstraction(view); var inheritedStyles = this.getInheritedNodeStyles(nodes); var viewNodeData = view.exists() ? view.getNodeData() : utils.makeHashMap(); var isStaticMode = view.exists() && !view.isEnabled("physics_mode"); // shortcuts (for performance and readability) var nodeIconField = $tm.field.nodeIcon; var tById = $tm.indeces.tById; for(var id in nodes) { var tRef = tById[id]; var tObj = $tw.wiki.getTiddler(tRef); var fields = tObj.fields; var node = nodes[id]; var faIcon = null; var twIcon = null; // == group styles == // will add local and global group styles if(inheritedStyles[tRef]) { if(inheritedStyles[tRef].style) { utils.merge(node, inheritedStyles[tRef].style); } faIcon = inheritedStyles[tRef]["fa-icon"]; twIcon = inheritedStyles[tRef]["tw-icon"]; } // == global node styles == // background color if(fields.color) { node.color = fields.color } // global node style from vis editor if(fields["tmap.style"]) { utils.merge(node, utils.parseJSON(fields["tmap.style"])); } faIcon = fields["tmap.fa-icon"] || faIcon; twIcon = fields["icon"] || twIcon; // == local node styles == // local node style and positions if(viewNodeData[id]) { utils.merge(node, viewNodeData[id]); if(isStaticMode) { // fix x if x-position is set; same for y node.fixed = { x: (node.x != null), y: (node.y != null) }; } faIcon = viewNodeData[id]["fa-icon"] || faIcon; twIcon = viewNodeData[id]["tw-icon"] || twIcon; } // == tweaks == var isColorObject = (node.color !== null && typeof node.color === "object"); // color/border-color may be undefined var color = (isColorObject ? node.color.background : node.color); node.color = { background: color, border: (isColorObject ? node.color.border : undefined) }; // ATTENTION: this function needs to be called after color is assigned this._addNodeIcon(node, faIcon, twIcon); // determine font color if not defined via a group- or node-style; // in case of global and local default styles, the user is responsible // him- or herself to adjust the font node.font = node.font || {}; if(node.shape && !this.visShapesWithTextInside[node.shape]) { node.font.color = "black"; // force a black color } else if(!node.font.color && color) { node.font.color = getContrastColour(color, color, "black", "white"); } if(node.shape === "icon" && typeof node.icon === "object") { node.icon.color = color; } } };
Adapter.prototype._addBodyAndFieldEdges = function(edges, tObj, toWL, typeWL) { // never assign a default to the typeWL. if it is not assigned it means // all types!! NEVER: typeWL = typeWL || utils.makeHashMap(); var fromTObjFields = tObj.fields; var fromTRef = utils.getTiddlerRef(tObj); var indeces = $tm.indeces; var maETyFiNa = indeces.maETyFiNa; // magic edge-type field names var refsByType = utils.makeHashMap(); // 1) Prepare if(!typeWL || typeWL["tw-body:link"]) { refsByType["tw-body:link"] = $tw.wiki.getTiddlerLinks(fromTRef); } // hack to support // https://github.com/felixhayashi/TW5-TiddlyMap/issues/198 if(this.isTransTypeEnabled && (!typeWL || typeWL["tw-body:transclude"])) { refsByType["tw-body:transclude"] = $tw.wiki.getTiddlerTranscludes(fromTRef); } for(var f in fromTObjFields) { var type = maETyFiNa[f]; if(!type || (typeWL && !typeWL[type.id])) continue; if(type.namespace === "tw-field") { refsByType[type.id] = [ fromTObjFields[f] ]; } else if(type.namespace === "tw-list") { refsByType[type.id] = $tw.utils.parseStringArray(fromTObjFields[f]); } else if(type.namespace === "tw-filter") { var filter = fromTObjFields[f]; refsByType[type.id] = utils.getMatches(filter, toWL); } } if(!refsByType) return; // 2) Add edges to list var fromId = tObj.fields["tmap.id"]; var idByT = indeces.idByT; var allETy = indeces.allETy; for(var typeId in refsByType) { var toRefs = refsByType[typeId]; if(!toRefs) continue; var type = allETy[typeId]; for(var i = toRefs.length; i--;) { var toTRef = toRefs[i]; if(!toTRef || !$tw.wiki.tiddlerExists(toTRef) || utils.isSystemOrDraft(toTRef) || (toWL && !toWL[toTRef])) continue; var id = type.id + $tw.utils.hashString(fromTRef + toTRef); var edge = this.makeEdge(fromId, idByT[toTRef], type, id); if(edge) { edges[edge.id] = edge; } } } };
/** * Adds styles to nodes. * * @param {Object<string, Node>} nodes * @param {ViewAbstraction|string} view */ attachStylesToNodes(nodes, view) { view = ViewAbstraction.exists(view) ? new ViewAbstraction(view) : null; const inheritedStyles = this.getInheritedNodeStyles(nodes); const viewNodeData = view ? view.getNodeData() : utils.makeHashMap(); const isStaticMode = view && !view.isEnabled('physics_mode'); for (let id in nodes) { const tRef = this.getTiddlerById(id); const tObj = this.wiki.getTiddler(tRef); const fields = tObj.fields; const node = nodes[id]; let icon; // == group styles == const inheritedStyle = inheritedStyles[tRef]; if (inheritedStyle) { utils.merge(node, inheritedStyle.style); icon = getIcon(inheritedStyle['fa-icon'], inheritedStyle['tw-icon']); } // == global node styles == // background color if (fields.color) { node.color = fields.color; } // global node style from vis editor if (fields['tmap.style']) { utils.merge(node, utils.parseJSON(fields['tmap.style'])); } icon = getIcon(fields['tmap.fa-icon'], fields['icon']) || icon; // == local node styles == // local node style and positions const nodeData = viewNodeData[id]; if (nodeData) { utils.merge(node, nodeData); if (isStaticMode) { // fix x if x-position is set; same for y node.fixed = { x: (node.x != null), y: (node.y != null) }; } icon = getIcon(nodeData['fa-icon'], nodeData['tw-icon']) || icon; } // == tweaks == const isColorObject = (node.color !== null && typeof node.color === 'object'); // color/border-color may be undefined const color = (isColorObject ? node.color.background : node.color); node.color = { background: color, border: (isColorObject ? node.color.border : undefined) }; // ATTENTION: this function needs to be called after color is assigned addNodeIcon(node, icon); // determine font color if not defined via a group- or node-style; // in case of global and local default styles, the user is responsible // him- or herself to adjust the font node.font = node.font || {}; if (node.shape && !this.visShapesWithTextInside[node.shape]) { node.font.color = 'black'; // force a black color } else if (!node.font.color && color) { node.font.color = getContrastColour(color, color, 'black', 'white'); } if (node.shape === 'icon' && typeof node.icon === 'object') { node.icon.color = color; } } if (view) { const node = nodes[view.getConfig('central-topic')]; if (node) { utils.merge(node, this.indeces.glNTyById['tmap:central-topic'].style); } } }
"use strict";exports.tiddlymap=MapWidget;exports.tmap=MapWidget;var utils=require("$:/plugins/felixhayashi/tiddlymap/js/utils");var DialogManager=require("$:/plugins/felixhayashi/tiddlymap/js/DialogManager");var CallbackManager=require("$:/plugins/felixhayashi/tiddlymap/js/CallbackManager");var ViewAbstraction=require("$:/plugins/felixhayashi/tiddlymap/js/ViewAbstraction");var EdgeType=require("$:/plugins/felixhayashi/tiddlymap/js/EdgeType");var NodeType=require("$:/plugins/felixhayashi/tiddlymap/js/NodeType");var Popup=require("$:/plugins/felixhayashi/tiddlymap/js/Popup");var vis=require("$:/plugins/felixhayashi/vis/vis.js");var Widget=require("$:/core/modules/widgets/widget.js").widget;function MapWidget(e,t){Widget.call(this,e,t);this.getAttr=this.getAttribute;this.isDebug=utils.isTrue($tm.config.sys.debug,false);utils.bind(this,["constructTooltip","handleResizeEvent","handleClickEvent","handleCanvasKeyup","handleCanvasKeydown","handleCanvasScroll","handleWidgetKeyup","handleWidgetKeydown","handleTriggeredRefresh"]);this.callbackManager=new CallbackManager;this.dialogManager=new DialogManager(this.callbackManager,this);this.computeAttributes();this.editorMode=this.getAttr("editor");this.clickToUse=utils.isTrue(this.getAttr("click-to-use"),false);this.id=this.getAttr("object-id")||this.getStateQualifier();this.widgetTempStatePath=$tm.path.tempStates+"/"+this.id;this.widgetPopupsPath=$tm.path.tempPopups+"/"+this.id;if(this.editorMode){utils.addTWlisteners({"tmap:tm-create-view":this.handleCreateView,"tmap:tm-rename-view":this.handleRenameView,"tmap:tm-delete-view":this.handleDeleteView,"tmap:tm-edit-view":this.handleEditView,"tmap:tm-store-position":this.handleStorePositions,"tmap:tm-generate-widget":this.handleGenerateWidget,"tmap:tm-save-canvas":this.handleSaveCanvas},this,this)}utils.addTWlisteners({"tmap:tm-focus-node":this.handleFocusNode,"tmap:tm-reset-focus":this.repaintGraph},this,this);this.visListeners={click:this.handleVisSingleClickEvent,doubleClick:this.handleVisDoubleClickEvent,stabilized:this.handleVisStabilizedEvent,selectNode:this.handleVisSelectNode,deselectNode:this.handleVisDeselectNode,dragStart:this.handleVisDragStart,dragEnd:this.handleVisDragEnd,hoverNode:this.handleVisHoverElement,hoverEdge:this.handleVisHoverElement,blurNode:this.handleVisBlurElement,blurEdge:this.handleVisBlurElement,oncontext:this.handleVisOnContext,beforeDrawing:this.handleVisBeforeDrawing,stabilizationProgress:this.handleVisLoading,stabilizationIterationsDone:this.handleVisLoadingDone};this.windowDomListeners={resize:[this.handleResizeEvent,false],click:[this.handleClickEvent,false]};this.canvasDomListeners={keyup:[this.handleCanvasKeyup,true],keydown:[this.handleCanvasKeydown,true],mousewheel:[this.handleCanvasScroll,true]};this.widgetDomListeners={keyup:[this.handleWidgetKeyup,true],keydown:[this.handleWidgetKeydown,true]}}MapWidget.prototype=Object.create(Widget.prototype);MapWidget.prototype.handleConnectionEvent=function(e,t){var i=this.view.getEdgeTypeFilter();var s={fromLabel:$tm.adapter.selectNodeById(e.from).label,toLabel:$tm.adapter.selectNodeById(e.to).label,viewNS:this.view.getConfig("edge_type_namespace"),eTyFilter:i.raw};var a="getEdgeType";this.dialogManager.open(a,s,function(s,a){if(s){var r=utils.getText(a);var o={namespace:this.view.getConfig("edge_type_namespace")};var r=new EdgeType(r,null,o);if(!r.exists())r.save();e.type=r.id;$tm.adapter.insertEdge(e);if(!this.view.isEdgeTypeVisible(r.id)){var n={type:r.id,view:this.view.getLabel(),eTyFilter:i.pretty};this.dialogManager.open("edgeNotVisible",n)}this.preventFitAfterRebuild=true}if(typeof t==="function"){t(s)}})};MapWidget.prototype.checkForFreshInstall=function(){var e=$tm.ref.sysMeta;if(!utils.getEntry(e,"showWelcomeMessage",true))return;utils.setEntry(e,"showWelcomeMessage",false);var t={};var i="welcome";this.dialogManager.open(i,t,function(e,t){if(utils.tiddlerExists("$:/plugins/felixhayashi/topstoryview")){utils.setText("$:/view","top");utils.setText("$:/config/Navigation/openLinkFromInsideRiver","above");utils.setText("$:/config/Navigation/openLinkFromOutsideRiver","top");utils.touch("$:/plugins/felixhayashi/topstoryview")}var i=$tm.misc.defaultViewLabel;var s={label:"Have fun with",x:0,y:0};var a=$tm.adapter.insertNode(s,i);var s={label:"TiddlyMap!!",x:100,y:100};var r=$tm.adapter.insertNode(s,i);$tm.adapter.insertEdge({from:a.id,to:r.id})})};MapWidget.prototype.openStandardConfirmDialog=function(e,t){var i={message:t};this.dialogManager.open("getConfirmation",i,e)};MapWidget.prototype.logger=function(e,t){if(this.isDebug){var i=Array.prototype.slice.call(arguments,1);i.unshift("@"+this.id);i.unshift(e);$tm.logger.apply(this,i)}};MapWidget.prototype.render=function(e,t){this.parentDomNode=e;this.domNode=this.document.createElement("div");e.insertBefore(this.domNode,t);this.registerClassNames(this.domNode);this.viewHolderRef=this.getViewHolderRef();this.view=this.getView();this.graphBarDomNode=this.document.createElement("div");$tw.utils.addClass(this.graphBarDomNode,"tmap-topbar");this.domNode.appendChild(this.graphBarDomNode);this.graphDomNode=this.document.createElement("div");this.domNode.appendChild(this.graphDomNode);$tw.utils.addClass(this.graphDomNode,"tmap-vis-graph");if(utils.isPreviewed(this)||this.domNode.isTiddlyWikiFakeDom){$tw.utils.addClass(this.domNode,"tmap-static-mode");this.renderPreview(this.graphBarDomNode,this.graphDomNode)}else{this.renderFullWidget(this.domNode,this.graphBarDomNode,this.graphDomNode)}};MapWidget.prototype.renderPreview=function(e,t){var i=this.view.getRoot()+"/snapshot";var s=utils.getTiddler(i);var a=this.document.createElement("span");a.innerHTML=this.view.getLabel();a.className="tmap-view-label";e.appendChild(a);if(s){var r=this.makeChildWidget({type:"transclude",attributes:{tiddler:{type:"string",value:i}}});r.renderChildren(t,null)}else{$tw.utils.addClass(t,"tmap-graph-placeholder")}};MapWidget.prototype.renderFullWidget=function(e,t,i){utils.setDomListeners("add",window,this.windowDomListeners);utils.setDomListeners("add",e,this.widgetDomListeners);this.addLoadingBar(this.domNode);var s={showDelay:$tm.config.sys.popups.delay};this.visTooltip=new Popup(this.domNode,s);this.sidebar=utils.getFirstElementByClassName("tc-sidebar-scrollable");this.isInSidebar=this.sidebar&&!this.domNode.isTiddlyWikiFakeDom&&this.sidebar.contains(this.domNode);this.doFitAfterStabilize=true;this.preventFitAfterRebuild=false;this.initAndRenderEditorBar(t);this.initAndRenderGraph(i);$tm.registry.push(this);this.reloadRefreshTriggers();this.checkForFreshInstall();if(this.id===$tm.misc.mainEditorId){var a=$tm.url;if(a&&a.query["tmap-enlarged"]){this.toggleEnlargedMode(a.query["tmap-enlarged"])}}};MapWidget.prototype.registerClassNames=function(e){var t=$tw.utils.addClass;t(e,"tmap-widget");if(this.clickToUse){t(e,"tmap-click-to-use")}if(this.getAttr("editor")==="advanced"){t(e,"tmap-advanced-editor")}if(this.getAttr("design")==="plain"){t(e,"tmap-plain-design")}if(!utils.isTrue(this.getAttr("show-buttons"),true)){t(e,"tmap-no-buttons")}if(this.getAttr("class")){t(e,this.getAttr("class"))}};MapWidget.prototype.addLoadingBar=function(e){this.graphLoadingBarDomNode=this.document.createElement("progress");$tw.utils.addClass(this.graphLoadingBarDomNode,"tmap-loading-bar");e.appendChild(this.graphLoadingBarDomNode)};MapWidget.prototype.initAndRenderEditorBar=function(e){this.rebuildEditorBar()};MapWidget.prototype.rebuildEditorBar=function(){var e=this.view;var t={widgetQualifier:this.getStateQualifier(),widgetTempPath:this.widgetTempPath,widgetPopupsPath:this.widgetPopupsPath,isViewBound:String(this.isViewBound()),viewRoot:e.getRoot(),viewLabel:e.getLabel(),viewHolder:this.getViewHolderRef(),edgeTypeFilter:e.getPaths().edgeTypeFilter,allEdgesFilter:$tm.selector.allEdgeTypes,neighScopeBtnClass:"tmap-neigh-scope-button"+(e.isEnabled("neighbourhood_scope")?" "+"tmap-active-button":"")};for(var i in t){this.setVariable(i,t[i])}var s={type:"tiddler",attributes:{tiddler:{type:"string",value:e.getRoot()}},children:[]};if(this.editorMode==="advanced"){s.children.push({type:"transclude",attributes:{tiddler:{type:"string",value:$tm.ref.graphBar}}})}else{s.children.push({type:"element",tag:"span",attributes:{"class":{type:"string",value:"tmap-view-label"}},children:[{type:"text",text:e.getLabel()}]})}s.children.push({type:"transclude",attributes:{tiddler:{type:"string",value:$tm.ref.focusButton}}});this.makeChildWidgets([s]);this.renderChildren(this.graphBarDomNode,this.graphBarDomNode.firstChild)};MapWidget.prototype.refresh=function(e){return false};MapWidget.prototype.update=function(e){if(!this.network||this.isZombieWidget()||utils.isPreviewed(this)){return}var t=e.changedTiddlers;var i=false;var s=false;var a=false;var r={};this.callbackManager.handleChanges(t);if(this.isViewSwitched(t)||this.hasChangedAttributes()||e[$tm.path.options]||e[$tm.path.nodeTypes]||t[this.view.getRoot()]){this.logger("warn","View switched (or main config change)");this.view=this.getView(true);this.reloadRefreshTriggers();i=true;a=true}else{var o=this.view.update(e);if(o&&!this.ignoreNextViewModification){this.logger("warn","View components modified");this.reloadBackgroundImage();i=true;s=true;r.resetEdgeTypeWL=true;if(!this.preventFitAfterRebuild){r.resetFocus={delay:0,duration:0}}}else{if(e[$tm.path.nodeTypes]){s=true}else if(this.hasChangedElements(t)){s=true}}}if(a){this.initAndRenderGraph(this.graphDomNode);this.visTooltip.hide(0,true)}else if(s){this.rebuildGraph(r);this.visTooltip.hide(0,true)}if(i){this.removeChildDomNodes();this.rebuildEditorBar()}else{this.refreshChildren(t)}this.ignoreNextViewModification=false};MapWidget.prototype.reloadRefreshTriggers=function(){this.callbackManager.remove(this.refreshTriggers);var e=this.getAttr("refresh-triggers")||this.view.getConfig("refresh-triggers");this.refreshTriggers=$tw.utils.parseStringArray(e)||[];this.logger("debug","Registering refresh trigger",this.refreshTriggers);for(var t=this.refreshTriggers.length;t--;){this.callbackManager.add(this.refreshTriggers[t],this.handleTriggeredRefresh,false)}};MapWidget.prototype.rebuildGraph=function(e){if(utils.isPreviewed(this))return;this.logger("debug","Rebuilding graph");e=e||{};this.hasNetworkStabilized=false;if(e.resetData){this.graphData.edges.clear();this.graphData.nodes.clear();this.graphData.edgesById=null;this.graphData.nodesById=null}if(!this.view.isEnabled("physics_mode")){var t=this.visOptions.physics;t[t.solver].centralGravity=.015}if(!e.resetFocus){this.doFitAfterStabilize=false}this.rebuildGraphData();if(!utils.hasElements(this.graphData.nodesById)){return}this.network.stabilize();if(e.resetFocus&&!this.preventFitAfterRebuild){this.doFitAfterStabilize=true;this.fitGraph(e.resetFocus.delay,e.resetFocus.duration)}this.preventFitAfterRebuild=false};MapWidget.prototype.getContainer=function(){return this.domNode};MapWidget.prototype.rebuildGraphData=function(e){$tm.start("Reloading Network");e=e||{};var t=$tm.adapter.getGraph({view:this.view});var i=t.nodes;var s=t.edges;this.graphData.nodes=this.getRefreshedDataSet(i,this.graphData.nodesById,this.graphData.nodes);this.graphData.edges=this.getRefreshedDataSet(s,this.graphData.edgesById,this.graphData.edges);this.graphData.nodesById=i;this.graphData.edgesById=s;utils.setField("$:/temp/tmap/nodes/"+this.view.getLabel(),"list",$tm.adapter.getTiddlersById(i));$tm.stop("Reloading Network");return this.graphData};MapWidget.prototype.isViewBound=function(){return utils.startsWith(this.getViewHolderRef(),$tm.path.localHolders)};MapWidget.prototype.isViewSwitched=function(e){return e[this.getViewHolderRef()]};MapWidget.prototype.hasChangedAttributes=function(){return Object.keys(this.computeAttributes()).length};MapWidget.prototype.hasChangedElements=function(e){var t=[];var i=this.graphData.nodesById;var s=this.view.isEnabled("neighbourhood_scope");var a=this.view.getEdgeTypeFilter("whitelist");for(var r in e){if(utils.isSystemOrDraft(r))continue;if(i[$tm.adapter.getId(r)]||s){return true}if(e[r].modified){t.push(r)}}if(t.length){var o=this.view.getNodeFilter("compiled");var n=utils.getMatches(o,t);return!!n.length}};MapWidget.prototype.initAndRenderGraph=function(e){if(this.network)this._destructVis();this.logger("info","Initializing and rendering the graph");if(!this.isInSidebar){this.callbackManager.add("$:/state/sidebar",this.handleResizeEvent)}this.visOptions=this.getVisOptions();this.graphData={nodes:new vis.DataSet,edges:new vis.DataSet,nodesById:utils.makeHashMap(),edgesById:utils.makeHashMap()};this.visTooltip.setEnabled(utils.isTrue($tm.config.sys.popups.enabled,true));this.network=new vis.Network(e,this.graphData,this.visOptions);this.canvas=e.getElementsByTagName("canvas")[0];this.canvas.tabIndex=0;for(var t in this.visListeners){this.network.on(t,this.visListeners[t].bind(this))}this.addGraphButtons({"fullscreen-button":function(){this.toggleEnlargedMode("fullscreen")},"halfscreen-button":function(){this.toggleEnlargedMode("halfscreen")}});utils.setDomListeners("add",this.canvas,this.canvasDomListeners);this.reloadBackgroundImage();this.rebuildGraph({resetFocus:{delay:0,duration:0}});this.handleResizeEvent();this.canvas.focus()};MapWidget.prototype.handleCanvasKeyup=function(){var e={from:null,to:null};return function(t){var i=this.network.getSelectedNodes();if(t.ctrlKey){t.preventDefault();if(t.keyCode===88){if(this.editorMode){this.handleAddNodesToClipboard("move")}else{$tm.notify("Map is read only!")}}else if(t.keyCode===67){this.handleAddNodesToClipboard("copy")}else if(t.keyCode===86){this.handlePasteNodesFromClipboard()}else if(t.keyCode===65){var s=Object.keys(this.graphData.nodesById);this.network.selectNodes(s)}else if(t.keyCode===49||t.keyCode===50){if(i.length!==1)return;var a=t.keyCode===49?"from":"to";$tm.notify(utils.ucFirst(a)+"-part selected");e[a]=i[0];if(e.from&&e.to){this.handleConnectionEvent(e,function(){e={from:null,to:null}})}}}else if(t.keyCode===13){if(i.length!==1)return;this.openTiddlerWithId(i[0])}}}();MapWidget.prototype.handleCanvasKeydown=function(e){if(e.keyCode===46){e.preventDefault();this.handleRemoveElements(this.network.getSelection())}};MapWidget.prototype.handleCanvasScroll=function(e){var t=!!(e.ctrlKey||this.isInSidebar||this.enlargedMode);if(t){e.preventDefault()}if(t!==this.visOptions.interaction.zoomView){e.preventDefault();e.stopPropagation();this.visOptions.interaction.zoomView=t;this.network.setOptions({interaction:{zoomView:t}});return false}};MapWidget.prototype.handleWidgetKeyup=function(e){};MapWidget.prototype.handleWidgetKeydown=function(e){if(e.ctrlKey){e.preventDefault();if(e.keyCode===70){e.preventDefault();var t=this.widgetPopupsPath+"/focus";utils.setText(t,utils.getText(t)?"":"1")}else{return}}else if(e.keyCode===120){e.preventDefault();this.toggleEnlargedMode("halfscreen")}else if(e.keyCode===121){e.preventDefault();this.toggleEnlargedMode("fullscreen")}else if(e.keyCode===27){e.preventDefault();utils.deleteByPrefix(this.widgetPopupsPath)}else{return}this.canvas.focus()};MapWidget.prototype.handlePasteNodesFromClipboard=function(){if(!this.editorMode||this.view.isLiveView()){$tm.notify("Map is read only!");return}if($tm.clipBoard){if($tm.clipBoard.type==="nodes"){var e=$tm.clipBoard.nodes;var t=Object.keys(e);if(t.length){for(var i in e){if(this.graphData.nodesById[i])continue;this.view.addNode(e[i]);this.graphData.nodes.update({id:i})}this.network.selectNodes(t);$tm.notify("pasted "+t.length+" nodes into map.")}return}}$tm.notify("TiddlyMap clipboad is empty!")};MapWidget.prototype.handleAddNodesToClipboard=function(e){var t=this.network.getSelectedNodes();if(!t.length)return;$tm.clipBoard={type:"nodes",nodes:this.graphData.nodes.get(t,{returnType:"Object"})};$tm.notify("Copied "+t.length+" nodes to clipboard");if(e==="move"){for(var i=t.length;i--;){this.view.removeNode(t[i])}}};MapWidget.prototype.isMobileMode=function(){var e=utils.getText($tm.ref.sidebarBreakpoint,960);return window.innerWidth<=parseInt(e)};MapWidget.prototype.getVisOptions=function(){var e=$tm.config.vis;var t=utils.parseJSON(this.view.getConfig("vis"));var i=utils.merge({},e,t);i.clickToUse=this.clickToUse;i.manipulation.enabled=!!this.editorMode;i.manipulation.deleteNode=function(e,t){this.handleRemoveElements(e);this.resetVisManipulationBar(t)}.bind(this);i.manipulation.deleteEdge=function(e,t){this.handleRemoveElements(e);this.resetVisManipulationBar(t)}.bind(this);i.manipulation.addEdge=function(e,t){this.handleConnectionEvent(e);this.resetVisManipulationBar(t)}.bind(this);i.manipulation.addNode=function(e,t){this.handleInsertNode(e);this.resetVisManipulationBar(t)}.bind(this);i.manipulation.editNode=function(e,t){this.handleEditNode(e);this.resetVisManipulationBar(t)}.bind(this);i.interaction.zoomView=!!(this.isInSidebar||this.enlargedMode);i.manipulation.editEdge=false;var s=i.physics;s[s.solver]=s[s.solver]||{};s.stabilization.iterations=1e3;this.logger("debug","Loaded graph options",i);return i};MapWidget.prototype.resetVisManipulationBar=function(e){if(e)e(null);this.network.disableEditMode();this.network.enableEditMode()};MapWidget.prototype.isVisInEditMode=function(){var e="vis-button vis-back";return this.graphDomNode.getElementsByClassName(e).length>0};MapWidget.prototype.handleCreateView=function(){var e={view:this.view.getLabel()};var t="createView";this.dialogManager.open(t,e,function(e,t){if(!e)return;var i=utils.getField(t,"name");var s=utils.getField(t,"clone",false);var a=new ViewAbstraction(i);if(a.exists()){$tm.notify("Forbidden! View already exists!");return}if(s&&this.view.isLiveView()){$tm.notify("Forbidden to clone the live view!");return}a=new ViewAbstraction(i,{isCreate:true,protoView:s?this.view:null});this.setView(a)})};MapWidget.prototype.handleRenameView=function(){if(this.view.isLocked()){$tm.notify("Forbidden!");return}var e=this.view.getOccurrences();var t={count:e.length.toString(),filter:utils.joinAndWrap(e,"[[","]]")};var i="renameView";this.dialogManager.open(i,t,function(e,t){if(e){var i=utils.getText(t);var s=new ViewAbstraction(i);if(!i){$tm.notify("Invalid name!")}else if(s.exists()){$tm.notify("Forbidden! View already exists!")}else{this.view.rename(i);this.setView(this.view)}}})};MapWidget.prototype.handleEditView=function(){var e=JSON.stringify($tm.config.vis);var t=this.graphData;var i=this.view.getConfig();var s={"filter.prettyNodeFltr":this.view.getNodeFilter("pretty"),"filter.prettyEdgeFltr":this.view.getEdgeTypeFilter("pretty"),"vis-inherited":e};var a={view:this.view.getLabel(),createdOn:this.view.getCreationDate(true),numberOfNodes:Object.keys(t.nodesById).length.toString(),numberOfEdges:Object.keys(t.edgesById).length.toString(),dialog:{preselects:$tw.utils.extend({},i,s)}};var r="configureView";this.dialogManager.open(r,a,function(e,t){if(!e)return;var i=utils.getPropertiesByPrefix(t.fields,"config.",true);var s=this.view.getConfig("background_image");this.view.setConfig(i);if(i["physics_mode"]&&!this.view.isEnabled("physics_mode")){this.handleStorePositions()}var a=this.view.getConfig("background_image");if(a&&a!==s){$tm.notify("Background changed! You may need to zoom out a bit.")}var r=utils.getField(t,"filter.prettyNodeFltr","");var o=utils.getField(t,"filter.prettyEdgeFltr","");this.view.setNodeFilter(r);this.view.setEdgeTypeFilter(o)})};MapWidget.prototype.handleSaveCanvas=function(){var e="$:/temp/tmap/snapshot";var t=this.createAndSaveSnapshot(e);var i=utils.getSnapshotTitle(this.view.getLabel(),"png");var s={dialog:{snapshot:e,width:this.canvas.width.toString(),height:this.canvas.height.toString(),preselects:{name:i,action:"download"}}};var a="saveCanvas";this.dialogManager.open(a,s,function(t,s){if(!t)return;i=s.fields.name||i;var a=s.fields.action;if(a==="download"){this.handleDownloadSnapshot(i)}else if(a==="wiki"){utils.cp(e,i,true);this.dispatchEvent({type:"tm-navigate",navigateTo:i})}else if(a==="placeholder"){this.view.addPlaceholder(e)}$tw.wiki.deleteTiddler("$:/temp/tmap/snapshot")})};MapWidget.prototype.handleDownloadSnapshot=function(e){var t=this.document.createElement("a");var i=this.view.getLabel();t.download=e||utils.getSnapshotTitle(i,"png");t.href=this.getSnapshot();var s=new MouseEvent("click");t.dispatchEvent(s)};MapWidget.prototype.createAndSaveSnapshot=function(e){var t=this.view.getLabel();var i=e||this.view.getRoot()+"/snapshot";$tw.wiki.addTiddler(new $tw.Tiddler({title:i,type:"image/png",text:this.getSnapshot(true),modified:new Date}));return i};MapWidget.prototype.getSnapshot=function(e){var t=this.canvas.toDataURL("image/png");return e?utils.getWithoutPrefix(t,"data:image/png;base64,"):t};MapWidget.prototype.handleDeleteView=function(){var e=this.view.getLabel();if(this.view.isLocked()){$tm.notify("Forbidden!");return}var t=this.view.getOccurrences();if(t.length){var i={count:t.length.toString(),filter:utils.joinAndWrap(t,"[[","]]")};this.dialogManager.open("cannotDeleteViewDialog",i);return}var s="You are about to delete the view "+"''"+e+"'' (no tiddler currently references this view).";this.openStandardConfirmDialog(function(t){if(t){this.view.destroy();this.setView($tm.misc.defaultViewLabel);this.logger("debug",'view "'+e+'" deleted ');$tm.notify('view "'+e+'" deleted ')}},s)};MapWidget.prototype.handleTriggeredRefresh=function(e){this.logger("log",e,"Triggered a refresh");if(this.id==="live_tab"){var t=utils.getTiddler(utils.getText(e));if(t){var i=t.fields["tmap.open-view"]||$tm.config.sys.liveTab.fallbackView;if(i&&i!==this.view.getLabel()){this.setView(i);return}}}this.rebuildGraph({resetFocus:{delay:1e3,duration:1e3}})};MapWidget.prototype.handleRemoveElements=function(e){if(e.nodes.length){this.handleRemoveNodes(e.nodes)}else if(e.edges.length){this.handleRemoveEdges(e.edges)}this.resetVisManipulationBar()};MapWidget.prototype.handleRemoveEdges=function(e){$tm.adapter.deleteEdges(this.graphData.edges.get(e));$tm.notify("edge"+(e.length>1?"s":"")+" removed");this.preventFitAfterRebuild=true};MapWidget.prototype.handleRemoveNodes=function(e){var t=$tm.adapter.getTiddlersById(e);var i={count:e.length.toString(),tiddlers:$tw.utils.stringifyList(t),dialog:{preselects:{"delete-from":"filter"}}};var s="deleteNodeDialog";this.dialogManager.open(s,i,function(t,i){if(!t)return;if(i.fields["delete-from"]==="system"){$tm.adapter.deleteNodes(e);var s=e.length}else{var s=0;for(var a=e.length;a--;){var r=this.view.removeNode(e[a]);if(r)s++}}this.preventFitAfterRebuild=true;$tm.notify("Removed "+s+" of "+e.length+" from "+i.fields["delete-from"])})};MapWidget.prototype.toggleEnlargedMode=function(e){if(!this.isInSidebar&&e==="halfscreen")return;this.logger("log","Toggled graph enlargement");var t=this.enlargedMode;if(t){this.network.setOptions({clickToUse:this.clickToUse});utils.findAndRemoveClassNames(["tmap-has-"+t+"-widget","tmap-"+t]);this.enlargedMode=null;document.body.scrollTop=this.scrollTop}if(!t||t!==e&&(e==="fullscreen"||e==="halfscreen"&&!this.isInSidebar)){var i=document.documentElement;this.scrollTop=document.body.scrollTop;this.enlargedMode=e;var s=this.isInSidebar?this.sidebar:utils.getFirstElementByClassName("tc-story-river");$tw.utils.addClass(this.document.body,"tmap-has-"+e+"-widget");$tw.utils.addClass(s,"tmap-has-"+e+"-widget");$tw.utils.addClass(this.domNode,"tmap-"+e);this.network.setOptions({clickToUse:false});$tm.notify("Toggled "+e+" mode")}this.handleResizeEvent()};MapWidget.prototype.handleGenerateWidget=function(e){$tw.rootWidget.dispatchEvent({type:"tmap:tm-generate-widget",paramObject:{view:this.view.getLabel()}})};MapWidget.prototype.handleStorePositions=function(e){var t=this.view.getNodeData();var i=this.network.getPositions();for(var s in i){t[s]=t[s]||{};t[s].x=i[s].x;t[s].y=i[s].y}this.view.saveNodeData(t);this.ignoreNextViewModification=true;if(e){$tm.notify("positions stored")}};MapWidget.prototype.handleVisStabilizedEvent=function(e){if(this.hasNetworkStabilized)return;this.hasNetworkStabilized=true;this.logger("log","Network stabilized after",e.iterations,"iterations");if(!this.view.isEnabled("physics_mode")){var t=this.graphData.nodesById;var i=[];for(var s in t){if(!t[s].x){i.push(s)}}if(i.length){this.setNodesMoveable(i,false);$tm.notify(i.length+" nodes were added to the graph");this.doFitAfterStabilize=true}var a=this.visOptions.physics;a[a.solver].centralGravity=0;this.network.setOptions(this.visOptions)}if(this.doFitAfterStabilize){this.doFitAfterStabilize=false;this.fitGraph(1e3,1e3)}};MapWidget.prototype.handleFocusNode=function(e){this.network.focus($tm.adapter.getId(e.param),{scale:1.5,animation:true})};MapWidget.prototype.isZombieWidget=function(){if(this.domNode.isTiddlyWikiFakeDom===true){return true}else{return!this.document.body.contains(this.getContainer())}};MapWidget.prototype.fitGraph=function(e,t){window.clearTimeout(this.activeFitTimeout);t=t||0;e=e||0;var i=function(){if(this.isZombieWidget())return;this.network.redraw();this.network.fit({animation:{duration:t,easingFunction:"easeOutQuart"}})};this.activeFitTimeout=window.setTimeout(i.bind(this),e)};MapWidget.prototype.handleInsertNode=function(e){var t="addNodeToMap";this.dialogManager.open(t,null,function(t,i){if(!t)return;var s=utils.getField(i,"draft.title");if(utils.tiddlerExists(s)){if(utils.isMatch(s,this.view.getNodeFilter("compiled"))){$tm.notify("Node already exists");return}else{e=$tm.adapter.makeNode(s,e);this.view.addNode(e)}}else{var a=new $tw.Tiddler(i,{"draft.title":null});e.label=s;$tm.adapter.insertNode(e,this.view,a)}this.preventFitAfterRebuild=true})};MapWidget.prototype.handleEditNode=function(e){var t=$tm.indeces.tById[e.id];var i=utils.getTiddler(t);var s=JSON.stringify($tm.config.vis);var a=this.view.getConfig("vis");var r={};r[e.id]=e;var o=$tm.adapter.getInheritedNodeStyles(r);var n=JSON.stringify(o[t]);var d=JSON.stringify(utils.merge({},{color:i.fields["color"]},utils.parseJSON(i.fields["tmap.style"])));var l=this.view.getLabel();var h={id:e.id};var g=this.view.getNodeData(e.id,true)||{};delete g.x;delete g.y;var p={view:l,tiddler:i.fields.title,tidColor:i.fields["color"],tidIcon:i.fields[$tm.field.nodeIcon]||i.fields["tmap.fa-icon"],tidLabelField:"global."+$tm.field.nodeLabel,tidIconField:"global."+$tm.field.nodeIcon,dialog:{preselects:{"inherited-global-default-style":s,"inherited-local-default-style":a,"inherited-group-styles":n,"global.tmap.style":d,"local-node-style":JSON.stringify(g)}}};var u=function(e,t,i){for(var s=i.length;s--;){p.dialog.preselects[e+"."+i[s]]=t[i[s]]||""}};u("local",g,["label","tw-icon","fa-icon","open-view"]);u("global",i.fields,[$tm.field.nodeLabel,$tm.field.nodeIcon,"tmap.fa-icon","tmap.open-view"]);this.dialogManager.open("editNode",p,function(i,s){if(!i)return;var a=s.fields;var r=utils.getPropertiesByPrefix(a,"global.",true);for(var o in r){utils.setField(t,o,r[o]||undefined)}var n=utils.getPropertiesByPrefix(a,"local.",true);var d=utils.parseJSON(a["local-node-style"],{});for(var o in n){d[o]=n[o]||undefined}this.view.saveNodeStyle(e.id,d);this.preventFitAfterRebuild=true})};MapWidget.prototype.handleVisSingleClickEvent=function(e){var t=utils.isTrue($tm.config.sys.singleClickMode);if(t&&!this.editorMode){this.handleOpenMapElementEvent(e)}};MapWidget.prototype.handleVisDoubleClickEvent=function(e){if(e.nodes.length||e.edges.length){if(this.editorMode||!utils.isTrue($tm.config.sys.singleClickMode)){this.handleOpenMapElementEvent(e)}}else{if(this.editorMode){this.handleInsertNode(e.pointer.canvas)}}};MapWidget.prototype.handleOpenMapElementEvent=function(e){if(e.nodes.length){var t=this.graphData.nodesById[e.nodes[0]];if(t["open-view"]){$tm.notify("Switching view");this.setView(t["open-view"])}else{this.openTiddlerWithId(e.nodes[0])}}else if(e.edges.length){this.logger("debug","Clicked on an Edge");var i=this.graphData.edgesById[e.edges[0]].type;this.handleEditEdgeType(i)}else{return}this.visTooltip.hide(0,true)};MapWidget.prototype.handleEditEdgeType=function(e){if(!this.editorMode)return;var t=$tm.config.sys.edgeClickBehaviour;if(t!=="manager")return;$tw.rootWidget.dispatchEvent({type:"tmap:tm-manage-edge-types",paramObject:{type:e}})};MapWidget.prototype.handleResizeEvent=function(e){if(this.isZombieWidget())return;var t=this.getAttr("height");var i=this.getAttr("width");if(this.isInSidebar){var s=this.domNode.getBoundingClientRect();var a=15;i=document.body.clientWidth-s.left-a+"px";var r=parseInt(this.getAttr("bottom-spacing"))||15;var o=window.innerHeight-s.top;t=o-r+"px"}this.domNode.style.height=t||"300px";this.domNode.style.width=i;this.repaintGraph()};MapWidget.prototype.handleClickEvent=function(e){if(this.isZombieWidget()||!this.network)return;if(!this.graphDomNode.contains(e.target)){var t=this.network.getSelection();if(t.nodes.length||t.edges.length){this.logger("debug","Clicked outside; deselecting nodes/edges");this.network.selectNodes([]);this.resetVisManipulationBar()}}else{this.canvas.focus()}};MapWidget.prototype.handleVisOnContext=function(e){};MapWidget.prototype.handleVisSelectNode=function(e){this.assignActiveStyle(e.nodes)};MapWidget.prototype.assignActiveStyle=function(e){if(!Array.isArray(e))e=[e];var t=this.visOptions.nodes.color;for(var i=e.length;i--;){var s=e[i];var a=this.graphData.nodesById[s];var r=utils.merge({},t,a.color);this.graphData.nodes.update({id:s,color:{highlight:r,hover:r}})}};MapWidget.prototype.handleVisDeselectNode=function(e){};MapWidget.prototype.handleVisDragEnd=function(e){if(!e.nodes.length)return;this.setNodesMoveable(e.nodes,false)};MapWidget.prototype.handleVisBeforeDrawing=function(e){if(this.backgroundImage){e.drawImage(this.backgroundImage,0,0)}};MapWidget.prototype.constructTooltip=function(e,t){var i=utils.parseJSON(e);var s=i.node||i.edge;var a=null;var r="text/html";var o="text/vnd-tiddlywiki";if(i.node){var n=$tm.indeces.tById[s];var d=utils.getTiddler(n);var l=d.fields[$tm.field.nodeInfo];if(l){t.innerHTML=$tw.wiki.renderText(r,o,l)}else if(d.fields.text){var h={type:"tiddler",attributes:{tiddler:{type:"string",value:n}},children:[{type:"transclude",attributes:{},isBlock:true}]};utils.removeArrayElement(this.children,this.tmpTooltipWidget);this.tmpTooltipWidget=this.makeChildWidget(h);this.tmpTooltipWidget.setVariable("tv-tiddler-preview","yes");this.tmpTooltipWidget.render(t,null);this.children.push(this.tmpTooltipWidget);return}else{t.innerHTML=n}}else{var g=this.graphData.edgesById[s];var p=$tm.indeces.allETy[g.type];if(p.description){a=$tw.wiki.renderText(r,o,p.description)}t.innerHTML=a||p.label||p.id}};MapWidget.prototype.handleVisHoverElement=function(e){if($tm.mouse.buttons)return;var t=e.node||e.edge;var i=JSON.stringify(e);if(e.node){this.assignActiveStyle(t)}if(!this.isVisInEditMode()){var s=this.constructTooltip;var i=JSON.stringify(e);this.visTooltip.show(i,s)}};MapWidget.prototype.handleVisBlurElement=function(e){this.visTooltip.hide()};MapWidget.prototype.handleVisLoading=function(e){this.graphLoadingBarDomNode.style.display="block";this.graphLoadingBarDomNode.setAttribute("max",e.total);this.graphLoadingBarDomNode.setAttribute("value",e.iterations)};MapWidget.prototype.handleVisLoadingDone=function(e){this.graphLoadingBarDomNode.style.display="none"};MapWidget.prototype.handleVisDragStart=function(e){if(e.nodes.length){this.visTooltip.hide(0,true);this.assignActiveStyle(e.nodes);this.setNodesMoveable(e.nodes,true)}};MapWidget.prototype.destruct=function(){utils.setDomListeners("remove",window,this.windowDomListeners);utils.setDomListeners("remove",this.domNode,this.widgetDomListeners);this._destructVis()};MapWidget.prototype._destructVis=function(){if(!this.network)return;utils.setDomListeners("remove",this.canvas,this.canvasDomListeners);this.network.destroy();this.network=null};MapWidget.prototype.openTiddlerWithId=function(e){var t=$tm.indeces.tById[e];this.logger("debug","Opening tiddler",t,"with id",e);if(this.enlargedMode==="fullscreen"){var i=this.wiki.findDraft(t);var s=!!i;if(!s){var a="tm-edit-tiddler";this.dispatchEvent({type:a,tiddlerTitle:t});i=this.wiki.findDraft(t)}var r={