tw5-graph 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -0
- package/package.json +39 -0
- package/plugins/graph/DefaultColourMappings.multids +8 -0
- package/plugins/graph/ViewTemplateBodyFilter/graph.tid +5 -0
- package/plugins/graph/ViewTemplateBodyFilter/properties.tid +5 -0
- package/plugins/graph/edges/fields/list.tid +7 -0
- package/plugins/graph/edges/fields/tags.tid +7 -0
- package/plugins/graph/edges/functions/links.tid +8 -0
- package/plugins/graph/edges/functions/transcludes.tid +8 -0
- package/plugins/graph/fieldtypes/filter.js +212 -0
- package/plugins/graph/fieldtypes/list.js +31 -0
- package/plugins/graph/fieldtypes/title.js +27 -0
- package/plugins/graph/filterrunprefixes/cache.js +118 -0
- package/plugins/graph/filters/gettyped.js +26 -0
- package/plugins/graph/graphengine.js +38 -0
- package/plugins/graph/icon.tid +16 -0
- package/plugins/graph/images/drag.tid +13 -0
- package/plugins/graph/macros/action.addedge.tid +16 -0
- package/plugins/graph/macros/edges.typed.tid +54 -0
- package/plugins/graph/macros/graph.view.tid +24 -0
- package/plugins/graph/macros/node.default.tid +9 -0
- package/plugins/graph/macros/nodes.neighbors.tid +62 -0
- package/plugins/graph/macros/nodes.writable.tid +37 -0
- package/plugins/graph/macros/properties.persistent.tid +27 -0
- package/plugins/graph/macros/properties.popup.tid +76 -0
- package/plugins/graph/macros/properties.river.tid +27 -0
- package/plugins/graph/macros/properties.settings.tid +54 -0
- package/plugins/graph/macros/properties.stack.tid +17 -0
- package/plugins/graph/macros/tiddlywiki.files +17 -0
- package/plugins/graph/nodes/neighbors/1.tid +8 -0
- package/plugins/graph/plugin.info +14 -0
- package/plugins/graph/presettypes/edges/fields.tid +18 -0
- package/plugins/graph/presettypes/edges/functions.tid +5 -0
- package/plugins/graph/presettypes/nodes/neighbors.tid +4 -0
- package/plugins/graph/presettypes/nodes/stack.tid +6 -0
- package/plugins/graph/propertytypes/actions.js +15 -0
- package/plugins/graph/propertytypes/boolean.js +23 -0
- package/plugins/graph/propertytypes/color.js +61 -0
- package/plugins/graph/propertytypes/enum.js +25 -0
- package/plugins/graph/propertytypes/filter.js +44 -0
- package/plugins/graph/propertytypes/image.js +185 -0
- package/plugins/graph/propertytypes/number.js +24 -0
- package/plugins/graph/propertytypes/string.js +13 -0
- package/plugins/graph/propertytypes/tiddlywiki.files +17 -0
- package/plugins/graph/readme.tid +5 -0
- package/plugins/graph/relink/attributes.js +52 -0
- package/plugins/graph/relink/attributes.multids +19 -0
- package/plugins/graph/relink/configprefix.js +76 -0
- package/plugins/graph/relink/fieldedgeprefix.js +39 -0
- package/plugins/graph/relink/fields.multids +11 -0
- package/plugins/graph/relink/graphprefix.js +28 -0
- package/plugins/graph/relink/operators.multids +3 -0
- package/plugins/graph/relink/propertyfields.js +81 -0
- package/plugins/graph/relink/utils.js +99 -0
- package/plugins/graph/settings.tid +13 -0
- package/plugins/graph/startup/messages.js +46 -0
- package/plugins/graph/stylesheets/base.css.tid +272 -0
- package/plugins/graph/stylesheets/fullscreen/core.css +11 -0
- package/plugins/graph/stylesheets/fullscreen/core.css.meta +3 -0
- package/plugins/graph/stylesheets/fullscreen.css.tid +48 -0
- package/plugins/graph/stylesheets/popup.css.tid +107 -0
- package/plugins/graph/subfilters.tid +23 -0
- package/plugins/graph/tags/GraphToolbar.tid +2 -0
- package/plugins/graph/tags/SettingsTab.tid +2 -0
- package/plugins/graph/tags/Template.tid +2 -0
- package/plugins/graph/tags/ViewEditTemplate.tid +2 -0
- package/plugins/graph/templates/live-graph.tid +34 -0
- package/plugins/graph/templates/standard-graph.tid +40 -0
- package/plugins/graph/ui/Buttons/center.tid +38 -0
- package/plugins/graph/ui/Buttons/export.tid +65 -0
- package/plugins/graph/ui/Buttons/fullscreen.tid +35 -0
- package/plugins/graph/ui/Buttons/settings.tid +28 -0
- package/plugins/graph/ui/Buttons/tiddlywiki.files +16 -0
- package/plugins/graph/ui/EditTemplate/Edges.tid +22 -0
- package/plugins/graph/ui/EditTemplate/Neighbors.tid +35 -0
- package/plugins/graph/ui/EditTemplate/Nodes.tid +12 -0
- package/plugins/graph/ui/EditTemplate/Popups.tid +27 -0
- package/plugins/graph/ui/EditTemplate/Properties.tid +21 -0
- package/plugins/graph/ui/EditTemplate/tiddlywiki.files +16 -0
- package/plugins/graph/ui/Modals/NewPropertySet.tid +20 -0
- package/plugins/graph/ui/Modals/NewView.tid +20 -0
- package/plugins/graph/ui/Modals/Select.tid +72 -0
- package/plugins/graph/ui/Modals/SelectField.tid +21 -0
- package/plugins/graph/ui/Modals/SelectTiddler.tid +15 -0
- package/plugins/graph/ui/Modals/Tiddler.tid +22 -0
- package/plugins/graph/ui/Modals/TiddlerHeader.tid +15 -0
- package/plugins/graph/ui/PropertyTypes/boolean.tid +11 -0
- package/plugins/graph/ui/PropertyTypes/color.tid +16 -0
- package/plugins/graph/ui/PropertyTypes/enum.tid +15 -0
- package/plugins/graph/ui/PropertyTypes/number.tid +17 -0
- package/plugins/graph/ui/Settings/Engine.tid +23 -0
- package/plugins/graph/ui/Settings/Graphs/EditTemplate.tid +52 -0
- package/plugins/graph/ui/Settings/Graphs.tid +49 -0
- package/plugins/graph/ui/Settings/Properties/ObjectsTypeTemplate.tid +46 -0
- package/plugins/graph/ui/Settings/Properties.tid +14 -0
- package/plugins/graph/ui/Settings/Toolbar.tid +5 -0
- package/plugins/graph/ui/SideBar/Graph.tid +77 -0
- package/plugins/graph/ui/Toolbars/GraphToolbar.tid +15 -0
- package/plugins/graph/ui/ViewTemplate/graph-object.tid +13 -0
- package/plugins/graph/ui/ViewTemplate/graph.tid +11 -0
- package/plugins/graph/ui/ViewTemplate/properties.tid +80 -0
- package/plugins/graph/ui/grouped-tabs.tid +109 -0
- package/plugins/graph/ui/selector.tid +74 -0
- package/plugins/graph/utils/propertyholder.js +80 -0
- package/plugins/graph/utils/widgetiterator.js +47 -0
- package/plugins/graph/utils.js +95 -0
- package/plugins/graph/widgets/action-delay.js +72 -0
- package/plugins/graph/widgets/action-modal.js +121 -0
- package/plugins/graph/widgets/action-typed.js +56 -0
- package/plugins/graph/widgets/action-with.js +70 -0
- package/plugins/graph/widgets/boundingbox.js +126 -0
- package/plugins/graph/widgets/fieldtranscriber/filter.js +93 -0
- package/plugins/graph/widgets/fieldtranscriber/json.js +34 -0
- package/plugins/graph/widgets/fieldtranscriber/plain.js +11 -0
- package/plugins/graph/widgets/fieldtranscriber.js +98 -0
- package/plugins/graph/widgets/graphobject.js +154 -0
- package/plugins/graph/widgets/messagerelay.js +115 -0
- package/plugins/graph/widgets/properties.js +130 -0
- package/plugins/graph/widgets/subclass/edge.js +55 -0
- package/plugins/graph/widgets/subclass/edit-color.js +52 -0
- package/plugins/graph/widgets/subclass/graph.js +380 -0
- package/plugins/graph/widgets/subclass/node.js +56 -0
- package/plugins/graph/widgets/tiddlywiki.files +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Graph for Tiddlywiki
|
|
2
|
+
|
|
3
|
+
Tiddlywiki is a great non-linear notebook.
|
|
4
|
+
The internet has countless amazing visualization libraries for creating graphs.
|
|
5
|
+
|
|
6
|
+
TW5-Graph brings them together.
|
|
7
|
+
|
|
8
|
+
It is a framework plugin for creating graphs in Tiddlywiki. It has a quick and simple interface to make graphs quickly, but is also highly customizable so you can create the exact style of graphs you need.
|
|
9
|
+
|
|
10
|
+
For a demonstration and documentation, see the [demo site](https://flibbles.github.io/tw5-graph/).
|
|
11
|
+
|
|
12
|
+
**TW5-Graph is still being developed! But I'm making a point of not adding features unless someone wants it, so if this plugin doesn't have a feature you think it should have, then open up an issue and make a feature request!**
|
|
13
|
+
|
|
14
|
+
## How to install
|
|
15
|
+
|
|
16
|
+
TW5-Graph requires you to install it **and** at least one other plugin wrapping a visualization engine. Currently, only one is supported.
|
|
17
|
+
|
|
18
|
+
[Vis-network](https://github.com/flibbles/tw5-vis-network)
|
|
19
|
+
|
|
20
|
+
If you're using a single-file tiddlywiki, all you have to do is visit the [demo site](https://flibbles.github.io/tw5-graph/), where both TW5-Graph and all its supported engines are available for a quick drag-and-drop install.
|
|
21
|
+
|
|
22
|
+
### For Node.js
|
|
23
|
+
|
|
24
|
+
The following is an abridged version of the [instructions found here](https://tiddlywiki.com/#Installing%20custom%20plugins%20on%20Node.js).
|
|
25
|
+
|
|
26
|
+
First, check out the source code using git. Then add its`plugins` directory to your TIDDLYWIKI_PLUGIN_PATH environment variable.
|
|
27
|
+
|
|
28
|
+
For instance, if you check out the project to a "~/Documents/Graph" directory. Then run `echo "TIDDLYWIKI_PLUGIN_PATH=${TIDDLYWIKI_PLUGIN_PATH}:~/Documents/Graph/plugins" >> .profile`
|
|
29
|
+
|
|
30
|
+
**You will need to repeat this process for the visualization libraries you plan to pair TW5-Graph with.**
|
|
31
|
+
|
|
32
|
+
Afterward, add the plugin inside your projects' `tiddlywiki.info` file.
|
|
33
|
+
The plugins section will look something like:
|
|
34
|
+
```
|
|
35
|
+
{
|
|
36
|
+
...
|
|
37
|
+
"plugins": [
|
|
38
|
+
...
|
|
39
|
+
"flibbles/graph",
|
|
40
|
+
"flibbles/(vis-network or some other visualization plugin)"
|
|
41
|
+
],
|
|
42
|
+
...
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Alternatively, you can also copy the `plugins` directly into your projects'
|
|
47
|
+
root directory. Though this makes the install local only to those specific
|
|
48
|
+
projects.
|
|
49
|
+
|
|
50
|
+
## How to test
|
|
51
|
+
|
|
52
|
+
### With npm
|
|
53
|
+
|
|
54
|
+
The simplest way is through npm. This will manage all dependencies. From the project's root directory, do the following:
|
|
55
|
+
|
|
56
|
+
1. Run `npm install` to build a few dependencies.
|
|
57
|
+
2. Run `npm test` to run the tests.
|
|
58
|
+
|
|
59
|
+
### Without npm
|
|
60
|
+
|
|
61
|
+
This project is simple enough that you can run the tests without having to deal with npm. If you have tiddlywiki available, all you have to do is run the following from the root directory:
|
|
62
|
+
|
|
63
|
+
`tiddlywiki --build test`
|
|
64
|
+
|
|
65
|
+
However, not all tests may run if you don't have _relink_ and _relink-fieldnames_ available on your `TIDDLYWIKI_PLUGIN_PATH` enviroment variable. See the [relink project page](https://github.com/flibbles/tw5-relink) for instructions on how to set that up.
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tw5-graph",
|
|
3
|
+
"version": "1.7.1",
|
|
4
|
+
"description": "Lightweight and programmable graphing for Tiddlywiki",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"directories": {
|
|
7
|
+
"doc": "docs"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tiddlywiki ++node_modules/tw5-vis-network/plugins/vis-network ++node_modules/mermaid-tw5/mermaid-tw5/plugins/mermaid-tw5 --build index bundle",
|
|
11
|
+
"test": "tiddlywiki ++node_modules/tw5-vis-network/plugins/vis-network ++node_modules/mermaid-tw5/mermaid-tw5/plugins/mermaid-tw5 ++node_modules/tw5-relink/plugins/relink ++node_modules/tw5-relink/plugins/relink-fieldnames --build test"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/flibbles/tw5-graph.git"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"tiddlywiki5",
|
|
19
|
+
"tiddlywiki-plugin",
|
|
20
|
+
"visualization-tools"
|
|
21
|
+
],
|
|
22
|
+
"author": "Flibbles",
|
|
23
|
+
"license": "BSD-3-Clause",
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/flibbles/tw5-graph/issues"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"plugins/"
|
|
29
|
+
],
|
|
30
|
+
"homepage": "https://github.com/flibbles/tw5-graph#readme",
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"tiddlywiki": "^5.3.8"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"tw5-relink": "github:flibbles/tw5-relink",
|
|
36
|
+
"tw5-vis-network": "github:flibbles/tw5-vis-network#v10.6.3",
|
|
37
|
+
"mermaid-tw5": "github:flibbles/mermaid-tw5"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
title: $:/config/DefaultColourMappings/
|
|
2
|
+
|
|
3
|
+
graph-banner-background: <<colour sidebar-tab-background>>
|
|
4
|
+
graph-banner-foreground: <<colour sidebar-tab-foreground>>
|
|
5
|
+
graph-background: <<colour background>>
|
|
6
|
+
graph-border: <<colour tiddler-border>>
|
|
7
|
+
graph-node-color: <<colour primary>>
|
|
8
|
+
graph-font-color: <<colour foreground>>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
title: $:/plugins/flibbles/graph/ViewTemplateBodyFilter/properties
|
|
2
|
+
list-before: $:/config/ViewTemplateBodyFilters/code-body
|
|
3
|
+
tags: $:/tags/ViewTemplateBodyFilter
|
|
4
|
+
|
|
5
|
+
[removeprefix[$:/config/flibbles/graph/]search:title[/]then[$:/plugins/flibbles/graph/ui/ViewTemplate/graph-object]]
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/*\
|
|
2
|
+
title: $:/plugins/flibbles/graph/fieldtypes/filter.js
|
|
3
|
+
type: application/javascript
|
|
4
|
+
module-type: fieldtype
|
|
5
|
+
|
|
6
|
+
\*/
|
|
7
|
+
|
|
8
|
+
"use strict";
|
|
9
|
+
|
|
10
|
+
exports.name = "filter";
|
|
11
|
+
|
|
12
|
+
exports.get = function(tiddler, field, options) {
|
|
13
|
+
// We optimize by storing a cache of compiled filters for this tiddler
|
|
14
|
+
// We will need them a lot, especially if our graphs are doing neighbor
|
|
15
|
+
// evaluation, which will call on these filters with every single change.
|
|
16
|
+
var fieldCache = options.wiki.getCacheForTiddler(tiddler.fields.title, "filter-fields", function() {
|
|
17
|
+
return Object.create(null);
|
|
18
|
+
});
|
|
19
|
+
var method = fieldCache[field];
|
|
20
|
+
if (method === undefined) {
|
|
21
|
+
// We haven't cached this filter function yet
|
|
22
|
+
var filterStr = tiddler.getFieldString(field);
|
|
23
|
+
fieldCache[field] = method = getFilterFunction(filterStr, options.wiki);
|
|
24
|
+
}
|
|
25
|
+
return method.call(options.wiki, null, options.widget);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
exports.add = function(tiddler, field, value, options) {
|
|
29
|
+
var filterString = tiddler && tiddler.getFieldString(field);
|
|
30
|
+
var changed = false;
|
|
31
|
+
// We don't want to add the title if it's already a filter result.
|
|
32
|
+
while (options.wiki.filterTiddlers(filterString, options.widget).indexOf(value) < 0) {
|
|
33
|
+
changed = true;
|
|
34
|
+
var filterTree = options.wiki.parseFilter(filterString);
|
|
35
|
+
var found = false;
|
|
36
|
+
// Search backwards for any explicit removal of the target Ref
|
|
37
|
+
// Otherwise, we might get `... -value value`
|
|
38
|
+
for (let i = filterTree.length-1; i>= 0; i--) {
|
|
39
|
+
var run = filterTree[i];
|
|
40
|
+
var title = runIsSingleTitle(run);
|
|
41
|
+
if (title !== null) {
|
|
42
|
+
if (run.prefix === "-" && title === value) {
|
|
43
|
+
// We found an explicit removal. Remove the removal.
|
|
44
|
+
filterTree.splice(i, 1);
|
|
45
|
+
found = true;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
} else if (run.prefix) {
|
|
49
|
+
// This filter has gotten complicated.
|
|
50
|
+
// Forget searching for explicit removals.
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (!found) {
|
|
55
|
+
// We didn't find an explicit removal (expected),
|
|
56
|
+
// so we add the title to the list.
|
|
57
|
+
filterTree.push({
|
|
58
|
+
prefix: "",
|
|
59
|
+
operators: [{operator: "title", operands: [{text: value}]}]});
|
|
60
|
+
}
|
|
61
|
+
filterString = reassembleFilter(filterTree);
|
|
62
|
+
// Now we go back and try again to make sure it actually took.
|
|
63
|
+
}
|
|
64
|
+
if (changed) {
|
|
65
|
+
return filterString;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
exports.remove = function(tiddler, field, value, options) {
|
|
70
|
+
var filterString = tiddler && tiddler.getFieldString(field);
|
|
71
|
+
var changed = false;
|
|
72
|
+
// We don't want to remove a title that's not already there
|
|
73
|
+
while (filterString && options.wiki.filterTiddlers(filterString, options.widget).indexOf(value) >= 0) {
|
|
74
|
+
changed = true;
|
|
75
|
+
var filterTree = options.wiki.parseFilter(filterString);
|
|
76
|
+
var found = false;
|
|
77
|
+
for (let i = filterTree.length-1; i >= 0; i--) {
|
|
78
|
+
let run = filterTree[i];
|
|
79
|
+
let title = runIsSingleTitle(run);
|
|
80
|
+
if (title !== null) {
|
|
81
|
+
if (!run.prefix && title === value) {
|
|
82
|
+
// This is the title we're looking for. Remove it.
|
|
83
|
+
filterTree.splice(i, 1);
|
|
84
|
+
found = true;
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
} else if (run.prefix) {
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (!found) {
|
|
92
|
+
// We couldn't find it. So it must be a complicated filter.
|
|
93
|
+
// We'll put in a manual removal.
|
|
94
|
+
filterTree.push({
|
|
95
|
+
prefix: "-",
|
|
96
|
+
operators: [{operator: "title", operands: [{text: value}]}]});
|
|
97
|
+
}
|
|
98
|
+
filterString = reassembleFilter(filterTree, this.actionClean);
|
|
99
|
+
// Now we do it again to make sure it was actually removed
|
|
100
|
+
}
|
|
101
|
+
if (changed) {
|
|
102
|
+
return filterString;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// This returns a compiled filter given a string. It optimizes where it can.
|
|
107
|
+
function getFilterFunction(filterStr, wiki) {
|
|
108
|
+
var method;
|
|
109
|
+
if (filterStr) {
|
|
110
|
+
method = wiki.compileFilter(filterStr);
|
|
111
|
+
// A further optimization here.
|
|
112
|
+
// If the filter is very simple, as in nothing by titles,
|
|
113
|
+
// then we can just call it now and cache the output,
|
|
114
|
+
// because it will never change.
|
|
115
|
+
if (filterStr.indexOf("[") < 0) {
|
|
116
|
+
var results = method.call(wiki);
|
|
117
|
+
method = function() { return results; };
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
method = function() { return []; };
|
|
121
|
+
}
|
|
122
|
+
return method;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// If this is a single title, return the title, otherwise null
|
|
126
|
+
function runIsSingleTitle(run) {
|
|
127
|
+
if (run.operators.length === 1 && !run.namedPrefix) {
|
|
128
|
+
var op = run.operators[0];
|
|
129
|
+
if (op.operator === "title"
|
|
130
|
+
&& op.operands.length === 1
|
|
131
|
+
&& !op.suffix
|
|
132
|
+
&& !op.prefix) {
|
|
133
|
+
var operand = op.operands[0];
|
|
134
|
+
if (!operand.variable && !operand.indirect) {
|
|
135
|
+
return operand.text;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return null;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
function reassembleFilter(parseTree, clean) {
|
|
143
|
+
// This will hold all of the filter parts
|
|
144
|
+
const fragments = [];
|
|
145
|
+
// Rebuild the filter.
|
|
146
|
+
for (var i = 0; i < parseTree.length; i++) {
|
|
147
|
+
var run = parseTree[i];
|
|
148
|
+
if (fragments.length > 0) {
|
|
149
|
+
fragments.push(" ");
|
|
150
|
+
}
|
|
151
|
+
fragments.push(run.prefix);
|
|
152
|
+
let title = runIsSingleTitle(run);
|
|
153
|
+
if (title) {
|
|
154
|
+
fragments.push(bestQuoteFor(title));
|
|
155
|
+
} else if (run.operators.length > 0) {
|
|
156
|
+
fragments.push("[");
|
|
157
|
+
for (let j = 0; j < run.operators.length; j++) {
|
|
158
|
+
let op = run.operators[j];
|
|
159
|
+
let firstOperand = true;
|
|
160
|
+
if (op.prefix) {
|
|
161
|
+
fragments.push(op.prefix);
|
|
162
|
+
}
|
|
163
|
+
if (op.operator !== "title" || op.suffix) {
|
|
164
|
+
fragments.push(op.operator);
|
|
165
|
+
}
|
|
166
|
+
if (op.suffix) {
|
|
167
|
+
fragments.push(':', op.suffix);
|
|
168
|
+
}
|
|
169
|
+
if (op.regexp) {
|
|
170
|
+
fragments.push("/", op.regexp.source, "/");
|
|
171
|
+
if (op.regexp.flags) {
|
|
172
|
+
fragments.push("(", op.regexp.flags, ")");
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
for (let k = 0; k < op.operands.length; k++) {
|
|
176
|
+
let operand = op.operands[k];
|
|
177
|
+
if (!firstOperand) {
|
|
178
|
+
fragments.push(',');
|
|
179
|
+
}
|
|
180
|
+
firstOperand = false;
|
|
181
|
+
if (operand.variable) {
|
|
182
|
+
fragments.push('<', operand.text, '>');
|
|
183
|
+
} else if (operand.indirect) {
|
|
184
|
+
fragments.push('{', operand.text, '}');
|
|
185
|
+
} else {
|
|
186
|
+
fragments.push('[', operand.text, ']');
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
fragments.push(']');
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Return compiled filter string, if there is one
|
|
195
|
+
if (clean && fragments.length == 0) {
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
return fragments.join("");
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
function bestQuoteFor(title) {
|
|
202
|
+
if (/^[^\s\[\]\-+~=:'"][^\s\[\]]*$/.test(title)) {
|
|
203
|
+
return title;
|
|
204
|
+
}
|
|
205
|
+
if (title.indexOf("]") < 0) {
|
|
206
|
+
return "[[" + title + "]]";
|
|
207
|
+
}
|
|
208
|
+
if (title.indexOf("'") < 0) {
|
|
209
|
+
return "'" + title + "'";
|
|
210
|
+
}
|
|
211
|
+
return '"' + title + '"';
|
|
212
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*\
|
|
2
|
+
title: $:/plugins/flibbles/graph/fieldtypes/list.js
|
|
3
|
+
type: application/javascript
|
|
4
|
+
module-type: fieldtype
|
|
5
|
+
|
|
6
|
+
\*/
|
|
7
|
+
|
|
8
|
+
"use strict";
|
|
9
|
+
|
|
10
|
+
exports.name = "list";
|
|
11
|
+
|
|
12
|
+
exports.add = function(tiddler, field, value, options) {
|
|
13
|
+
var array = (tiddler && tiddler.getFieldList(field)) || [];
|
|
14
|
+
if (array.indexOf(value) < 0) {
|
|
15
|
+
array.push(value);
|
|
16
|
+
return $tw.utils.stringifyList(array);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
exports.remove = function(tiddler, field, value, options) {
|
|
21
|
+
var array = (tiddler && tiddler.getFieldList(field)) || [];
|
|
22
|
+
var index = array.indexOf(value);
|
|
23
|
+
if (index >= 0) {
|
|
24
|
+
array.splice(index, 1);
|
|
25
|
+
return $tw.utils.stringifyList(array);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
exports.get = function(tiddler, field, options) {
|
|
30
|
+
return tiddler.getFieldList(field);
|
|
31
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/*\
|
|
2
|
+
title: $:/plugins/flibbles/graph/fieldtypes/title.js
|
|
3
|
+
type: application/javascript
|
|
4
|
+
module-type: fieldtype
|
|
5
|
+
|
|
6
|
+
\*/
|
|
7
|
+
|
|
8
|
+
"use strict";
|
|
9
|
+
|
|
10
|
+
exports.name = "title";
|
|
11
|
+
|
|
12
|
+
exports.add = function(tiddler, field, value, options) {
|
|
13
|
+
if (!tiddler || tiddler.fields[field] !== value) {
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
exports.remove = function(tiddler, field, value, options) {
|
|
19
|
+
if (tiddler && tiddler.fields[field] === value) {
|
|
20
|
+
return "";
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
exports.get = function(tiddler, field) {
|
|
25
|
+
var value = tiddler.getFieldString(field);
|
|
26
|
+
return value? [value]: [];
|
|
27
|
+
};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/*\
|
|
2
|
+
title: $:/plugins/flibbles/graph/filterrunprefixes/cache.js
|
|
3
|
+
type: application/javascript
|
|
4
|
+
module-type: filterrunprefix
|
|
5
|
+
|
|
6
|
+
Allows the results of a filter run to be cached for later filter executions.
|
|
7
|
+
The runs MUST be generator functions. Local-run input is ignored, but run is
|
|
8
|
+
executed each time
|
|
9
|
+
|
|
10
|
+
\*/
|
|
11
|
+
|
|
12
|
+
"use strict";
|
|
13
|
+
|
|
14
|
+
// The counter is an incrementing value we use to uniquely identify
|
|
15
|
+
// instances of opFunction. opFunction, in turn, is cached by TW's limited
|
|
16
|
+
// cache of compiled filters.
|
|
17
|
+
var counter = 0;
|
|
18
|
+
|
|
19
|
+
exports.cache = function(operationSubFunction, options) {
|
|
20
|
+
var opFunction = function(results, _/*ignored source*/, widget) {
|
|
21
|
+
// Use the input from previous runs as currentTiddlers.
|
|
22
|
+
// If there was not input, then we'll introduce an empty string as
|
|
23
|
+
// currentTiddler.
|
|
24
|
+
var inputTitles = results.toArray();
|
|
25
|
+
if (inputTitles.length == 0) {
|
|
26
|
+
inputTitles.push("");
|
|
27
|
+
}
|
|
28
|
+
results.clear();
|
|
29
|
+
var root = options.wiki.getGlobalCache("filterPrefix-" + opFunction.cacheKey, function() { return Object.create(null); });
|
|
30
|
+
for (var i = 0; i < inputTitles.length; i++) {
|
|
31
|
+
var current = inputTitles[i];
|
|
32
|
+
// Roots start as {}, or a Node that is not yet Branch or Leaf
|
|
33
|
+
root[current] = root[current] || {};
|
|
34
|
+
var output = execute(current, root[current], operationSubFunction, widget);
|
|
35
|
+
results.push.apply(results, output);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
opFunction.cacheKey = counter++;
|
|
39
|
+
return opFunction;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/*
|
|
43
|
+
Node = { } // A node begins as undefined until we make it a branch or node.
|
|
44
|
+
Branch = {
|
|
45
|
+
variable: "Variable name",
|
|
46
|
+
options: (options that came with getVariable call)
|
|
47
|
+
children: { "variable value": <Node>, ...},
|
|
48
|
+
}
|
|
49
|
+
Leaf = {
|
|
50
|
+
value: ["Outputs", ...]
|
|
51
|
+
}
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
function execute(currentTiddler, root, operationSubFunction, widget) {
|
|
55
|
+
// First, try to retrieve from cache if it's available
|
|
56
|
+
var node = root;
|
|
57
|
+
var variables = {currentTiddler: currentTiddler};
|
|
58
|
+
var mockWidget = widget.makeFakeWidgetWithVariables(variables);
|
|
59
|
+
do {
|
|
60
|
+
if (node.value !== undefined) {
|
|
61
|
+
// We have a value to return
|
|
62
|
+
return node.value;
|
|
63
|
+
}
|
|
64
|
+
if (node.variable === undefined) {
|
|
65
|
+
// No value, and no variable either. Must be a fresh cache.
|
|
66
|
+
// This should only happen with the root node. It's the only one
|
|
67
|
+
// that isn't necessarily a Branch or Leaf when execute starts.
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
var info = mockWidget.getVariableInfo(node.variable, node.options);
|
|
71
|
+
node = node.children[info.text];
|
|
72
|
+
} while (node !== undefined);
|
|
73
|
+
// It wasn't cached. We must now start back at the root and begin recording
|
|
74
|
+
node = root;
|
|
75
|
+
var trackWidget = widget.makeFakeWidgetWithVariables(variables);
|
|
76
|
+
var visited = Object.create(null);
|
|
77
|
+
trackWidget.oldVariable = trackWidget.getVariable;
|
|
78
|
+
trackWidget.getVariable = function(name, options) {
|
|
79
|
+
var value = this.oldVariable(name, options);
|
|
80
|
+
extendTree(name, value, options);
|
|
81
|
+
return value;
|
|
82
|
+
};
|
|
83
|
+
trackWidget.oldVariableInfo = trackWidget.getVariableInfo;
|
|
84
|
+
trackWidget.getVariableInfo = function(name, options) {
|
|
85
|
+
var info = this.oldVariableInfo(name, options);
|
|
86
|
+
extendTree(name, info.text, options);
|
|
87
|
+
return info;
|
|
88
|
+
};
|
|
89
|
+
function extendTree(name, value, options) {
|
|
90
|
+
// We don't need to extend the tree for currentTiddler.
|
|
91
|
+
// It's already accounted for.
|
|
92
|
+
// Also, if we've already encountered this variable, no need to
|
|
93
|
+
// extend the tree again.
|
|
94
|
+
if (name !== "currentTiddler" && !visited[name]) {
|
|
95
|
+
visited[name] = true;
|
|
96
|
+
// Logically, we're pointing at a node that does not have a value.
|
|
97
|
+
if (node.variable === undefined) {
|
|
98
|
+
// It's an undefined node. Make it a branch.
|
|
99
|
+
node.variable = name;
|
|
100
|
+
node.options = options;
|
|
101
|
+
node.children = Object.create(null);
|
|
102
|
+
} else if (node.variable !== name) {
|
|
103
|
+
// Unexpected. Variables should always be called in
|
|
104
|
+
// the same order that they were before.
|
|
105
|
+
throw "Non-deterministic filter";
|
|
106
|
+
}
|
|
107
|
+
var child = node.children[value];
|
|
108
|
+
if (child === undefined) {
|
|
109
|
+
child = node.children[value] = {};
|
|
110
|
+
}
|
|
111
|
+
node = child;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
var output = operationSubFunction(function() {/*No source*/}, trackWidget);
|
|
115
|
+
// Change the current node (which is undefined) into a leaf.
|
|
116
|
+
node.value = output;
|
|
117
|
+
return output;
|
|
118
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/*\
|
|
2
|
+
title: $:/plugins/flibbles/graph/filters/gettyped.js
|
|
3
|
+
type: application/javascript
|
|
4
|
+
module-type: filteroperator
|
|
5
|
+
|
|
6
|
+
Filter operator which replcaes tiddler titles with the values of the field of the specified operand, but does so in a way that's responsive to the type of field, depending on how it's configured by Relink.
|
|
7
|
+
|
|
8
|
+
\*/
|
|
9
|
+
|
|
10
|
+
"use strict";
|
|
11
|
+
|
|
12
|
+
var typeOperators = $tw.modules.getModulesByTypeAsHashmap("fieldtype");
|
|
13
|
+
var relinkPrefix = "$:/config/flibbles/relink/fields/" ;
|
|
14
|
+
|
|
15
|
+
exports.gettyped = function(source, operator, options) {
|
|
16
|
+
var results = [];
|
|
17
|
+
var field = operator.operand;
|
|
18
|
+
var typeName = options.wiki.getTiddlerText(relinkPrefix + field, "list");
|
|
19
|
+
var type = typeOperators[typeName] || typeOperators.list;
|
|
20
|
+
source(function(tiddler, title) {
|
|
21
|
+
if (tiddler) {
|
|
22
|
+
results.push.apply(results, type.get(tiddler, field, options));
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
return results;
|
|
26
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/*\
|
|
2
|
+
title: $:/plugins/flibbles/graph/graphengine.js
|
|
3
|
+
type: application/javascript
|
|
4
|
+
module-type: macro
|
|
5
|
+
|
|
6
|
+
Macro returns the graph engine of choice within the current context.
|
|
7
|
+
|
|
8
|
+
\*/
|
|
9
|
+
|
|
10
|
+
"use strict";
|
|
11
|
+
|
|
12
|
+
var utils = require("./utils.js");
|
|
13
|
+
var config = "$:/config/flibbles/graph/engine";
|
|
14
|
+
|
|
15
|
+
exports.name = "graphengine";
|
|
16
|
+
exports.params = [];
|
|
17
|
+
|
|
18
|
+
exports.run = function() {
|
|
19
|
+
return exports.get(this.wiki);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
exports.get = function(wiki) {
|
|
23
|
+
return wiki.getCacheForTiddler(config, "graphengine", function() {
|
|
24
|
+
var specified = wiki.getTiddlerText(config);
|
|
25
|
+
if (specified) {
|
|
26
|
+
return specified;
|
|
27
|
+
} else {
|
|
28
|
+
var engineMap = utils.getEngineMap();
|
|
29
|
+
var keys = Object.keys(engineMap);
|
|
30
|
+
if (keys.length > 0) {
|
|
31
|
+
// We go with the first one by alphabetical order
|
|
32
|
+
keys.sort();
|
|
33
|
+
return keys[0];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return "";
|
|
37
|
+
});
|
|
38
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
title: $:/plugins/flibbles/graph/icon
|
|
2
|
+
|
|
3
|
+
\parameters (size:"22pt")
|
|
4
|
+
\procedure pi() 3.141592653589793
|
|
5
|
+
\function pair() [all[]sin[]] [all[]cos[]] +[multiply[-50]join[ ]]
|
|
6
|
+
\procedure nodes() [range[0],[4]divide[6]multiply[2]multiply<pi>] :map[function[pair]] "0 0"
|
|
7
|
+
\whitespace trim
|
|
8
|
+
|
|
9
|
+
<$wikify name=edge-color text="<<colour muted-foreground>>" >
|
|
10
|
+
<svg class="graph-icon" width=<<size>> height=<<size>> version="1.1" viewBox="-64 -64 128 128">
|
|
11
|
+
<path class="graph-icon-splash" stroke-width=15 d=`M 0 0 S ${[subfilter<nodes>join[ ]]}$` style=`fill:$(edge-color)$;` />
|
|
12
|
+
<$list variable=pos filter="[subfilter<nodes>putlast[]butfirst[3]]">
|
|
13
|
+
<circle class="graph-icon-node" r=14
|
|
14
|
+
cx={{{ [<pos>split[ ]first[]] }}}
|
|
15
|
+
cy={{{ [<pos>split[ ]last[]] }}}
|
|
16
|
+
fill=<<node-color>> />
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
title: $:/plugins/flibbles/graph/images/drag
|
|
2
|
+
tags: $:/tags/Image
|
|
3
|
+
|
|
4
|
+
\whitespace trim
|
|
5
|
+
\parameters (size:"22pt")
|
|
6
|
+
<svg width=<<size>> height=<<size>> class="tc-draggable-button tc-image-button" viewBox="0 0 30 30">
|
|
7
|
+
<circle r=3 cx=10 cy=5 />
|
|
8
|
+
<circle r=3 cx=10 cy=15 />
|
|
9
|
+
<circle r=3 cx=10 cy=25 />
|
|
10
|
+
<circle r=3 cx=20 cy=5 />
|
|
11
|
+
<circle r=3 cx=20 cy=15 />
|
|
12
|
+
<circle r=3 cx=20 cy=25 />
|
|
13
|
+
</svg>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
\widget $action.addedge()
|
|
2
|
+
\whitespace trim
|
|
3
|
+
<$parameters
|
|
4
|
+
$$fromTiddler={{{ [<fromTiddler>!match[]else<currentTiddler>] }}}
|
|
5
|
+
$$toTiddler={{{ [<toTiddler>!match[]else<currentTiddler>] }}} >
|
|
6
|
+
|
|
7
|
+
<$action-modal $tiddler="$:/plugins/flibbles/graph/ui/Modals/SelectField">
|
|
8
|
+
|
|
9
|
+
<$action-addtyped $tiddler=<<$fromTiddler>> $field=<<selection>> $value=<<$toTiddler>> />
|
|
10
|
+
|
|
11
|
+
</$action-modal>
|
|
12
|
+
<$action-sendmessage $message=tm-focus-selector $param="input.graph-select" />
|
|
13
|
+
|
|
14
|
+
\end
|
|
15
|
+
|
|
16
|
+
\relink $action.addedge $fromTiddler:title $oTiddler:title
|