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.
Files changed (123) hide show
  1. package/README.md +65 -0
  2. package/package.json +39 -0
  3. package/plugins/graph/DefaultColourMappings.multids +8 -0
  4. package/plugins/graph/ViewTemplateBodyFilter/graph.tid +5 -0
  5. package/plugins/graph/ViewTemplateBodyFilter/properties.tid +5 -0
  6. package/plugins/graph/edges/fields/list.tid +7 -0
  7. package/plugins/graph/edges/fields/tags.tid +7 -0
  8. package/plugins/graph/edges/functions/links.tid +8 -0
  9. package/plugins/graph/edges/functions/transcludes.tid +8 -0
  10. package/plugins/graph/fieldtypes/filter.js +212 -0
  11. package/plugins/graph/fieldtypes/list.js +31 -0
  12. package/plugins/graph/fieldtypes/title.js +27 -0
  13. package/plugins/graph/filterrunprefixes/cache.js +118 -0
  14. package/plugins/graph/filters/gettyped.js +26 -0
  15. package/plugins/graph/graphengine.js +38 -0
  16. package/plugins/graph/icon.tid +16 -0
  17. package/plugins/graph/images/drag.tid +13 -0
  18. package/plugins/graph/macros/action.addedge.tid +16 -0
  19. package/plugins/graph/macros/edges.typed.tid +54 -0
  20. package/plugins/graph/macros/graph.view.tid +24 -0
  21. package/plugins/graph/macros/node.default.tid +9 -0
  22. package/plugins/graph/macros/nodes.neighbors.tid +62 -0
  23. package/plugins/graph/macros/nodes.writable.tid +37 -0
  24. package/plugins/graph/macros/properties.persistent.tid +27 -0
  25. package/plugins/graph/macros/properties.popup.tid +76 -0
  26. package/plugins/graph/macros/properties.river.tid +27 -0
  27. package/plugins/graph/macros/properties.settings.tid +54 -0
  28. package/plugins/graph/macros/properties.stack.tid +17 -0
  29. package/plugins/graph/macros/tiddlywiki.files +17 -0
  30. package/plugins/graph/nodes/neighbors/1.tid +8 -0
  31. package/plugins/graph/plugin.info +14 -0
  32. package/plugins/graph/presettypes/edges/fields.tid +18 -0
  33. package/plugins/graph/presettypes/edges/functions.tid +5 -0
  34. package/plugins/graph/presettypes/nodes/neighbors.tid +4 -0
  35. package/plugins/graph/presettypes/nodes/stack.tid +6 -0
  36. package/plugins/graph/propertytypes/actions.js +15 -0
  37. package/plugins/graph/propertytypes/boolean.js +23 -0
  38. package/plugins/graph/propertytypes/color.js +61 -0
  39. package/plugins/graph/propertytypes/enum.js +25 -0
  40. package/plugins/graph/propertytypes/filter.js +44 -0
  41. package/plugins/graph/propertytypes/image.js +185 -0
  42. package/plugins/graph/propertytypes/number.js +24 -0
  43. package/plugins/graph/propertytypes/string.js +13 -0
  44. package/plugins/graph/propertytypes/tiddlywiki.files +17 -0
  45. package/plugins/graph/readme.tid +5 -0
  46. package/plugins/graph/relink/attributes.js +52 -0
  47. package/plugins/graph/relink/attributes.multids +19 -0
  48. package/plugins/graph/relink/configprefix.js +76 -0
  49. package/plugins/graph/relink/fieldedgeprefix.js +39 -0
  50. package/plugins/graph/relink/fields.multids +11 -0
  51. package/plugins/graph/relink/graphprefix.js +28 -0
  52. package/plugins/graph/relink/operators.multids +3 -0
  53. package/plugins/graph/relink/propertyfields.js +81 -0
  54. package/plugins/graph/relink/utils.js +99 -0
  55. package/plugins/graph/settings.tid +13 -0
  56. package/plugins/graph/startup/messages.js +46 -0
  57. package/plugins/graph/stylesheets/base.css.tid +272 -0
  58. package/plugins/graph/stylesheets/fullscreen/core.css +11 -0
  59. package/plugins/graph/stylesheets/fullscreen/core.css.meta +3 -0
  60. package/plugins/graph/stylesheets/fullscreen.css.tid +48 -0
  61. package/plugins/graph/stylesheets/popup.css.tid +107 -0
  62. package/plugins/graph/subfilters.tid +23 -0
  63. package/plugins/graph/tags/GraphToolbar.tid +2 -0
  64. package/plugins/graph/tags/SettingsTab.tid +2 -0
  65. package/plugins/graph/tags/Template.tid +2 -0
  66. package/plugins/graph/tags/ViewEditTemplate.tid +2 -0
  67. package/plugins/graph/templates/live-graph.tid +34 -0
  68. package/plugins/graph/templates/standard-graph.tid +40 -0
  69. package/plugins/graph/ui/Buttons/center.tid +38 -0
  70. package/plugins/graph/ui/Buttons/export.tid +65 -0
  71. package/plugins/graph/ui/Buttons/fullscreen.tid +35 -0
  72. package/plugins/graph/ui/Buttons/settings.tid +28 -0
  73. package/plugins/graph/ui/Buttons/tiddlywiki.files +16 -0
  74. package/plugins/graph/ui/EditTemplate/Edges.tid +22 -0
  75. package/plugins/graph/ui/EditTemplate/Neighbors.tid +35 -0
  76. package/plugins/graph/ui/EditTemplate/Nodes.tid +12 -0
  77. package/plugins/graph/ui/EditTemplate/Popups.tid +27 -0
  78. package/plugins/graph/ui/EditTemplate/Properties.tid +21 -0
  79. package/plugins/graph/ui/EditTemplate/tiddlywiki.files +16 -0
  80. package/plugins/graph/ui/Modals/NewPropertySet.tid +20 -0
  81. package/plugins/graph/ui/Modals/NewView.tid +20 -0
  82. package/plugins/graph/ui/Modals/Select.tid +72 -0
  83. package/plugins/graph/ui/Modals/SelectField.tid +21 -0
  84. package/plugins/graph/ui/Modals/SelectTiddler.tid +15 -0
  85. package/plugins/graph/ui/Modals/Tiddler.tid +22 -0
  86. package/plugins/graph/ui/Modals/TiddlerHeader.tid +15 -0
  87. package/plugins/graph/ui/PropertyTypes/boolean.tid +11 -0
  88. package/plugins/graph/ui/PropertyTypes/color.tid +16 -0
  89. package/plugins/graph/ui/PropertyTypes/enum.tid +15 -0
  90. package/plugins/graph/ui/PropertyTypes/number.tid +17 -0
  91. package/plugins/graph/ui/Settings/Engine.tid +23 -0
  92. package/plugins/graph/ui/Settings/Graphs/EditTemplate.tid +52 -0
  93. package/plugins/graph/ui/Settings/Graphs.tid +49 -0
  94. package/plugins/graph/ui/Settings/Properties/ObjectsTypeTemplate.tid +46 -0
  95. package/plugins/graph/ui/Settings/Properties.tid +14 -0
  96. package/plugins/graph/ui/Settings/Toolbar.tid +5 -0
  97. package/plugins/graph/ui/SideBar/Graph.tid +77 -0
  98. package/plugins/graph/ui/Toolbars/GraphToolbar.tid +15 -0
  99. package/plugins/graph/ui/ViewTemplate/graph-object.tid +13 -0
  100. package/plugins/graph/ui/ViewTemplate/graph.tid +11 -0
  101. package/plugins/graph/ui/ViewTemplate/properties.tid +80 -0
  102. package/plugins/graph/ui/grouped-tabs.tid +109 -0
  103. package/plugins/graph/ui/selector.tid +74 -0
  104. package/plugins/graph/utils/propertyholder.js +80 -0
  105. package/plugins/graph/utils/widgetiterator.js +47 -0
  106. package/plugins/graph/utils.js +95 -0
  107. package/plugins/graph/widgets/action-delay.js +72 -0
  108. package/plugins/graph/widgets/action-modal.js +121 -0
  109. package/plugins/graph/widgets/action-typed.js +56 -0
  110. package/plugins/graph/widgets/action-with.js +70 -0
  111. package/plugins/graph/widgets/boundingbox.js +126 -0
  112. package/plugins/graph/widgets/fieldtranscriber/filter.js +93 -0
  113. package/plugins/graph/widgets/fieldtranscriber/json.js +34 -0
  114. package/plugins/graph/widgets/fieldtranscriber/plain.js +11 -0
  115. package/plugins/graph/widgets/fieldtranscriber.js +98 -0
  116. package/plugins/graph/widgets/graphobject.js +154 -0
  117. package/plugins/graph/widgets/messagerelay.js +115 -0
  118. package/plugins/graph/widgets/properties.js +130 -0
  119. package/plugins/graph/widgets/subclass/edge.js +55 -0
  120. package/plugins/graph/widgets/subclass/edit-color.js +52 -0
  121. package/plugins/graph/widgets/subclass/graph.js +380 -0
  122. package/plugins/graph/widgets/subclass/node.js +56 -0
  123. package/plugins/graph/widgets/tiddlywiki.files +43 -0
@@ -0,0 +1,95 @@
1
+ /*\
2
+ title: $:/plugins/flibbles/graph/utils.js
3
+ type: application/javascript
4
+ module-type: library
5
+
6
+ Utility methods used by the graphing widgets.
7
+
8
+ \*/
9
+
10
+ "use strict";
11
+
12
+ var Engines = $tw.modules.createClassesFromModules("graphengine");
13
+
14
+ $tw.modules.applyMethods("graphutils", exports);
15
+
16
+ /*
17
+ Returns the window for flibbles/graph to use. I do this so that the testing
18
+ framework can mock it out on Node.JS.
19
+ */
20
+ exports.window = function() { return window; };
21
+
22
+ exports.getEngineMap = function() {
23
+ return Engines;
24
+ };
25
+
26
+ exports.getEngine = function(name) {
27
+ var engineMap = exports.getEngineMap();
28
+ return engineMap[name] || null;
29
+ };
30
+
31
+ exports.getParentProperties = function(widget, type) {
32
+ // For now, we hard-stop at the graph. We don't take properties outside
33
+ // We may some day, but for now, support for that would be frought with
34
+ // complications
35
+ while (widget.parentWidget && widget.graphObjectType !== "graph") {
36
+ widget = widget.parentWidget;
37
+ if (widget.graphPropertiesWidget && widget.type === type) {
38
+ return widget;
39
+ }
40
+ };
41
+ return null;
42
+ };
43
+
44
+ /*** Destructor methods ***/
45
+
46
+ // Aren't we all eventually garbage?
47
+ var eventualGarbage = [];
48
+ var upkeepId;
49
+
50
+ /*
51
+ Register an object for destruction. It's ready to pass on once its
52
+ isGarbage method returns true;
53
+
54
+ object requirements:
55
+ .garbageCollect()
56
+ .isGarbage() => true/false
57
+ */
58
+ exports.registerForGarbageCollection = function(object) {
59
+ var destroy = object.destroy;
60
+ if (destroy) {
61
+ // This object has a destroy method, which means it's probably
62
+ // a widget in ^v5.4.0 TiddlyWiki, which are capable of
63
+ // destruction. We'll use that system instead. It's better.
64
+ object.destroy = function() {
65
+ // Call the widget core destroy method
66
+ destroy.apply(object, arguments);
67
+ // And then our own method
68
+ object.garbageCollect();
69
+ };
70
+ } else {
71
+ // Otherwise, we'll need to keep tabs on this so we can check
72
+ // back in occasionally to see if it should be destroyed.
73
+ if (!upkeepId) {
74
+ upkeepId = setInterval(exports.upkeep, 5000);
75
+ }
76
+ eventualGarbage.push(object);
77
+ }
78
+ };
79
+
80
+ exports.upkeep = function() {
81
+ var i = eventualGarbage.length;
82
+ while (i > 0) {
83
+ i--;
84
+ var object = eventualGarbage[i];
85
+ if (object.isGarbage()) {
86
+ eventualGarbage.splice(i, 1);
87
+ object.garbageCollect();
88
+ }
89
+ }
90
+ // No managed objects. Let's shut down for now.
91
+ if (eventualGarbage.length == 0) {
92
+ clearInterval(upkeepId);
93
+ upkeepId = null;
94
+ }
95
+ };
@@ -0,0 +1,72 @@
1
+ /*\
2
+
3
+ Action widget that introduces a delay before executing any nested actions it contains.
4
+
5
+ \*/
6
+
7
+ "use strict";
8
+
9
+ var Widget = require("$:/core/modules/widgets/widget.js").widget;
10
+
11
+ var DelayWidget = function(parseTreeNode, options) {
12
+ this.initialise(parseTreeNode, options);
13
+ };
14
+
15
+ DelayWidget.prototype = new Widget();
16
+
17
+ DelayWidget.prototype.render = function(parent, nextSibling) {
18
+ this.parentDomNode = parent;
19
+ this.computeAttributes();
20
+ this.execute();
21
+ this.renderChildren(parent, nextSibling);
22
+ };
23
+
24
+ DelayWidget.prototype.execute = function() {
25
+ this.ms = this.getAttribute("$ms", 0);
26
+ this.state = this.getAttribute("$state");
27
+ this.makeChildWidgets();
28
+ };
29
+
30
+ DelayWidget.prototype.refresh = function(changedTiddlers) {
31
+ var changedAttributes = this.computeAttributes();
32
+ if ($tw.utils.count(changedAttributes) > 0) {
33
+ this.refreshSelf();
34
+ return true;
35
+ }
36
+ return this.refreshChildren(changedTiddlers);
37
+ };
38
+
39
+ var counter = 0;
40
+
41
+ DelayWidget.prototype.invokeAction = function(triggeringWidget, event) {
42
+ // The id is used to make sure the later timed invocation corresponds
43
+ // to this method call here.
44
+ var id = (counter++).toString();
45
+ if (this.state) {
46
+ this.wiki.addTiddler({title: this.state, text: id});
47
+ }
48
+ return setTimeout(execute, this.ms, this, triggeringWidget, event, id);
49
+ };
50
+
51
+ DelayWidget.prototype.allowActionPropagation = function() {
52
+ return false;
53
+ };
54
+
55
+ function execute(delayWidget, triggeringWidget, event, id) {
56
+ var state = delayWidget.state;
57
+ if (state) {
58
+ var text = delayWidget.wiki.getTiddlerText(state);
59
+ if (text !== id) {
60
+ // The state tiddler was touched by another action.
61
+ // So we should not act. We're stale.
62
+ return;
63
+ }
64
+ }
65
+ delayWidget.refreshChildren();
66
+ delayWidget.invokeActions(triggeringWidget, event);
67
+ if (state) {
68
+ delayWidget.wiki.deleteTiddler(state);
69
+ }
70
+ };
71
+
72
+ exports["action-delay"] = DelayWidget;
@@ -0,0 +1,121 @@
1
+ /*\
2
+
3
+ Action widget that creates a modal to select an existing tiddler, or specify a new one. After dialog is confirmed, it will execute any nested actions it contains.
4
+
5
+ \*/
6
+
7
+ "use strict";
8
+
9
+ var Widget = require("$:/core/modules/widgets/widget.js").widget;
10
+ var utils = require("../utils.js");
11
+
12
+ /**
13
+ * This points to whatever action invoked the current modal. It assumes that
14
+ * only one modal is possible at a time. Probably a safe assumption.
15
+ */
16
+ var primedWidget;
17
+
18
+ var ModalWidget = function(parseTreeNode, options) {
19
+ this.initialise(parseTreeNode, options);
20
+ };
21
+
22
+ ModalWidget.prototype = new Widget();
23
+
24
+ ModalWidget.prototype.render = function(parent, nextSibling) {
25
+ this.parentDomNode = parent;
26
+ this.computeAttributes();
27
+ this.execute();
28
+ this.renderChildren(parent, nextSibling);
29
+ };
30
+
31
+ ModalWidget.prototype.execute = function() {
32
+ this.modalTiddler = this.getAttribute("$tiddler");
33
+ this.modal = $tw.modal;
34
+ if (!this.modal || this.modal.wiki !== this.wiki) {
35
+ // Ah, we have a modal working with a subwiki (or a Node.JS system
36
+ // which has no modal). We'll create an overlay of the modal
37
+ // that works with our subwiki instead.
38
+ this.modal = Object.create($tw.modal || null);
39
+ this.modal.wiki = this.wiki;
40
+ }
41
+ this.makeChildWidgets();
42
+ };
43
+
44
+ ModalWidget.prototype.refresh = function(changedTiddlers) {
45
+ var changedAttributes = this.computeAttributes();
46
+ if ($tw.utils.count(changedAttributes) > 0) {
47
+ this.refreshSelf();
48
+ return true;
49
+ }
50
+ return this.refreshChildren(changedTiddlers);
51
+ };
52
+
53
+ ModalWidget.prototype.invokeAction = function(triggeringWidget, event) {
54
+ if (!$tw.rootWidget.eventListeners['tm-modal-finish']) {
55
+ $tw.rootWidget.addEventListener("tm-modal-finish", function(finishEvent) {
56
+ if (primedWidget) {
57
+ var value = finishEvent.param;
58
+ primedWidget.setVariable("selection", value);
59
+ primedWidget.refreshChildren();
60
+ primedWidget.invokeActions(primedWidget, event);
61
+ primedWidget = undefined;
62
+ }
63
+ });
64
+ }
65
+ primedWidget = this;
66
+ var variables = Object.create(null);
67
+ for (var key in this.attributes) {
68
+ if (key.charAt(0) !== "$") {
69
+ variables[key] = this.attributes[key];
70
+ }
71
+ }
72
+ if (this.modalTiddler) {
73
+ var self = this;
74
+ // We need to delay the assignment of click handlers for a few
75
+ // milliseconds. See Issue #43. If we don't, a click event might
76
+ // follow right after the "make modal" which closes the modal
77
+ // immediately.
78
+ delayEventListenerAssignment(function() {
79
+ self.modal.display(self.modalTiddler, {
80
+ variables: variables,
81
+ event: event});
82
+ });
83
+ }
84
+
85
+ };
86
+
87
+ ModalWidget.prototype.allowActionPropagation = function() {
88
+ return false;
89
+ };
90
+
91
+ function delayEventListenerAssignment(method) {
92
+ var assignments = [];
93
+ // We use this requested window instead of just accessing directly
94
+ // so that the test framework can mock it up.
95
+ var window = utils.window();
96
+ var oldListener = window.EventTarget.prototype.addEventListener;
97
+ window.EventTarget.prototype.addEventListener = function(type) {
98
+ var args = Array.prototype.slice.call(arguments);
99
+ if (type === "click") {
100
+ // This is the click which might accidentally apply to the
101
+ // backdrop if we're on mobile. Delay it.
102
+ assignments.push({self: this, args: args});
103
+ } else {
104
+ // Just call through. We don't care about this handler.
105
+ oldListener.apply(this, args);
106
+ }
107
+ };
108
+ try {
109
+ method();
110
+ } finally {
111
+ window.EventTarget.prototype.addEventListener = oldListener;
112
+ }
113
+ setTimeout(function() {
114
+ for (var i = 0; i < assignments.length; i++) {
115
+ var set = assignments[i];
116
+ set.self.addEventListener.apply(set.self, set.args);
117
+ }
118
+ }, 10);
119
+ };
120
+
121
+ exports["action-modal"] = ModalWidget;
@@ -0,0 +1,56 @@
1
+ /*\
2
+
3
+ Creates two action widgets for adding and removing from typed fields.
4
+
5
+ \*/
6
+
7
+ "use strict";
8
+
9
+ var Widget = require("$:/core/modules/widgets/widget.js").widget;
10
+ var typeOperators = $tw.modules.getModulesByTypeAsHashmap("fieldtype");
11
+ var relinkPrefix = "$:/config/flibbles/relink/fields/" ;
12
+
13
+ var TypedWidget = new Widget();
14
+
15
+ TypedWidget.render = function(parent, nextSibling) {
16
+ this.computeAttributes();
17
+ this.execute();
18
+ };
19
+
20
+ TypedWidget.execute = function() {
21
+ this.actionTiddler = this.getAttribute("$tiddler") || (!this.hasParseTreeNodeAttribute("$tiddler") && this.getVariable("currentTiddler"));
22
+ this.actionField = this.getAttribute("$field");
23
+ this.actionValue = this.getAttribute("$value");
24
+ this.actionTimestamp = this.getAttribute("$timestamp","yes") === "yes";
25
+ this.actionClean = this.getAttribute("$clean","yes") === "yes";
26
+ };
27
+
28
+ TypedWidget.invokeAction = function(triggeringWidget, event) {
29
+ var tiddler = this.wiki.getTiddler(this.actionTiddler),
30
+ hasChanged = false,
31
+ options = {wiki: this.wiki, widget: this};
32
+ if (this.actionTiddler && this.actionField) {
33
+ options.suppressTimestamp = !this.actionTimestamp;
34
+ var typeName = this.wiki.getTiddlerText(relinkPrefix + this.actionField, "list");
35
+ var type = typeOperators[typeName];
36
+ if (type) {
37
+ var newValue = type[this.actionMethod](tiddler, this.actionField, this.actionValue, options);
38
+ if (newValue !== undefined) {
39
+ if (newValue === "" && this.actionClean) {
40
+ newValue = undefined;
41
+ }
42
+ options.wiki.setText(this.actionTiddler, this.actionField, null, newValue, options);
43
+ }
44
+ }
45
+ }
46
+ };
47
+
48
+ $tw.utils.each(["add", "remove"], function(method) {
49
+ var MethodWidget = function(parseTreeNode, options) {
50
+ this.initialise(parseTreeNode, options);
51
+ };
52
+
53
+ MethodWidget.prototype = Object.create(TypedWidget);
54
+ MethodWidget.prototype.actionMethod = method;
55
+ exports["action-" + method + "typed"] = MethodWidget;
56
+ });
@@ -0,0 +1,70 @@
1
+ /*\
2
+
3
+ Action widget that executes actions within it while exposing variables representing the mouse's current location.
4
+
5
+ \*/
6
+
7
+ "use strict";
8
+
9
+ var Widget = require("$:/core/modules/widgets/widget.js").widget;
10
+
11
+ var WithWidget = function(parseTreeNode, options) {
12
+ this.initialise(parseTreeNode, options);
13
+ };
14
+
15
+ WithWidget.prototype = new Widget();
16
+
17
+ WithWidget.prototype.render = function(parent, nextSibling) {
18
+ this.parentDomNode = parent;
19
+ this.computeAttributes();
20
+ this.execute();
21
+ this.renderChildren(parent, nextSibling);
22
+ };
23
+
24
+ WithWidget.prototype.execute = function() {
25
+ this.withOffset = this.getAttribute("$offset");
26
+ this.withCanvas = this.getAttribute("$canvas");
27
+ this.makeChildWidgets();
28
+ };
29
+
30
+ WithWidget.prototype.refresh = function(changedTiddlers) {
31
+ var changedAttributes = this.computeAttributes();
32
+ for (var attribute in changedAttributes) {
33
+ this.refreshSelf();
34
+ return true;
35
+ }
36
+ return this.refreshChildren(changedTiddlers);
37
+ };
38
+
39
+ WithWidget.prototype.invokeAction = function(triggeringWidget, event) {
40
+ var graph = getGraphWidget(this);
41
+ if (graph) {
42
+ if (this.withOffset) {
43
+ var mouse = graph.mouse,
44
+ x = mouse.x.toString(),
45
+ y = mouse.y.toString();
46
+ this.setVariable(this.withOffset + "-x", x);
47
+ this.setVariable(this.withOffset + "-y", y);
48
+ }
49
+ if (this.withCanvas) {
50
+ var element = graph.graphElement;
51
+ this.setVariable(this.withCanvas + "-width", element.offsetWidth);
52
+ this.setVariable(this.withCanvas + "-height", element.offsetHeight);
53
+ }
54
+ }
55
+ this.refreshChildren();
56
+ return true;
57
+ };
58
+
59
+ function getGraphWidget(self) {
60
+ var widget = self.parentWidget;
61
+ while (widget) {
62
+ if (widget.graphObjectType === "graph") {
63
+ return widget;
64
+ }
65
+ widget = widget.parentWidget;
66
+ }
67
+ return null;
68
+ };
69
+
70
+ exports["action-with"] = WithWidget;
@@ -0,0 +1,126 @@
1
+ /*\
2
+
3
+ Widget for creating a DOM element which has strictly controlled dimensions,
4
+ intended for a contained graph.
5
+
6
+ \*/
7
+
8
+ "use strict";
9
+
10
+ var Widget = require("$:/core/modules/widgets/widget.js").widget;
11
+ var utils = require("../utils.js");
12
+
13
+ var BoxWidget = function(parseTreeNode, options) {
14
+ this.initialise(parseTreeNode, options);
15
+ utils.registerForGarbageCollection(this);
16
+ this.resizeInstance = this.resize.bind(this);
17
+ this.window = utils.window();
18
+ this.window.addEventListener("resize", this.resizeInstance);
19
+ };
20
+
21
+ /**
22
+ * Inherit from the base widget class
23
+ */
24
+ BoxWidget.prototype = new Widget();
25
+
26
+ /**
27
+ * Render this widget into the DOM
28
+ */
29
+ BoxWidget.prototype.render = function(parent, nextSibling) {
30
+ this.parentDomNode = parent;
31
+ this.computeAttributes();
32
+ this.execute();
33
+ this.domNode = this.document.createElement("div");
34
+ this.domNode.className = this.boxClass;
35
+ parent.insertBefore(this.domNode, nextSibling);
36
+ // Make sure this comes AFTER inserting domNode into the tree,
37
+ // otherwise getBoundingClientRect() will be all zeros.
38
+ this.resize();
39
+ this.renderChildren(this.domNode, null);
40
+ this.domNodes.push(this.domNode);
41
+ };
42
+
43
+ /**
44
+ * Compute the internal state of the widget
45
+ */
46
+ BoxWidget.prototype.execute = function() {
47
+ this.executeClass();
48
+ this.executeDimensions();
49
+ this.makeChildWidgets();
50
+ };
51
+
52
+ BoxWidget.prototype.executeDimensions = function() {
53
+ var self = this;
54
+ this.widthFilter = this.wiki.compileFilter(this.getAttribute("width", ""));
55
+ this.heightFilter = this.wiki.compileFilter(this.getAttribute("height", ""));
56
+ // We set up the widget so it only gets values for these variables
57
+ // if needed. This keeps down unncessary calls to window and document,
58
+ // and makes the $graph widget usable on Node, if that ever comes up.
59
+ var variableMethods = {
60
+ // It may be better to use document.body.clientWidth,
61
+ // which doesn't consider the scrollbar.
62
+ windowWidth: function() { return self.window.innerWidth.toString(); },
63
+ windowHeight: function() { return self.window.innerHeight.toString(); },
64
+ boundingLeft: function() { return self.domNode.getBoundingClientRect().left.toString(); },
65
+ boundingTop: function() { return self.domNode.getBoundingClientRect().top.toString(); },
66
+ };
67
+ var variables = {};
68
+ for (var name in variableMethods) {
69
+ Object.defineProperty(variables, name, { get: variableMethods[name] });
70
+ }
71
+ this.dimensionWidget = this.makeFakeWidgetWithVariables(variables);
72
+ };
73
+
74
+ /**
75
+ * Selectively refreshes the widget if needed.
76
+ * Returns true if the widget or any of its children needed re-rendering
77
+ */
78
+ BoxWidget.prototype.refresh = function(changedTiddlers) {
79
+ var changedAttributes = this.computeAttributes();
80
+ var changed = false;
81
+ if (changedAttributes["class"]) {
82
+ this.executeClass();
83
+ this.domNode.className = this.boxClass;
84
+ changed = true;
85
+ }
86
+ if ($tw.utils.count(changedAttributes) > 0) {
87
+ this.executeDimensions();
88
+ changed = true;
89
+ }
90
+ // We always try to resize.
91
+ // The $dimension filters might spit out something different.
92
+ this.resize();
93
+ return this.refreshChildren(changedTiddlers) || changed;
94
+ };
95
+
96
+ BoxWidget.prototype.executeClass = function() {
97
+ var nodeClass = "boundingbox";
98
+ var extraClasses = this.getAttribute("class", "");
99
+ if (extraClasses) {
100
+ nodeClass += " " + extraClasses;
101
+ }
102
+ this.boxClass = nodeClass;
103
+ };
104
+
105
+ BoxWidget.prototype.resize = function(event) {
106
+ var newWidth = this.widthFilter(null, this.dimensionWidget)[0] || "";
107
+ var newHeight = this.heightFilter(null, this.dimensionWidget)[0] || "";
108
+ var style = this.domNode.style;
109
+ if (newWidth !== style.width) {
110
+ style.width = newWidth;
111
+ }
112
+ if (newHeight !== style.height) {
113
+ style.height = newHeight;
114
+ }
115
+ };
116
+
117
+ BoxWidget.prototype.garbageCollect = function() {
118
+ this.window.removeEventListener("resize", this.resizeInstance);
119
+ };
120
+
121
+ BoxWidget.prototype.isGarbage = function() {
122
+ var body = this.document.body;
123
+ return !body || !body.contains(this.domNode);
124
+ };
125
+
126
+ exports.boundingbox = BoxWidget;
@@ -0,0 +1,93 @@
1
+ /*\
2
+
3
+ Type for transcribing application/x-tiddler-filter between text and field.
4
+
5
+ Changes \n into " " between runs to mitigate the need for multilines.
6
+ However, it's impossible to guarantee a single line filter if newlines are
7
+ used in operands.
8
+
9
+ \*/
10
+
11
+ "use strict";
12
+
13
+ exports.name = "application/x-tiddler-filter";
14
+
15
+ exports.toField = function(text) {
16
+ return filterWhitespaceWalk(text, function(start, end) {
17
+ var substr = text.substring(start, end);
18
+ var change = substr.replaceAll("\n", " ");
19
+ return substr !== change ? change: null;
20
+ }).trim();
21
+ };
22
+
23
+ exports.fromField = function(text) {
24
+ return filterWhitespaceWalk(text, function(start, end) {
25
+ var substr = text.substring(start, end);
26
+ var change = substr.replaceAll(" ", "\n");
27
+ return substr !== change ? change: null;
28
+ });
29
+ };
30
+
31
+ var brackets = { "{": "}", "[": "]", "<": ">" };
32
+
33
+ function filterWhitespaceWalk(filterString, method) {
34
+ var p = 0, replaceHead = 0, replacements = [], match, nextBracketPos;
35
+ var whitespaceRegExp = /(\s+)/mg;
36
+ var operandRegExp = /((?:\+|\-|~|=|\:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
37
+ while (p < filterString.length) {
38
+ whitespaceRegExp.lastIndex = p;
39
+ match = whitespaceRegExp.exec(filterString);
40
+ if (match && match.index === p) {
41
+ var end = p + match[0].length;
42
+ var replacement = method(p, end);
43
+ if (replacement !== null) {
44
+ replacements.push(filterString.substring(replaceHead, p));
45
+ replacements.push(replacement);
46
+ replaceHead = end;
47
+ }
48
+ p = end;
49
+ }
50
+ if (p < filterString.length) {
51
+ operandRegExp.lastIndex = p;
52
+ match = operandRegExp.exec(filterString);
53
+ if (!match || match.index !== p) {
54
+ // Broken filter
55
+ return filterString;
56
+ }
57
+ if (match[1]) {
58
+ // Skip the named prefix
59
+ p += match[1].length;
60
+ }
61
+ if (match[4]) {
62
+ // It's a filter operation. Skip by [...]
63
+ if (filterString.charAt(p++) !== "[") {
64
+ return filterString;
65
+ }
66
+ do {
67
+ if(filterString.charAt(p) === "!") {
68
+ filterString.charAt(p++);
69
+ }
70
+ // Get the operator name
71
+ nextBracketPos = filterString.substring(p).search(/[\[\{<\/]/);
72
+ if(nextBracketPos === -1) {
73
+ return filterString;
74
+ }
75
+ nextBracketPos += p;
76
+ var bracket = filterString.charAt(nextBracketPos);
77
+ nextBracketPos = filterString.indexOf(brackets[bracket], p);
78
+ if (nextBracketPos === -1) {
79
+ return filterString;
80
+ }
81
+ p = nextBracketPos + 1;
82
+ } while (filterString.charAt(p++) !== "]");
83
+ } else {
84
+ p = match.index + match[0].length;
85
+ }
86
+ }
87
+ }
88
+ if (replacements.length > 0) {
89
+ replacements.push(filterString.substr(replaceHead));
90
+ return replacements.join("");
91
+ }
92
+ return filterString;
93
+ };
@@ -0,0 +1,34 @@
1
+ /*\
2
+
3
+ Type for transcribing application/json between text and field.
4
+
5
+ Focuses on keeping dataTiddler style pretty printing for text, but puts all
6
+ json on one line for fields.
7
+
8
+ \*/
9
+
10
+ "use strict";
11
+
12
+ exports.name = "application/json";
13
+
14
+ exports.toField = function(text) {
15
+ if (!text) {
16
+ return "";
17
+ }
18
+ try {
19
+ return JSON.stringify(JSON.parse(text));
20
+ } catch {
21
+ return "{}";
22
+ }
23
+ };
24
+
25
+ exports.fromField = function(text) {
26
+ if (!text) {
27
+ return "";
28
+ }
29
+ try {
30
+ return JSON.stringify(JSON.parse(text), null, $tw.config.preferences.jsonSpaces);
31
+ } catch {
32
+ return "{}";
33
+ }
34
+ };
@@ -0,0 +1,11 @@
1
+ /*\
2
+
3
+ Type for transcribing text/plain between text and field.
4
+
5
+ \*/
6
+
7
+ "use strict";
8
+
9
+ exports.name = "text/plain";
10
+
11
+ exports.fromField = exports.toField = function(text) { return text; };