1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2026-01-26 12:53:42 +00:00

Compare commits

..

7 Commits

Author SHA1 Message Date
jeremy@jermolene.com
162e4be9f2 Docs updates 2022-05-23 09:21:12 +01:00
jeremy@jermolene.com
1ef9d11ca3 Merge branch 'master' into json-ops 2022-05-23 09:16:44 +01:00
jeremy@jermolene.com
28f1d587b6 Rename JSON operators
See https://github.com/Jermolene/TiddlyWiki5/pull/6522#issuecomment-1111206619
2022-04-27 17:35:45 +01:00
jeremy@jermolene.com
096b30f43b WIP 2022-04-27 17:28:02 +01:00
jeremy@jermolene.com
1d4418a777 Merge branch 'master' into json-ops 2022-04-27 17:27:43 +01:00
jeremy@jermolene.com
093cda65fb Merge branch 'master' into json-ops 2022-04-06 17:37:21 +01:00
jeremy@jermolene.com
5f4dc2a5fe Initial Commit 2022-03-11 10:25:16 +00:00
1147 changed files with 36121 additions and 19641 deletions

2
.gitignore vendored
View File

@@ -1,7 +1,5 @@
.DS_Store .DS_Store
.c9/ .c9/
.vscode/
tmp/ tmp/
output/ output/
node_modules/ node_modules/

View File

@@ -5,7 +5,7 @@
# Default to the current version number for building the plugin library # Default to the current version number for building the plugin library
if [ -z "$TW5_BUILD_VERSION" ]; then if [ -z "$TW5_BUILD_VERSION" ]; then
TW5_BUILD_VERSION=v5.2.8 TW5_BUILD_VERSION=v5.2.3
fi fi
echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]" echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]"
@@ -233,15 +233,6 @@ node $TW5_BUILD_TIDDLYWIKI \
--build index \ --build index \
|| exit 1 || 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 # Plugin demos
@@ -359,14 +350,14 @@ node $TW5_BUILD_TIDDLYWIKI \
# Delete any existing static content # Delete any existing static content
rm -rf $TW5_BUILD_OUTPUT/languages/de-AT/static/* rm $TW5_BUILD_OUTPUT/languages/de-AT/static/*
rm -rf $TW5_BUILD_OUTPUT/languages/de-DE/static/* rm $TW5_BUILD_OUTPUT/languages/de-DE/static/*
rm -rf $TW5_BUILD_OUTPUT/languages/es-ES/static/* rm $TW5_BUILD_OUTPUT/languages/es-ES/static/*
rm -rf $TW5_BUILD_OUTPUT/languages/fr-FR/static/* rm $TW5_BUILD_OUTPUT/languages/fr-FR/static/*
rm -rf $TW5_BUILD_OUTPUT/languages/ja-JP/static/* rm $TW5_BUILD_OUTPUT/languages/ja-JP/static/*
rm -rf $TW5_BUILD_OUTPUT/languages/ko-KR/static/* rm $TW5_BUILD_OUTPUT/languages/ko-KR/static/*
rm -rf $TW5_BUILD_OUTPUT/languages/zh-Hans/static/* rm $TW5_BUILD_OUTPUT/languages/zh-Hans/static/*
rm -rf $TW5_BUILD_OUTPUT/languages/zh-Hant/static/* rm $TW5_BUILD_OUTPUT/languages/zh-Hant/static/*
# /languages/de-AT/index.html Demo wiki with de-AT language # /languages/de-AT/index.html Demo wiki with de-AT language
# /languages/de-AT/empty.html Empty wiki with de-AT language # /languages/de-AT/empty.html Empty wiki with de-AT language
@@ -459,7 +450,7 @@ node $TW5_BUILD_TIDDLYWIKI \
--verbose \ --verbose \
--load $TW5_BUILD_OUTPUT/build.tid \ --load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/library/$TW5_BUILD_VERSION \ --output $TW5_BUILD_OUTPUT/library/$TW5_BUILD_VERSION \
--build library\ --build \
|| exit 1 || exit 1
# Delete the temporary build tiddler # Delete the temporary build tiddler

View File

@@ -2,4 +2,4 @@
# Remove any output files # Remove any output files
find . -regex "^./editions/.*/output/.*" -delete find . -regex "^./editions/[a-z0-9\.-]*/output/.*" -delete

View File

@@ -9,7 +9,6 @@ node ./tiddlywiki.js \
--verbose \ --verbose \
--version \ --version \
--rendertiddler $:/core/save/all test.html text/plain \ --rendertiddler $:/core/save/all test.html text/plain \
--test \
|| exit 1 || exit 1
echo To run the tests in a browser, open "editions/test/output/test.html" echo To run the tests in a browser, open "editions/test/output/test.html"

View File

@@ -313,7 +313,7 @@ $tw.utils.getLocationHash = function() {
var idx = href.indexOf('#'); var idx = href.indexOf('#');
if(idx === -1) { if(idx === -1) {
return "#"; return "#";
} else if(href.substr(idx + 1,1) === "#" || href.substr(idx + 1,3) === "%23") { } else if(idx < href.length-1 && href[idx+1] === '#') {
// Special case: ignore location hash if it itself starts with a # // Special case: ignore location hash if it itself starts with a #
return "#"; return "#";
} else { } else {
@@ -375,7 +375,7 @@ $tw.utils.stringifyList = function(value) {
var result = new Array(value.length); var result = new Array(value.length);
for(var t=0, l=value.length; t<l; t++) { for(var t=0, l=value.length; t<l; t++) {
var entry = value[t] || ""; var entry = value[t] || "";
if(entry.match(/[^\S\xA0]/mg)) { if(entry.indexOf(" ") !== -1) {
result[t] = "[[" + entry + "]]"; result[t] = "[[" + entry + "]]";
} else { } else {
result[t] = entry; result[t] = entry;
@@ -1230,16 +1230,13 @@ $tw.Wiki = function(options) {
this.getTiddler = function(title) { this.getTiddler = function(title) {
if(title) { if(title) {
var t = tiddlers[title]; var t = tiddlers[title];
if(t !== undefined) { if(t instanceof $tw.Tiddler) {
return t; return t;
} else { } else if(title !== undefined && shadowTiddlers[title]) {
var s = shadowTiddlers[title]; return shadowTiddlers[title].tiddler;
if(s !== undefined) {
return s.tiddler;
}
} }
return undefined;
} }
return undefined;
}; };
// Get an array of all tiddler titles // Get an array of all tiddler titles
@@ -1881,7 +1878,7 @@ A default set of files for TiddlyWiki to ignore during load.
This matches what NPM ignores, and adds "*.meta" to ignore tiddler This matches what NPM ignores, and adds "*.meta" to ignore tiddler
metadata files. metadata files.
*/ */
$tw.boot.excludeRegExp = /^\.DS_Store$|^.*\.meta$|^\..*\.swp$|^\._.*$|^\.git$|^\.github$|^\.vscode$|^\.hg$|^\.lock-wscript$|^\.svn$|^\.wafpickle-.*$|^CVS$|^npm-debug\.log$/; $tw.boot.excludeRegExp = /^\.DS_Store$|^.*\.meta$|^\..*\.swp$|^\._.*$|^\.git$|^\.hg$|^\.lock-wscript$|^\.svn$|^\.wafpickle-.*$|^CVS$|^npm-debug\.log$/;
/* /*
Load all the tiddlers recursively from a directory, including honouring `tiddlywiki.files` files for drawing in external files. Returns an array of {filepath:,type:,tiddlers: [{..fields...}],hasMetaFile:}. Note that no file information is returned for externally loaded tiddlers, just the `tiddlers` property. Load all the tiddlers recursively from a directory, including honouring `tiddlywiki.files` files for drawing in external files. Returns an array of {filepath:,type:,tiddlers: [{..fields...}],hasMetaFile:}. Note that no file information is returned for externally loaded tiddlers, just the `tiddlers` property.
@@ -2403,12 +2400,11 @@ $tw.boot.initStartup = function(options) {
$tw.utils.registerFileType("application/x-font-ttf","base64",".woff"); $tw.utils.registerFileType("application/x-font-ttf","base64",".woff");
$tw.utils.registerFileType("application/font-woff2","base64",".woff2"); $tw.utils.registerFileType("application/font-woff2","base64",".woff2");
$tw.utils.registerFileType("audio/ogg","base64",".ogg"); $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/ogg","base64",[".ogm",".ogv",".ogg"]);
$tw.utils.registerFileType("video/webm","base64",".webm"); $tw.utils.registerFileType("video/webm","base64",".webm");
$tw.utils.registerFileType("video/mp4","base64",".mp4"); $tw.utils.registerFileType("video/mp4","base64",".mp4");
$tw.utils.registerFileType("audio/mp3","base64",".mp3"); $tw.utils.registerFileType("audio/mp3","base64",".mp3");
$tw.utils.registerFileType("audio/mpeg","base64"); $tw.utils.registerFileType("audio/mp4","base64",[".mp4",".m4a"]);
$tw.utils.registerFileType("text/markdown","utf8",[".md",".markdown"],{deserializerType:"text/x-markdown"}); $tw.utils.registerFileType("text/markdown","utf8",[".md",".markdown"],{deserializerType:"text/x-markdown"});
$tw.utils.registerFileType("text/x-markdown","utf8",[".md",".markdown"]); $tw.utils.registerFileType("text/x-markdown","utf8",[".md",".markdown"]);
$tw.utils.registerFileType("application/enex+xml","utf8",".enex"); $tw.utils.registerFileType("application/enex+xml","utf8",".enex");
@@ -2420,7 +2416,7 @@ $tw.boot.initStartup = function(options) {
$tw.utils.registerFileType("application/epub+zip","base64",".epub"); $tw.utils.registerFileType("application/epub+zip","base64",".epub");
$tw.utils.registerFileType("application/octet-stream","base64",".octet-stream"); $tw.utils.registerFileType("application/octet-stream","base64",".octet-stream");
// Create the wiki store for the app // Create the wiki store for the app
$tw.wiki = new $tw.Wiki($tw.safeMode && {enableIndexers: []}); $tw.wiki = new $tw.Wiki();
// Install built in tiddler fields modules // Install built in tiddler fields modules
$tw.Tiddler.fieldModules = $tw.modules.getModulesByTypeAsHashmap("tiddlerfield"); $tw.Tiddler.fieldModules = $tw.modules.getModulesByTypeAsHashmap("tiddlerfield");
// Install the tiddler deserializer modules // Install the tiddler deserializer modules

File diff suppressed because one or more lines are too long

View File

@@ -4,7 +4,7 @@ type: text/plain
TiddlyWiki created by Jeremy Ruston, (jeremy [at] jermolene [dot] com) TiddlyWiki created by Jeremy Ruston, (jeremy [at] jermolene [dot] com)
Copyright (c) 2004-2007, Jeremy Ruston Copyright (c) 2004-2007, Jeremy Ruston
Copyright (c) 2007-2023, UnaMesa Association Copyright (c) 2007-2022, UnaMesa Association
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View File

@@ -1,4 +0,0 @@
title: $:/core/images/layout-button
tags: $:/tags/Image
<svg width="22pt" height="22pt" class="tc-image-layout-button tc-image-button" viewBox="0 0 24 24" stroke-width="1" stroke="none"><path d="M0 0h24v24H0z" fill="none"/><rect x="2" y="2" width="7" height="7" rx="2"/><rect x="2" y="13" width="7" height="9" rx="2"/><rect x="12" y="2" width="10" height="20" rx="2"/></svg>

View File

@@ -1,6 +0,0 @@
title: $:/core/images/mastodon
tags: $:/tags/Image
<svg width="22pt" height="22pt" class="tc-image-mastodon tc-image-button" viewBox="0 0 128 128">
<path d="M112.716,76.735C111.231,85.764 99.411,95.646 85.836,97.561C78.757,98.559 71.787,99.476 64.355,99.073C52.201,98.415 42.61,95.646 42.61,95.646C42.61,97.044 42.683,98.374 42.829,99.619C44.409,113.79 54.723,114.639 64.493,115.035C74.354,115.434 83.134,112.163 83.134,112.163L83.539,122.695C83.539,122.695 76.642,127.071 64.355,127.875C57.58,128.315 49.167,127.674 39.369,124.61C18.118,117.965 14.463,91.202 13.904,64.048C13.733,55.985 13.839,48.383 13.839,42.024C13.839,14.257 29.238,6.118 29.238,6.118C37.002,1.905 50.326,0.134 64.177,-0L64.517,-0C78.369,0.134 91.701,1.905 99.465,6.118C99.465,6.118 114.864,14.257 114.864,42.024C114.864,42.024 115.057,62.511 112.716,76.735ZM96.7,44.179C96.7,37.307 95.219,31.847 92.245,27.807C89.177,23.767 85.16,21.696 80.174,21.696C74.403,21.696 70.034,24.316 67.146,29.556L64.337,35.118L61.529,29.556C58.64,24.316 54.271,21.696 48.501,21.696C43.514,21.696 39.497,23.767 36.43,27.807C33.455,31.847 31.974,37.307 31.974,44.179L31.974,77.8L43.249,77.8L43.249,45.167C43.249,38.288 45.699,34.796 50.599,34.796C56.017,34.796 58.733,38.938 58.733,47.128L58.733,64.99L69.941,64.99L69.941,47.128C69.941,38.938 72.657,34.796 78.075,34.796C82.975,34.796 85.425,38.288 85.425,45.167L85.425,77.8L96.7,77.8L96.7,44.179Z"/>
</svg>

View File

@@ -1,12 +0,0 @@
title: $:/core/images/save-button-dynamic
tags: $:/tags/Image
<svg width="22pt" height="22pt" class="tc-image-save-button-dynamic tc-image-button" viewBox="0 0 128 128">
<g class="tc-image-save-button-dynamic-clean">
<path fill-rule="evenodd" d="M120.783 34.33c4.641 8.862 7.266 18.948 7.266 29.646 0 35.347-28.653 64-64 64-35.346 0-64-28.653-64-64 0-35.346 28.654-64 64-64 18.808 0 35.72 8.113 47.43 21.03l2.68-2.68c3.13-3.13 8.197-3.132 11.321-.008 3.118 3.118 3.121 8.193-.007 11.32l-4.69 4.691zm-12.058 12.058a47.876 47.876 0 013.324 17.588c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48c14.39 0 27.3 6.332 36.098 16.362L58.941 73.544 41.976 56.578c-3.127-3.127-8.201-3.123-11.32-.005-3.123 3.124-3.119 8.194.006 11.319l22.617 22.617a7.992 7.992 0 005.659 2.347c2.05 0 4.101-.783 5.667-2.349l44.12-44.12z"/>
</g>
<g class="tc-image-save-button-dynamic-dirty">
<path d="M64.856912,0 C100.203136,0 128.856912,28.653776 128.856912,64 C128.856912,99.346224 100.203136,128 64.856912,128 C29.510688,128 0.856911958,99.346224 0.856911958,64 C0.856911958,28.653776 29.510688,0 64.856912,0 Z M64.856912,16 C38.347244,16 16.856912,37.490332 16.856912,64 C16.856912,90.509668 38.347244,112 64.856912,112 C91.3665799,112 112.856912,90.509668 112.856912,64 C112.856912,37.490332 91.3665799,16 64.856912,16 Z"></path>
<circle cx="65" cy="64" r="32"></circle>
</g>
</svg>

View File

@@ -18,8 +18,6 @@ CopyToClipboard/Caption: copy to clipboard
CopyToClipboard/Hint: Copy this text to the clipboard CopyToClipboard/Hint: Copy this text to the clipboard
Delete/Caption: delete Delete/Caption: delete
Delete/Hint: Delete this tiddler Delete/Hint: Delete this tiddler
DeleteTiddlers/Caption: delete tiddlers
DeleteTiddlers/Hint: Delete tiddlers
Edit/Caption: edit Edit/Caption: edit
Edit/Hint: Edit this tiddler Edit/Hint: Edit this tiddler
Encryption/Caption: encryption Encryption/Caption: encryption
@@ -59,8 +57,6 @@ Home/Caption: home
Home/Hint: Open the default tiddlers Home/Hint: Open the default tiddlers
Language/Caption: language Language/Caption: language
Language/Hint: Choose the user interface language Language/Hint: Choose the user interface language
LayoutSwitcher/Hint: Open layout switcher
LayoutSwitcher/Caption: layout
Manager/Caption: tiddler manager Manager/Caption: tiddler manager
Manager/Hint: Open tiddler manager Manager/Hint: Open tiddler manager
More/Caption: more More/Caption: more

View File

@@ -7,7 +7,7 @@ Appearance/Hint: Ways to customise the appearance of your TiddlyWiki.
Basics/AnimDuration/Prompt: Animation duration Basics/AnimDuration/Prompt: Animation duration
Basics/AutoFocus/Prompt: Default focus field for new tiddlers Basics/AutoFocus/Prompt: Default focus field for new tiddlers
Basics/Caption: Basics Basics/Caption: Basics
Basics/DefaultTiddlers/BottomHint: Use &#91;&#91;double square brackets&#93;&#93; for titles with spaces. Or you can choose to {{retain story ordering||$:/snippets/retain-story-ordering-button}} Basics/DefaultTiddlers/BottomHint: Use &#91;&#91;double square brackets&#93;&#93; for titles with spaces. Or you can choose to <$button set="$:/DefaultTiddlers" setTo="[list[$:/StoryList]]">retain story ordering</$button>
Basics/DefaultTiddlers/Prompt: Default tiddlers Basics/DefaultTiddlers/Prompt: Default tiddlers
Basics/DefaultTiddlers/TopHint: Choose which tiddlers are displayed at startup Basics/DefaultTiddlers/TopHint: Choose which tiddlers are displayed at startup
Basics/Language/Prompt: Hello! Current language: Basics/Language/Prompt: Hello! Current language:
@@ -90,8 +90,8 @@ Plugins/Languages/Caption: Languages
Plugins/Languages/Hint: Language pack plugins Plugins/Languages/Hint: Language pack plugins
Plugins/NoInfoFound/Hint: No ''"<$text text=<<currentTab>>/>"'' found Plugins/NoInfoFound/Hint: No ''"<$text text=<<currentTab>>/>"'' found
Plugins/NotInstalled/Hint: This plugin is not currently installed Plugins/NotInstalled/Hint: This plugin is not currently installed
Plugins/OpenPluginLibrary: Open plugin library Plugins/OpenPluginLibrary: open plugin library
Plugins/ClosePluginLibrary: Close plugin library Plugins/ClosePluginLibrary: close plugin library
Plugins/PluginWillRequireReload: (requires reload) Plugins/PluginWillRequireReload: (requires reload)
Plugins/Plugins/Caption: Plugins Plugins/Plugins/Caption: Plugins
Plugins/Plugins/Hint: Plugins Plugins/Plugins/Hint: Plugins

View File

@@ -1,6 +1,5 @@
title: $:/language/EditTemplate/ 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/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/Placeholder: Type the text for this tiddler
Body/Preview/Type/Output: output Body/Preview/Type/Output: output

View File

@@ -1,13 +1,11 @@
title: $:/language/Docs/Fields/ title: $:/language/Docs/Fields/
_canonical_uri: The full URI of an external image tiddler _canonical_uri: The full URI of an external image tiddler
author: Name of the author of a plugin
bag: The name of the bag from which a tiddler came bag: The name of the bag from which a tiddler came
caption: The text to be displayed on a tab or button caption: The text to be displayed on a tab or button
code-body: The view template will display the tiddler as code if set to ''yes'' code-body: The view template will display the tiddler as code if set to ''yes''
color: The CSS color value associated with a tiddler color: The CSS color value associated with a tiddler
component: The name of the component responsible for an [[alert tiddler|AlertMechanism]] component: The name of the component responsible for an [[alert tiddler|AlertMechanism]]
core-version: For a plugin, indicates what version of TiddlyWiki with which it is compatible
current-tiddler: Used to cache the top tiddler in a [[history list|HistoryMechanism]] current-tiddler: Used to cache the top tiddler in a [[history list|HistoryMechanism]]
created: The date a tiddler was created created: The date a tiddler was created
creator: The name of the person who created a tiddler creator: The name of the person who created a tiddler
@@ -15,7 +13,7 @@ dependents: For a plugin, lists the dependent plugin titles
description: The descriptive text for a plugin, or a modal dialogue 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.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 draft.title: For draft tiddlers, contains the proposed new title of the tiddler
footer: The footer text for a modal footer: The footer text for a wizard
hide-body: The view template will hide bodies of tiddlers if set to ''yes'' 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 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'' library: Indicates that a tiddler should be saved as a JavaScript library if set to ''yes''
@@ -24,15 +22,13 @@ list-before: If set, the title of a tiddler before which this tiddler should be
list-after: If set, the title of the tiddler after which this tiddler should be added to the ordered list of tiddler titles, or at the end of the list if this field is present but empty list-after: If set, the title of the tiddler after which this tiddler should be added to the ordered list of tiddler titles, or at the end of the list if this field is present but empty
modified: The date and time at which a tiddler was last modified modified: The date and time at which a tiddler was last modified
modifier: The tiddler title associated with the person who last modified a tiddler modifier: The tiddler title associated with the person who last modified a tiddler
module-type: For javascript tiddlers, specifies what kind of module it is
name: The human readable name associated with a plugin tiddler name: The human readable name associated with a plugin tiddler
parent-plugin: For a plugin, specifies which plugin of which it is a sub-plugin
plugin-priority: A numerical value indicating the priority of a plugin tiddler plugin-priority: A numerical value indicating the priority of a plugin tiddler
plugin-type: The type of plugin in a plugin tiddler plugin-type: The type of plugin in a plugin tiddler
revision: The revision of the tiddler held at the server revision: The revision of the tiddler held at the server
released: Date of a TiddlyWiki release released: Date of a TiddlyWiki release
source: The source URL associated with a tiddler source: The source URL associated with a tiddler
subtitle: The subtitle text for a modal subtitle: The subtitle text for a wizard
tags: A list of tags associated with a tiddler tags: A list of tags associated with a tiddler
text: The body text of a tiddler text: The body text of a tiddler
throttle.refresh: If present, throttles refreshes of this tiddler throttle.refresh: If present, throttles refreshes of this tiddler

View File

@@ -9,10 +9,9 @@ Before you start storing important information in ~TiddlyWiki it is vital to mak
<div class="tc-control-panel"> <div class="tc-control-panel">
|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="$:/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="$:/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>>// |
|^ <$link to="$:/DefaultTiddlers"><<lingo DefaultTiddlers/Prompt>></$link><br><<lingo DefaultTiddlers/TopHint>>|<$edit tag="textarea" tiddler="$:/DefaultTiddlers"/><br>//<<lingo DefaultTiddlers/BottomHint>>// |
</div> </div>
See the [[control panel|$:/ControlPanel]] for more options. See the [[control panel|$:/ControlPanel]] for more options.

View File

@@ -1,18 +0,0 @@
title: $:/language/Help/commands
description: Run commands returned from a filter
Sequentially run the command tokens returned from a filter
```
--commands <filter>
```
Examples
```
--commands "[enlist{$:/build-commands-as-text}]"
```
```
--commands "[{$:/build-commands-as-json}jsonindexes[]] :map[{$:/build-commands-as-json}jsonget<currentTiddler>]"
```

View File

@@ -31,5 +31,5 @@ Notes:
Examples: 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"

View File

@@ -8,7 +8,6 @@ CloseAll/Button: close all
ColourPicker/Recent: Recent: ColourPicker/Recent: Recent:
ConfirmCancelTiddler: Do you wish to discard changes to the tiddler "<$text text=<<title>>/>"? ConfirmCancelTiddler: Do you wish to discard changes to the tiddler "<$text text=<<title>>/>"?
ConfirmDeleteTiddler: Do you wish to delete 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>>/>"? 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>>/>"? 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? ConfirmAction: Do you wish to proceed?
@@ -40,7 +39,6 @@ Error/RetrievingSkinny: Error retrieving skinny tiddler list
Error/SavingToTWEdit: Error saving to TWEdit Error/SavingToTWEdit: Error saving to TWEdit
Error/WhileSaving: Error while saving Error/WhileSaving: Error while saving
Error/XMLHttpRequest: XMLHttpRequest error code Error/XMLHttpRequest: XMLHttpRequest error code
Error/ZoominTextNode: Story View Error: It appears you tried to interact with a tiddler that displays in a custom container. This is most likely caused by using `$:/tags/StoryTiddlerTemplateFilter` with a template that contains text or whitespace at the start. Please use the pragma `\whitespace trim` and ensure the whole contents of the tiddler is wrapped in a single HTML element. The text that caused this issue:
InternalJavaScriptError/Title: Internal JavaScript Error InternalJavaScriptError/Title: Internal JavaScript Error
InternalJavaScriptError/Hint: Well, this is embarrassing. It is recommended that you restart TiddlyWiki by refreshing your browser InternalJavaScriptError/Hint: Well, this is embarrassing. It is recommended that you restart TiddlyWiki by refreshing your browser
LayoutSwitcher/Description: Open the layout switcher LayoutSwitcher/Description: Open the layout switcher

View File

@@ -0,0 +1,21 @@
title: $:/language/Modals/SaveInstructions
subtitle: Save your work
footer: <$button message="tm-close-tiddler">Close</$button>
help: https://tiddlywiki.com/static/SavingChanges.html
Your changes to this wiki need to be saved as a ~TiddlyWiki HTML file.
!!! Desktop browsers
# Select ''Save As'' from the ''File'' menu
# Choose a filename and location
#* Some browsers also require you to explicitly specify the file saving format as ''Webpage, HTML only'' or similar
# Close this tab
!!! Smartphone browsers
# Create a bookmark to this page
#* If you've got iCloud or Google Sync set up then the bookmark will automatically sync to your desktop where you can open it and save it as above
# Close this tab
//If you open the bookmark again in Mobile Safari you will see this message again. If you want to go ahead and use the file, just click the ''close'' button below//

View File

@@ -1,6 +1,5 @@
title: $:/language/SideBar/ title: $:/language/SideBar/
Caption: Sidebar
All/Caption: All All/Caption: All
Contents/Caption: Contents Contents/Caption: Contents
Drafts/Caption: Drafts Drafts/Caption: Drafts

View File

@@ -1,42 +0,0 @@
/*\
title: $:/core/modules/commands/commands.js
type: application/javascript
module-type: command
Runs the commands returned from a filter
\*/
(function() {
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "commands",
synchronous: true
};
var Command = function(params, commander) {
this.params = params;
this.commander = commander;
};
Command.prototype.execute = function() {
// Parse the filter
var filter = this.params[0];
if(!filter) {
return "No filter specified";
}
var commands = this.commander.wiki.filterTiddlers(filter)
if(commands.length === 0) {
return "No tiddlers found for filter '" + filter + "'";
}
this.commander.addCommandTokens(commands);
return null;
};
exports.Command = Command;
})();

View File

@@ -50,7 +50,7 @@ Render individual tiddlers and save the results to the specified files
console.log("Rendering \"" + title + "\" to \"" + filepath + "\""); console.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
} }
var parser = wiki.parseTiddler(template || title), var parser = wiki.parseTiddler(template || title),
widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title,storyTiddler: title})}), widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title})}),
container = $tw.fakeDocument.createElement("div"); container = $tw.fakeDocument.createElement("div");
widgetNode.render(container,null); widgetNode.render(container,null);
var text = type === "text/html" ? container.innerHTML : container.textContent; var text = type === "text/html" ? container.innerHTML : container.textContent;

View File

@@ -40,7 +40,6 @@ Command.prototype.execute = function() {
$tw.utils.createFileDirectories(filename); $tw.utils.createFileDirectories(filename);
if(template) { if(template) {
variables.currentTiddler = title; variables.currentTiddler = title;
variables.storyTiddler = title;
title = template; title = template;
} }
if(name && value) { if(name && value) {

View File

@@ -46,7 +46,7 @@ Command.prototype.execute = function() {
} }
$tw.utils.each(tiddlers,function(title) { $tw.utils.each(tiddlers,function(title) {
var parser = wiki.parseTiddler(template), var parser = wiki.parseTiddler(template),
widgetNode = wiki.makeWidget(parser,{variables: {currentTiddler: title, storyTiddler: title}}), widgetNode = wiki.makeWidget(parser,{variables: {currentTiddler: title}}),
container = $tw.fakeDocument.createElement("div"); container = $tw.fakeDocument.createElement("div");
widgetNode.render(container,null); widgetNode.render(container,null);
var text = type === "text/html" ? container.innerHTML : container.textContent, var text = type === "text/html" ? container.innerHTML : container.textContent,
@@ -57,7 +57,7 @@ Command.prototype.execute = function() {
exportPath = path.resolve(outputPath,macroPath + extension); exportPath = path.resolve(outputPath,macroPath + extension);
} }
} }
var finalPath = exportPath || path.resolve(pathname,$tw.utils.encodeURIComponentExtended(title) + extension); var finalPath = exportPath || path.resolve(pathname,encodeURIComponent(title) + extension);
$tw.utils.createFileDirectories(finalPath); $tw.utils.createFileDirectories(finalPath);
fs.writeFileSync(finalPath,text,"utf8"); fs.writeFileSync(finalPath,text,"utf8");
}); });

View File

@@ -65,7 +65,7 @@ Command.prototype.execute = function() {
$tw.utils.each(filteredPluginList,function(title) { $tw.utils.each(filteredPluginList,function(title) {
var tiddler = containerData.tiddlers[title]; var tiddler = containerData.tiddlers[title];
// Save each JSON file and collect the skinny data // Save each JSON file and collect the skinny data
var pathname = path.resolve(self.commander.outputPath,basepath + $tw.utils.encodeURIComponentExtended(title) + ".json"); var pathname = path.resolve(self.commander.outputPath,basepath + encodeURIComponent(title) + ".json");
$tw.utils.createFileDirectories(pathname); $tw.utils.createFileDirectories(pathname);
fs.writeFileSync(pathname,JSON.stringify(tiddler),"utf8"); fs.writeFileSync(pathname,JSON.stringify(tiddler),"utf8");
// Collect the skinny list data // Collect the skinny list data

View File

@@ -45,7 +45,7 @@ Command.prototype.execute = function() {
var tiddler = self.commander.wiki.getTiddler(title), var tiddler = self.commander.wiki.getTiddler(title),
type = tiddler.fields.type || "text/vnd.tiddlywiki", type = tiddler.fields.type || "text/vnd.tiddlywiki",
contentTypeInfo = $tw.config.contentTypeInfo[type] || {encoding: "utf8"}, contentTypeInfo = $tw.config.contentTypeInfo[type] || {encoding: "utf8"},
filename = path.resolve(pathname,$tw.utils.encodeURIComponentExtended(title)); filename = path.resolve(pathname,encodeURIComponent(title));
fs.writeFileSync(filename,tiddler.fields.text,contentTypeInfo.encoding); fs.writeFileSync(filename,tiddler.fields.text,contentTypeInfo.encoding);
}); });
return null; return null;

View File

@@ -30,7 +30,7 @@ exports.textPrimitives.wikiLink = exports.textPrimitives.upperLetter + "+" +
exports.textPrimitives.upperLetter + exports.textPrimitives.upperLetter +
exports.textPrimitives.anyLetter + "*"; exports.textPrimitives.anyLetter + "*";
exports.htmlEntities = {quot:34, dollar:36, amp:38, apos:39, lt:60, gt:62, nbsp:160, iexcl:161, cent:162, pound:163, curren:164, yen:165, brvbar:166, sect:167, uml:168, copy:169, ordf:170, laquo:171, not:172, shy:173, reg:174, macr:175, deg:176, plusmn:177, sup2:178, sup3:179, acute:180, micro:181, para:182, middot:183, cedil:184, sup1:185, ordm:186, raquo:187, frac14:188, frac12:189, frac34:190, iquest:191, Agrave:192, Aacute:193, Acirc:194, Atilde:195, Auml:196, Aring:197, AElig:198, Ccedil:199, Egrave:200, Eacute:201, Ecirc:202, Euml:203, Igrave:204, Iacute:205, Icirc:206, Iuml:207, ETH:208, Ntilde:209, Ograve:210, Oacute:211, Ocirc:212, Otilde:213, Ouml:214, times:215, Oslash:216, Ugrave:217, Uacute:218, Ucirc:219, Uuml:220, Yacute:221, THORN:222, szlig:223, agrave:224, aacute:225, acirc:226, atilde:227, auml:228, aring:229, aelig:230, ccedil:231, egrave:232, eacute:233, ecirc:234, euml:235, igrave:236, iacute:237, icirc:238, iuml:239, eth:240, ntilde:241, ograve:242, oacute:243, ocirc:244, otilde:245, ouml:246, divide:247, oslash:248, ugrave:249, uacute:250, ucirc:251, uuml:252, yacute:253, thorn:254, yuml:255, OElig:338, oelig:339, Scaron:352, scaron:353, Yuml:376, fnof:402, circ:710, tilde:732, Alpha:913, Beta:914, Gamma:915, Delta:916, Epsilon:917, Zeta:918, Eta:919, Theta:920, Iota:921, Kappa:922, Lambda:923, Mu:924, Nu:925, Xi:926, Omicron:927, Pi:928, Rho:929, Sigma:931, Tau:932, Upsilon:933, Phi:934, Chi:935, Psi:936, Omega:937, alpha:945, beta:946, gamma:947, delta:948, epsilon:949, zeta:950, eta:951, theta:952, iota:953, kappa:954, lambda:955, mu:956, nu:957, xi:958, omicron:959, pi:960, rho:961, sigmaf:962, sigma:963, tau:964, upsilon:965, phi:966, chi:967, psi:968, omega:969, thetasym:977, upsih:978, piv:982, ensp:8194, emsp:8195, thinsp:8201, zwnj:8204, zwj:8205, lrm:8206, rlm:8207, ndash:8211, mdash:8212, lsquo:8216, rsquo:8217, sbquo:8218, ldquo:8220, rdquo:8221, bdquo:8222, dagger:8224, Dagger:8225, bull:8226, hellip:8230, permil:8240, prime:8242, Prime:8243, lsaquo:8249, rsaquo:8250, oline:8254, frasl:8260, euro:8364, image:8465, weierp:8472, real:8476, trade:8482, alefsym:8501, larr:8592, uarr:8593, rarr:8594, darr:8595, harr:8596, crarr:8629, lArr:8656, uArr:8657, rArr:8658, dArr:8659, hArr:8660, forall:8704, part:8706, exist:8707, empty:8709, nabla:8711, isin:8712, notin:8713, ni:8715, prod:8719, sum:8721, minus:8722, lowast:8727, radic:8730, prop:8733, infin:8734, ang:8736, and:8743, or:8744, cap:8745, cup:8746, int:8747, there4:8756, sim:8764, cong:8773, asymp:8776, ne:8800, equiv:8801, le:8804, ge:8805, sub:8834, sup:8835, nsub:8836, sube:8838, supe:8839, oplus:8853, otimes:8855, perp:8869, sdot:8901, lceil:8968, rceil:8969, lfloor:8970, rfloor:8971, lang:9001, rang:9002, loz:9674, spades:9824, clubs:9827, hearts:9829, diams:9830 }; exports.htmlEntities = {quot:34, amp:38, apos:39, lt:60, gt:62, nbsp:160, iexcl:161, cent:162, pound:163, curren:164, yen:165, brvbar:166, sect:167, uml:168, copy:169, ordf:170, laquo:171, not:172, shy:173, reg:174, macr:175, deg:176, plusmn:177, sup2:178, sup3:179, acute:180, micro:181, para:182, middot:183, cedil:184, sup1:185, ordm:186, raquo:187, frac14:188, frac12:189, frac34:190, iquest:191, Agrave:192, Aacute:193, Acirc:194, Atilde:195, Auml:196, Aring:197, AElig:198, Ccedil:199, Egrave:200, Eacute:201, Ecirc:202, Euml:203, Igrave:204, Iacute:205, Icirc:206, Iuml:207, ETH:208, Ntilde:209, Ograve:210, Oacute:211, Ocirc:212, Otilde:213, Ouml:214, times:215, Oslash:216, Ugrave:217, Uacute:218, Ucirc:219, Uuml:220, Yacute:221, THORN:222, szlig:223, agrave:224, aacute:225, acirc:226, atilde:227, auml:228, aring:229, aelig:230, ccedil:231, egrave:232, eacute:233, ecirc:234, euml:235, igrave:236, iacute:237, icirc:238, iuml:239, eth:240, ntilde:241, ograve:242, oacute:243, ocirc:244, otilde:245, ouml:246, divide:247, oslash:248, ugrave:249, uacute:250, ucirc:251, uuml:252, yacute:253, thorn:254, yuml:255, OElig:338, oelig:339, Scaron:352, scaron:353, Yuml:376, fnof:402, circ:710, tilde:732, Alpha:913, Beta:914, Gamma:915, Delta:916, Epsilon:917, Zeta:918, Eta:919, Theta:920, Iota:921, Kappa:922, Lambda:923, Mu:924, Nu:925, Xi:926, Omicron:927, Pi:928, Rho:929, Sigma:931, Tau:932, Upsilon:933, Phi:934, Chi:935, Psi:936, Omega:937, alpha:945, beta:946, gamma:947, delta:948, epsilon:949, zeta:950, eta:951, theta:952, iota:953, kappa:954, lambda:955, mu:956, nu:957, xi:958, omicron:959, pi:960, rho:961, sigmaf:962, sigma:963, tau:964, upsilon:965, phi:966, chi:967, psi:968, omega:969, thetasym:977, upsih:978, piv:982, ensp:8194, emsp:8195, thinsp:8201, zwnj:8204, zwj:8205, lrm:8206, rlm:8207, ndash:8211, mdash:8212, lsquo:8216, rsquo:8217, sbquo:8218, ldquo:8220, rdquo:8221, bdquo:8222, dagger:8224, Dagger:8225, bull:8226, hellip:8230, permil:8240, prime:8242, Prime:8243, lsaquo:8249, rsaquo:8250, oline:8254, frasl:8260, euro:8364, image:8465, weierp:8472, real:8476, trade:8482, alefsym:8501, larr:8592, uarr:8593, rarr:8594, darr:8595, harr:8596, crarr:8629, lArr:8656, uArr:8657, rArr:8658, dArr:8659, hArr:8660, forall:8704, part:8706, exist:8707, empty:8709, nabla:8711, isin:8712, notin:8713, ni:8715, prod:8719, sum:8721, minus:8722, lowast:8727, radic:8730, prop:8733, infin:8734, ang:8736, and:8743, or:8744, cap:8745, cup:8746, int:8747, there4:8756, sim:8764, cong:8773, asymp:8776, ne:8800, equiv:8801, le:8804, ge:8805, sub:8834, sup:8835, nsub:8836, sube:8838, supe:8839, oplus:8853, otimes:8855, perp:8869, sdot:8901, lceil:8968, rceil:8969, lfloor:8970, rfloor:8971, lang:9001, rang:9002, loz:9674, spades:9824, clubs:9827, hearts:9829, diams:9830 };
exports.htmlVoidElements = "area,base,br,col,command,embed,hr,img,input,keygen,link,meta,param,source,track,wbr".split(","); exports.htmlVoidElements = "area,base,br,col,command,embed,hr,img,input,keygen,link,meta,param,source,track,wbr".split(",");

View File

@@ -35,7 +35,7 @@ function FramedEngine(options) {
this.iframeDoc = this.iframeNode.contentWindow.document; this.iframeDoc = this.iframeNode.contentWindow.document;
// (Firefox requires us to put some empty content in the iframe) // (Firefox requires us to put some empty content in the iframe)
var paletteTitle = this.widget.wiki.getTiddlerText("$:/palette"); var paletteTitle = this.widget.wiki.getTiddlerText("$:/palette");
var colorScheme = (this.widget.wiki.getTiddler(paletteTitle) || {fields: {}}).fields["color-scheme"] || "light"; var colorScheme = this.widget.wiki.getTiddler(paletteTitle).fields["color-scheme"] || "light";
this.iframeDoc.open(); this.iframeDoc.open();
this.iframeDoc.write("<meta name='color-scheme' content='" + colorScheme + "'>"); this.iframeDoc.write("<meta name='color-scheme' content='" + colorScheme + "'>");
this.iframeDoc.close(); this.iframeDoc.close();
@@ -87,7 +87,7 @@ function FramedEngine(options) {
$tw.utils.addEventListeners(this.domNode,[ $tw.utils.addEventListeners(this.domNode,[
{name: "click",handlerObject: this,handlerMethod: "handleClickEvent"}, {name: "click",handlerObject: this,handlerMethod: "handleClickEvent"},
{name: "input",handlerObject: this,handlerMethod: "handleInputEvent"}, {name: "input",handlerObject: this,handlerMethod: "handleInputEvent"},
{name: "keydown",handlerObject: this,handlerMethod: "handleKeydownEvent"}, {name: "keydown",handlerObject: this.widget,handlerMethod: "handleKeydownEvent"},
{name: "focus",handlerObject: this,handlerMethod: "handleFocusEvent"} {name: "focus",handlerObject: this,handlerMethod: "handleFocusEvent"}
]); ]);
// Add drag and drop event listeners if fileDrop is enabled // Add drag and drop event listeners if fileDrop is enabled
@@ -162,13 +162,13 @@ FramedEngine.prototype.fixHeight = function() {
if(this.widget.editAutoHeight) { if(this.widget.editAutoHeight) {
if(this.domNode && !this.domNode.isTiddlyWikiFakeDom) { if(this.domNode && !this.domNode.isTiddlyWikiFakeDom) {
var newHeight = $tw.utils.resizeTextAreaToFit(this.domNode,this.widget.editMinHeight); var newHeight = $tw.utils.resizeTextAreaToFit(this.domNode,this.widget.editMinHeight);
this.iframeNode.style.height = newHeight + "px"; this.iframeNode.style.height = (newHeight + 14) + "px"; // +14 for the border on the textarea
} }
} else { } else {
var fixedHeight = parseInt(this.widget.wiki.getTiddlerText(HEIGHT_VALUE_TITLE,"400px"),10); var fixedHeight = parseInt(this.widget.wiki.getTiddlerText(HEIGHT_VALUE_TITLE,"400px"),10);
fixedHeight = Math.max(fixedHeight,20); fixedHeight = Math.max(fixedHeight,20);
this.domNode.style.height = fixedHeight + "px"; this.domNode.style.height = fixedHeight + "px";
this.iframeNode.style.height = fixedHeight + "px"; this.iframeNode.style.height = (fixedHeight + 14) + "px";
} }
} }
}; };
@@ -177,11 +177,9 @@ FramedEngine.prototype.fixHeight = function() {
Focus the engine node Focus the engine node
*/ */
FramedEngine.prototype.focus = function() { FramedEngine.prototype.focus = function() {
if(this.domNode.focus) { if(this.domNode.focus && this.domNode.select) {
this.domNode.focus(); this.domNode.focus();
} this.domNode.select();
if(this.domNode.select) {
$tw.utils.setSelectionByPosition(this.domNode,this.widget.editFocusSelectFromStart,this.widget.editFocusSelectFromEnd);
} }
}; };
@@ -194,17 +192,6 @@ 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 Handle a click
*/ */

View File

@@ -119,12 +119,10 @@ SimpleEngine.prototype.fixHeight = function() {
/* /*
Focus the engine node Focus the engine node
*/ */
SimpleEngine.prototype.focus = function() { SimpleEngine.prototype.focus = function() {
if(this.domNode.focus) { if(this.domNode.focus && this.domNode.select) {
this.domNode.focus(); this.domNode.focus();
} this.domNode.select();
if(this.domNode.select) {
$tw.utils.setSelectionByPosition(this.domNode,this.widget.editFocusSelectFromStart,this.widget.editFocusSelectFromEnd);
} }
}; };

View File

@@ -115,7 +115,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
// Otherwise, we need to construct a default value for the editor // Otherwise, we need to construct a default value for the editor
switch(this.editField) { switch(this.editField) {
case "text": case "text":
value = ""; value = "Type the text for the tiddler '" + this.editTitle + "'";
type = "text/vnd.tiddlywiki"; type = "text/vnd.tiddlywiki";
break; break;
case "title": case "title":
@@ -180,8 +180,6 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
this.editMinHeight = this.getAttribute("minHeight",DEFAULT_MIN_TEXT_AREA_HEIGHT); this.editMinHeight = this.getAttribute("minHeight",DEFAULT_MIN_TEXT_AREA_HEIGHT);
this.editFocusPopup = this.getAttribute("focusPopup"); this.editFocusPopup = this.getAttribute("focusPopup");
this.editFocus = this.getAttribute("focus"); this.editFocus = this.getAttribute("focus");
this.editFocusSelectFromStart = $tw.utils.parseNumber(this.getAttribute("focusSelectFromStart","0"));
this.editFocusSelectFromEnd = $tw.utils.parseNumber(this.getAttribute("focusSelectFromEnd","0"));
this.editTabIndex = this.getAttribute("tabindex"); this.editTabIndex = this.getAttribute("tabindex");
this.editCancelPopups = this.getAttribute("cancelPopups","") === "yes"; this.editCancelPopups = this.getAttribute("cancelPopups","") === "yes";
this.editInputActions = this.getAttribute("inputActions"); this.editInputActions = this.getAttribute("inputActions");
@@ -220,7 +218,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
EditTextWidget.prototype.refresh = function(changedTiddlers) { EditTextWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes(); var changedAttributes = this.computeAttributes();
// Completely rerender if any of our attributes have changed // Completely rerender if any of our attributes have changed
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedTiddlers["$:/palette"] || changedAttributes.disabled || changedAttributes.fileDrop) { if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedAttributes.disabled || changedAttributes.fileDrop) {
this.refreshSelf(); this.refreshSelf();
return true; return true;
} else if (changedTiddlers[this.editRefreshTitle]) { } else if (changedTiddlers[this.editRefreshTitle]) {
@@ -300,7 +298,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
Propogate keydown events to our container for the keyboard widgets benefit Propogate keydown events to our container for the keyboard widgets benefit
*/ */
EditTextWidget.prototype.propogateKeydownEvent = function(event) { EditTextWidget.prototype.propogateKeydownEvent = function(event) {
var newEvent = this.cloneEvent(event,["keyCode","code","which","key","metaKey","ctrlKey","altKey","shiftKey"]); var newEvent = this.cloneEvent(event,["keyCode","which","metaKey","ctrlKey","altKey","shiftKey"]);
return !this.parentDomNode.dispatchEvent(newEvent); return !this.parentDomNode.dispatchEvent(newEvent);
}; };

View File

@@ -25,10 +25,20 @@ exports.cascade = function(operationSubFunction,options) {
if(!filterFnList[index]) { if(!filterFnList[index]) {
filterFnList[index] = options.wiki.compileFilter(filter); filterFnList[index] = options.wiki.compileFilter(filter);
} }
var output = filterFnList[index](options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({ var output = filterFnList[index](options.wiki.makeTiddlerIterator([title]),{
"currentTiddler": "" + title, getVariable: function(name,opts) {
"..currentTiddler": widget.getVariable("currentTiddler","") opts = opts || {};
})); opts.variables = {
"currentTiddler": "" + title,
"..currentTiddler": widget.getVariable("currentTiddler")
};
if(name in opts.variables) {
return opts.variables[name];
} else {
return widget.getVariable(name,opts);
}
}
});
if(output.length !== 0) { if(output.length !== 0) {
result = output[0]; result = output[0];
return false; return false;

View File

@@ -19,13 +19,23 @@ exports.filter = function(operationSubFunction,options) {
var resultsToRemove = [], var resultsToRemove = [],
index = 0; index = 0;
results.each(function(title) { results.each(function(title) {
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({ var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
"currentTiddler": "" + title, getVariable: function(name,opts) {
"..currentTiddler": widget.getVariable("currentTiddler",""), opts = opts || {};
"index": "" + index, opts.variables = {
"revIndex": "" + (results.length - 1 - index), "currentTiddler": "" + title,
"length": "" + results.length "..currentTiddler": widget.getVariable("currentTiddler"),
})); "index": "" + index,
"revIndex": "" + (results.length - 1 - index),
"length": "" + results.length
};
if(name in opts.variables) {
return opts.variables[name];
} else {
return widget.getVariable(name,opts);
}
}
});
if(filtered.length === 0) { if(filtered.length === 0) {
resultsToRemove.push(title); resultsToRemove.push(title);
} }

View File

@@ -16,25 +16,27 @@ exports.map = function(operationSubFunction,options) {
return function(results,source,widget) { return function(results,source,widget) {
if(results.length > 0) { if(results.length > 0) {
var inputTitles = results.toArray(), var inputTitles = results.toArray(),
index = 0, index = 0;
suffixes = options.suffixes,
flatten = (suffixes[0] && suffixes[0][0] === "flat") ? true : false;
results.clear(); results.clear();
$tw.utils.each(inputTitles,function(title) { $tw.utils.each(inputTitles,function(title) {
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({ var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
"currentTiddler": "" + title, getVariable: function(name,opts) {
"..currentTiddler": widget.getVariable("currentTiddler",""), opts = opts || {};
"index": "" + index, opts.variables = {
"revIndex": "" + (inputTitles.length - 1 - index), "currentTiddler": "" + title,
"length": "" + inputTitles.length "..currentTiddler": widget.getVariable("currentTiddler"),
})); "index": "" + index,
if(filtered.length && flatten) { "revIndex": "" + (inputTitles.length - 1 - index),
$tw.utils.each(filtered,function(value) { "length": "" + inputTitles.length
results.push(value); };
}) if(name in opts.variables) {
} else { return opts.variables[name];
results.push(filtered[0]||""); } else {
} return widget.getVariable(name,opts);
}
}
});
results.push(filtered[0] || "");
++index; ++index;
}); });
} }

View File

@@ -18,14 +18,24 @@ exports.reduce = function(operationSubFunction,options) {
var accumulator = "", var accumulator = "",
index = 0; index = 0;
results.each(function(title) { results.each(function(title) {
var list = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({ var list = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
"currentTiddler": "" + title, getVariable: function(name,opts) {
"..currentTiddler": widget.getVariable("currentTiddler"), opts = opts || {};
"index": "" + index, opts.variables = {
"revIndex": "" + (results.length - 1 - index), "currentTiddler": "" + title,
"length": "" + results.length, "..currentTiddler": widget.getVariable("currentTiddler"),
"accumulator": "" + accumulator "index": "" + index,
})); "revIndex": "" + (results.length - 1 - index),
"length": "" + results.length,
"accumulator": "" + accumulator
};
if(name in opts.variables) {
return opts.variables[name];
} else {
return widget.getVariable(name,opts);
}
}
});
if(list.length > 0) { if(list.length > 0) {
accumulator = "" + list[0]; accumulator = "" + list[0];
} }

View File

@@ -25,10 +25,20 @@ exports.sort = function(operationSubFunction,options) {
indexes = new Array(inputTitles.length), indexes = new Array(inputTitles.length),
compareFn; compareFn;
results.each(function(title) { results.each(function(title) {
var key = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({ var key = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
"currentTiddler": "" + title, getVariable: function(name,opts) {
"..currentTiddler": widget.getVariable("currentTiddler") opts = opts || {};
})); opts.variables = {
"currentTiddler": "" + title,
"..currentTiddler": widget.getVariable("currentTiddler")
};
if(name in opts.variables) {
return opts.variables[name];
} else {
return widget.getVariable(name,opts);
}
}
});
sortKeys.push(key[0] || ""); sortKeys.push(key[0] || "");
}); });
results.clear(); results.clear();

View File

@@ -12,9 +12,6 @@ Adds tiddler filtering methods to the $tw.Wiki object.
/*global $tw: false */ /*global $tw: false */
"use strict"; "use strict";
/* Maximum permitted filter recursion depth */
var MAX_FILTER_DEPTH = 300;
/* /*
Parses an operation (i.e. a run) within a filter string Parses an operation (i.e. a run) within a filter string
operators: Array of array of operator nodes into which results should be inserted operators: Array of array of operator nodes into which results should be inserted
@@ -223,18 +220,10 @@ source: an iterator function for the source tiddlers, called source(iterator), w
widget: an optional widget node for retrieving the current tiddler etc. widget: an optional widget node for retrieving the current tiddler etc.
*/ */
exports.compileFilter = function(filterString) { 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; var filterParseTree;
try { try {
filterParseTree = this.parseFilter(filterString); filterParseTree = this.parseFilter(filterString);
} catch(e) { } catch(e) {
// We do not cache this result, so it adjusts along with localization changes
return function(source,widget) { return function(source,widget) {
return [$tw.language.getString("Error/Filter") + ": " + e]; return [$tw.language.getString("Error/Filter") + ": " + e];
}; };
@@ -255,21 +244,19 @@ exports.compileFilter = function(filterString) {
var operands = [], var operands = [],
operatorFunction; operatorFunction;
if(!operator.operator) { if(!operator.operator) {
// Use the "title" operator if no operator is specified
operatorFunction = filterOperators.title; operatorFunction = filterOperators.title;
} else if(!filterOperators[operator.operator]) { } else if(!filterOperators[operator.operator]) {
// Unknown operators treated as "[unknown]" - at run time we can distinguish between a custom operator and falling back to the default "field" operator operatorFunction = filterOperators.field;
operatorFunction = filterOperators["[unknown]"];
} else { } else {
// Use the operator function
operatorFunction = filterOperators[operator.operator]; operatorFunction = filterOperators[operator.operator];
} }
$tw.utils.each(operator.operands,function(operand) { $tw.utils.each(operator.operands,function(operand) {
if(operand.indirect) { if(operand.indirect) {
operand.value = self.getTextReference(operand.text,"",currTiddlerTitle); operand.value = self.getTextReference(operand.text,"",currTiddlerTitle);
} else if(operand.variable) { } else if(operand.variable) {
var varTree = $tw.utils.parseFilterVariable(operand.text); var varTree = $tw.utils.parseFilterVariable(operand.text);
operand.value = widget.evaluateVariable(varTree.name,{params: varTree.params, source: source})[0] || ""; operand.value = widget.getVariable(varTree.name,{params:varTree.params,defaultValue: ""});
} else { } else {
operand.value = operand.text; operand.value = operand.text;
} }
@@ -333,7 +320,7 @@ exports.compileFilter = function(filterString) {
})()); })());
}); });
// Return a function that applies the operations to a source iterator of tiddler titles // Return a function that applies the operations to a source iterator of tiddler titles
var fnMeasured = $tw.perf.measure("filter: " + filterString,function filterFunction(source,widget) { return $tw.perf.measure("filter: " + filterString,function filterFunction(source,widget) {
if(!source) { if(!source) {
source = self.each; source = self.each;
} else if(typeof source === "object") { // Array or hashmap } else if(typeof source === "object") { // Array or hashmap
@@ -343,27 +330,11 @@ exports.compileFilter = function(filterString) {
widget = $tw.rootWidget; widget = $tw.rootWidget;
} }
var results = new $tw.utils.LinkedList(); var results = new $tw.utils.LinkedList();
self.filterRecursionCount = (self.filterRecursionCount || 0) + 1; $tw.utils.each(operationFunctions,function(operationFunction) {
if(self.filterRecursionCount < MAX_FILTER_DEPTH) { operationFunction(results,source,widget);
$tw.utils.each(operationFunctions,function(operationFunction) { });
operationFunction(results,source,widget);
});
} else {
results.push("/**-- Excessive filter recursion --**/");
}
self.filterRecursionCount = self.filterRecursionCount - 1;
return results.toArray(); 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;
}; };
})(); })();

View File

@@ -16,22 +16,6 @@ Filter operator for applying decodeURIComponent() to each item.
Export our filter functions Export our filter functions
*/ */
exports.decodebase64 = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
results.push($tw.utils.base64Decode(title));
});
return results;
};
exports.encodebase64 = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
results.push($tw.utils.base64Encode(title));
});
return results;
};
exports.decodeuricomponent = function(source,operator,options) { exports.decodeuricomponent = function(source,operator,options) {
var results = []; var results = [];
source(function(tiddler,title) { source(function(tiddler,title) {
@@ -43,7 +27,7 @@ exports.decodeuricomponent = function(source,operator,options) {
exports.encodeuricomponent = function(source,operator,options) { exports.encodeuricomponent = function(source,operator,options) {
var results = []; var results = [];
source(function(tiddler,title) { source(function(tiddler,title) {
results.push($tw.utils.encodeURIComponentExtended(title)); results.push(encodeURIComponent(title));
}); });
return results; return results;
}; };

View File

@@ -20,10 +20,18 @@ exports.filter = function(source,operator,options) {
results = [], results = [],
target = operator.prefix !== "!"; target = operator.prefix !== "!";
source(function(tiddler,title) { source(function(tiddler,title) {
var list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),options.widget.makeFakeWidgetWithVariables({ var list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),{
"currentTiddler": "" + title, getVariable: function(name) {
"..currentTiddler": options.widget.getVariable("currentTiddler","") switch(name) {
})); case "currentTiddler":
return "" + title;
case "..currentTiddler":
return options.widget.getVariable("currentTiddler");
default:
return options.widget.getVariable(name);
}
}
});
if((list.length > 0) === target) { if((list.length > 0) === target) {
results.push(title); results.push(title);
} }

View File

@@ -1,35 +0,0 @@
/*\
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;
};
})();

View File

@@ -1,32 +0,0 @@
/*\
title: $:/core/modules/filters/function.js
type: application/javascript
module-type: filteroperator
Filter operator returning those input titles that are returned from a function
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.function = function(source,operator,options) {
var functionName = operator.operands[0],
variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(functionName);
if(variableInfo && variableInfo.srcVariable && variableInfo.srcVariable.isFunctionDefinition) {
return options.widget.evaluateVariable(functionName,{params: operator.operands.slice(1), source: source});
}
// Return the input list if the function wasn't found
var results = [];
source(function(tiddler,title) {
results.push(title);
});
return results;
};
})();

View File

@@ -1,46 +0,0 @@
/*\
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;
};
})();

View File

@@ -32,12 +32,7 @@ exports.insertbefore = function(source,operator,options) {
if(pos !== -1) { if(pos !== -1) {
results.splice(pos,0,operator.operand); results.splice(pos,0,operator.operand);
} else { } else {
var suffix = operator.operands.length > 1 ? operator.suffix : ""; results.push(operator.operand);
if(suffix == "start") {
results.splice(0,0,operator.operand);
} else {
results.push(operator.operand);
}
} }
} }
return results; return results;

View File

@@ -19,13 +19,13 @@ exports.variable = function(source,prefix,options) {
var results = []; var results = [];
if(prefix === "!") { if(prefix === "!") {
source(function(tiddler,title) { source(function(tiddler,title) {
if(options.widget.getVariable(title) === undefined) { if(!(title in options.widget.variables)) {
results.push(title); results.push(title);
} }
}); });
} else { } else {
source(function(tiddler,title) { source(function(tiddler,title) {
if(options.widget.getVariable(title) !== undefined) { if(title in options.widget.variables) {
results.push(title); results.push(title);
} }
}); });

View File

@@ -15,25 +15,11 @@ Filter operators for JSON operations
exports["jsonget"] = function(source,operator,options) { exports["jsonget"] = function(source,operator,options) {
var results = []; var results = [];
source(function(tiddler,title) { source(function(tiddler,title) {
var data = $tw.utils.parseJSONSafe(title,title); var data = options.wiki.getTiddlerDataCached(title);
if(data) { if(data) {
var items = getDataItemValueAsStrings(data,operator.operands); var item = getDataItemValueAsStrings(data,operator.operands);
if(items !== undefined) {
results.push.apply(results,items);
}
}
});
return results;
};
exports["jsonextract"] = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
var data = $tw.utils.parseJSONSafe(title,title);
if(data) {
var item = getDataItem(data,operator.operands);
if(item !== undefined) { if(item !== undefined) {
results.push(JSON.stringify(item)); results.push.apply(results,item);
} }
} }
}); });
@@ -43,11 +29,11 @@ exports["jsonextract"] = function(source,operator,options) {
exports["jsonindexes"] = function(source,operator,options) { exports["jsonindexes"] = function(source,operator,options) {
var results = []; var results = [];
source(function(tiddler,title) { source(function(tiddler,title) {
var data = $tw.utils.parseJSONSafe(title,title); var data = options.wiki.getTiddlerDataCached(title);
if(data) { if(data) {
var items = getDataItemKeysAsStrings(data,operator.operands); var item = getDataItemKeysAsStrings(data,operator.operands);
if(items !== undefined) { if(item !== undefined) {
results.push.apply(results,items); results.push.apply(results,item);
} }
} }
}); });
@@ -57,7 +43,7 @@ exports["jsonindexes"] = function(source,operator,options) {
exports["jsontype"] = function(source,operator,options) { exports["jsontype"] = function(source,operator,options) {
var results = []; var results = [];
source(function(tiddler,title) { source(function(tiddler,title) {
var data = $tw.utils.parseJSONSafe(title,title); var data = options.wiki.getTiddlerDataCached(title);
if(data) { if(data) {
var item = getDataItemType(data,operator.operands); var item = getDataItemType(data,operator.operands);
if(item !== undefined) { if(item !== undefined) {
@@ -74,7 +60,7 @@ Given a JSON data structure and an array of index strings, return an array of th
function getDataItemValueAsStrings(data,indexes) { function getDataItemValueAsStrings(data,indexes) {
// Get the item // Get the item
var item = getDataItem(data,indexes); var item = getDataItem(data,indexes);
// Return the item as a string list // Return the item as a string
return convertDataItemValueToStrings(item); return convertDataItemValueToStrings(item);
} }
@@ -94,29 +80,24 @@ Return an array of the string representation of the values of a data item, or "u
function convertDataItemValueToStrings(item) { function convertDataItemValueToStrings(item) {
// Return the item as a string // Return the item as a string
if(item === undefined) { if(item === undefined) {
return undefined; return item;
} else if(item === null) { }
return ["null"] if(typeof item === "object") {
} else if(typeof item === "object") { if(item === null) {
var results = [],i,t; return ["null"];
if($tw.utils.isArray(item)) { }
// Return all the items in arrays recursively var results = [];
for(i=0; i<item.length; i++) { if($tw.utils.isArray(item)) {
t = convertDataItemValueToStrings(item[i]) $tw.utils.each(item,function(value) {
if(t !== undefined) { results.push.apply(results,convertDataItemValueToStrings(value));
results.push.apply(results,t); });
} return results;
} } else {
} else { $tw.utils.each(Object.keys(item).sort(),function(key) {
// Return all the values in objects recursively results.push.apply(results,convertDataItemValueToStrings(item[key]));
$tw.utils.each(Object.keys(item).sort(),function(key) { });
t = convertDataItemValueToStrings(item[key]); return results;
if(t !== undefined) {
results.push.apply(results,t);
}
});
} }
return results;
} }
return [item.toString()]; return [item.toString()];
} }
@@ -176,11 +157,7 @@ function getDataItem(data,indexes) {
var item = data; var item = data;
for(var i=0; i<indexes.length; i++) { for(var i=0; i<indexes.length; i++) {
if(item !== undefined) { if(item !== undefined) {
if(item !== null && ["number","string","boolean"].indexOf(typeof item) === -1) { item = item[indexes[i]];
item = item[indexes[i]];
} else {
item = undefined;
}
} }
} }
return item; return item;

View File

@@ -26,14 +26,26 @@ exports.reduce = function(source,operator,options) {
accumulator = operator.operands[1] || ""; accumulator = operator.operands[1] || "";
for(var index=0; index<results.length; index++) { for(var index=0; index<results.length; index++) {
var title = results[index], var title = results[index],
list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),options.widget.makeFakeWidgetWithVariables({ list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),{
"currentTiddler": "" + title, getVariable: function(name) {
"..currentTiddler": options.widget.getVariable("currentTiddler"), switch(name) {
"accumulator": "" + accumulator, case "currentTiddler":
"index": "" + index, return "" + title;
"revIndex": "" + (results.length - 1 - index), case "..currentTiddler":
"length": "" + results.length return options.widget.getVariable("currentTiddler");
})); case "accumulator":
return "" + accumulator;
case "index":
return "" + index;
case "revIndex":
return "" + (results.length - 1 - index);
case "length":
return "" + results.length;
default:
return options.widget.getVariable(name);
}
}
});
if(list.length > 0) { if(list.length > 0) {
accumulator = "" + list[0]; accumulator = "" + list[0];
} }

View File

@@ -25,10 +25,18 @@ exports.sortsub = function(source,operator,options) {
inputTitles.push(title); inputTitles.push(title);
var r = filterFn.call(options.wiki,function(iterator) { var r = filterFn.call(options.wiki,function(iterator) {
iterator(options.wiki.getTiddler(title),title); iterator(options.wiki.getTiddler(title),title);
},options.widget.makeFakeWidgetWithVariables({ },{
"currentTiddler": "" + title, getVariable: function(name) {
"..currentTiddler": options.widget.getVariable("currentTiddler") switch(name) {
})); case "currentTiddler":
return "" + title;
case "..currentTiddler":
return options.widget.getVariable("currentTiddler");
default:
return options.widget.getVariable(name);
}
}
});
sortKeys.push(r[0] || ""); sortKeys.push(r[0] || "");
}); });
// Rather than sorting the titles array, we'll sort the indexes so that we can consult both arrays // Rather than sorting the titles array, we'll sort the indexes so that we can consult both arrays

View File

@@ -74,113 +74,6 @@ exports.join = makeStringReducingOperator(
},null },null
); );
var dmp = require("$:/core/modules/utils/diff-match-patch/diff_match_patch.js");
exports.levenshtein = makeStringBinaryOperator(
function(a,b) {
var dmpObject = new dmp.diff_match_patch(),
diffs = dmpObject.diff_main(a,b);
return [dmpObject.diff_levenshtein(diffs) + ""];
}
);
// these two functions are adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
function diffLineWordMode(text1,text2,mode) {
var dmpObject = new dmp.diff_match_patch();
var a = diffPartsToChars(text1,text2,mode);
var lineText1 = a.chars1;
var lineText2 = a.chars2;
var lineArray = a.lineArray;
var diffs = dmpObject.diff_main(lineText1,lineText2,false);
dmpObject.diff_charsToLines_(diffs,lineArray);
return diffs;
}
function diffPartsToChars(text1,text2,mode) {
var lineArray = [];
var lineHash = {};
lineArray[0] = '';
function diff_linesToPartsMunge_(text,mode) {
var chars = '';
var lineStart = 0;
var lineEnd = -1;
var lineArrayLength = lineArray.length,
regexpResult;
var searchRegexp = /\W+/g;
while(lineEnd < text.length - 1) {
if(mode === "words") {
regexpResult = searchRegexp.exec(text);
lineEnd = searchRegexp.lastIndex;
if(regexpResult === null) {
lineEnd = text.length;
}
lineEnd = --lineEnd;
} else {
lineEnd = text.indexOf('\n', lineStart);
if(lineEnd == -1) {
lineEnd = text.length - 1;
}
}
var line = text.substring(lineStart, lineEnd + 1);
if(lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) : (lineHash[line] !== undefined)) {
chars += String.fromCharCode(lineHash[line]);
} else {
if (lineArrayLength == maxLines) {
line = text.substring(lineStart);
lineEnd = text.length;
}
chars += String.fromCharCode(lineArrayLength);
lineHash[line] = lineArrayLength;
lineArray[lineArrayLength++] = line;
}
lineStart = lineEnd + 1;
}
return chars;
}
var maxLines = 40000;
var chars1 = diff_linesToPartsMunge_(text1,mode);
maxLines = 65535;
var chars2 = diff_linesToPartsMunge_(text2,mode);
return {chars1: chars1, chars2: chars2, lineArray: lineArray};
};
exports.makepatches = function(source,operator,options) {
var dmpObject = new dmp.diff_match_patch(),
suffix = operator.suffix || "",
result = [];
source(function(tiddler,title) {
var diffs, patches;
if(suffix === "lines" || suffix === "words") {
diffs = diffLineWordMode(title,operator.operand,suffix);
patches = dmpObject.patch_make(title,diffs);
} else {
patches = dmpObject.patch_make(title,operator.operand);
}
Array.prototype.push.apply(result,[dmpObject.patch_toText(patches)]);
});
return result;
};
exports.applypatches = makeStringBinaryOperator(
function(a,b) {
var dmpObject = new dmp.diff_match_patch(),
patches;
try {
patches = dmpObject.patch_fromText(b);
} catch(e) {
}
if(patches) {
return [dmpObject.patch_apply(patches,a)[0]];
} else {
return [a];
}
}
);
function makeStringBinaryOperator(fnCalc) { function makeStringBinaryOperator(fnCalc) {
return function(source,operator,options) { return function(source,operator,options) {
var result = []; var result = [];
@@ -291,4 +184,4 @@ exports.charcode = function(source,operator,options) {
return [chars.join("")]; return [chars.join("")];
}; };
})(); })();

View File

@@ -1,45 +0,0 @@
/*\
title: $:/core/modules/filters/unknown.js
type: application/javascript
module-type: filteroperator
Filter operator for handling unknown filter operators.
Not intended to be used directly by end users, hence the square brackets around the name.
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var fieldFilterOperatorFn = require("$:/core/modules/filters/field.js").field;
/*
Export our filter function
*/
exports["[unknown]"] = function(source,operator,options) {
// Check for a user defined filter operator
if(operator.operator.charAt(0) === ".") {
var variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(operator.operator);
if(variableInfo && variableInfo.srcVariable && variableInfo.srcVariable.isFunctionDefinition) {
var list = options.widget.evaluateVariable(operator.operator,{params: operator.operands, source: source});
if(operator.prefix === "!") {
var results = [];
source(function(tiddler,title) {
if(list.indexOf(title) === -1) {
results.push(title);
}
});
return results;
} else {
return list;
}
}
}
// Otherwise, use the "field" operator
return fieldFilterOperatorFn(source,operator,options);
};
})();

View File

@@ -16,15 +16,9 @@ Filter operator for returning the names of the active variables
Export our filter function Export our filter function
*/ */
exports.variables = function(source,operator,options) { exports.variables = function(source,operator,options) {
var names = [], var names = [];
widget = options.widget; for(var variable in options.widget.variables) {
while(widget && !widget.hasOwnProperty("variables")) { names.push(variable);
widget = widget.parentWidget;
}
if(widget && widget.variables) {
for(var variable in widget.variables) {
names.push(variable);
}
} }
return names.sort(); return names.sort();
}; };

View File

@@ -32,18 +32,18 @@ FieldIndexer.prototype.setMaxIndexedValueLength = function(length) {
FieldIndexer.prototype.addIndexMethods = function() { FieldIndexer.prototype.addIndexMethods = function() {
var self = this; var self = this;
// get all tiddlers, including those overwrite shadow tiddlers
this.wiki.each.byField = function(name,value) { this.wiki.each.byField = function(name,value) {
var lookup = self.lookup(name,value); var titles = self.wiki.allTitles(),
lookup = self.lookup(name,value);
return lookup && lookup.filter(function(title) { return lookup && lookup.filter(function(title) {
return self.wiki.tiddlerExists(title) return titles.indexOf(title) !== -1;
}); });
}; };
// get shadow tiddlers, including shadow tiddlers that is overwritten
this.wiki.eachShadow.byField = function(name,value) { this.wiki.eachShadow.byField = function(name,value) {
var lookup = self.lookup(name,value); var titles = self.wiki.allShadowTitles(),
lookup = self.lookup(name,value);
return lookup && lookup.filter(function(title) { return lookup && lookup.filter(function(title) {
return self.wiki.isShadowTiddler(title) return titles.indexOf(title) !== -1;
}); });
}; };
this.wiki.eachTiddlerPlusShadows.byField = function(name,value) { this.wiki.eachTiddlerPlusShadows.byField = function(name,value) {

View File

@@ -141,7 +141,6 @@ function KeyboardManager(options) {
this.shortcutKeysList = [], // Stores the shortcut-key descriptors this.shortcutKeysList = [], // Stores the shortcut-key descriptors
this.shortcutActionList = [], // Stores the corresponding action strings this.shortcutActionList = [], // Stores the corresponding action strings
this.shortcutParsedList = []; // Stores the parsed key descriptors this.shortcutParsedList = []; // Stores the parsed key descriptors
this.shortcutPriorityList = []; // Stores the parsed shortcut priority
this.lookupNames = ["shortcuts"]; this.lookupNames = ["shortcuts"];
this.lookupNames.push($tw.platform.isMac ? "shortcuts-mac" : "shortcuts-not-mac") this.lookupNames.push($tw.platform.isMac ? "shortcuts-mac" : "shortcuts-not-mac")
this.lookupNames.push($tw.platform.isWindows ? "shortcuts-windows" : "shortcuts-not-windows"); this.lookupNames.push($tw.platform.isWindows ? "shortcuts-windows" : "shortcuts-not-windows");
@@ -319,23 +318,12 @@ KeyboardManager.prototype.updateShortcutLists = function(tiddlerList) {
this.shortcutKeysList[i] = tiddlerFields.key !== undefined ? tiddlerFields.key : undefined; this.shortcutKeysList[i] = tiddlerFields.key !== undefined ? tiddlerFields.key : undefined;
this.shortcutActionList[i] = tiddlerFields.text; this.shortcutActionList[i] = tiddlerFields.text;
this.shortcutParsedList[i] = this.shortcutKeysList[i] !== undefined ? this.parseKeyDescriptors(this.shortcutKeysList[i]) : undefined; 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; var key, action;
for(var i=0; i<this.shortcutTiddlers.length; i++) { 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])) { if(this.shortcutParsedList[i] !== undefined && this.checkKeyDescriptors(event,this.shortcutParsedList[i])) {
key = this.shortcutParsedList[i]; key = this.shortcutParsedList[i];
action = this.shortcutActionList[i]; action = this.shortcutActionList[i];

View File

@@ -28,8 +28,6 @@ var AudioParser = function(type,text,options) {
element.attributes.src = {type: "string", value: "data:" + type + ";base64," + text}; element.attributes.src = {type: "string", value: "data:" + type + ";base64," + text};
} }
this.tree = [element]; this.tree = [element];
this.source = text;
this.type = type;
}; };
exports["audio/ogg"] = AudioParser; exports["audio/ogg"] = AudioParser;

View File

@@ -23,7 +23,7 @@ var BinaryParser = function(type,text,options) {
children: [{ children: [{
type: "transclude", type: "transclude",
attributes: { attributes: {
"$tiddler": {type: "string", value: BINARY_WARNING_MESSAGE} tiddler: {type: "string", value: BINARY_WARNING_MESSAGE}
} }
}] }]
}; };
@@ -38,7 +38,7 @@ var BinaryParser = function(type,text,options) {
children: [{ children: [{
type: "transclude", type: "transclude",
attributes: { attributes: {
"$tiddler": {type: "string", value: EXPORT_BUTTON_IMAGE} tiddler: {type: "string", value: EXPORT_BUTTON_IMAGE}
} }
}] }]
}; };
@@ -64,8 +64,6 @@ var BinaryParser = function(type,text,options) {
children: [warn, link] children: [warn, link]
} }
this.tree = [element]; this.tree = [element];
this.source = text;
this.type = type;
}; };
exports["application/octet-stream"] = BinaryParser; exports["application/octet-stream"] = BinaryParser;

View File

@@ -13,11 +13,6 @@ The CSV text parser processes CSV files into a table wrapped in a scrollable wid
"use strict"; "use strict";
var CsvParser = function(type,text,options) { var CsvParser = function(type,text,options) {
// Special handler for tab-delimited files
if (type === 'text/tab-delimited-values' && !options.separator) {
options.separator = "\t";
}
// Table framework // Table framework
this.tree = [{ this.tree = [{
"type": "scrollable", "children": [{ "type": "scrollable", "children": [{
@@ -29,35 +24,30 @@ var CsvParser = function(type,text,options) {
}] }]
}]; }];
// Split the text into lines // Split the text into lines
var lines = $tw.utils.parseCsvString(text, options), var lines = text.split(/\r?\n/mg),
tag = "th"; tag = "th";
var maxColumns = 0;
$tw.utils.each(lines, function(columns) {
maxColumns = Math.max(columns.length, maxColumns);
});
for(var line=0; line<lines.length; line++) { for(var line=0; line<lines.length; line++) {
var columns = lines[line]; var lineText = lines[line];
var row = { if(lineText) {
"type": "element", "tag": "tr", "children": [] var row = {
}; "type": "element", "tag": "tr", "children": []
for(var column=0; column<maxColumns; column++) { };
row.children.push({ var columns = lineText.split(",");
"type": "element", "tag": tag, "children": [{ for(var column=0; column<columns.length; column++) {
"type": "text", row.children.push({
"text": columns[column] || '' "type": "element", "tag": tag, "children": [{
}] "type": "text",
}); "text": columns[column]
}]
});
}
tag = "td";
this.tree[0].children[0].children[0].children.push(row);
} }
tag = "td";
this.tree[0].children[0].children[0].children.push(row);
} }
this.source = text;
this.type = type;
}; };
exports["text/csv"] = CsvParser; exports["text/csv"] = CsvParser;
exports["text/tab-delimited-values"] = CsvParser;
})(); })();

View File

@@ -29,8 +29,6 @@ var HtmlParser = function(type,text,options) {
if($tw.wiki.getTiddlerText("$:/config/HtmlParser/DisableSandbox","no") !== "yes") { if($tw.wiki.getTiddlerText("$:/config/HtmlParser/DisableSandbox","no") !== "yes") {
this.tree[0].attributes.sandbox = {type: "string", value: $tw.wiki.getTiddlerText("$:/config/HtmlParser/SandboxTokens","")}; this.tree[0].attributes.sandbox = {type: "string", value: $tw.wiki.getTiddlerText("$:/config/HtmlParser/SandboxTokens","")};
} }
this.source = text;
this.type = type;
}; };
exports["text/html"] = HtmlParser; exports["text/html"] = HtmlParser;

View File

@@ -28,8 +28,6 @@ var ImageParser = function(type,text,options) {
} }
} }
this.tree = [element]; this.tree = [element];
this.source = text;
this.type = type;
}; };
exports["image/svg+xml"] = ImageParser; exports["image/svg+xml"] = ImageParser;

View File

@@ -123,36 +123,6 @@ exports.parseStringLiteral = function(source,pos) {
} }
}; };
/*
Returns an array of {name:} with an optional "default" property. Options include:
requireParenthesis: require the parameter definition to be wrapped in parenthesis
*/
exports.parseParameterDefinition = function(paramString,options) {
options = options || {};
if(options.requireParenthesis) {
var parenMatch = /^\s*\((.*)\)\s*$/g.exec(paramString);
if(!parenMatch) {
return [];
}
paramString = parenMatch[1];
}
var params = [],
reParam = /\s*([^:),\s]+)(?:\s*:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|([^,"'\s]+)))?/mg,
paramMatch = reParam.exec(paramString);
while(paramMatch) {
// Save the parameter details
var paramInfo = {name: paramMatch[1]},
defaultValue = paramMatch[2] || paramMatch[3] || paramMatch[4] || paramMatch[5];
if(defaultValue !== undefined) {
paramInfo["default"] = defaultValue;
}
params.push(paramInfo);
// Look for the next parameter
paramMatch = reParam.exec(paramString);
}
return params;
};
exports.parseMacroParameters = function(node,source,pos) { exports.parseMacroParameters = function(node,source,pos) {
// Process parameters // Process parameters
var parameter = $tw.utils.parseMacroParameter(source,pos); var parameter = $tw.utils.parseMacroParameter(source,pos);
@@ -205,36 +175,7 @@ exports.parseMacroParameter = function(source,pos) {
}; };
/* /*
Look for a macro invocation. Returns null if not found, or {type: "transclude", attributes:, start:, end:} Look for a macro invocation. Returns null if not found, or {type: "macrocall", name:, parameters:, start:, end:}
*/
exports.parseMacroInvocationAsTransclusion = function(source,pos) {
var node = $tw.utils.parseMacroInvocation(source,pos);
if(node) {
var positionalName = 0,
transclusion = {
type: "transclude",
start: node.start,
end: node.end
};
$tw.utils.addAttributeToParseTreeNode(transclusion,"$variable",node.name);
$tw.utils.each(node.params,function(param) {
var name = param.name;
if(name) {
if(name.charAt(0) === "$") {
name = "$" + name;
}
$tw.utils.addAttributeToParseTreeNode(transclusion,{name: name,type: "string", value: param.value, start: param.start, end: param.end});
} else {
$tw.utils.addAttributeToParseTreeNode(transclusion,{name: (positionalName++) + "",type: "string", value: param.value, start: param.start, end: param.end});
}
});
return transclusion;
}
return node;
};
/*
Look for a macro invocation. Returns null if not found, or {type: "macrocall", name:, params:, start:, end:}
*/ */
exports.parseMacroInvocation = function(source,pos) { exports.parseMacroInvocation = function(source,pos) {
var node = { var node = {

View File

@@ -15,7 +15,7 @@ The PDF parser embeds a PDF viewer
var ImageParser = function(type,text,options) { var ImageParser = function(type,text,options) {
var element = { var element = {
type: "element", type: "element",
tag: "iframe", tag: "embed",
attributes: {} attributes: {}
}, },
src; src;
@@ -25,8 +25,6 @@ var ImageParser = function(type,text,options) {
element.attributes.src = {type: "string", value: "data:application/pdf;base64," + text}; element.attributes.src = {type: "string", value: "data:application/pdf;base64," + text};
} }
this.tree = [element]; this.tree = [element];
this.source = text;
this.type = type;
}; };
exports["application/pdf"] = ImageParser; exports["application/pdf"] = ImageParser;

View File

@@ -20,8 +20,6 @@ var TextParser = function(type,text,options) {
language: {type: "string", value: type} language: {type: "string", value: type}
} }
}]; }];
this.source = text;
this.type = type;
}; };
exports["text/plain"] = TextParser; exports["text/plain"] = TextParser;

View File

@@ -28,8 +28,6 @@ var VideoParser = function(type,text,options) {
element.attributes.src = {type: "string", value: "data:" + type + ";base64," + text}; element.attributes.src = {type: "string", value: "data:" + type + ";base64," + text};
} }
this.tree = [element]; this.tree = [element];
this.source = text;
this.type = type;
}; };
exports["video/ogg"] = VideoParser; exports["video/ogg"] = VideoParser;

View File

@@ -1,97 +0,0 @@
/*\
title: $:/core/modules/parsers/wikiparser/rules/fnprocdef.js
type: application/javascript
module-type: wikirule
Wiki pragma rule for function, procedure and widget definitions
```
\function name(param:defaultvalue,param2:defaultvalue)
definition text
\end
\procedure name(param:defaultvalue,param2:defaultvalue)
definition text
\end
\widget $mywidget(param:defaultvalue,param2:defaultvalue)
definition text
\end
```
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.name = "fnprocdef";
exports.types = {pragma: true};
/*
Instantiate parse rule
*/
exports.init = function(parser) {
this.parser = parser;
// Regexp to match
this.matchRegExp = /^\\(function|procedure|widget)\s+([^(\s]+)\((\s*([^)]*))?\)(\s*\r?\n)?/mg;
};
/*
Parse the most recent match
*/
exports.parse = function() {
// Move past the macro name and parameters
this.parser.pos = this.matchRegExp.lastIndex;
// Parse the parameters
var params = [];
if(this.match[3]) {
params = $tw.utils.parseParameterDefinition(this.match[4]);
}
// Is this a multiline definition?
var reEnd;
if(this.match[5]) {
// If so, the end of the body is marked with \end
reEnd = new RegExp("(\\r?\\n\\\\end[^\\S\\n\\r]*(?:" + $tw.utils.escapeRegExp(this.match[2]) + ")?(?:$|\\r?\\n))","mg");
} else {
// Otherwise, the end of the definition is marked by the end of the line
reEnd = /($|\r?\n)/mg;
// Move past any whitespace
this.parser.pos = $tw.utils.skipWhiteSpace(this.parser.source,this.parser.pos);
}
// Find the end of the definition
reEnd.lastIndex = this.parser.pos;
var text,
endMatch = reEnd.exec(this.parser.source);
if(endMatch) {
text = this.parser.source.substring(this.parser.pos,endMatch.index);
this.parser.pos = endMatch.index + endMatch[0].length;
} else {
// We didn't find the end of the definition, so we'll make it blank
text = "";
}
// Save the macro definition
var parseTreeNodes = [{
type: "set",
attributes: {},
children: [],
params: params
}];
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],"name",this.match[2]);
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],"value",text);
if(this.match[1] === "function") {
parseTreeNodes[0].isFunctionDefinition = true;
} else if(this.match[1] === "procedure") {
parseTreeNodes[0].isProcedureDefinition = true;
} else if(this.match[1] === "widget") {
parseTreeNodes[0].isWidgetDefinition = true;
}
if(this.parser.configTrimWhiteSpace) {
parseTreeNodes[0].configTrimWhiteSpace = true;
}
return parseTreeNodes;
};
})();

View File

@@ -93,6 +93,9 @@ exports.parseTag = function(source,pos,options) {
return null; return null;
} }
node.tag = token.match[1]; node.tag = token.match[1];
if(node.tag.slice(1).indexOf("$") !== -1) {
return null;
}
if(node.tag.charAt(0) === "$") { if(node.tag.charAt(0) === "$") {
node.type = node.tag.substr(1); node.type = node.tag.substr(1);
} }

View File

@@ -25,7 +25,7 @@ Instantiate parse rule
exports.init = function(parser) { exports.init = function(parser) {
this.parser = parser; this.parser = parser;
// Regexp to match // Regexp to match
this.matchRegExp = /\\import[^\S\n]/mg; this.matchRegExp = /^\\import[^\S\n]/mg;
}; };
/* /*

View File

@@ -27,7 +27,7 @@ exports.findNextMatch = function(startPos) {
var nextStart = startPos; var nextStart = startPos;
// Try parsing at all possible macrocall openers until we match // Try parsing at all possible macrocall openers until we match
while((nextStart = this.parser.source.indexOf("<<",nextStart)) >= 0) { while((nextStart = this.parser.source.indexOf("<<",nextStart)) >= 0) {
var nextCall = $tw.utils.parseMacroInvocationAsTransclusion(this.parser.source,nextStart); var nextCall = $tw.utils.parseMacroInvocation(this.parser.source,nextStart);
if(nextCall) { if(nextCall) {
var c = this.parser.source.charAt(nextCall.end); var c = this.parser.source.charAt(nextCall.end);
// Ensure EOL after parsed macro // Ensure EOL after parsed macro

View File

@@ -27,7 +27,7 @@ exports.findNextMatch = function(startPos) {
var nextStart = startPos; var nextStart = startPos;
// Try parsing at all possible macrocall openers until we match // Try parsing at all possible macrocall openers until we match
while((nextStart = this.parser.source.indexOf("<<",nextStart)) >= 0) { while((nextStart = this.parser.source.indexOf("<<",nextStart)) >= 0) {
this.nextCall = $tw.utils.parseMacroInvocationAsTransclusion(this.parser.source,nextStart); this.nextCall = $tw.utils.parseMacroInvocation(this.parser.source,nextStart);
if(this.nextCall) { if(this.nextCall) {
return nextStart; return nextStart;
} }

View File

@@ -27,7 +27,7 @@ Instantiate parse rule
exports.init = function(parser) { exports.init = function(parser) {
this.parser = parser; this.parser = parser;
// Regexp to match // Regexp to match
this.matchRegExp = /\\define\s+([^(\s]+)\(\s*([^)]*)\)(\s*\r?\n)?/mg; this.matchRegExp = /^\\define\s+([^(\s]+)\(\s*([^)]*)\)(\s*\r?\n)?/mg;
}; };
/* /*
@@ -58,7 +58,7 @@ exports.parse = function() {
var reEnd; var reEnd;
if(this.match[3]) { if(this.match[3]) {
// If so, the end of the body is marked with \end // If so, the end of the body is marked with \end
reEnd = new RegExp("(\\r?\\n[^\\S\\n\\r]*\\\\end[^\\S\\n\\r]*(?:" + $tw.utils.escapeRegExp(this.match[1]) + ")?(?:$|\\r?\\n))","mg"); reEnd = /(\r?\n\\end[^\S\n\r]*(?:$|\r?\n))/mg;
} else { } else {
// Otherwise, the end of the definition is marked by the end of the line // Otherwise, the end of the definition is marked by the end of the line
reEnd = /($|\r?\n)/mg; reEnd = /($|\r?\n)/mg;
@@ -77,16 +77,16 @@ exports.parse = function() {
text = ""; text = "";
} }
// Save the macro definition // Save the macro definition
var parseTreeNodes = [{ return [{
type: "set", type: "set",
attributes: {}, attributes: {
name: {type: "string", value: this.match[1]},
value: {type: "string", value: text}
},
children: [], children: [],
params: params, params: params,
isMacroDefinition: true isMacroDefinition: true
}]; }];
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],"name",this.match[1]);
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],"value",text);
return parseTreeNodes;
}; };
})(); })();

View File

@@ -1,60 +0,0 @@
/*\
title: $:/core/modules/parsers/wikiparser/rules/parameters.js
type: application/javascript
module-type: wikirule
Wiki pragma rule for parameter definitions
```
\parameters(param:defaultvalue,param2:defaultvalue)
definition text
```
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.name = "parameters";
exports.types = {pragma: true};
/*
Instantiate parse rule
*/
exports.init = function(parser) {
this.parser = parser;
// Regexp to match
this.matchRegExp = /^\\parameters\s*\(([^)]*)\)\s*\r?\n/mg;
};
/*
Parse the most recent match
*/
exports.parse = function() {
// Move past the macro name and parameters
this.parser.pos = this.matchRegExp.lastIndex;
// Parse the parameters
var params = $tw.utils.parseParameterDefinition(this.match[1]);
var attributes = Object.create(null),
orderedAttributes = [];
$tw.utils.each(params,function(param) {
var name = param.name;
// Parameter names starting with dollar must be escaped to double dollars for the parameters widget
if(name.charAt(0) === "$") {
name = "$" + name;
}
var attribute = {name: name, type: "string", value: param["default"] || ""};
attributes[name] = attribute;
orderedAttributes.push(attribute);
});
// Save the macro definition
return [{
type: "parameters",
attributes: attributes,
orderedAttributes: orderedAttributes
}];
};
})();

View File

@@ -1,68 +0,0 @@
/*\
title: $:/core/modules/parsers/wikiparser/rules/parsermode.js
type: application/javascript
module-type: wikirule
Wiki pragma rule for parser mode specifications
```
\parsermode block
\parsermode inline
```
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.name = "parsermode";
exports.types = {pragma: true};
/*
Instantiate parse rule
*/
exports.init = function(parser) {
this.parser = parser;
// Regexp to match
this.matchRegExp = /\\parsermode[^\S\n]/mg;
};
/*
Parse the most recent match
*/
exports.parse = function() {
// Move past the pragma invocation
this.parser.pos = this.matchRegExp.lastIndex;
// Parse whitespace delimited tokens terminated by a line break
var reMatch = /[^\S\n]*(\S+)|(\r?\n)/mg,
parserMode = undefined;
reMatch.lastIndex = this.parser.pos;
var match = reMatch.exec(this.parser.source);
while(match && match.index === this.parser.pos) {
this.parser.pos = reMatch.lastIndex;
// Exit if we've got the line break
if(match[2]) {
break;
}
// Process the token
if(match[1]) {
parserMode = match[1];
}
// Match the next token
match = reMatch.exec(this.parser.source);
}
// Process the tokens
if(parserMode !== undefined) {
if(parserMode === "block") {
this.parser.parseAsInline = false;
} else if(parserMode === "inline") {
this.parser.parseAsInline = true;
}
}
// No parse tree nodes to return
return [];
};
})();

View File

@@ -26,7 +26,7 @@ Instantiate parse rule
exports.init = function(parser) { exports.init = function(parser) {
this.parser = parser; this.parser = parser;
// Regexp to match // Regexp to match
this.matchRegExp = /\\rules[^\S\n]/mg; this.matchRegExp = /^\\rules[^\S\n]/mg;
}; };
/* /*

View File

@@ -41,6 +41,9 @@ exports.parse = function() {
var node = { var node = {
type: "element", type: "element",
tag: "span", tag: "span",
attributes: {
"class": {type: "string", value: "tc-inline-style"}
},
children: tree children: tree
}; };
if(classString) { if(classString) {
@@ -49,9 +52,6 @@ exports.parse = function() {
if(stylesString) { if(stylesString) {
$tw.utils.addAttributeToParseTreeNode(node,"style",stylesString); $tw.utils.addAttributeToParseTreeNode(node,"style",stylesString);
} }
if(!classString && !stylesString) {
$tw.utils.addClassToParseTreeNode(node,"tc-inline-style");
}
return [node]; return [node];
}; };

View File

@@ -23,7 +23,7 @@ exports.types = {block: true};
exports.init = function(parser) { exports.init = function(parser) {
this.parser = parser; this.parser = parser;
// Regexp to match // Regexp to match
this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?(?:\|([^\{\}]+))?\}\}(?:\r?\n|$)/mg; this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?\}\}(?:\r?\n|$)/mg;
}; };
exports.parse = function() { exports.parse = function() {
@@ -31,22 +31,13 @@ exports.parse = function() {
this.parser.pos = this.matchRegExp.lastIndex; this.parser.pos = this.matchRegExp.lastIndex;
// Get the match details // Get the match details
var template = $tw.utils.trim(this.match[2]), var template = $tw.utils.trim(this.match[2]),
textRef = $tw.utils.trim(this.match[1]), textRef = $tw.utils.trim(this.match[1]);
params = this.match[3] ? this.match[3].split("|") : [];
// Prepare the transclude widget // Prepare the transclude widget
var transcludeNode = { var transcludeNode = {
type: "transclude", type: "transclude",
attributes: {}, attributes: {},
isBlock: true isBlock: true
}; };
$tw.utils.each(params,function(paramValue,index) {
var name = "" + index;
transcludeNode.attributes[name] = {
name: name,
type: "string",
value: paramValue
}
});
// Prepare the tiddler widget // Prepare the tiddler widget
var tr, targetTitle, targetField, targetIndex, tiddlerNode; var tr, targetTitle, targetField, targetIndex, tiddlerNode;
if(textRef) { if(textRef) {
@@ -57,14 +48,14 @@ exports.parse = function() {
tiddlerNode = { tiddlerNode = {
type: "tiddler", type: "tiddler",
attributes: { attributes: {
tiddler: {name: "tiddler", type: "string", value: targetTitle} tiddler: {type: "string", value: targetTitle}
}, },
isBlock: true, isBlock: true,
children: [transcludeNode] children: [transcludeNode]
}; };
} }
if(template) { if(template) {
transcludeNode.attributes["$tiddler"] = {name: "$tiddler", type: "string", value: template}; transcludeNode.attributes.tiddler = {type: "string", value: template};
if(textRef) { if(textRef) {
return [tiddlerNode]; return [tiddlerNode];
} else { } else {
@@ -72,12 +63,12 @@ exports.parse = function() {
} }
} else { } else {
if(textRef) { if(textRef) {
transcludeNode.attributes["$tiddler"] = {name: "$tiddler", type: "string", value: targetTitle}; transcludeNode.attributes.tiddler = {type: "string", value: targetTitle};
if(targetField) { if(targetField) {
transcludeNode.attributes["$field"] = {name: "$field", type: "string", value: targetField}; transcludeNode.attributes.field = {type: "string", value: targetField};
} }
if(targetIndex) { if(targetIndex) {
transcludeNode.attributes["$index"] = {name: "$index", type: "string", value: targetIndex}; transcludeNode.attributes.index = {type: "string", value: targetIndex};
} }
return [tiddlerNode]; return [tiddlerNode];
} else { } else {

View File

@@ -23,7 +23,7 @@ exports.types = {inline: true};
exports.init = function(parser) { exports.init = function(parser) {
this.parser = parser; this.parser = parser;
// Regexp to match // Regexp to match
this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?(?:\|([^\{\}]+))?\}\}/mg; this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?\}\}/mg;
}; };
exports.parse = function() { exports.parse = function() {
@@ -31,21 +31,12 @@ exports.parse = function() {
this.parser.pos = this.matchRegExp.lastIndex; this.parser.pos = this.matchRegExp.lastIndex;
// Get the match details // Get the match details
var template = $tw.utils.trim(this.match[2]), var template = $tw.utils.trim(this.match[2]),
textRef = $tw.utils.trim(this.match[1]), textRef = $tw.utils.trim(this.match[1]);
params = this.match[3] ? this.match[3].split("|") : [];
// Prepare the transclude widget // Prepare the transclude widget
var transcludeNode = { var transcludeNode = {
type: "transclude", type: "transclude",
attributes: {} attributes: {}
}; };
$tw.utils.each(params,function(paramValue,index) {
var name = "" + index;
transcludeNode.attributes[name] = {
name: name,
type: "string",
value: paramValue
}
});
// Prepare the tiddler widget // Prepare the tiddler widget
var tr, targetTitle, targetField, targetIndex, tiddlerNode; var tr, targetTitle, targetField, targetIndex, tiddlerNode;
if(textRef) { if(textRef) {
@@ -56,13 +47,13 @@ exports.parse = function() {
tiddlerNode = { tiddlerNode = {
type: "tiddler", type: "tiddler",
attributes: { attributes: {
tiddler: {name: "tiddler", type: "string", value: targetTitle} tiddler: {type: "string", value: targetTitle}
}, },
children: [transcludeNode] children: [transcludeNode]
}; };
} }
if(template) { if(template) {
transcludeNode.attributes["$tiddler"] = {name: "$tiddler", type: "string", value: template}; transcludeNode.attributes.tiddler = {type: "string", value: template};
if(textRef) { if(textRef) {
return [tiddlerNode]; return [tiddlerNode];
} else { } else {
@@ -70,12 +61,12 @@ exports.parse = function() {
} }
} else { } else {
if(textRef) { if(textRef) {
transcludeNode.attributes["$tiddler"] = {name: "$tiddler", type: "string", value: targetTitle}; transcludeNode.attributes.tiddler = {type: "string", value: targetTitle};
if(targetField) { if(targetField) {
transcludeNode.attributes["$field"] = {name: "$field", type: "string", value: targetField}; transcludeNode.attributes.field = {type: "string", value: targetField};
} }
if(targetIndex) { if(targetIndex) {
transcludeNode.attributes["$index"] = {name: "$index", type: "string", value: targetIndex}; transcludeNode.attributes.index = {type: "string", value: targetIndex};
} }
return [tiddlerNode]; return [tiddlerNode];
} else { } else {

View File

@@ -26,7 +26,7 @@ Instantiate parse rule
exports.init = function(parser) { exports.init = function(parser) {
this.parser = parser; this.parser = parser;
// Regexp to match // Regexp to match
this.matchRegExp = /\\whitespace[^\S\n]/mg; this.matchRegExp = /^\\whitespace[^\S\n]/mg;
}; };
/* /*

View File

@@ -32,7 +32,6 @@ options: see below:
parseAsInline: true to parse text as inline instead of block parseAsInline: true to parse text as inline instead of block
wiki: reference to wiki to use wiki: reference to wiki to use
_canonical_uri: optional URI of content if text is missing or empty _canonical_uri: optional URI of content if text is missing or empty
configTrimWhiteSpace: true to trim whitespace
*/ */
var WikiParser = function(type,text,options) { var WikiParser = function(type,text,options) {
this.wiki = options.wiki; this.wiki = options.wiki;
@@ -47,9 +46,7 @@ var WikiParser = function(type,text,options) {
this.source = text || ""; this.source = text || "";
this.sourceLength = this.source.length; this.sourceLength = this.source.length;
// Flag for ignoring whitespace // Flag for ignoring whitespace
this.configTrimWhiteSpace = options.configTrimWhiteSpace !== undefined ? options.configTrimWhiteSpace : false; this.configTrimWhiteSpace = false;
// Parser mode
this.parseAsInline = options.parseAsInline;
// Set current parse position // Set current parse position
this.pos = 0; this.pos = 0;
// Start with empty output // Start with empty output
@@ -86,7 +83,7 @@ var WikiParser = function(type,text,options) {
// Parse any pragmas // Parse any pragmas
var topBranch = this.parsePragmas(); var topBranch = this.parsePragmas();
// Parse the text into inline runs or blocks // Parse the text into inline runs or blocks
if(this.parseAsInline) { if(options.parseAsInline) {
topBranch.push.apply(topBranch,this.parseInlineRun()); topBranch.push.apply(topBranch,this.parseInlineRun());
} else { } else {
topBranch.push.apply(topBranch,this.parseBlocks()); topBranch.push.apply(topBranch,this.parseBlocks());
@@ -119,7 +116,7 @@ WikiParser.prototype.loadRemoteTiddler = function(url) {
*/ */
WikiParser.prototype.setupRules = function(proto,configPrefix) { WikiParser.prototype.setupRules = function(proto,configPrefix) {
var self = this; var self = this;
if(!$tw.safeMode) { if(!$tw.safemode) {
$tw.utils.each(proto,function(object,name) { $tw.utils.each(proto,function(object,name) {
if(self.wiki.getTiddlerText(configPrefix + name,"enable") !== "enable") { if(self.wiki.getTiddlerText(configPrefix + name,"enable") !== "enable") {
delete proto[name]; delete proto[name];

View File

@@ -0,0 +1,64 @@
/*\
title: $:/core/modules/savers/beaker.js
type: application/javascript
module-type: saver
Saves files using the Beaker browser's (https://beakerbrowser.com) Dat protocol (https://datproject.org/)
Compatible with beaker >= V0.7.2
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Set up the saver
*/
var BeakerSaver = function(wiki) {
this.wiki = wiki;
};
BeakerSaver.prototype.save = function(text,method,callback) {
var dat = new DatArchive("" + window.location),
pathname = ("" + window.location.pathname).split("#")[0];
dat.stat(pathname).then(function(value) {
if(value.isDirectory()) {
pathname = pathname + "/index.html";
}
dat.writeFile(pathname,text,"utf8").then(function(value) {
callback(null);
},function(reason) {
callback("Beaker Saver Write Error: " + reason);
});
},function(reason) {
callback("Beaker Saver Stat Error: " + reason);
});
return true;
};
/*
Information about this saver
*/
BeakerSaver.prototype.info = {
name: "beaker",
priority: 3000,
capabilities: ["save", "autosave"]
};
/*
Static method that returns true if this saver is capable of working
*/
exports.canSave = function(wiki) {
return !!window.DatArchive && location.protocol==="dat:";
};
/*
Create an instance of this saver
*/
exports.create = function(wiki) {
return new BeakerSaver(wiki);
};
})();

View File

@@ -0,0 +1,64 @@
/*\
title: $:/core/modules/savers/hyperdrive.js
type: application/javascript
module-type: saver
Saves files using the Hyperdrive Protocol (https://hypercore-protocol.org/#hyperdrive) Beaker browser beta-1.0 and later (https://beakerbrowser.com)
Compatible with beaker >= V1.0.0
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Set up the saver
*/
var HyperdriveSaver = function(wiki) {
this.wiki = wiki;
};
HyperdriveSaver.prototype.save = function(text,method,callback) {
var dat = beaker.hyperdrive.drive("" + window.location),
pathname = ("" + window.location.pathname).split("#")[0];
dat.stat(pathname).then(function(value) {
if(value.isDirectory()) {
pathname = pathname + "/index.html";
}
dat.writeFile(pathname,text,"utf8").then(function(value) {
callback(null);
},function(reason) {
callback("Hyperdrive Saver Write Error: " + reason);
});
},function(reason) {
callback("Hyperdrive Saver Stat Error: " + reason);
});
return true;
};
/*
Information about this saver
*/
HyperdriveSaver.prototype.info = {
name: "beaker-1.x",
priority: 3000,
capabilities: ["save", "autosave"]
};
/*
Static method that returns true if this saver is capable of working
*/
exports.canSave = function(wiki) {
return !!window.beaker && !!beaker.hyperdrive && location.protocol==="hyper:";
};
/*
Create an instance of this saver
*/
exports.create = function(wiki) {
return new HyperdriveSaver(wiki);
};
})();

View File

@@ -21,7 +21,6 @@ exports.handler = function(request,response,state) {
username: state.authenticatedUsername || state.server.get("anon-username") || "", username: state.authenticatedUsername || state.server.get("anon-username") || "",
anonymous: !state.authenticatedUsername, anonymous: !state.authenticatedUsername,
read_only: !state.server.isAuthorized("writers",state.authenticatedUsername), read_only: !state.server.isAuthorized("writers",state.authenticatedUsername),
logout_is_available: false,
space: { space: {
recipe: "default" recipe: "default"
}, },

View File

@@ -30,16 +30,6 @@ exports.handler = function(request,response,state) {
if(fields.revision) { if(fields.revision) {
delete 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})); state.wiki.addTiddler(new $tw.Tiddler(fields,{title: title}));
var changeCount = state.wiki.getChangeCount(title).toString(); var changeCount = state.wiki.getChangeCount(title).toString();
response.writeHead(204, "OK",{ response.writeHead(204, "OK",{

View File

@@ -359,9 +359,8 @@ 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) // 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() { server.on("listening",function() {
var address = server.address(), var address = server.address();
url = self.protocol + "://" + (address.family === "IPv6" ? "[" + address.address + "]" : address.address) + ":" + address.port + prefix; $tw.utils.log("Serving on " + self.protocol + "://" + address.address + ":" + address.port + prefix,"brown/orange");
$tw.utils.log("Serving on " + url,"brown/orange");
$tw.utils.log("(press ctrl-C to exit)","red"); $tw.utils.log("(press ctrl-C to exit)","red");
}); });
// Listen // Listen

View File

@@ -62,14 +62,12 @@ function loadIFrame(url,callback) {
Unload library iframe for given url Unload library iframe for given url
*/ */
function unloadIFrame(url){ function unloadIFrame(url){
var iframes = document.getElementsByTagName('iframe'); $tw.utils.each(document.getElementsByTagName('iframe'), function(iframe) {
for(var t=iframes.length-1; t--; t>=0) {
var iframe = iframes[t];
if(iframe.getAttribute("library") === "true" && if(iframe.getAttribute("library") === "true" &&
iframe.getAttribute("src") === url) { iframe.getAttribute("src") === url) {
iframe.parentNode.removeChild(iframe); iframe.parentNode.removeChild(iframe);
} }
} });
} }
function saveIFrameInfoTiddler(iframeInfo) { function saveIFrameInfoTiddler(iframeInfo) {

View File

@@ -87,6 +87,13 @@ exports.startup = function() {
} }
}); });
} }
// If we're being viewed on a data: URI then give instructions for how to save
if(document.location.protocol === "data:") {
$tw.rootWidget.dispatchEvent({
type: "tm-modal",
param: "$:/language/Modals/SaveInstructions"
});
}
}; };
})(); })();

View File

@@ -121,11 +121,7 @@ exports.startup = function() {
}); });
// Set up the syncer object if we've got a syncadaptor // Set up the syncer object if we've got a syncadaptor
if($tw.syncadaptor) { if($tw.syncadaptor) {
$tw.syncer = new $tw.Syncer({ $tw.syncer = new $tw.Syncer({wiki: $tw.wiki, syncadaptor: $tw.syncadaptor});
wiki: $tw.wiki,
syncadaptor: $tw.syncadaptor,
logging: $tw.wiki.getTiddlerText('$:/config/SyncLogging', "yes") === "yes"
});
} }
// Setup the saver handler // Setup the saver handler
$tw.saverHandler = new $tw.SaverHandler({ $tw.saverHandler = new $tw.SaverHandler({

View File

@@ -54,9 +54,7 @@ exports.startup = function() {
var hash = $tw.utils.getLocationHash(); var hash = $tw.utils.getLocationHash();
if(hash !== $tw.locationHash) { if(hash !== $tw.locationHash) {
$tw.locationHash = hash; $tw.locationHash = hash;
if(hash !== "#") { openStartupTiddlers({defaultToCurrentStory: true});
openStartupTiddlers({defaultToCurrentStory: true});
}
} }
},false); },false);
// Listen for the tm-browser-refresh message // Listen for the tm-browser-refresh message

View File

@@ -17,10 +17,6 @@ var easing = "cubic-bezier(0.645, 0.045, 0.355, 1)"; // From http://easings.net/
var ZoominListView = function(listWidget) { var ZoominListView = function(listWidget) {
var self = this; var self = this;
this.listWidget = listWidget; this.listWidget = listWidget;
this.textNodeLogger = new $tw.utils.Logger("zoomin story river view", {
enable: true,
colour: 'red'
});
// Get the index of the tiddler that is at the top of the history // Get the index of the tiddler that is at the top of the history
var history = this.listWidget.wiki.getTiddlerDataCached(this.listWidget.historyTitle,[]), var history = this.listWidget.wiki.getTiddlerDataCached(this.listWidget.historyTitle,[]),
targetTiddler; targetTiddler;
@@ -52,10 +48,7 @@ ZoominListView.prototype.navigateTo = function(historyInfo) {
var listItemWidget = this.listWidget.children[listElementIndex], var listItemWidget = this.listWidget.children[listElementIndex],
targetElement = listItemWidget.findFirstDomNode(); targetElement = listItemWidget.findFirstDomNode();
// Abandon if the list entry isn't a DOM element (it might be a text node) // Abandon if the list entry isn't a DOM element (it might be a text node)
if(!targetElement) { if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
return;
} else if (targetElement.nodeType === Node.TEXT_NODE) {
this.logTextNodeRoot(targetElement);
return; return;
} }
// Make the new tiddler be position absolute and visible so that we can measure it // Make the new tiddler be position absolute and visible so that we can measure it
@@ -137,10 +130,7 @@ function findTitleDomNode(widget,targetClass) {
ZoominListView.prototype.insert = function(widget) { ZoominListView.prototype.insert = function(widget) {
var targetElement = widget.findFirstDomNode(); var targetElement = widget.findFirstDomNode();
// Abandon if the list entry isn't a DOM element (it might be a text node) // Abandon if the list entry isn't a DOM element (it might be a text node)
if(!targetElement) { if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
return;
} else if (targetElement.nodeType === Node.TEXT_NODE) {
this.logTextNodeRoot(targetElement);
return; return;
} }
// Make the newly inserted node position absolute and hidden // Make the newly inserted node position absolute and hidden
@@ -183,21 +173,16 @@ ZoominListView.prototype.remove = function(widget) {
var toWidgetDomNode = toWidget && toWidget.findFirstDomNode(); var toWidgetDomNode = toWidget && toWidget.findFirstDomNode();
// Set up the tiddler we're moving back in // Set up the tiddler we're moving back in
if(toWidgetDomNode) { if(toWidgetDomNode) {
if (toWidgetDomNode.nodeType === Node.TEXT_NODE) { $tw.utils.addClass(toWidgetDomNode,"tc-storyview-zoomin-tiddler");
this.logTextNodeRoot(toWidgetDomNode); $tw.utils.setStyle(toWidgetDomNode,[
toWidgetDomNode = null; {display: "block"},
} else { {transformOrigin: "50% 50%"},
$tw.utils.addClass(toWidgetDomNode,"tc-storyview-zoomin-tiddler"); {transform: "translateX(0px) translateY(0px) scale(10)"},
$tw.utils.setStyle(toWidgetDomNode,[ {transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms " + easing + ", opacity " + duration + "ms " + easing},
{display: "block"}, {opacity: "0"},
{transformOrigin: "50% 50%"}, {zIndex: "500"}
{transform: "translateX(0px) translateY(0px) scale(10)"}, ]);
{transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms " + easing + ", opacity " + duration + "ms " + easing}, this.currentTiddlerDomNode = toWidgetDomNode;
{opacity: "0"},
{zIndex: "500"}
]);
this.currentTiddlerDomNode = toWidgetDomNode;
}
} }
// Animate them both // Animate them both
// Force layout // Force layout
@@ -221,10 +206,6 @@ ZoominListView.prototype.remove = function(widget) {
return true; // Indicate that we'll delete the DOM node return true; // Indicate that we'll delete the DOM node
}; };
ZoominListView.prototype.logTextNodeRoot = function(node) {
this.textNodeLogger.log($tw.language.getString("Error/ZoominTextNode") + " " + node.textContent);
};
exports.zoomin = ZoominListView; exports.zoomin = ZoominListView;
})(); })();

View File

@@ -402,7 +402,6 @@ Syncer.prototype.handleLazyLoadEvent = function(title) {
// Mark the tiddler as needing loading, and having already been lazily loaded // Mark the tiddler as needing loading, and having already been lazily loaded
this.titlesToBeLoaded[title] = true; this.titlesToBeLoaded[title] = true;
this.titlesHaveBeenLazyLoaded[title] = true; this.titlesHaveBeenLazyLoaded[title] = true;
this.processTaskQueue();
} }
} }
}; };

View File

@@ -12,113 +12,35 @@ A barebones CSV parser
/*global $tw: false */ /*global $tw: false */
"use strict"; "use strict";
var QUOTE = '"';
var getCellInfo = function(text, start, length, SEPARATOR) {
var isCellQuoted = text.charAt(start) === QUOTE;
var cellStart = isCellQuoted ? start + 1 : start;
if (text.charAt(i) === SEPARATOR) {
return [cellStart, cellStart, false];
}
for (var i = cellStart; i < length; i++) {
var cellCharacter = text.charAt(i);
var isEOL = cellCharacter === "\n" || cellCharacter === "\r";
if (isEOL && !isCellQuoted) {
return [cellStart, i, false];
} else if (cellCharacter === SEPARATOR && !isCellQuoted) {
return [cellStart, i, false];
} else if (cellCharacter === QUOTE && isCellQuoted) {
var nextCharacter = i + 1 < length ? text.charAt(i + 1) : '';
if (nextCharacter !== QUOTE) {
return [cellStart, i, true];
} else {
i++;
}
}
}
return [cellStart, i, isCellQuoted];
}
exports.parseCsvString = function(text, options) {
if (!text) {
return [];
}
options = options || {};
var SEPARATOR = options.separator || ",",
length = text.length,
rows = [],
nextRow = [];
for (var i = 0; i < length; i++) {
var cellInfo = getCellInfo(text, i, length, SEPARATOR);
var cellText = text.substring(cellInfo[0], cellInfo[1]);
if (cellInfo[2]) {
cellText = cellText.replace(/""/g, '"');
cellInfo[1]++;
}
nextRow.push(cellText);
i = cellInfo[1];
var character = text.charAt(i);
var nextCharacter = i + 1 < length ? text.charAt(i + 1) : '';
if (character === "\r" || character === "\n") {
// Edge case for empty rows
if (nextRow.length === 1 && nextRow[0] === '') {
nextRow.length = 0;
}
rows.push(nextRow);
nextRow = [];
if (character === "\r") {
var nextCharacter = i + 1 < length ? text.charAt(i + 1) : '';
if (nextCharacter === "\n") {
i++;
}
}
}
}
// Special case if last cell in last row is an empty cell
if (text.charAt(length - 1) === SEPARATOR) {
nextRow.push("");
}
rows.push(nextRow);
return rows;
}
/* /*
Parse a CSV string with a header row and return an array of hashmaps. Parse a CSV string with a header row and return an array of hashmaps.
*/ */
exports.parseCsvStringWithHeader = function(text,options) { exports.parseCsvStringWithHeader = function(text,options) {
var csv = $tw.utils.parseCsvString(text, options); options = options || {};
var headers = csv[0]; var separator = options.separator || ",",
rows = text.split(/\r?\n/mg).map(function(row) {
csv = csv.slice(1); return $tw.utils.trim(row);
for (var i = 0; i < csv.length; i++) { }).filter(function(row) {
var row = csv[i]; return row !== "";
var rowObject = Object.create(null); });
if(rows.length < 1) {
for(var columnIndex=0; columnIndex<headers.length; columnIndex++) { return "Missing header row";
var columnName = headers[columnIndex];
if (columnName) {
rowObject[columnName] = $tw.utils.trim(row[columnIndex] || "");
}
}
csv[i] = rowObject;
} }
return csv; var headings = rows[0].split(separator),
results = [];
for(var row=1; row<rows.length; row++) {
var columns = rows[row].split(separator),
columnResult = Object.create(null);
if(columns.length !== headings.length) {
return "Malformed CSV row '" + rows[row] + "'";
}
for(var column=0; column<columns.length; column++) {
var columnName = headings[column];
columnResult[columnName] = $tw.utils.trim(columns[column] || "");
}
results.push(columnResult);
}
return results;
} }
})(); })();

View File

@@ -12,8 +12,6 @@ Various static DOM-related utility functions.
/*global $tw: false */ /*global $tw: false */
"use strict"; "use strict";
var Popup = require("$:/core/modules/utils/dom/popup.js");
/* /*
Determines whether element 'a' contains element 'b' Determines whether element 'a' contains element 'b'
Code thanks to John Resig, http://ejohn.org/blog/comparing-document-position/ Code thanks to John Resig, http://ejohn.org/blog/comparing-document-position/
@@ -28,24 +26,6 @@ exports.domMatchesSelector = function(node,selector) {
return node.matches ? node.matches(selector) : node.msMatchesSelector(selector); return node.matches ? node.matches(selector) : node.msMatchesSelector(selector);
}; };
/*
Select text in a an input or textarea (setSelectionRange crashes on certain input types)
*/
exports.setSelectionRangeSafe = function(node,start,end,direction) {
try {
node.setSelectionRange(start,end,direction);
} catch(e) {
node.select();
}
};
/*
Select the text in an input or textarea by position
*/
exports.setSelectionByPosition = function(node,selectFromStart,selectFromEnd) {
$tw.utils.setSelectionRangeSafe(node,selectFromStart,node.value.length - selectFromEnd);
};
exports.removeChildren = function(node) { exports.removeChildren = function(node) {
while(node.hasChildNodes()) { while(node.hasChildNodes()) {
node.removeChild(node.firstChild); node.removeChild(node.firstChild);
@@ -314,21 +294,8 @@ exports.collectDOMVariables = function(selectedNode,domNode,event) {
}); });
if(selectedNode.offsetLeft) { if(selectedNode.offsetLeft) {
// Add variables with a (relative and absolute) popup coordinate string for the selected node // Add a variable with a popup coordinate string for the selected node
var nodeRect = { variables["tv-popup-coords"] = "(" + selectedNode.offsetLeft + "," + selectedNode.offsetTop +"," + selectedNode.offsetWidth + "," + selectedNode.offsetHeight + ")";
left: selectedNode.offsetLeft,
top: selectedNode.offsetTop,
width: selectedNode.offsetWidth,
height: selectedNode.offsetHeight
};
variables["tv-popup-coords"] = Popup.buildCoordinates(Popup.coordinatePrefix.csOffsetParent,nodeRect);
var absRect = $tw.utils.extend({}, nodeRect);
for (var currentNode = selectedNode.offsetParent; currentNode; currentNode = currentNode.offsetParent) {
absRect.left += currentNode.offsetLeft;
absRect.top += currentNode.offsetTop;
}
variables["tv-popup-abs-coords"] = Popup.buildCoordinates(Popup.coordinatePrefix.csAbsolute,absRect);
// Add variables for offset of selected node // Add variables for offset of selected node
variables["tv-selectednode-posx"] = selectedNode.offsetLeft.toString(); variables["tv-selectednode-posx"] = selectedNode.offsetLeft.toString();

View File

@@ -25,13 +25,14 @@ widget: widget to use as the context for the filter
exports.makeDraggable = function(options) { exports.makeDraggable = function(options) {
var dragImageType = options.dragImageType || "dom", var dragImageType = options.dragImageType || "dom",
dragImage, dragImage,
domNode = options.domNode; domNode = options.domNode,
dragHandle = options.selector && domNode.querySelector(options.selector) || domNode;
// Make the dom node draggable (not necessary for anchor tags) // Make the dom node draggable (not necessary for anchor tags)
if(!options.selector && ((domNode.tagName || "").toLowerCase() !== "a")) { if((domNode.tagName || "").toLowerCase() !== "a") {
domNode.setAttribute("draggable","true"); dragHandle.setAttribute("draggable","true");
} }
// Add event handlers // Add event handlers
$tw.utils.addEventListeners(domNode,[ $tw.utils.addEventListeners(dragHandle,[
{name: "dragstart", handlerFunction: function(event) { {name: "dragstart", handlerFunction: function(event) {
if(event.dataTransfer === undefined) { if(event.dataTransfer === undefined) {
return false; return false;
@@ -40,19 +41,19 @@ exports.makeDraggable = function(options) {
var dragTiddler = options.dragTiddlerFn && options.dragTiddlerFn(), var dragTiddler = options.dragTiddlerFn && options.dragTiddlerFn(),
dragFilter = options.dragFilterFn && options.dragFilterFn(), dragFilter = options.dragFilterFn && options.dragFilterFn(),
titles = dragTiddler ? [dragTiddler] : [], titles = dragTiddler ? [dragTiddler] : [],
startActions = options.startActions, startActions = options.startActions,
variables, variables,
domNodeRect; domNodeRect;
if(dragFilter) { if(dragFilter) {
titles.push.apply(titles,options.widget.wiki.filterTiddlers(dragFilter,options.widget)); titles.push.apply(titles,options.widget.wiki.filterTiddlers(dragFilter,options.widget));
} }
var titleString = $tw.utils.stringifyList(titles); var titleString = $tw.utils.stringifyList(titles);
// Check that we've something to drag // Check that we've something to drag
if(titles.length > 0 && (options.selector && $tw.utils.domMatchesSelector(event.target,options.selector) || event.target === domNode)) { if(titles.length > 0 && event.target === dragHandle) {
// Mark the drag in progress // Mark the drag in progress
$tw.dragInProgress = domNode; $tw.dragInProgress = domNode;
// Set the dragging class on the element being dragged // Set the dragging class on the element being dragged
$tw.utils.addClass(domNode,"tc-dragging"); $tw.utils.addClass(event.target,"tc-dragging");
// Invoke drag-start actions if given // Invoke drag-start actions if given
if(startActions !== undefined) { if(startActions !== undefined) {
// Collect our variables // Collect our variables
@@ -106,22 +107,21 @@ exports.makeDraggable = function(options) {
dataTransfer.setData("text/vnd.tiddler",jsonData); dataTransfer.setData("text/vnd.tiddler",jsonData);
dataTransfer.setData("text/plain",titleString); dataTransfer.setData("text/plain",titleString);
dataTransfer.setData("text/x-moz-url","data:text/vnd.tiddler," + encodeURIComponent(jsonData)); 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); dataTransfer.setData("Text",titleString);
event.stopPropagation(); event.stopPropagation();
} }
return false; return false;
}}, }},
{name: "dragend", handlerFunction: function(event) { {name: "dragend", handlerFunction: function(event) {
if((options.selector && $tw.utils.domMatchesSelector(event.target,options.selector)) || event.target === domNode) { if(event.target === domNode) {
// Collect the tiddlers being dragged // Collect the tiddlers being dragged
var dragTiddler = options.dragTiddlerFn && options.dragTiddlerFn(), var dragTiddler = options.dragTiddlerFn && options.dragTiddlerFn(),
dragFilter = options.dragFilterFn && options.dragFilterFn(), dragFilter = options.dragFilterFn && options.dragFilterFn(),
titles = dragTiddler ? [dragTiddler] : [], titles = dragTiddler ? [dragTiddler] : [],
endActions = options.endActions, endActions = options.endActions,
variables; variables;
if(dragFilter) { if(dragFilter) {
titles.push.apply(titles,options.widget.wiki.filterTiddlers(dragFilter,options.widget)); 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); options.widget.invokeActionString(endActions,options.widget,event,variables);
} }
// Remove the dragging class on the element being dragged // Remove the dragging class on the element being dragged
$tw.utils.removeClass(domNode,"tc-dragging"); $tw.utils.removeClass(event.target,"tc-dragging");
// Delete the drag image element // Delete the drag image element
if(dragImage) { if(dragImage) {
dragImage.parentNode.removeChild(dragImage); dragImage.parentNode.removeChild(dragImage);

View File

@@ -26,8 +26,6 @@ Display a modal dialogue
options: see below options: see below
Options include: Options include:
downloadLink: Text of a big download link to include downloadLink: Text of a big download link to include
event: widget event
variables: from event.paramObject
*/ */
Modal.prototype.display = function(title,options) { Modal.prototype.display = function(title,options) {
options = options || {}; options = options || {};
@@ -211,10 +209,6 @@ Modal.prototype.display = function(title,options) {
headerWidgetNode.addEventListener("tm-close-tiddler",closeHandler,false); headerWidgetNode.addEventListener("tm-close-tiddler",closeHandler,false);
bodyWidgetNode.addEventListener("tm-close-tiddler",closeHandler,false); bodyWidgetNode.addEventListener("tm-close-tiddler",closeHandler,false);
footerWidgetNode.addEventListener("tm-close-tiddler",closeHandler,false); footerWidgetNode.addEventListener("tm-close-tiddler",closeHandler,false);
// Whether to close the modal dialog when the mask (area outside the modal) is clicked
if(tiddler.fields && (tiddler.fields["mask-closable"] === "yes" || tiddler.fields["mask-closable"] === "true")) {
modalBackdrop.addEventListener("click",closeHandler,false);
}
// Set the initial styles for the message // Set the initial styles for the message
$tw.utils.setStyle(modalBackdrop,[ $tw.utils.setStyle(modalBackdrop,[
{opacity: "0"} {opacity: "0"}

View File

@@ -36,9 +36,8 @@ Notifier.prototype.display = function(title,options) {
if(!tiddler) { if(!tiddler) {
return; return;
} }
// Add classes and roles // Add classes
$tw.utils.addClass(notification,"tc-notification"); $tw.utils.addClass(notification,"tc-notification");
notification.setAttribute("role","alert");
// Create the variables // Create the variables
var variables = $tw.utils.extend({currentTiddler: title},options.variables); var variables = $tw.utils.extend({currentTiddler: title},options.variables);
// Render the body of the notification // Render the body of the notification

View File

@@ -22,19 +22,6 @@ var Popup = function(options) {
this.popups = []; // Array of {title:,wiki:,domNode:} objects this.popups = []; // Array of {title:,wiki:,domNode:} objects
}; };
/*
Global regular expression for parsing the location of a popup.
This is also used by the Reveal widget.
*/
exports.popupLocationRegExp = /^(@?)\((-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+)\)$/
/*
Objekt containing the available prefixes for coordinates build with the `buildCoordinates` function:
- csOffsetParent: Uses a coordinate system based on the offset parent (no prefix).
- csAbsolute: Use an absolute coordinate system (prefix "@").
*/
exports.coordinatePrefix = { csOffsetParent: "", csAbsolute: "@" }
/* /*
Trigger a popup open or closed. Parameters are in a hashmap: Trigger a popup open or closed. Parameters are in a hashmap:
title: title of the tiddler where the popup details are stored title: title of the tiddler where the popup details are stored
@@ -149,17 +136,8 @@ Popup.prototype.show = function(options) {
height: options.domNode.offsetHeight height: options.domNode.offsetHeight
}; };
} }
if(options.absolute && options.domNode) { var popupRect = "(" + rect.left + "," + rect.top + "," +
// Walk the offsetParent chain and add the position of the offsetParents to make rect.width + "," + rect.height + ")";
// the position absolute to the root node of the page.
var currentNode = options.domNode.offsetParent;
while(currentNode) {
rect.left += currentNode.offsetLeft;
rect.top += currentNode.offsetTop;
currentNode = currentNode.offsetParent;
}
}
var popupRect = exports.buildCoordinates(options.absolute?exports.coordinatePrefix.csAbsolute:exports.coordinatePrefix.csOffsetParent,rect);
if(options.noStateReference) { if(options.noStateReference) {
options.wiki.setText(options.title,"text",undefined,popupRect); options.wiki.setText(options.title,"text",undefined,popupRect);
} else { } else {
@@ -194,54 +172,13 @@ Popup.prototype.cancel = function(level) {
}; };
/* /*
Returns true if the specified title and text identifies an active popup. Returns true if the specified title and text identifies an active popup
This function is safe to call, even if the popup class was not initialized.
*/ */
exports.readPopupState = function(text) { Popup.prototype.readPopupState = function(text) {
return exports.popupLocationRegExp.test(text); var popupLocationRegExp = /^\((-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+)\)$/;
return popupLocationRegExp.test(text);
}; };
/*
Parses a coordinate string in the format `(x,y,w,h)` or `@(x,y,z,h)` and returns
an object containing the position, width and height. The absolute-Mark is boolean
value that indicates the coordinate system of the coordinates. If they start with
an `@`, `absolute` is set to true and the coordinates are relative to the root
element. If the initial `@` is missing, they are relative to the offset parent
element and `absoute` is false.
This function is safe to call, even if the popup class was not initialized.
*/
exports.parseCoordinates = function(coordinates) {
var match = exports.popupLocationRegExp.exec(coordinates);
if(match) {
return {
absolute: (match[1] === "@"),
left: parseFloat(match[2]),
top: parseFloat(match[3]),
width: parseFloat(match[4]),
height: parseFloat(match[5])
};
} else {
return false;
}
}
/*
Builds a coordinate string from a coordinate system identifier and an object
containing the left, top, width and height values.
Use constants defined in coordinatePrefix to specify a coordinate system.
If one of the parameters is invalid for building a coordinate string `(0,0,0,0)`
will be returned.
This function is safe to call, even if the popup class was not initialized.
*/
exports.buildCoordinates = function(prefix,position) {
var coord = prefix + "(" + position.left + "," + position.top + "," + position.width + "," + position.height + ")";
if (exports.popupLocationRegExp.test(coord)) {
return coord;
} else {
return "(0,0,0,0)";
}
}
exports.Popup = Popup; exports.Popup = Popup;
})(); })();

View File

@@ -42,7 +42,7 @@ var TW_TextNode = function(text) {
this.textContent = text + ""; this.textContent = text + "";
}; };
Object.setPrototypeOf(TW_TextNode,TW_Node.prototype); TW_TextNode.prototype = Object.create(TW_Node.prototype);
Object.defineProperty(TW_TextNode.prototype, "nodeType", { Object.defineProperty(TW_TextNode.prototype, "nodeType", {
get: function() { get: function() {
@@ -67,7 +67,7 @@ var TW_Element = function(tag,namespace) {
this.namespaceURI = namespace || "http://www.w3.org/1999/xhtml"; this.namespaceURI = namespace || "http://www.w3.org/1999/xhtml";
}; };
Object.setPrototypeOf(TW_Element,TW_Node.prototype); TW_Element.prototype = Object.create(TW_Node.prototype);
Object.defineProperty(TW_Element.prototype, "style", { Object.defineProperty(TW_Element.prototype, "style", {
get: function() { get: function() {

View File

@@ -228,7 +228,7 @@ exports.generateTiddlerFileInfo = function(tiddler,options) {
hasUnsafeFields = hasUnsafeFields || /[\x00-\x1F]/mg.test(value); hasUnsafeFields = hasUnsafeFields || /[\x00-\x1F]/mg.test(value);
hasUnsafeFields = hasUnsafeFields || ($tw.utils.trim(value) !== value); hasUnsafeFields = hasUnsafeFields || ($tw.utils.trim(value) !== value);
} }
hasUnsafeFields = hasUnsafeFields || /:|#/mg.test(fieldName); hasUnsafeFields = hasUnsafeFields || /:/mg.test(fieldName);
}); });
// Check for field values // Check for field values
if(hasUnsafeFields) { if(hasUnsafeFields) {
@@ -238,7 +238,7 @@ exports.generateTiddlerFileInfo = function(tiddler,options) {
} else { } else {
// Save as a .tid or a text/binary file plus a .meta file // Save as a .tid or a text/binary file plus a .meta file
var tiddlerType = tiddler.fields.type || "text/vnd.tiddlywiki"; var tiddlerType = tiddler.fields.type || "text/vnd.tiddlywiki";
if(tiddlerType === "text/vnd.tiddlywiki" || tiddler.hasField("_canonical_uri")) { if(tiddlerType === "text/vnd.tiddlywiki") {
// Save as a .tid file // Save as a .tid file
fileInfo.type = "application/x-tiddler"; fileInfo.type = "application/x-tiddler";
fileInfo.hasMetaFile = false; fileInfo.hasMetaFile = false;
@@ -393,7 +393,7 @@ exports.generateTiddlerFilepath = function(title,options) {
} while(fs.existsSync(fullPath)); } while(fs.existsSync(fullPath));
// If the last write failed with an error, or if path does not start with: // If the last write failed with an error, or if path does not start with:
// the resolved options.directory, the resolved wikiPath directory, the wikiTiddlersPath directory, // the resolved options.directory, the resolved wikiPath directory, the wikiTiddlersPath directory,
// or the 'originalpath' directory, then $tw.utils.encodeURIComponentExtended() and resolve to tiddler directory. // or the 'originalpath' directory, then encodeURIComponent() and resolve to tiddler directory.
var writePath = $tw.hooks.invokeHook("th-make-tiddler-path",fullPath,fullPath), var writePath = $tw.hooks.invokeHook("th-make-tiddler-path",fullPath,fullPath),
encode = (options.fileInfo || {writeError: false}).writeError == true; encode = (options.fileInfo || {writeError: false}).writeError == true;
if(!encode) { if(!encode) {
@@ -403,7 +403,7 @@ exports.generateTiddlerFilepath = function(title,options) {
writePath.indexOf(path.resolve($tw.boot.wikiTiddlersPath,originalpath)) == 0 ); writePath.indexOf(path.resolve($tw.boot.wikiTiddlersPath,originalpath)) == 0 );
} }
if(encode) { if(encode) {
writePath = path.resolve(directory,$tw.utils.encodeURIComponentExtended(fullPath)); writePath = path.resolve(directory,encodeURIComponent(fullPath));
} }
// Return the full path to the file // Return the full path to the file
return writePath; return writePath;

View File

@@ -15,11 +15,10 @@ function LinkedList() {
LinkedList.prototype.clear = function() { LinkedList.prototype.clear = function() {
// LinkedList performs the duty of both the head and tail node // LinkedList performs the duty of both the head and tail node
this.next = new LLMap(); this.next = Object.create(null);
this.prev = new LLMap(); this.prev = Object.create(null);
// Linked list head initially points to itself this.first = undefined;
this.next.set(null, null); this.last = undefined;
this.prev.set(null, null);
this.length = 0; this.length = 0;
}; };
@@ -42,29 +41,28 @@ Push behaves like array.push and accepts multiple string arguments. But it also
accepts a single array argument too, to be consistent with its other methods. accepts a single array argument too, to be consistent with its other methods.
*/ */
LinkedList.prototype.push = function(/* values */) { LinkedList.prototype.push = function(/* values */) {
var i, values = arguments; var values = arguments;
if($tw.utils.isArray(values[0])) { if($tw.utils.isArray(values[0])) {
values = values[0]; values = values[0];
} }
for(i = 0; i < values.length; i++) { for(var i = 0; i < values.length; i++) {
_assertString(values[i]); _assertString(values[i]);
} }
for(i = 0; i < values.length; i++) { for(var i = 0; i < values.length; i++) {
_linkToEnd(this,values[i]); _linkToEnd(this,values[i]);
} }
return this.length; return this.length;
}; };
LinkedList.prototype.pushTop = function(value) { LinkedList.prototype.pushTop = function(value) {
var t;
if($tw.utils.isArray(value)) { if($tw.utils.isArray(value)) {
for (t=0; t<value.length; t++) { for (var t=0; t<value.length; t++) {
_assertString(value[t]); _assertString(value[t]);
} }
for(t=0; t<value.length; t++) { for(var t=0; t<value.length; t++) {
_removeOne(this,value[t]); _removeOne(this,value[t]);
} }
for(t=0; t<value.length; t++) { for(var t=0; t<value.length; t++) {
_linkToEnd(this,value[t]); _linkToEnd(this,value[t]);
} }
} else { } else {
@@ -76,11 +74,11 @@ LinkedList.prototype.pushTop = function(value) {
LinkedList.prototype.each = function(callback) { LinkedList.prototype.each = function(callback) {
var visits = Object.create(null), var visits = Object.create(null),
value = this.next.get(null); value = this.first;
while(value !== null) { while(value !== undefined) {
callback(value); callback(value);
var next = this.next.get(value); var next = this.next[value];
if(Array.isArray(next)) { if(typeof next === "object") {
var i = visits[value] || 0; var i = visits[value] || 0;
visits[value] = i+1; visits[value] = i+1;
value = next[i]; value = next[i];
@@ -107,79 +105,91 @@ LinkedList.prototype.makeTiddlerIterator = function(wiki) {
}; };
function _removeOne(list,value) { function _removeOne(list,value) {
var nextEntry = list.next.get(value); var prevEntry = list.prev[value],
if(nextEntry === undefined) { nextEntry = list.next[value],
return;
}
var prevEntry = list.prev.get(value),
prev = prevEntry, prev = prevEntry,
next = nextEntry, next = nextEntry;
ref; if(typeof nextEntry === "object") {
if(Array.isArray(nextEntry)) {
next = nextEntry[0]; next = nextEntry[0];
prev = prevEntry[0]; prev = prevEntry[0];
} }
// Relink preceding element. // Relink preceding element.
ref = list.next.get(prev); if(list.first === value) {
if(Array.isArray(ref)) { list.first = next
var i = ref.indexOf(value); } else if(prev !== undefined) {
ref[i] = next; if(typeof list.next[prev] === "object") {
if(next === undefined) {
// Must have been last, and 'i' would be last element.
list.next[prev].pop();
} else {
var i = list.next[prev].indexOf(value);
list.next[prev][i] = next;
}
} else {
list.next[prev] = next;
}
} else { } else {
list.next.set(prev,next); return;
} }
// Now relink following element // Now relink following element
ref = list.prev.get(next); // Check "next !== undefined" rather than "list.last === value" because
if(Array.isArray(ref)) { // we need to know if the FIRST value is the last in the list, not the last.
var i = ref.indexOf(value); if(next !== undefined) {
ref[i] = prev; if(typeof list.prev[next] === "object") {
if(prev === undefined) {
// Must have been first, and 'i' would be 0.
list.prev[next].shift();
} else {
var i = list.prev[next].indexOf(value);
list.prev[next][i] = prev;
}
} else {
list.prev[next] = prev;
}
} else { } else {
list.prev.set(next,prev); list.last = prev;
} }
// Delink actual value. If it uses arrays, just remove first entries. // Delink actual value. If it uses arrays, just remove first entries.
if(Array.isArray(nextEntry) && nextEntry.length > 1) { if(typeof nextEntry === "object") {
nextEntry.shift(); nextEntry.shift();
prevEntry.shift(); prevEntry.shift();
} else { } else {
list.next.set(value,undefined); list.next[value] = undefined;
list.prev.set(value,undefined); list.prev[value] = undefined;
} }
list.length -= 1; list.length -= 1;
}; };
// Sticks the given node onto the end of the list. // Sticks the given node onto the end of the list.
function _linkToEnd(list,value) { function _linkToEnd(list,value) {
var old = list.next.get(value); if(list.first === undefined) {
var last = list.prev.get(null); list.first = value;
// Does it already exists?
if(old !== undefined) {
if(!Array.isArray(old)) {
old = [old];
list.next.set(value,old);
list.prev.set(value,[list.prev.get(value)]);
}
old.push(null);
list.prev.get(value).push(last);
} else { } else {
list.next.set(value,null); // Does it already exists?
list.prev.set(value,last); if(list.first === value || list.prev[value] !== undefined) {
} if(typeof list.next[value] === "string") {
// Make the old last point to this new one. list.next[value] = [list.next[value]];
if(value !== last) { list.prev[value] = [list.prev[value]];
var array = list.next.get(last); } else if(typeof list.next[value] === "undefined") {
if(Array.isArray(array)) { // list.next[value] must be undefined.
array[array.length-1] = value; // Special case. List already has 1 value. It's at the end.
list.next[value] = [];
list.prev[value] = [list.prev[value]];
}
list.prev[value].push(list.last);
// We do NOT append a new value onto "next" list. Iteration will
// figure out it must point to End-of-List on its own.
} else { } else {
list.next.set(last,value); list.prev[value] = list.last;
}
// Make the old last point to this new one.
if(typeof list.next[list.last] === "object") {
list.next[list.last].push(value);
} else {
list.next[list.last] = value;
} }
list.prev.set(null,value);
} else {
// Edge case, the pushed value was already the last value.
// The second-to-last nextPtr for that value must point to itself now.
var array = list.next.get(last);
array[array.length-2] = value;
} }
list.last = value;
list.length += 1; list.length += 1;
}; };
@@ -189,20 +199,6 @@ function _assertString(value) {
} }
}; };
var LLMap = function() {
this.map = Object.create(null);
};
// Just a wrapper so our object map can also accept null.
LLMap.prototype = {
set: function(key,val) {
(key === null) ? (this.null = val) : (this.map[key] = val);
},
get: function(key) {
return (key === null) ? this.null : this.map[key];
}
};
exports.LinkedList = LinkedList; exports.LinkedList = LinkedList;
})(); })();

View File

@@ -48,9 +48,7 @@ Logger.prototype.log = function(/* args */) {
this.saveBufferLogger.buffer = this.saveBufferLogger.buffer.slice(-this.saveBufferLogger.saveLimit); this.saveBufferLogger.buffer = this.saveBufferLogger.buffer.slice(-this.saveBufferLogger.saveLimit);
} }
if(console !== undefined && console.log !== undefined) { if(console !== undefined && console.log !== undefined) {
var logMessage = [$tw.utils.terminalColour(this.colour) + this.componentName + ":"].concat(Array.prototype.slice.call(arguments,0)); 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()));
logMessage[logMessage.length-1] += $tw.utils.terminalColour();
return Function.apply.call(console.log, console, logMessage);
} }
} }
}; };

View File

@@ -12,26 +12,12 @@ Parse tree utility functions.
/*global $tw: false */ /*global $tw: false */
"use strict"; "use strict";
/*
Add attribute to parse tree node
Can be invoked as (node,name,value) or (node,attr)
*/
exports.addAttributeToParseTreeNode = function(node,name,value) { exports.addAttributeToParseTreeNode = function(node,name,value) {
var attribute = typeof name === "object" ? name : {name: name, type: "string", value: value}; var attribute = {name: name, type: "string", value: value};
name = attribute.name;
node.attributes = node.attributes || {}; node.attributes = node.attributes || {};
node.orderedAttributes = node.orderedAttributes || [];
node.attributes[name] = attribute; node.attributes[name] = attribute;
var foundIndex = -1; if(node.orderedAttributes) {
$tw.utils.each(node.orderedAttributes,function(attr,index) {
if(attr.name === name) {
foundIndex = index;
}
});
if(foundIndex === -1) {
node.orderedAttributes.push(attribute); node.orderedAttributes.push(attribute);
} else {
node.orderedAttributes[foundIndex] = attribute;
} }
}; };
@@ -65,8 +51,10 @@ exports.addClassToParseTreeNode = function(node,classString) {
// If the class attribute does not exist, we must create it first. // If the class attribute does not exist, we must create it first.
attribute = {name: "class", type: "string", value: ""}; attribute = {name: "class", type: "string", value: ""};
node.attributes["class"] = attribute; node.attributes["class"] = attribute;
node.orderedAttributes = node.orderedAttributes || []; if(node.orderedAttributes) {
node.orderedAttributes.push(attribute); // If there are orderedAttributes, we've got to add them there too.
node.orderedAttributes.push(attribute);
}
} }
if(attribute.type === "string") { if(attribute.type === "string") {
if(attribute.value !== "") { if(attribute.value !== "") {
@@ -86,8 +74,10 @@ exports.addStyleToParseTreeNode = function(node,name,value) {
if(!attribute) { if(!attribute) {
attribute = {name: "style", type: "string", value: ""}; attribute = {name: "style", type: "string", value: ""};
node.attributes.style = attribute; node.attributes.style = attribute;
node.orderedAttributes = node.orderedAttributes || []; if(node.orderedAttributes) {
node.orderedAttributes.push(attribute); // If there are orderedAttributes, we've got to add them there too.
node.orderedAttributes.push(attribute);
}
} }
if(attribute.type === "string") { if(attribute.type === "string") {
attribute.value += name + ":" + value + ";"; attribute.value += name + ":" + value + ";";

View File

@@ -354,9 +354,6 @@ exports.formatDateString = function(date,template) {
var result = "", var result = "",
t = template, t = template,
matches = [ matches = [
[/^TIMESTAMP/, function() {
return date.getTime();
}],
[/^0hh12/, function() { [/^0hh12/, function() {
return $tw.utils.pad($tw.utils.getHours12(date)); return $tw.utils.pad($tw.utils.getHours12(date));
}], }],
@@ -685,19 +682,9 @@ exports.escapeRegExp = function(s) {
return s.replace(/[\-\/\\\^\$\*\+\?\.\(\)\|\[\]\{\}]/g, '\\$&'); return s.replace(/[\-\/\\\^\$\*\+\?\.\(\)\|\[\]\{\}]/g, '\\$&');
}; };
/*
Extended version of encodeURIComponent that encodes additional characters including
those that are illegal within filepaths on various platforms including Windows
*/
exports.encodeURIComponentExtended = function(s) {
return encodeURIComponent(s).replace(/[!'()*]/g,function(c) {
return "%" + c.charCodeAt(0).toString(16).toUpperCase();
});
};
// Checks whether a link target is external, i.e. not a tiddler title // Checks whether a link target is external, i.e. not a tiddler title
exports.isLinkExternal = function(to) { exports.isLinkExternal = function(to) {
var externalRegExp = /^(?:file|http|https|mailto|ftp|irc|news|obsidian|data|skype):[^\s<>{}\[\]`|"\\^]+(?:\/|\b)/i; var externalRegExp = /^(?:file|http|https|mailto|ftp|irc|news|data|skype):[^\s<>{}\[\]`|"\\^]+(?:\/|\b)/i;
return externalRegExp.test(to); return externalRegExp.test(to);
}; };

View File

@@ -36,7 +36,7 @@ Compute the internal state of the widget
*/ */
DeleteFieldWidget.prototype.execute = function() { DeleteFieldWidget.prototype.execute = function() {
this.actionTiddler = this.getAttribute("$tiddler",this.getVariable("currentTiddler")); this.actionTiddler = this.getAttribute("$tiddler",this.getVariable("currentTiddler"));
this.actionField = this.getAttribute("$field",null); this.actionField = this.getAttribute("$field");
}; };
/* /*
@@ -59,7 +59,7 @@ DeleteFieldWidget.prototype.invokeAction = function(triggeringWidget,event) {
tiddler = this.wiki.getTiddler(self.actionTiddler), tiddler = this.wiki.getTiddler(self.actionTiddler),
removeFields = {}, removeFields = {},
hasChanged = false; hasChanged = false;
if((this.actionField !== null) && tiddler) { if(this.actionField && tiddler) {
removeFields[this.actionField] = undefined; removeFields[this.actionField] = undefined;
if(this.actionField in tiddler.fields) { if(this.actionField in tiddler.fields) {
hasChanged = true; hasChanged = true;

View File

@@ -14,8 +14,6 @@ Action widget to trigger a popup.
var Widget = require("$:/core/modules/widgets/widget.js").widget; var Widget = require("$:/core/modules/widgets/widget.js").widget;
var Popup = require("$:/core/modules/utils/dom/popup.js");
var ActionPopupWidget = function(parseTreeNode,options) { var ActionPopupWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options); this.initialise(parseTreeNode,options);
}; };
@@ -59,20 +57,20 @@ Invoke the action associated with this widget
*/ */
ActionPopupWidget.prototype.invokeAction = function(triggeringWidget,event) { ActionPopupWidget.prototype.invokeAction = function(triggeringWidget,event) {
// Trigger the popup // Trigger the popup
var coordinates = Popup.parseCoordinates(this.actionCoords || ""); var popupLocationRegExp = /^\((-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+)\)$/,
if(coordinates) { match = popupLocationRegExp.exec(this.actionCoords || "");
if(match) {
$tw.popup.triggerPopup({ $tw.popup.triggerPopup({
domNode: null, domNode: null,
domNodeRect: { domNodeRect: {
left: coordinates.left, left: parseFloat(match[1]),
top: coordinates.top, top: parseFloat(match[2]),
width: coordinates.width, width: parseFloat(match[3]),
height: coordinates.height height: parseFloat(match[4])
}, },
title: this.actionState, title: this.actionState,
wiki: this.wiki, wiki: this.wiki,
floating: this.floating, floating: this.floating
absolute: coordinates.absolute
}); });
} else { } else {
$tw.popup.cancel(0); $tw.popup.cancel(0);

View File

@@ -14,8 +14,6 @@ Button widget
var Widget = require("$:/core/modules/widgets/widget.js").widget; var Widget = require("$:/core/modules/widgets/widget.js").widget;
var Popup = require("$:/core/modules/utils/dom/popup.js");
var ButtonWidget = function(parseTreeNode,options) { var ButtonWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options); this.initialise(parseTreeNode,options);
}; };
@@ -48,8 +46,7 @@ ButtonWidget.prototype.render = function(parent,nextSibling) {
isPoppedUp = (this.popup || this.popupTitle) && this.isPoppedUp(); isPoppedUp = (this.popup || this.popupTitle) && this.isPoppedUp();
if(this.selectedClass) { if(this.selectedClass) {
if((this.set || this.setTitle) && this.setTo && this.isSelected()) { 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) { if(isPoppedUp) {
$tw.utils.pushTop(classes,this.selectedClass.split(" ")); $tw.utils.pushTop(classes,this.selectedClass.split(" "));
@@ -69,9 +66,6 @@ ButtonWidget.prototype.render = function(parent,nextSibling) {
if(this["aria-label"]) { if(this["aria-label"]) {
domNode.setAttribute("aria-label",this["aria-label"]); domNode.setAttribute("aria-label",this["aria-label"]);
} }
if (this.role) {
domNode.setAttribute("role", this.role);
}
if(this.popup || this.popupTitle) { if(this.popup || this.popupTitle) {
domNode.setAttribute("aria-expanded",isPoppedUp ? "true" : "false"); domNode.setAttribute("aria-expanded",isPoppedUp ? "true" : "false");
} }
@@ -149,7 +143,7 @@ ButtonWidget.prototype.isSelected = function() {
ButtonWidget.prototype.isPoppedUp = function() { ButtonWidget.prototype.isPoppedUp = function() {
var tiddler = this.popupTitle ? this.wiki.getTiddler(this.popupTitle) : this.wiki.getTiddler(this.popup); var tiddler = this.popupTitle ? this.wiki.getTiddler(this.popupTitle) : this.wiki.getTiddler(this.popup);
var result = tiddler && tiddler.fields.text ? Popup.readPopupState(tiddler.fields.text) : false; var result = tiddler && tiddler.fields.text ? $tw.popup.readPopupState(tiddler.fields.text) : false;
return result; return result;
}; };
@@ -175,7 +169,6 @@ ButtonWidget.prototype.triggerPopup = function(event) {
if(this.popupTitle) { if(this.popupTitle) {
$tw.popup.triggerPopup({ $tw.popup.triggerPopup({
domNode: this.domNodes[0], domNode: this.domNodes[0],
absolute: (this.popupAbsCoords === "yes"),
title: this.popupTitle, title: this.popupTitle,
wiki: this.wiki, wiki: this.wiki,
noStateReference: true noStateReference: true
@@ -183,7 +176,6 @@ ButtonWidget.prototype.triggerPopup = function(event) {
} else { } else {
$tw.popup.triggerPopup({ $tw.popup.triggerPopup({
domNode: this.domNodes[0], domNode: this.domNodes[0],
absolute: (this.popupAbsCoords === "yes"),
title: this.popup, title: this.popup,
wiki: this.wiki wiki: this.wiki
}); });
@@ -214,7 +206,6 @@ ButtonWidget.prototype.execute = function() {
this.popup = this.getAttribute("popup"); this.popup = this.getAttribute("popup");
this.hover = this.getAttribute("hover"); this.hover = this.getAttribute("hover");
this["aria-label"] = this.getAttribute("aria-label"); this["aria-label"] = this.getAttribute("aria-label");
this.role = this.getAttribute("role");
this.tooltip = this.getAttribute("tooltip"); this.tooltip = this.getAttribute("tooltip");
this.style = this.getAttribute("style"); this.style = this.getAttribute("style");
this["class"] = this.getAttribute("class",""); this["class"] = this.getAttribute("class","");
@@ -227,7 +218,6 @@ ButtonWidget.prototype.execute = function() {
this.setField = this.getAttribute("setField"); this.setField = this.getAttribute("setField");
this.setIndex = this.getAttribute("setIndex"); this.setIndex = this.getAttribute("setIndex");
this.popupTitle = this.getAttribute("popupTitle"); this.popupTitle = this.getAttribute("popupTitle");
this.popupAbsCoords = this.getAttribute("popupAbsCoords", "no");
this.tabIndex = this.getAttribute("tabindex"); this.tabIndex = this.getAttribute("tabindex");
this.isDisabled = this.getAttribute("disabled","no"); this.isDisabled = this.getAttribute("disabled","no");
// Make child widgets // Make child widgets
@@ -257,7 +247,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
*/ */
ButtonWidget.prototype.refresh = function(changedTiddlers) { ButtonWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes(); var changedAttributes = this.computeAttributes();
if(changedAttributes.actions || changedAttributes.to || changedAttributes.message || changedAttributes.param || changedAttributes.set || changedAttributes.setTo || changedAttributes.popup || changedAttributes.hover || changedAttributes.selectedClass || changedAttributes.style || changedAttributes.dragFilter || changedAttributes.dragTiddler || (this.set && changedTiddlers[this.set]) || (this.popup && changedTiddlers[this.popup]) || (this.popupTitle && changedTiddlers[this.popupTitle]) || changedAttributes.popupAbsCoords || changedAttributes.setTitle || changedAttributes.setField || changedAttributes.setIndex || changedAttributes.popupTitle || changedAttributes.disabled || changedAttributes["default"]) { if(changedAttributes.actions || changedAttributes.to || changedAttributes.message || changedAttributes.param || changedAttributes.set || changedAttributes.setTo || changedAttributes.popup || changedAttributes.hover || changedAttributes.selectedClass || changedAttributes.style || changedAttributes.dragFilter || changedAttributes.dragTiddler || (this.set && changedTiddlers[this.set]) || (this.popup && changedTiddlers[this.popup]) || (this.popupTitle && changedTiddlers[this.popupTitle]) || changedAttributes.setTitle || changedAttributes.setField || changedAttributes.setIndex || changedAttributes.popupTitle || changedAttributes.disabled || changedAttributes["default"]) {
this.refreshSelf(); this.refreshSelf();
return true; return true;
} else if(changedAttributes["class"]) { } else if(changedAttributes["class"]) {

Some files were not shown because too many files have changed in this diff Show More