mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-01-22 19:04:38 +00:00
Compare commits
192 Commits
json-ops
...
twitter-ar
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f922149b32 | ||
|
|
344110e289 | ||
|
|
ae12e8fb69 | ||
|
|
e8148ff978 | ||
|
|
965bd090a9 | ||
|
|
3be9b13814 | ||
|
|
62f26d6630 | ||
|
|
8fe2f6086d | ||
|
|
30af537b91 | ||
|
|
f54ecc23f3 | ||
|
|
67dd3f06bf | ||
|
|
6af3eb539b | ||
|
|
3f55f827a6 | ||
|
|
b9d27e9fd5 | ||
|
|
5b85786f73 | ||
|
|
24dbf69180 | ||
|
|
7b408c7adf | ||
|
|
c19d6d6328 | ||
|
|
941c09fae2 | ||
|
|
b531984f50 | ||
|
|
8f079e2d45 | ||
|
|
cfd894e6fb | ||
|
|
91327c1af0 | ||
|
|
6f98edd6bd | ||
|
|
23e0eeb556 | ||
|
|
f33c7e2aef | ||
|
|
fc586481a9 | ||
|
|
09179d2f62 | ||
|
|
d6ff38095b | ||
|
|
3bbbe77471 | ||
|
|
5657dfec0e | ||
|
|
31ab6dce77 | ||
|
|
4007610d52 | ||
|
|
fb34df84ed | ||
|
|
79e2e317cf | ||
|
|
36896c3db8 | ||
|
|
82de7c9b1a | ||
|
|
1841b0fa4f | ||
|
|
47f80339b2 | ||
|
|
db6abb9703 | ||
|
|
8d1e6b5d23 | ||
|
|
1df4c29d73 | ||
|
|
81e4745c56 | ||
|
|
87597ea273 | ||
|
|
4e9267ea58 | ||
|
|
dd66fcc759 | ||
|
|
8ebb9ef442 | ||
|
|
81ac987484 | ||
|
|
0a00da6db9 | ||
|
|
53d229592d | ||
|
|
166a156584 | ||
|
|
c5d3d4c26e | ||
|
|
51bdf60ee8 | ||
|
|
50f54ba6ca | ||
|
|
1a0ab68dec | ||
|
|
bb67f96562 | ||
|
|
a981f8ccfe | ||
|
|
859d15a446 | ||
|
|
debfd42d51 | ||
|
|
fe365354d0 | ||
|
|
d825f1c875 | ||
|
|
fe74a776e9 | ||
|
|
93e1a632b8 | ||
|
|
9b7edfc1a7 | ||
|
|
3b2c64a85b | ||
|
|
35b9faaa89 | ||
|
|
11b258a14b | ||
|
|
7652aa5fed | ||
|
|
d62a16ee46 | ||
|
|
0b1fc8e574 | ||
|
|
127f660c91 | ||
|
|
668f443fc2 | ||
|
|
c8ad385947 | ||
|
|
c1f6e02d14 | ||
|
|
f0423c20b9 | ||
|
|
953b89fd6b | ||
|
|
f87ab06414 | ||
|
|
2ff5bd5a0f | ||
|
|
d7b9e6fb02 | ||
|
|
8420f8430f | ||
|
|
a572979cc4 | ||
|
|
90d6a0f1a6 | ||
|
|
406dbd0883 | ||
|
|
3fd2cfc339 | ||
|
|
f690458792 | ||
|
|
6bc18570f2 | ||
|
|
1f4b12cd0e | ||
|
|
608aa3378a | ||
|
|
bff7dc88e8 | ||
|
|
667da96c97 | ||
|
|
fb037de091 | ||
|
|
75865385a6 | ||
|
|
091a6a9dc1 | ||
|
|
38f0337207 | ||
|
|
a3b294470f | ||
|
|
53c5cc535e | ||
|
|
9e6713d3e0 | ||
|
|
1acad41574 | ||
|
|
9a5f6558fe | ||
|
|
5d9b71771a | ||
|
|
f891eacddc | ||
|
|
178e652a5d | ||
|
|
daf4eec702 | ||
|
|
34b1b8128f | ||
|
|
a453121e96 | ||
|
|
e849aaab4d | ||
|
|
453d91caeb | ||
|
|
0ad0001e29 | ||
|
|
2441819c70 | ||
|
|
ca762ab7a6 | ||
|
|
28070f847c | ||
|
|
8f85fbca33 | ||
|
|
655cf4729a | ||
|
|
55f3ee5eab | ||
|
|
63bba13758 | ||
|
|
c22d52c046 | ||
|
|
8c57cfdf26 | ||
|
|
4f38903c7b | ||
|
|
ab1e85e01e | ||
|
|
065911259b | ||
|
|
6497633859 | ||
|
|
9cc4c3ead7 | ||
|
|
613b3df367 | ||
|
|
39996c7a2f | ||
|
|
0237d9ed94 | ||
|
|
7e9c2a1a10 | ||
|
|
d4fc8f585e | ||
|
|
caa6b888e9 | ||
|
|
a1b240de2f | ||
|
|
7a98ab1677 | ||
|
|
c49d5a3b08 | ||
|
|
93717560dc | ||
|
|
abc3af16c3 | ||
|
|
97eaec88d1 | ||
|
|
2275255c2b | ||
|
|
fe1147c6fd | ||
|
|
eceacc23c8 | ||
|
|
1ca6305acb | ||
|
|
19331cc6f9 | ||
|
|
f6e021d70f | ||
|
|
2da117484c | ||
|
|
1c1dd2a4cf | ||
|
|
f957874d18 | ||
|
|
aa4a284b88 | ||
|
|
338dc11436 | ||
|
|
22d8fdd259 | ||
|
|
c270e3cd6b | ||
|
|
18d8173dcc | ||
|
|
4cd3c065e7 | ||
|
|
45895bd560 | ||
|
|
af86080943 | ||
|
|
94b02ba3a0 | ||
|
|
bbae2ab6da | ||
|
|
3b778c156b | ||
|
|
2f817e4293 | ||
|
|
0112d04033 | ||
|
|
56d8f47710 | ||
|
|
f818fd96cd | ||
|
|
c5821326d0 | ||
|
|
add14ef65a | ||
|
|
f93fe50044 | ||
|
|
ceec7b5737 | ||
|
|
76bc2f7524 | ||
|
|
a59ec3ebf7 | ||
|
|
20df381cf3 | ||
|
|
4185d9a26c | ||
|
|
bf6d5fa767 | ||
|
|
92c4c82005 | ||
|
|
1110fd50cf | ||
|
|
2c607ee8e6 | ||
|
|
dfebd69d8f | ||
|
|
926b7808b3 | ||
|
|
7ac7d26f86 | ||
|
|
f02bd2392f | ||
|
|
2b45bbc4c4 | ||
|
|
bce3ec6e6f | ||
|
|
5e35c8dda6 | ||
|
|
8af7054efa | ||
|
|
10bc84ba6c | ||
|
|
0391e1855c | ||
|
|
a29889a741 | ||
|
|
27609d2619 | ||
|
|
d5030eb87b | ||
|
|
35b0833e0c | ||
|
|
45f5ba7d38 | ||
|
|
8e64e21039 | ||
|
|
bb47cc97f5 | ||
|
|
7e4722f07a | ||
|
|
df7416d16b | ||
|
|
a226975b3e | ||
|
|
2a62da1498 | ||
|
|
696c5c9c7a |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
.DS_Store
|
||||
.c9/
|
||||
.vscode/
|
||||
tmp/
|
||||
output/
|
||||
node_modules/
|
||||
|
||||
@@ -233,6 +233,15 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
--build index \
|
||||
|| exit 1
|
||||
|
||||
# /editions/twitter-archivist/index.html Twitter Archivist edition
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/twitter-archivist \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/editions/twitter-archivist/ \
|
||||
--build index \
|
||||
|| exit 1
|
||||
|
||||
######################################################
|
||||
#
|
||||
# Plugin demos
|
||||
|
||||
15
boot/boot.js
15
boot/boot.js
@@ -1230,13 +1230,16 @@ $tw.Wiki = function(options) {
|
||||
this.getTiddler = function(title) {
|
||||
if(title) {
|
||||
var t = tiddlers[title];
|
||||
if(t instanceof $tw.Tiddler) {
|
||||
if(t !== undefined) {
|
||||
return t;
|
||||
} else if(title !== undefined && shadowTiddlers[title]) {
|
||||
return shadowTiddlers[title].tiddler;
|
||||
} else {
|
||||
var s = shadowTiddlers[title];
|
||||
if(s !== undefined) {
|
||||
return s.tiddler;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
// Get an array of all tiddler titles
|
||||
@@ -2400,11 +2403,11 @@ $tw.boot.initStartup = function(options) {
|
||||
$tw.utils.registerFileType("application/x-font-ttf","base64",".woff");
|
||||
$tw.utils.registerFileType("application/font-woff2","base64",".woff2");
|
||||
$tw.utils.registerFileType("audio/ogg","base64",".ogg");
|
||||
$tw.utils.registerFileType("audio/mp4","base64",[".mp4",".m4a"]);
|
||||
$tw.utils.registerFileType("video/ogg","base64",[".ogm",".ogv",".ogg"]);
|
||||
$tw.utils.registerFileType("video/webm","base64",".webm");
|
||||
$tw.utils.registerFileType("video/mp4","base64",".mp4");
|
||||
$tw.utils.registerFileType("audio/mp3","base64",".mp3");
|
||||
$tw.utils.registerFileType("audio/mp4","base64",[".mp4",".m4a"]);
|
||||
$tw.utils.registerFileType("text/markdown","utf8",[".md",".markdown"],{deserializerType:"text/x-markdown"});
|
||||
$tw.utils.registerFileType("text/x-markdown","utf8",[".md",".markdown"]);
|
||||
$tw.utils.registerFileType("application/enex+xml","utf8",".enex");
|
||||
@@ -2416,7 +2419,7 @@ $tw.boot.initStartup = function(options) {
|
||||
$tw.utils.registerFileType("application/epub+zip","base64",".epub");
|
||||
$tw.utils.registerFileType("application/octet-stream","base64",".octet-stream");
|
||||
// Create the wiki store for the app
|
||||
$tw.wiki = new $tw.Wiki();
|
||||
$tw.wiki = new $tw.Wiki($tw.safeMode && {enableIndexers: []});
|
||||
// Install built in tiddler fields modules
|
||||
$tw.Tiddler.fieldModules = $tw.modules.getModulesByTypeAsHashmap("tiddlerfield");
|
||||
// Install the tiddler deserializer modules
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -18,6 +18,8 @@ CopyToClipboard/Caption: copy to clipboard
|
||||
CopyToClipboard/Hint: Copy this text to the clipboard
|
||||
Delete/Caption: delete
|
||||
Delete/Hint: Delete this tiddler
|
||||
DeleteTiddlers/Caption: delete tiddlers
|
||||
DeleteTiddlers/Hint: Delete tiddlers
|
||||
Edit/Caption: edit
|
||||
Edit/Hint: Edit this tiddler
|
||||
Encryption/Caption: encryption
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
title: $:/language/EditTemplate/
|
||||
|
||||
Caption: Editor
|
||||
Body/External/Hint: This tiddler shows content stored outside of the main TiddlyWiki file. You can edit the tags and fields but cannot directly edit the content itself
|
||||
Body/Placeholder: Type the text for this tiddler
|
||||
Body/Preview/Type/Output: output
|
||||
|
||||
@@ -13,7 +13,7 @@ dependents: For a plugin, lists the dependent plugin titles
|
||||
description: The descriptive text for a plugin, or a modal dialogue
|
||||
draft.of: For draft tiddlers, contains the title of the tiddler of which this is a draft
|
||||
draft.title: For draft tiddlers, contains the proposed new title of the tiddler
|
||||
footer: The footer text for a wizard
|
||||
footer: The footer text for a modal
|
||||
hide-body: The view template will hide bodies of tiddlers if set to ''yes''
|
||||
icon: The title of the tiddler containing the icon associated with a tiddler
|
||||
library: Indicates that a tiddler should be saved as a JavaScript library if set to ''yes''
|
||||
@@ -28,7 +28,7 @@ plugin-type: The type of plugin in a plugin tiddler
|
||||
revision: The revision of the tiddler held at the server
|
||||
released: Date of a TiddlyWiki release
|
||||
source: The source URL associated with a tiddler
|
||||
subtitle: The subtitle text for a wizard
|
||||
subtitle: The subtitle text for a modal
|
||||
tags: A list of tags associated with a tiddler
|
||||
text: The body text of a tiddler
|
||||
throttle.refresh: If present, throttles refreshes of this tiddler
|
||||
|
||||
@@ -9,9 +9,10 @@ Before you start storing important information in ~TiddlyWiki it is vital to mak
|
||||
|
||||
<div class="tc-control-panel">
|
||||
|
||||
|<$link to="$:/SiteTitle"><<lingo Title/Prompt>></$link> |<$edit-text tiddler="$:/SiteTitle" default="" tag="input"/> |
|
||||
|<$link to="$:/SiteSubtitle"><<lingo Subtitle/Prompt>></$link> |<$edit-text tiddler="$:/SiteSubtitle" default="" tag="input"/> |
|
||||
|<$link to="$:/DefaultTiddlers"><<lingo DefaultTiddlers/Prompt>></$link> |<<lingo DefaultTiddlers/TopHint>><br> <$edit tag="textarea" tiddler="$:/DefaultTiddlers"/><br>//<<lingo DefaultTiddlers/BottomHint>>// |
|
||||
|tc-table-no-border tc-first-col-min-width tc-first-link-nowrap|k
|
||||
| <$link to="$:/SiteTitle"><<lingo Title/Prompt>></$link>|<$edit-text tiddler="$:/SiteTitle" default="" tag="input"/> |
|
||||
| <$link to="$:/SiteSubtitle"><<lingo Subtitle/Prompt>></$link>|<$edit-text tiddler="$:/SiteSubtitle" default="" tag="input"/> |
|
||||
|^ <$link to="$:/DefaultTiddlers"><<lingo DefaultTiddlers/Prompt>></$link><br><<lingo DefaultTiddlers/TopHint>>|<$edit tag="textarea" tiddler="$:/DefaultTiddlers"/><br>//<<lingo DefaultTiddlers/BottomHint>>// |
|
||||
</div>
|
||||
|
||||
See the [[control panel|$:/ControlPanel]] for more options.
|
||||
|
||||
@@ -31,5 +31,5 @@ Notes:
|
||||
|
||||
Examples:
|
||||
|
||||
* `--render "[!is[system]]" "[encodeuricomponent[]addprefix[tiddlers/]addsuffix[.html]]"` -- renders all non-system tiddlers as files in the subdirectory "tiddlers" with URL-encoded titles and the extension HTML
|
||||
|
||||
* `--render '[!is[system]]' '[encodeuricomponent[]addprefix[tiddlers/]addsuffix[.html]]'` -- renders all non-system tiddlers as files in the subdirectory "tiddlers" with URL-encoded titles and the extension HTML
|
||||
* `--render '.' 'tiddlers.json' 'text/plain' '$:/core/templates/exporters/JsonFile' 'exportFilter' '[tag[HelloThere]]'` -- renders the tiddlers tagged "HelloThere" to a JSON file named "tiddlers.json"
|
||||
|
||||
@@ -8,6 +8,7 @@ CloseAll/Button: close all
|
||||
ColourPicker/Recent: Recent:
|
||||
ConfirmCancelTiddler: Do you wish to discard changes to the tiddler "<$text text=<<title>>/>"?
|
||||
ConfirmDeleteTiddler: Do you wish to delete the tiddler "<$text text=<<title>>/>"?
|
||||
ConfirmDeleteTiddlers: Are you sure you wish to delete <<resultCount>> tiddler(s)?
|
||||
ConfirmOverwriteTiddler: Do you wish to overwrite the tiddler "<$text text=<<title>>/>"?
|
||||
ConfirmEditShadowTiddler: You are about to edit a ShadowTiddler. Any changes will override the default system making future upgrades non-trivial. Are you sure you want to edit "<$text text=<<title>>/>"?
|
||||
ConfirmAction: Do you wish to proceed?
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
title: $:/language/SideBar/
|
||||
|
||||
Caption: Sidebar
|
||||
All/Caption: All
|
||||
Contents/Caption: Contents
|
||||
Drafts/Caption: Drafts
|
||||
|
||||
@@ -50,7 +50,7 @@ Render individual tiddlers and save the results to the specified files
|
||||
console.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
|
||||
}
|
||||
var parser = wiki.parseTiddler(template || title),
|
||||
widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title})}),
|
||||
widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title,storyTiddler: title})}),
|
||||
container = $tw.fakeDocument.createElement("div");
|
||||
widgetNode.render(container,null);
|
||||
var text = type === "text/html" ? container.innerHTML : container.textContent;
|
||||
|
||||
@@ -40,6 +40,7 @@ Command.prototype.execute = function() {
|
||||
$tw.utils.createFileDirectories(filename);
|
||||
if(template) {
|
||||
variables.currentTiddler = title;
|
||||
variables.storyTiddler = title;
|
||||
title = template;
|
||||
}
|
||||
if(name && value) {
|
||||
|
||||
@@ -46,7 +46,7 @@ Command.prototype.execute = function() {
|
||||
}
|
||||
$tw.utils.each(tiddlers,function(title) {
|
||||
var parser = wiki.parseTiddler(template),
|
||||
widgetNode = wiki.makeWidget(parser,{variables: {currentTiddler: title}}),
|
||||
widgetNode = wiki.makeWidget(parser,{variables: {currentTiddler: title, storyTiddler: title}}),
|
||||
container = $tw.fakeDocument.createElement("div");
|
||||
widgetNode.render(container,null);
|
||||
var text = type === "text/html" ? container.innerHTML : container.textContent,
|
||||
|
||||
@@ -35,7 +35,7 @@ function FramedEngine(options) {
|
||||
this.iframeDoc = this.iframeNode.contentWindow.document;
|
||||
// (Firefox requires us to put some empty content in the iframe)
|
||||
var paletteTitle = this.widget.wiki.getTiddlerText("$:/palette");
|
||||
var colorScheme = this.widget.wiki.getTiddler(paletteTitle).fields["color-scheme"] || "light";
|
||||
var colorScheme = (this.widget.wiki.getTiddler(paletteTitle) || {fields: {}}).fields["color-scheme"] || "light";
|
||||
this.iframeDoc.open();
|
||||
this.iframeDoc.write("<meta name='color-scheme' content='" + colorScheme + "'>");
|
||||
this.iframeDoc.close();
|
||||
@@ -87,7 +87,7 @@ function FramedEngine(options) {
|
||||
$tw.utils.addEventListeners(this.domNode,[
|
||||
{name: "click",handlerObject: this,handlerMethod: "handleClickEvent"},
|
||||
{name: "input",handlerObject: this,handlerMethod: "handleInputEvent"},
|
||||
{name: "keydown",handlerObject: this.widget,handlerMethod: "handleKeydownEvent"},
|
||||
{name: "keydown",handlerObject: this,handlerMethod: "handleKeydownEvent"},
|
||||
{name: "focus",handlerObject: this,handlerMethod: "handleFocusEvent"}
|
||||
]);
|
||||
// Add drag and drop event listeners if fileDrop is enabled
|
||||
@@ -192,6 +192,17 @@ FramedEngine.prototype.handleFocusEvent = function(event) {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Handle a keydown event
|
||||
*/
|
||||
FramedEngine.prototype.handleKeydownEvent = function(event) {
|
||||
if ($tw.keyboardManager.handleKeydownEvent(event, {onlyPriority: true})) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.widget.handleKeydownEvent(event);
|
||||
};
|
||||
|
||||
/*
|
||||
Handle a click
|
||||
*/
|
||||
|
||||
@@ -115,7 +115,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
// Otherwise, we need to construct a default value for the editor
|
||||
switch(this.editField) {
|
||||
case "text":
|
||||
value = "Type the text for the tiddler '" + this.editTitle + "'";
|
||||
value = "";
|
||||
type = "text/vnd.tiddlywiki";
|
||||
break;
|
||||
case "title":
|
||||
|
||||
@@ -16,7 +16,9 @@ exports.map = function(operationSubFunction,options) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length > 0) {
|
||||
var inputTitles = results.toArray(),
|
||||
index = 0;
|
||||
index = 0,
|
||||
suffixes = options.suffixes,
|
||||
flatten = (suffixes[0] && suffixes[0][0] === "flat") ? true : false;
|
||||
results.clear();
|
||||
$tw.utils.each(inputTitles,function(title) {
|
||||
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
||||
@@ -36,7 +38,13 @@ exports.map = function(operationSubFunction,options) {
|
||||
}
|
||||
}
|
||||
});
|
||||
results.push(filtered[0] || "");
|
||||
if(filtered.length && flatten) {
|
||||
$tw.utils.each(filtered,function(value) {
|
||||
results.push(value);
|
||||
})
|
||||
} else {
|
||||
results.push(filtered[0]||"");
|
||||
}
|
||||
++index;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12,6 +12,9 @@ Adds tiddler filtering methods to the $tw.Wiki object.
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/* Maximum permitted filter recursion depth */
|
||||
var MAX_FILTER_DEPTH = 300;
|
||||
|
||||
/*
|
||||
Parses an operation (i.e. a run) within a filter string
|
||||
operators: Array of array of operator nodes into which results should be inserted
|
||||
@@ -220,10 +223,18 @@ source: an iterator function for the source tiddlers, called source(iterator), w
|
||||
widget: an optional widget node for retrieving the current tiddler etc.
|
||||
*/
|
||||
exports.compileFilter = function(filterString) {
|
||||
if(!this.filterCache) {
|
||||
this.filterCache = Object.create(null);
|
||||
this.filterCacheCount = 0;
|
||||
}
|
||||
if(this.filterCache[filterString] !== undefined) {
|
||||
return this.filterCache[filterString];
|
||||
}
|
||||
var filterParseTree;
|
||||
try {
|
||||
filterParseTree = this.parseFilter(filterString);
|
||||
} catch(e) {
|
||||
// We do not cache this result, so it adjusts along with localization changes
|
||||
return function(source,widget) {
|
||||
return [$tw.language.getString("Error/Filter") + ": " + e];
|
||||
};
|
||||
@@ -320,7 +331,7 @@ exports.compileFilter = function(filterString) {
|
||||
})());
|
||||
});
|
||||
// Return a function that applies the operations to a source iterator of tiddler titles
|
||||
return $tw.perf.measure("filter: " + filterString,function filterFunction(source,widget) {
|
||||
var fnMeasured = $tw.perf.measure("filter: " + filterString,function filterFunction(source,widget) {
|
||||
if(!source) {
|
||||
source = self.each;
|
||||
} else if(typeof source === "object") { // Array or hashmap
|
||||
@@ -330,11 +341,27 @@ exports.compileFilter = function(filterString) {
|
||||
widget = $tw.rootWidget;
|
||||
}
|
||||
var results = new $tw.utils.LinkedList();
|
||||
$tw.utils.each(operationFunctions,function(operationFunction) {
|
||||
operationFunction(results,source,widget);
|
||||
});
|
||||
self.filterRecursionCount = (self.filterRecursionCount || 0) + 1;
|
||||
if(self.filterRecursionCount < MAX_FILTER_DEPTH) {
|
||||
$tw.utils.each(operationFunctions,function(operationFunction) {
|
||||
operationFunction(results,source,widget);
|
||||
});
|
||||
} else {
|
||||
results.push("/**-- Excessive filter recursion --**/");
|
||||
}
|
||||
self.filterRecursionCount = self.filterRecursionCount - 1;
|
||||
return results.toArray();
|
||||
});
|
||||
if(this.filterCacheCount >= 2000) {
|
||||
// To prevent memory leak, we maintain an upper limit for cache size.
|
||||
// Reset if exceeded. This should give us 95% of the benefit
|
||||
// that no cache limit would give us.
|
||||
this.filterCache = Object.create(null);
|
||||
this.filterCacheCount = 0;
|
||||
}
|
||||
this.filterCache[filterString] = fnMeasured;
|
||||
this.filterCacheCount++;
|
||||
return fnMeasured;
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
35
core/modules/filters/format/json.js
Normal file
35
core/modules/filters/format/json.js
Normal file
@@ -0,0 +1,35 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/format/json.js
|
||||
type: application/javascript
|
||||
module-type: formatfilteroperator
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.json = function(source,operand,options) {
|
||||
var results = [],
|
||||
spaces = null;
|
||||
if(operand) {
|
||||
spaces = /^\d+$/.test(operand) ? parseInt(operand,10) : operand;
|
||||
}
|
||||
source(function(tiddler,title) {
|
||||
var data = $tw.utils.parseJSONSafe(title);
|
||||
try {
|
||||
data = JSON.parse(title);
|
||||
} catch(e) {
|
||||
data = undefined;
|
||||
}
|
||||
if(data !== undefined) {
|
||||
results.push(JSON.stringify(data,null,spaces));
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
46
core/modules/filters/insertafter.js
Normal file
46
core/modules/filters/insertafter.js
Normal file
@@ -0,0 +1,46 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/insertafter.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Insert an item after another item in a list
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Order a list
|
||||
*/
|
||||
exports.insertafter = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
var target = operator.operands[1] || (options.widget && options.widget.getVariable(operator.suffix || "currentTiddler"));
|
||||
if(target !== operator.operand) {
|
||||
// Remove the entry from the list if it is present
|
||||
var pos = results.indexOf(operator.operand);
|
||||
if(pos !== -1) {
|
||||
results.splice(pos,1);
|
||||
}
|
||||
// Insert the entry after the target marker
|
||||
pos = results.indexOf(target);
|
||||
if(pos !== -1) {
|
||||
results.splice(pos+1,0,operator.operand);
|
||||
} else {
|
||||
var suffix = operator.operands.length > 1 ? operator.suffix : "";
|
||||
if(suffix === "start") {
|
||||
results.splice(0,0,operator.operand);
|
||||
} else {
|
||||
results.push(operator.operand);
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -32,7 +32,12 @@ exports.insertbefore = function(source,operator,options) {
|
||||
if(pos !== -1) {
|
||||
results.splice(pos,0,operator.operand);
|
||||
} else {
|
||||
results.push(operator.operand);
|
||||
var suffix = operator.operands.length > 1 ? operator.suffix : "";
|
||||
if(suffix == "start") {
|
||||
results.splice(0,0,operator.operand);
|
||||
} else {
|
||||
results.push(operator.operand);
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
|
||||
@@ -19,13 +19,13 @@ exports.variable = function(source,prefix,options) {
|
||||
var results = [];
|
||||
if(prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(!(title in options.widget.variables)) {
|
||||
if(options.widget.getVariable(title) === undefined) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
if(title in options.widget.variables) {
|
||||
if(options.widget.getVariable(title) !== undefined) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
|
||||
153
core/modules/filters/json-ops.js
Normal file
153
core/modules/filters/json-ops.js
Normal file
@@ -0,0 +1,153 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/json-ops.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operators for JSON operations
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports["jsonget"] = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var data = $tw.utils.parseJSONSafe(title,title);
|
||||
if(data) {
|
||||
var item = getDataItemValueAsString(data,operator.operands);
|
||||
if(item !== undefined) {
|
||||
results.push(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
exports["jsonindexes"] = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var data = $tw.utils.parseJSONSafe(title,title);
|
||||
if(data) {
|
||||
var item = getDataItemKeysAsStrings(data,operator.operands);
|
||||
if(item !== undefined) {
|
||||
results.push.apply(results,item);
|
||||
}
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
exports["jsontype"] = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var data = $tw.utils.parseJSONSafe(title,title);
|
||||
if(data) {
|
||||
var item = getDataItemType(data,operator.operands);
|
||||
if(item !== undefined) {
|
||||
results.push(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
/*
|
||||
Given a JSON data structure and an array of index strings, return an array of the string representation of the values at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||
*/
|
||||
function getDataItemValueAsString(data,indexes) {
|
||||
// Get the item
|
||||
var item = getDataItem(data,indexes);
|
||||
// Return the item as a string
|
||||
return convertDataItemValueToString(item);
|
||||
}
|
||||
|
||||
/*
|
||||
Given a JSON data structure and an array of index strings, return an array of the string representation of the keys of the item at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||
*/
|
||||
function getDataItemKeysAsStrings(data,indexes) {
|
||||
// Get the item
|
||||
var item = getDataItem(data,indexes);
|
||||
// Return the item keys as a string
|
||||
return convertDataItemKeysToStrings(item);
|
||||
}
|
||||
|
||||
/*
|
||||
Return an array of the string representation of the values of a data item, or "undefined" if the item is undefined
|
||||
*/
|
||||
function convertDataItemValueToString(item) {
|
||||
// Return the item as a string
|
||||
if(item === undefined) {
|
||||
return item;
|
||||
}
|
||||
if(typeof item === "object") {
|
||||
return JSON.stringify(item);
|
||||
}
|
||||
return item.toString();
|
||||
}
|
||||
|
||||
/*
|
||||
Return an array of the string representation of the keys of a data item, or "undefined" if the item is undefined
|
||||
*/
|
||||
function convertDataItemKeysToStrings(item) {
|
||||
// Return the item as a string
|
||||
if(item === undefined) {
|
||||
return item;
|
||||
} else if(typeof item === "object") {
|
||||
if(item === null) {
|
||||
return [];
|
||||
}
|
||||
var results = [];
|
||||
if($tw.utils.isArray(item)) {
|
||||
for(var i=0; i<item.length; i++) {
|
||||
results.push(i.toString());
|
||||
}
|
||||
return results;
|
||||
} else {
|
||||
$tw.utils.each(Object.keys(item).sort(),function(key) {
|
||||
results.push(key);
|
||||
});
|
||||
return results;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function getDataItemType(data,indexes) {
|
||||
// Get the item
|
||||
var item = getDataItem(data,indexes);
|
||||
// Return the item type
|
||||
if(item === undefined) {
|
||||
return item;
|
||||
} else if(item === null) {
|
||||
return "null";
|
||||
} else if($tw.utils.isArray(item)) {
|
||||
return "array";
|
||||
} else if(typeof item === "object") {
|
||||
return "object";
|
||||
} else {
|
||||
return typeof item;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Given a JSON data structure and an array of index strings, return the value at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||
*/
|
||||
function getDataItem(data,indexes) {
|
||||
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
||||
return data;
|
||||
}
|
||||
// Get the item
|
||||
var item = data;
|
||||
for(var i=0; i<indexes.length; i++) {
|
||||
if(item !== undefined) {
|
||||
item = item[indexes[i]];
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
@@ -16,9 +16,15 @@ Filter operator for returning the names of the active variables
|
||||
Export our filter function
|
||||
*/
|
||||
exports.variables = function(source,operator,options) {
|
||||
var names = [];
|
||||
for(var variable in options.widget.variables) {
|
||||
names.push(variable);
|
||||
var names = [],
|
||||
widget = options.widget;
|
||||
while(widget && !widget.hasOwnProperty("variables")) {
|
||||
widget = widget.parentWidget;
|
||||
}
|
||||
if(widget && widget.variables) {
|
||||
for(var variable in widget.variables) {
|
||||
names.push(variable);
|
||||
}
|
||||
}
|
||||
return names.sort();
|
||||
};
|
||||
|
||||
@@ -141,6 +141,7 @@ function KeyboardManager(options) {
|
||||
this.shortcutKeysList = [], // Stores the shortcut-key descriptors
|
||||
this.shortcutActionList = [], // Stores the corresponding action strings
|
||||
this.shortcutParsedList = []; // Stores the parsed key descriptors
|
||||
this.shortcutPriorityList = []; // Stores the parsed shortcut priority
|
||||
this.lookupNames = ["shortcuts"];
|
||||
this.lookupNames.push($tw.platform.isMac ? "shortcuts-mac" : "shortcuts-not-mac")
|
||||
this.lookupNames.push($tw.platform.isWindows ? "shortcuts-windows" : "shortcuts-not-windows");
|
||||
@@ -318,12 +319,23 @@ KeyboardManager.prototype.updateShortcutLists = function(tiddlerList) {
|
||||
this.shortcutKeysList[i] = tiddlerFields.key !== undefined ? tiddlerFields.key : undefined;
|
||||
this.shortcutActionList[i] = tiddlerFields.text;
|
||||
this.shortcutParsedList[i] = this.shortcutKeysList[i] !== undefined ? this.parseKeyDescriptors(this.shortcutKeysList[i]) : undefined;
|
||||
this.shortcutPriorityList[i] = tiddlerFields.priority === "yes" ? true : false;
|
||||
}
|
||||
};
|
||||
|
||||
KeyboardManager.prototype.handleKeydownEvent = function(event) {
|
||||
/*
|
||||
event: the keyboard event object
|
||||
options:
|
||||
onlyPriority: true if only priority global shortcuts should be invoked
|
||||
*/
|
||||
KeyboardManager.prototype.handleKeydownEvent = function(event, options) {
|
||||
options = options || {};
|
||||
var key, action;
|
||||
for(var i=0; i<this.shortcutTiddlers.length; i++) {
|
||||
if(options.onlyPriority && this.shortcutPriorityList[i] !== true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(this.shortcutParsedList[i] !== undefined && this.checkKeyDescriptors(event,this.shortcutParsedList[i])) {
|
||||
key = this.shortcutParsedList[i];
|
||||
action = this.shortcutActionList[i];
|
||||
|
||||
@@ -41,9 +41,6 @@ exports.parse = function() {
|
||||
var node = {
|
||||
type: "element",
|
||||
tag: "span",
|
||||
attributes: {
|
||||
"class": {type: "string", value: "tc-inline-style"}
|
||||
},
|
||||
children: tree
|
||||
};
|
||||
if(classString) {
|
||||
@@ -52,6 +49,9 @@ exports.parse = function() {
|
||||
if(stylesString) {
|
||||
$tw.utils.addAttributeToParseTreeNode(node,"style",stylesString);
|
||||
}
|
||||
if(!classString && !stylesString) {
|
||||
$tw.utils.addClassToParseTreeNode(node,"tc-inline-style");
|
||||
}
|
||||
return [node];
|
||||
};
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ WikiParser.prototype.loadRemoteTiddler = function(url) {
|
||||
*/
|
||||
WikiParser.prototype.setupRules = function(proto,configPrefix) {
|
||||
var self = this;
|
||||
if(!$tw.safemode) {
|
||||
if(!$tw.safeMode) {
|
||||
$tw.utils.each(proto,function(object,name) {
|
||||
if(self.wiki.getTiddlerText(configPrefix + name,"enable") !== "enable") {
|
||||
delete proto[name];
|
||||
|
||||
@@ -30,6 +30,16 @@ exports.handler = function(request,response,state) {
|
||||
if(fields.revision) {
|
||||
delete fields.revision;
|
||||
}
|
||||
// If this is a skinny tiddler, it means the client never got the full
|
||||
// version of the tiddler to edit. So we must preserve whatever text
|
||||
// already exists on the server, or else we'll inadvertently delete it.
|
||||
if(fields._is_skinny !== undefined) {
|
||||
var tiddler = state.wiki.getTiddler(title);
|
||||
if(tiddler) {
|
||||
fields.text = tiddler.fields.text;
|
||||
}
|
||||
delete fields._is_skinny;
|
||||
}
|
||||
state.wiki.addTiddler(new $tw.Tiddler(fields,{title: title}));
|
||||
var changeCount = state.wiki.getChangeCount(title).toString();
|
||||
response.writeHead(204, "OK",{
|
||||
|
||||
@@ -359,8 +359,9 @@ Server.prototype.listen = function(port,host,prefix) {
|
||||
}
|
||||
// Display the port number after we've started listening (the port number might have been specified as zero, in which case we will get an assigned port)
|
||||
server.on("listening",function() {
|
||||
var address = server.address();
|
||||
$tw.utils.log("Serving on " + self.protocol + "://" + address.address + ":" + address.port + prefix,"brown/orange");
|
||||
var address = server.address(),
|
||||
url = self.protocol + "://" + (address.family === "IPv6" ? "[" + address.address + "]" : address.address) + ":" + address.port + prefix;
|
||||
$tw.utils.log("Serving on " + url,"brown/orange");
|
||||
$tw.utils.log("(press ctrl-C to exit)","red");
|
||||
});
|
||||
// Listen
|
||||
|
||||
@@ -62,12 +62,14 @@ function loadIFrame(url,callback) {
|
||||
Unload library iframe for given url
|
||||
*/
|
||||
function unloadIFrame(url){
|
||||
$tw.utils.each(document.getElementsByTagName('iframe'), function(iframe) {
|
||||
var iframes = document.getElementsByTagName('iframe');
|
||||
for(var t=iframes.length-1; t--; t>=0) {
|
||||
var iframe = iframes[t];
|
||||
if(iframe.getAttribute("library") === "true" &&
|
||||
iframe.getAttribute("src") === url) {
|
||||
iframe.parentNode.removeChild(iframe);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function saveIFrameInfoTiddler(iframeInfo) {
|
||||
|
||||
@@ -54,7 +54,9 @@ exports.startup = function() {
|
||||
var hash = $tw.utils.getLocationHash();
|
||||
if(hash !== $tw.locationHash) {
|
||||
$tw.locationHash = hash;
|
||||
openStartupTiddlers({defaultToCurrentStory: true});
|
||||
if(hash !== "#") {
|
||||
openStartupTiddlers({defaultToCurrentStory: true});
|
||||
}
|
||||
}
|
||||
},false);
|
||||
// Listen for the tm-browser-refresh message
|
||||
|
||||
@@ -25,14 +25,13 @@ widget: widget to use as the context for the filter
|
||||
exports.makeDraggable = function(options) {
|
||||
var dragImageType = options.dragImageType || "dom",
|
||||
dragImage,
|
||||
domNode = options.domNode,
|
||||
dragHandle = options.selector && domNode.querySelector(options.selector) || domNode;
|
||||
domNode = options.domNode;
|
||||
// Make the dom node draggable (not necessary for anchor tags)
|
||||
if((domNode.tagName || "").toLowerCase() !== "a") {
|
||||
dragHandle.setAttribute("draggable","true");
|
||||
if(!options.selector && ((domNode.tagName || "").toLowerCase() !== "a")) {
|
||||
domNode.setAttribute("draggable","true");
|
||||
}
|
||||
// Add event handlers
|
||||
$tw.utils.addEventListeners(dragHandle,[
|
||||
$tw.utils.addEventListeners(domNode,[
|
||||
{name: "dragstart", handlerFunction: function(event) {
|
||||
if(event.dataTransfer === undefined) {
|
||||
return false;
|
||||
@@ -41,19 +40,19 @@ exports.makeDraggable = function(options) {
|
||||
var dragTiddler = options.dragTiddlerFn && options.dragTiddlerFn(),
|
||||
dragFilter = options.dragFilterFn && options.dragFilterFn(),
|
||||
titles = dragTiddler ? [dragTiddler] : [],
|
||||
startActions = options.startActions,
|
||||
variables,
|
||||
domNodeRect;
|
||||
startActions = options.startActions,
|
||||
variables,
|
||||
domNodeRect;
|
||||
if(dragFilter) {
|
||||
titles.push.apply(titles,options.widget.wiki.filterTiddlers(dragFilter,options.widget));
|
||||
}
|
||||
var titleString = $tw.utils.stringifyList(titles);
|
||||
// Check that we've something to drag
|
||||
if(titles.length > 0 && event.target === dragHandle) {
|
||||
if(titles.length > 0 && (options.selector && $tw.utils.domMatchesSelector(event.target,options.selector) || event.target === domNode)) {
|
||||
// Mark the drag in progress
|
||||
$tw.dragInProgress = domNode;
|
||||
// Set the dragging class on the element being dragged
|
||||
$tw.utils.addClass(event.target,"tc-dragging");
|
||||
$tw.utils.addClass(domNode,"tc-dragging");
|
||||
// Invoke drag-start actions if given
|
||||
if(startActions !== undefined) {
|
||||
// Collect our variables
|
||||
@@ -107,21 +106,22 @@ exports.makeDraggable = function(options) {
|
||||
dataTransfer.setData("text/vnd.tiddler",jsonData);
|
||||
dataTransfer.setData("text/plain",titleString);
|
||||
dataTransfer.setData("text/x-moz-url","data:text/vnd.tiddler," + encodeURIComponent(jsonData));
|
||||
} else {
|
||||
dataTransfer.setData("URL","data:text/vnd.tiddler," + encodeURIComponent(jsonData));
|
||||
}
|
||||
dataTransfer.setData("URL","data:text/vnd.tiddler," + encodeURIComponent(jsonData));
|
||||
dataTransfer.setData("Text",titleString);
|
||||
event.stopPropagation();
|
||||
}
|
||||
return false;
|
||||
}},
|
||||
{name: "dragend", handlerFunction: function(event) {
|
||||
if(event.target === domNode) {
|
||||
if((options.selector && $tw.utils.domMatchesSelector(event.target,options.selector)) || event.target === domNode) {
|
||||
// Collect the tiddlers being dragged
|
||||
var dragTiddler = options.dragTiddlerFn && options.dragTiddlerFn(),
|
||||
dragFilter = options.dragFilterFn && options.dragFilterFn(),
|
||||
titles = dragTiddler ? [dragTiddler] : [],
|
||||
endActions = options.endActions,
|
||||
variables;
|
||||
endActions = options.endActions,
|
||||
variables;
|
||||
if(dragFilter) {
|
||||
titles.push.apply(titles,options.widget.wiki.filterTiddlers(dragFilter,options.widget));
|
||||
}
|
||||
@@ -135,7 +135,7 @@ exports.makeDraggable = function(options) {
|
||||
options.widget.invokeActionString(endActions,options.widget,event,variables);
|
||||
}
|
||||
// Remove the dragging class on the element being dragged
|
||||
$tw.utils.removeClass(event.target,"tc-dragging");
|
||||
$tw.utils.removeClass(domNode,"tc-dragging");
|
||||
// Delete the drag image element
|
||||
if(dragImage) {
|
||||
dragImage.parentNode.removeChild(dragImage);
|
||||
|
||||
@@ -36,8 +36,9 @@ Notifier.prototype.display = function(title,options) {
|
||||
if(!tiddler) {
|
||||
return;
|
||||
}
|
||||
// Add classes
|
||||
// Add classes and roles
|
||||
$tw.utils.addClass(notification,"tc-notification");
|
||||
notification.setAttribute("role","alert");
|
||||
// Create the variables
|
||||
var variables = $tw.utils.extend({currentTiddler: title},options.variables);
|
||||
// Render the body of the notification
|
||||
|
||||
@@ -42,7 +42,7 @@ var TW_TextNode = function(text) {
|
||||
this.textContent = text + "";
|
||||
};
|
||||
|
||||
TW_TextNode.prototype = Object.create(TW_Node.prototype);
|
||||
Object.setPrototypeOf(TW_TextNode,TW_Node.prototype);
|
||||
|
||||
Object.defineProperty(TW_TextNode.prototype, "nodeType", {
|
||||
get: function() {
|
||||
@@ -67,7 +67,7 @@ var TW_Element = function(tag,namespace) {
|
||||
this.namespaceURI = namespace || "http://www.w3.org/1999/xhtml";
|
||||
};
|
||||
|
||||
TW_Element.prototype = Object.create(TW_Node.prototype);
|
||||
Object.setPrototypeOf(TW_Element,TW_Node.prototype);
|
||||
|
||||
Object.defineProperty(TW_Element.prototype, "style", {
|
||||
get: function() {
|
||||
|
||||
@@ -48,7 +48,9 @@ Logger.prototype.log = function(/* args */) {
|
||||
this.saveBufferLogger.buffer = this.saveBufferLogger.buffer.slice(-this.saveBufferLogger.saveLimit);
|
||||
}
|
||||
if(console !== undefined && console.log !== undefined) {
|
||||
return Function.apply.call(console.log, console, [$tw.utils.terminalColour(this.colour),this.componentName + ":"].concat(Array.prototype.slice.call(arguments,0)).concat($tw.utils.terminalColour()));
|
||||
var logMessage = [$tw.utils.terminalColour(this.colour) + this.componentName + ":"].concat(Array.prototype.slice.call(arguments,0));
|
||||
logMessage[logMessage.length-1] += $tw.utils.terminalColour();
|
||||
return Function.apply.call(console.log, console, logMessage);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -12,12 +12,26 @@ Parse tree utility functions.
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Add attribute to parse tree node
|
||||
Can be invoked as (node,name,value) or (node,attr)
|
||||
*/
|
||||
exports.addAttributeToParseTreeNode = function(node,name,value) {
|
||||
var attribute = {name: name, type: "string", value: value};
|
||||
var attribute = typeof name === "object" ? name : {name: name, type: "string", value: value};
|
||||
name = attribute.name;
|
||||
node.attributes = node.attributes || {};
|
||||
node.orderedAttributes = node.orderedAttributes || [];
|
||||
node.attributes[name] = attribute;
|
||||
if(node.orderedAttributes) {
|
||||
var foundIndex = -1;
|
||||
$tw.utils.each(node.orderedAttributes,function(attr,index) {
|
||||
if(attr.name === name) {
|
||||
foundIndex = index;
|
||||
}
|
||||
});
|
||||
if(foundIndex === -1) {
|
||||
node.orderedAttributes.push(attribute);
|
||||
} else {
|
||||
node.orderedAttributes[foundIndex] = attribute;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -51,10 +65,8 @@ exports.addClassToParseTreeNode = function(node,classString) {
|
||||
// If the class attribute does not exist, we must create it first.
|
||||
attribute = {name: "class", type: "string", value: ""};
|
||||
node.attributes["class"] = attribute;
|
||||
if(node.orderedAttributes) {
|
||||
// If there are orderedAttributes, we've got to add them there too.
|
||||
node.orderedAttributes.push(attribute);
|
||||
}
|
||||
node.orderedAttributes = node.orderedAttributes || [];
|
||||
node.orderedAttributes.push(attribute);
|
||||
}
|
||||
if(attribute.type === "string") {
|
||||
if(attribute.value !== "") {
|
||||
@@ -74,10 +86,8 @@ exports.addStyleToParseTreeNode = function(node,name,value) {
|
||||
if(!attribute) {
|
||||
attribute = {name: "style", type: "string", value: ""};
|
||||
node.attributes.style = attribute;
|
||||
if(node.orderedAttributes) {
|
||||
// If there are orderedAttributes, we've got to add them there too.
|
||||
node.orderedAttributes.push(attribute);
|
||||
}
|
||||
node.orderedAttributes = node.orderedAttributes || [];
|
||||
node.orderedAttributes.push(attribute);
|
||||
}
|
||||
if(attribute.type === "string") {
|
||||
attribute.value += name + ":" + value + ";";
|
||||
|
||||
@@ -36,7 +36,7 @@ Compute the internal state of the widget
|
||||
*/
|
||||
DeleteFieldWidget.prototype.execute = function() {
|
||||
this.actionTiddler = this.getAttribute("$tiddler",this.getVariable("currentTiddler"));
|
||||
this.actionField = this.getAttribute("$field");
|
||||
this.actionField = this.getAttribute("$field",null);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -59,7 +59,7 @@ DeleteFieldWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
tiddler = this.wiki.getTiddler(self.actionTiddler),
|
||||
removeFields = {},
|
||||
hasChanged = false;
|
||||
if(this.actionField && tiddler) {
|
||||
if((this.actionField !== null) && tiddler) {
|
||||
removeFields[this.actionField] = undefined;
|
||||
if(this.actionField in tiddler.fields) {
|
||||
hasChanged = true;
|
||||
|
||||
@@ -46,7 +46,8 @@ ButtonWidget.prototype.render = function(parent,nextSibling) {
|
||||
isPoppedUp = (this.popup || this.popupTitle) && this.isPoppedUp();
|
||||
if(this.selectedClass) {
|
||||
if((this.set || this.setTitle) && this.setTo && this.isSelected()) {
|
||||
$tw.utils.pushTop(classes,this.selectedClass.split(" "));
|
||||
$tw.utils.pushTop(classes, this.selectedClass.split(" "));
|
||||
domNode.setAttribute("aria-checked", "true");
|
||||
}
|
||||
if(isPoppedUp) {
|
||||
$tw.utils.pushTop(classes,this.selectedClass.split(" "));
|
||||
@@ -66,6 +67,9 @@ ButtonWidget.prototype.render = function(parent,nextSibling) {
|
||||
if(this["aria-label"]) {
|
||||
domNode.setAttribute("aria-label",this["aria-label"]);
|
||||
}
|
||||
if (this.role) {
|
||||
domNode.setAttribute("role", this.role);
|
||||
}
|
||||
if(this.popup || this.popupTitle) {
|
||||
domNode.setAttribute("aria-expanded",isPoppedUp ? "true" : "false");
|
||||
}
|
||||
@@ -206,6 +210,7 @@ ButtonWidget.prototype.execute = function() {
|
||||
this.popup = this.getAttribute("popup");
|
||||
this.hover = this.getAttribute("hover");
|
||||
this["aria-label"] = this.getAttribute("aria-label");
|
||||
this.role = this.getAttribute("role");
|
||||
this.tooltip = this.getAttribute("tooltip");
|
||||
this.style = this.getAttribute("style");
|
||||
this["class"] = this.getAttribute("class","");
|
||||
|
||||
@@ -66,14 +66,14 @@ CheckboxWidget.prototype.render = function(parent,nextSibling) {
|
||||
CheckboxWidget.prototype.getValue = function() {
|
||||
var tiddler = this.wiki.getTiddler(this.checkboxTitle);
|
||||
if(tiddler || this.checkboxFilter) {
|
||||
if(this.checkboxTag) {
|
||||
if(tiddler && this.checkboxTag) {
|
||||
if(this.checkboxInvertTag === "yes") {
|
||||
return !tiddler.hasTag(this.checkboxTag);
|
||||
} else {
|
||||
return tiddler.hasTag(this.checkboxTag);
|
||||
}
|
||||
}
|
||||
if(this.checkboxField || this.checkboxIndex) {
|
||||
if(tiddler && (this.checkboxField || this.checkboxIndex)) {
|
||||
// Same logic applies to fields and indexes
|
||||
var value;
|
||||
if(this.checkboxField) {
|
||||
@@ -206,11 +206,18 @@ CheckboxWidget.prototype.handleChangeEvent = function(event) {
|
||||
}
|
||||
// Set the list field (or index) if specified
|
||||
if(this.checkboxListField || this.checkboxListIndex) {
|
||||
var listContents, oldPos, newPos;
|
||||
var fieldContents, listContents, oldPos, newPos;
|
||||
if(this.checkboxListField) {
|
||||
listContents = tiddler.getFieldList(this.checkboxListField);
|
||||
fieldContents = tiddler ? tiddler.fields[this.checkboxListField] : undefined;
|
||||
} else {
|
||||
listContents = $tw.utils.parseStringArray(this.wiki.extractTiddlerDataItem(this.checkboxTitle,this.checkboxListIndex) || "") || [];
|
||||
fieldContents = this.wiki.extractTiddlerDataItem(this.checkboxTitle,this.checkboxListIndex);
|
||||
}
|
||||
if($tw.utils.isArray(fieldContents)) {
|
||||
// Make a copy so we can modify it without changing original that's refrenced elsewhere
|
||||
listContents = fieldContents.slice(0);
|
||||
} else {
|
||||
listContents = $tw.utils.parseStringArray(fieldContents) || [];
|
||||
// No need to copy since parseStringArray returns a fresh array, not refrenced elsewhere
|
||||
}
|
||||
oldPos = notValue ? listContents.indexOf(notValue) : -1;
|
||||
newPos = value ? listContents.indexOf(value) : -1;
|
||||
|
||||
@@ -87,12 +87,32 @@ DraggableWidget.prototype.execute = function() {
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
||||
|
||||
DraggableWidget.prototype.updateDomNodeClasses = function() {
|
||||
var domNodeClasses = this.domNodes[0].className.split(" "),
|
||||
oldClasses = this.draggableClasses.split(" ");
|
||||
this.draggableClasses = this.getAttribute("class");
|
||||
//Remove classes assigned from the old value of class attribute
|
||||
$tw.utils.each(oldClasses,function(oldClass){
|
||||
var i = domNodeClasses.indexOf(oldClass);
|
||||
if(i !== -1) {
|
||||
domNodeClasses.splice(i,1);
|
||||
}
|
||||
});
|
||||
//Add new classes from updated class attribute.
|
||||
$tw.utils.pushTop(domNodeClasses,this.draggableClasses);
|
||||
this.domNodes[0].setAttribute("class",domNodeClasses.join(" "))
|
||||
}
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
DraggableWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if($tw.utils.count(changedAttributes) > 0) {
|
||||
var changedAttributes = this.computeAttributes(),
|
||||
changedAttributesCount = $tw.utils.count(changedAttributes);
|
||||
if(changedAttributesCount === 1 && changedAttributes["class"]) {
|
||||
this.updateDomNodeClasses();
|
||||
} else if(changedAttributesCount > 0) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
@@ -101,4 +121,4 @@ DraggableWidget.prototype.refresh = function(changedTiddlers) {
|
||||
|
||||
exports.draggable = DraggableWidget;
|
||||
|
||||
})();
|
||||
})();
|
||||
@@ -42,16 +42,22 @@ ElementWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.tag = "h" + headingLevel;
|
||||
}
|
||||
// Select the namespace for the tag
|
||||
var tagNamespaces = {
|
||||
var XHTML_NAMESPACE = "http://www.w3.org/1999/xhtml",
|
||||
tagNamespaces = {
|
||||
svg: "http://www.w3.org/2000/svg",
|
||||
math: "http://www.w3.org/1998/Math/MathML",
|
||||
body: "http://www.w3.org/1999/xhtml"
|
||||
body: XHTML_NAMESPACE
|
||||
};
|
||||
this.namespace = tagNamespaces[this.tag];
|
||||
if(this.namespace) {
|
||||
this.setVariable("namespace",this.namespace);
|
||||
} else {
|
||||
this.namespace = this.getVariable("namespace",{defaultValue: "http://www.w3.org/1999/xhtml"});
|
||||
if(this.hasAttribute("xmlns")) {
|
||||
this.namespace = this.getAttribute("xmlns");
|
||||
this.setVariable("namespace",this.namespace);
|
||||
} else {
|
||||
this.namespace = this.getVariable("namespace",{defaultValue: XHTML_NAMESPACE});
|
||||
}
|
||||
}
|
||||
// Invoke the th-rendering-element hook
|
||||
var parseTreeNodes = $tw.hooks.invokeHook("th-rendering-element",null,this);
|
||||
|
||||
63
core/modules/widgets/error.js
Normal file
63
core/modules/widgets/error.js
Normal file
@@ -0,0 +1,63 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/error.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Error widget
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var ErrorWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
ErrorWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
ErrorWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
var message = this.getAttribute("$message","Unknown error"),
|
||||
domNode = this.document.createElement("span");
|
||||
domNode.appendChild(this.document.createTextNode(message));
|
||||
domNode.className = "tc-error";
|
||||
parent.insertBefore(domNode,nextSibling);
|
||||
this.domNodes.push(domNode);
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
ErrorWidget.prototype.execute = function() {
|
||||
// Nothing to do for a text node
|
||||
};
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
ErrorWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes["$message"]) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
exports.error = ErrorWidget;
|
||||
|
||||
})();
|
||||
108
core/modules/widgets/genesis.js
Normal file
108
core/modules/widgets/genesis.js
Normal file
@@ -0,0 +1,108 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/genesis.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Genesis widget for dynamically creating widgets
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var GenesisWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
GenesisWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
GenesisWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes({filterFn: function(name) {
|
||||
// Only compute our own attributes which start with a single dollar
|
||||
return name.charAt(0) === "$" && name.charAt(1) !== "$";
|
||||
}});
|
||||
this.execute();
|
||||
this.renderChildren(parent,nextSibling);
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
GenesisWidget.prototype.execute = function() {
|
||||
var self = this;
|
||||
// Collect attributes
|
||||
this.genesisType = this.getAttribute("$type","element");
|
||||
this.genesisRemappable = this.getAttribute("$remappable","yes") === "yes";
|
||||
this.genesisNames = this.getAttribute("$names","");
|
||||
this.genesisValues = this.getAttribute("$values","");
|
||||
// Construct parse tree
|
||||
var isElementWidget = this.genesisType.charAt(0) !== "$",
|
||||
nodeType = isElementWidget ? "element" : this.genesisType.substr(1),
|
||||
nodeTag = isElementWidget ? this.genesisType : undefined;
|
||||
var parseTreeNodes = [{
|
||||
type: nodeType,
|
||||
tag: nodeTag,
|
||||
attributes: {},
|
||||
orderedAttributes: [],
|
||||
children: this.parseTreeNode.children || [],
|
||||
isNotRemappable: !this.genesisRemappable
|
||||
}];
|
||||
// Apply explicit attributes
|
||||
$tw.utils.each($tw.utils.getOrderedAttributesFromParseTreeNode(this.parseTreeNode),function(attribute) {
|
||||
var name = attribute.name;
|
||||
if(name.charAt(0) === "$") {
|
||||
if(name.charAt(1) === "$") {
|
||||
// Double $$ is changed to a single $
|
||||
name = name.substr(1);
|
||||
} else {
|
||||
// Single dollar is ignored
|
||||
return;
|
||||
}
|
||||
}
|
||||
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],$tw.utils.extend({},attribute,{name: name}));
|
||||
});
|
||||
// Apply attributes in $names/$values
|
||||
this.attributeNames = [];
|
||||
this.attributeValues = [];
|
||||
if(this.genesisNames && this.genesisValues) {
|
||||
this.attributeNames = this.wiki.filterTiddlers(self.genesisNames,this);
|
||||
this.attributeValues = this.wiki.filterTiddlers(self.genesisValues,this);
|
||||
$tw.utils.each(this.attributeNames,function(varname,index) {
|
||||
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],varname,self.attributeValues[index] || "");
|
||||
});
|
||||
}
|
||||
// Construct the child widgets
|
||||
this.makeChildWidgets(parseTreeNodes);
|
||||
};
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
GenesisWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes(),
|
||||
filterNames = this.getAttribute("$names",""),
|
||||
filterValues = this.getAttribute("$values",""),
|
||||
attributeNames = this.wiki.filterTiddlers(filterNames,this),
|
||||
attributeValues = this.wiki.filterTiddlers(filterValues,this);
|
||||
if($tw.utils.count(changedAttributes) > 0 || !$tw.utils.isArrayEqual(this.attributeNames,attributeNames) || !$tw.utils.isArrayEqual(this.attributeValues,attributeValues)) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
}
|
||||
};
|
||||
|
||||
exports.genesis = GenesisWidget;
|
||||
|
||||
})();
|
||||
@@ -111,6 +111,9 @@ ImageWidget.prototype.render = function(parent,nextSibling) {
|
||||
if(this.imageAlt) {
|
||||
domNode.setAttribute("alt",this.imageAlt);
|
||||
}
|
||||
if(this.lazyLoading && tag === "img") {
|
||||
domNode.setAttribute("loading",this.lazyLoading);
|
||||
}
|
||||
// Add classes when the image loads or fails
|
||||
$tw.utils.addClass(domNode,"tc-image-loading");
|
||||
domNode.addEventListener("load",function() {
|
||||
@@ -137,6 +140,7 @@ ImageWidget.prototype.execute = function() {
|
||||
this.imageClass = this.getAttribute("class");
|
||||
this.imageTooltip = this.getAttribute("tooltip");
|
||||
this.imageAlt = this.getAttribute("alt");
|
||||
this.lazyLoading = this.getAttribute("loading");
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -39,7 +39,10 @@ Compute the internal state of the widget
|
||||
ImportVariablesWidget.prototype.execute = function(tiddlerList) {
|
||||
var widgetPointer = this;
|
||||
// Got to flush all the accumulated variables
|
||||
this.variables = new this.variablesConstructor();
|
||||
this.variables = Object.create(null);
|
||||
if(this.parentWidget) {
|
||||
Object.setPrototypeOf(this.variables,this.parentWidget.variables);
|
||||
}
|
||||
// Get our parameters
|
||||
this.filter = this.getAttribute("filter");
|
||||
// Compute the filter
|
||||
|
||||
@@ -53,6 +53,10 @@ KeyboardWidget.prototype.render = function(parent,nextSibling) {
|
||||
};
|
||||
|
||||
KeyboardWidget.prototype.handleChangeEvent = function(event) {
|
||||
if ($tw.keyboardManager.handleKeydownEvent(event, {onlyPriority: true})) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var keyInfo = $tw.keyboardManager.getMatchingKeyDescriptor(event,this.keyInfoArray);
|
||||
if(keyInfo) {
|
||||
var handled = this.invokeActions(this,event);
|
||||
|
||||
@@ -51,11 +51,9 @@ LetWidget.prototype.computeAttributes = function() {
|
||||
$tw.utils.each($tw.utils.getOrderedAttributesFromParseTreeNode(this.parseTreeNode),function(attribute) {
|
||||
var value = self.computeAttribute(attribute),
|
||||
name = attribute.name;
|
||||
if(name.charAt(0) !== "$") {
|
||||
// Now that it's prepped, we're allowed to look this variable up
|
||||
// when defining later variables
|
||||
self.currentValueFor[name] = value;
|
||||
}
|
||||
// Now that it's prepped, we're allowed to look this variable up
|
||||
// when defining later variables
|
||||
self.currentValueFor[name] = value;
|
||||
});
|
||||
// Run through again, setting variables and looking for differences
|
||||
$tw.utils.each(this.currentValueFor,function(value,name) {
|
||||
|
||||
@@ -175,6 +175,11 @@ SelectWidget.prototype.refresh = function(changedTiddlers) {
|
||||
return true;
|
||||
// If the target tiddler value has changed, just update setting and refresh the children
|
||||
} else {
|
||||
if(changedAttributes.class) {
|
||||
this.selectClass = this.getAttribute("class");
|
||||
this.getSelectDomNode().setAttribute("class",this.selectClass);
|
||||
}
|
||||
|
||||
var childrenRefreshed = this.refreshChildren(changedTiddlers);
|
||||
if(changedTiddlers[this.selectTitle] || childrenRefreshed) {
|
||||
this.setSelectValue();
|
||||
|
||||
@@ -70,11 +70,9 @@ TranscludeWidget.prototype.execute = function() {
|
||||
// Check for recursion
|
||||
if(parser) {
|
||||
if(this.parentWidget && this.parentWidget.hasVariable("transclusion",recursionMarker)) {
|
||||
parseTreeNodes = [{type: "element", tag: "span", attributes: {
|
||||
"class": {type: "string", value: "tc-error"}
|
||||
}, children: [
|
||||
{type: "text", text: $tw.language.getString("Error/RecursiveTransclusion")}
|
||||
]}];
|
||||
parseTreeNodes = [{type: "error", attributes: {
|
||||
"$message": {type: "string", value: $tw.language.getString("Error/RecursiveTransclusion")}
|
||||
}}];
|
||||
}
|
||||
}
|
||||
// Construct the child widgets
|
||||
|
||||
@@ -12,6 +12,9 @@ Widget base class
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/* Maximum permitted depth of the widget tree for recursion detection */
|
||||
var MAX_WIDGET_TREE_DEPTH = 1000;
|
||||
|
||||
/*
|
||||
Create a widget object for a parse tree node
|
||||
parseTreeNode: reference to the parse tree node to be rendered
|
||||
@@ -38,9 +41,10 @@ Widget.prototype.initialise = function(parseTreeNode,options) {
|
||||
this.parseTreeNode = parseTreeNode;
|
||||
this.wiki = options.wiki;
|
||||
this.parentWidget = options.parentWidget;
|
||||
this.variablesConstructor = function() {};
|
||||
this.variablesConstructor.prototype = this.parentWidget ? this.parentWidget.variables : {};
|
||||
this.variables = new this.variablesConstructor();
|
||||
this.variables = Object.create(null);
|
||||
if(this.parentWidget) {
|
||||
Object.setPrototypeOf(this.variables,this.parentWidget.variables);
|
||||
}
|
||||
this.document = options.document;
|
||||
this.attributes = {};
|
||||
this.children = [];
|
||||
@@ -357,6 +361,20 @@ Widget.prototype.assignAttributes = function(domNode,options) {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Get the number of ancestor widgets for this widget
|
||||
*/
|
||||
Widget.prototype.getAncestorCount = function() {
|
||||
if(this.ancestorCount === undefined) {
|
||||
if(this.parentWidget) {
|
||||
this.ancestorCount = this.parentWidget.getAncestorCount() + 1;
|
||||
} else {
|
||||
this.ancestorCount = 0;
|
||||
}
|
||||
}
|
||||
return this.ancestorCount;
|
||||
};
|
||||
|
||||
/*
|
||||
Make child widgets correspondng to specified parseTreeNodes
|
||||
*/
|
||||
@@ -364,21 +382,29 @@ Widget.prototype.makeChildWidgets = function(parseTreeNodes,options) {
|
||||
options = options || {};
|
||||
this.children = [];
|
||||
var self = this;
|
||||
// Create set variable widgets for each variable
|
||||
$tw.utils.each(options.variables,function(value,name) {
|
||||
var setVariableWidget = {
|
||||
type: "set",
|
||||
attributes: {
|
||||
name: {type: "string", value: name},
|
||||
value: {type: "string", value: value}
|
||||
},
|
||||
children: parseTreeNodes
|
||||
};
|
||||
parseTreeNodes = [setVariableWidget];
|
||||
});
|
||||
$tw.utils.each(parseTreeNodes || (this.parseTreeNode && this.parseTreeNode.children),function(childNode) {
|
||||
self.children.push(self.makeChildWidget(childNode));
|
||||
});
|
||||
// Check for too much recursion
|
||||
if(this.getAncestorCount() > MAX_WIDGET_TREE_DEPTH) {
|
||||
this.children.push(this.makeChildWidget({type: "error", attributes: {
|
||||
"$message": {type: "string", value: $tw.language.getString("Error/RecursiveTransclusion")}
|
||||
}}));
|
||||
} else {
|
||||
// Create set variable widgets for each variable
|
||||
$tw.utils.each(options.variables,function(value,name) {
|
||||
var setVariableWidget = {
|
||||
type: "set",
|
||||
attributes: {
|
||||
name: {type: "string", value: name},
|
||||
value: {type: "string", value: value}
|
||||
},
|
||||
children: parseTreeNodes
|
||||
};
|
||||
parseTreeNodes = [setVariableWidget];
|
||||
});
|
||||
// Create the child widgets
|
||||
$tw.utils.each(parseTreeNodes || (this.parseTreeNode && this.parseTreeNode.children),function(childNode) {
|
||||
self.children.push(self.makeChildWidget(childNode));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -50,7 +50,7 @@ exports.getTextReference = function(textRef,defaultText,currTiddlerTitle) {
|
||||
if(tr.field) {
|
||||
var tiddler = this.getTiddler(title);
|
||||
if(tr.field === "title") { // Special case so we can return the title of a non-existent tiddler
|
||||
return title;
|
||||
return title || defaultText;
|
||||
} else if(tiddler && $tw.utils.hop(tiddler.fields,tr.field)) {
|
||||
return tiddler.getFieldString(tr.field);
|
||||
} else {
|
||||
|
||||
@@ -34,6 +34,8 @@ external-link-foreground-hover: inherit
|
||||
external-link-foreground-visited: #0000aa
|
||||
external-link-foreground: #0000ee
|
||||
foreground: #333333
|
||||
highlight-background: #ffff00
|
||||
highlight-foreground: #000000
|
||||
message-background: #ecf2ff
|
||||
message-border: #cfd6e6
|
||||
message-foreground: #547599
|
||||
|
||||
@@ -34,6 +34,8 @@ external-link-foreground-hover: inherit
|
||||
external-link-foreground-visited: #0000aa
|
||||
external-link-foreground: #0000ee
|
||||
foreground: #333353
|
||||
highlight-background: #ffff00
|
||||
highlight-foreground: #000000
|
||||
message-background: #ecf2ff
|
||||
message-border: #cfd6e6
|
||||
message-foreground: #547599
|
||||
|
||||
@@ -34,6 +34,8 @@ external-link-foreground-hover: inherit
|
||||
external-link-foreground-visited: #0000aa
|
||||
external-link-foreground: #0000ee
|
||||
foreground: #333333
|
||||
highlight-background: #ffff00
|
||||
highlight-foreground: #000000
|
||||
message-background: #ecf2ff
|
||||
message-border: #cfd6e6
|
||||
message-foreground: #547599
|
||||
|
||||
@@ -34,6 +34,8 @@ external-link-foreground-hover: inherit
|
||||
external-link-foreground-visited: #00a
|
||||
external-link-foreground: #00e
|
||||
foreground: #000
|
||||
highlight-background: #ffff00
|
||||
highlight-foreground: #000000
|
||||
message-background: <<colour foreground>>
|
||||
message-border: <<colour background>>
|
||||
message-foreground: <<colour background>>
|
||||
|
||||
@@ -34,6 +34,8 @@ external-link-foreground-hover: inherit
|
||||
external-link-foreground-visited: #00a
|
||||
external-link-foreground: #00e
|
||||
foreground: #fff
|
||||
highlight-background: #ffff00
|
||||
highlight-foreground: #000000
|
||||
message-background: <<colour foreground>>
|
||||
message-border: <<colour background>>
|
||||
message-foreground: <<colour background>>
|
||||
|
||||
@@ -32,6 +32,8 @@ external-link-foreground-hover:
|
||||
external-link-foreground-visited: #BF5AF2
|
||||
external-link-foreground: #32D74B
|
||||
foreground: #FFFFFF
|
||||
highlight-background: #ffff78
|
||||
highlight-foreground: #000000
|
||||
menubar-background: #464646
|
||||
menubar-foreground: #ffffff
|
||||
message-background: <<colour background>>
|
||||
|
||||
@@ -36,6 +36,8 @@ external-link-foreground-hover: inherit
|
||||
external-link-foreground-visited: #0000aa
|
||||
external-link-foreground: #0000ee
|
||||
foreground: #333333
|
||||
highlight-background: #ffff00
|
||||
highlight-foreground: #000000
|
||||
message-background: #ecf2ff
|
||||
message-border: #cfd6e6
|
||||
message-foreground: #547599
|
||||
|
||||
@@ -40,6 +40,8 @@ external-link-foreground-hover: inherit
|
||||
external-link-foreground-visited: #313163
|
||||
external-link-foreground: #555592
|
||||
foreground: #2D2A23
|
||||
highlight-background: #ffff00
|
||||
highlight-foreground: #000000
|
||||
menubar-background: #CDC2A6
|
||||
menubar-foreground: #5A5446
|
||||
message-background: #ECE5CF
|
||||
|
||||
@@ -41,6 +41,8 @@ external-link-foreground-hover: inherit
|
||||
external-link-foreground-visited: #d3869b
|
||||
external-link-foreground: #8ec07c
|
||||
foreground: #fbf1c7
|
||||
highlight-background: #ffff79
|
||||
highlight-foreground: #000000
|
||||
menubar-background: #504945
|
||||
menubar-foreground: <<colour foreground>>
|
||||
message-background: #83a598
|
||||
|
||||
@@ -41,6 +41,8 @@ external-link-foreground-hover: inherit
|
||||
external-link-foreground-visited: #5E81AC
|
||||
external-link-foreground: #8FBCBB
|
||||
foreground: #d8dee9
|
||||
highlight-background: #ffff78
|
||||
highlight-foreground: #000000
|
||||
menubar-background: #2E3440
|
||||
menubar-foreground: #d8dee9
|
||||
message-background: #2E3440
|
||||
|
||||
@@ -34,6 +34,8 @@ external-link-foreground-hover: inherit
|
||||
external-link-foreground-visited: #0000aa
|
||||
external-link-foreground: #0000ee
|
||||
foreground: #333333
|
||||
highlight-background: #ffff00
|
||||
highlight-foreground: #000000
|
||||
message-background: #ecf2ff
|
||||
message-border: #cfd6e6
|
||||
message-foreground: #547599
|
||||
|
||||
@@ -131,6 +131,8 @@ external-link-background-hover: inherit
|
||||
external-link-background-visited: inherit
|
||||
external-link-background: inherit
|
||||
external-link-foreground-hover: inherit
|
||||
highlight-background: #ffff00
|
||||
highlight-foreground: #000000
|
||||
message-border: #cfd6e6
|
||||
modal-border: #999999
|
||||
select-tag-background:
|
||||
|
||||
@@ -35,6 +35,8 @@ external-link-foreground: #268bd2
|
||||
external-link-foreground-hover:
|
||||
external-link-foreground-visited: #268bd2
|
||||
foreground: #839496
|
||||
highlight-background: #ffff78
|
||||
highlight-foreground: #000000
|
||||
message-background: #002b36
|
||||
message-border: #586e75
|
||||
message-foreground: #839496
|
||||
|
||||
@@ -35,6 +35,8 @@ external-link-foreground: #268bd2
|
||||
external-link-foreground-hover: inherit
|
||||
external-link-foreground-visited: #268bd2
|
||||
foreground: #657b83
|
||||
highlight-background: #ffff00
|
||||
highlight-foreground: #000000
|
||||
message-background: #fdf6e3
|
||||
message-border: #93a1a1
|
||||
message-foreground: #657b83
|
||||
|
||||
@@ -34,6 +34,8 @@ external-link-foreground-hover:
|
||||
external-link-foreground-visited:
|
||||
external-link-foreground:
|
||||
foreground: rgba(0, 0, 0, 0.87)
|
||||
highlight-background: #ffff00
|
||||
highlight-foreground: #000000
|
||||
message-background: <<colour background>>
|
||||
message-border: <<colour very-muted-foreground>>
|
||||
message-foreground: rgba(0, 0, 0, 0.54)
|
||||
|
||||
@@ -34,6 +34,8 @@ external-link-foreground-hover:
|
||||
external-link-foreground-visited: #7c318c
|
||||
external-link-foreground: #9e3eb3
|
||||
foreground: rgba(255, 255, 255, 0.7)
|
||||
highlight-background: #ffff78
|
||||
highlight-foreground: #000000
|
||||
message-background: <<colour background>>
|
||||
message-border: <<colour very-muted-foreground>>
|
||||
message-foreground: rgba(255, 255, 255, 0.54)
|
||||
|
||||
@@ -43,6 +43,8 @@ external-link-foreground: rgb(179, 179, 255)
|
||||
external-link-foreground-hover: inherit
|
||||
external-link-foreground-visited: rgb(153, 153, 255)
|
||||
foreground: rgb(179, 179, 179)
|
||||
highlight-background: #ffff78
|
||||
highlight-foreground: #000000
|
||||
message-background: <<colour tag-foreground>>
|
||||
message-border: #96ccff
|
||||
message-foreground: <<colour tag-background>>
|
||||
|
||||
@@ -42,6 +42,8 @@ external-link-foreground-hover: inherit
|
||||
external-link-foreground-visited: #0000aa
|
||||
external-link-foreground: #0000ee
|
||||
foreground: #333333
|
||||
highlight-background: #ffff00
|
||||
highlight-foreground: #000000
|
||||
message-background: #ecf2ff
|
||||
message-border: #cfd6e6
|
||||
message-foreground: #547599
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
title: $:/core/templates/server/static.sidebar.wikitext
|
||||
|
||||
\whitespace trim
|
||||
<div class="tc-sidebar-scrollable" style="overflow: auto;">
|
||||
<div class="tc-sidebar-scrollable" style="overflow: auto;" role="region" aria-label={{$:/language/SideBar/Caption}}>
|
||||
<div class="tc-sidebar-header">
|
||||
<h1 class="tc-site-title">
|
||||
<$transclude tiddler="$:/SiteTitle"/>
|
||||
|
||||
@@ -19,8 +19,8 @@ title: $:/core/templates/server/static.tiddler.html
|
||||
</head>
|
||||
<body class="tc-body">
|
||||
<$transclude tiddler="$:/core/templates/server/static.sidebar.wikitext" mode="inline"/>
|
||||
<section class="tc-story-river">
|
||||
<div class="tc-tiddler-frame">
|
||||
<section class="tc-story-river" role="main">
|
||||
<div class="tc-tiddler-frame" role="article">
|
||||
<$transclude tiddler="$:/core/templates/server/static.tiddler.wikitext" mode="inline"/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -18,7 +18,7 @@ tc-page-container tc-page-view-$(storyviewTitle)$ tc-language-$(languageTitle)$
|
||||
|
||||
<$navigator story="$:/StoryList" history="$:/HistoryList">
|
||||
|
||||
<$transclude mode="block"/>
|
||||
<$transclude tiddler="$:/core/ui/ViewTemplate/body" mode="block"/>
|
||||
|
||||
</$navigator>
|
||||
|
||||
|
||||
@@ -2,11 +2,5 @@ title: $:/core/ui/Actions/new-image
|
||||
tags: $:/tags/Actions
|
||||
description: create a new image tiddler
|
||||
|
||||
\define get-type()
|
||||
image/$(imageType)$
|
||||
\end
|
||||
\define get-tags() $(textFieldTags)$ $(tagsFieldTags)$
|
||||
\whitespace trim
|
||||
<$vars imageType={{$:/config/NewImageType}} textFieldTags={{$:/config/NewJournal/Tags}} tagsFieldTags={{$:/config/NewJournal/Tags!!tags}}>
|
||||
<$action-sendmessage $message="tm-new-tiddler" type=<<get-type>> tags=<<get-tags>>/>
|
||||
</$vars>
|
||||
<$action-sendmessage $message="tm-new-tiddler" type={{{ [{$:/config/NewImageType}addprefix[image/]] }}}/>
|
||||
|
||||
@@ -3,7 +3,7 @@ tags: $:/tags/AdvancedSearch/FilterButton
|
||||
|
||||
\whitespace trim
|
||||
<$reveal state="$:/temp/advancedsearch" type="nomatch" text="">
|
||||
<$button popup=<<qualify "$:/state/filterDeleteDropdown">> class="tc-btn-invisible">
|
||||
<$button tooltip={{$:/language/Buttons/DeleteTiddlers/Hint}} popup=<<qualify "$:/state/filterDeleteDropdown">> class="tc-btn-invisible">
|
||||
{{$:/core/images/delete-button}}
|
||||
</$button>
|
||||
</$reveal>
|
||||
@@ -13,13 +13,13 @@ tags: $:/tags/AdvancedSearch/FilterButton
|
||||
<div class="tc-block-dropdown tc-edit-type-dropdown">
|
||||
<div class="tc-dropdown-item-plain">
|
||||
<$set name="resultCount" value="""<$count filter={{$:/temp/advancedsearch}}/>""">
|
||||
Are you sure you wish to delete <<resultCount>> tiddler(s)?
|
||||
{{$:/language/ConfirmDeleteTiddlers}}
|
||||
</$set>
|
||||
</div>
|
||||
<div class="tc-dropdown-item-plain">
|
||||
<$button class="tc-btn">
|
||||
<$action-deletetiddler $filter={{$:/temp/advancedsearch}}/>
|
||||
Delete these tiddlers
|
||||
{{$:/language/Buttons/DeleteTiddlers/Hint}}
|
||||
</$button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -15,7 +15,7 @@ tags: $:/tags/AdvancedSearch/FilterButton
|
||||
<div class="tc-block-dropdown-wrapper">
|
||||
<div class="tc-block-dropdown tc-edit-type-dropdown">
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/Filter]]">
|
||||
<$link to={{!!filter}}><$transclude field="description"/></$link>
|
||||
<$link to={{!!filter}}><$let tv-wikilinks="no"><$transclude field="description"/></$let></$link>
|
||||
</$list>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -23,7 +23,9 @@ title: $:/core/ui/EditTemplate
|
||||
<div
|
||||
data-tiddler-title=<<currentTiddler>>
|
||||
data-tags={{!!tags}}
|
||||
class={{{ tc-tiddler-frame tc-tiddler-edit-frame [<currentTiddler>is[tiddler]then[tc-tiddler-exists]] [<currentTiddler>is[missing]!is[shadow]then[tc-tiddler-missing]] [<currentTiddler>is[shadow]then[tc-tiddler-exists tc-tiddler-shadow]] [<currentTiddler>is[system]then[tc-tiddler-system]] [{!!class}] [<currentTiddler>tags[]encodeuricomponent[]addprefix[tc-tagged-]] +[join[ ]] }}}>
|
||||
class={{{ [all[shadows+tiddlers]tag[$:/tags/ClassFilters/TiddlerTemplate]!is[draft]] :map:flat[subfilter{!!text}] tc-tiddler-frame tc-tiddler-edit-frame [<currentTiddler>is[tiddler]then[tc-tiddler-exists]] [<currentTiddler>is[missing]!is[shadow]then[tc-tiddler-missing]] [<currentTiddler>is[shadow]then[tc-tiddler-exists tc-tiddler-shadow]] [<currentTiddler>is[system]then[tc-tiddler-system]] [{!!class}] [<currentTiddler>tags[]encodeuricomponent[]addprefix[tc-tagged-]] +[join[ ]] }}}
|
||||
role="region"
|
||||
aria-label={{$:/language/EditTemplate/Caption}}>
|
||||
<$fieldmangler>
|
||||
<$vars
|
||||
storyTiddler=<<currentTiddler>>
|
||||
|
||||
@@ -5,6 +5,6 @@ caption: {{$:/language/EditTemplate/Body/Preview/Type/Output}}
|
||||
\import [all[shadows+tiddlers]tag[$:/tags/Macro/View]!has[draft.of]] [all[shadows+tiddlers]tag[$:/tags/Macro/View/Body]!has[draft.of]]
|
||||
<$set name="tv-tiddler-preview" value="yes">
|
||||
|
||||
<$transclude />
|
||||
<$transclude tiddler={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/ViewTemplateBodyFilter]!is[draft]get[text]] :and[!is[blank]else[$:/core/ui/ViewTemplate/body/default]] }}} />
|
||||
|
||||
</$set>
|
||||
|
||||
@@ -3,9 +3,6 @@ name: {{$:/language/PageTemplate/Name}}
|
||||
description: {{$:/language/PageTemplate/Description}}
|
||||
|
||||
\whitespace trim
|
||||
\define containerClasses()
|
||||
tc-page-container tc-page-view-$(storyviewTitle)$ tc-language-$(languageTitle)$
|
||||
\end
|
||||
\import [[$:/core/ui/PageMacros]] [all[shadows+tiddlers]tag[$:/tags/Macro]!has[draft.of]]
|
||||
|
||||
<$vars
|
||||
@@ -17,7 +14,7 @@ tc-page-container tc-page-view-$(storyviewTitle)$ tc-language-$(languageTitle)$
|
||||
storyviewTitle={{$:/view}}
|
||||
languageTitle={{{ [{$:/language}get[name]] }}}>
|
||||
|
||||
<div class=<<containerClasses>>>
|
||||
<div class={{{ [all[shadows+tiddlers]tag[$:/tags/ClassFilters/PageTemplate]!is[draft]] :map:flat[subfilter{!!text}] tc-page-container [[tc-page-view-]addsuffix<storyviewTitle>] [[tc-language-]addsuffix<languageTitle>] :and[unique[]join[ ]] }}} >
|
||||
|
||||
<$navigator story="$:/StoryList" history="$:/HistoryList" openLinkFromInsideRiver={{$:/config/Navigation/openLinkFromInsideRiver}} openLinkFromOutsideRiver={{$:/config/Navigation/openLinkFromOutsideRiver}} relinkOnRename={{$:/config/RelinkOnRename}}>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ title: $:/core/ui/PageTemplate/story
|
||||
tags: $:/tags/PageTemplate
|
||||
|
||||
\whitespace trim
|
||||
<section class="tc-story-river">
|
||||
<section class="tc-story-river" role="main">
|
||||
|
||||
<section class="story-backdrop">
|
||||
|
||||
|
||||
@@ -51,12 +51,14 @@ tags: $:/tags/SideBarSegment
|
||||
<$keyboard key="((input-tab-right))" actions=<<set-next-input-tab>>>
|
||||
<$keyboard key="((input-tab-left))" actions=<<set-next-input-tab "before">>>
|
||||
<$keyboard key="((advanced-search-sidebar))" actions=<<advanced-search-actions>>>
|
||||
<form class="tc-form-inline">
|
||||
<$macrocall $name="keyboard-driven-input" tiddler=<<editTiddler>> storeTitle=<<searchTiddler>>
|
||||
selectionStateTitle=<<searchListState>> refreshTitle="$:/temp/search/refresh" type="search"
|
||||
tag="input" focus={{$:/config/Search/AutoFocus}} focusPopup=<<qualify "$:/state/popup/search-dropdown">>
|
||||
class="tc-popup-handle" filterMinLength={{$:/config/Search/MinLength}} inputCancelActions=<<cancel-search-actions>>
|
||||
inputAcceptActions=<<input-accept-actions>> inputAcceptVariantActions=<<input-accept-variant-actions>> cancelPopups="yes"
|
||||
configTiddlerFilter="[[$:/state/search/currentTab]!is[missing]get[text]] ~[{$:/config/SearchResults/Default}]"/>
|
||||
</form>
|
||||
</$keyboard>
|
||||
</$keyboard>
|
||||
</$keyboard>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
title: $:/core/ui/SideBarSegments/tabs
|
||||
tags: $:/tags/SideBarSegment
|
||||
|
||||
<div class="tc-sidebar-lists tc-sidebar-tabs">
|
||||
<div class="tc-sidebar-lists tc-sidebar-tabs" role="region" aria-label={{$:/language/SideBar/Caption}}>
|
||||
|
||||
<$macrocall $name="tabs" tabsList="[all[shadows+tiddlers]tag[$:/tags/SideBar]!has[draft.of]]" default={{$:/config/DefaultSidebarTab}} state="$:/state/tab/sidebar" class="tc-sidebar-tabs-main" explicitState="$:/state/tab/sidebar--595412856"/>
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ $:/state/folded/$(currentTiddler)$
|
||||
\define cancel-delete-tiddler-actions(message) <$action-sendmessage $message="tm-$message$-tiddler"/>
|
||||
\import [all[shadows+tiddlers]tag[$:/tags/Macro/View]!has[draft.of]]
|
||||
<$vars storyTiddler=<<currentTiddler>> tiddlerInfoState=<<qualify "$:/state/popup/tiddler-info">>>
|
||||
<div data-tiddler-title=<<currentTiddler>> data-tags={{!!tags}} class={{{ tc-tiddler-frame tc-tiddler-view-frame [<currentTiddler>is[tiddler]then[tc-tiddler-exists]] [<currentTiddler>is[missing]!is[shadow]then[tc-tiddler-missing]] [<currentTiddler>is[shadow]then[tc-tiddler-exists tc-tiddler-shadow]] [<currentTiddler>is[shadow]is[tiddler]then[tc-tiddler-overridden-shadow]] [<currentTiddler>is[system]then[tc-tiddler-system]] [{!!class}] [<currentTiddler>tags[]encodeuricomponent[]addprefix[tc-tagged-]] +[join[ ]] }}}>
|
||||
<div data-tiddler-title=<<currentTiddler>> data-tags={{!!tags}} class={{{ [all[shadows+tiddlers]tag[$:/tags/ClassFilters/TiddlerTemplate]!is[draft]] :map:flat[subfilter{!!text}] tc-tiddler-frame tc-tiddler-view-frame [<currentTiddler>is[tiddler]then[tc-tiddler-exists]] [<currentTiddler>is[missing]!is[shadow]then[tc-tiddler-missing]] [<currentTiddler>is[shadow]then[tc-tiddler-exists tc-tiddler-shadow]] [<currentTiddler>is[shadow]is[tiddler]then[tc-tiddler-overridden-shadow]] [<currentTiddler>is[system]then[tc-tiddler-system]] [{!!class}] [<currentTiddler>tags[]encodeuricomponent[]addprefix[tc-tagged-]] +[join[ ]] }}} role="article">
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/ViewTemplate]!has[draft.of]]" variable="listItem">
|
||||
<$transclude tiddler=<<listItem>>/>
|
||||
</$list>
|
||||
|
||||
7
core/ui/ViewTemplate/body/rendered-plain-text.tid
Normal file
7
core/ui/ViewTemplate/body/rendered-plain-text.tid
Normal file
@@ -0,0 +1,7 @@
|
||||
title: $:/core/ui/ViewTemplate/body/rendered-plain-text
|
||||
code-body: yes
|
||||
|
||||
\whitespace trim
|
||||
<$wikify name="text" text={{!!text}} type={{!!type}}>
|
||||
<$codeblock code=<<text>> language="css"/>
|
||||
</$wikify>
|
||||
@@ -4,7 +4,11 @@ tags: $:/tags/ViewTemplate
|
||||
\whitespace trim
|
||||
<$reveal type="nomatch" stateTitle=<<folded-state>> text="hide" tag="div" retain="yes" animate="yes">
|
||||
<div class="tc-subtitle">
|
||||
<$link to={{!!modifier}} />
|
||||
<$view field="modified" format="date" template={{$:/language/Tiddler/DateFormat}}/>
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/ViewTemplate/Subtitle]!has[draft.of]]" variable="subtitleTiddler" counter="indexSubtitleTiddler">
|
||||
<$list filter="[<indexSubtitleTiddler-first>match[no]]" variable="ignore">
|
||||
|
||||
</$list>
|
||||
<$transclude tiddler=<<subtitleTiddler>> mode="inline"/>
|
||||
</$list>
|
||||
</div>
|
||||
</$reveal>
|
||||
|
||||
4
core/ui/ViewTemplate/subtitle/modified.tid
Normal file
4
core/ui/ViewTemplate/subtitle/modified.tid
Normal file
@@ -0,0 +1,4 @@
|
||||
title: $:/core/ui/ViewTemplate/subtitle/modified
|
||||
tags: $:/tags/ViewTemplate/Subtitle
|
||||
|
||||
<$view field="modified" format="date" template={{$:/language/Tiddler/DateFormat}}/>
|
||||
4
core/ui/ViewTemplate/subtitle/modifier.tid
Normal file
4
core/ui/ViewTemplate/subtitle/modifier.tid
Normal file
@@ -0,0 +1,4 @@
|
||||
title: $:/core/ui/ViewTemplate/subtitle/modifier
|
||||
tags: $:/tags/ViewTemplate/Subtitle
|
||||
|
||||
<$link to={{!!modifier}}/>
|
||||
@@ -1,6 +1,6 @@
|
||||
title: $:/config/OfficialPluginLibrary
|
||||
tags: $:/tags/PluginLibrary
|
||||
url: https://tiddlywiki.com/library/v5.2.3/index.html
|
||||
url: https://tiddlywiki.com/library/v5.2.4/index.html
|
||||
caption: {{$:/language/OfficialPluginLibrary}}
|
||||
|
||||
{{$:/language/OfficialPluginLibrary/Hint}}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
title: $:/config/ViewTemplateBodyFilters/
|
||||
tags: $:/tags/ViewTemplateBodyFilter
|
||||
|
||||
stylesheet: [tag[$:/tags/Stylesheet]then[$:/core/ui/ViewTemplate/body/rendered-plain-text]]
|
||||
system: [prefix[$:/boot/]] [prefix[$:/config/]] [prefix[$:/core/macros]] [prefix[$:/core/save/]] [prefix[$:/core/templates/]] [prefix[$:/core/ui/]split[/]count[]compare:number:eq[4]] [prefix[$:/info/]] [prefix[$:/language/]] [prefix[$:/languages/]] [prefix[$:/snippets/]] [prefix[$:/state/]] [prefix[$:/status/]] [prefix[$:/info/]] [prefix[$:/temp/]] +[!is[image]limit[1]then[$:/core/ui/ViewTemplate/body/code]]
|
||||
code-body: [field:code-body[yes]then[$:/core/ui/ViewTemplate/body/code]]
|
||||
import: [field:plugin-type[import]then[$:/core/ui/ViewTemplate/body/import]]
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
title: $:/core/macros/list
|
||||
tags: $:/tags/Macro
|
||||
|
||||
\define list-links(filter,type:"ul",subtype:"li",class:"",emptyMessage)
|
||||
\define list-links(filter,type:"ul",subtype:"li",class:"",emptyMessage,field:"caption")
|
||||
\whitespace trim
|
||||
<$type$ class="$class$">
|
||||
<$list filter="$filter$" emptyMessage=<<__emptyMessage__>>>
|
||||
<$subtype$>
|
||||
<$genesis $type=<<__type__>> class=<<__class__>>>
|
||||
<$list filter=<<__filter__>> emptyMessage=<<__emptyMessage__>>>
|
||||
<$genesis $type=<<__subtype__>>>
|
||||
<$link to={{!!title}}>
|
||||
<$let tv-wikilinks="no">
|
||||
<$transclude field="caption">
|
||||
<$transclude field=<<__field__>>>
|
||||
<$view field="title"/>
|
||||
</$transclude>
|
||||
</$let>
|
||||
</$link>
|
||||
</$subtype$>
|
||||
</$genesis>
|
||||
</$list>
|
||||
</$type$>
|
||||
</$genesis>
|
||||
\end
|
||||
|
||||
\define list-links-draggable-drop-actions()
|
||||
<$action-listops $tiddler=<<targetTiddler>> $field=<<targetField>> $subfilter="+[insertbefore<actionTiddler>,<currentTiddler>]"/>
|
||||
\end
|
||||
|
||||
\define list-links-draggable(tiddler,field:"list",type:"ul",subtype:"li",class:"",itemTemplate)
|
||||
\define list-links-draggable(tiddler,field:"list",emptyMessage,type:"ul",subtype:"li",class:"",itemTemplate)
|
||||
\whitespace trim
|
||||
<span class="tc-links-draggable-list">
|
||||
<$vars targetTiddler="""$tiddler$""" targetField="""$field$""">
|
||||
<$type$ class="$class$">
|
||||
<$list filter="[list[$tiddler$!!$field$]]">
|
||||
<$list filter="[list[$tiddler$!!$field$]]" emptyMessage=<<__emptyMessage__>>>
|
||||
<$droppable actions=<<list-links-draggable-drop-actions>> tag="""$subtype$""" enable=<<tv-enable-drag-and-drop>>>
|
||||
<div class="tc-droppable-placeholder"/>
|
||||
<div>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
title: $:/core/macros/tabs
|
||||
tags: $:/tags/Macro
|
||||
code_body: yes
|
||||
code-body: yes
|
||||
|
||||
\define tabs-button()
|
||||
\whitespace trim
|
||||
<$button set=<<tabsState>> setTo=<<currentTab>> default=<<__default__>> selectedClass="tc-tab-selected" tooltip={{!!tooltip}}>
|
||||
<$button set=<<tabsState>> setTo=<<currentTab>> default=<<__default__>> selectedClass="tc-tab-selected" tooltip={{!!tooltip}} role="switch">
|
||||
<$tiddler tiddler=<<save-currentTiddler>>>
|
||||
<$set name="tv-wikilinks" value="no">
|
||||
<$transclude tiddler=<<__buttonTemplate__>> mode="inline">
|
||||
@@ -48,7 +48,7 @@ code_body: yes
|
||||
\define tabs(tabsList,default,state:"$:/state/tab",class,template,buttonTemplate,retain,actions,explicitState)
|
||||
\whitespace trim
|
||||
<$qualify title=<<__state__>> name="qualifiedState">
|
||||
<$set name="tabsState" filter={{{ [<__explicitState__>minlength[1]] ~[<qualifiedState>] }}}>
|
||||
<$let tabsState={{{ [<__explicitState__>minlength[1]] ~[<qualifiedState>] }}}>
|
||||
<div class={{{ [[tc-tab-set]addsuffix[ ]addsuffix<__class__>] }}}>
|
||||
<div class={{{ [[tc-tab-buttons]addsuffix[ ]addsuffix<__class__>] }}}>
|
||||
<<tabs-tab-list>>
|
||||
@@ -58,6 +58,6 @@ code_body: yes
|
||||
<<tabs-tab-body>>
|
||||
</div>
|
||||
</div>
|
||||
</$set>
|
||||
</$let>
|
||||
</$qualify>
|
||||
\end
|
||||
|
||||
@@ -11,7 +11,7 @@ second-search-filter: [tags[]is[system]search:title<userInput>sort[]]
|
||||
\whitespace trim
|
||||
<$set name="tag" value={{{ [<__tiddler__>get[text]] }}}>
|
||||
<$list filter="[<saveTiddler>!contains:$tagField$<tag>!match[]]" variable="ignore" emptyMessage="<$action-listops $tiddler=<<saveTiddler>> $field=<<__tagField__>> $subfilter='-[<tag>]'/>">
|
||||
<$action-listops $tiddler=<<saveTiddler>> $field=<<__tagField__>> $subfilter="[<tag>]"/>
|
||||
<$action-listops $tiddler=<<saveTiddler>> $field=<<__tagField__>> $subfilter="[<tag>trim[]]"/>
|
||||
$actions$
|
||||
</$list>
|
||||
</$set>
|
||||
@@ -52,7 +52,7 @@ $actions$
|
||||
</span><$button popup=<<qualify "$:/state/popup/tags-auto-complete">> class="tc-btn-invisible tc-btn-dropdown" tooltip={{$:/language/EditTemplate/Tags/Dropdown/Hint}} aria-label={{$:/language/EditTemplate/Tags/Dropdown/Caption}}>{{$:/core/images/down-arrow}}</$button><$reveal state=<<storeTitle>> type="nomatch" text=""><$button class="tc-btn-invisible tc-small-gap tc-btn-dropdown" tooltip={{$:/language/EditTemplate/Tags/ClearInput/Hint}} aria-label={{$:/language/EditTemplate/Tags/ClearInput/Caption}}>{{$:/core/images/close-button}}<<delete-tag-state-tiddlers>></$button></$reveal><span class="tc-add-tag-button tc-small-gap-left">
|
||||
<$set name="tag" value={{{ [<newTagNameTiddler>get[text]] }}}>
|
||||
<$button set=<<newTagNameTiddler>> setTo="" class="">
|
||||
<$action-listops $tiddler=<<saveTiddler>> $field=<<__tagField__>> $subfilter="[<tag>]"/>
|
||||
<$action-listops $tiddler=<<saveTiddler>> $field=<<__tagField__>> $subfilter="[<tag>trim[]]"/>
|
||||
$actions$
|
||||
<$set name="currentTiddlerCSSEscaped" value={{{ [<saveTiddler>escapecss[]] }}}>
|
||||
<<delete-tag-state-tiddlers>><$action-sendmessage $message="tm-focus-selector" $param=<<get-tagpicker-focus-selector>>/>
|
||||
|
||||
@@ -16,7 +16,7 @@ color:$(foregroundColor)$;
|
||||
$element-attributes$
|
||||
class="tc-tag-label tc-btn-invisible"
|
||||
style=<<tag-pill-styles>>
|
||||
>$actions$<$transclude tiddler="""$icon$"""/><$view tiddler=<<__tag__>> field="title" format="text" />
|
||||
>$actions$<$transclude tiddler="""$icon$"""/><$view tiddler=<<__tag__>> field="title" format="text" /></$element-tag$>
|
||||
\end
|
||||
|
||||
\define tag-pill-body(tag,icon,colour,palette,element-tag,element-attributes,actions)
|
||||
|
||||
@@ -3,11 +3,13 @@ tags: $:/tags/Macro
|
||||
|
||||
\define toc-caption()
|
||||
\whitespace trim
|
||||
<span class="tc-toc-caption tc-tiny-gap-left">
|
||||
<$set name="tv-wikilinks" value="no">
|
||||
<$transclude field="caption">
|
||||
<$view field="title"/>
|
||||
</$transclude>
|
||||
</$set>
|
||||
</span>
|
||||
\end
|
||||
|
||||
\define toc-body(tag,sort:"",itemClassFilter,exclude,path)
|
||||
@@ -51,7 +53,6 @@ tags: $:/tags/Macro
|
||||
{{$:/core/images/down-arrow}}
|
||||
</$button>
|
||||
</$reveal>
|
||||
 
|
||||
<<toc-caption>>
|
||||
</$link>
|
||||
<$reveal type="match" stateTitle=<<toc-state>> text="open">
|
||||
@@ -71,14 +72,12 @@ tags: $:/tags/Macro
|
||||
<$reveal type="nomatch" stateTitle=<<toc-state>> text="open">
|
||||
<$button setTitle=<<toc-state>> setTo="open" class="tc-btn-invisible tc-popup-keep">
|
||||
{{$:/core/images/right-arrow}}
|
||||
 
|
||||
<<toc-caption>>
|
||||
</$button>
|
||||
</$reveal>
|
||||
<$reveal type="match" stateTitle=<<toc-state>> text="open">
|
||||
<$button setTitle=<<toc-state>> setTo="close" class="tc-btn-invisible tc-popup-keep">
|
||||
{{$:/core/images/down-arrow}}
|
||||
 
|
||||
<<toc-caption>>
|
||||
</$button>
|
||||
</$reveal>
|
||||
@@ -127,7 +126,6 @@ tags: $:/tags/Macro
|
||||
</$button>
|
||||
</$reveal>
|
||||
</$list>
|
||||
 
|
||||
<<toc-caption>>
|
||||
</$link>
|
||||
<$reveal type="match" stateTitle=<<toc-state>> text="open">
|
||||
@@ -147,14 +145,12 @@ tags: $:/tags/Macro
|
||||
<$reveal type="nomatch" stateTitle=<<toc-state>> text="open">
|
||||
<$button setTitle=<<toc-state>> setTo="open" class="tc-btn-invisible tc-popup-keep">
|
||||
{{$:/core/images/right-arrow}}
|
||||
 
|
||||
<<toc-caption>>
|
||||
</$button>
|
||||
</$reveal>
|
||||
<$reveal type="match" stateTitle=<<toc-state>> text="open">
|
||||
<$button setTitle=<<toc-state>> setTo="close" class="tc-btn-invisible tc-popup-keep">
|
||||
{{$:/core/images/down-arrow}}
|
||||
 
|
||||
<<toc-caption>>
|
||||
</$button>
|
||||
</$reveal>
|
||||
|
||||
@@ -23,11 +23,7 @@ title: $:/snippets/peek-stylesheets
|
||||
<$reveal type="match" state=<<state>> text="yes" tag="div">
|
||||
<$set name="source" tiddler=<<currentTiddler>>>
|
||||
<$wikify name="styles" text=<<source>>>
|
||||
<pre>
|
||||
<code>
|
||||
<$text text=<<styles>>/>
|
||||
</code>
|
||||
</pre>
|
||||
<$codeblock code=<<styles>> language="css"/>
|
||||
</$wikify>
|
||||
</$set>
|
||||
</$reveal>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
title: $:/tags/ViewTemplateBodyFilter
|
||||
list: $:/config/ViewTemplateBodyFilters/system $:/config/ViewTemplateBodyFilters/code-body $:/config/ViewTemplateBodyFilters/import $:/config/ViewTemplateBodyFilters/plugin $:/config/ViewTemplateBodyFilters/hide-body $:/config/ViewTemplateBodyFilters/default
|
||||
list: $:/config/ViewTemplateBodyFilters/hide-body $:/config/ViewTemplateBodyFilters/code-body $:/config/ViewTemplateBodyFilters/stylesheet $:/config/ViewTemplateBodyFilters/system $:/config/ViewTemplateBodyFilters/import $:/config/ViewTemplateBodyFilters/plugin $:/config/ViewTemplateBodyFilters/default
|
||||
|
||||
|
||||
2
core/wiki/tags/ViewTemplateSubtitle.tid
Normal file
2
core/wiki/tags/ViewTemplateSubtitle.tid
Normal file
@@ -0,0 +1,2 @@
|
||||
title: $:/tags/ViewTemplate/Subtitle
|
||||
list: $:/core/ui/ViewTemplate/subtitle/modifier $:/core/ui/ViewTemplate/subtitle/modified
|
||||
@@ -1,5 +1,5 @@
|
||||
created: 20190115173333457
|
||||
modified: 20190115173723915
|
||||
modified: 20221029175754753
|
||||
tags: TableOfContents
|
||||
title: HelloThere
|
||||
type: text/vnd.tiddlywiki
|
||||
@@ -15,6 +15,7 @@ Welcome to the developer documentation for TiddlyWiki (https://tiddlywiki.com/).
|
||||
** [[Using ES2016 for Writing Plugins]]
|
||||
** [[Adding Babel Polyfill to TiddlyWiki]]
|
||||
** [[TiddlyWiki Drag and Drop Interoperability]]
|
||||
** [[Javascript Widget Tutorial]]
|
||||
* The original developer documentation from https://tiddlywiki.com:
|
||||
** [[TiddlyWiki for Developers]]
|
||||
** [[TiddlyWiki Coding Style Guidelines]]
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
created: 20190202160512541
|
||||
modified: 20190222231130254
|
||||
title: Child widgets tutorial
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
\define showTrees(wikitext)
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>wiki text</th><th>html</th><th>renders as</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`$wikitext$`</td>
|
||||
<td>
|
||||
<$wikify name=html text="""$wikitext$""" output=html mode=inline>
|
||||
<$text text=<<html>>/>
|
||||
</$wikify>
|
||||
</td>
|
||||
<td>$wikitext$</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>parse tree</th><th>widget tree</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="vertical-align: text-top">
|
||||
<pre><code>
|
||||
<$wikify name=parsetree text="""$wikitext$""" output=parsetree mode=inline>
|
||||
<<parsetree>>
|
||||
</$wikify>
|
||||
</code></pre>
|
||||
</td>
|
||||
<td style="vertical-align: text-top">
|
||||
<pre><code>
|
||||
<$wikify name=widgettree text="""$wikitext$""" output=widgettree mode=inline>
|
||||
<<widgettree>>
|
||||
</$wikify>
|
||||
</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
\end
|
||||
|
||||
! Introduction
|
||||
|
||||
Until now the examples have covered only simple, leaf widgets, but widgets can be arranged into a hierarchy. Compared to a leaf-only widget, widget classes which support having children must contain code to instantiate the children.
|
||||
|
||||
Not all widgets need to support having children. Widgets whose only purpose is to integrate third party javascript libraries, for example may not need it.
|
||||
|
||||
! wiki text ⇨ parse tree ⇨ widget tree ⇨ DOM tree
|
||||
|
||||
# [[wiki text|https://tiddlywiki.com/#WikiText]] - Users write content in tiddlers using wiki text.
|
||||
# [[parse tree|https://tiddlywiki.com/dev/#ParsingMechanism]] - A parse tree is a JSON data structure describing the wiki text. Wiki text can be converted into a parse tree using `this.wiki.parseText`.
|
||||
# ''widget tree'' - Most items in the parse tree correspond to one or more items in the widget tree. The `this.makeChildWidgets` method is used to convert the parse tree into a widget tree.
|
||||
# [[DOM tree|https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction]] - A DOM tree is a standard javascript datastructure used by browsers to display a web page. The `this.renderChildren` method is used to instantiate the widget class and then render each widget in the widget tree. If a given widget will be visible in the browser, then one or more DOM nodes will be created.
|
||||
|
||||
!Examples
|
||||
|
||||
!! Simple trees without nesting
|
||||
|
||||
[[Widgets in wiki text|https://tiddlywiki.com/#Widgets%20in%20WikiText]] have a syntax similar to html (i.e. `<$list/>`). But all [[wiki markup|https://tiddlywiki.com/#WikiText]] is seen by the tiddlywiki code as widgets.
|
||||
|
||||
Even a simple string with no special syntax will be treated as a widget. In this case a widget of type `text`:
|
||||
|
||||
<<showTrees """hello""">>
|
||||
|
||||
The above bare string of text is mostly just a synonym for this widget syntax:
|
||||
|
||||
<<showTrees """<$text text=hello/>""">>
|
||||
|
||||
Some of the details of the parseTree and widgetTree are different in the two examples, but the general structure is the same and the rendered output is the same.
|
||||
|
||||
In these two simple examples, there is no nesting and so no child widgets are created.
|
||||
|
||||
!! Trees with one level of nesting
|
||||
|
||||
This next example shows the structure for bold wiki syntax. It is still simple, but does introduce one level of nesting: `element`→`text`
|
||||
|
||||
The wiki syntax for bold converts to the standard html element `strong`. Any standard html element is represented in tiddlywiki as a widget of type `element`:
|
||||
|
||||
<<showTrees """''bold''""">>
|
||||
|
||||
Another example showing one level of nesting (`link`→`text`):
|
||||
|
||||
<<showTrees """<$link to=atiddler>link</$link>""">>
|
||||
|
||||
!!Widgets with no DOM contribution
|
||||
Not all widgets contribute items to the DOM. The purpose of some widgets is to affect the display of descendant widgets by changing some state. The `$set` widget for example sets a variable which will be accessible to the descendant widgets:
|
||||
|
||||
<<showTrees """<$set name=myvar value=hi/>""">>
|
||||
|
||||
Nothing is rendered and there is no html, but the parse tree and widget tree contain information about the variable.
|
||||
|
||||
!! Dynamic widget children using this.wiki.parseText
|
||||
|
||||
In all the examples so far, there has been a close mapping between the nesting structure of the parse tree and the widget tree. If the item is in the parse tree, then it is in the widget tree. If the parse tree item has children, then the widget tree has the same number of children.
|
||||
|
||||
However, there are several examples of widgets in which more levels of nesting are created dynamically during the widget rendering process
|
||||
|
||||
The `$macrocall` widget is one example:
|
||||
|
||||
<<showTrees """<$macrocall $name=now/>""" >>
|
||||
|
||||
The parse tree has just a single type=$macrocall element with no children. The widget tree has that same type=$macrocall element, but it also has a child widget which wasn't in the parse tree.
|
||||
|
||||
In all cases, the `$macrocall` widget calls the given macro and then calls `this.wiki.parseText` on the output. This results in a new parse tree which is used to make the child widgets.
|
||||
|
||||
In this particular case, the `now` macro is called. It returns a simple string of text, so when it is parsed the result causes the creation of a single child text widget containing the current date and time.
|
||||
|
||||
!! Widgets which do not support nesting
|
||||
|
||||
Just as some widgets can cause widget trees to have more nesting than the parse tree, some widgets can cause widget trees to have less nesting.
|
||||
|
||||
This happens when there is no use for the widget to have any children. The `$text` widget, for example, has no use for displaying any descendants.
|
||||
|
||||
This behavior is accomplished by not calling the `makeChildWidgets` method. Without that method call, the child widgets are not created from the child parse tree items. For example:
|
||||
|
||||
<$macrocall $name=showTrees wikitext="""<$text text="hi">ignored child text</$text>"""/>
|
||||
|
||||
Since the `$text` widget does not have a call to `makeChildWidgets`, 'ignored child text' above is present in the parse tree, but not in the widget tree.
|
||||
|
||||
!Reference
|
||||
|
||||
|!method|!when to call|!what it does|
|
||||
|`makeChildWidgets`|directly or indirectly from `render` method|converts child parse tree items into widget tree items|
|
||||
|`renderChildren`|directly or indirectly from `render` method, after the `makeChildWidgets` call|calls the `render` method of the child widget|
|
||||
|`refreshChildren`|directly or indirectly from `refresh` method, only needed if `refreshSelf` is not called|calls the `refresh` method of of the child widgets so they can check if refresh is needed|
|
||||
|`this.wiki.parseText`|pass the output parse tree to `makeChildWidgets`|converts the given text to a parse tree...only needed for dynamically constructed parsetree|
|
||||
|
||||
|!example call|!purpose|!widgets using this approach|
|
||||
|`this.makeChildWidgets()`|construct child widgets from the static parse tree|[[$link|$:/core/modules/widgets/link.js]], [[$button|$:/core/modules/widgets/button.js]], etc.|
|
||||
|`this.makeChildWidgets(parseTreeNodes)`|construct child widgets from a dynamic parse tree|[[$list|$:/core/modules/widgets/list.js]], [[$transclude|$:/core/modules/widgets/transclude.js]], [[$macrocall|$:/core/modules/widgets/macrocall.js]], etc|
|
||||
|`this.renderChildren(parent, nextSibling)`|when the widget adds nothing to the dom, just pass the `render` arguments through to the children|[[$set|$:/core/modules/widgets/set.js]], [[$importvariables|$:/core/modules/widgets/importvariables.js]], [[$tiddler|$:/core/modules/widgets/tiddler.js]], [[$wikify|$:/core/modules/widgets/wikify.js]], etc.|
|
||||
|`this.renderChildren(domNode, null)`|passes the dom node generated by this widget into the children|[[$link|$:/core/modules/widgets/link.js]], [[$button|$:/core/modules/widgets/button.js]], etc|
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
created: 20190201120100249
|
||||
modified: 20190201222600576
|
||||
tags:
|
||||
title: Do nothing widget demo
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<!-- The innerwiki doesn't refresh on its own when tiddlers on the outside change, so use the list widget to force a dependency -->
|
||||
<$list name=refresh filter=[[donothing.js]get[text]]>
|
||||
<$innerwiki width="600" height="400" style="width:100%;">
|
||||
<$data title="$:/DefaultTiddlers" text="[[do nothing widget]]"/>
|
||||
<$data $tiddler=donothing.js/>
|
||||
<$data title="do nothing widget" text="""
|
||||
```
|
||||
<$donothing/>
|
||||
```
|
||||
|
||||
Renders as:
|
||||
|
||||
<$donothing/>
|
||||
"""/>
|
||||
</$innerwiki>
|
||||
</$list>
|
||||
@@ -0,0 +1,25 @@
|
||||
created: 20190201232102417
|
||||
modified: 20190202145547621
|
||||
tags:
|
||||
title: Do nothing widget tutorial
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
In order to define a widget in a tiddler, the tiddler must satisfy these requirements:
|
||||
|
||||
* type field is application/javascript
|
||||
* module-type field is widget
|
||||
* the text field contains the javascript code
|
||||
|
||||
The [[donothing.js]] tiddler fulfills the requirements and its code looks like this:
|
||||
{{donothing.js}}
|
||||
That code does 2 key things:
|
||||
|
||||
* Imports the core Widget class ([[$:/core/modules/widgets/widget.js]])
|
||||
* exports the class in an attribute with the name we want our widget to have (`donothing`)
|
||||
|
||||
Here's what it looks like:
|
||||
{{Do nothing widget demo}}
|
||||
And it worked. No error message this time.
|
||||
|
||||
''Exercise'': Modify [[donothing.js]] and [[Do nothing widget demo]] so the widget is named `noop` instead of `donothing`
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user