@zakkzhang/tw5-graph 1.6.4

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 (116) 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 +56 -0
  28. package/plugins/graph/macros/properties.stack.tid +17 -0
  29. package/plugins/graph/macros/tiddlywiki.files +17 -0
  30. package/plugins/graph/plugin.info +14 -0
  31. package/plugins/graph/presettypes/edges/fields.tid +18 -0
  32. package/plugins/graph/presettypes/edges/functions.tid +5 -0
  33. package/plugins/graph/presettypes/nodes/stack.tid +6 -0
  34. package/plugins/graph/propertytypes/actions.js +15 -0
  35. package/plugins/graph/propertytypes/boolean.js +23 -0
  36. package/plugins/graph/propertytypes/enum.js +25 -0
  37. package/plugins/graph/propertytypes/image.js +140 -0
  38. package/plugins/graph/propertytypes/number.js +24 -0
  39. package/plugins/graph/propertytypes/string.js +13 -0
  40. package/plugins/graph/propertytypes/tiddlywiki.files +17 -0
  41. package/plugins/graph/readme.tid +5 -0
  42. package/plugins/graph/relink/attributes.js +52 -0
  43. package/plugins/graph/relink/attributes.multids +19 -0
  44. package/plugins/graph/relink/configprefix.js +76 -0
  45. package/plugins/graph/relink/fieldedgeprefix.js +39 -0
  46. package/plugins/graph/relink/fields.multids +11 -0
  47. package/plugins/graph/relink/graphprefix.js +28 -0
  48. package/plugins/graph/relink/operators.multids +3 -0
  49. package/plugins/graph/relink/propertyfields.js +81 -0
  50. package/plugins/graph/relink/utils.js +99 -0
  51. package/plugins/graph/settings.tid +13 -0
  52. package/plugins/graph/startup/messages.js +46 -0
  53. package/plugins/graph/stylesheets/base.css.tid +263 -0
  54. package/plugins/graph/stylesheets/fullscreen/core.css +11 -0
  55. package/plugins/graph/stylesheets/fullscreen/core.css.meta +3 -0
  56. package/plugins/graph/stylesheets/fullscreen.css.tid +46 -0
  57. package/plugins/graph/stylesheets/popup.css.tid +107 -0
  58. package/plugins/graph/subfilters.tid +23 -0
  59. package/plugins/graph/tags/GraphToolbar.tid +2 -0
  60. package/plugins/graph/tags/SettingsTab.tid +2 -0
  61. package/plugins/graph/tags/Template.tid +2 -0
  62. package/plugins/graph/tags/ViewEditTemplate.tid +2 -0
  63. package/plugins/graph/templates/live-graph.tid +34 -0
  64. package/plugins/graph/templates/standard-graph.tid +40 -0
  65. package/plugins/graph/ui/Buttons/center.tid +38 -0
  66. package/plugins/graph/ui/Buttons/export.tid +65 -0
  67. package/plugins/graph/ui/Buttons/fullscreen.tid +35 -0
  68. package/plugins/graph/ui/Buttons/settings.tid +28 -0
  69. package/plugins/graph/ui/Buttons/tiddlywiki.files +16 -0
  70. package/plugins/graph/ui/EditTemplate/Edges.tid +22 -0
  71. package/plugins/graph/ui/EditTemplate/Neighbors.tid +35 -0
  72. package/plugins/graph/ui/EditTemplate/Nodes.tid +12 -0
  73. package/plugins/graph/ui/EditTemplate/Popups.tid +27 -0
  74. package/plugins/graph/ui/EditTemplate/Properties.tid +21 -0
  75. package/plugins/graph/ui/EditTemplate/tiddlywiki.files +16 -0
  76. package/plugins/graph/ui/Modals/NewPropertySet.tid +20 -0
  77. package/plugins/graph/ui/Modals/NewView.tid +20 -0
  78. package/plugins/graph/ui/Modals/Select.tid +72 -0
  79. package/plugins/graph/ui/Modals/SelectField.tid +21 -0
  80. package/plugins/graph/ui/Modals/SelectTiddler.tid +15 -0
  81. package/plugins/graph/ui/Modals/Tiddler.tid +22 -0
  82. package/plugins/graph/ui/Modals/TiddlerHeader.tid +15 -0
  83. package/plugins/graph/ui/PropertyTypes/boolean.tid +11 -0
  84. package/plugins/graph/ui/PropertyTypes/color.tid +5 -0
  85. package/plugins/graph/ui/PropertyTypes/enum.tid +15 -0
  86. package/plugins/graph/ui/PropertyTypes/number.tid +17 -0
  87. package/plugins/graph/ui/Settings/Engine.tid +23 -0
  88. package/plugins/graph/ui/Settings/Graphs/EditTemplate.tid +52 -0
  89. package/plugins/graph/ui/Settings/Graphs.tid +49 -0
  90. package/plugins/graph/ui/Settings/Properties/ObjectsTypeTemplate.tid +44 -0
  91. package/plugins/graph/ui/Settings/Properties.tid +14 -0
  92. package/plugins/graph/ui/Settings/Toolbar.tid +5 -0
  93. package/plugins/graph/ui/SideBar/Graph.tid +77 -0
  94. package/plugins/graph/ui/Toolbars/GraphToolbar.tid +15 -0
  95. package/plugins/graph/ui/ViewTemplate/graph-object.tid +13 -0
  96. package/plugins/graph/ui/ViewTemplate/graph.tid +11 -0
  97. package/plugins/graph/ui/ViewTemplate/properties.tid +80 -0
  98. package/plugins/graph/ui/grouped-tabs.tid +109 -0
  99. package/plugins/graph/ui/selector.tid +74 -0
  100. package/plugins/graph/utils.js +148 -0
  101. package/plugins/graph/widgets/action-delay.js +72 -0
  102. package/plugins/graph/widgets/action-modal.js +121 -0
  103. package/plugins/graph/widgets/action-typed.js +56 -0
  104. package/plugins/graph/widgets/action-with.js +70 -0
  105. package/plugins/graph/widgets/boundingbox.js +126 -0
  106. package/plugins/graph/widgets/fieldTranscriber.js +98 -0
  107. package/plugins/graph/widgets/fieldtranscriber/filter.js +93 -0
  108. package/plugins/graph/widgets/fieldtranscriber/json.js +34 -0
  109. package/plugins/graph/widgets/fieldtranscriber/plain.js +11 -0
  110. package/plugins/graph/widgets/graphobject.js +120 -0
  111. package/plugins/graph/widgets/messagerelay.js +115 -0
  112. package/plugins/graph/widgets/properties.js +131 -0
  113. package/plugins/graph/widgets/subclass/edge.js +47 -0
  114. package/plugins/graph/widgets/subclass/graph.js +424 -0
  115. package/plugins/graph/widgets/subclass/node.js +44 -0
  116. package/plugins/graph/widgets/tiddlywiki.files +43 -0
@@ -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,98 @@
1
+ /*\
2
+
3
+ Widget for transcribing the text of one data tiddler
4
+ into the field of another. and vice-versa.
5
+
6
+ \*/
7
+
8
+ "use strict";
9
+
10
+ var Widget = require("$:/core/modules/widgets/widget.js").widget;
11
+
12
+ var Scribers = $tw.modules.getModulesByTypeAsHashmap("fieldtranscribertype");
13
+
14
+ var ScriberWidget = function(parseTreeNode, options) {
15
+ this.initialise(parseTreeNode, options);
16
+ };
17
+
18
+ ScriberWidget.prototype = new Widget();
19
+
20
+ ScriberWidget.prototype.render = function(parent, nextSibling) {
21
+ this.parentDomNode = parent;
22
+ this.computeAttributes();
23
+ this.execute();
24
+ this.renderChildren(parent, nextSibling);
25
+ };
26
+
27
+ ScriberWidget.prototype.execute = function() {
28
+ this.scribeField = this.getAttribute("field");
29
+ this.scribeTiddler = this.getAttribute("tiddler") || (!this.hasParseTreeNodeAttribute("tiddler") && this.getVariable("currentTiddler"));
30
+ this.scribeType = this.getAttribute("type");
31
+ this.scribeState = this.getAttribute("state");
32
+ if (!this.scribeState) {
33
+ this.scribeState = "$:/temp/flibbles/graph/fieldtranscriber/" + encodeURIComponent(this.scribeField) + "/" + this.scribeTiddler;
34
+ }
35
+ if (!Scribers[this.scribeType]) {
36
+ this.scribeType = "text/plain";
37
+ }
38
+ this.setVariable("state", this.scribeState);
39
+ this.transcriber = Scribers[this.scribeType];
40
+ this.prepState();
41
+ this.makeChildWidgets();
42
+ };
43
+
44
+ ScriberWidget.prototype.refresh = function(changedTiddlers) {
45
+ var changedAttributes = this.computeAttributes();
46
+ if ($tw.utils.count(changedAttributes) > 0) {
47
+ this.refreshSelf();
48
+ return true;
49
+ }
50
+ if (changedTiddlers[this.scribeState] && this.scribeField) {
51
+ // Our tracked state has changed. Time to transcribe.
52
+ var state = this.wiki.getTiddler(this.scribeState);
53
+ if (state) {
54
+ var stateText = state.getFieldString("text");
55
+ if (this.stateText !== stateText) {
56
+ var fieldText = this.transcriber.toField(stateText);
57
+ if (fieldText !== this.fieldText) {
58
+ this.wiki.setText(this.scribeTiddler, this.scribeField, null, fieldText);
59
+ this.fieldText = fieldText;
60
+ this.stateText = stateText;
61
+ }
62
+ }
63
+ } else {
64
+ this.wiki.setText(this.scribeTiddler, this.scribeField, null, undefined);
65
+ this.fieldText = undefined;
66
+ this.stateText = undefined;
67
+ }
68
+ }
69
+ if (changedTiddlers[this.scribeTiddler]) {
70
+ this.prepState();
71
+ }
72
+ return this.refreshChildren(changedTiddlers);
73
+ };
74
+
75
+ ScriberWidget.prototype.prepState = function() {
76
+ if (this.scribeState && this.scribeField) {
77
+ var tiddler = this.wiki.getTiddler(this.scribeTiddler);
78
+ if (tiddler) {
79
+ var fieldText = tiddler.fields[this.scribeField];
80
+ if (this.fieldText !== fieldText) {
81
+ this.fieldText = fieldText;
82
+ if (fieldText === undefined) {
83
+ this.wiki.deleteTiddler(this.scribeState);
84
+ this.stateText = undefined;
85
+ } else {
86
+ this.stateText = this.transcriber.fromField(fieldText);
87
+ this.wiki.addTiddler({
88
+ title: this.scribeState,
89
+ text: this.stateText,
90
+ type: this.scribeType
91
+ });
92
+ }
93
+ }
94
+ }
95
+ }
96
+ };
97
+
98
+ exports.fieldtranscriber = ScriberWidget;
@@ -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; };