mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-02-02 16:20:23 +00:00
Compare commits
113 Commits
offload-se
...
new-releas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2fab886564 | ||
|
|
f4db2300be | ||
|
|
33d3372229 | ||
|
|
7a304df673 | ||
|
|
a273ed05eb | ||
|
|
a4721ce24a | ||
|
|
3cf71365a5 | ||
|
|
799618d9f5 | ||
|
|
3ab6302353 | ||
|
|
85ed513bef | ||
|
|
1832aff565 | ||
|
|
a07ecb6156 | ||
|
|
19177964c8 | ||
|
|
c8e41bfade | ||
|
|
fb4d417629 | ||
|
|
20d6be1e23 | ||
|
|
7898cb8446 | ||
|
|
9a5f4cc0ef | ||
|
|
cda8d7ca8c | ||
|
|
f38e9f0822 | ||
|
|
5848d66e96 | ||
|
|
485051951e | ||
|
|
135e685811 | ||
|
|
99682c5731 | ||
|
|
d58eec47c0 | ||
|
|
059978ec63 | ||
|
|
b5e20a58a6 | ||
|
|
e8fe6b98bc | ||
|
|
317104774c | ||
|
|
deed8631d8 | ||
|
|
d733b77e2f | ||
|
|
46c26a64b9 | ||
|
|
ec81d6663b | ||
|
|
23f0a9bf79 | ||
|
|
bad87c405e | ||
|
|
6f23a078b7 | ||
|
|
c3706b8a79 | ||
|
|
7ca8fb29af | ||
|
|
d39bb5274e | ||
|
|
81b69783c4 | ||
|
|
40cc62f727 | ||
|
|
b349adde16 | ||
|
|
d63a1896b3 | ||
|
|
b65fa11643 | ||
|
|
4043499633 | ||
|
|
6a39a4e13b | ||
|
|
b5153c0066 | ||
|
|
b061f90f87 | ||
|
|
8be83cf01b | ||
|
|
5b5147dade | ||
|
|
ad6ac480f9 | ||
|
|
8168512e95 | ||
|
|
276fdc8634 | ||
|
|
0b38ced43a | ||
|
|
d7e48207b9 | ||
|
|
2c8fafee48 | ||
|
|
a6383aaaea | ||
|
|
61619c07c8 | ||
|
|
09a42a54c0 | ||
|
|
f4f31c37fc | ||
|
|
61e638c972 | ||
|
|
6bdd51d72a | ||
|
|
ed3405672a | ||
|
|
e3af967cbb | ||
|
|
6b0d3fab5d | ||
|
|
13f1689e7e | ||
|
|
4c09a88272 | ||
|
|
fbf110e209 | ||
|
|
3c1d658fad | ||
|
|
5d738673ac | ||
|
|
91871d2ced | ||
|
|
5143da9cce | ||
|
|
186d1b014a | ||
|
|
58e41ee0ad | ||
|
|
97824cc3a3 | ||
|
|
6e493755be | ||
|
|
64fce62075 | ||
|
|
5a4ff56477 | ||
|
|
3889a2a0d0 | ||
|
|
34737f4e28 | ||
|
|
94673a1028 | ||
|
|
b462aaa9a3 | ||
|
|
4552c117fc | ||
|
|
dc7f2a57bb | ||
|
|
7e91bac6b8 | ||
|
|
15ba415a45 | ||
|
|
2405e65308 | ||
|
|
865f36a6f5 | ||
|
|
a36356a07d | ||
|
|
ee23097816 | ||
|
|
e753851d49 | ||
|
|
cae3d0fa2c | ||
|
|
7c020d0eb6 | ||
|
|
afe2ac45d9 | ||
|
|
6791f0f130 | ||
|
|
a2e5c2cca2 | ||
|
|
87ba87bdd2 | ||
|
|
619bdfcab5 | ||
|
|
5ff4e02a61 | ||
|
|
f8170cd50a | ||
|
|
5389dc0fa7 | ||
|
|
2cc7c96eec | ||
|
|
8cd3d4e22c | ||
|
|
37e09d1c25 | ||
|
|
7a080092d0 | ||
|
|
810ac42810 | ||
|
|
88d3f69a3b | ||
|
|
e956bb32e9 | ||
|
|
dd91ac0b82 | ||
|
|
af63a3b920 | ||
|
|
e4fb47ee76 | ||
|
|
7944f42467 | ||
|
|
578c09e0ce |
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
|||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "${{ env.NODE_VERSION }}"
|
node-version: "${{ env.NODE_VERSION }}"
|
||||||
@@ -30,7 +30,7 @@ jobs:
|
|||||||
TW5_BUILD_MAIN_EDITION: "./editions/prerelease"
|
TW5_BUILD_MAIN_EDITION: "./editions/prerelease"
|
||||||
TW5_BUILD_OUTPUT: "./output/prerelease"
|
TW5_BUILD_OUTPUT: "./output/prerelease"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "${{ env.NODE_VERSION }}"
|
node-version: "${{ env.NODE_VERSION }}"
|
||||||
@@ -62,7 +62,7 @@ jobs:
|
|||||||
TW5_BUILD_OUTPUT: "./output"
|
TW5_BUILD_OUTPUT: "./output"
|
||||||
TW5_BUILD_ARCHIVE: "./output"
|
TW5_BUILD_ARCHIVE: "./output"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "${{ env.NODE_VERSION }}"
|
node-version: "${{ env.NODE_VERSION }}"
|
||||||
|
|||||||
40
.github/workflows/eslint.yml
vendored
Normal file
40
.github/workflows/eslint.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
name: ESLint
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: lint-${{ github.event.pull_request.number || github.ref_name }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
# Needed for GitHub Checks API
|
||||||
|
checks: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
eslint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm install --include=dev
|
||||||
|
|
||||||
|
- name: Run ESLint with reviewdog (GitHub Checks)
|
||||||
|
uses: reviewdog/action-eslint@v1
|
||||||
|
with:
|
||||||
|
eslint_flags: '.'
|
||||||
|
reporter: github-pr-check
|
||||||
|
fail_level: error
|
||||||
|
level: error
|
||||||
|
tool_name: ESLint PR code
|
||||||
@@ -73,10 +73,8 @@ rm $TW5_BUILD_OUTPUT/dev/static/*
|
|||||||
|
|
||||||
echo "<a href='./plugins/tiddlywiki/tw2parser/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/tw2parser/index.html</a>" > $TW5_BUILD_OUTPUT/classicparserdemo.html
|
echo "<a href='./plugins/tiddlywiki/tw2parser/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/tw2parser/index.html</a>" > $TW5_BUILD_OUTPUT/classicparserdemo.html
|
||||||
echo "<a href='./plugins/tiddlywiki/codemirror/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/codemirror/index.html</a>" > $TW5_BUILD_OUTPUT/codemirrordemo.html
|
echo "<a href='./plugins/tiddlywiki/codemirror/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/codemirror/index.html</a>" > $TW5_BUILD_OUTPUT/codemirrordemo.html
|
||||||
echo "<a href='./plugins/tiddlywiki/d3/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/d3/index.html</a>" > $TW5_BUILD_OUTPUT/d3demo.html
|
|
||||||
echo "<a href='./plugins/tiddlywiki/highlight/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/highlight/index.html</a>" > $TW5_BUILD_OUTPUT/highlightdemo.html
|
echo "<a href='./plugins/tiddlywiki/highlight/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/highlight/index.html</a>" > $TW5_BUILD_OUTPUT/highlightdemo.html
|
||||||
echo "<a href='./plugins/tiddlywiki/markdown/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/markdown/index.html</a>" > $TW5_BUILD_OUTPUT/markdowndemo.html
|
echo "<a href='./plugins/tiddlywiki/markdown/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/markdown/index.html</a>" > $TW5_BUILD_OUTPUT/markdowndemo.html
|
||||||
echo "<a href='./plugins/tiddlywiki/tahoelafs/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/tahoelafs/index.html</a>" > $TW5_BUILD_OUTPUT/tahoelafs.html
|
|
||||||
|
|
||||||
# Put the build details into a .tid file so that it can be included in each build (deleted at the end of this script)
|
# Put the build details into a .tid file so that it can be included in each build (deleted at the end of this script)
|
||||||
|
|
||||||
@@ -301,26 +299,6 @@ node $TW5_BUILD_TIDDLYWIKI \
|
|||||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/katex/empty.html text/plain \
|
--rendertiddler $:/core/save/empty plugins/tiddlywiki/katex/empty.html text/plain \
|
||||||
|| exit 1
|
|| exit 1
|
||||||
|
|
||||||
# /plugins/tiddlywiki/tahoelafs/index.html Demo wiki with Tahoe-LAFS plugin
|
|
||||||
# /plugins/tiddlywiki/tahoelafs/empty.html Empty wiki with Tahoe-LAFS plugin
|
|
||||||
node $TW5_BUILD_TIDDLYWIKI \
|
|
||||||
./editions/tahoelafs \
|
|
||||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
|
||||||
--output $TW5_BUILD_OUTPUT \
|
|
||||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/tahoelafs/index.html text/plain \
|
|
||||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/tahoelafs/empty.html text/plain \
|
|
||||||
|| exit 1
|
|
||||||
|
|
||||||
# /plugins/tiddlywiki/d3/index.html Demo wiki with D3 plugin
|
|
||||||
# /plugins/tiddlywiki/d3/empty.html Empty wiki with D3 plugin
|
|
||||||
node $TW5_BUILD_TIDDLYWIKI \
|
|
||||||
./editions/d3demo \
|
|
||||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
|
||||||
--output $TW5_BUILD_OUTPUT \
|
|
||||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/d3/index.html text/plain \
|
|
||||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/d3/empty.html text/plain \
|
|
||||||
|| exit 1
|
|
||||||
|
|
||||||
# /plugins/tiddlywiki/codemirror/index.html Demo wiki with codemirror plugin
|
# /plugins/tiddlywiki/codemirror/index.html Demo wiki with codemirror plugin
|
||||||
# /plugins/tiddlywiki/codemirror/empty.html Empty wiki with codemirror plugin
|
# /plugins/tiddlywiki/codemirror/empty.html Empty wiki with codemirror plugin
|
||||||
node $TW5_BUILD_TIDDLYWIKI \
|
node $TW5_BUILD_TIDDLYWIKI \
|
||||||
|
|||||||
69
boot/boot.js
69
boot/boot.js
@@ -641,7 +641,7 @@ $tw.utils.evalGlobal = function(code,context,filename,sandbox,allowGlobals) {
|
|||||||
// Call the function and return the exports
|
// Call the function and return the exports
|
||||||
return fn.apply(null,contextValues);
|
return fn.apply(null,contextValues);
|
||||||
};
|
};
|
||||||
$tw.utils.sandbox = !$tw.browser ? vm.createContext({}) : undefined;
|
$tw.utils.sandbox = !$tw.browser ? vm.createContext({}) : undefined;
|
||||||
/*
|
/*
|
||||||
Run code in a sandbox with only the specified context variables in scope
|
Run code in a sandbox with only the specified context variables in scope
|
||||||
*/
|
*/
|
||||||
@@ -799,12 +799,13 @@ the password, and to encrypt/decrypt a block of text
|
|||||||
$tw.utils.Crypto = function() {
|
$tw.utils.Crypto = function() {
|
||||||
var sjcl = $tw.node ? (global.sjcl || require("./sjcl.js")) : window.sjcl,
|
var sjcl = $tw.node ? (global.sjcl || require("./sjcl.js")) : window.sjcl,
|
||||||
currentPassword = null,
|
currentPassword = null,
|
||||||
callSjcl = function(method,inputText,password) {
|
callSjcl = function(method,inputText,password,options) {
|
||||||
|
options = options || {};
|
||||||
password = password || currentPassword;
|
password = password || currentPassword;
|
||||||
var outputText;
|
var outputText;
|
||||||
try {
|
try {
|
||||||
if(password) {
|
if(password) {
|
||||||
outputText = sjcl[method](password,inputText);
|
outputText = sjcl[method](password,inputText,options);
|
||||||
}
|
}
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
console.log("Crypto error:" + ex);
|
console.log("Crypto error:" + ex);
|
||||||
@@ -830,7 +831,8 @@ $tw.utils.Crypto = function() {
|
|||||||
return !!currentPassword;
|
return !!currentPassword;
|
||||||
}
|
}
|
||||||
this.encrypt = function(text,password) {
|
this.encrypt = function(text,password) {
|
||||||
return callSjcl("encrypt",text,password);
|
// set default ks:256 -- see: http://bitwiseshiftleft.github.io/sjcl/doc/convenience.js.html
|
||||||
|
return callSjcl("encrypt",text,password,{v:1,iter:10000,ks:256,ts:64,mode:"ccm",adata:"",cipher:"aes"});
|
||||||
};
|
};
|
||||||
this.decrypt = function(text,password) {
|
this.decrypt = function(text,password) {
|
||||||
return callSjcl("decrypt",text,password);
|
return callSjcl("decrypt",text,password);
|
||||||
@@ -1433,7 +1435,7 @@ $tw.Wiki = function(options) {
|
|||||||
checkTiddler = function(tiddler,title) {
|
checkTiddler = function(tiddler,title) {
|
||||||
if(tiddler && tiddler.fields.type === "application/json" && tiddler.fields["plugin-type"] && (!pluginType || tiddler.fields["plugin-type"] === pluginType)) {
|
if(tiddler && tiddler.fields.type === "application/json" && tiddler.fields["plugin-type"] && (!pluginType || tiddler.fields["plugin-type"] === pluginType)) {
|
||||||
var disablingTiddler = self.getTiddler("$:/config/Plugins/Disabled/" + title);
|
var disablingTiddler = self.getTiddler("$:/config/Plugins/Disabled/" + title);
|
||||||
if(title === "$:/core" || !disablingTiddler || (disablingTiddler.fields.text || "").trim() !== "yes") {
|
if(title === "$:/core" || title === "$:/core-server" || !disablingTiddler || (disablingTiddler.fields.text || "").trim() !== "yes") {
|
||||||
self.unregisterPluginTiddlers(null,[title]); // Unregister the plugin if it's already registered
|
self.unregisterPluginTiddlers(null,[title]); // Unregister the plugin if it's already registered
|
||||||
pluginTiddlers.push(tiddler);
|
pluginTiddlers.push(tiddler);
|
||||||
registeredTitles.push(tiddler.fields.title);
|
registeredTitles.push(tiddler.fields.title);
|
||||||
@@ -1530,7 +1532,8 @@ Define all modules stored in ordinary tiddlers
|
|||||||
*/
|
*/
|
||||||
$tw.Wiki.prototype.defineTiddlerModules = function() {
|
$tw.Wiki.prototype.defineTiddlerModules = function() {
|
||||||
this.each(function(tiddler,title) {
|
this.each(function(tiddler,title) {
|
||||||
if(tiddler.hasField("module-type")) {
|
// Modules in draft tiddlers are disabled
|
||||||
|
if(tiddler.hasField("module-type") && (!tiddler.hasField("draft.of"))) {
|
||||||
switch(tiddler.fields.type) {
|
switch(tiddler.fields.type) {
|
||||||
case "application/javascript":
|
case "application/javascript":
|
||||||
// We only define modules that haven't already been defined, because in the browser modules in system tiddlers are defined in inline script
|
// We only define modules that haven't already been defined, because in the browser modules in system tiddlers are defined in inline script
|
||||||
@@ -1557,6 +1560,11 @@ $tw.Wiki.prototype.defineShadowModules = function() {
|
|||||||
this.eachShadow(function(tiddler,title) {
|
this.eachShadow(function(tiddler,title) {
|
||||||
// Don't define the module if it is overidden by an ordinary tiddler
|
// Don't define the module if it is overidden by an ordinary tiddler
|
||||||
if(!self.tiddlerExists(title) && tiddler.hasField("module-type")) {
|
if(!self.tiddlerExists(title) && tiddler.hasField("module-type")) {
|
||||||
|
if(tiddler.hasField("draft.of")) {
|
||||||
|
// Report a fundamental problem
|
||||||
|
console.warn(`TiddlyWiki: Plugins should not contain tiddlers with a 'draft.of' field: ${tiddler.fields.title}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Define the module
|
// Define the module
|
||||||
$tw.modules.define(tiddler.fields.title,tiddler.fields["module-type"],tiddler.fields.text);
|
$tw.modules.define(tiddler.fields.title,tiddler.fields["module-type"],tiddler.fields.text);
|
||||||
}
|
}
|
||||||
@@ -1905,7 +1913,7 @@ $tw.loadTiddlersFromFile = function(filepath,fields) {
|
|||||||
fileSize = fs.statSync(filepath).size,
|
fileSize = fs.statSync(filepath).size,
|
||||||
data;
|
data;
|
||||||
if(fileSize > $tw.config.maxEditFileSize) {
|
if(fileSize > $tw.config.maxEditFileSize) {
|
||||||
data = "File " + filepath + "not loaded because it is too large";
|
data = "File " + filepath + " not loaded because it is too large";
|
||||||
console.log("Warning: " + data);
|
console.log("Warning: " + data);
|
||||||
ext = ".txt";
|
ext = ".txt";
|
||||||
} else {
|
} else {
|
||||||
@@ -1976,22 +1984,41 @@ filepath: pathname of the directory containing the specification file
|
|||||||
$tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
$tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||||
var tiddlers = [];
|
var tiddlers = [];
|
||||||
// Read the specification
|
// Read the specification
|
||||||
var filesInfo = $tw.utils.parseJSONSafe(fs.readFileSync(filepath + path.sep + "tiddlywiki.files","utf8"));
|
var filesInfo = $tw.utils.parseJSONSafe(fs.readFileSync(filepath + path.sep + "tiddlywiki.files","utf8"), function(e) {
|
||||||
|
console.log("Warning: tiddlywiki.files in " + filepath + " invalid: " + e.message);
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
|
||||||
// Helper to process a file
|
// Helper to process a file
|
||||||
var processFile = function(filename,isTiddlerFile,fields,isEditableFile,rootPath) {
|
var processFile = function(filename,isTiddlerFile,fields,isEditableFile,rootPath) {
|
||||||
var extInfo = $tw.config.fileExtensionInfo[path.extname(filename)],
|
var extInfo = $tw.config.fileExtensionInfo[path.extname(filename)],
|
||||||
type = (extInfo || {}).type || fields.type || "text/plain",
|
type = (extInfo || {}).type || fields.type || "text/plain",
|
||||||
typeInfo = $tw.config.contentTypeInfo[type] || {},
|
typeInfo = $tw.config.contentTypeInfo[type] || {},
|
||||||
pathname = path.resolve(filepath,filename),
|
pathname = path.resolve(filepath,filename),
|
||||||
text = fs.readFileSync(pathname,typeInfo.encoding || "utf8"),
|
|
||||||
metadata = $tw.loadMetadataForFile(pathname) || {},
|
metadata = $tw.loadMetadataForFile(pathname) || {},
|
||||||
fileTiddlers;
|
fileTooLarge = false,
|
||||||
|
text, fileTiddlers;
|
||||||
|
|
||||||
|
if("_canonical_uri" in fields) {
|
||||||
|
text = "";
|
||||||
|
} else if(fs.statSync(pathname).size > $tw.config.maxEditFileSize) {
|
||||||
|
var msg = "File " + pathname + " not loaded because it is too large";
|
||||||
|
console.log("Warning: " + msg);
|
||||||
|
fileTooLarge = true;
|
||||||
|
text = isTiddlerFile ? msg : "";
|
||||||
|
} else {
|
||||||
|
text = fs.readFileSync(pathname,typeInfo.encoding || "utf8");
|
||||||
|
}
|
||||||
|
|
||||||
if(isTiddlerFile) {
|
if(isTiddlerFile) {
|
||||||
fileTiddlers = $tw.wiki.deserializeTiddlers(path.extname(pathname),text,metadata) || [];
|
fileTiddlers = $tw.wiki.deserializeTiddlers(fileTooLarge ? ".txt" : path.extname(pathname),text,metadata) || [];
|
||||||
} else {
|
} else {
|
||||||
fileTiddlers = [$tw.utils.extend({text: text},metadata)];
|
fileTiddlers = [$tw.utils.extend({text: text},metadata)];
|
||||||
}
|
}
|
||||||
var combinedFields = $tw.utils.extend({},fields,metadata);
|
var combinedFields = $tw.utils.extend({},fields,metadata);
|
||||||
|
if(fileTooLarge && isTiddlerFile) {
|
||||||
|
delete combinedFields.type; // type altered
|
||||||
|
}
|
||||||
$tw.utils.each(fileTiddlers,function(tiddler) {
|
$tw.utils.each(fileTiddlers,function(tiddler) {
|
||||||
$tw.utils.each(combinedFields,function(fieldInfo,name) {
|
$tw.utils.each(combinedFields,function(fieldInfo,name) {
|
||||||
if(typeof fieldInfo === "string" || $tw.utils.isArray(fieldInfo)) {
|
if(typeof fieldInfo === "string" || $tw.utils.isArray(fieldInfo)) {
|
||||||
@@ -2066,6 +2093,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
|||||||
} else if(tidInfo.suffix) {
|
} else if(tidInfo.suffix) {
|
||||||
tidInfo.fields.text = {suffix: tidInfo.suffix};
|
tidInfo.fields.text = {suffix: tidInfo.suffix};
|
||||||
}
|
}
|
||||||
|
tidInfo.fields = tidInfo.fields || {};
|
||||||
processFile(tidInfo.file,tidInfo.isTiddlerFile,tidInfo.fields);
|
processFile(tidInfo.file,tidInfo.isTiddlerFile,tidInfo.fields);
|
||||||
});
|
});
|
||||||
// Process any listed directories
|
// Process any listed directories
|
||||||
@@ -2087,6 +2115,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
|||||||
var thisPath = path.relative(filepath, files[t]),
|
var thisPath = path.relative(filepath, files[t]),
|
||||||
filename = path.basename(thisPath);
|
filename = path.basename(thisPath);
|
||||||
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
|
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
|
||||||
|
dirSpec.fields = dirSpec.fields || {};
|
||||||
processFile(thisPath,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile,dirSpec.path);
|
processFile(thisPath,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile,dirSpec.path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2350,6 +2379,7 @@ $tw.loadTiddlersNode = function() {
|
|||||||
});
|
});
|
||||||
// Load the core tiddlers
|
// Load the core tiddlers
|
||||||
$tw.wiki.addTiddler($tw.loadPluginFolder($tw.boot.corePath));
|
$tw.wiki.addTiddler($tw.loadPluginFolder($tw.boot.corePath));
|
||||||
|
$tw.wiki.addTiddler($tw.loadPluginFolder($tw.boot.coreServerPath));
|
||||||
// Load any extra plugins
|
// Load any extra plugins
|
||||||
$tw.utils.each($tw.boot.extraPlugins,function(name) {
|
$tw.utils.each($tw.boot.extraPlugins,function(name) {
|
||||||
if(name.charAt(0) === "+") { // Relative path to plugin
|
if(name.charAt(0) === "+") { // Relative path to plugin
|
||||||
@@ -2423,6 +2453,7 @@ $tw.boot.initStartup = function(options) {
|
|||||||
// System paths and filenames
|
// System paths and filenames
|
||||||
$tw.boot.bootPath = options.bootPath || path.dirname(module.filename);
|
$tw.boot.bootPath = options.bootPath || path.dirname(module.filename);
|
||||||
$tw.boot.corePath = path.resolve($tw.boot.bootPath,"../core");
|
$tw.boot.corePath = path.resolve($tw.boot.bootPath,"../core");
|
||||||
|
$tw.boot.coreServerPath = path.resolve($tw.boot.bootPath,"../core-server");
|
||||||
// If there's no arguments then default to `--help`
|
// If there's no arguments then default to `--help`
|
||||||
if($tw.boot.argv.length === 0) {
|
if($tw.boot.argv.length === 0) {
|
||||||
$tw.boot.argv = ["--help"];
|
$tw.boot.argv = ["--help"];
|
||||||
@@ -2547,10 +2578,10 @@ $tw.boot.execStartup = function(options){
|
|||||||
if($tw.safeMode) {
|
if($tw.safeMode) {
|
||||||
$tw.wiki.processSafeMode();
|
$tw.wiki.processSafeMode();
|
||||||
}
|
}
|
||||||
// Register typed modules from the tiddlers we've just loaded
|
// Register typed modules from the tiddlers we've just loaded and any modules within plugins
|
||||||
$tw.wiki.defineTiddlerModules();
|
// Tiddlers should appear last so that they may overwrite shadows during module registration
|
||||||
// And any modules within plugins
|
|
||||||
$tw.wiki.defineShadowModules();
|
$tw.wiki.defineShadowModules();
|
||||||
|
$tw.wiki.defineTiddlerModules();
|
||||||
// Make sure the crypto state tiddler is up to date
|
// Make sure the crypto state tiddler is up to date
|
||||||
if($tw.crypto) {
|
if($tw.crypto) {
|
||||||
$tw.crypto.updateCryptoStateTiddler();
|
$tw.crypto.updateCryptoStateTiddler();
|
||||||
@@ -2619,11 +2650,13 @@ $tw.boot.executeNextStartupTask = function(callback) {
|
|||||||
$tw.boot.log(s.join(" "));
|
$tw.boot.log(s.join(" "));
|
||||||
// Execute task
|
// Execute task
|
||||||
if(!$tw.utils.hop(task,"synchronous") || task.synchronous) {
|
if(!$tw.utils.hop(task,"synchronous") || task.synchronous) {
|
||||||
task.startup();
|
const thenable = task.startup();
|
||||||
if(task.name) {
|
if(thenable && typeof thenable.then === "function"){
|
||||||
$tw.boot.executedStartupModules[task.name] = true;
|
thenable.then(asyncTaskCallback);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return asyncTaskCallback();
|
||||||
}
|
}
|
||||||
return $tw.boot.executeNextStartupTask(callback);
|
|
||||||
} else {
|
} else {
|
||||||
task.startup(asyncTaskCallback);
|
task.startup(asyncTaskCallback);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ talk.tiddlywiki.org: jeremyruston
|
|||||||
github: Jermolene
|
github: Jermolene
|
||||||
linkedin: www.linkedin.com/in/jermy
|
linkedin: www.linkedin.com/in/jermy
|
||||||
flickr: www.flickr.com/photos/jermy/
|
flickr: www.flickr.com/photos/jermy/
|
||||||
|
bluesky: https://bsky.app/profile/jermolene.bsky.social
|
||||||
homepage: jermolene.com
|
homepage: jermolene.com
|
||||||
email: jeremy@jermolene.com
|
email: jeremy@jermolene.com
|
||||||
avatar: /9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAgICAgJCAkKCgkNDgwODRMREBARExwUFhQWFBwrGx8bGx8bKyYuJSMlLiZENS8vNUROQj5CTl9VVV93cXecnNEBCAgICAkICQoKCQ0ODA4NExEQEBETHBQWFBYUHCsbHxsbHxsrJi4lIyUuJkQ1Ly81RE5CPkJOX1VVX3dxd5yc0f/CABEIACAAIAMBIgACEQEDEQH/xAAtAAEBAAMAAAAAAAAAAAAAAAAHBgIEBQEBAQEBAAAAAAAAAAAAAAAAAgQBBf/aAAwDAQACEAMQAAAANF4uTuPRhD2nBLnUiJvKM0DtMKy//8QAKxAAAgIBAwMDAQkAAAAAAAAAAQIDBBEABRITITEiMkFxFEJRUmFicoGR/9oACAEBAAE/AInTA6gUGP4ZOQbW1bPsmyUq1q+gmvFPUzZPDkPamtwqU75ks04JakroVcg5RwRjg66NUx25KbzqJYyMngfqSuq0M3NZYIebJIvZozIvI/iNPcp/aalSdJXsS4VcKeIzlvU3jVTcYLNiaGISrjkhWQYDfQ63pYAzCDBsOiu7Dsx4EHH6r2w2ttimjd2IsNErhhJHKI04/uzqxuCxpBYVVWKSHqwMyMSQ33SB7dUJFmlkMYRgnqZgCMf7rf8AeEt3A9YOhjXAb2k8u7dtT1RZeOtXmYxiOPj4ZWY/lb51skqUNnNW/wBNzC7IpB6gQeeB/jq/fqGOaLbowuYn5MAQOw8LjW5Vmeo0qIsqYLLKjHIZmwv9fB1//8QAHxEAAQMEAwEAAAAAAAAAAAAAEQABAgMSIWExMkFR/9oACAECAQE/AD9iTy2lJmHUB8BVKM4SNSOj46a29saX/8QAHREAAgICAwEAAAAAAAAAAAAAAQIAAwQRITGBkf/aAAgBAwEBPwDHpFpJZtamVSiBWT2Yt7hmCDsb+TKtsKqpGg3M/9k=
|
avatar: /9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAgICAgJCAkKCgkNDgwODRMREBARExwUFhQWFBwrGx8bGx8bKyYuJSMlLiZENS8vNUROQj5CTl9VVV93cXecnNEBCAgICAkICQoKCQ0ODA4NExEQEBETHBQWFBYUHCsbHxsbHxsrJi4lIyUuJkQ1Ly81RE5CPkJOX1VVX3dxd5yc0f/CABEIACAAIAMBIgACEQEDEQH/xAAtAAEBAAMAAAAAAAAAAAAAAAAHBgIEBQEBAQEBAAAAAAAAAAAAAAAAAgQBBf/aAAwDAQACEAMQAAAANF4uTuPRhD2nBLnUiJvKM0DtMKy//8QAKxAAAgIBAwMDAQkAAAAAAAAAAQIDBBEABRITITEiMkFxFEJRUmFicoGR/9oACAEBAAE/AInTA6gUGP4ZOQbW1bPsmyUq1q+gmvFPUzZPDkPamtwqU75ks04JakroVcg5RwRjg66NUx25KbzqJYyMngfqSuq0M3NZYIebJIvZozIvI/iNPcp/aalSdJXsS4VcKeIzlvU3jVTcYLNiaGISrjkhWQYDfQ63pYAzCDBsOiu7Dsx4EHH6r2w2ttimjd2IsNErhhJHKI04/uzqxuCxpBYVVWKSHqwMyMSQ33SB7dUJFmlkMYRgnqZgCMf7rf8AeEt3A9YOhjXAb2k8u7dtT1RZeOtXmYxiOPj4ZWY/lb51skqUNnNW/wBNzC7IpB6gQeeB/jq/fqGOaLbowuYn5MAQOw8LjW5Vmeo0qIsqYLLKjHIZmwv9fB1//8QAHxEAAQMEAwEAAAAAAAAAAAAAEQABAgMSIWExMkFR/9oACAECAQE/AD9iTy2lJmHUB8BVKM4SNSOj46a29saX/8QAHREAAgICAwEAAAAAAAAAAAAAAQIAAwQRITGBkf/aAAgBAwEBPwDHpFpJZtamVSiBWT2Yt7hmCDsb+TKtsKqpGg3M/9k=
|
||||||
|
|||||||
@@ -99,16 +99,18 @@ Commander.prototype.executeNextCommand = function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(command.info.synchronous) {
|
if(command.info.synchronous) {
|
||||||
// Synchronous command
|
// Synchronous command (await thenables)
|
||||||
c = new command.Command(params,this);
|
c = new command.Command(params,this);
|
||||||
err = c.execute();
|
err = c.execute();
|
||||||
if(err) {
|
if(err && typeof err.then === "function") {
|
||||||
|
err.then(e => { e ? this.callback(e) : this.executeNextCommand(); });
|
||||||
|
} else if(err) {
|
||||||
this.callback(err);
|
this.callback(err);
|
||||||
} else {
|
} else {
|
||||||
this.executeNextCommand();
|
this.executeNextCommand();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Asynchronous command
|
// Asynchronous command (await thenables)
|
||||||
c = new command.Command(params,this,function(err) {
|
c = new command.Command(params,this,function(err) {
|
||||||
if(err) {
|
if(err) {
|
||||||
self.callback(err);
|
self.callback(err);
|
||||||
@@ -117,7 +119,9 @@ Commander.prototype.executeNextCommand = function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
err = c.execute();
|
err = c.execute();
|
||||||
if(err) {
|
if(err && typeof err.then === "function") {
|
||||||
|
err.then(e => { if(e) this.callback(e); });
|
||||||
|
} else if(err) {
|
||||||
this.callback(err);
|
this.callback(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,6 +76,7 @@ WikiFolderMaker.prototype.tiddlersToIgnore = [
|
|||||||
"$:/boot/boot.js",
|
"$:/boot/boot.js",
|
||||||
"$:/boot/bootprefix.js",
|
"$:/boot/bootprefix.js",
|
||||||
"$:/core",
|
"$:/core",
|
||||||
|
"$:/core-server",
|
||||||
"$:/library/sjcl.js",
|
"$:/library/sjcl.js",
|
||||||
"$:/temp/info-plugin"
|
"$:/temp/info-plugin"
|
||||||
];
|
];
|
||||||
11
core-server/plugin.info
Normal file
11
core-server/plugin.info
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"title": "$:/core-server",
|
||||||
|
"name": "Core Server Components",
|
||||||
|
"description": "TiddlyWiki5 core server components",
|
||||||
|
"author": "JeremyRuston",
|
||||||
|
"core-version": ">=5.0.0",
|
||||||
|
"platform": "server",
|
||||||
|
"plugin-priority": "0",
|
||||||
|
"list": "readme",
|
||||||
|
"stability": "STABILITY_2_STABLE"
|
||||||
|
}
|
||||||
7
core-server/readme.tid
Normal file
7
core-server/readme.tid
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
title: $:/core-server/readme
|
||||||
|
|
||||||
|
This plugin contains TiddlyWiki's core components that are only needed on the server, comprising:
|
||||||
|
|
||||||
|
* Commands
|
||||||
|
* HTTP server code
|
||||||
|
* Utility functions for server
|
||||||
@@ -8,10 +8,14 @@ DELETE /recipes/default/tiddlers/:title
|
|||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "DELETE";
|
exports.methods = ["DELETE"];
|
||||||
|
|
||||||
exports.path = /^\/bags\/default\/tiddlers\/(.+)$/;
|
exports.path = /^\/bags\/default\/tiddlers\/(.+)$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]);
|
var title = $tw.utils.decodeURIComponentSafe(state.params[0]);
|
||||||
state.wiki.deleteTiddler(title);
|
state.wiki.deleteTiddler(title);
|
||||||
@@ -8,10 +8,14 @@ GET /favicon.ico
|
|||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/favicon.ico$/;
|
exports.path = /^\/favicon.ico$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var buffer = state.wiki.getTiddlerText("$:/favicon.ico","");
|
var buffer = state.wiki.getTiddlerText("$:/favicon.ico","");
|
||||||
state.sendResponse(200,{"Content-Type": "image/x-icon"},buffer,"base64");
|
state.sendResponse(200,{"Content-Type": "image/x-icon"},buffer,"base64");
|
||||||
73
core-server/server/routes/get-file.js
Normal file
73
core-server/server/routes/get-file.js
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/server/routes/get-file.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: route
|
||||||
|
|
||||||
|
GET /files/:filepath
|
||||||
|
|
||||||
|
\*/
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
|
exports.path = /^\/files\/(.+)$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.handler = function(request,response,state) {
|
||||||
|
var path = require("path"),
|
||||||
|
fs = require("fs"),
|
||||||
|
suppliedFilename = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||||
|
baseFilename = path.resolve(state.boot.wikiPath,"files"),
|
||||||
|
filename = path.resolve(baseFilename,suppliedFilename),
|
||||||
|
extension = path.extname(filename);
|
||||||
|
// Check that the filename is inside the wiki files folder
|
||||||
|
if(path.relative(baseFilename,filename).indexOf("..") === 0) {
|
||||||
|
return state.sendResponse(404,{"Content-Type": "text/plain"},"File '" + suppliedFilename + "' not found");
|
||||||
|
}
|
||||||
|
fs.stat(filename, function(err, stats) {
|
||||||
|
if(err) {
|
||||||
|
return state.sendResponse(404,{"Content-Type": "text/plain"},"File '" + suppliedFilename + "' not found");
|
||||||
|
} else {
|
||||||
|
var type = ($tw.config.fileExtensionInfo[extension] ? $tw.config.fileExtensionInfo[extension].type : "application/octet-stream"),
|
||||||
|
responseHeaders = {
|
||||||
|
"Content-Type": type,
|
||||||
|
"Accept-Ranges": "bytes"
|
||||||
|
};
|
||||||
|
var rangeHeader = request.headers.range,
|
||||||
|
stream;
|
||||||
|
if(rangeHeader) {
|
||||||
|
// Handle range requests
|
||||||
|
var parts = rangeHeader.replace(/bytes=/, "").split("-"),
|
||||||
|
start = parseInt(parts[0], 10),
|
||||||
|
end = parts[1] ? parseInt(parts[1], 10) : stats.size - 1;
|
||||||
|
// Validate start and end
|
||||||
|
if(isNaN(start) || isNaN(end) || start < 0 || end < start || end >= stats.size) {
|
||||||
|
responseHeaders["Content-Range"] = "bytes */" + stats.size;
|
||||||
|
return response.writeHead(416, responseHeaders).end();
|
||||||
|
}
|
||||||
|
var chunksize = (end - start) + 1;
|
||||||
|
responseHeaders["Content-Range"] = "bytes " + start + "-" + end + "/" + stats.size;
|
||||||
|
responseHeaders["Content-Length"] = chunksize;
|
||||||
|
response.writeHead(206, responseHeaders);
|
||||||
|
stream = fs.createReadStream(filename, {start: start, end: end});
|
||||||
|
} else {
|
||||||
|
responseHeaders["Content-Length"] = stats.size;
|
||||||
|
response.writeHead(200, responseHeaders);
|
||||||
|
stream = fs.createReadStream(filename);
|
||||||
|
}
|
||||||
|
// Common stream error handling
|
||||||
|
stream.on("error", function(err) {
|
||||||
|
if(!response.headersSent) {
|
||||||
|
response.writeHead(500, {"Content-Type": "text/plain"});
|
||||||
|
response.end("Read error");
|
||||||
|
} else {
|
||||||
|
response.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
stream.pipe(response);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -8,10 +8,14 @@ GET /
|
|||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/$/;
|
exports.path = /^\/$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var text = state.wiki.renderTiddler(state.server.get("root-render-type"),state.server.get("root-tiddler")),
|
var text = state.wiki.renderTiddler(state.server.get("root-render-type"),state.server.get("root-tiddler")),
|
||||||
responseHeaders = {
|
responseHeaders = {
|
||||||
@@ -8,10 +8,14 @@ GET /login-basic -- force a Basic Authentication challenge
|
|||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/login-basic$/;
|
exports.path = /^\/login-basic$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
if(!state.authenticatedUsername) {
|
if(!state.authenticatedUsername) {
|
||||||
// Challenge if there's no username
|
// Challenge if there's no username
|
||||||
@@ -8,10 +8,14 @@ GET /status
|
|||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/status$/;
|
exports.path = /^\/status$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var text = JSON.stringify({
|
var text = JSON.stringify({
|
||||||
username: state.authenticatedUsername || state.server.get("anon-username") || "",
|
username: state.authenticatedUsername || state.server.get("anon-username") || "",
|
||||||
@@ -8,10 +8,14 @@ GET /:title
|
|||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/([^\/]+)$/;
|
exports.path = /^\/([^\/]+)$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||||
tiddler = state.wiki.getTiddler(title);
|
tiddler = state.wiki.getTiddler(title);
|
||||||
@@ -8,10 +8,14 @@ GET /recipes/default/tiddlers/:title
|
|||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||||
tiddler = state.wiki.getTiddler(title),
|
tiddler = state.wiki.getTiddler(title),
|
||||||
@@ -10,10 +10,14 @@ GET /recipes/default/tiddlers.json?filter=<filter>
|
|||||||
|
|
||||||
var DEFAULT_FILTER = "[all[tiddlers]!is[system]sort[title]]";
|
var DEFAULT_FILTER = "[all[tiddlers]!is[system]sort[title]]";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/recipes\/default\/tiddlers.json$/;
|
exports.path = /^\/recipes\/default\/tiddlers.json$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var filter = state.queryParameters.filter || DEFAULT_FILTER;
|
var filter = state.queryParameters.filter || DEFAULT_FILTER;
|
||||||
if(state.wiki.getTiddlerText("$:/config/Server/AllowAllExternalFilters") !== "yes") {
|
if(state.wiki.getTiddlerText("$:/config/Server/AllowAllExternalFilters") !== "yes") {
|
||||||
@@ -8,10 +8,14 @@ PUT /recipes/default/tiddlers/:title
|
|||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "PUT";
|
exports.methods = ["PUT"];
|
||||||
|
|
||||||
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||||
fields = $tw.utils.parseJSONSafe(state.data);
|
fields = $tw.utils.parseJSONSafe(state.data);
|
||||||
@@ -74,6 +74,11 @@ function Server(options) {
|
|||||||
// console.log("Loading server route " + title);
|
// console.log("Loading server route " + title);
|
||||||
self.addRoute(routeDefinition);
|
self.addRoute(routeDefinition);
|
||||||
});
|
});
|
||||||
|
this.routes.sort((a, b) => {
|
||||||
|
const priorityA = a.info?.priority ?? 100,
|
||||||
|
priorityB = b.info?.priority ?? 100;
|
||||||
|
return priorityB - priorityA;
|
||||||
|
});
|
||||||
// Initialise the http vs https
|
// Initialise the http vs https
|
||||||
this.listenOptions = null;
|
this.listenOptions = null;
|
||||||
this.protocol = "http";
|
this.protocol = "http";
|
||||||
@@ -217,7 +222,7 @@ Server.prototype.findMatchingRoute = function(request,state) {
|
|||||||
} else {
|
} else {
|
||||||
match = potentialRoute.path.exec(pathname);
|
match = potentialRoute.path.exec(pathname);
|
||||||
}
|
}
|
||||||
if(match && request.method === potentialRoute.method) {
|
if(match && (potentialRoute.methods?.includes(request.method) || potentialRoute.method === request.method)) {
|
||||||
state.params = [];
|
state.params = [];
|
||||||
for(var p=1; p<match.length; p++) {
|
for(var p=1; p<match.length; p++) {
|
||||||
state.params.push(match[p]);
|
state.params.push(match[p]);
|
||||||
@@ -147,7 +147,7 @@ Settings/AutoSave/Disabled/Description: Do not save changes automatically
|
|||||||
Settings/AutoSave/Enabled/Description: Save changes automatically
|
Settings/AutoSave/Enabled/Description: Save changes automatically
|
||||||
Settings/AutoSave/Hint: Attempt to automatically save changes during editing when using a supporting saver
|
Settings/AutoSave/Hint: Attempt to automatically save changes during editing when using a supporting saver
|
||||||
Settings/CamelCase/Caption: Camel Case Wiki Links
|
Settings/CamelCase/Caption: Camel Case Wiki Links
|
||||||
Settings/CamelCase/Hint: You can globally disable automatic linking of ~CamelCase phrases. Requires reload to take effect
|
Settings/CamelCase/Hint: Requires reload to take effect
|
||||||
Settings/CamelCase/Description: Enable automatic ~CamelCase linking
|
Settings/CamelCase/Description: Enable automatic ~CamelCase linking
|
||||||
Settings/Caption: Settings
|
Settings/Caption: Settings
|
||||||
Settings/EditorToolbar/Caption: Editor Toolbar
|
Settings/EditorToolbar/Caption: Editor Toolbar
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ function FramedEngine(options) {
|
|||||||
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: {}}).fields["color-scheme"] || "light";
|
||||||
this.iframeDoc.open();
|
this.iframeDoc.open();
|
||||||
this.iframeDoc.write("<meta name='color-scheme' content='" + colorScheme + "'>");
|
this.iframeDoc.write("<!DOCTYPE html><html><head><meta name='color-scheme' content='" + colorScheme + "'></head><body></body></html>");
|
||||||
this.iframeDoc.close();
|
this.iframeDoc.close();
|
||||||
// Style the iframe
|
// Style the iframe
|
||||||
this.iframeNode.className = this.dummyTextArea.className;
|
this.iframeNode.className = this.dummyTextArea.className;
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
|||||||
// Fix height
|
// Fix height
|
||||||
this.engine.fixHeight();
|
this.engine.fixHeight();
|
||||||
// Focus if required
|
// Focus if required
|
||||||
if(this.editFocus === "true" || this.editFocus === "yes") {
|
if($tw.browser && (this.editFocus === "true" || this.editFocus === "yes") && !$tw.utils.hasClass(this.parentDomNode.ownerDocument.activeElement,"tc-keep-focus")) {
|
||||||
this.engine.focus();
|
this.engine.focus();
|
||||||
}
|
}
|
||||||
// Add widget message listeners
|
// Add widget message listeners
|
||||||
|
|||||||
@@ -16,12 +16,8 @@ exports.json = function(source,operand,options) {
|
|||||||
spaces = /^\d+$/.test(operand) ? parseInt(operand,10) : operand;
|
spaces = /^\d+$/.test(operand) ? parseInt(operand,10) : operand;
|
||||||
}
|
}
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
var data = $tw.utils.parseJSONSafe(title);
|
var data = $tw.utils.parseJSONSafe(title,function(){return undefined;});
|
||||||
try {
|
|
||||||
data = JSON.parse(title);
|
|
||||||
} catch(e) {
|
|
||||||
data = undefined;
|
|
||||||
}
|
|
||||||
if(data !== undefined) {
|
if(data !== undefined) {
|
||||||
results.push(JSON.stringify(data,null,spaces));
|
results.push(JSON.stringify(data,null,spaces));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -217,6 +217,10 @@ function makeNumericReducingOperator(fnCalc,initialValue,fnFinal) {
|
|||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
result.push($tw.utils.parseNumber(title));
|
result.push($tw.utils.parseNumber(title));
|
||||||
});
|
});
|
||||||
|
// We return an empty array if there are no input titles
|
||||||
|
if(result.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
var value = result.reduce(function(accumulator,currentValue) {
|
var value = result.reduce(function(accumulator,currentValue) {
|
||||||
return fnCalc(accumulator,currentValue);
|
return fnCalc(accumulator,currentValue);
|
||||||
},initialValue);
|
},initialValue);
|
||||||
|
|||||||
86
core/modules/info/dimensions.js
Normal file
86
core/modules/info/dimensions.js
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/info/windowdimensions.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: info
|
||||||
|
\*/
|
||||||
|
|
||||||
|
exports.getInfoTiddlerFields = function(updateInfoTiddlersCallback) {
|
||||||
|
if(!$tw.browser) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class WindowDimensionsTracker {
|
||||||
|
constructor(updateCallback) {
|
||||||
|
this.updateCallback = updateCallback;
|
||||||
|
this.resizeHandlers = new Map();
|
||||||
|
this.dimensionsInfo = [
|
||||||
|
["outer/width", win => win.outerWidth],
|
||||||
|
["outer/height", win => win.outerHeight],
|
||||||
|
["inner/width", win => win.innerWidth],
|
||||||
|
["inner/height", win => win.innerHeight],
|
||||||
|
["client/width", win => win.document.documentElement.clientWidth],
|
||||||
|
["client/height", win => win.document.documentElement.clientHeight]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTiddlers(win,windowId) {
|
||||||
|
const prefix = `$:/info/browser/window/${windowId}/`;
|
||||||
|
return this.dimensionsInfo.map(([suffix, getter]) => ({
|
||||||
|
title: prefix + suffix,
|
||||||
|
text: String(getter(win))
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
clearTiddlers(windowId) {
|
||||||
|
const prefix = `$:/info/browser/window/${windowId}/`,
|
||||||
|
deletions = this.dimensionsInfo.map(([suffix]) => prefix + suffix);
|
||||||
|
this.updateCallback([], deletions);
|
||||||
|
}
|
||||||
|
|
||||||
|
getUpdateHandler(win,windowId) {
|
||||||
|
let scheduled = false;
|
||||||
|
return () => {
|
||||||
|
if(!scheduled) {
|
||||||
|
scheduled = true;
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.updateCallback(this.buildTiddlers(win,windowId), []);
|
||||||
|
scheduled = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
trackWindow(win,windowId) {
|
||||||
|
const handler = this.getUpdateHandler(win, windowId);
|
||||||
|
handler(); // initial update
|
||||||
|
win.addEventListener("resize",handler,{passive:true});
|
||||||
|
this.resizeHandlers.set(windowId,{win, handler});
|
||||||
|
}
|
||||||
|
|
||||||
|
untrackWindow(windowId) {
|
||||||
|
const entry = this.resizeHandlers.get(windowId);
|
||||||
|
if(entry) {
|
||||||
|
entry.win.removeEventListener("resize", entry.handler);
|
||||||
|
this.resizeHandlers.delete(windowId);
|
||||||
|
}
|
||||||
|
this.clearTiddlers(windowId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tracker = new WindowDimensionsTracker(updateInfoTiddlersCallback);
|
||||||
|
|
||||||
|
// Track main window
|
||||||
|
tracker.trackWindow(window,"system/main");
|
||||||
|
|
||||||
|
// Hook into event bus for user windows
|
||||||
|
if($tw.eventBus) {
|
||||||
|
$tw.eventBus.on("window:opened", ({window: win, windowID}) => {
|
||||||
|
tracker.trackWindow(win, "user/" + windowID);
|
||||||
|
});
|
||||||
|
$tw.eventBus.on("window:closed", ({windowID}) => {
|
||||||
|
tracker.untrackWindow("user/" + windowID);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
};
|
||||||
@@ -7,23 +7,34 @@ The audio parser parses an audio tiddler into an embeddable HTML element
|
|||||||
|
|
||||||
\*/
|
\*/
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var AudioParser = function(type,text,options) {
|
var AudioParser = function(type,text,options) {
|
||||||
var element = {
|
var element = {
|
||||||
type: "element",
|
type: "element",
|
||||||
tag: "audio",
|
tag: "$audio", // Using $audio to enable widget interception
|
||||||
attributes: {
|
attributes: {
|
||||||
controls: {type: "string", value: "controls"},
|
controls: {type: "string", value: "controls"},
|
||||||
style: {type: "string", value: "width: 100%; object-fit: contain"}
|
style: {type: "string", value: "width: 100%; object-fit: contain"}
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
src;
|
|
||||||
|
// Pass through source information
|
||||||
if(options._canonical_uri) {
|
if(options._canonical_uri) {
|
||||||
element.attributes.src = {type: "string", value: options._canonical_uri};
|
element.attributes.src = {type: "string", value: options._canonical_uri};
|
||||||
|
element.attributes.type = {type: "string", value: type};
|
||||||
} else if(text) {
|
} else if(text) {
|
||||||
element.attributes.src = {type: "string", value: "data:" + type + ";base64," + text};
|
element.attributes.src = {type: "string", value: "data:" + type + ";base64," + text};
|
||||||
|
element.attributes.type = {type: "string", value: type};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pass through tiddler title if available
|
||||||
|
if(options.title) {
|
||||||
|
element.attributes.tiddler = {type: "string", value: options.title};
|
||||||
|
}
|
||||||
|
|
||||||
this.tree = [element];
|
this.tree = [element];
|
||||||
this.source = text;
|
this.source = text;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
@@ -33,3 +44,4 @@ exports["audio/ogg"] = AudioParser;
|
|||||||
exports["audio/mpeg"] = AudioParser;
|
exports["audio/mpeg"] = AudioParser;
|
||||||
exports["audio/mp3"] = AudioParser;
|
exports["audio/mp3"] = AudioParser;
|
||||||
exports["audio/mp4"] = AudioParser;
|
exports["audio/mp4"] = AudioParser;
|
||||||
|
|
||||||
@@ -82,6 +82,7 @@ exports.parseTokenString = function(source,pos,token) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Look for a token matching a regex. Returns null if not found, otherwise returns {type: "regexp", match:, start:, end:,}
|
Look for a token matching a regex. Returns null if not found, otherwise returns {type: "regexp", match:, start:, end:,}
|
||||||
|
Use the "Y" (sticky) flag to avoid searching the entire rest of the string
|
||||||
*/
|
*/
|
||||||
exports.parseTokenRegExp = function(source,pos,reToken) {
|
exports.parseTokenRegExp = function(source,pos,reToken) {
|
||||||
var node = {
|
var node = {
|
||||||
@@ -172,7 +173,7 @@ exports.parseMacroParameter = function(source,pos) {
|
|||||||
start: pos
|
start: pos
|
||||||
};
|
};
|
||||||
// Define our regexp
|
// Define our regexp
|
||||||
var reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|((?:(?:>(?!>))|[^\s>"'])+)))/g;
|
const reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|((?:(?:>(?!>))|[^\s>"'])+)))/y;
|
||||||
// Skip whitespace
|
// Skip whitespace
|
||||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||||
// Look for the parameter
|
// Look for the parameter
|
||||||
@@ -240,7 +241,7 @@ exports.parseMacroInvocation = function(source,pos) {
|
|||||||
params: []
|
params: []
|
||||||
};
|
};
|
||||||
// Define our regexps
|
// Define our regexps
|
||||||
var reMacroName = /([^\s>"'=]+)/g;
|
const reMacroName = /([^\s>"'=]+)/y;
|
||||||
// Skip whitespace
|
// Skip whitespace
|
||||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||||
// Look for a double less than sign
|
// Look for a double less than sign
|
||||||
@@ -277,7 +278,7 @@ exports.parseFilterVariable = function(source) {
|
|||||||
params: [],
|
params: [],
|
||||||
},
|
},
|
||||||
pos = 0,
|
pos = 0,
|
||||||
reName = /([^\s"']+)/g;
|
reName = /([^\s"']+)/y;
|
||||||
// If there is no whitespace or it is an empty string then there are no macro parameters
|
// If there is no whitespace or it is an empty string then there are no macro parameters
|
||||||
if(/^\S*$/.test(source)) {
|
if(/^\S*$/.test(source)) {
|
||||||
node.name = source;
|
node.name = source;
|
||||||
@@ -302,11 +303,11 @@ exports.parseAttribute = function(source,pos) {
|
|||||||
start: pos
|
start: pos
|
||||||
};
|
};
|
||||||
// Define our regexps
|
// Define our regexps
|
||||||
var reAttributeName = /([^\/\s>"'`=]+)/g,
|
const reAttributeName = /([^\/\s>"'`=]+)/y,
|
||||||
reUnquotedAttribute = /([^\/\s<>"'`=]+)/g,
|
reUnquotedAttribute = /([^\/\s<>"'`=]+)/y,
|
||||||
reFilteredValue = /\{\{\{([\S\s]+?)\}\}\}/g,
|
reFilteredValue = /\{\{\{([\S\s]+?)\}\}\}/y,
|
||||||
reIndirectValue = /\{\{([^\}]+)\}\}/g,
|
reIndirectValue = /\{\{([^\}]+)\}\}/y,
|
||||||
reSubstitutedValue = /(?:```([\s\S]*?)```|`([^`]|[\S\s]*?)`)/g;
|
reSubstitutedValue = /(?:```([\s\S]*?)```|`([^`]|[\S\s]*?)`)/y;
|
||||||
// Skip whitespace
|
// Skip whitespace
|
||||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||||
// Get the attribute name
|
// Get the attribute name
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ Note that the syntax for comments is simplified to an opening "<!--" sequence an
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.name = "commentblock";
|
exports.name = "commentblock";
|
||||||
exports.types = {block:true, pragma:true};
|
exports.types = {block: true, pragma: true};
|
||||||
|
|
||||||
exports.init = function(parser) {
|
exports.init = function(parser) {
|
||||||
this.parser = parser;
|
this.parser = parser;
|
||||||
@@ -43,9 +43,18 @@ exports.findNextMatch = function(startPos) {
|
|||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
exports.parse = function() {
|
exports.parse = function() {
|
||||||
// Move past the match
|
// Move past the match
|
||||||
this.parser.pos = this.endMatchRegExp.lastIndex;
|
this.parser.pos = this.endMatchRegExp.lastIndex;
|
||||||
// Don't return any elements
|
// Return a node representing the comment that is not rendered
|
||||||
return [];
|
var commentStart = this.match.index;
|
||||||
|
var commentEnd = this.endMatch.index + this.endMatch[0].length;
|
||||||
|
return [{
|
||||||
|
type: "void",
|
||||||
|
children: [],
|
||||||
|
text: this.parser.source.slice(commentStart, commentEnd),
|
||||||
|
start: commentStart,
|
||||||
|
end: commentEnd
|
||||||
|
}];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -40,6 +40,13 @@ exports.findNextMatch = function(startPos) {
|
|||||||
exports.parse = function() {
|
exports.parse = function() {
|
||||||
// Move past the match
|
// Move past the match
|
||||||
this.parser.pos = this.endMatchRegExp.lastIndex;
|
this.parser.pos = this.endMatchRegExp.lastIndex;
|
||||||
// Don't return any elements
|
// Return a node representing the inline comment
|
||||||
return [];
|
var commentStart = this.match.index;
|
||||||
|
var commentEnd = this.endMatch.index + this.endMatch[0].length;
|
||||||
|
return [{
|
||||||
|
type: "void",
|
||||||
|
text: this.parser.source.slice(commentStart, commentEnd),
|
||||||
|
start: commentStart,
|
||||||
|
end: commentEnd
|
||||||
|
}];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ exports.parse = function() {
|
|||||||
// Return the classed span
|
// Return the classed span
|
||||||
return [{
|
return [{
|
||||||
type: "element",
|
type: "element",
|
||||||
tag: "strike",
|
tag: "s",
|
||||||
children: tree
|
children: tree
|
||||||
}];
|
}];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ exports.init = function(parser) {
|
|||||||
|
|
||||||
exports.parse = function() {
|
exports.parse = function() {
|
||||||
// Move past the match
|
// Move past the match
|
||||||
var start = this.parser.pos;
|
var start = this.parser.pos;
|
||||||
this.parser.pos = this.matchRegExp.lastIndex;
|
this.parser.pos = this.matchRegExp.lastIndex;
|
||||||
// Create the link unless it is suppressed
|
// Create the link unless it is suppressed
|
||||||
if(this.match[0].substr(0,1) === "~") {
|
if(this.match[0].substr(0,1) === "~") {
|
||||||
return [{type: "text", text: this.match[0].substr(1)}];
|
return [{type: "text", text: this.match[0].substr(1), start: start, end: this.parser.pos}];
|
||||||
} else {
|
} else {
|
||||||
return [{
|
return [{
|
||||||
type: "element",
|
type: "element",
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ module-type: wikirule
|
|||||||
Wiki pragma rule for function, procedure and widget definitions
|
Wiki pragma rule for function, procedure and widget definitions
|
||||||
|
|
||||||
```
|
```
|
||||||
\function name(param:defaultvalue,param2:defaultvalue)
|
\function name(param:"defaultvalue", param2:"defaultvalue")
|
||||||
definition text
|
definition text
|
||||||
\end
|
\end
|
||||||
|
|
||||||
\procedure name(param:defaultvalue,param2:defaultvalue)
|
\procedure name(param:"defaultvalue", param2:"defaultvalue")
|
||||||
definition text
|
definition text
|
||||||
\end
|
\end
|
||||||
|
|
||||||
\widget $mywidget(param:defaultvalue,param2:defaultvalue)
|
\widget $mywidget(param:"defaultvalue", param2:"defaultvalue")
|
||||||
definition text
|
definition text
|
||||||
\end
|
\end
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ exports.parse = function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while(match && !match[1]);
|
} while(match && !match[1]);
|
||||||
// Return the nodes
|
// Mark first and last node, and return the nodes
|
||||||
|
if(tree[0]) tree[0].isRuleStart = true;
|
||||||
|
if(tree[tree.length-1]) tree[tree.length-1].isRuleEnd = true;
|
||||||
return tree;
|
return tree;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ Parse the most recent match
|
|||||||
exports.parse = function() {
|
exports.parse = function() {
|
||||||
// Retrieve the most recent match so that recursive calls don't overwrite it
|
// Retrieve the most recent match so that recursive calls don't overwrite it
|
||||||
var tag = this.nextTag;
|
var tag = this.nextTag;
|
||||||
if (!tag.isSelfClosing) {
|
if(!tag.isSelfClosing) {
|
||||||
tag.openTagStart = tag.start;
|
tag.openTagStart = tag.start;
|
||||||
tag.openTagEnd = tag.end;
|
tag.openTagEnd = tag.end;
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ exports.parse = function() {
|
|||||||
// Advance the parser position to past the tag
|
// Advance the parser position to past the tag
|
||||||
this.parser.pos = tag.end;
|
this.parser.pos = tag.end;
|
||||||
// Check for an immediately following double linebreak
|
// Check for an immediately following double linebreak
|
||||||
var hasLineBreak = !tag.isSelfClosing && !!$tw.utils.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/g);
|
var hasLineBreak = !tag.isSelfClosing && !!$tw.utils.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/y);
|
||||||
// Set whether we're in block mode
|
// Set whether we're in block mode
|
||||||
tag.isBlock = this.is.block || hasLineBreak;
|
tag.isBlock = this.is.block || hasLineBreak;
|
||||||
// Parse the body if we need to
|
// Parse the body if we need to
|
||||||
@@ -63,22 +63,22 @@ exports.parse = function() {
|
|||||||
}
|
}
|
||||||
tag.end = this.parser.pos;
|
tag.end = this.parser.pos;
|
||||||
tag.closeTagEnd = tag.end;
|
tag.closeTagEnd = tag.end;
|
||||||
if (tag.closeTagEnd === tag.openTagEnd || this.parser.source[tag.closeTagEnd - 1] !== '>') {
|
if(tag.closeTagEnd === tag.openTagEnd || this.parser.source[tag.closeTagEnd - 1] !== ">") {
|
||||||
tag.closeTagStart = tag.end;
|
tag.closeTagStart = tag.end;
|
||||||
} else {
|
} else {
|
||||||
tag.closeTagStart = tag.closeTagEnd - 2;
|
tag.closeTagStart = tag.closeTagEnd - 2;
|
||||||
var closeTagMinPos = tag.children.length > 0 ? tag.children[tag.children.length-1].end : tag.openTagEnd;
|
var closeTagMinPos = tag.children.length > 0 ? tag.children[tag.children.length-1].end : tag.openTagEnd;
|
||||||
if (!Number.isSafeInteger(closeTagMinPos)) closeTagMinPos = tag.openTagEnd;
|
if(!Number.isSafeInteger(closeTagMinPos)) closeTagMinPos = tag.openTagEnd;
|
||||||
while (tag.closeTagStart >= closeTagMinPos) {
|
while(tag.closeTagStart >= closeTagMinPos) {
|
||||||
var char = this.parser.source[tag.closeTagStart];
|
var char = this.parser.source[tag.closeTagStart];
|
||||||
if (char === '>') {
|
if(char === ">") {
|
||||||
tag.closeTagStart = -1;
|
tag.closeTagStart = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (char === '<') break;
|
if(char === "<") break;
|
||||||
tag.closeTagStart -= 1;
|
tag.closeTagStart -= 1;
|
||||||
}
|
}
|
||||||
if (tag.closeTagStart < closeTagMinPos) {
|
if(tag.closeTagStart < closeTagMinPos) {
|
||||||
tag.closeTagStart = tag.end;
|
tag.closeTagStart = tag.end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,7 +100,7 @@ exports.parseTag = function(source,pos,options) {
|
|||||||
orderedAttributes: []
|
orderedAttributes: []
|
||||||
};
|
};
|
||||||
// Define our regexps
|
// Define our regexps
|
||||||
var reTagName = /([a-zA-Z0-9\-\$\.]+)/g;
|
const reTagName = /([a-zA-Z0-9\-\$\.]+)/y;
|
||||||
// Skip whitespace
|
// Skip whitespace
|
||||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||||
// Look for a less than sign
|
// Look for a less than sign
|
||||||
@@ -148,7 +148,7 @@ exports.parseTag = function(source,pos,options) {
|
|||||||
pos = token.end;
|
pos = token.end;
|
||||||
// Check for a required line break
|
// Check for a required line break
|
||||||
if(options.requireLineBreak) {
|
if(options.requireLineBreak) {
|
||||||
token = $tw.utils.parseTokenRegExp(source,pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/g);
|
token = $tw.utils.parseTokenRegExp(source,pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/y);
|
||||||
if(!token) {
|
if(!token) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ exports.parseImage = function(source,pos) {
|
|||||||
// Skip whitespace
|
// Skip whitespace
|
||||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||||
// Get the source up to the terminating `]]`
|
// Get the source up to the terminating `]]`
|
||||||
token = $tw.utils.parseTokenRegExp(source,pos,/(?:([^|\]]*?)\|)?([^\]]+?)\]\]/g);
|
token = $tw.utils.parseTokenRegExp(source,pos,/(?:([^|\]]*?)\|)?([^\]]+?)\]\]/y);
|
||||||
if(!token) {
|
if(!token) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ var listTypes = {
|
|||||||
":": {listTag: "dl", itemTag: "dd"},
|
":": {listTag: "dl", itemTag: "dd"},
|
||||||
">": {listTag: "blockquote", itemTag: "div"}
|
">": {listTag: "blockquote", itemTag: "div"}
|
||||||
};
|
};
|
||||||
|
exports.listTypes = listTypes;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Parse the most recent match
|
Parse the most recent match
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ exports.findNextMatch = function(startPos) {
|
|||||||
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
|
||||||
// If we didn't need to support IE, we'd just use /(?:\r?\n|$)/ym
|
// If we didn't need to support IE, we'd just use /(?:\r?\n|$)/ym
|
||||||
if ((c === "") || (c === "\n") || ((c === "\r") && this.parser.source.charAt(nextCall.end+1) === "\n")) {
|
if((c === "") || (c === "\n") || ((c === "\r") && this.parser.source.charAt(nextCall.end+1) === "\n")) {
|
||||||
this.nextCall = nextCall;
|
this.nextCall = nextCall;
|
||||||
return nextStart;
|
return nextStart;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,3 +42,5 @@ exports.parse = function() {
|
|||||||
this.parser.pos = call.end;
|
this.parser.pos = call.end;
|
||||||
return [call];
|
return [call];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -52,9 +52,10 @@ exports.parse = function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Is the remainder of the \define line blank after the parameter close paren?
|
// Is the remainder of the \define line blank after the parameter close paren?
|
||||||
var reEnd;
|
var reEnd,isBlock = true;
|
||||||
if(this.match[3]) {
|
if(this.match[3]) {
|
||||||
// If so, it is a multiline definition and the end of the body is marked with \end
|
// If so, it is a multiline definition and the end of the body is marked with \end
|
||||||
|
isBlock = false;
|
||||||
reEnd = new RegExp("((?:^|\\r?\\n)[^\\S\\n\\r]*\\\\end[^\\S\\n\\r]*(?:" + $tw.utils.escapeRegExp(this.match[1]) + ")?\\s*?(?:$|\\r?\\n))","mg");
|
reEnd = new RegExp("((?:^|\\r?\\n)[^\\S\\n\\r]*\\\\end[^\\S\\n\\r]*(?:" + $tw.utils.escapeRegExp(this.match[1]) + ")?\\s*?(?:$|\\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
|
||||||
@@ -79,7 +80,8 @@ exports.parse = function() {
|
|||||||
attributes: {},
|
attributes: {},
|
||||||
children: [],
|
children: [],
|
||||||
params: params,
|
params: params,
|
||||||
isMacroDefinition: true
|
isMacroDefinition: true,
|
||||||
|
isBlock: isBlock && !!endMatch
|
||||||
}];
|
}];
|
||||||
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],"name",this.match[1]);
|
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],"name",this.match[1]);
|
||||||
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],"value",text);
|
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],"value",text);
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ Parse the most recent match
|
|||||||
*/
|
*/
|
||||||
exports.parse = function() {
|
exports.parse = function() {
|
||||||
// Move past the pragma invocation
|
// Move past the pragma invocation
|
||||||
|
var start = this.parser.pos;
|
||||||
this.parser.pos = this.matchRegExp.lastIndex;
|
this.parser.pos = this.matchRegExp.lastIndex;
|
||||||
// Parse whitespace delimited tokens terminated by a line break
|
// Parse whitespace delimited tokens terminated by a line break
|
||||||
var reMatch = /[^\S\n]*(\S+)|(\r?\n)/mg,
|
var reMatch = /[^\S\n]*(\S+)|(\r?\n)/mg,
|
||||||
@@ -58,6 +59,11 @@ exports.parse = function() {
|
|||||||
this.parser.parseAsInline = true;
|
this.parser.parseAsInline = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No parse tree nodes to return
|
return [{
|
||||||
return [];
|
type: "void",
|
||||||
|
children: [],
|
||||||
|
parseAsInline: this.parser.parseAsInline,
|
||||||
|
start: start,
|
||||||
|
end: this.parser.pos
|
||||||
|
}];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -113,3 +113,5 @@ exports.parseLink = function(source,pos) {
|
|||||||
node.end = closePos + 2;
|
node.end = closePos + 2;
|
||||||
return node;
|
return node;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ exports.parse = function() {
|
|||||||
var text = this.match[1],
|
var text = this.match[1],
|
||||||
link = this.match[2] || text,
|
link = this.match[2] || text,
|
||||||
textEndPos = this.parser.source.indexOf("|", start);
|
textEndPos = this.parser.source.indexOf("|", start);
|
||||||
if (textEndPos < 0 || textEndPos > this.matchRegExp.lastIndex) {
|
if(textEndPos < 0 || textEndPos > this.matchRegExp.lastIndex) {
|
||||||
textEndPos = this.matchRegExp.lastIndex - 2;
|
textEndPos = this.matchRegExp.lastIndex - 2;
|
||||||
}
|
}
|
||||||
var linkStart = this.match[2] ? (start + this.match[1].length + 1) : start;
|
var linkStart = this.match[2] ? (start + this.match[1].length + 1) : start;
|
||||||
|
|||||||
@@ -54,6 +54,13 @@ exports.parse = function() {
|
|||||||
if(tokens.length > 0) {
|
if(tokens.length > 0) {
|
||||||
this.parser.amendRules(tokens[0],tokens.slice(1));
|
this.parser.amendRules(tokens[0],tokens.slice(1));
|
||||||
}
|
}
|
||||||
// No parse tree nodes to return
|
// No widget to render, return void node.
|
||||||
return [];
|
return [{
|
||||||
|
type: "void",
|
||||||
|
attributes: {
|
||||||
|
action: {type: "string", value: tokens[0]},
|
||||||
|
rules: {type: "string", value: tokens.slice(1).join(" ")}
|
||||||
|
},
|
||||||
|
children: []
|
||||||
|
}];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -64,5 +64,8 @@ exports.parse = function() {
|
|||||||
$tw.utils.addAttributeToParseTreeNode(tree[t],"style",styles.join(""));
|
$tw.utils.addAttributeToParseTreeNode(tree[t],"style",styles.join(""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tree;
|
return [{
|
||||||
|
type: "void",
|
||||||
|
children: tree
|
||||||
|
}]
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,7 +21,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 /@@(styles)?\s*(\.class\s+)?/
|
||||||
this.matchRegExp = /@@((?:[^\.\r\n\s:]+:[^\r\n;]+;)+)?(\.(?:[^\r\n\s]+)\s+)?/mg;
|
this.matchRegExp = /@@((?:[^\.\r\n\s:]+:[^\r\n;]+;)+)?(\.(?:[^\r\n\s]+)\s+)?/mg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,27 @@ exports.init = function(parser) {
|
|||||||
this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?(?:\|([^\{\}]+))?\}\}(?:\r?\n|$)/mg;
|
this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?(?:\|([^\{\}]+))?\}\}(?:\r?\n|$)/mg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Reject the match if we don't have a template or text reference
|
||||||
|
*/
|
||||||
|
exports.findNextMatch = function(startPos) {
|
||||||
|
this.matchRegExp.lastIndex = startPos;
|
||||||
|
this.match = this.matchRegExp.exec(this.parser.source);
|
||||||
|
if(this.match) {
|
||||||
|
var template = $tw.utils.trim(this.match[2]),
|
||||||
|
textRef = $tw.utils.trim(this.match[1]);
|
||||||
|
// Bail if we don't have a template or text reference
|
||||||
|
if(!template && !textRef) {
|
||||||
|
return undefined;
|
||||||
|
} else {
|
||||||
|
return this.match.index;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return this.match ? this.match.index : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
exports.parse = function() {
|
exports.parse = function() {
|
||||||
// Move past the match
|
// Move past the match
|
||||||
this.parser.pos = this.matchRegExp.lastIndex;
|
this.parser.pos = this.matchRegExp.lastIndex;
|
||||||
|
|||||||
@@ -23,6 +23,27 @@ exports.init = function(parser) {
|
|||||||
this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?(?:\|([^\{\}]+))?\}\}/mg;
|
this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?(?:\|([^\{\}]+))?\}\}/mg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Reject the match if we don't have a template or text reference
|
||||||
|
*/
|
||||||
|
exports.findNextMatch = function(startPos) {
|
||||||
|
this.matchRegExp.lastIndex = startPos;
|
||||||
|
this.match = this.matchRegExp.exec(this.parser.source);
|
||||||
|
if(this.match) {
|
||||||
|
var template = $tw.utils.trim(this.match[2]),
|
||||||
|
textRef = $tw.utils.trim(this.match[1]);
|
||||||
|
// Bail if we don't have a template or text reference
|
||||||
|
if(!template && !textRef) {
|
||||||
|
return undefined;
|
||||||
|
} else {
|
||||||
|
return this.match.index;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return this.match ? this.match.index : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
exports.parse = function() {
|
exports.parse = function() {
|
||||||
// Move past the match
|
// Move past the match
|
||||||
this.parser.pos = this.matchRegExp.lastIndex;
|
this.parser.pos = this.matchRegExp.lastIndex;
|
||||||
|
|||||||
@@ -60,22 +60,37 @@ exports.parse = function() {
|
|||||||
var parser = this.parser.wiki.parseText(parseType,text,{defaultType: "text/plain"});
|
var parser = this.parser.wiki.parseText(parseType,text,{defaultType: "text/plain"});
|
||||||
// If there's no render type, just return the parse tree
|
// If there's no render type, just return the parse tree
|
||||||
if(!renderType) {
|
if(!renderType) {
|
||||||
return parser.tree;
|
return [{
|
||||||
|
type: "void",
|
||||||
|
children: $tw.utils.isArray(parser.tree) ? parser.tree : [parser.tree],
|
||||||
|
parseType: parseType,
|
||||||
|
renderType: renderType,
|
||||||
|
text: text,
|
||||||
|
start: start,
|
||||||
|
end: this.parser.pos
|
||||||
|
}];
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, render to the rendertype and return in a <PRE> tag
|
// Otherwise, render to the rendertype and return in a <PRE> tag
|
||||||
var widgetNode = this.parser.wiki.makeWidget(parser),
|
var widgetNode = this.parser.wiki.makeWidget(parser),
|
||||||
container = $tw.fakeDocument.createElement("div");
|
container = $tw.fakeDocument.createElement("div");
|
||||||
widgetNode.render(container,null);
|
widgetNode.render(container,null);
|
||||||
text = renderType === "text/html" ? container.innerHTML : container.textContent;
|
var renderResult = renderType === "text/html" ? container.innerHTML : container.textContent;
|
||||||
|
// Use void node to carry important info for typedblock
|
||||||
return [{
|
return [{
|
||||||
type: "element",
|
type: "void",
|
||||||
tag: "pre",
|
|
||||||
children: [{
|
children: [{
|
||||||
type: "text",
|
type: "element",
|
||||||
text: text,
|
tag: "pre",
|
||||||
start: start,
|
children: [{
|
||||||
end: this.parser.pos
|
type: "text",
|
||||||
}]
|
text: renderResult,
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
parseType: parseType,
|
||||||
|
renderType: renderType,
|
||||||
|
text: text,
|
||||||
|
start: start,
|
||||||
|
end: this.parser.pos
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -215,8 +215,8 @@ WikiParser.prototype.parsePragmas = function() {
|
|||||||
var subTree = nextMatch.rule.parse();
|
var subTree = nextMatch.rule.parse();
|
||||||
if(subTree.length > 0) {
|
if(subTree.length > 0) {
|
||||||
// Set the start and end positions of the pragma rule if
|
// Set the start and end positions of the pragma rule if
|
||||||
if (subTree[0].start === undefined) subTree[0].start = start;
|
if(subTree[0].start === undefined) subTree[0].start = start;
|
||||||
if (subTree[subTree.length - 1].end === undefined) subTree[subTree.length - 1].end = this.pos;
|
if(subTree[subTree.length - 1].end === undefined) subTree[subTree.length - 1].end = this.pos;
|
||||||
$tw.utils.each(subTree, function (node) { node.rule = nextMatch.rule.name; });
|
$tw.utils.each(subTree, function (node) { node.rule = nextMatch.rule.name; });
|
||||||
// Quick hack; we only cope with a single parse tree node being returned, which is true at the moment
|
// Quick hack; we only cope with a single parse tree node being returned, which is true at the moment
|
||||||
currentTreeBranch.push.apply(currentTreeBranch,subTree);
|
currentTreeBranch.push.apply(currentTreeBranch,subTree);
|
||||||
@@ -245,9 +245,9 @@ WikiParser.prototype.parseBlock = function(terminatorRegExpString) {
|
|||||||
var start = this.pos;
|
var start = this.pos;
|
||||||
var subTree = nextMatch.rule.parse();
|
var subTree = nextMatch.rule.parse();
|
||||||
// Set the start and end positions of the first and last blocks if they're not already set
|
// Set the start and end positions of the first and last blocks if they're not already set
|
||||||
if (subTree.length > 0) {
|
if(subTree.length > 0) {
|
||||||
if (subTree[0].start === undefined) subTree[0].start = start;
|
if(subTree[0].start === undefined) subTree[0].start = start;
|
||||||
if (subTree[subTree.length - 1].end === undefined) subTree[subTree.length - 1].end = this.pos;
|
if(subTree[subTree.length - 1].end === undefined) subTree[subTree.length - 1].end = this.pos;
|
||||||
}
|
}
|
||||||
$tw.utils.each(subTree, function (node) { node.rule = nextMatch.rule.name; });
|
$tw.utils.each(subTree, function (node) { node.rule = nextMatch.rule.name; });
|
||||||
return subTree;
|
return subTree;
|
||||||
@@ -256,7 +256,7 @@ WikiParser.prototype.parseBlock = function(terminatorRegExpString) {
|
|||||||
var start = this.pos;
|
var start = this.pos;
|
||||||
var children = this.parseInlineRun(terminatorRegExp);
|
var children = this.parseInlineRun(terminatorRegExp);
|
||||||
var end = this.pos;
|
var end = this.pos;
|
||||||
return [{type: "element", tag: "p", children: children, start: start, end: end }];
|
return [{type: "element", tag: "p", children: children, start: start, end: end, rule: "parseblock" }];
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -350,10 +350,10 @@ WikiParser.prototype.parseInlineRunUnterminated = function(options) {
|
|||||||
var start = this.pos;
|
var start = this.pos;
|
||||||
var subTree = nextMatch.rule.parse();
|
var subTree = nextMatch.rule.parse();
|
||||||
// Set the start and end positions of the first and last child if they're not already set
|
// Set the start and end positions of the first and last child if they're not already set
|
||||||
if (subTree.length > 0) {
|
if(subTree.length > 0) {
|
||||||
// Set the start and end positions of the first and last child if they're not already set
|
// Set the start and end positions of the first and last child if they're not already set
|
||||||
if (subTree[0].start === undefined) subTree[0].start = start;
|
if(subTree[0].start === undefined) subTree[0].start = start;
|
||||||
if (subTree[subTree.length - 1].end === undefined) subTree[subTree.length - 1].end = this.pos;
|
if(subTree[subTree.length - 1].end === undefined) subTree[subTree.length - 1].end = this.pos;
|
||||||
}
|
}
|
||||||
$tw.utils.each(subTree, function (node) { node.rule = nextMatch.rule.name; });
|
$tw.utils.each(subTree, function (node) { node.rule = nextMatch.rule.name; });
|
||||||
tree.push.apply(tree,subTree);
|
tree.push.apply(tree,subTree);
|
||||||
@@ -410,9 +410,9 @@ WikiParser.prototype.parseInlineRunTerminatedExtended = function(terminatorRegEx
|
|||||||
var start = this.pos;
|
var start = this.pos;
|
||||||
var subTree = inlineRuleMatch.rule.parse();
|
var subTree = inlineRuleMatch.rule.parse();
|
||||||
// Set the start and end positions of the first and last child if they're not already set
|
// Set the start and end positions of the first and last child if they're not already set
|
||||||
if (subTree.length > 0) {
|
if(subTree.length > 0) {
|
||||||
if (subTree[0].start === undefined) subTree[0].start = start;
|
if(subTree[0].start === undefined) subTree[0].start = start;
|
||||||
if (subTree[subTree.length - 1].end === undefined) subTree[subTree.length - 1].end = this.pos;
|
if(subTree[subTree.length - 1].end === undefined) subTree[subTree.length - 1].end = this.pos;
|
||||||
}
|
}
|
||||||
$tw.utils.each(subTree, function (node) { node.rule = inlineRuleMatch.rule.name; });
|
$tw.utils.each(subTree, function (node) { node.rule = inlineRuleMatch.rule.name; });
|
||||||
tree.push.apply(tree,subTree);
|
tree.push.apply(tree,subTree);
|
||||||
|
|||||||
@@ -35,7 +35,9 @@ DownloadSaver.prototype.save = function(text,method,callback,options) {
|
|||||||
}
|
}
|
||||||
// Set up the link
|
// Set up the link
|
||||||
var link = document.createElement("a");
|
var link = document.createElement("a");
|
||||||
if(Blob !== undefined) {
|
// We prefer Blobs if they're available, unless we're dealing with a tiddler type declaring itself full of base64 encoded content.
|
||||||
|
// Then we use data urls, because browsers will know to decode the stream and download the actual binary file as intended.
|
||||||
|
if(Blob !== undefined && !type.includes(";base64")) {
|
||||||
var blob = new Blob([text], {type: type});
|
var blob = new Blob([text], {type: type});
|
||||||
link.setAttribute("href", URL.createObjectURL(blob));
|
link.setAttribute("href", URL.createObjectURL(blob));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
66
core/modules/savers/postmessage.js
Normal file
66
core/modules/savers/postmessage.js
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/savers/postmessage.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: saver
|
||||||
|
|
||||||
|
Handles saving changes via window.postMessage() to the window.parent
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Select the appropriate saver module and set it up
|
||||||
|
*/
|
||||||
|
var PostMessageSaver = function(wiki) {
|
||||||
|
this.publisher = new $tw.utils.BrowserMessagingPublisher({type: "SAVE"});
|
||||||
|
};
|
||||||
|
|
||||||
|
PostMessageSaver.prototype.save = function(text,method,callback,options) {
|
||||||
|
// Fail if the publisher hasn't been fully initialised
|
||||||
|
if(!this.publisher.canSend()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Send the save request
|
||||||
|
this.publisher.send({
|
||||||
|
verb: "SAVE",
|
||||||
|
body: text
|
||||||
|
},function(err) {
|
||||||
|
if(err) {
|
||||||
|
callback("PostMessageSaver Error: " + err);
|
||||||
|
} else {
|
||||||
|
callback(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Indicate that we handled the save
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Information about this saver
|
||||||
|
*/
|
||||||
|
PostMessageSaver.prototype.info = {
|
||||||
|
name: "postmessage",
|
||||||
|
capabilities: ["save", "autosave"],
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Static method that returns true if this saver is capable of working
|
||||||
|
*/
|
||||||
|
exports.canSave = function(wiki) {
|
||||||
|
// Provisionally say that we can save
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create an instance of this saver
|
||||||
|
*/
|
||||||
|
exports.create = function(wiki) {
|
||||||
|
return new PostMessageSaver(wiki);
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
/*\
|
|
||||||
title: $:/core/modules/server/routes/get-file.js
|
|
||||||
type: application/javascript
|
|
||||||
module-type: route
|
|
||||||
|
|
||||||
GET /files/:filepath
|
|
||||||
|
|
||||||
\*/
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
exports.method = "GET";
|
|
||||||
|
|
||||||
exports.path = /^\/files\/(.+)$/;
|
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
|
||||||
var path = require("path"),
|
|
||||||
fs = require("fs"),
|
|
||||||
util = require("util"),
|
|
||||||
suppliedFilename = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
|
||||||
baseFilename = path.resolve(state.boot.wikiPath,"files"),
|
|
||||||
filename = path.resolve(baseFilename,suppliedFilename),
|
|
||||||
extension = path.extname(filename);
|
|
||||||
// Check that the filename is inside the wiki files folder
|
|
||||||
if(path.relative(baseFilename,filename).indexOf("..") !== 0) {
|
|
||||||
// Send the file
|
|
||||||
fs.readFile(filename,function(err,content) {
|
|
||||||
var status,content,type = "text/plain";
|
|
||||||
if(err) {
|
|
||||||
console.log("Error accessing file " + filename + ": " + err.toString());
|
|
||||||
status = 404;
|
|
||||||
content = "File '" + suppliedFilename + "' not found";
|
|
||||||
} else {
|
|
||||||
status = 200;
|
|
||||||
content = content;
|
|
||||||
type = ($tw.config.fileExtensionInfo[extension] ? $tw.config.fileExtensionInfo[extension].type : "application/octet-stream");
|
|
||||||
}
|
|
||||||
state.sendResponse(status,{"Content-Type": type},content);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
state.sendResponse(404,{"Content-Type": "text/plain"},"File '" + suppliedFilename + "' not found");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
46
core/modules/startup/eventbus.js
Normal file
46
core/modules/startup/eventbus.js
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/startup/eventbus.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: startup
|
||||||
|
|
||||||
|
Event bus for cross module communication
|
||||||
|
\*/
|
||||||
|
|
||||||
|
exports.name = "eventbus";
|
||||||
|
exports.platforms = ["browser"];
|
||||||
|
exports.before = ["windows"];
|
||||||
|
exports.synchronous = true;
|
||||||
|
|
||||||
|
$tw.eventBus = {
|
||||||
|
listenersMap: new Map(),
|
||||||
|
|
||||||
|
on(event,handler) {
|
||||||
|
if(!this.listenersMap.has(event)) {
|
||||||
|
this.listenersMap.set(event,new Set());
|
||||||
|
}
|
||||||
|
const listeners = this.listenersMap.get(event);
|
||||||
|
listeners.add(handler);
|
||||||
|
},
|
||||||
|
|
||||||
|
off(event,handler) {
|
||||||
|
const listeners = this.listenersMap.get(event);
|
||||||
|
if(listeners) {
|
||||||
|
listeners.delete(handler);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
once(event,handler) {
|
||||||
|
const wrapper = (...args) => {
|
||||||
|
handler(...args);
|
||||||
|
this.off(event, wrapper);
|
||||||
|
};
|
||||||
|
this.on(event, wrapper);
|
||||||
|
},
|
||||||
|
|
||||||
|
emit(event,data) {
|
||||||
|
const listeners = this.listenersMap.get(event);
|
||||||
|
if(listeners) {
|
||||||
|
listeners.forEach(fn => fn(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -19,6 +19,16 @@ exports.synchronous = true;
|
|||||||
var FAVICON_TITLE = "$:/favicon.ico";
|
var FAVICON_TITLE = "$:/favicon.ico";
|
||||||
|
|
||||||
exports.startup = function() {
|
exports.startup = function() {
|
||||||
|
var setFavicon = function() {
|
||||||
|
var tiddler = $tw.wiki.getTiddler(FAVICON_TITLE);
|
||||||
|
if(tiddler) {
|
||||||
|
var faviconLink = document.getElementById("faviconLink"),
|
||||||
|
dataURI = $tw.utils.makeDataUri(tiddler.fields.text,tiddler.fields.type,tiddler.fields._canonical_uri);
|
||||||
|
faviconLink.setAttribute("href",dataURI);
|
||||||
|
$tw.faviconPublisher.send({verb: "FAVICON",body: dataURI});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$tw.faviconPublisher = new $tw.utils.BrowserMessagingPublisher({type: "FAVICON", onsubscribe: setFavicon});
|
||||||
// Set up the favicon
|
// Set up the favicon
|
||||||
setFavicon();
|
setFavicon();
|
||||||
// Reset the favicon when the tiddler changes
|
// Reset the favicon when the tiddler changes
|
||||||
@@ -28,11 +38,3 @@ exports.startup = function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function setFavicon() {
|
|
||||||
var tiddler = $tw.wiki.getTiddler(FAVICON_TITLE);
|
|
||||||
if(tiddler) {
|
|
||||||
var faviconLink = document.getElementById("faviconLink");
|
|
||||||
faviconLink.setAttribute("href",$tw.utils.makeDataUri(tiddler.fields.text,tiddler.fields.type,tiddler.fields._canonical_uri));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -19,11 +19,17 @@ var TITLE_INFO_PLUGIN = "$:/temp/info-plugin";
|
|||||||
|
|
||||||
exports.startup = function() {
|
exports.startup = function() {
|
||||||
// Function to bake the info plugin with new tiddlers
|
// Function to bake the info plugin with new tiddlers
|
||||||
var updateInfoPlugin = function(tiddlerFieldsArray) {
|
// additions: array of tiddler field objects
|
||||||
|
// removals: array of titles to remove
|
||||||
|
var updateInfoPlugin = function(additions = [], removals = []) {
|
||||||
// Get the existing tiddlers
|
// Get the existing tiddlers
|
||||||
var json = $tw.wiki.getTiddlerData(TITLE_INFO_PLUGIN,{tiddlers: {}});
|
var json = $tw.wiki.getTiddlerData(TITLE_INFO_PLUGIN,{tiddlers: {}});
|
||||||
// Add the new ones
|
$tw.utils.each(removals,function(title) {
|
||||||
$tw.utils.each(tiddlerFieldsArray,function(fields) {
|
if(json.tiddlers[title]) {
|
||||||
|
delete json.tiddlers[title];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$tw.utils.each(additions,function(fields) {
|
||||||
if(fields && fields.title) {
|
if(fields && fields.title) {
|
||||||
json.tiddlers[fields.title] = fields;
|
json.tiddlers[fields.title] = fields;
|
||||||
}
|
}
|
||||||
@@ -47,7 +53,7 @@ exports.startup = function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
updateInfoPlugin(tiddlerFieldsArray);
|
updateInfoPlugin(tiddlerFieldsArray);
|
||||||
var changes = $tw.wiki.readPluginInfo([TITLE_INFO_PLUGIN]);
|
$tw.wiki.readPluginInfo([TITLE_INFO_PLUGIN]);
|
||||||
$tw.wiki.registerPluginTiddlers("info",[TITLE_INFO_PLUGIN]);
|
$tw.wiki.registerPluginTiddlers("info",[TITLE_INFO_PLUGIN]);
|
||||||
$tw.wiki.unpackPluginTiddlers();
|
$tw.wiki.unpackPluginTiddlers();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,5 +31,7 @@ exports.startup = function() {
|
|||||||
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
|
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
|
||||||
$tw.macros = $tw.modules.getModulesByTypeAsHashmap("macro");
|
$tw.macros = $tw.modules.getModulesByTypeAsHashmap("macro");
|
||||||
$tw.wiki.initParsers();
|
$tw.wiki.initParsers();
|
||||||
$tw.Commander.initCommands();
|
if($tw.node) {
|
||||||
|
$tw.Commander.initCommands();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -33,10 +33,15 @@ exports.startup = function() {
|
|||||||
});
|
});
|
||||||
$tw.titleContainer = $tw.fakeDocument.createElement("div");
|
$tw.titleContainer = $tw.fakeDocument.createElement("div");
|
||||||
$tw.titleWidgetNode.render($tw.titleContainer,null);
|
$tw.titleWidgetNode.render($tw.titleContainer,null);
|
||||||
document.title = $tw.titleContainer.textContent;
|
var publishTitle = function() {
|
||||||
|
$tw.titlePublisher.send({verb: "PAGETITLE",body: document.title});
|
||||||
|
document.title = $tw.titleContainer.textContent;
|
||||||
|
};
|
||||||
|
$tw.titlePublisher = new $tw.utils.BrowserMessagingPublisher({type: "PAGETITLE", onsubscribe: publishTitle});
|
||||||
|
publishTitle();
|
||||||
$tw.wiki.addEventListener("change",function(changes) {
|
$tw.wiki.addEventListener("change",function(changes) {
|
||||||
if($tw.titleWidgetNode.refresh(changes,$tw.titleContainer,null)) {
|
if($tw.titleWidgetNode.refresh(changes,$tw.titleContainer,null)) {
|
||||||
document.title = $tw.titleContainer.textContent;
|
publishTitle();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Set up the styles
|
// Set up the styles
|
||||||
|
|||||||
@@ -56,9 +56,11 @@ exports.startup = function() {
|
|||||||
srcDocument.write("<!DOCTYPE html><head></head><body class='tc-body tc-single-tiddler-window'></body></html>");
|
srcDocument.write("<!DOCTYPE html><head></head><body class='tc-body tc-single-tiddler-window'></body></html>");
|
||||||
srcDocument.close();
|
srcDocument.close();
|
||||||
srcDocument.title = windowTitle;
|
srcDocument.title = windowTitle;
|
||||||
|
$tw.eventBus.emit("window:opened",{windowID, window: srcWindow});
|
||||||
srcWindow.addEventListener("beforeunload",function(event) {
|
srcWindow.addEventListener("beforeunload",function(event) {
|
||||||
delete $tw.windows[windowID];
|
delete $tw.windows[windowID];
|
||||||
$tw.wiki.removeEventListener("change",refreshHandler);
|
$tw.wiki.removeEventListener("change",refreshHandler);
|
||||||
|
$tw.eventBus.emit("window:closed",{windowID});
|
||||||
},false);
|
},false);
|
||||||
// Set up the styles
|
// Set up the styles
|
||||||
var styleWidgetNode = $tw.wiki.makeTranscludeWidget("$:/core/ui/PageStylesheet",{
|
var styleWidgetNode = $tw.wiki.makeTranscludeWidget("$:/core/ui/PageStylesheet",{
|
||||||
|
|||||||
@@ -47,16 +47,16 @@ ClassicStoryView.prototype.insert = function(widget) {
|
|||||||
// Reset the margin once the transition is over
|
// Reset the margin once the transition is over
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
$tw.utils.setStyle(targetElement,[
|
$tw.utils.setStyle(targetElement,[
|
||||||
{transition: "none"},
|
|
||||||
{marginBottom: ""}
|
{marginBottom: ""}
|
||||||
]);
|
]);
|
||||||
|
$tw.utils.removeStyle(targetElement, "transition");
|
||||||
},duration);
|
},duration);
|
||||||
// Set up the initial position of the element
|
// Set up the initial position of the element
|
||||||
$tw.utils.setStyle(targetElement,[
|
$tw.utils.setStyle(targetElement,[
|
||||||
{transition: "none"},
|
|
||||||
{marginBottom: (-currHeight) + "px"},
|
{marginBottom: (-currHeight) + "px"},
|
||||||
{opacity: "0.0"}
|
{opacity: "0.0"}
|
||||||
]);
|
]);
|
||||||
|
$tw.utils.removeStyle(targetElement, "transition");
|
||||||
$tw.utils.forceLayout(targetElement);
|
$tw.utils.forceLayout(targetElement);
|
||||||
// Transition to the final position
|
// Transition to the final position
|
||||||
$tw.utils.setStyle(targetElement,[
|
$tw.utils.setStyle(targetElement,[
|
||||||
@@ -64,7 +64,7 @@ ClassicStoryView.prototype.insert = function(widget) {
|
|||||||
"margin-bottom " + duration + "ms " + easing},
|
"margin-bottom " + duration + "ms " + easing},
|
||||||
{marginBottom: currMarginBottom + "px"},
|
{marginBottom: currMarginBottom + "px"},
|
||||||
{opacity: "1.0"}
|
{opacity: "1.0"}
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -94,11 +94,9 @@ ClassicStoryView.prototype.remove = function(widget) {
|
|||||||
setTimeout(removeElement,duration);
|
setTimeout(removeElement,duration);
|
||||||
// Animate the closure
|
// Animate the closure
|
||||||
$tw.utils.setStyle(targetElement,[
|
$tw.utils.setStyle(targetElement,[
|
||||||
{transition: "none"},
|
|
||||||
{transform: "translateX(0px)"},
|
|
||||||
{marginBottom: currMarginBottom + "px"},
|
{marginBottom: currMarginBottom + "px"},
|
||||||
{opacity: "1.0"}
|
|
||||||
]);
|
]);
|
||||||
|
$tw.utils.removeStyles(targetElement, ["transition", "transform", "opacity"]);
|
||||||
$tw.utils.forceLayout(targetElement);
|
$tw.utils.forceLayout(targetElement);
|
||||||
$tw.utils.setStyle(targetElement,[
|
$tw.utils.setStyle(targetElement,[
|
||||||
{transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms " + easing + ", " +
|
{transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms " + easing + ", " +
|
||||||
@@ -113,4 +111,4 @@ ClassicStoryView.prototype.remove = function(widget) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.classic = ClassicStoryView;
|
exports.classic = ClassicStoryView;
|
||||||
@@ -37,10 +37,7 @@ PopStoryView.prototype.insert = function(widget) {
|
|||||||
}
|
}
|
||||||
// Reset once the transition is over
|
// Reset once the transition is over
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
$tw.utils.setStyle(targetElement,[
|
$tw.utils.removeStyles(targetElement, ["transition", "transform"]);
|
||||||
{transition: "none"},
|
|
||||||
{transform: "none"}
|
|
||||||
]);
|
|
||||||
$tw.utils.setStyle(widget.document.body,[
|
$tw.utils.setStyle(widget.document.body,[
|
||||||
{"overflow-x": ""}
|
{"overflow-x": ""}
|
||||||
]);
|
]);
|
||||||
@@ -51,10 +48,10 @@ PopStoryView.prototype.insert = function(widget) {
|
|||||||
]);
|
]);
|
||||||
// Set up the initial position of the element
|
// Set up the initial position of the element
|
||||||
$tw.utils.setStyle(targetElement,[
|
$tw.utils.setStyle(targetElement,[
|
||||||
{transition: "none"},
|
|
||||||
{transform: "scale(2)"},
|
{transform: "scale(2)"},
|
||||||
{opacity: "0.0"}
|
{opacity: "0.0"}
|
||||||
]);
|
]);
|
||||||
|
$tw.utils.removeStyle(targetElement, "transition");
|
||||||
$tw.utils.forceLayout(targetElement);
|
$tw.utils.forceLayout(targetElement);
|
||||||
// Transition to the final position
|
// Transition to the final position
|
||||||
$tw.utils.setStyle(targetElement,[
|
$tw.utils.setStyle(targetElement,[
|
||||||
@@ -63,6 +60,9 @@ PopStoryView.prototype.insert = function(widget) {
|
|||||||
{transform: "scale(1)"},
|
{transform: "scale(1)"},
|
||||||
{opacity: "1.0"}
|
{opacity: "1.0"}
|
||||||
]);
|
]);
|
||||||
|
setTimeout(function() {
|
||||||
|
$tw.utils.removeStyles(targetElement, ["transition", "transform", "opactity"]);
|
||||||
|
}, duration)
|
||||||
};
|
};
|
||||||
|
|
||||||
PopStoryView.prototype.remove = function(widget) {
|
PopStoryView.prototype.remove = function(widget) {
|
||||||
@@ -81,11 +81,7 @@ PopStoryView.prototype.remove = function(widget) {
|
|||||||
// Remove the element at the end of the transition
|
// Remove the element at the end of the transition
|
||||||
setTimeout(removeElement,duration);
|
setTimeout(removeElement,duration);
|
||||||
// Animate the closure
|
// Animate the closure
|
||||||
$tw.utils.setStyle(targetElement,[
|
$tw.utils.removeStyles(targetElement, ["transition", "transform", "opacity"]);
|
||||||
{transition: "none"},
|
|
||||||
{transform: "scale(1)"},
|
|
||||||
{opacity: "1.0"}
|
|
||||||
]);
|
|
||||||
$tw.utils.forceLayout(targetElement);
|
$tw.utils.forceLayout(targetElement);
|
||||||
$tw.utils.setStyle(targetElement,[
|
$tw.utils.setStyle(targetElement,[
|
||||||
{transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms ease-in-out, " +
|
{transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms ease-in-out, " +
|
||||||
@@ -95,4 +91,4 @@ PopStoryView.prototype.remove = function(widget) {
|
|||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.pop = PopStoryView;
|
exports.pop = PopStoryView;
|
||||||
@@ -96,6 +96,9 @@ ZoominListView.prototype.navigateTo = function(historyInfo) {
|
|||||||
{transform: "translateX(0px) translateY(0px) scale(1)"},
|
{transform: "translateX(0px) translateY(0px) scale(1)"},
|
||||||
{zIndex: "500"},
|
{zIndex: "500"},
|
||||||
]);
|
]);
|
||||||
|
setTimeout(function() {
|
||||||
|
$tw.utils.removeStyles(targetElement, ["transition", "opacity", "transform", "zIndex"]);
|
||||||
|
}, duration);
|
||||||
// Transform the previous tiddler out of the way and then hide it
|
// Transform the previous tiddler out of the way and then hide it
|
||||||
if(prevCurrentTiddler && prevCurrentTiddler !== targetElement) {
|
if(prevCurrentTiddler && prevCurrentTiddler !== targetElement) {
|
||||||
scale = zoomBounds.width / sourceBounds.width;
|
scale = zoomBounds.width / sourceBounds.width;
|
||||||
@@ -207,6 +210,9 @@ ZoominListView.prototype.remove = function(widget) {
|
|||||||
{opacity: "0"},
|
{opacity: "0"},
|
||||||
{zIndex: "0"}
|
{zIndex: "0"}
|
||||||
]);
|
]);
|
||||||
|
setTimeout(function() {
|
||||||
|
$tw.utils.removeStyles(toWidgetDomNode, ["transformOrigin", "transform", "transition", "opacity", "zIndex"]);
|
||||||
|
}, duration);
|
||||||
setTimeout(removeElement,duration);
|
setTimeout(removeElement,duration);
|
||||||
// Now the tiddler we're going back to
|
// Now the tiddler we're going back to
|
||||||
if(toWidgetDomNode) {
|
if(toWidgetDomNode) {
|
||||||
@@ -222,4 +228,4 @@ ZoominListView.prototype.logTextNodeRoot = function(node) {
|
|||||||
this.textNodeLogger.log($tw.language.getString("Error/ZoominTextNode") + " " + node.textContent);
|
this.textNodeLogger.log($tw.language.getString("Error/ZoominTextNode") + " " + node.textContent);
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.zoomin = ZoominListView;
|
exports.zoomin = ZoominListView;
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
// From https://gist.github.com/Nijikokun/5192472
|
|
||||||
//
|
|
||||||
// UTF8 Module
|
|
||||||
//
|
|
||||||
// Cleaner and modularized utf-8 encoding and decoding library for javascript.
|
|
||||||
//
|
|
||||||
// copyright: MIT
|
|
||||||
// author: Nijiko Yonskai, @nijikokun, nijikokun@gmail.com
|
|
||||||
(function (name, definition, context, dependencies) {
|
|
||||||
if (typeof context['module'] !== 'undefined' && context['module']['exports']) { if (dependencies && context['require']) { for (var i = 0; i < dependencies.length; i++) context[dependencies[i]] = context['require'](dependencies[i]); } context['module']['exports'] = definition.apply(context); }
|
|
||||||
else if (typeof context['define'] !== 'undefined' && context['define'] === 'function' && context['define']['amd']) { define(name, (dependencies || []), definition); }
|
|
||||||
else { context[name] = definition.apply(context); }
|
|
||||||
})('utf8', function () {
|
|
||||||
return {
|
|
||||||
encode: function (string) {
|
|
||||||
if (typeof string !== 'string') return string;
|
|
||||||
else string = string.replace(/\r\n/g, "\n");
|
|
||||||
var output = "", i = 0, charCode;
|
|
||||||
|
|
||||||
for (i; i < string.length; i++) {
|
|
||||||
charCode = string.charCodeAt(i);
|
|
||||||
|
|
||||||
if (charCode < 128) {
|
|
||||||
output += String.fromCharCode(charCode);
|
|
||||||
} else if ((charCode > 127) && (charCode < 2048)) {
|
|
||||||
output += String.fromCharCode((charCode >> 6) | 192);
|
|
||||||
output += String.fromCharCode((charCode & 63) | 128);
|
|
||||||
} else if ((charCode > 55295) && (charCode < 57344) && string.length > i+1) {
|
|
||||||
// Surrogate pair
|
|
||||||
var hiSurrogate = charCode;
|
|
||||||
var loSurrogate = string.charCodeAt(i+1);
|
|
||||||
i++; // Skip the low surrogate on the next loop pass
|
|
||||||
var codePoint = (((hiSurrogate - 55296) << 10) | (loSurrogate - 56320)) + 65536;
|
|
||||||
output += String.fromCharCode((codePoint >> 18) | 240);
|
|
||||||
output += String.fromCharCode(((codePoint >> 12) & 63) | 128);
|
|
||||||
output += String.fromCharCode(((codePoint >> 6) & 63) | 128);
|
|
||||||
output += String.fromCharCode((codePoint & 63) | 128);
|
|
||||||
} else {
|
|
||||||
// Not a surrogate pair, or a dangling surrogate without its partner that we'll just encode as-is
|
|
||||||
output += String.fromCharCode((charCode >> 12) | 224);
|
|
||||||
output += String.fromCharCode(((charCode >> 6) & 63) | 128);
|
|
||||||
output += String.fromCharCode((charCode & 63) | 128);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
},
|
|
||||||
|
|
||||||
decode: function (string) {
|
|
||||||
if (typeof string !== 'string') return string;
|
|
||||||
var output = "", i = 0, charCode = 0;
|
|
||||||
|
|
||||||
while (i < string.length) {
|
|
||||||
charCode = string.charCodeAt(i);
|
|
||||||
|
|
||||||
if (charCode < 128) {
|
|
||||||
output += String.fromCharCode(charCode),
|
|
||||||
i++;
|
|
||||||
} else if ((charCode > 191) && (charCode < 224)) {
|
|
||||||
output += String.fromCharCode(((charCode & 31) << 6) | (string.charCodeAt(i + 1) & 63));
|
|
||||||
i += 2;
|
|
||||||
} else if ((charCode > 223) && (charCode < 240)) {
|
|
||||||
output += String.fromCharCode(((charCode & 15) << 12) | ((string.charCodeAt(i + 1) & 63) << 6) | (string.charCodeAt(i + 2) & 63));
|
|
||||||
i += 3;
|
|
||||||
} else {
|
|
||||||
var codePoint = ((charCode & 7) << 18) | ((string.charCodeAt(i + 1) & 63) << 12) | ((string.charCodeAt(i + 2) & 63) << 6) | (string.charCodeAt(i + 3) & 63);
|
|
||||||
// output += String.fromCodePoint(codePoint); // Can't do this because Internet Explorer doesn't have String.fromCodePoint
|
|
||||||
output += String.fromCharCode(((codePoint - 65536) >> 10) + 55296) + String.fromCharCode(((codePoint - 65536) & 1023) + 56320); // So we do this instead
|
|
||||||
i += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
// Base64 Module
|
|
||||||
//
|
|
||||||
// Cleaner, modularized and properly scoped base64 encoding and decoding module for strings.
|
|
||||||
//
|
|
||||||
// copyright: MIT
|
|
||||||
// author: Nijiko Yonskai, @nijikokun, nijikokun@gmail.com
|
|
||||||
(function (name, definition, context, dependencies) {
|
|
||||||
if (typeof context['module'] !== 'undefined' && context['module']['exports']) { if (dependencies && context['require']) { for (var i = 0; i < dependencies.length; i++) context[dependencies[i]] = context['require'](dependencies[i]); } context['module']['exports'] = definition.apply(context); }
|
|
||||||
else if (typeof context['define'] !== 'undefined' && context['define'] === 'function' && context['define']['amd']) { define(name, (dependencies || []), definition); }
|
|
||||||
else { context[name] = definition.apply(context); }
|
|
||||||
})('base64', function (utf8) {
|
|
||||||
var $this = this;
|
|
||||||
var $utf8 = utf8 || this.utf8;
|
|
||||||
var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
|
||||||
|
|
||||||
return {
|
|
||||||
encode: function (input) {
|
|
||||||
if (typeof $utf8 === 'undefined') throw { error: "MissingMethod", message: "UTF8 Module is missing." };
|
|
||||||
if (typeof input !== 'string') return input;
|
|
||||||
else input = $utf8.encode(input);
|
|
||||||
var output = "", a, b, c, d, e, f, g, i = 0;
|
|
||||||
|
|
||||||
while (i < input.length) {
|
|
||||||
a = input.charCodeAt(i++);
|
|
||||||
b = input.charCodeAt(i++);
|
|
||||||
c = input.charCodeAt(i++);
|
|
||||||
d = a >> 2;
|
|
||||||
e = ((a & 3) << 4) | (b >> 4);
|
|
||||||
f = ((b & 15) << 2) | (c >> 6);
|
|
||||||
g = c & 63;
|
|
||||||
|
|
||||||
if (isNaN(b)) f = g = 64;
|
|
||||||
else if (isNaN(c)) g = 64;
|
|
||||||
|
|
||||||
output += map.charAt(d) + map.charAt(e) + map.charAt(f) + map.charAt(g);
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
},
|
|
||||||
|
|
||||||
decode: function (input) {
|
|
||||||
if (typeof $utf8 === 'undefined') throw { error: "MissingMethod", message: "UTF8 Module is missing." };
|
|
||||||
if (typeof input !== 'string') return input;
|
|
||||||
else input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
|
|
||||||
var output = "", a, b, c, d, e, f, g, i = 0;
|
|
||||||
|
|
||||||
while (i < input.length) {
|
|
||||||
d = map.indexOf(input.charAt(i++));
|
|
||||||
e = map.indexOf(input.charAt(i++));
|
|
||||||
f = map.indexOf(input.charAt(i++));
|
|
||||||
g = map.indexOf(input.charAt(i++));
|
|
||||||
|
|
||||||
a = (d << 2) | (e >> 4);
|
|
||||||
b = ((e & 15) << 4) | (f >> 2);
|
|
||||||
c = ((f & 3) << 6) | g;
|
|
||||||
|
|
||||||
output += String.fromCharCode(a);
|
|
||||||
if (f != 64) output += String.fromCharCode(b);
|
|
||||||
if (g != 64) output += String.fromCharCode(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $utf8.decode(output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, this, [ "utf8" ]);
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
// From https://gist.github.com/Nijikokun/5192472
|
|
||||||
//
|
|
||||||
// UTF8 Module
|
|
||||||
//
|
|
||||||
// Cleaner and modularized utf-8 encoding and decoding library for javascript.
|
|
||||||
//
|
|
||||||
// copyright: MIT
|
|
||||||
// author: Nijiko Yonskai, @nijikokun, nijikokun@gmail.com
|
|
||||||
!function(r,e,o,t){void 0!==o.module&&o.module.exports?o.module.exports=e.apply(o):void 0!==o.define&&"function"===o.define&&o.define.amd?define("utf8",[],e):o.utf8=e.apply(o)}(0,function(){return{encode:function(r){if("string"!=typeof r)return r;r=r.replace(/\r\n/g,"\n");for(var e,o="",t=0;t<r.length;t++)if((e=r.charCodeAt(t))<128)o+=String.fromCharCode(e);else if(e>127&&e<2048)o+=String.fromCharCode(e>>6|192),o+=String.fromCharCode(63&e|128);else if(e>55295&&e<57344&&r.length>t+1){var i=e,n=r.charCodeAt(t+1);t++;var d=65536+(i-55296<<10|n-56320);o+=String.fromCharCode(d>>18|240),o+=String.fromCharCode(d>>12&63|128),o+=String.fromCharCode(d>>6&63|128),o+=String.fromCharCode(63&d|128)}else o+=String.fromCharCode(e>>12|224),o+=String.fromCharCode(e>>6&63|128),o+=String.fromCharCode(63&e|128);return o},decode:function(r){if("string"!=typeof r)return r;for(var e="",o=0,t=0;o<r.length;)if((t=r.charCodeAt(o))<128)e+=String.fromCharCode(t),o++;else if(t>191&&t<224)e+=String.fromCharCode((31&t)<<6|63&r.charCodeAt(o+1)),o+=2;else if(t>223&&t<240)e+=String.fromCharCode((15&t)<<12|(63&r.charCodeAt(o+1))<<6|63&r.charCodeAt(o+2)),o+=3;else{var i=(7&t)<<18|(63&r.charCodeAt(o+1))<<12|(63&r.charCodeAt(o+2))<<6|63&r.charCodeAt(o+3);e+=String.fromCharCode(55296+(i-65536>>10))+String.fromCharCode(56320+(i-65536&1023)),o+=4}return e}}},this),function(r,e,o,t){if(void 0!==o.module&&o.module.exports){if(t&&o.require)for(var i=0;i<t.length;i++)o[t[i]]=o.require(t[i]);o.module.exports=e.apply(o)}else void 0!==o.define&&"function"===o.define&&o.define.amd?define("base64",t||[],e):o.base64=e.apply(o)}(0,function(r){var e=r||this.utf8,o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";return{encode:function(r){if(void 0===e)throw{error:"MissingMethod",message:"UTF8 Module is missing."};if("string"!=typeof r)return r;r=e.encode(r);for(var t,i,n,d,f,a,h,C="",c=0;c<r.length;)d=(t=r.charCodeAt(c++))>>2,f=(3&t)<<4|(i=r.charCodeAt(c++))>>4,a=(15&i)<<2|(n=r.charCodeAt(c++))>>6,h=63&n,isNaN(i)?a=h=64:isNaN(n)&&(h=64),C+=o.charAt(d)+o.charAt(f)+o.charAt(a)+o.charAt(h);return C},decode:function(r){if(void 0===e)throw{error:"MissingMethod",message:"UTF8 Module is missing."};if("string"!=typeof r)return r;r=r.replace(/[^A-Za-z0-9\+\/\=]/g,"");for(var t,i,n,d,f,a,h="",C=0;C<r.length;)t=o.indexOf(r.charAt(C++))<<2|(d=o.indexOf(r.charAt(C++)))>>4,i=(15&d)<<4|(f=o.indexOf(r.charAt(C++)))>>2,n=(3&f)<<6|(a=o.indexOf(r.charAt(C++))),h+=String.fromCharCode(t),64!=f&&(h+=String.fromCharCode(i)),64!=a&&(h+=String.fromCharCode(n));return e.decode(h)}}},this,["utf8"]);
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"tiddlers": [
|
|
||||||
{
|
|
||||||
"file": "base64-utf8.module.min.js",
|
|
||||||
"fields": {
|
|
||||||
"type": "application/javascript",
|
|
||||||
"title": "$:/core/modules/utils/base64-utf8/base64-utf8.module.js",
|
|
||||||
"module-type": "library"
|
|
||||||
},
|
|
||||||
"prefix": "(function(){",
|
|
||||||
"suffix": "}).call(exports);"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -24,6 +24,26 @@ exports.setStyle = function(element,styles) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Remove style properties of an element
|
||||||
|
element: dom node
|
||||||
|
styleProperties: ordered array of string property names
|
||||||
|
*/
|
||||||
|
exports.removeStyles = function(element, styleProperties) {
|
||||||
|
for (var i=0; i<styleProperties.length; i++) {
|
||||||
|
element.style.removeProperty($tw.utils.convertStyleNameToPropertyName(styleProperties[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Remove single style property of an element
|
||||||
|
element: dom node
|
||||||
|
styleProperty: string property name
|
||||||
|
*/
|
||||||
|
exports.removeStyle = function(element, styleProperty) {
|
||||||
|
$tw.utils.removeStyles(element, [styleProperty])
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Converts a standard CSS property name into the local browser-specific equivalent. For example:
|
Converts a standard CSS property name into the local browser-specific equivalent. For example:
|
||||||
"background-color" --> "backgroundColor"
|
"background-color" --> "backgroundColor"
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ Modal.prototype.display = function(title,options) {
|
|||||||
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
|
// 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")) {
|
if(tiddler.fields && (tiddler.fields["mask-closable"] === "yes" || tiddler.fields["mask-closable"] === "true" || tiddler.fields["mask-closable"] === "" || "mask-closable" in tiddler.fields === false)) {
|
||||||
modalBackdrop.addEventListener("click",closeHandler,false);
|
modalBackdrop.addEventListener("click",closeHandler,false);
|
||||||
}
|
}
|
||||||
// Set the initial styles for the message
|
// Set the initial styles for the message
|
||||||
|
|||||||
126
core/modules/utils/messaging.js
Normal file
126
core/modules/utils/messaging.js
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/utils/messaging.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: utils-browser
|
||||||
|
|
||||||
|
Messaging utilities for use with window.postMessage() etc.
|
||||||
|
|
||||||
|
This module intentionally has no dependencies so that it can be included in non-TiddlyWiki projects
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var RESPONSE_TIMEOUT = 2 * 1000;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Class to handle subscribing to publishers
|
||||||
|
|
||||||
|
target: Target window (eg iframe.contentWindow)
|
||||||
|
type: String indicating type of item for which subscriptions are being provided (eg "SAVING")
|
||||||
|
onsubscribe: Function to be invoked with err parameter when the subscription is established, or there is a timeout
|
||||||
|
onmessage: Function to be invoked when a new message arrives, invoked with (data,callback). The callback is invoked with the argument (response)
|
||||||
|
*/
|
||||||
|
function BrowserMessagingSubscriber(options) {
|
||||||
|
var self = this;
|
||||||
|
this.target = options.target;
|
||||||
|
this.type = options.type;
|
||||||
|
this.onsubscribe = options.onsubscribe || function() {};
|
||||||
|
this.onmessage = options.onmessage;
|
||||||
|
this.hasConfirmed = false;
|
||||||
|
this.channel = new MessageChannel();
|
||||||
|
this.channel.port1.addEventListener("message",function(event) {
|
||||||
|
if(this.timerID) {
|
||||||
|
clearTimeout(this.timerID);
|
||||||
|
this.timerID = null;
|
||||||
|
}
|
||||||
|
if(event.data) {
|
||||||
|
if(event.data.verb === "SUBSCRIBED") {
|
||||||
|
self.hasConfirmed = true;
|
||||||
|
self.onsubscribe(null);
|
||||||
|
} else if(event.data.verb === self.type) {
|
||||||
|
self.onmessage(event.data,function(response) {
|
||||||
|
// Send the response back on the supplied port, and then close it
|
||||||
|
event.ports[0].postMessage(response);
|
||||||
|
event.ports[0].close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Set a timer so that if we don't hear from the iframe before a timeout we alert the user
|
||||||
|
this.timerID = setTimeout(function() {
|
||||||
|
if(!self.hasConfirmed) {
|
||||||
|
self.onsubscribe("NO_RESPONSE");
|
||||||
|
}
|
||||||
|
},RESPONSE_TIMEOUT);
|
||||||
|
this.channel.port1.start();
|
||||||
|
this.target.postMessage({verb: "SUBSCRIBE",to: self.type},"*",[this.channel.port2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.BrowserMessagingSubscriber = BrowserMessagingSubscriber;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Class to handle publishing subscriptions
|
||||||
|
|
||||||
|
type: String indicating type of item for which subscriptions are being provided (eg "SAVING")
|
||||||
|
onsubscribe: Function to be invoked when a subscription occurs
|
||||||
|
*/
|
||||||
|
function BrowserMessagingPublisher(options) {
|
||||||
|
var self = this;
|
||||||
|
this.type = options.type;
|
||||||
|
this.hostIsListening = false;
|
||||||
|
this.port = null;
|
||||||
|
// Listen to connection requests from the host
|
||||||
|
window.addEventListener("message",function(event) {
|
||||||
|
if(event.data && event.data.verb === "SUBSCRIBE" && event.data.to === self.type) {
|
||||||
|
self.hostIsListening = true;
|
||||||
|
// Acknowledge
|
||||||
|
self.port = event.ports[0];
|
||||||
|
self.port.postMessage({verb: "SUBSCRIBED", to: self.type});
|
||||||
|
if(options.onsubscribe) {
|
||||||
|
options.onsubscribe(event.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
BrowserMessagingPublisher.prototype.canSend = function() {
|
||||||
|
return !!this.hostIsListening && !!this.port;
|
||||||
|
};
|
||||||
|
|
||||||
|
BrowserMessagingPublisher.prototype.send = function(data,callback) {
|
||||||
|
var self = this;
|
||||||
|
callback = callback || function() {};
|
||||||
|
// Check that we've been initialised by the host
|
||||||
|
if(!this.hostIsListening || !this.port) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Create a channel for the confirmation
|
||||||
|
var channel = new MessageChannel();
|
||||||
|
channel.port1.addEventListener("message",function(event) {
|
||||||
|
if(event.data && event.data.verb === "OK") {
|
||||||
|
callback(null);
|
||||||
|
} else {
|
||||||
|
callback("BrowserMessagingPublisher for " + self.type + " error: " + (event.data || {}).verb);
|
||||||
|
}
|
||||||
|
channel.port1.close();
|
||||||
|
});
|
||||||
|
channel.port1.start();
|
||||||
|
// Send the save request with the port for the response
|
||||||
|
this.port.postMessage(data,[channel.port2]);
|
||||||
|
};
|
||||||
|
|
||||||
|
BrowserMessagingPublisher.prototype.close = function() {
|
||||||
|
if(this.port) {
|
||||||
|
this.port.close();
|
||||||
|
this.hostIsListening = false;
|
||||||
|
this.port = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.BrowserMessagingPublisher = BrowserMessagingPublisher;
|
||||||
|
|
||||||
|
})();
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user