mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-16 23:04:50 +00:00
Merge branch 'master' into external-tasks
This commit is contained in:
commit
979f079c7a
@ -5,7 +5,7 @@
|
|||||||
# Default to the current version number for building the plugin library
|
# Default to the current version number for building the plugin library
|
||||||
|
|
||||||
if [ -z "$TW5_BUILD_VERSION" ]; then
|
if [ -z "$TW5_BUILD_VERSION" ]; then
|
||||||
TW5_BUILD_VERSION=v5.1.24
|
TW5_BUILD_VERSION=v5.2.0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]"
|
echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]"
|
||||||
|
@ -5,52 +5,52 @@ Optimise the SVGs in ./core/images using SVGO from https://github.com/svg/svgo
|
|||||||
|
|
||||||
Install SVGO with the following command in the root of the repo:
|
Install SVGO with the following command in the root of the repo:
|
||||||
|
|
||||||
npm install svgo
|
npm install svgo@2.3.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var fs = require("fs"),
|
var fs = require("fs"),
|
||||||
path = require("path"),
|
path = require("path"),
|
||||||
SVGO = require("svgo"),
|
{ optimize } = require("svgo"),
|
||||||
svgo = new SVGO({
|
config = {
|
||||||
plugins: [
|
plugins: [
|
||||||
{cleanupAttrs: true},
|
'cleanupAttrs',
|
||||||
{removeDoctype: true},
|
'removeDoctype',
|
||||||
{removeXMLProcInst: true},
|
'removeXMLProcInst',
|
||||||
{removeComments: true},
|
'removeComments',
|
||||||
{removeMetadata: true},
|
'removeMetadata',
|
||||||
{removeTitle: true},
|
'removeTitle',
|
||||||
{removeDesc: true},
|
'removeDesc',
|
||||||
{removeUselessDefs: true},
|
'removeUselessDefs',
|
||||||
{removeEditorsNSData: true},
|
'removeEditorsNSData',
|
||||||
{removeEmptyAttrs: true},
|
'removeEmptyAttrs',
|
||||||
{removeHiddenElems: true},
|
'removeHiddenElems',
|
||||||
{removeEmptyText: true},
|
'removeEmptyText',
|
||||||
{removeEmptyContainers: true},
|
'removeEmptyContainers',
|
||||||
{removeViewBox: false},
|
// 'removeViewBox',
|
||||||
{cleanupEnableBackground: true},
|
'cleanupEnableBackground',
|
||||||
{convertStyleToAttrs: true},
|
'convertStyleToAttrs',
|
||||||
{convertColors: true},
|
'convertColors',
|
||||||
{convertPathData: true},
|
'convertPathData',
|
||||||
{convertTransform: true},
|
'convertTransform',
|
||||||
{removeUnknownsAndDefaults: true},
|
'removeUnknownsAndDefaults',
|
||||||
{removeNonInheritableGroupAttrs: true},
|
'removeNonInheritableGroupAttrs',
|
||||||
{removeUselessStrokeAndFill: true},
|
'removeUselessStrokeAndFill',
|
||||||
{removeUnusedNS: true},
|
'removeUnusedNS',
|
||||||
{cleanupIDs: true},
|
'cleanupIDs',
|
||||||
{cleanupNumericValues: true},
|
'cleanupNumericValues',
|
||||||
{moveElemsAttrsToGroup: true},
|
'moveElemsAttrsToGroup',
|
||||||
{moveGroupAttrsToElems: true},
|
'moveGroupAttrsToElems',
|
||||||
{collapseGroups: true},
|
'collapseGroups',
|
||||||
{removeRasterImages: false},
|
// 'removeRasterImages',
|
||||||
{mergePaths: true},
|
'mergePaths',
|
||||||
{convertShapeToPath: true},
|
'convertShapeToPath',
|
||||||
{sortAttrs: true},
|
'sortAttrs',
|
||||||
{removeDimensions: false},
|
//'removeDimensions',
|
||||||
{removeAttrs: {attrs: "(stroke|fill)"}}
|
{name: 'removeAttrs', params: { attrs: '(stroke|fill)' } }
|
||||||
]
|
]
|
||||||
});
|
};
|
||||||
|
|
||||||
var basepath = "./core/images/",
|
var basepath = "./core/images/",
|
||||||
files = fs.readdirSync(basepath).sort();
|
files = fs.readdirSync(basepath).sort();
|
||||||
@ -66,12 +66,14 @@ files.forEach(function(filename) {
|
|||||||
fakeSVG = body.join("\n");
|
fakeSVG = body.join("\n");
|
||||||
// A hack to make the new-journal-button work
|
// A hack to make the new-journal-button work
|
||||||
fakeSVG = fakeSVG.replace("<<now \"DD\">>","<<now "DD">>");
|
fakeSVG = fakeSVG.replace("<<now \"DD\">>","<<now "DD">>");
|
||||||
svgo.optimize(fakeSVG, {path: filepath}).then(function(result) {
|
config.path = filepath;
|
||||||
|
var result = optimize(fakeSVG,config);
|
||||||
|
if(result) {
|
||||||
var newSVG = header.join("\n") + "\n\n" + result.data.replace("<<now "DD">>","<<now \"DD\">>");
|
var newSVG = header.join("\n") + "\n\n" + result.data.replace("<<now "DD">>","<<now \"DD\">>");
|
||||||
fs.writeFileSync(filepath,newSVG);
|
fs.writeFileSync(filepath,newSVG);
|
||||||
},function(err) {
|
} else {
|
||||||
console.log("Error " + err + " with " + filename)
|
console.log("Error " + err + " with " + filename)
|
||||||
process.exit();
|
process.exit();
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
116
boot/boot.js
116
boot/boot.js
@ -256,6 +256,28 @@ $tw.utils.deepDefaults = function(object /*, sourceObjectList */) {
|
|||||||
return object;
|
return object;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Convert a URIComponent encoded string to a string safely
|
||||||
|
*/
|
||||||
|
$tw.utils.decodeURIComponentSafe = function(s) {
|
||||||
|
var v = s;
|
||||||
|
try {
|
||||||
|
v = decodeURIComponent(s);
|
||||||
|
} catch(e) {}
|
||||||
|
return v;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Convert a URI encoded string to a string safely
|
||||||
|
*/
|
||||||
|
$tw.utils.decodeURISafe = function(s) {
|
||||||
|
var v = s;
|
||||||
|
try {
|
||||||
|
v = decodeURI(s);
|
||||||
|
} catch(e) {}
|
||||||
|
return v;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Convert "&" to &, " " to nbsp, "<" to <, ">" to > and """ to "
|
Convert "&" to &, " " to nbsp, "<" to <, ">" to > and """ to "
|
||||||
*/
|
*/
|
||||||
@ -1212,9 +1234,13 @@ $tw.Wiki = function(options) {
|
|||||||
index,titlesLength,title;
|
index,titlesLength,title;
|
||||||
for(index = 0, titlesLength = titles.length; index < titlesLength; index++) {
|
for(index = 0, titlesLength = titles.length; index < titlesLength; index++) {
|
||||||
title = titles[index];
|
title = titles[index];
|
||||||
|
if(tiddlers[title]) {
|
||||||
|
callback(tiddlers[title],title);
|
||||||
|
} else {
|
||||||
var shadowInfo = shadowTiddlers[title];
|
var shadowInfo = shadowTiddlers[title];
|
||||||
callback(shadowInfo.tiddler,title);
|
callback(shadowInfo.tiddler,title);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Iterate through all tiddlers and then the shadows
|
// Iterate through all tiddlers and then the shadows
|
||||||
@ -1602,8 +1628,8 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/json","tiddlerdeserializer",{
|
|||||||
}
|
}
|
||||||
for(var f in data) {
|
for(var f in data) {
|
||||||
if($tw.utils.hop(data,f)) {
|
if($tw.utils.hop(data,f)) {
|
||||||
// Check field name doesn't contain whitespace or control characters
|
// Check field name doesn't contain control characters
|
||||||
if(typeof(data[f]) !== "string" || /[\x00-\x1F\s]/.test(f)) {
|
if(typeof(data[f]) !== "string" || /[\x00-\x1F]/.test(f)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1618,7 +1644,12 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/json","tiddlerdeserializer",{
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
data = {};
|
||||||
|
try {
|
||||||
data = JSON.parse(text);
|
data = JSON.parse(text);
|
||||||
|
} catch(e) {
|
||||||
|
// Ignore JSON parse errors
|
||||||
|
}
|
||||||
if($tw.utils.isArray(data) && isTiddlerArrayValid(data)) {
|
if($tw.utils.isArray(data) && isTiddlerArrayValid(data)) {
|
||||||
return data;
|
return data;
|
||||||
} else if(isTiddlerValid(data)) {
|
} else if(isTiddlerValid(data)) {
|
||||||
@ -1724,6 +1755,12 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/dom","tiddlerdeserializer",{
|
|||||||
},
|
},
|
||||||
t,result = [];
|
t,result = [];
|
||||||
if(node) {
|
if(node) {
|
||||||
|
var type = (node.getAttribute && node.getAttribute("type")) || null;
|
||||||
|
if(type) {
|
||||||
|
// A new-style container with an explicit deserialization type
|
||||||
|
result = $tw.wiki.deserializeTiddlers(type,node.textContent);
|
||||||
|
} else {
|
||||||
|
// An old-style container of classic DIV-based tiddlers
|
||||||
for(t = 0; t < node.childNodes.length; t++) {
|
for(t = 0; t < node.childNodes.length; t++) {
|
||||||
var childNode = node.childNodes[t],
|
var childNode = node.childNodes[t],
|
||||||
tiddlers = extractTextTiddlers(childNode);
|
tiddlers = extractTextTiddlers(childNode);
|
||||||
@ -1733,23 +1770,30 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/dom","tiddlerdeserializer",{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$tw.loadTiddlersBrowser = function() {
|
$tw.loadTiddlersBrowser = function() {
|
||||||
// In the browser, we load tiddlers from certain elements
|
// In the browser, we load tiddlers from certain elements
|
||||||
var containerIds = [
|
var containerSelectors = [
|
||||||
"libraryModules",
|
// IDs for old-style v5.1.x tiddler stores
|
||||||
"modules",
|
"#libraryModules",
|
||||||
"bootKernelPrefix",
|
"#modules",
|
||||||
"bootKernel",
|
"#bootKernelPrefix",
|
||||||
"styleArea",
|
"#bootKernel",
|
||||||
"storeArea",
|
"#styleArea",
|
||||||
"systemArea"
|
"#storeArea",
|
||||||
|
"#systemArea",
|
||||||
|
// Classes for new-style v5.2.x JSON tiddler stores
|
||||||
|
"script.tiddlywiki-tiddler-store"
|
||||||
];
|
];
|
||||||
for(var t=0; t<containerIds.length; t++) {
|
for(var t=0; t<containerSelectors.length; t++) {
|
||||||
$tw.wiki.addTiddlers($tw.wiki.deserializeTiddlers("(DOM)",document.getElementById(containerIds[t])));
|
var nodes = document.querySelectorAll(containerSelectors[t]);
|
||||||
|
for(var n=0; n<nodes.length; n++) {
|
||||||
|
$tw.wiki.addTiddlers($tw.wiki.deserializeTiddlers("(DOM)",nodes[n]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1872,13 +1916,13 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
|||||||
value = path.basename(filename);
|
value = path.basename(filename);
|
||||||
break;
|
break;
|
||||||
case "filename-uri-decoded":
|
case "filename-uri-decoded":
|
||||||
value = decodeURIComponent(path.basename(filename));
|
value = $tw.utils.decodeURIComponentSafe(path.basename(filename));
|
||||||
break;
|
break;
|
||||||
case "basename":
|
case "basename":
|
||||||
value = path.basename(filename,path.extname(filename));
|
value = path.basename(filename,path.extname(filename));
|
||||||
break;
|
break;
|
||||||
case "basename-uri-decoded":
|
case "basename-uri-decoded":
|
||||||
value = decodeURIComponent(path.basename(filename,path.extname(filename)));
|
value = $tw.utils.decodeURIComponentSafe(path.basename(filename,path.extname(filename)));
|
||||||
break;
|
break;
|
||||||
case "extname":
|
case "extname":
|
||||||
value = path.extname(filename);
|
value = path.extname(filename);
|
||||||
@ -1906,6 +1950,20 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
|||||||
tiddlers.push({tiddlers: fileTiddlers});
|
tiddlers.push({tiddlers: fileTiddlers});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// Helper to recursively search subdirectories
|
||||||
|
var getAllFiles = function(dirPath, recurse, arrayOfFiles) {
|
||||||
|
recurse = recurse || false;
|
||||||
|
arrayOfFiles = arrayOfFiles || [];
|
||||||
|
var files = fs.readdirSync(dirPath);
|
||||||
|
files.forEach(function(file) {
|
||||||
|
if (recurse && fs.statSync(dirPath + path.sep + file).isDirectory()) {
|
||||||
|
arrayOfFiles = getAllFiles(dirPath + path.sep + file, recurse, arrayOfFiles);
|
||||||
|
} else if(fs.statSync(dirPath + path.sep + file).isFile()){
|
||||||
|
arrayOfFiles.push(path.join(dirPath, path.sep, file));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return arrayOfFiles;
|
||||||
|
}
|
||||||
// Process the listed tiddlers
|
// Process the listed tiddlers
|
||||||
$tw.utils.each(filesInfo.tiddlers,function(tidInfo) {
|
$tw.utils.each(filesInfo.tiddlers,function(tidInfo) {
|
||||||
if(tidInfo.prefix && tidInfo.suffix) {
|
if(tidInfo.prefix && tidInfo.suffix) {
|
||||||
@ -1929,13 +1987,14 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
|||||||
// Process directory specifier
|
// Process directory specifier
|
||||||
var dirPath = path.resolve(filepath,dirSpec.path);
|
var dirPath = path.resolve(filepath,dirSpec.path);
|
||||||
if(fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
|
if(fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
|
||||||
var files = fs.readdirSync(dirPath),
|
var files = getAllFiles(dirPath, dirSpec.searchSubdirectories),
|
||||||
fileRegExp = new RegExp(dirSpec.filesRegExp || "^.*$"),
|
fileRegExp = new RegExp(dirSpec.filesRegExp || "^.*$"),
|
||||||
metaRegExp = /^.*\.meta$/;
|
metaRegExp = /^.*\.meta$/;
|
||||||
for(var t=0; t<files.length; t++) {
|
for(var t=0; t<files.length; t++) {
|
||||||
var filename = files[t];
|
var thisPath = path.relative(filepath, files[t]),
|
||||||
|
filename = path.basename(thisPath);
|
||||||
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
|
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
|
||||||
processFile(dirPath + path.sep + filename,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile);
|
processFile(thisPath,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1985,7 +2044,7 @@ $tw.loadPluginFolder = function(filepath,excludeRegExp) {
|
|||||||
pluginInfo.dependents = pluginInfo.dependents || [];
|
pluginInfo.dependents = pluginInfo.dependents || [];
|
||||||
pluginInfo.type = "application/json";
|
pluginInfo.type = "application/json";
|
||||||
// Set plugin text
|
// Set plugin text
|
||||||
pluginInfo.text = JSON.stringify({tiddlers: pluginInfo.tiddlers},null,4);
|
pluginInfo.text = JSON.stringify({tiddlers: pluginInfo.tiddlers});
|
||||||
delete pluginInfo.tiddlers;
|
delete pluginInfo.tiddlers;
|
||||||
// Deserialise array fields (currently required for the dependents field)
|
// Deserialise array fields (currently required for the dependents field)
|
||||||
for(var field in pluginInfo) {
|
for(var field in pluginInfo) {
|
||||||
@ -2467,17 +2526,30 @@ $tw.boot.executeNextStartupTask = function(callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Returns true if we are running on one platforms specified in a task modules `platforms` array
|
Returns true if we are running on one of the platforms specified in taskModule's
|
||||||
|
`platforms` array; or if `platforms` property is not defined.
|
||||||
*/
|
*/
|
||||||
$tw.boot.doesTaskMatchPlatform = function(taskModule) {
|
$tw.boot.doesTaskMatchPlatform = function(taskModule) {
|
||||||
var platforms = taskModule.platforms;
|
var platforms = taskModule.platforms;
|
||||||
if(platforms) {
|
if(platforms) {
|
||||||
for(var t=0; t<platforms.length; t++) {
|
for(var t=0; t<platforms.length; t++) {
|
||||||
if((platforms[t] === "browser" && !$tw.browser) || (platforms[t] === "node" && !$tw.node)) {
|
switch (platforms[t]) {
|
||||||
|
case "browser":
|
||||||
|
if ($tw.browser) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "node":
|
||||||
|
if ($tw.node) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$tw.utils.error("Module " + taskModule.name + ": '" + platforms[t] + "' in export.platforms invalid");
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
4
core/images/minus-button.tid
Normal file
4
core/images/minus-button.tid
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
title: $:/core/images/minus-button
|
||||||
|
tags: $:/tags/Image
|
||||||
|
|
||||||
|
<svg width="22pt" height="22pt" class="tc-image-minus-button tc-image-button" viewBox="0 0 128 128"><path d="M64 0c35.346 0 64 28.654 64 64 0 35.346-28.654 64-64 64-35.346 0-64-28.654-64-64C0 28.654 28.654 0 64 0zm.332 16c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48z"/><rect width="80" height="16" x="24" y="56" rx="8"/></svg>
|
4
core/images/plus-button.tid
Normal file
4
core/images/plus-button.tid
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
title: $:/core/images/plus-button
|
||||||
|
tags: $:/tags/Image
|
||||||
|
|
||||||
|
<svg width="22pt" height="22pt" class="tc-image-plus-button tc-image-button" viewBox="0 0 128 128"><path d="M64-.333c35.346 0 64 28.654 64 64 0 35.346-28.654 64-64 64-35.346 0-64-28.654-64-64 0-35.346 28.654-64 64-64zM64 16c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48z"/><rect width="80" height="16" x="24" y="56" rx="8"/><rect width="16" height="80" x="56" y="24" rx="8"/></svg>
|
@ -123,12 +123,12 @@ Saving/TiddlySpot/BackupDir: Backup Directory
|
|||||||
Saving/TiddlySpot/ControlPanel: ~TiddlySpot Control Panel
|
Saving/TiddlySpot/ControlPanel: ~TiddlySpot Control Panel
|
||||||
Saving/TiddlySpot/Backups: Backups
|
Saving/TiddlySpot/Backups: Backups
|
||||||
Saving/TiddlySpot/Caption: ~TiddlySpot Saver
|
Saving/TiddlySpot/Caption: ~TiddlySpot Saver
|
||||||
Saving/TiddlySpot/Description: These settings are only used when saving to http://tiddlyspot.com or a compatible remote server
|
Saving/TiddlySpot/Description: These settings are only used when saving to [[TiddlySpot|http://tiddlyspot.com]], [[TiddlyHost|https://tiddlyhost.com]], or a compatible remote server. See [[here|https://github.com/simonbaird/tiddlyhost/wiki/TiddlySpot-Saver-configuration-for-Tiddlyhost-and-Tiddlyspot]] for information on ~TiddlySpot and ~TiddlyHost saving configuration.
|
||||||
Saving/TiddlySpot/Filename: Upload Filename
|
Saving/TiddlySpot/Filename: Upload Filename
|
||||||
Saving/TiddlySpot/Heading: ~TiddlySpot
|
Saving/TiddlySpot/Heading: ~TiddlySpot
|
||||||
Saving/TiddlySpot/Hint: //The server URL defaults to `http://<wikiname>.tiddlyspot.com/store.cgi` and can be changed to use a custom server address, e.g. `http://example.com/store.php`.//
|
Saving/TiddlySpot/Hint: //The server URL defaults to `http://<wikiname>.tiddlyspot.com/store.cgi` and can be changed to use a custom server address, e.g. `http://example.com/store.php`.//
|
||||||
Saving/TiddlySpot/Password: Password
|
Saving/TiddlySpot/Password: Password
|
||||||
Saving/TiddlySpot/ReadOnly: The ~TiddlySpot service is currently only available in read-only form. Please see http://tiddlyspot.com/ for the latest details. The ~TiddlySpot saver can still be used to save to compatible servers.
|
Saving/TiddlySpot/ReadOnly: Note that [[TiddlySpot|http://tiddlyspot.com]] no longer allows the creation of new sites. For new sites, you can use [[TiddlyHost|https://tiddlyhost.com]], a new hosting service that replaces ~TiddlySpot.
|
||||||
Saving/TiddlySpot/ServerURL: Server URL
|
Saving/TiddlySpot/ServerURL: Server URL
|
||||||
Saving/TiddlySpot/UploadDir: Upload Directory
|
Saving/TiddlySpot/UploadDir: Upload Directory
|
||||||
Saving/TiddlySpot/UserName: Wiki Name
|
Saving/TiddlySpot/UserName: Wiki Name
|
||||||
|
@ -3,6 +3,8 @@ title: $:/language/EditTemplate/
|
|||||||
Body/External/Hint: This tiddler shows content stored outside of the main TiddlyWiki file. You can edit the tags and fields but cannot directly edit the content itself
|
Body/External/Hint: This tiddler shows content stored outside of the main TiddlyWiki file. You can edit the tags and fields but cannot directly edit the content itself
|
||||||
Body/Placeholder: Type the text for this tiddler
|
Body/Placeholder: Type the text for this tiddler
|
||||||
Body/Preview/Type/Output: output
|
Body/Preview/Type/Output: output
|
||||||
|
Body/Preview/Type/DiffShadow: differences from shadow (if any)
|
||||||
|
Body/Preview/Type/DiffCurrent: differences from current
|
||||||
Field/Remove/Caption: remove field
|
Field/Remove/Caption: remove field
|
||||||
Field/Remove/Hint: Remove field
|
Field/Remove/Hint: Remove field
|
||||||
Field/Dropdown/Caption: field list
|
Field/Dropdown/Caption: field list
|
||||||
|
@ -19,10 +19,9 @@ All parameters are optional with safe defaults, and can be specified in any orde
|
|||||||
* ''username'' - optional username for basic authentication
|
* ''username'' - optional username for basic authentication
|
||||||
* ''password'' - optional password for basic authentication
|
* ''password'' - optional password for basic authentication
|
||||||
* ''authenticated-user-header'' - optional name of header to be used for trusted authentication
|
* ''authenticated-user-header'' - optional name of header to be used for trusted authentication
|
||||||
* ''readers'' - comma separated list of principals allowed to read from this wiki
|
* ''readers'' - comma-separated list of principals allowed to read from this wiki
|
||||||
* ''writers'' - comma separated list of principals allowed to write to this wiki
|
* ''writers'' - comma-separated list of principals allowed to write to this wiki
|
||||||
* ''csrf-disable'' - set to "yes" to disable CSRF checks (defaults to "no")
|
* ''csrf-disable'' - set to "yes" to disable CSRF checks (defaults to "no")
|
||||||
* ''sse-enabled'' - set to "yes" to enable Server-sent events (defaults to "no")
|
|
||||||
* ''root-tiddler'' - the tiddler to serve at the root (defaults to "$:/core/save/all")
|
* ''root-tiddler'' - the tiddler to serve at the root (defaults to "$:/core/save/all")
|
||||||
* ''root-render-type'' - the content type to which the root tiddler should be rendered (defaults to "text/plain")
|
* ''root-render-type'' - the content type to which the root tiddler should be rendered (defaults to "text/plain")
|
||||||
* ''root-serve-type'' - the content type with which the root tiddler should be served (defaults to "text/html")
|
* ''root-serve-type'' - the content type with which the root tiddler should be served (defaults to "text/html")
|
||||||
@ -30,6 +29,7 @@ All parameters are optional with safe defaults, and can be specified in any orde
|
|||||||
* ''tls-key'' - pathname of TLS key file (relative to wiki folder)
|
* ''tls-key'' - pathname of TLS key file (relative to wiki folder)
|
||||||
* ''debug-level'' - optional debug level; set to "debug" to view request details (defaults to "none")
|
* ''debug-level'' - optional debug level; set to "debug" to view request details (defaults to "none")
|
||||||
* ''gzip'' - set to "yes" to enable gzip compression for some http endpoints (defaults to "no")
|
* ''gzip'' - set to "yes" to enable gzip compression for some http endpoints (defaults to "no")
|
||||||
|
* ''use-browser-cache'' - set to "yes" to allow the browser to cache responses to save bandwidth (defaults to "no")
|
||||||
|
|
||||||
For information on opening up your instance to the entire local network, and possible security concerns, see the WebServer tiddler at TiddlyWiki.com.
|
For information on opening up your instance to the entire local network, and possible security concerns, see the WebServer tiddler at TiddlyWiki.com.
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
title: $:/language/Import/
|
title: $:/language/Import/
|
||||||
|
|
||||||
|
Editor/Import/Heading: Import images and insert them into the editor.
|
||||||
Imported/Hint: The following tiddlers were imported:
|
Imported/Hint: The following tiddlers were imported:
|
||||||
Listing/Cancel/Caption: Cancel
|
Listing/Cancel/Caption: Cancel
|
||||||
|
Listing/Cancel/Warning: Do you wish to cancel the import?
|
||||||
Listing/Hint: These tiddlers are ready to import:
|
Listing/Hint: These tiddlers are ready to import:
|
||||||
Listing/Import/Caption: Import
|
Listing/Import/Caption: Import
|
||||||
Listing/Select/Caption: Select
|
Listing/Select/Caption: Select
|
||||||
@ -22,7 +24,11 @@ Upgrader/Plugins/Suppressed/Incompatible: Blocked incompatible or obsolete plugi
|
|||||||
Upgrader/Plugins/Suppressed/Version: Blocked plugin (due to incoming <<incoming>> not being newer than existing <<existing>>).
|
Upgrader/Plugins/Suppressed/Version: Blocked plugin (due to incoming <<incoming>> not being newer than existing <<existing>>).
|
||||||
Upgrader/Plugins/Upgraded: Upgraded plugin from <<incoming>> to <<upgraded>>.
|
Upgrader/Plugins/Upgraded: Upgraded plugin from <<incoming>> to <<upgraded>>.
|
||||||
Upgrader/State/Suppressed: Blocked temporary state tiddler.
|
Upgrader/State/Suppressed: Blocked temporary state tiddler.
|
||||||
|
Upgrader/System/Disabled: Disabled system tiddler.
|
||||||
Upgrader/System/Suppressed: Blocked system tiddler.
|
Upgrader/System/Suppressed: Blocked system tiddler.
|
||||||
Upgrader/System/Warning: Core module tiddler.
|
Upgrader/System/Warning: Core module tiddler.
|
||||||
Upgrader/System/Alert: You are about to import a tiddler that will overwrite a core module tiddler. This is not recommended as it may make the system unstable.
|
Upgrader/System/Alert: You are about to import a tiddler that will overwrite a core module tiddler. This is not recommended as it may make the system unstable.
|
||||||
Upgrader/ThemeTweaks/Created: Migrated theme tweak from <$text text=<<from>>/>.
|
Upgrader/ThemeTweaks/Created: Migrated theme tweak from <$text text=<<from>>/>.
|
||||||
|
Upgrader/Tiddler/Disabled: Disabled tiddler.
|
||||||
|
Upgrader/Tiddler/Selected: Selected tiddler.
|
||||||
|
Upgrader/Tiddler/Unselected: Unselected tiddler.
|
||||||
|
@ -24,7 +24,6 @@ Encryption/RepeatPassword: Repeat password
|
|||||||
Encryption/PasswordNoMatch: Passwords do not match
|
Encryption/PasswordNoMatch: Passwords do not match
|
||||||
Encryption/SetPassword: Set password
|
Encryption/SetPassword: Set password
|
||||||
Error/Caption: Error
|
Error/Caption: Error
|
||||||
Error/EditConflict: File changed on server
|
|
||||||
Error/Filter: Filter error
|
Error/Filter: Filter error
|
||||||
Error/FilterSyntax: Syntax error in filter expression
|
Error/FilterSyntax: Syntax error in filter expression
|
||||||
Error/FilterRunPrefix: Filter Error: Unknown prefix for filter run
|
Error/FilterRunPrefix: Filter Error: Unknown prefix for filter run
|
||||||
@ -32,6 +31,9 @@ Error/IsFilterOperator: Filter Error: Unknown operand for the 'is' filter operat
|
|||||||
Error/FormatFilterOperator: Filter Error: Unknown suffix for the 'format' filter operator
|
Error/FormatFilterOperator: Filter Error: Unknown suffix for the 'format' filter operator
|
||||||
Error/LoadingPluginLibrary: Error loading plugin library
|
Error/LoadingPluginLibrary: Error loading plugin library
|
||||||
Error/NetworkErrorAlert: `<h2>''Network Error''</h2>It looks like the connection to the server has been lost. This may indicate a problem with your network connection. Please attempt to restore network connectivity before continuing.<br><br>''Any unsaved changes will be automatically synchronised when connectivity is restored''.`
|
Error/NetworkErrorAlert: `<h2>''Network Error''</h2>It looks like the connection to the server has been lost. This may indicate a problem with your network connection. Please attempt to restore network connectivity before continuing.<br><br>''Any unsaved changes will be automatically synchronised when connectivity is restored''.`
|
||||||
|
Error/PutEditConflict: File changed on server
|
||||||
|
Error/PutForbidden: Permission denied
|
||||||
|
Error/PutUnauthorized: Authentication required
|
||||||
Error/RecursiveTransclusion: Recursive transclusion error in transclude widget
|
Error/RecursiveTransclusion: Recursive transclusion error in transclude widget
|
||||||
Error/RetrievingSkinny: Error retrieving skinny tiddler list
|
Error/RetrievingSkinny: Error retrieving skinny tiddler list
|
||||||
Error/SavingToTWEdit: Error saving to TWEdit
|
Error/SavingToTWEdit: Error saving to TWEdit
|
||||||
@ -39,7 +41,6 @@ Error/WhileSaving: Error while saving
|
|||||||
Error/XMLHttpRequest: XMLHttpRequest error code
|
Error/XMLHttpRequest: XMLHttpRequest error code
|
||||||
InternalJavaScriptError/Title: Internal JavaScript Error
|
InternalJavaScriptError/Title: Internal JavaScript Error
|
||||||
InternalJavaScriptError/Hint: Well, this is embarrassing. It is recommended that you restart TiddlyWiki by refreshing your browser
|
InternalJavaScriptError/Hint: Well, this is embarrassing. It is recommended that you restart TiddlyWiki by refreshing your browser
|
||||||
InvalidFieldName: Illegal characters in field name "<$text text=<<fieldName>>/>". Fields can only contain lowercase letters, digits and the characters underscore (`_`), hyphen (`-`) and period (`.`)
|
|
||||||
LayoutSwitcher/Description: Open the layout switcher
|
LayoutSwitcher/Description: Open the layout switcher
|
||||||
LazyLoadingWarning: <p>Trying to load external content from ''<$text text={{!!_canonical_uri}}/>''</p><p>If this message doesn't disappear, either the tiddler content type doesn't match the type of the external content, or you may be using a browser that doesn't support external content for wikis loaded as standalone files. See https://tiddlywiki.com/#ExternalText</p>
|
LazyLoadingWarning: <p>Trying to load external content from ''<$text text={{!!_canonical_uri}}/>''</p><p>If this message doesn't disappear, either the tiddler content type doesn't match the type of the external content, or you may be using a browser that doesn't support external content for wikis loaded as standalone files. See https://tiddlywiki.com/#ExternalText</p>
|
||||||
LoginToTiddlySpace: Login to TiddlySpace
|
LoginToTiddlySpace: Login to TiddlySpace
|
||||||
|
@ -45,15 +45,15 @@ Command.prototype.execute = function() {
|
|||||||
variableList = variableList.slice(2);
|
variableList = variableList.slice(2);
|
||||||
}
|
}
|
||||||
$tw.utils.each(tiddlers,function(title) {
|
$tw.utils.each(tiddlers,function(title) {
|
||||||
var parser = wiki.parseTiddler(template || title);
|
var filepath = path.resolve(self.commander.outputPath,wiki.filterTiddlers(filenameFilter,$tw.rootWidget,wiki.makeTiddlerIterator([title]))[0]);
|
||||||
var widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title})}),
|
|
||||||
container = $tw.fakeDocument.createElement("div");
|
|
||||||
widgetNode.render(container,null);
|
|
||||||
var text = type === "text/html" ? container.innerHTML : container.textContent,
|
|
||||||
filepath = path.resolve(self.commander.outputPath,wiki.filterTiddlers(filenameFilter,$tw.rootWidget,wiki.makeTiddlerIterator([title]))[0]);
|
|
||||||
if(self.commander.verbose) {
|
if(self.commander.verbose) {
|
||||||
console.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
|
console.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
|
||||||
}
|
}
|
||||||
|
var parser = wiki.parseTiddler(template || title),
|
||||||
|
widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title})}),
|
||||||
|
container = $tw.fakeDocument.createElement("div");
|
||||||
|
widgetNode.render(container,null);
|
||||||
|
var text = type === "text/html" ? container.innerHTML : container.textContent;
|
||||||
$tw.utils.createFileDirectories(filepath);
|
$tw.utils.createFileDirectories(filepath);
|
||||||
fs.writeFileSync(filepath,text,"utf8");
|
fs.writeFileSync(filepath,text,"utf8");
|
||||||
});
|
});
|
||||||
@ -63,3 +63,4 @@ Command.prototype.execute = function() {
|
|||||||
exports.Command = Command;
|
exports.Command = Command;
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
@ -34,7 +34,7 @@ exports.htmlEntities = {quot:34, amp:38, apos:39, lt:60, gt:62, nbsp:160, iexcl:
|
|||||||
|
|
||||||
exports.htmlVoidElements = "area,base,br,col,command,embed,hr,img,input,keygen,link,meta,param,source,track,wbr".split(",");
|
exports.htmlVoidElements = "area,base,br,col,command,embed,hr,img,input,keygen,link,meta,param,source,track,wbr".split(",");
|
||||||
|
|
||||||
exports.htmlBlockElements = "address,article,aside,audio,blockquote,canvas,dd,div,dl,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,hr,li,noscript,ol,output,p,pre,section,table,tfoot,ul,video".split(",");
|
exports.htmlBlockElements = "address,article,aside,audio,blockquote,canvas,dd,details,div,dl,dt,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,hr,li,nav,ol,p,pre,section,summary,table,tfoot,ul,video".split(",");
|
||||||
|
|
||||||
exports.htmlUnsafeElements = "script".split(",");
|
exports.htmlUnsafeElements = "script".split(",");
|
||||||
|
|
||||||
|
@ -12,6 +12,124 @@ Functions to deserialise tiddlers from a block of text
|
|||||||
/*global $tw: false */
|
/*global $tw: false */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
exports["application/x-tiddler-html-div"] = function(text,fields) {
|
||||||
|
return [deserializeTiddlerDiv(text,fields)];
|
||||||
|
};
|
||||||
|
|
||||||
|
exports["application/json"] = function(text,fields) {
|
||||||
|
var incoming,
|
||||||
|
results = [];
|
||||||
|
try {
|
||||||
|
incoming = JSON.parse(text);
|
||||||
|
} catch(e) {
|
||||||
|
incoming = [{
|
||||||
|
title: "JSON error: " + e,
|
||||||
|
text: ""
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
if(!$tw.utils.isArray(incoming)) {
|
||||||
|
incoming = [incoming];
|
||||||
|
}
|
||||||
|
for(var t=0; t<incoming.length; t++) {
|
||||||
|
var incomingFields = incoming[t],
|
||||||
|
fields = {};
|
||||||
|
for(var f in incomingFields) {
|
||||||
|
if(typeof incomingFields[f] === "string") {
|
||||||
|
fields[f] = incomingFields[f];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
results.push(fields);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Parse an HTML file into tiddlers. There are three possibilities:
|
||||||
|
# A TiddlyWiki classic HTML file containing `text/x-tiddlywiki` tiddlers
|
||||||
|
# A TiddlyWiki5 HTML file containing `text/vnd.tiddlywiki` tiddlers
|
||||||
|
# An ordinary HTML file
|
||||||
|
*/
|
||||||
|
exports["text/html"] = function(text,fields) {
|
||||||
|
var results = [];
|
||||||
|
// Check if we've got an old-style store area
|
||||||
|
var storeAreaMarkerRegExp = /<div id=["']?storeArea['"]?( style=["']?display:none;["']?)?>/gi,
|
||||||
|
storeAreaMatch = storeAreaMarkerRegExp.exec(text);
|
||||||
|
if(storeAreaMatch) {
|
||||||
|
// If so, we've got tiddlers in classic TiddlyWiki format or unencrypted old-style TW5 format
|
||||||
|
results.push.apply(results,deserializeStoreArea(text,storeAreaMarkerRegExp.lastIndex,!!storeAreaMatch[1],fields));
|
||||||
|
}
|
||||||
|
// Check for new-style store areas
|
||||||
|
var newStoreAreaMarkerRegExp = /<script class="tiddlywiki-tiddler-store" type="([^"]*)">/gi,
|
||||||
|
newStoreAreaMatch = newStoreAreaMarkerRegExp.exec(text),
|
||||||
|
haveHadNewStoreArea = !!newStoreAreaMatch;
|
||||||
|
while(newStoreAreaMatch) {
|
||||||
|
results.push.apply(results,deserializeNewStoreArea(text,newStoreAreaMarkerRegExp.lastIndex,newStoreAreaMatch[1],fields));
|
||||||
|
newStoreAreaMatch = newStoreAreaMarkerRegExp.exec(text);
|
||||||
|
}
|
||||||
|
// Return if we had either an old-style or a new-style store area
|
||||||
|
if(storeAreaMatch || haveHadNewStoreArea) {
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
// Otherwise, check whether we've got an encrypted file
|
||||||
|
var encryptedStoreArea = $tw.utils.extractEncryptedStoreArea(text);
|
||||||
|
if(encryptedStoreArea) {
|
||||||
|
// If so, attempt to decrypt it using the current password
|
||||||
|
return $tw.utils.decryptStoreArea(encryptedStoreArea);
|
||||||
|
} else {
|
||||||
|
// It's not a TiddlyWiki so we'll return the entire HTML file as a tiddler
|
||||||
|
return deserializeHtmlFile(text,fields);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function deserializeHtmlFile(text,fields) {
|
||||||
|
var result = {};
|
||||||
|
$tw.utils.each(fields,function(value,name) {
|
||||||
|
result[name] = value;
|
||||||
|
});
|
||||||
|
result.text = text;
|
||||||
|
result.type = "text/html";
|
||||||
|
return [result];
|
||||||
|
}
|
||||||
|
|
||||||
|
function deserializeNewStoreArea(text,storeAreaEnd,type,fields) {
|
||||||
|
var endOfScriptRegExp = /<\/script>/gi;
|
||||||
|
endOfScriptRegExp.lastIndex = storeAreaEnd;
|
||||||
|
var match = endOfScriptRegExp.exec(text);
|
||||||
|
if(match) {
|
||||||
|
var scriptContent = text.substring(storeAreaEnd,match.index);
|
||||||
|
return $tw.wiki.deserializeTiddlers(type,scriptContent);
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function deserializeStoreArea(text,storeAreaEnd,isTiddlyWiki5,fields) {
|
||||||
|
var results = [],
|
||||||
|
endOfDivRegExp = /(<\/div>\s*)/gi,
|
||||||
|
startPos = storeAreaEnd,
|
||||||
|
defaultType = isTiddlyWiki5 ? undefined : "text/x-tiddlywiki";
|
||||||
|
endOfDivRegExp.lastIndex = startPos;
|
||||||
|
var match = endOfDivRegExp.exec(text);
|
||||||
|
while(match) {
|
||||||
|
var endPos = endOfDivRegExp.lastIndex,
|
||||||
|
tiddlerFields = deserializeTiddlerDiv(text.substring(startPos,endPos),fields,{type: defaultType});
|
||||||
|
if(!tiddlerFields) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$tw.utils.each(tiddlerFields,function(value,name) {
|
||||||
|
if(typeof value === "string") {
|
||||||
|
tiddlerFields[name] = $tw.utils.htmlDecode(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(tiddlerFields.text !== null) {
|
||||||
|
results.push(tiddlerFields);
|
||||||
|
}
|
||||||
|
startPos = endPos;
|
||||||
|
match = endOfDivRegExp.exec(text);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Utility function to parse an old-style tiddler DIV in a *.tid file. It looks like this:
|
Utility function to parse an old-style tiddler DIV in a *.tid file. It looks like this:
|
||||||
|
|
||||||
@ -24,7 +142,7 @@ Note that the field attributes are HTML encoded, but that the body of the <PRE>
|
|||||||
|
|
||||||
When these tiddler DIVs are encountered within a TiddlyWiki HTML file then the body is encoded in the usual way.
|
When these tiddler DIVs are encountered within a TiddlyWiki HTML file then the body is encoded in the usual way.
|
||||||
*/
|
*/
|
||||||
var parseTiddlerDiv = function(text /* [,fields] */) {
|
var deserializeTiddlerDiv = function(text /* [,fields] */) {
|
||||||
// Slot together the default results
|
// Slot together the default results
|
||||||
var result = {};
|
var result = {};
|
||||||
if(arguments.length > 1) {
|
if(arguments.length > 1) {
|
||||||
@ -67,106 +185,4 @@ var parseTiddlerDiv = function(text /* [,fields] */) {
|
|||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports["application/x-tiddler-html-div"] = function(text,fields) {
|
|
||||||
return [parseTiddlerDiv(text,fields)];
|
|
||||||
};
|
|
||||||
|
|
||||||
exports["application/json"] = function(text,fields) {
|
|
||||||
var incoming,
|
|
||||||
results = [];
|
|
||||||
try {
|
|
||||||
incoming = JSON.parse(text);
|
|
||||||
} catch(e) {
|
|
||||||
incoming = [{
|
|
||||||
title: "JSON error: " + e,
|
|
||||||
text: ""
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
if(!$tw.utils.isArray(incoming)) {
|
|
||||||
incoming = [incoming];
|
|
||||||
}
|
|
||||||
for(var t=0; t<incoming.length; t++) {
|
|
||||||
var incomingFields = incoming[t],
|
|
||||||
fields = {};
|
|
||||||
for(var f in incomingFields) {
|
|
||||||
if(typeof incomingFields[f] === "string") {
|
|
||||||
fields[f] = incomingFields[f];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
results.push(fields);
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Parse an HTML file into tiddlers. There are three possibilities:
|
|
||||||
# A TiddlyWiki classic HTML file containing `text/x-tiddlywiki` tiddlers
|
|
||||||
# A TiddlyWiki5 HTML file containing `text/vnd.tiddlywiki` tiddlers
|
|
||||||
# An ordinary HTML file
|
|
||||||
*/
|
|
||||||
exports["text/html"] = function(text,fields) {
|
|
||||||
// Check if we've got a store area
|
|
||||||
var storeAreaMarkerRegExp = /<div id=["']?storeArea['"]?( style=["']?display:none;["']?)?>/gi,
|
|
||||||
match = storeAreaMarkerRegExp.exec(text);
|
|
||||||
if(match) {
|
|
||||||
// If so, it's either a classic TiddlyWiki file or an unencrypted TW5 file
|
|
||||||
// First read the normal tiddlers
|
|
||||||
var results = deserializeTiddlyWikiFile(text,storeAreaMarkerRegExp.lastIndex,!!match[1],fields);
|
|
||||||
// Then any system tiddlers
|
|
||||||
var systemAreaMarkerRegExp = /<div id=["']?systemArea['"]?( style=["']?display:none;["']?)?>/gi,
|
|
||||||
sysMatch = systemAreaMarkerRegExp.exec(text);
|
|
||||||
if(sysMatch) {
|
|
||||||
results.push.apply(results,deserializeTiddlyWikiFile(text,systemAreaMarkerRegExp.lastIndex,!!sysMatch[1],fields));
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
} else {
|
|
||||||
// Check whether we've got an encrypted file
|
|
||||||
var encryptedStoreArea = $tw.utils.extractEncryptedStoreArea(text);
|
|
||||||
if(encryptedStoreArea) {
|
|
||||||
// If so, attempt to decrypt it using the current password
|
|
||||||
return $tw.utils.decryptStoreArea(encryptedStoreArea);
|
|
||||||
} else {
|
|
||||||
// It's not a TiddlyWiki so we'll return the entire HTML file as a tiddler
|
|
||||||
return deserializeHtmlFile(text,fields);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function deserializeHtmlFile(text,fields) {
|
|
||||||
var result = {};
|
|
||||||
$tw.utils.each(fields,function(value,name) {
|
|
||||||
result[name] = value;
|
|
||||||
});
|
|
||||||
result.text = text;
|
|
||||||
result.type = "text/html";
|
|
||||||
return [result];
|
|
||||||
}
|
|
||||||
|
|
||||||
function deserializeTiddlyWikiFile(text,storeAreaEnd,isTiddlyWiki5,fields) {
|
|
||||||
var results = [],
|
|
||||||
endOfDivRegExp = /(<\/div>\s*)/gi,
|
|
||||||
startPos = storeAreaEnd,
|
|
||||||
defaultType = isTiddlyWiki5 ? undefined : "text/x-tiddlywiki";
|
|
||||||
endOfDivRegExp.lastIndex = startPos;
|
|
||||||
var match = endOfDivRegExp.exec(text);
|
|
||||||
while(match) {
|
|
||||||
var endPos = endOfDivRegExp.lastIndex,
|
|
||||||
tiddlerFields = parseTiddlerDiv(text.substring(startPos,endPos),fields,{type: defaultType});
|
|
||||||
if(!tiddlerFields) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$tw.utils.each(tiddlerFields,function(value,name) {
|
|
||||||
if(typeof value === "string") {
|
|
||||||
tiddlerFields[name] = $tw.utils.htmlDecode(value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if(tiddlerFields.text !== null) {
|
|
||||||
results.push(tiddlerFields);
|
|
||||||
}
|
|
||||||
startPos = endPos;
|
|
||||||
match = endOfDivRegExp.exec(text);
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -88,6 +88,18 @@ function FramedEngine(options) {
|
|||||||
{name: "keydown",handlerObject: this.widget,handlerMethod: "handleKeydownEvent"},
|
{name: "keydown",handlerObject: this.widget,handlerMethod: "handleKeydownEvent"},
|
||||||
{name: "focus",handlerObject: this,handlerMethod: "handleFocusEvent"}
|
{name: "focus",handlerObject: this,handlerMethod: "handleFocusEvent"}
|
||||||
]);
|
]);
|
||||||
|
// Add drag and drop event listeners if fileDrop is enabled
|
||||||
|
if(this.widget.isFileDropEnabled) {
|
||||||
|
$tw.utils.addEventListeners(this.domNode,[
|
||||||
|
{name: "dragenter",handlerObject: this.widget,handlerMethod: "handleDragEnterEvent"},
|
||||||
|
{name: "dragover",handlerObject: this.widget,handlerMethod: "handleDragOverEvent"},
|
||||||
|
{name: "dragleave",handlerObject: this.widget,handlerMethod: "handleDragLeaveEvent"},
|
||||||
|
{name: "dragend",handlerObject: this.widget,handlerMethod: "handleDragEndEvent"},
|
||||||
|
{name: "drop", handlerObject: this.widget,handlerMethod: "handleDropEvent"},
|
||||||
|
{name: "paste", handlerObject: this.widget,handlerMethod: "handlePasteEvent"},
|
||||||
|
{name: "click",handlerObject: this.widget,handlerMethod: "handleClickEvent"}
|
||||||
|
]);
|
||||||
|
}
|
||||||
// Insert the element into the DOM
|
// Insert the element into the DOM
|
||||||
this.iframeDoc.body.appendChild(this.domNode);
|
this.iframeDoc.body.appendChild(this.domNode);
|
||||||
}
|
}
|
||||||
@ -123,7 +135,11 @@ FramedEngine.prototype.setText = function(text,type) {
|
|||||||
Update the DomNode with the new text
|
Update the DomNode with the new text
|
||||||
*/
|
*/
|
||||||
FramedEngine.prototype.updateDomNodeText = function(text) {
|
FramedEngine.prototype.updateDomNodeText = function(text) {
|
||||||
|
try {
|
||||||
this.domNode.value = text;
|
this.domNode.value = text;
|
||||||
|
} catch(e) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -85,7 +85,11 @@ SimpleEngine.prototype.setText = function(text,type) {
|
|||||||
Update the DomNode with the new text
|
Update the DomNode with the new text
|
||||||
*/
|
*/
|
||||||
SimpleEngine.prototype.updateDomNodeText = function(text) {
|
SimpleEngine.prototype.updateDomNodeText = function(text) {
|
||||||
|
try {
|
||||||
this.domNode.value = text;
|
this.domNode.value = text;
|
||||||
|
} catch(e) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -103,7 +103,11 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
|||||||
var tiddler = this.wiki.getTiddler(this.editTitle);
|
var tiddler = this.wiki.getTiddler(this.editTitle);
|
||||||
if(tiddler) {
|
if(tiddler) {
|
||||||
// If we've got a tiddler, the value to display is the field string value
|
// If we've got a tiddler, the value to display is the field string value
|
||||||
|
if(tiddler.hasField(this.editField)) {
|
||||||
value = tiddler.getFieldString(this.editField);
|
value = tiddler.getFieldString(this.editField);
|
||||||
|
} else {
|
||||||
|
value = this.editDefault || "";
|
||||||
|
}
|
||||||
if(this.editField === "text") {
|
if(this.editField === "text") {
|
||||||
type = tiddler.fields.type || "text/vnd.tiddlywiki";
|
type = tiddler.fields.type || "text/vnd.tiddlywiki";
|
||||||
}
|
}
|
||||||
@ -182,6 +186,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
|||||||
this.editRefreshTitle = this.getAttribute("refreshTitle");
|
this.editRefreshTitle = this.getAttribute("refreshTitle");
|
||||||
this.editAutoComplete = this.getAttribute("autocomplete");
|
this.editAutoComplete = this.getAttribute("autocomplete");
|
||||||
this.isDisabled = this.getAttribute("disabled","no");
|
this.isDisabled = this.getAttribute("disabled","no");
|
||||||
|
this.isFileDropEnabled = this.getAttribute("fileDrop","no") === "yes";
|
||||||
// Get the default editor element tag and type
|
// Get the default editor element tag and type
|
||||||
var tag,type;
|
var tag,type;
|
||||||
if(this.editField === "text") {
|
if(this.editField === "text") {
|
||||||
@ -213,7 +218,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
|||||||
EditTextWidget.prototype.refresh = function(changedTiddlers) {
|
EditTextWidget.prototype.refresh = function(changedTiddlers) {
|
||||||
var changedAttributes = this.computeAttributes();
|
var changedAttributes = this.computeAttributes();
|
||||||
// Completely rerender if any of our attributes have changed
|
// Completely rerender if any of our attributes have changed
|
||||||
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedAttributes.disabled) {
|
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedAttributes.disabled || changedAttributes.fileDrop) {
|
||||||
this.refreshSelf();
|
this.refreshSelf();
|
||||||
return true;
|
return true;
|
||||||
} else if (changedTiddlers[this.editRefreshTitle]) {
|
} else if (changedTiddlers[this.editRefreshTitle]) {
|
||||||
@ -293,21 +298,89 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
|||||||
Propogate keydown events to our container for the keyboard widgets benefit
|
Propogate keydown events to our container for the keyboard widgets benefit
|
||||||
*/
|
*/
|
||||||
EditTextWidget.prototype.propogateKeydownEvent = function(event) {
|
EditTextWidget.prototype.propogateKeydownEvent = function(event) {
|
||||||
var newEvent = this.document.createEventObject ? this.document.createEventObject() : this.document.createEvent("Events");
|
var newEvent = this.cloneEvent(event,["keyCode","which","metaKey","ctrlKey","altKey","shiftKey"]);
|
||||||
if(newEvent.initEvent) {
|
|
||||||
newEvent.initEvent("keydown", true, true);
|
|
||||||
}
|
|
||||||
newEvent.keyCode = event.keyCode;
|
|
||||||
newEvent.which = event.which;
|
|
||||||
newEvent.metaKey = event.metaKey;
|
|
||||||
newEvent.ctrlKey = event.ctrlKey;
|
|
||||||
newEvent.altKey = event.altKey;
|
|
||||||
newEvent.shiftKey = event.shiftKey;
|
|
||||||
return !this.parentDomNode.dispatchEvent(newEvent);
|
return !this.parentDomNode.dispatchEvent(newEvent);
|
||||||
};
|
};
|
||||||
|
|
||||||
return EditTextWidget;
|
EditTextWidget.prototype.cloneEvent = function(event,propertiesToCopy) {
|
||||||
|
var propertiesToCopy = propertiesToCopy || [],
|
||||||
|
newEvent = this.document.createEventObject ? this.document.createEventObject() : this.document.createEvent("Events");
|
||||||
|
if(newEvent.initEvent) {
|
||||||
|
newEvent.initEvent(event.type, true, true);
|
||||||
|
}
|
||||||
|
$tw.utils.each(propertiesToCopy,function(prop){
|
||||||
|
newEvent[prop] = event[prop];
|
||||||
|
});
|
||||||
|
return newEvent;
|
||||||
|
};
|
||||||
|
|
||||||
|
EditTextWidget.prototype.dispatchDOMEvent = function(newEvent) {
|
||||||
|
var dispatchNode = this.engine.iframeNode || this.engine.parentNode;
|
||||||
|
return dispatchNode.dispatchEvent(newEvent);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Propogate drag and drop events with File data to our container for the dropzone widgets benefit.
|
||||||
|
If there are no Files, let the browser handle it.
|
||||||
|
*/
|
||||||
|
EditTextWidget.prototype.handleDropEvent = function(event) {
|
||||||
|
if(event.dataTransfer.files.length) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
this.dispatchDOMEvent(this.cloneEvent(event,["dataTransfer"]));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EditTextWidget.prototype.handlePasteEvent = function(event) {
|
||||||
|
if(event.clipboardData && event.clipboardData.files && event.clipboardData.files.length) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
this.dispatchDOMEvent(this.cloneEvent(event,["clipboardData"]));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EditTextWidget.prototype.handleDragEnterEvent = function(event) {
|
||||||
|
if($tw.utils.dragEventContainsFiles(event)) {
|
||||||
|
// Ignore excessive events fired by FF when entering and leaving text nodes in a text area.
|
||||||
|
if( event.relatedTarget && (event.relatedTarget.nodeType === 3 || event.target === event.relatedTarget)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
return this.dispatchDOMEvent(this.cloneEvent(event,["dataTransfer"]));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
EditTextWidget.prototype.handleDragOverEvent = function(event) {
|
||||||
|
if($tw.utils.dragEventContainsFiles(event)) {
|
||||||
|
// Call preventDefault() in browsers that default to not allowing drop events on textarea
|
||||||
|
if($tw.browser.isFirefox || $tw.browser.isIE) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
event.dataTransfer.dropEffect = "copy";
|
||||||
|
return this.dispatchDOMEvent(this.cloneEvent(event,["dataTransfer"]));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
EditTextWidget.prototype.handleDragLeaveEvent = function(event) {
|
||||||
|
// Ignore excessive events fired by FF when entering and leaving text nodes in a text area.
|
||||||
|
if(event.relatedTarget && ((event.relatedTarget.nodeType === 3) || (event.target === event.relatedTarget))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
this.dispatchDOMEvent(this.cloneEvent(event,["dataTransfer"]));
|
||||||
|
};
|
||||||
|
|
||||||
|
EditTextWidget.prototype.handleDragEndEvent = function(event) {
|
||||||
|
this.dispatchDOMEvent(this.cloneEvent(event));
|
||||||
|
};
|
||||||
|
|
||||||
|
EditTextWidget.prototype.handleClickEvent = function(event) {
|
||||||
|
return !this.dispatchDOMEvent(this.cloneEvent(event));
|
||||||
|
};
|
||||||
|
|
||||||
|
return EditTextWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.editTextWidgetFactory = editTextWidgetFactory;
|
exports.editTextWidgetFactory = editTextWidgetFactory;
|
||||||
|
17
core/modules/editor/operations/text/focus-editor.js
Normal file
17
core/modules/editor/operations/text/focus-editor.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/editor/operations/text/focus-editor.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: texteditoroperation
|
||||||
|
Simply focus the Text editor
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
exports["focus-editor"] = function(event,operation) {
|
||||||
|
operation = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
23
core/modules/editor/operations/text/insert-text.js
Normal file
23
core/modules/editor/operations/text/insert-text.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/editor/operations/text/insert-text.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: texteditoroperation
|
||||||
|
|
||||||
|
Text editor operation insert text at the caret position. If there is a selection it is replaced.
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
exports["insert-text"] = function(event,operation) {
|
||||||
|
operation.replacement = event.paramObject.text;
|
||||||
|
operation.cutStart = operation.selStart;
|
||||||
|
operation.cutEnd = operation.selEnd;
|
||||||
|
operation.newSelStart = operation.selStart + operation.replacement.length;
|
||||||
|
operation.newSelEnd = operation.newSelStart;
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
@ -17,10 +17,21 @@ exports.filter = function(operationSubFunction,options) {
|
|||||||
return function(results,source,widget) {
|
return function(results,source,widget) {
|
||||||
if(results.length > 0) {
|
if(results.length > 0) {
|
||||||
var resultsToRemove = [];
|
var resultsToRemove = [];
|
||||||
results.each(function(result) {
|
results.each(function(title) {
|
||||||
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([result]),widget);
|
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
||||||
|
getVariable: function(name) {
|
||||||
|
switch(name) {
|
||||||
|
case "currentTiddler":
|
||||||
|
return "" + title;
|
||||||
|
case "..currentTiddler":
|
||||||
|
return widget.getVariable("currentTiddler");
|
||||||
|
default:
|
||||||
|
return widget.getVariable(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
if(filtered.length === 0) {
|
if(filtered.length === 0) {
|
||||||
resultsToRemove.push(result);
|
resultsToRemove.push(title);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
results.remove(resultsToRemove);
|
results.remove(resultsToRemove);
|
||||||
|
39
core/modules/filterrunprefixes/map.js
Normal file
39
core/modules/filterrunprefixes/map.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/filterrunprefixes/map.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: filterrunprefix
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Export our filter prefix function
|
||||||
|
*/
|
||||||
|
exports.map = function(operationSubFunction,options) {
|
||||||
|
return function(results,source,widget) {
|
||||||
|
if(results.length > 0) {
|
||||||
|
var inputTitles = results.toArray();
|
||||||
|
results.clear();
|
||||||
|
$tw.utils.each(inputTitles,function(title) {
|
||||||
|
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
||||||
|
getVariable: function(name) {
|
||||||
|
switch(name) {
|
||||||
|
case "currentTiddler":
|
||||||
|
return "" + title;
|
||||||
|
case "..currentTiddler":
|
||||||
|
return widget.getVariable("currentTiddler");
|
||||||
|
default:
|
||||||
|
return widget.getVariable(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
results.push(filtered[0] || "");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
@ -23,6 +23,8 @@ exports.reduce = function(operationSubFunction,options) {
|
|||||||
switch(name) {
|
switch(name) {
|
||||||
case "currentTiddler":
|
case "currentTiddler":
|
||||||
return "" + title;
|
return "" + title;
|
||||||
|
case "..currentTiddler":
|
||||||
|
return widget.getVariable("currentTiddler");
|
||||||
case "accumulator":
|
case "accumulator":
|
||||||
return "" + accumulator;
|
return "" + accumulator;
|
||||||
case "index":
|
case "index":
|
||||||
|
60
core/modules/filterrunprefixes/sort.js
Normal file
60
core/modules/filterrunprefixes/sort.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/filterrunprefixes/sort.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: filterrunprefix
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Export our filter prefix function
|
||||||
|
*/
|
||||||
|
exports.sort = function(operationSubFunction,options) {
|
||||||
|
return function(results,source,widget) {
|
||||||
|
if(results.length > 0) {
|
||||||
|
var suffixes = options.suffixes,
|
||||||
|
sortType = (suffixes[0] && suffixes[0][0]) ? suffixes[0][0] : "string",
|
||||||
|
invert = suffixes[1] ? (suffixes[1].indexOf("reverse") !== -1) : false,
|
||||||
|
isCaseSensitive = suffixes[1] ? (suffixes[1].indexOf("casesensitive") !== -1) : false,
|
||||||
|
inputTitles = results.toArray(),
|
||||||
|
sortKeys = [],
|
||||||
|
indexes = new Array(inputTitles.length),
|
||||||
|
compareFn;
|
||||||
|
results.each(function(title) {
|
||||||
|
var key = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
||||||
|
getVariable: function(name) {
|
||||||
|
switch(name) {
|
||||||
|
case "currentTiddler":
|
||||||
|
return "" + title;
|
||||||
|
case "..currentTiddler":
|
||||||
|
return widget.getVariable("currentTiddler");
|
||||||
|
default:
|
||||||
|
return widget.getVariable(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
sortKeys.push(key[0] || "");
|
||||||
|
});
|
||||||
|
results.clear();
|
||||||
|
// Prepare an array of indexes to sort
|
||||||
|
for(var t=0; t<inputTitles.length; t++) {
|
||||||
|
indexes[t] = t;
|
||||||
|
}
|
||||||
|
// Sort the indexes
|
||||||
|
compareFn = $tw.utils.makeCompareFunction(sortType,{defaultType: "string", invert:invert, isCaseSensitive:isCaseSensitive});
|
||||||
|
indexes = indexes.sort(function(a,b) {
|
||||||
|
return compareFn(sortKeys[a],sortKeys[b]);
|
||||||
|
});
|
||||||
|
// Add to results in correct order
|
||||||
|
$tw.utils.each(indexes,function(index) {
|
||||||
|
results.push(inputTitles[index]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
@ -137,7 +137,7 @@ exports.parseFilter = function(filterString) {
|
|||||||
p = 0, // Current position in the filter string
|
p = 0, // Current position in the filter string
|
||||||
match;
|
match;
|
||||||
var whitespaceRegExp = /(\s+)/mg,
|
var whitespaceRegExp = /(\s+)/mg,
|
||||||
operandRegExp = /((?:\+|\-|~|=|\:(\w+))?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
|
operandRegExp = /((?:\+|\-|~|=|\:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
|
||||||
while(p < filterString.length) {
|
while(p < filterString.length) {
|
||||||
// Skip any whitespace
|
// Skip any whitespace
|
||||||
whitespaceRegExp.lastIndex = p;
|
whitespaceRegExp.lastIndex = p;
|
||||||
@ -162,15 +162,27 @@ exports.parseFilter = function(filterString) {
|
|||||||
if(match[2]) {
|
if(match[2]) {
|
||||||
operation.namedPrefix = match[2];
|
operation.namedPrefix = match[2];
|
||||||
}
|
}
|
||||||
|
if(match[3]) {
|
||||||
|
operation.suffixes = [];
|
||||||
|
$tw.utils.each(match[3].split(":"),function(subsuffix) {
|
||||||
|
operation.suffixes.push([]);
|
||||||
|
$tw.utils.each(subsuffix.split(","),function(entry) {
|
||||||
|
entry = $tw.utils.trim(entry);
|
||||||
|
if(entry) {
|
||||||
|
operation.suffixes[operation.suffixes.length -1].push(entry);
|
||||||
}
|
}
|
||||||
if(match[3]) { // Opening square bracket
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(match[4]) { // Opening square bracket
|
||||||
p = parseFilterOperation(operation.operators,filterString,p);
|
p = parseFilterOperation(operation.operators,filterString,p);
|
||||||
} else {
|
} else {
|
||||||
p = match.index + match[0].length;
|
p = match.index + match[0].length;
|
||||||
}
|
}
|
||||||
if(match[4] || match[5] || match[6]) { // Double quoted string, single quoted string or unquoted title
|
if(match[5] || match[6] || match[7]) { // Double quoted string, single quoted string or unquoted title
|
||||||
operation.operators.push(
|
operation.operators.push(
|
||||||
{operator: "title", operands: [{text: match[4] || match[5] || match[6]}]}
|
{operator: "title", operands: [{text: match[5] || match[6] || match[7]}]}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
results.push(operation);
|
results.push(operation);
|
||||||
@ -241,7 +253,8 @@ exports.compileFilter = function(filterString) {
|
|||||||
if(operand.indirect) {
|
if(operand.indirect) {
|
||||||
operand.value = self.getTextReference(operand.text,"",currTiddlerTitle);
|
operand.value = self.getTextReference(operand.text,"",currTiddlerTitle);
|
||||||
} else if(operand.variable) {
|
} else if(operand.variable) {
|
||||||
operand.value = widget.getVariable(operand.text,{defaultValue: ""});
|
var varTree = $tw.utils.parseFilterVariable(operand.text);
|
||||||
|
operand.value = widget.getVariable(varTree.name,{params:varTree.params,defaultValue: ""});
|
||||||
} else {
|
} else {
|
||||||
operand.value = operand.text;
|
operand.value = operand.text;
|
||||||
}
|
}
|
||||||
@ -280,7 +293,7 @@ exports.compileFilter = function(filterString) {
|
|||||||
var filterRunPrefixes = self.getFilterRunPrefixes();
|
var filterRunPrefixes = self.getFilterRunPrefixes();
|
||||||
// Wrap the operator functions in a wrapper function that depends on the prefix
|
// Wrap the operator functions in a wrapper function that depends on the prefix
|
||||||
operationFunctions.push((function() {
|
operationFunctions.push((function() {
|
||||||
var options = {wiki: self};
|
var options = {wiki: self, suffixes: operation.suffixes || []};
|
||||||
switch(operation.prefix || "") {
|
switch(operation.prefix || "") {
|
||||||
case "": // No prefix means that the operation is unioned into the result
|
case "": // No prefix means that the operation is unioned into the result
|
||||||
return filterRunPrefixes["or"](operationSubFunction, options);
|
return filterRunPrefixes["or"](operationSubFunction, options);
|
||||||
@ -311,6 +324,9 @@ exports.compileFilter = function(filterString) {
|
|||||||
} else if(typeof source === "object") { // Array or hashmap
|
} else if(typeof source === "object") { // Array or hashmap
|
||||||
source = self.makeTiddlerIterator(source);
|
source = self.makeTiddlerIterator(source);
|
||||||
}
|
}
|
||||||
|
if(!widget) {
|
||||||
|
widget = $tw.rootWidget;
|
||||||
|
}
|
||||||
var results = new $tw.utils.LinkedList();
|
var results = new $tw.utils.LinkedList();
|
||||||
$tw.utils.each(operationFunctions,function(operationFunction) {
|
$tw.utils.each(operationFunctions,function(operationFunction) {
|
||||||
operationFunction(results,source,widget);
|
operationFunction(results,source,widget);
|
||||||
|
@ -52,7 +52,7 @@ exports.all = function(source,operator,options) {
|
|||||||
results.pushTop(subop(source,operator.prefix,options));
|
results.pushTop(subop(source,operator.prefix,options));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return results.toArray();
|
return results.makeTiddlerIterator(options.wiki);
|
||||||
};
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -16,11 +16,11 @@ Filter operator for returning all the backlinks from a tiddler
|
|||||||
Export our filter function
|
Export our filter function
|
||||||
*/
|
*/
|
||||||
exports.backlinks = function(source,operator,options) {
|
exports.backlinks = function(source,operator,options) {
|
||||||
var results = [];
|
var results = new $tw.utils.LinkedList();
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
$tw.utils.pushTop(results,options.wiki.getTiddlerBacklinks(title));
|
results.pushTop(options.wiki.getTiddlerBacklinks(title));
|
||||||
});
|
});
|
||||||
return results;
|
return results.makeTiddlerIterator(options.wiki);
|
||||||
};
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -17,7 +17,7 @@ Export our filter function
|
|||||||
*/
|
*/
|
||||||
exports.contains = function(source,operator,options) {
|
exports.contains = function(source,operator,options) {
|
||||||
var results = [],
|
var results = [],
|
||||||
fieldname = (operator.suffix || "list").toLowerCase();
|
fieldname = operator.suffix || "list";
|
||||||
if(operator.prefix === "!") {
|
if(operator.prefix === "!") {
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
if(tiddler) {
|
if(tiddler) {
|
||||||
|
27
core/modules/filters/deserializers.js
Normal file
27
core/modules/filters/deserializers.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/filters/deserializers.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: filteroperator
|
||||||
|
|
||||||
|
Filter operator for returning the names of the deserializers in this wiki
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Export our filter function
|
||||||
|
*/
|
||||||
|
exports.deserializers = function(source,operator,options) {
|
||||||
|
var results = [];
|
||||||
|
$tw.utils.each($tw.Wiki.tiddlerDeserializerModules,function(deserializer,type) {
|
||||||
|
results.push(type);
|
||||||
|
});
|
||||||
|
results.sort();
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
@ -19,12 +19,7 @@ Export our filter functions
|
|||||||
exports.decodeuricomponent = function(source,operator,options) {
|
exports.decodeuricomponent = function(source,operator,options) {
|
||||||
var results = [];
|
var results = [];
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
var value = title;
|
results.push($tw.utils.decodeURIComponentSafe(title));
|
||||||
try {
|
|
||||||
value = decodeURIComponent(title);
|
|
||||||
} catch(e) {
|
|
||||||
}
|
|
||||||
results.push(value);
|
|
||||||
});
|
});
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
@ -40,12 +35,7 @@ exports.encodeuricomponent = function(source,operator,options) {
|
|||||||
exports.decodeuri = function(source,operator,options) {
|
exports.decodeuri = function(source,operator,options) {
|
||||||
var results = [];
|
var results = [];
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
var value = title;
|
results.push($tw.utils.decodeURISafe(title));
|
||||||
try {
|
|
||||||
value = decodeURI(title);
|
|
||||||
} catch(e) {
|
|
||||||
}
|
|
||||||
results.push(value);
|
|
||||||
});
|
});
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
@ -102,7 +92,7 @@ exports.escapecss = function(source,operator,options) {
|
|||||||
var results = [];
|
var results = [];
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
// escape any character with a special meaning in CSS using CSS.escape()
|
// escape any character with a special meaning in CSS using CSS.escape()
|
||||||
results.push(CSS.escape(title));
|
results.push($tw.utils.escapeCSS(title));
|
||||||
});
|
});
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
@ -17,7 +17,7 @@ Export our filter function
|
|||||||
*/
|
*/
|
||||||
exports.field = function(source,operator,options) {
|
exports.field = function(source,operator,options) {
|
||||||
var results = [],indexedResults,
|
var results = [],indexedResults,
|
||||||
fieldname = (operator.suffix || operator.operator || "title").toLowerCase();
|
fieldname = operator.suffix || operator.operator || "title";
|
||||||
if(operator.prefix === "!") {
|
if(operator.prefix === "!") {
|
||||||
if(operator.regexp) {
|
if(operator.regexp) {
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
|
@ -20,7 +20,18 @@ exports.filter = function(source,operator,options) {
|
|||||||
results = [],
|
results = [],
|
||||||
target = operator.prefix !== "!";
|
target = operator.prefix !== "!";
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
var list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]));
|
var list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),{
|
||||||
|
getVariable: function(name) {
|
||||||
|
switch(name) {
|
||||||
|
case "currentTiddler":
|
||||||
|
return "" + title;
|
||||||
|
case "..currentTiddler":
|
||||||
|
return options.widget.getVariable("currentTiddler");
|
||||||
|
default:
|
||||||
|
return options.widget.getVariable(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
if((list.length > 0) === target) {
|
if((list.length > 0) === target) {
|
||||||
results.push(title);
|
results.push(title);
|
||||||
}
|
}
|
||||||
|
25
core/modules/filters/format/titlelist.js
Normal file
25
core/modules/filters/format/titlelist.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/filters/format/titlelist.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: formatfilteroperator
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Export our filter function
|
||||||
|
*/
|
||||||
|
exports.titlelist = function(source,operand,options) {
|
||||||
|
var results = [];
|
||||||
|
source(function(tiddler,title) {
|
||||||
|
if(title && title.length) {
|
||||||
|
results.push($tw.utils.stringifyList([title]));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
@ -20,7 +20,7 @@ exports.links = function(source,operator,options) {
|
|||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
results.pushTop(options.wiki.getTiddlerLinks(title));
|
results.pushTop(options.wiki.getTiddlerLinks(title));
|
||||||
});
|
});
|
||||||
return results.toArray();
|
return results.makeTiddlerIterator(options.wiki);
|
||||||
};
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -125,6 +125,83 @@ exports.minall = makeNumericReducingOperator(
|
|||||||
Infinity // Initial value
|
Infinity // Initial value
|
||||||
);
|
);
|
||||||
|
|
||||||
|
exports.median = makeNumericArrayOperator(
|
||||||
|
function(values) {
|
||||||
|
var len = values.length, median;
|
||||||
|
values.sort();
|
||||||
|
if(len % 2) {
|
||||||
|
// Odd, return the middle number
|
||||||
|
median = values[(len - 1) / 2];
|
||||||
|
} else {
|
||||||
|
// Even, return average of two middle numbers
|
||||||
|
median = (values[len / 2 - 1] + values[len / 2]) / 2;
|
||||||
|
}
|
||||||
|
return [median];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
exports.average = makeNumericReducingOperator(
|
||||||
|
function(accumulator,value) {return accumulator + value},
|
||||||
|
0, // Initial value
|
||||||
|
function(finalValue,numberOfValues) {
|
||||||
|
return finalValue/numberOfValues;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
exports.variance = makeNumericReducingOperator(
|
||||||
|
function(accumulator,value) {return accumulator + value},
|
||||||
|
0,
|
||||||
|
function(finalValue,numberOfValues,originalValues) {
|
||||||
|
return getVarianceFromArray(originalValues,finalValue/numberOfValues);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
exports["standard-deviation"] = makeNumericReducingOperator(
|
||||||
|
function(accumulator,value) {return accumulator + value},
|
||||||
|
0,
|
||||||
|
function(finalValue,numberOfValues,originalValues) {
|
||||||
|
var variance = getVarianceFromArray(originalValues,finalValue/numberOfValues);
|
||||||
|
return Math.sqrt(variance);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//trigonometry
|
||||||
|
exports.cos = makeNumericBinaryOperator(
|
||||||
|
function(a) {return Math.cos(a)}
|
||||||
|
);
|
||||||
|
|
||||||
|
exports.sin = makeNumericBinaryOperator(
|
||||||
|
function(a) {return Math.sin(a)}
|
||||||
|
);
|
||||||
|
|
||||||
|
exports.tan = makeNumericBinaryOperator(
|
||||||
|
function(a) {return Math.tan(a)}
|
||||||
|
);
|
||||||
|
|
||||||
|
exports.acos = makeNumericBinaryOperator(
|
||||||
|
function(a) {return Math.acos(a)}
|
||||||
|
);
|
||||||
|
|
||||||
|
exports.asin = makeNumericBinaryOperator(
|
||||||
|
function(a) {return Math.asin(a)}
|
||||||
|
);
|
||||||
|
|
||||||
|
exports.atan = makeNumericBinaryOperator(
|
||||||
|
function(a) {return Math.atan(a)}
|
||||||
|
);
|
||||||
|
|
||||||
|
exports.atan2 = makeNumericBinaryOperator(
|
||||||
|
function(a,b) {return Math.atan2(a,b)}
|
||||||
|
);
|
||||||
|
|
||||||
|
//Calculate the variance of a population of numbers in an array given its mean
|
||||||
|
function getVarianceFromArray(values,mean) {
|
||||||
|
var deviationTotal = values.reduce(function(accumulator,value) {
|
||||||
|
return accumulator + Math.pow(value - mean, 2);
|
||||||
|
},0);
|
||||||
|
return deviationTotal/values.length;
|
||||||
|
};
|
||||||
|
|
||||||
function makeNumericBinaryOperator(fnCalc) {
|
function makeNumericBinaryOperator(fnCalc) {
|
||||||
return function(source,operator,options) {
|
return function(source,operator,options) {
|
||||||
var result = [],
|
var result = [],
|
||||||
@ -134,19 +211,37 @@ function makeNumericBinaryOperator(fnCalc) {
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
function makeNumericReducingOperator(fnCalc,initialValue) {
|
function makeNumericReducingOperator(fnCalc,initialValue,fnFinal) {
|
||||||
initialValue = initialValue || 0;
|
initialValue = initialValue || 0;
|
||||||
return function(source,operator,options) {
|
return function(source,operator,options) {
|
||||||
var result = [];
|
var result = [];
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
result.push(title);
|
result.push($tw.utils.parseNumber(title));
|
||||||
});
|
});
|
||||||
return [$tw.utils.stringifyNumber(result.reduce(function(accumulator,currentValue) {
|
var value = result.reduce(function(accumulator,currentValue) {
|
||||||
return fnCalc(accumulator,$tw.utils.parseNumber(currentValue));
|
return fnCalc(accumulator,currentValue);
|
||||||
},initialValue))];
|
},initialValue);
|
||||||
};
|
if(fnFinal) {
|
||||||
|
value = fnFinal(value,result.length,result);
|
||||||
}
|
}
|
||||||
|
return [$tw.utils.stringifyNumber(value)];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function makeNumericArrayOperator(fnCalc) {
|
||||||
|
return function(source,operator,options) {
|
||||||
|
var results = [];
|
||||||
|
source(function(tiddler,title) {
|
||||||
|
results.push($tw.utils.parseNumber(title));
|
||||||
|
});
|
||||||
|
results = fnCalc(results);
|
||||||
|
$tw.utils.each(results,function(value,index) {
|
||||||
|
results[index] = $tw.utils.stringifyNumber(value);
|
||||||
|
});
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
30
core/modules/filters/moduleproperty.js
Normal file
30
core/modules/filters/moduleproperty.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/filters/moduleproperty.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: filteroperator
|
||||||
|
|
||||||
|
Filter [[module-name]moduleproperty[name]] retrieve a module property
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Export our filter function
|
||||||
|
*/
|
||||||
|
exports.moduleproperty = function(source,operator,options) {
|
||||||
|
var results = [];
|
||||||
|
source(function(tiddler,title) {
|
||||||
|
var value = require(title)[operator.operand || ""];
|
||||||
|
if(value !== undefined) {
|
||||||
|
results.push(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
results.sort();
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
@ -17,11 +17,23 @@ Export our filter function
|
|||||||
*/
|
*/
|
||||||
exports.modules = function(source,operator,options) {
|
exports.modules = function(source,operator,options) {
|
||||||
var results = [];
|
var results = [];
|
||||||
|
if(operator.operands.length >= 2) {
|
||||||
|
// Return the modules that have the module property specified in the first operand with the value in the second operand
|
||||||
|
source(function(tiddler,title) {
|
||||||
|
$tw.utils.each($tw.modules.types[title],function(moduleInfo,moduleName) {
|
||||||
|
if(require(moduleName)[operator.operands[0]] === operator.operands[1]) {
|
||||||
|
results.push(moduleName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Return all the module names without filtering
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
$tw.utils.each($tw.modules.types[title],function(moduleInfo,moduleName) {
|
$tw.utils.each($tw.modules.types[title],function(moduleInfo,moduleName) {
|
||||||
results.push(moduleName);
|
results.push(moduleName);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}
|
||||||
results.sort();
|
results.sort();
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
@ -17,9 +17,13 @@ Export our filter function
|
|||||||
*/
|
*/
|
||||||
exports.range = function(source,operator,options) {
|
exports.range = function(source,operator,options) {
|
||||||
var results = [];
|
var results = [];
|
||||||
// Split the operand into numbers delimited by these symbols
|
// For backwards compatibility, if there is only one operand, try to split it using one of the delimiters
|
||||||
var parts = operator.operand.split(/[,:;]/g),
|
var parts = operator.operands || [];
|
||||||
beg, end, inc, i, fixed = 0;
|
if(parts.length === 1) {
|
||||||
|
parts = operator.operand.split(/[,:;]/g);
|
||||||
|
}
|
||||||
|
// Process the parts
|
||||||
|
var beg, end, inc, i, fixed = 0;
|
||||||
for (i=0; i<parts.length; i++) {
|
for (i=0; i<parts.length; i++) {
|
||||||
// Validate real number
|
// Validate real number
|
||||||
if(!/^\s*[+-]?((\d+(\.\d*)?)|(\.\d+))\s*$/.test(parts[i])) {
|
if(!/^\s*[+-]?((\d+(\.\d*)?)|(\.\d+))\s*$/.test(parts[i])) {
|
||||||
|
@ -31,6 +31,8 @@ exports.reduce = function(source,operator,options) {
|
|||||||
switch(name) {
|
switch(name) {
|
||||||
case "currentTiddler":
|
case "currentTiddler":
|
||||||
return "" + title;
|
return "" + title;
|
||||||
|
case "..currentTiddler":
|
||||||
|
return options.widget.getVariable("currentTiddler");
|
||||||
case "accumulator":
|
case "accumulator":
|
||||||
return "" + accumulator;
|
return "" + accumulator;
|
||||||
case "index":
|
case "index":
|
||||||
|
@ -17,7 +17,7 @@ Export our filter function
|
|||||||
*/
|
*/
|
||||||
exports.regexp = function(source,operator,options) {
|
exports.regexp = function(source,operator,options) {
|
||||||
var results = [],
|
var results = [],
|
||||||
fieldname = (operator.suffix || "title").toLowerCase(),
|
fieldname = operator.suffix || "title",
|
||||||
regexpString, regexp, flags = "", match,
|
regexpString, regexp, flags = "", match,
|
||||||
getFieldString = function(tiddler,title) {
|
getFieldString = function(tiddler,title) {
|
||||||
if(tiddler) {
|
if(tiddler) {
|
||||||
|
@ -27,9 +27,12 @@ exports.sortsub = function(source,operator,options) {
|
|||||||
iterator(options.wiki.getTiddler(title),title);
|
iterator(options.wiki.getTiddler(title),title);
|
||||||
},{
|
},{
|
||||||
getVariable: function(name) {
|
getVariable: function(name) {
|
||||||
if(name === "currentTiddler") {
|
switch(name) {
|
||||||
return title;
|
case "currentTiddler":
|
||||||
} else {
|
return "" + title;
|
||||||
|
case "..currentTiddler":
|
||||||
|
return options.widget.getVariable("currentTiddler");
|
||||||
|
default:
|
||||||
return options.widget.getVariable(name);
|
return options.widget.getVariable(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ exports["search-replace"] = function(source,operator,options) {
|
|||||||
var results = [],
|
var results = [],
|
||||||
suffixes = operator.suffixes || [],
|
suffixes = operator.suffixes || [],
|
||||||
flagSuffix = (suffixes[0] ? (suffixes[0][0] || "") : ""),
|
flagSuffix = (suffixes[0] ? (suffixes[0][0] || "") : ""),
|
||||||
flags = (flagSuffix.indexOf("g") !== -1 ? "g" : "") + (flagSuffix.indexOf("i") !== -1 ? "i" : ""),
|
flags = (flagSuffix.indexOf("g") !== -1 ? "g" : "") + (flagSuffix.indexOf("i") !== -1 ? "i" : "") + (flagSuffix.indexOf("m") !== -1 ? "m" : ""),
|
||||||
isRegExp = (suffixes[1] && suffixes[1][0] === "regexp") ? true : false,
|
isRegExp = (suffixes[1] && suffixes[1][0] === "regexp") ? true : false,
|
||||||
searchTerm,
|
searchTerm,
|
||||||
regExp;
|
regExp;
|
||||||
@ -172,4 +172,14 @@ exports.pad = function(source,operator,options) {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.charcode = function(source,operator,options) {
|
||||||
|
var chars = [];
|
||||||
|
$tw.utils.each(operator.operands,function(operand) {
|
||||||
|
if(operand !== "") {
|
||||||
|
chars.push(String.fromCharCode($tw.utils.parseInt(operand)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return [chars.join("")];
|
||||||
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -16,20 +16,13 @@ Filter operator returning all the selected tiddlers that are untagged
|
|||||||
Export our filter function
|
Export our filter function
|
||||||
*/
|
*/
|
||||||
exports.untagged = function(source,operator,options) {
|
exports.untagged = function(source,operator,options) {
|
||||||
var results = [];
|
var results = [],
|
||||||
if(operator.prefix === "!") {
|
expected = (operator.prefix === "!");
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
if(tiddler && $tw.utils.isArray(tiddler.fields.tags) && tiddler.fields.tags.length > 0) {
|
if((tiddler && $tw.utils.isArray(tiddler.fields.tags) && tiddler.fields.tags.length > 0) === expected) {
|
||||||
$tw.utils.pushTop(results,title);
|
results.push(title);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
source(function(tiddler,title) {
|
|
||||||
if(!tiddler || !tiddler.hasField("tags") || ($tw.utils.isArray(tiddler.fields.tags) && tiddler.fields.tags.length === 0)) {
|
|
||||||
$tw.utils.pushTop(results,title);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -179,7 +179,7 @@ Key descriptors have the following format:
|
|||||||
ctrl+enter
|
ctrl+enter
|
||||||
ctrl+shift+alt+A
|
ctrl+shift+alt+A
|
||||||
*/
|
*/
|
||||||
KeyboardManager.prototype.parseKeyDescriptor = function(keyDescriptor) {
|
KeyboardManager.prototype.parseKeyDescriptor = function(keyDescriptor,options) {
|
||||||
var components = keyDescriptor.split(/\+|\-/),
|
var components = keyDescriptor.split(/\+|\-/),
|
||||||
info = {
|
info = {
|
||||||
keyCode: 0,
|
keyCode: 0,
|
||||||
@ -206,6 +206,9 @@ KeyboardManager.prototype.parseKeyDescriptor = function(keyDescriptor) {
|
|||||||
info.keyCode = this.namedKeys[s];
|
info.keyCode = this.namedKeys[s];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(options.keyDescriptor) {
|
||||||
|
info.keyDescriptor = options.keyDescriptor;
|
||||||
|
}
|
||||||
if(info.keyCode) {
|
if(info.keyCode) {
|
||||||
return info;
|
return info;
|
||||||
} else {
|
} else {
|
||||||
@ -237,6 +240,7 @@ KeyboardManager.prototype.parseKeyDescriptors = function(keyDescriptors,options)
|
|||||||
lookupName = function(configName) {
|
lookupName = function(configName) {
|
||||||
var keyDescriptors = wiki.getTiddlerText("$:/config/" + configName + "/" + name);
|
var keyDescriptors = wiki.getTiddlerText("$:/config/" + configName + "/" + name);
|
||||||
if(keyDescriptors) {
|
if(keyDescriptors) {
|
||||||
|
options.keyDescriptor = keyDescriptor;
|
||||||
result.push.apply(result,self.parseKeyDescriptors(keyDescriptors,options));
|
result.push.apply(result,self.parseKeyDescriptors(keyDescriptors,options));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -245,7 +249,7 @@ KeyboardManager.prototype.parseKeyDescriptors = function(keyDescriptors,options)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result.push(self.parseKeyDescriptor(keyDescriptor));
|
result.push(self.parseKeyDescriptor(keyDescriptor,options));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
@ -276,12 +280,16 @@ KeyboardManager.prototype.checkKeyDescriptor = function(event,keyInfo) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
KeyboardManager.prototype.checkKeyDescriptors = function(event,keyInfoArray) {
|
KeyboardManager.prototype.checkKeyDescriptors = function(event,keyInfoArray) {
|
||||||
|
return (this.getMatchingKeyDescriptor(event,keyInfoArray) !== null);
|
||||||
|
};
|
||||||
|
|
||||||
|
KeyboardManager.prototype.getMatchingKeyDescriptor = function(event,keyInfoArray) {
|
||||||
for(var t=0; t<keyInfoArray.length; t++) {
|
for(var t=0; t<keyInfoArray.length; t++) {
|
||||||
if(this.checkKeyDescriptor(event,keyInfoArray[t])) {
|
if(this.checkKeyDescriptor(event,keyInfoArray[t])) {
|
||||||
return true;
|
return keyInfoArray[t];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
KeyboardManager.prototype.getEventModifierKeyDescriptor = function(event) {
|
KeyboardManager.prototype.getEventModifierKeyDescriptor = function(event) {
|
||||||
@ -295,7 +303,7 @@ KeyboardManager.prototype.getEventModifierKeyDescriptor = function(event) {
|
|||||||
event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey ? "meta" :
|
event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey ? "meta" :
|
||||||
event.metaKey && event.ctrlKey && !event.shiftKey && !event.altKey ? "meta-ctrl" :
|
event.metaKey && event.ctrlKey && !event.shiftKey && !event.altKey ? "meta-ctrl" :
|
||||||
event.metaKey && event.ctrlKey && event.shiftKey && !event.altKey ? "meta-ctrl-shift" :
|
event.metaKey && event.ctrlKey && event.shiftKey && !event.altKey ? "meta-ctrl-shift" :
|
||||||
event.metaKey && event.ctrlKey & event.shiftKey && event.altKey ? "meta-ctrl-alt-shift" : "normal";
|
event.metaKey && event.ctrlKey && event.shiftKey && event.altKey ? "meta-ctrl-alt-shift" : "normal";
|
||||||
};
|
};
|
||||||
|
|
||||||
KeyboardManager.prototype.getShortcutTiddlerList = function() {
|
KeyboardManager.prototype.getShortcutTiddlerList = function() {
|
||||||
@ -324,7 +332,7 @@ KeyboardManager.prototype.handleKeydownEvent = function(event) {
|
|||||||
if(key !== undefined) {
|
if(key !== undefined) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
$tw.rootWidget.invokeActionString(action,$tw.rootWidget);
|
$tw.rootWidget.invokeActionString(action,$tw.rootWidget,event);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
title: $:/core/modules/macros/unusedtitle.js
|
title: $:/core/modules/macros/unusedtitle.js
|
||||||
type: application/javascript
|
type: application/javascript
|
||||||
module-type: macro
|
module-type: macro
|
||||||
|
|
||||||
Macro to return a new title that is unused in the wiki. It can be given a name as a base.
|
Macro to return a new title that is unused in the wiki. It can be given a name as a base.
|
||||||
\*/
|
\*/
|
||||||
(function(){
|
(function(){
|
||||||
@ -10,25 +11,25 @@ Macro to return a new title that is unused in the wiki. It can be given a name a
|
|||||||
/*global $tw: false */
|
/*global $tw: false */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
/*
|
|
||||||
Information about this macro
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.name = "unusedtitle";
|
exports.name = "unusedtitle";
|
||||||
|
|
||||||
exports.params = [
|
exports.params = [
|
||||||
{name: "baseName"},
|
{name: "baseName"},
|
||||||
{name: "options"}
|
{name: "separator"},
|
||||||
|
{name: "template"}
|
||||||
];
|
];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Run the macro
|
Run the macro
|
||||||
*/
|
*/
|
||||||
exports.run = function(baseName, options) {
|
exports.run = function(baseName,separator,template) {
|
||||||
|
separator = separator || " ";
|
||||||
if(!baseName) {
|
if(!baseName) {
|
||||||
baseName = $tw.language.getString("DefaultNewTiddlerTitle");
|
baseName = $tw.language.getString("DefaultNewTiddlerTitle");
|
||||||
}
|
}
|
||||||
return this.wiki.generateNewTitle(baseName, options);
|
// $tw.wiki.generateNewTitle = function(baseTitle,options)
|
||||||
|
// options.prefix must be a string!
|
||||||
|
return this.wiki.generateNewTitle(baseName, {"prefix": separator, "template": template});
|
||||||
};
|
};
|
||||||
|
|
||||||
})();
|
})();
|
@ -23,10 +23,12 @@ var HtmlParser = function(type,text,options) {
|
|||||||
type: "element",
|
type: "element",
|
||||||
tag: "iframe",
|
tag: "iframe",
|
||||||
attributes: {
|
attributes: {
|
||||||
src: {type: "string", value: src},
|
src: {type: "string", value: src}
|
||||||
sandbox: {type: "string", value: ""}
|
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
if($tw.wiki.getTiddlerText("$:/config/HtmlParser/DisableSandbox","no") !== "yes") {
|
||||||
|
this.tree[0].attributes.sandbox = {type: "string", value: $tw.wiki.getTiddlerText("$:/config/HtmlParser/SandboxTokens","")};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exports["text/html"] = HtmlParser;
|
exports["text/html"] = HtmlParser;
|
||||||
|
@ -123,6 +123,19 @@ exports.parseStringLiteral = function(source,pos) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.parseMacroParameters = function(node,source,pos) {
|
||||||
|
// Process parameters
|
||||||
|
var parameter = $tw.utils.parseMacroParameter(source,pos);
|
||||||
|
while(parameter) {
|
||||||
|
node.params.push(parameter);
|
||||||
|
pos = parameter.end;
|
||||||
|
// Get the next parameter
|
||||||
|
parameter = $tw.utils.parseMacroParameter(source,pos);
|
||||||
|
}
|
||||||
|
node.end = pos;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Look for a macro invocation parameter. Returns null if not found, or {type: "macro-parameter", name:, value:, start:, end:}
|
Look for a macro invocation parameter. Returns null if not found, or {type: "macro-parameter", name:, value:, start:, end:}
|
||||||
*/
|
*/
|
||||||
@ -187,14 +200,8 @@ exports.parseMacroInvocation = function(source,pos) {
|
|||||||
}
|
}
|
||||||
node.name = name.match[1];
|
node.name = name.match[1];
|
||||||
pos = name.end;
|
pos = name.end;
|
||||||
// Process parameters
|
node = $tw.utils.parseMacroParameters(node,source,pos);
|
||||||
var parameter = $tw.utils.parseMacroParameter(source,pos);
|
pos = node.end;
|
||||||
while(parameter) {
|
|
||||||
node.params.push(parameter);
|
|
||||||
pos = parameter.end;
|
|
||||||
// Get the next parameter
|
|
||||||
parameter = $tw.utils.parseMacroParameter(source,pos);
|
|
||||||
}
|
|
||||||
// Skip whitespace
|
// Skip whitespace
|
||||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||||
// Look for a double greater than sign
|
// Look for a double greater than sign
|
||||||
@ -208,6 +215,29 @@ exports.parseMacroInvocation = function(source,pos) {
|
|||||||
return node;
|
return node;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.parseFilterVariable = function(source) {
|
||||||
|
var node = {
|
||||||
|
name: "",
|
||||||
|
params: [],
|
||||||
|
},
|
||||||
|
pos = 0,
|
||||||
|
reName = /([^\s"']+)/g;
|
||||||
|
// If there is no whitespace or it is an empty string then there are no macro parameters
|
||||||
|
if(/^\S*$/.test(source)) {
|
||||||
|
node.name = source;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
// Get the variable name
|
||||||
|
var nameMatch = $tw.utils.parseTokenRegExp(source,pos,reName);
|
||||||
|
if(nameMatch) {
|
||||||
|
node.name = nameMatch.match[1];
|
||||||
|
pos = nameMatch.end;
|
||||||
|
node = $tw.utils.parseMacroParameters(node,source,pos);
|
||||||
|
delete node.end;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Look for an HTML attribute definition. Returns null if not found, otherwise returns {type: "attribute", name:, valueType: "string|indirect|macro", value:, start:, end:,}
|
Look for an HTML attribute definition. Returns null if not found, otherwise returns {type: "attribute", name:, valueType: "string|indirect|macro", value:, start:, end:,}
|
||||||
*/
|
*/
|
||||||
|
@ -7,6 +7,12 @@ Wiki text block rule for HTML comments. For example:
|
|||||||
|
|
||||||
```
|
```
|
||||||
<!-- This is a comment -->
|
<!-- This is a comment -->
|
||||||
|
\define macroX()
|
||||||
|
<!-- This is a comment -->
|
||||||
|
xxxx
|
||||||
|
\end
|
||||||
|
<!-- This is a comment -->
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that the syntax for comments is simplified to an opening "<!--" sequence and a closing "-->" sequence -- HTML itself implements a more complex format (see http://ostermiller.org/findhtmlcomment.html)
|
Note that the syntax for comments is simplified to an opening "<!--" sequence and a closing "-->" sequence -- HTML itself implements a more complex format (see http://ostermiller.org/findhtmlcomment.html)
|
||||||
@ -19,7 +25,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};
|
exports.types = {block:true, pragma:true};
|
||||||
|
|
||||||
exports.init = function(parser) {
|
exports.init = function(parser) {
|
||||||
this.parser = parser;
|
this.parser = parser;
|
||||||
|
@ -66,7 +66,7 @@ exports.parse = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Look for an HTML tag. Returns null if not found, otherwise returns {type: "element", name:, attributes: [], isSelfClosing:, start:, end:,}
|
Look for an HTML tag. Returns null if not found, otherwise returns {type: "element", name:, attributes: {}, orderedAttributes: [], isSelfClosing:, start:, end:,}
|
||||||
*/
|
*/
|
||||||
exports.parseTag = function(source,pos,options) {
|
exports.parseTag = function(source,pos,options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
@ -74,7 +74,8 @@ exports.parseTag = function(source,pos,options) {
|
|||||||
node = {
|
node = {
|
||||||
type: "element",
|
type: "element",
|
||||||
start: pos,
|
start: pos,
|
||||||
attributes: {}
|
attributes: {},
|
||||||
|
orderedAttributes: []
|
||||||
};
|
};
|
||||||
// Define our regexps
|
// Define our regexps
|
||||||
var reTagName = /([a-zA-Z0-9\-\$]+)/g;
|
var reTagName = /([a-zA-Z0-9\-\$]+)/g;
|
||||||
@ -106,6 +107,7 @@ exports.parseTag = function(source,pos,options) {
|
|||||||
// Process attributes
|
// Process attributes
|
||||||
var attribute = $tw.utils.parseAttribute(source,pos);
|
var attribute = $tw.utils.parseAttribute(source,pos);
|
||||||
while(attribute) {
|
while(attribute) {
|
||||||
|
node.orderedAttributes.push(attribute);
|
||||||
node.attributes[attribute.name] = attribute;
|
node.attributes[attribute.name] = attribute;
|
||||||
pos = attribute.end;
|
pos = attribute.end;
|
||||||
// Get the next attribute
|
// Get the next attribute
|
||||||
|
@ -36,7 +36,7 @@ exports.parse = function() {
|
|||||||
// Move past the pragma invocation
|
// Move past the pragma invocation
|
||||||
this.parser.pos = this.matchRegExp.lastIndex;
|
this.parser.pos = this.matchRegExp.lastIndex;
|
||||||
// Parse the filter terminated by a line break
|
// Parse the filter terminated by a line break
|
||||||
var reMatch = /(.*)(\r?\n)|$/mg;
|
var reMatch = /(.*)(?:$|\r?\n)/mg;
|
||||||
reMatch.lastIndex = this.parser.pos;
|
reMatch.lastIndex = this.parser.pos;
|
||||||
var match = reMatch.exec(this.parser.source);
|
var match = reMatch.exec(this.parser.source);
|
||||||
this.parser.pos = reMatch.lastIndex;
|
this.parser.pos = reMatch.lastIndex;
|
||||||
|
@ -231,7 +231,10 @@ WikiParser.prototype.parseBlock = function(terminatorRegExpString) {
|
|||||||
return nextMatch.rule.parse();
|
return nextMatch.rule.parse();
|
||||||
}
|
}
|
||||||
// Treat it as a paragraph if we didn't find a block rule
|
// Treat it as a paragraph if we didn't find a block rule
|
||||||
return [{type: "element", tag: "p", children: this.parseInlineRun(terminatorRegExp)}];
|
var start = this.pos;
|
||||||
|
var children = this.parseInlineRun(terminatorRegExp);
|
||||||
|
var end = this.pos;
|
||||||
|
return [{type: "element", tag: "p", children: children, start: start, end: end }];
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -307,7 +310,7 @@ WikiParser.prototype.parseInlineRunUnterminated = function(options) {
|
|||||||
while(this.pos < this.sourceLength && nextMatch) {
|
while(this.pos < this.sourceLength && nextMatch) {
|
||||||
// Process the text preceding the run rule
|
// Process the text preceding the run rule
|
||||||
if(nextMatch.matchIndex > this.pos) {
|
if(nextMatch.matchIndex > this.pos) {
|
||||||
this.pushTextWidget(tree,this.source.substring(this.pos,nextMatch.matchIndex));
|
this.pushTextWidget(tree,this.source.substring(this.pos,nextMatch.matchIndex),this.pos,nextMatch.matchIndex);
|
||||||
this.pos = nextMatch.matchIndex;
|
this.pos = nextMatch.matchIndex;
|
||||||
}
|
}
|
||||||
// Process the run rule
|
// Process the run rule
|
||||||
@ -317,7 +320,7 @@ WikiParser.prototype.parseInlineRunUnterminated = function(options) {
|
|||||||
}
|
}
|
||||||
// Process the remaining text
|
// Process the remaining text
|
||||||
if(this.pos < this.sourceLength) {
|
if(this.pos < this.sourceLength) {
|
||||||
this.pushTextWidget(tree,this.source.substr(this.pos));
|
this.pushTextWidget(tree,this.source.substr(this.pos),this.pos,this.sourceLength);
|
||||||
}
|
}
|
||||||
this.pos = this.sourceLength;
|
this.pos = this.sourceLength;
|
||||||
return tree;
|
return tree;
|
||||||
@ -337,7 +340,7 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
|
|||||||
if(terminatorMatch) {
|
if(terminatorMatch) {
|
||||||
if(!inlineRuleMatch || inlineRuleMatch.matchIndex >= terminatorMatch.index) {
|
if(!inlineRuleMatch || inlineRuleMatch.matchIndex >= terminatorMatch.index) {
|
||||||
if(terminatorMatch.index > this.pos) {
|
if(terminatorMatch.index > this.pos) {
|
||||||
this.pushTextWidget(tree,this.source.substring(this.pos,terminatorMatch.index));
|
this.pushTextWidget(tree,this.source.substring(this.pos,terminatorMatch.index),this.pos,terminatorMatch.index);
|
||||||
}
|
}
|
||||||
this.pos = terminatorMatch.index;
|
this.pos = terminatorMatch.index;
|
||||||
if(options.eatTerminator) {
|
if(options.eatTerminator) {
|
||||||
@ -350,7 +353,7 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
|
|||||||
if(inlineRuleMatch) {
|
if(inlineRuleMatch) {
|
||||||
// Preceding text
|
// Preceding text
|
||||||
if(inlineRuleMatch.matchIndex > this.pos) {
|
if(inlineRuleMatch.matchIndex > this.pos) {
|
||||||
this.pushTextWidget(tree,this.source.substring(this.pos,inlineRuleMatch.matchIndex));
|
this.pushTextWidget(tree,this.source.substring(this.pos,inlineRuleMatch.matchIndex),this.pos,inlineRuleMatch.matchIndex);
|
||||||
this.pos = inlineRuleMatch.matchIndex;
|
this.pos = inlineRuleMatch.matchIndex;
|
||||||
}
|
}
|
||||||
// Process the inline rule
|
// Process the inline rule
|
||||||
@ -364,7 +367,7 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
|
|||||||
}
|
}
|
||||||
// Process the remaining text
|
// Process the remaining text
|
||||||
if(this.pos < this.sourceLength) {
|
if(this.pos < this.sourceLength) {
|
||||||
this.pushTextWidget(tree,this.source.substr(this.pos));
|
this.pushTextWidget(tree,this.source.substr(this.pos),this.pos,this.sourceLength);
|
||||||
}
|
}
|
||||||
this.pos = this.sourceLength;
|
this.pos = this.sourceLength;
|
||||||
return tree;
|
return tree;
|
||||||
@ -373,12 +376,12 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
|
|||||||
/*
|
/*
|
||||||
Push a text widget onto an array, respecting the configTrimWhiteSpace setting
|
Push a text widget onto an array, respecting the configTrimWhiteSpace setting
|
||||||
*/
|
*/
|
||||||
WikiParser.prototype.pushTextWidget = function(array,text) {
|
WikiParser.prototype.pushTextWidget = function(array,text,start,end) {
|
||||||
if(this.configTrimWhiteSpace) {
|
if(this.configTrimWhiteSpace) {
|
||||||
text = $tw.utils.trim(text);
|
text = $tw.utils.trim(text);
|
||||||
}
|
}
|
||||||
if(text) {
|
if(text) {
|
||||||
array.push({type: "text", text: text});
|
array.push({type: "text", text: text, start: start, end: end});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -157,7 +157,8 @@ SaverHandler.prototype.saveWiki = function(options) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var variables = options.variables || {},
|
var variables = options.variables || {},
|
||||||
template = options.template || "$:/core/save/all",
|
template = (options.template ||
|
||||||
|
this.wiki.getTiddlerText("$:/config/SaveWikiButton/Template","$:/core/save/all")).trim(),
|
||||||
downloadType = options.downloadType || "text/plain",
|
downloadType = options.downloadType || "text/plain",
|
||||||
text = this.wiki.renderTiddler(downloadType,template,options),
|
text = this.wiki.renderTiddler(downloadType,template,options),
|
||||||
callback = function(err) {
|
callback = function(err) {
|
||||||
|
@ -42,7 +42,7 @@ AndTidWiki.prototype.save = function(text,method,callback,options) {
|
|||||||
window.twi.saveWiki(text);
|
window.twi.saveWiki(text);
|
||||||
} else {
|
} else {
|
||||||
// Get the pathname of this document
|
// Get the pathname of this document
|
||||||
var pathname = decodeURIComponent(document.location.toString().split("#")[0]);
|
var pathname = $tw.utils.decodeURIComponentSafe(document.location.toString().split("#")[0]);
|
||||||
// Strip the file://
|
// Strip the file://
|
||||||
if(pathname.indexOf("file://") === 0) {
|
if(pathname.indexOf("file://") === 0) {
|
||||||
pathname = pathname.substr(7);
|
pathname = pathname.substr(7);
|
||||||
|
@ -26,7 +26,7 @@ DownloadSaver.prototype.save = function(text,method,callback,options) {
|
|||||||
var p = document.location.pathname.lastIndexOf("/");
|
var p = document.location.pathname.lastIndexOf("/");
|
||||||
if(p !== -1) {
|
if(p !== -1) {
|
||||||
// We decode the pathname because document.location is URL encoded by the browser
|
// We decode the pathname because document.location is URL encoded by the browser
|
||||||
filename = decodeURIComponent(document.location.pathname.substr(p+1));
|
filename = $tw.utils.decodeURIComponentSafe(document.location.pathname.substr(p+1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!filename) {
|
if(!filename) {
|
||||||
|
@ -72,7 +72,7 @@ GiteaSaver.prototype.save = function(text,method,callback) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var data = {
|
var data = {
|
||||||
message: $tw.language.getRawString("ControlPanel/Saving/GitService/CommitMessage"),
|
message: $tw.language.getString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||||
content: $tw.utils.base64Encode(text),
|
content: $tw.utils.base64Encode(text),
|
||||||
sha: sha
|
sha: sha
|
||||||
};
|
};
|
||||||
|
@ -69,7 +69,7 @@ GitHubSaver.prototype.save = function(text,method,callback) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
var data = {
|
var data = {
|
||||||
message: $tw.language.getRawString("ControlPanel/Saving/GitService/CommitMessage"),
|
message: $tw.language.getString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||||
content: $tw.utils.base64Encode(text),
|
content: $tw.utils.base64Encode(text),
|
||||||
branch: branch,
|
branch: branch,
|
||||||
sha: sha
|
sha: sha
|
||||||
|
@ -67,7 +67,7 @@ GitLabSaver.prototype.save = function(text,method,callback) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
var data = {
|
var data = {
|
||||||
commit_message: $tw.language.getRawString("ControlPanel/Saving/GitService/CommitMessage"),
|
commit_message: $tw.language.getString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||||
content: text,
|
content: text,
|
||||||
branch: branch,
|
branch: branch,
|
||||||
sha: sha
|
sha: sha
|
||||||
|
@ -89,9 +89,12 @@ PutSaver.prototype.save = function(text,method,callback) {
|
|||||||
if(err) {
|
if(err) {
|
||||||
// response is textual: "XMLHttpRequest error code: 412"
|
// response is textual: "XMLHttpRequest error code: 412"
|
||||||
var status = Number(err.substring(err.indexOf(':') + 2, err.length))
|
var status = Number(err.substring(err.indexOf(':') + 2, err.length))
|
||||||
if(status === 412) { // edit conflict
|
if(status === 412) { // file changed on server
|
||||||
var message = $tw.language.getString("Error/EditConflict");
|
callback($tw.language.getString("Error/PutEditConflict"));
|
||||||
callback(message);
|
} else if(status === 401) { // authentication required
|
||||||
|
callback($tw.language.getString("Error/PutUnauthorized"));
|
||||||
|
} else if(status === 403) { // permission denied
|
||||||
|
callback($tw.language.getString("Error/PutForbidden"));
|
||||||
} else {
|
} else {
|
||||||
callback(err); // fail
|
callback(err); // fail
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ TiddlyFoxSaver.prototype.save = function(text,method,callback) {
|
|||||||
}
|
}
|
||||||
// Create the message element and put it in the message box
|
// Create the message element and put it in the message box
|
||||||
var message = document.createElement("div");
|
var message = document.createElement("div");
|
||||||
message.setAttribute("data-tiddlyfox-path",decodeURIComponent(pathname));
|
message.setAttribute("data-tiddlyfox-path",$tw.utils.decodeURIComponentSafe(pathname));
|
||||||
message.setAttribute("data-tiddlyfox-content",text);
|
message.setAttribute("data-tiddlyfox-content",text);
|
||||||
messageBox.appendChild(message);
|
messageBox.appendChild(message);
|
||||||
// Add an event handler for when the file has been saved
|
// Add an event handler for when the file has been saved
|
||||||
|
@ -21,7 +21,7 @@ TWEditSaver.prototype.save = function(text,method,callback) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Get the pathname of this document
|
// Get the pathname of this document
|
||||||
var pathname = decodeURIComponent(document.location.pathname);
|
var pathname = $tw.utils.decodeURIComponentSafe(document.location.pathname);
|
||||||
// Strip any query or location part
|
// Strip any query or location part
|
||||||
var p = pathname.indexOf("?");
|
var p = pathname.indexOf("?");
|
||||||
if(p !== -1) {
|
if(p !== -1) {
|
||||||
|
@ -17,7 +17,7 @@ exports.method = "DELETE";
|
|||||||
exports.path = /^\/bags\/default\/tiddlers\/(.+)$/;
|
exports.path = /^\/bags\/default\/tiddlers\/(.+)$/;
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var title = decodeURIComponent(state.params[0]);
|
var title = $tw.utils.decodeURIComponentSafe(state.params[0]);
|
||||||
state.wiki.deleteTiddler(title);
|
state.wiki.deleteTiddler(title);
|
||||||
response.writeHead(204, "OK", {
|
response.writeHead(204, "OK", {
|
||||||
"Content-Type": "text/plain"
|
"Content-Type": "text/plain"
|
||||||
|
@ -17,9 +17,8 @@ exports.method = "GET";
|
|||||||
exports.path = /^\/favicon.ico$/;
|
exports.path = /^\/favicon.ico$/;
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
response.writeHead(200, {"Content-Type": "image/x-icon"});
|
|
||||||
var buffer = state.wiki.getTiddlerText("$:/favicon.ico","");
|
var buffer = state.wiki.getTiddlerText("$:/favicon.ico","");
|
||||||
response.end(buffer,"base64");
|
state.sendResponse(200,{"Content-Type": "image/x-icon"},buffer,"base64");
|
||||||
};
|
};
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
@ -20,9 +20,13 @@ exports.handler = function(request,response,state) {
|
|||||||
var path = require("path"),
|
var path = require("path"),
|
||||||
fs = require("fs"),
|
fs = require("fs"),
|
||||||
util = require("util"),
|
util = require("util"),
|
||||||
suppliedFilename = decodeURIComponent(state.params[0]),
|
suppliedFilename = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||||
filename = path.resolve(state.boot.wikiPath,"files",suppliedFilename),
|
baseFilename = path.resolve(state.boot.wikiPath,"files"),
|
||||||
|
filename = path.resolve(baseFilename,suppliedFilename),
|
||||||
extension = path.extname(filename);
|
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) {
|
fs.readFile(filename,function(err,content) {
|
||||||
var status,content,type = "text/plain";
|
var status,content,type = "text/plain";
|
||||||
if(err) {
|
if(err) {
|
||||||
@ -34,11 +38,11 @@ exports.handler = function(request,response,state) {
|
|||||||
content = content;
|
content = content;
|
||||||
type = ($tw.config.fileExtensionInfo[extension] ? $tw.config.fileExtensionInfo[extension].type : "application/octet-stream");
|
type = ($tw.config.fileExtensionInfo[extension] ? $tw.config.fileExtensionInfo[extension].type : "application/octet-stream");
|
||||||
}
|
}
|
||||||
response.writeHead(status,{
|
state.sendResponse(status,{"Content-Type": type},content);
|
||||||
"Content-Type": type
|
|
||||||
});
|
|
||||||
response.end(content);
|
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
state.sendResponse(404,{"Content-Type": "text/plain"},"File '" + suppliedFilename + "' not found");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
@ -12,38 +12,16 @@ GET /
|
|||||||
/*global $tw: false */
|
/*global $tw: false */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var zlib = require("zlib");
|
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.method = "GET";
|
||||||
|
|
||||||
exports.path = /^\/$/;
|
exports.path = /^\/$/;
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var acceptEncoding = request.headers["accept-encoding"];
|
|
||||||
if(!acceptEncoding) {
|
|
||||||
acceptEncoding = "";
|
|
||||||
}
|
|
||||||
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 = {
|
||||||
"Content-Type": state.server.get("root-serve-type")
|
"Content-Type": state.server.get("root-serve-type")
|
||||||
};
|
};
|
||||||
/*
|
state.sendResponse(200,responseHeaders,text);
|
||||||
If the gzip=yes flag for `listen` is set, check if the user agent permits
|
|
||||||
compression. If so, compress our response. Note that we use the synchronous
|
|
||||||
functions from zlib to stay in the imperative style. The current `Server`
|
|
||||||
doesn't depend on this, and we may just as well use the async versions.
|
|
||||||
*/
|
|
||||||
if(state.server.enableGzip) {
|
|
||||||
if (/\bdeflate\b/.test(acceptEncoding)) {
|
|
||||||
responseHeaders["Content-Encoding"] = "deflate";
|
|
||||||
text = zlib.deflateSync(text);
|
|
||||||
} else if (/\bgzip\b/.test(acceptEncoding)) {
|
|
||||||
responseHeaders["Content-Encoding"] = "gzip";
|
|
||||||
text = zlib.gzipSync(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response.writeHead(200,responseHeaders);
|
|
||||||
response.end(text);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
@ -17,18 +17,16 @@ exports.method = "GET";
|
|||||||
exports.path = /^\/status$/;
|
exports.path = /^\/status$/;
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
response.writeHead(200, {"Content-Type": "application/json"});
|
|
||||||
var text = JSON.stringify({
|
var text = JSON.stringify({
|
||||||
username: state.authenticatedUsername || state.server.get("anon-username") || "",
|
username: state.authenticatedUsername || state.server.get("anon-username") || "",
|
||||||
anonymous: !state.authenticatedUsername,
|
anonymous: !state.authenticatedUsername,
|
||||||
read_only: !state.server.isAuthorized("writers",state.authenticatedUsername),
|
read_only: !state.server.isAuthorized("writers",state.authenticatedUsername),
|
||||||
sse_enabled: state.server.get("sse-enabled") === "yes",
|
|
||||||
space: {
|
space: {
|
||||||
recipe: "default"
|
recipe: "default"
|
||||||
},
|
},
|
||||||
tiddlywiki_version: $tw.version
|
tiddlywiki_version: $tw.version
|
||||||
});
|
});
|
||||||
response.end(text,"utf8");
|
state.sendResponse(200,{"Content-Type": "application/json"},text,"utf8");
|
||||||
};
|
};
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
@ -17,7 +17,7 @@ exports.method = "GET";
|
|||||||
exports.path = /^\/([^\/]+)$/;
|
exports.path = /^\/([^\/]+)$/;
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var title = decodeURIComponent(state.params[0]),
|
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||||
tiddler = state.wiki.getTiddler(title);
|
tiddler = state.wiki.getTiddler(title);
|
||||||
if(tiddler) {
|
if(tiddler) {
|
||||||
var renderType = tiddler.getFieldString("_render_type"),
|
var renderType = tiddler.getFieldString("_render_type"),
|
||||||
@ -32,9 +32,9 @@ exports.handler = function(request,response,state) {
|
|||||||
renderTemplate = renderTemplate || state.server.get("tiddler-render-template");
|
renderTemplate = renderTemplate || state.server.get("tiddler-render-template");
|
||||||
}
|
}
|
||||||
var text = state.wiki.renderTiddler(renderType,renderTemplate,{parseAsInline: true, variables: {currentTiddler: title}});
|
var text = state.wiki.renderTiddler(renderType,renderTemplate,{parseAsInline: true, variables: {currentTiddler: title}});
|
||||||
|
|
||||||
// Naughty not to set a content-type, but it's the easiest way to ensure the browser will see HTML pages as HTML, and accept plain text tiddlers as CSS or JS
|
// Naughty not to set a content-type, but it's the easiest way to ensure the browser will see HTML pages as HTML, and accept plain text tiddlers as CSS or JS
|
||||||
response.writeHead(200);
|
state.sendResponse(200,{},text,"utf8");
|
||||||
response.end(text,"utf8");
|
|
||||||
} else {
|
} else {
|
||||||
response.writeHead(404);
|
response.writeHead(404);
|
||||||
response.end();
|
response.end();
|
||||||
|
@ -17,7 +17,7 @@ exports.method = "GET";
|
|||||||
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var title = decodeURIComponent(state.params[0]),
|
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||||
tiddler = state.wiki.getTiddler(title),
|
tiddler = state.wiki.getTiddler(title),
|
||||||
tiddlerFields = {},
|
tiddlerFields = {},
|
||||||
knownFields = [
|
knownFields = [
|
||||||
@ -36,8 +36,7 @@ exports.handler = function(request,response,state) {
|
|||||||
tiddlerFields.revision = state.wiki.getChangeCount(title);
|
tiddlerFields.revision = state.wiki.getChangeCount(title);
|
||||||
tiddlerFields.bag = "default";
|
tiddlerFields.bag = "default";
|
||||||
tiddlerFields.type = tiddlerFields.type || "text/vnd.tiddlywiki";
|
tiddlerFields.type = tiddlerFields.type || "text/vnd.tiddlywiki";
|
||||||
response.writeHead(200, {"Content-Type": "application/json"});
|
state.sendResponse(200,{"Content-Type": "application/json"},JSON.stringify(tiddlerFields),"utf8");
|
||||||
response.end(JSON.stringify(tiddlerFields),"utf8");
|
|
||||||
} else {
|
} else {
|
||||||
response.writeHead(404);
|
response.writeHead(404);
|
||||||
response.end();
|
response.end();
|
||||||
|
@ -33,7 +33,6 @@ exports.handler = function(request,response,state) {
|
|||||||
}
|
}
|
||||||
var excludeFields = (state.queryParameters.exclude || "text").split(","),
|
var excludeFields = (state.queryParameters.exclude || "text").split(","),
|
||||||
titles = state.wiki.filterTiddlers(filter);
|
titles = state.wiki.filterTiddlers(filter);
|
||||||
response.writeHead(200, {"Content-Type": "application/json"});
|
|
||||||
var tiddlers = [];
|
var tiddlers = [];
|
||||||
$tw.utils.each(titles,function(title) {
|
$tw.utils.each(titles,function(title) {
|
||||||
var tiddler = state.wiki.getTiddler(title);
|
var tiddler = state.wiki.getTiddler(title);
|
||||||
@ -45,7 +44,7 @@ exports.handler = function(request,response,state) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
var text = JSON.stringify(tiddlers);
|
var text = JSON.stringify(tiddlers);
|
||||||
response.end(text,"utf8");
|
state.sendResponse(200,{"Content-Type": "application/json"},text,"utf8");
|
||||||
};
|
};
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
@ -17,7 +17,7 @@ exports.method = "PUT";
|
|||||||
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var title = decodeURIComponent(state.params[0]),
|
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||||
fields = JSON.parse(state.data);
|
fields = JSON.parse(state.data);
|
||||||
// Pull up any subfields in the `fields` object
|
// Pull up any subfields in the `fields` object
|
||||||
if(fields.fields) {
|
if(fields.fields) {
|
||||||
@ -30,7 +30,7 @@ exports.handler = function(request,response,state) {
|
|||||||
if(fields.revision) {
|
if(fields.revision) {
|
||||||
delete fields.revision;
|
delete fields.revision;
|
||||||
}
|
}
|
||||||
state.wiki.addTiddler(new $tw.Tiddler(state.wiki.getCreationFields(),fields,{title: title},state.wiki.getModificationFields()));
|
state.wiki.addTiddler(new $tw.Tiddler(fields,{title: title}));
|
||||||
var changeCount = state.wiki.getChangeCount(title).toString();
|
var changeCount = state.wiki.getChangeCount(title).toString();
|
||||||
response.writeHead(204, "OK",{
|
response.writeHead(204, "OK",{
|
||||||
Etag: "\"default/" + encodeURIComponent(title) + "/" + changeCount + ":\"",
|
Etag: "\"default/" + encodeURIComponent(title) + "/" + changeCount + ":\"",
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
/*\
|
|
||||||
title: $:/core/modules/server/server-sent-events.js
|
|
||||||
type: application/javascript
|
|
||||||
module-type: library
|
|
||||||
\*/
|
|
||||||
(function(){
|
|
||||||
|
|
||||||
/*jslint node: true, browser: true */
|
|
||||||
/*global $tw: false */
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
/*
|
|
||||||
parameters:
|
|
||||||
prefix - usually the plugin path, such as `plugins/tiddlywiki/tiddlyweb`. The
|
|
||||||
route will match `/events/${prefix}` exactly.
|
|
||||||
|
|
||||||
handler - a function that will be called each time a request comes in with the
|
|
||||||
request and state from the route and an emit function to call.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var ServerSentEvents = function ServerSentEvents(prefix, handler) {
|
|
||||||
this.handler = handler;
|
|
||||||
this.prefix = prefix;
|
|
||||||
};
|
|
||||||
|
|
||||||
ServerSentEvents.prototype.getExports = function() {
|
|
||||||
return {
|
|
||||||
bodyFormat: "stream",
|
|
||||||
method: "GET",
|
|
||||||
path: new RegExp("^/events/" + this.prefix + "$"),
|
|
||||||
handler: this.handleEventRequest.bind(this)
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
ServerSentEvents.prototype.handleEventRequest = function(request,response,state) {
|
|
||||||
if(ServerSentEvents.prototype.isEventStreamRequest(request)) {
|
|
||||||
response.writeHead(200, {
|
|
||||||
"Content-Type": "text/event-stream",
|
|
||||||
"Cache-Control": "no-cache",
|
|
||||||
"Connection": "keep-alive"
|
|
||||||
});
|
|
||||||
this.handler(request,state,this.emit.bind(this,response),this.end.bind(this,response));
|
|
||||||
} else {
|
|
||||||
response.writeHead(406,"Not Acceptable",{});
|
|
||||||
response.end();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ServerSentEvents.prototype.isEventStreamRequest = function(request) {
|
|
||||||
return request.headers.accept &&
|
|
||||||
request.headers.accept.match(/^text\/event-stream/);
|
|
||||||
};
|
|
||||||
|
|
||||||
ServerSentEvents.prototype.emit = function(response,event,data) {
|
|
||||||
if(typeof event !== "string" || event.indexOf("\n") !== -1) {
|
|
||||||
throw new Error("Type must be a single-line string");
|
|
||||||
}
|
|
||||||
if(typeof data !== "string" || data.indexOf("\n") !== -1) {
|
|
||||||
throw new Error("Data must be a single-line string");
|
|
||||||
}
|
|
||||||
response.write("event: " + event + "\ndata: " + data + "\n\n", "utf8");
|
|
||||||
};
|
|
||||||
|
|
||||||
ServerSentEvents.prototype.end = function(response) {
|
|
||||||
response.end();
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.ServerSentEvents = ServerSentEvents;
|
|
||||||
|
|
||||||
})();
|
|
@ -17,7 +17,9 @@ if($tw.node) {
|
|||||||
fs = require("fs"),
|
fs = require("fs"),
|
||||||
url = require("url"),
|
url = require("url"),
|
||||||
path = require("path"),
|
path = require("path"),
|
||||||
querystring = require("querystring");
|
querystring = require("querystring"),
|
||||||
|
crypto = require("crypto"),
|
||||||
|
zlib = require("zlib");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -47,6 +49,8 @@ function Server(options) {
|
|||||||
this.csrfDisable = this.get("csrf-disable") === "yes";
|
this.csrfDisable = this.get("csrf-disable") === "yes";
|
||||||
// Initialize Gzip compression
|
// Initialize Gzip compression
|
||||||
this.enableGzip = this.get("gzip") === "yes";
|
this.enableGzip = this.get("gzip") === "yes";
|
||||||
|
// Initialize browser-caching
|
||||||
|
this.enableBrowserCache = this.get("use-browser-cache") === "yes";
|
||||||
// Initialise authorization
|
// Initialise authorization
|
||||||
var authorizedUserName = (this.get("username") && this.get("password")) ? this.get("username") : "(anon)";
|
var authorizedUserName = (this.get("username") && this.get("password")) ? this.get("username") : "(anon)";
|
||||||
this.authorizationPrincipals = {
|
this.authorizationPrincipals = {
|
||||||
@ -78,6 +82,71 @@ function Server(options) {
|
|||||||
this.transport = require(this.protocol);
|
this.transport = require(this.protocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Send a response to the client. This method checks if the response must be sent
|
||||||
|
or if the client alrady has the data cached. If that's the case only a 304
|
||||||
|
response will be transmitted and the browser will use the cached data.
|
||||||
|
Only requests with status code 200 are considdered for caching.
|
||||||
|
request: request instance passed to the handler
|
||||||
|
response: response instance passed to the handler
|
||||||
|
statusCode: stauts code to send to the browser
|
||||||
|
headers: response headers (they will be augmented with an `Etag` header)
|
||||||
|
data: the data to send (passed to the end method of the response instance)
|
||||||
|
encoding: the encoding of the data to send (passed to the end method of the response instance)
|
||||||
|
*/
|
||||||
|
function sendResponse(request,response,statusCode,headers,data,encoding) {
|
||||||
|
if(this.enableBrowserCache && (statusCode == 200)) {
|
||||||
|
var hash = crypto.createHash('md5');
|
||||||
|
// Put everything into the hash that could change and invalidate the data that
|
||||||
|
// the browser already stored. The headers the data and the encoding.
|
||||||
|
hash.update(data);
|
||||||
|
hash.update(JSON.stringify(headers));
|
||||||
|
if(encoding) {
|
||||||
|
hash.update(encoding);
|
||||||
|
}
|
||||||
|
var contentDigest = hash.digest("hex");
|
||||||
|
// RFC 7232 section 2.3 mandates for the etag to be enclosed in quotes
|
||||||
|
headers["Etag"] = '"' + contentDigest + '"';
|
||||||
|
headers["Cache-Control"] = "max-age=0, must-revalidate";
|
||||||
|
// Check if any of the hashes contained within the if-none-match header
|
||||||
|
// matches the current hash.
|
||||||
|
// If one matches, do not send the data but tell the browser to use the
|
||||||
|
// cached data.
|
||||||
|
// We do not implement "*" as it makes no sense here.
|
||||||
|
var ifNoneMatch = request.headers["if-none-match"];
|
||||||
|
if(ifNoneMatch) {
|
||||||
|
var matchParts = ifNoneMatch.split(",").map(function(etag) {
|
||||||
|
return etag.replace(/^[ "]+|[ "]+$/g, "");
|
||||||
|
});
|
||||||
|
if(matchParts.indexOf(contentDigest) != -1) {
|
||||||
|
response.writeHead(304,headers);
|
||||||
|
response.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
If the gzip=yes is set, check if the user agent permits compression. If so,
|
||||||
|
compress our response if the raw data is bigger than 2k. Compressing less
|
||||||
|
data is inefficient. Note that we use the synchronous functions from zlib
|
||||||
|
to stay in the imperative style. The current `Server` doesn't depend on
|
||||||
|
this, and we may just as well use the async versions.
|
||||||
|
*/
|
||||||
|
if(this.enableGzip && (data.length > 2048)) {
|
||||||
|
var acceptEncoding = request.headers["accept-encoding"] || "";
|
||||||
|
if(/\bdeflate\b/.test(acceptEncoding)) {
|
||||||
|
headers["Content-Encoding"] = "deflate";
|
||||||
|
data = zlib.deflateSync(data);
|
||||||
|
} else if(/\bgzip\b/.test(acceptEncoding)) {
|
||||||
|
headers["Content-Encoding"] = "gzip";
|
||||||
|
data = zlib.gzipSync(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response.writeHead(statusCode,headers);
|
||||||
|
response.end(data,encoding);
|
||||||
|
}
|
||||||
|
|
||||||
Server.prototype.defaultVariables = {
|
Server.prototype.defaultVariables = {
|
||||||
port: "8080",
|
port: "8080",
|
||||||
host: "127.0.0.1",
|
host: "127.0.0.1",
|
||||||
@ -89,7 +158,8 @@ Server.prototype.defaultVariables = {
|
|||||||
"system-tiddler-render-type": "text/plain",
|
"system-tiddler-render-type": "text/plain",
|
||||||
"system-tiddler-render-template": "$:/core/templates/wikified-tiddler",
|
"system-tiddler-render-template": "$:/core/templates/wikified-tiddler",
|
||||||
"debug-level": "none",
|
"debug-level": "none",
|
||||||
"gzip": "no"
|
"gzip": "no",
|
||||||
|
"use-browser-cache": "no"
|
||||||
};
|
};
|
||||||
|
|
||||||
Server.prototype.get = function(name) {
|
Server.prototype.get = function(name) {
|
||||||
@ -167,6 +237,7 @@ Server.prototype.requestHandler = function(request,response,options) {
|
|||||||
state.urlInfo = url.parse(request.url);
|
state.urlInfo = url.parse(request.url);
|
||||||
state.queryParameters = querystring.parse(state.urlInfo.query);
|
state.queryParameters = querystring.parse(state.urlInfo.query);
|
||||||
state.pathPrefix = options.pathPrefix || this.get("path-prefix") || "";
|
state.pathPrefix = options.pathPrefix || this.get("path-prefix") || "";
|
||||||
|
state.sendResponse = sendResponse.bind(self,request,response);
|
||||||
// Get the principals authorized to access this resource
|
// Get the principals authorized to access this resource
|
||||||
var authorizationType = this.methodMappings[request.method] || "readers";
|
var authorizationType = this.methodMappings[request.method] || "readers";
|
||||||
// Check for the CSRF header if this is a write
|
// Check for the CSRF header if this is a write
|
||||||
|
@ -82,7 +82,7 @@ exports.startup = function() {
|
|||||||
var onlyThrottledTiddlersHaveChanged = true;
|
var onlyThrottledTiddlersHaveChanged = true;
|
||||||
for(var title in changes) {
|
for(var title in changes) {
|
||||||
var tiddler = $tw.wiki.getTiddler(title);
|
var tiddler = $tw.wiki.getTiddler(title);
|
||||||
if(!tiddler || !(tiddler.hasField("draft.of") || tiddler.hasField("throttle.refresh"))) {
|
if(!$tw.wiki.isVolatileTiddler(title) && (!tiddler || !(tiddler.hasField("draft.of") || tiddler.hasField("throttle.refresh")))) {
|
||||||
onlyThrottledTiddlersHaveChanged = false;
|
onlyThrottledTiddlersHaveChanged = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,9 +40,10 @@ exports.startup = function() {
|
|||||||
// Install the tm-focus-selector message
|
// Install the tm-focus-selector message
|
||||||
$tw.rootWidget.addEventListener("tm-focus-selector",function(event) {
|
$tw.rootWidget.addEventListener("tm-focus-selector",function(event) {
|
||||||
var selector = event.param || "",
|
var selector = event.param || "",
|
||||||
element;
|
element,
|
||||||
|
doc = event.event && event.event.target ? event.event.target.ownerDocument : document;
|
||||||
try {
|
try {
|
||||||
element = document.querySelector(selector);
|
element = doc.querySelector(selector);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.log("Error in selector: ",selector)
|
console.log("Error in selector: ",selector)
|
||||||
}
|
}
|
||||||
|
@ -120,10 +120,10 @@ function openStartupTiddlers(options) {
|
|||||||
var hash = $tw.locationHash.substr(1),
|
var hash = $tw.locationHash.substr(1),
|
||||||
split = hash.indexOf(":");
|
split = hash.indexOf(":");
|
||||||
if(split === -1) {
|
if(split === -1) {
|
||||||
target = decodeURIComponent(hash.trim());
|
target = $tw.utils.decodeURIComponentSafe(hash.trim());
|
||||||
} else {
|
} else {
|
||||||
target = decodeURIComponent(hash.substr(0,split).trim());
|
target = $tw.utils.decodeURIComponentSafe(hash.substr(0,split).trim());
|
||||||
storyFilter = decodeURIComponent(hash.substr(split + 1).trim());
|
storyFilter = $tw.utils.decodeURIComponentSafe(hash.substr(split + 1).trim());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If the story wasn't specified use the current tiddlers or a blank story
|
// If the story wasn't specified use the current tiddlers or a blank story
|
||||||
|
@ -27,7 +27,7 @@ ClassicStoryView.prototype.navigateTo = function(historyInfo) {
|
|||||||
var listItemWidget = this.listWidget.children[listElementIndex],
|
var listItemWidget = this.listWidget.children[listElementIndex],
|
||||||
targetElement = listItemWidget.findFirstDomNode();
|
targetElement = listItemWidget.findFirstDomNode();
|
||||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||||
if(!(targetElement instanceof Element)) {
|
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(duration) {
|
if(duration) {
|
||||||
@ -43,7 +43,7 @@ ClassicStoryView.prototype.insert = function(widget) {
|
|||||||
if(duration) {
|
if(duration) {
|
||||||
var targetElement = widget.findFirstDomNode();
|
var targetElement = widget.findFirstDomNode();
|
||||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||||
if(!(targetElement instanceof Element)) {
|
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Get the current height of the tiddler
|
// Get the current height of the tiddler
|
||||||
@ -83,7 +83,7 @@ ClassicStoryView.prototype.remove = function(widget) {
|
|||||||
widget.removeChildDomNodes();
|
widget.removeChildDomNodes();
|
||||||
};
|
};
|
||||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||||
if(!(targetElement instanceof Element)) {
|
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||||
removeElement();
|
removeElement();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ PopStoryView.prototype.navigateTo = function(historyInfo) {
|
|||||||
var listItemWidget = this.listWidget.children[listElementIndex],
|
var listItemWidget = this.listWidget.children[listElementIndex],
|
||||||
targetElement = listItemWidget.findFirstDomNode();
|
targetElement = listItemWidget.findFirstDomNode();
|
||||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||||
if(!(targetElement instanceof Element)) {
|
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Scroll the node into view
|
// Scroll the node into view
|
||||||
@ -35,7 +35,7 @@ PopStoryView.prototype.insert = function(widget) {
|
|||||||
var targetElement = widget.findFirstDomNode(),
|
var targetElement = widget.findFirstDomNode(),
|
||||||
duration = $tw.utils.getAnimationDuration();
|
duration = $tw.utils.getAnimationDuration();
|
||||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||||
if(!(targetElement instanceof Element)) {
|
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Reset once the transition is over
|
// Reset once the transition is over
|
||||||
@ -77,7 +77,7 @@ PopStoryView.prototype.remove = function(widget) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||||
if(!(targetElement instanceof Element)) {
|
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||||
removeElement();
|
removeElement();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ ZoominListView.prototype.navigateTo = function(historyInfo) {
|
|||||||
var listItemWidget = this.listWidget.children[listElementIndex],
|
var listItemWidget = this.listWidget.children[listElementIndex],
|
||||||
targetElement = listItemWidget.findFirstDomNode();
|
targetElement = listItemWidget.findFirstDomNode();
|
||||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||||
if(!(targetElement instanceof Element)) {
|
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Make the new tiddler be position absolute and visible so that we can measure it
|
// Make the new tiddler be position absolute and visible so that we can measure it
|
||||||
@ -130,7 +130,7 @@ function findTitleDomNode(widget,targetClass) {
|
|||||||
ZoominListView.prototype.insert = function(widget) {
|
ZoominListView.prototype.insert = function(widget) {
|
||||||
var targetElement = widget.findFirstDomNode();
|
var targetElement = widget.findFirstDomNode();
|
||||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||||
if(!(targetElement instanceof Element)) {
|
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Make the newly inserted node position absolute and hidden
|
// Make the newly inserted node position absolute and hidden
|
||||||
@ -147,7 +147,7 @@ ZoominListView.prototype.remove = function(widget) {
|
|||||||
widget.removeChildDomNodes();
|
widget.removeChildDomNodes();
|
||||||
};
|
};
|
||||||
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
// Abandon if the list entry isn't a DOM element (it might be a text node)
|
||||||
if(!(targetElement instanceof Element)) {
|
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
|
||||||
removeElement();
|
removeElement();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ Syncer.prototype.titleIsAnonymous = "$:/status/IsAnonymous";
|
|||||||
Syncer.prototype.titleIsReadOnly = "$:/status/IsReadOnly";
|
Syncer.prototype.titleIsReadOnly = "$:/status/IsReadOnly";
|
||||||
Syncer.prototype.titleUserName = "$:/status/UserName";
|
Syncer.prototype.titleUserName = "$:/status/UserName";
|
||||||
Syncer.prototype.titleSyncFilter = "$:/config/SyncFilter";
|
Syncer.prototype.titleSyncFilter = "$:/config/SyncFilter";
|
||||||
Syncer.prototype.titleSyncDisablePolling = "$:/config/SyncDisablePolling";
|
|
||||||
Syncer.prototype.titleSyncPollingInterval = "$:/config/SyncPollingInterval";
|
Syncer.prototype.titleSyncPollingInterval = "$:/config/SyncPollingInterval";
|
||||||
Syncer.prototype.titleSyncDisableLazyLoading = "$:/config/SyncDisableLazyLoading";
|
Syncer.prototype.titleSyncDisableLazyLoading = "$:/config/SyncDisableLazyLoading";
|
||||||
Syncer.prototype.titleSavedNotification = "$:/language/Notifications/Save/Done";
|
Syncer.prototype.titleSavedNotification = "$:/language/Notifications/Save/Done";
|
||||||
@ -273,9 +272,9 @@ Syncer.prototype.getStatus = function(callback) {
|
|||||||
// Mark us as not logged in
|
// Mark us as not logged in
|
||||||
this.wiki.addTiddler({title: this.titleIsLoggedIn,text: "no"});
|
this.wiki.addTiddler({title: this.titleIsLoggedIn,text: "no"});
|
||||||
// Get login status
|
// Get login status
|
||||||
this.syncadaptor.getStatus(function(err,isLoggedIn,username,isReadOnly,isAnonymous,isPollingDisabled) {
|
this.syncadaptor.getStatus(function(err,isLoggedIn,username,isReadOnly,isAnonymous) {
|
||||||
if(err) {
|
if(err) {
|
||||||
self.logger.alert(err);
|
self.displayError("Get Status Error",err);
|
||||||
} else {
|
} else {
|
||||||
// Set the various status tiddlers
|
// Set the various status tiddlers
|
||||||
self.wiki.addTiddler({title: self.titleIsReadOnly,text: isReadOnly ? "yes" : "no"});
|
self.wiki.addTiddler({title: self.titleIsReadOnly,text: isReadOnly ? "yes" : "no"});
|
||||||
@ -284,9 +283,6 @@ Syncer.prototype.getStatus = function(callback) {
|
|||||||
if(isLoggedIn) {
|
if(isLoggedIn) {
|
||||||
self.wiki.addTiddler({title: self.titleUserName,text: username || ""});
|
self.wiki.addTiddler({title: self.titleUserName,text: username || ""});
|
||||||
}
|
}
|
||||||
if(isPollingDisabled) {
|
|
||||||
self.wiki.addTiddler({title: self.titleSyncDisablePolling, text: "yes"});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Invoke the callback
|
// Invoke the callback
|
||||||
if(callback) {
|
if(callback) {
|
||||||
@ -310,15 +306,12 @@ Syncer.prototype.syncFromServer = function() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
triggerNextSync = function() {
|
triggerNextSync = function() {
|
||||||
if(pollingEnabled) {
|
|
||||||
self.pollTimerId = setTimeout(function() {
|
self.pollTimerId = setTimeout(function() {
|
||||||
self.pollTimerId = null;
|
self.pollTimerId = null;
|
||||||
self.syncFromServer.call(self);
|
self.syncFromServer.call(self);
|
||||||
},self.pollTimerInterval);
|
},self.pollTimerInterval);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
syncSystemFromServer = (self.wiki.getTiddlerText("$:/config/SyncSystemTiddlersFromServer") === "yes"),
|
syncSystemFromServer = (self.wiki.getTiddlerText("$:/config/SyncSystemTiddlersFromServer") === "yes" ? true : false);
|
||||||
pollingEnabled = (self.wiki.getTiddlerText(self.titleSyncDisablePolling) !== "yes");
|
|
||||||
if(this.syncadaptor && this.syncadaptor.getUpdatedTiddlers) {
|
if(this.syncadaptor && this.syncadaptor.getUpdatedTiddlers) {
|
||||||
this.logger.log("Retrieving updated tiddler list");
|
this.logger.log("Retrieving updated tiddler list");
|
||||||
cancelNextSync();
|
cancelNextSync();
|
||||||
@ -484,7 +477,7 @@ Syncer.prototype.handleLogoutEvent = function() {
|
|||||||
if(this.syncadaptor.logout) {
|
if(this.syncadaptor.logout) {
|
||||||
this.syncadaptor.logout(function(err) {
|
this.syncadaptor.logout(function(err) {
|
||||||
if(err) {
|
if(err) {
|
||||||
self.logger.alert(err);
|
self.displayError("Logout Error",err);
|
||||||
} else {
|
} else {
|
||||||
self.getStatus();
|
self.getStatus();
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,8 @@ Upgrader module that suppresses certain system tiddlers that shouldn't be import
|
|||||||
/*global $tw: false */
|
/*global $tw: false */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var DONT_IMPORT_LIST = ["$:/StoryList","$:/HistoryList"],
|
var DONT_IMPORT_LIST = ["$:/Import"],
|
||||||
DONT_IMPORT_PREFIX_LIST = ["$:/temp/","$:/state/","$:/Import"],
|
UNSELECT_PREFIX_LIST = ["$:/temp/","$:/state/","$:/StoryList","$:/HistoryList"],
|
||||||
WARN_IMPORT_PREFIX_LIST = ["$:/core/modules/"];
|
WARN_IMPORT_PREFIX_LIST = ["$:/core/modules/"];
|
||||||
|
|
||||||
exports.upgrade = function(wiki,titles,tiddlers) {
|
exports.upgrade = function(wiki,titles,tiddlers) {
|
||||||
@ -26,11 +26,10 @@ exports.upgrade = function(wiki,titles,tiddlers) {
|
|||||||
tiddlers[title] = Object.create(null);
|
tiddlers[title] = Object.create(null);
|
||||||
messages[title] = $tw.language.getString("Import/Upgrader/System/Suppressed");
|
messages[title] = $tw.language.getString("Import/Upgrader/System/Suppressed");
|
||||||
} else {
|
} else {
|
||||||
for(var t=0; t<DONT_IMPORT_PREFIX_LIST.length; t++) {
|
for(var t=0; t<UNSELECT_PREFIX_LIST.length; t++) {
|
||||||
var prefix = DONT_IMPORT_PREFIX_LIST[t];
|
var prefix = UNSELECT_PREFIX_LIST[t];
|
||||||
if(title.substr(0,prefix.length) === prefix) {
|
if(title.substr(0,prefix.length) === prefix) {
|
||||||
tiddlers[title] = Object.create(null);
|
messages[title] = $tw.language.getString("Import/Upgrader/Tiddler/Unselected");
|
||||||
messages[title] = $tw.language.getString("Import/Upgrader/State/Suppressed");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(var t=0; t<WARN_IMPORT_PREFIX_LIST.length; t++) {
|
for(var t=0; t<WARN_IMPORT_PREFIX_LIST.length; t++) {
|
||||||
|
@ -22,6 +22,10 @@ exports.domContains = function(a,b) {
|
|||||||
!!(a.compareDocumentPosition(b) & 16);
|
!!(a.compareDocumentPosition(b) & 16);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.domMatchesSelector = function(node,selector) {
|
||||||
|
return node.matches ? node.matches(selector) : node.msMatchesSelector(selector);
|
||||||
|
};
|
||||||
|
|
||||||
exports.removeChildren = function(node) {
|
exports.removeChildren = function(node) {
|
||||||
while(node.hasChildNodes()) {
|
while(node.hasChildNodes()) {
|
||||||
node.removeChild(node.firstChild);
|
node.removeChild(node.firstChild);
|
||||||
|
@ -16,7 +16,7 @@ Browser data transfer utilities, used with the clipboard and drag and drop
|
|||||||
Options:
|
Options:
|
||||||
|
|
||||||
domNode: dom node to make draggable
|
domNode: dom node to make draggable
|
||||||
dragImageType: "pill" or "dom"
|
dragImageType: "pill", "blank" or "dom" (the default)
|
||||||
dragTiddlerFn: optional function to retrieve the title of tiddler to drag
|
dragTiddlerFn: optional function to retrieve the title of tiddler to drag
|
||||||
dragFilterFn: optional function to retreive the filter defining a list of tiddlers to drag
|
dragFilterFn: optional function to retreive the filter defining a list of tiddlers to drag
|
||||||
widget: widget to use as the contect for the filter
|
widget: widget to use as the contect for the filter
|
||||||
@ -73,6 +73,9 @@ exports.makeDraggable = function(options) {
|
|||||||
if(dataTransfer.setDragImage) {
|
if(dataTransfer.setDragImage) {
|
||||||
if(dragImageType === "pill") {
|
if(dragImageType === "pill") {
|
||||||
dataTransfer.setDragImage(dragImage.firstChild,-16,-16);
|
dataTransfer.setDragImage(dragImage.firstChild,-16,-16);
|
||||||
|
} else if (dragImageType === "blank") {
|
||||||
|
dragImage.removeChild(dragImage.firstChild);
|
||||||
|
dataTransfer.setDragImage(dragImage,0,0);
|
||||||
} else {
|
} else {
|
||||||
var r = domNode.getBoundingClientRect();
|
var r = domNode.getBoundingClientRect();
|
||||||
dataTransfer.setDragImage(domNode,event.clientX-r.left,event.clientY-r.top);
|
dataTransfer.setDragImage(domNode,event.clientX-r.left,event.clientY-r.top);
|
||||||
@ -164,7 +167,7 @@ var importDataTypes = [
|
|||||||
}},
|
}},
|
||||||
{type: "URL", IECompatible: true, toTiddlerFieldsArray: function(data,fallbackTitle) {
|
{type: "URL", IECompatible: true, toTiddlerFieldsArray: function(data,fallbackTitle) {
|
||||||
// Check for tiddler data URI
|
// Check for tiddler data URI
|
||||||
var match = decodeURIComponent(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
|
var match = $tw.utils.decodeURIComponentSafe(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
|
||||||
if(match) {
|
if(match) {
|
||||||
return parseJSONTiddlers(match[1],fallbackTitle);
|
return parseJSONTiddlers(match[1],fallbackTitle);
|
||||||
} else {
|
} else {
|
||||||
@ -173,7 +176,7 @@ var importDataTypes = [
|
|||||||
}},
|
}},
|
||||||
{type: "text/x-moz-url", IECompatible: false, toTiddlerFieldsArray: function(data,fallbackTitle) {
|
{type: "text/x-moz-url", IECompatible: false, toTiddlerFieldsArray: function(data,fallbackTitle) {
|
||||||
// Check for tiddler data URI
|
// Check for tiddler data URI
|
||||||
var match = decodeURIComponent(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
|
var match = $tw.utils.decodeURIComponentSafe(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
|
||||||
if(match) {
|
if(match) {
|
||||||
return parseJSONTiddlers(match[1],fallbackTitle);
|
return parseJSONTiddlers(match[1],fallbackTitle);
|
||||||
} else {
|
} else {
|
||||||
@ -205,4 +208,16 @@ function parseJSONTiddlers(json,fallbackTitle) {
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.dragEventContainsFiles = function(event) {
|
||||||
|
if(event.dataTransfer.types) {
|
||||||
|
for(var i=0; i<event.dataTransfer.types.length; i++) {
|
||||||
|
if(event.dataTransfer.types[i] === "Files") {
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -34,6 +34,23 @@ exports.httpRequest = function(options) {
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
getHeader = function(targetHeader) {
|
||||||
|
return headers[targetHeader] || headers[targetHeader.toLowerCase()];
|
||||||
|
},
|
||||||
|
isSimpleRequest = function(type,headers) {
|
||||||
|
if(["GET","HEAD","POST"].indexOf(type) === -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for(var header in headers) {
|
||||||
|
if(["accept","accept-language","content-language","content-type"].indexOf(header.toLowerCase()) === -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(hasHeader("Content-Type") && ["application/x-www-form-urlencoded","multipart/form-data","text/plain"].indexOf(getHeader["Content-Type"]) === -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
returnProp = options.returnProp || "responseText",
|
returnProp = options.returnProp || "responseText",
|
||||||
request = new XMLHttpRequest(),
|
request = new XMLHttpRequest(),
|
||||||
data = "",
|
data = "",
|
||||||
@ -76,7 +93,7 @@ exports.httpRequest = function(options) {
|
|||||||
if(data && !hasHeader("Content-Type")) {
|
if(data && !hasHeader("Content-Type")) {
|
||||||
request.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
|
request.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
|
||||||
}
|
}
|
||||||
if(!hasHeader("X-Requested-With")) {
|
if(!hasHeader("X-Requested-With") && !isSimpleRequest(type,headers)) {
|
||||||
request.setRequestHeader("X-Requested-With","TiddlyWiki");
|
request.setRequestHeader("X-Requested-With","TiddlyWiki");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
@ -243,6 +243,7 @@ Modal.prototype.adjustPageClass = function() {
|
|||||||
if(windowContainer) {
|
if(windowContainer) {
|
||||||
$tw.utils.toggleClass(windowContainer,"tc-modal-displayed",this.modalCount > 0);
|
$tw.utils.toggleClass(windowContainer,"tc-modal-displayed",this.modalCount > 0);
|
||||||
}
|
}
|
||||||
|
$tw.utils.toggleClass(this.srcDocument.body,"tc-modal-prevent-scroll",this.modalCount > 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.Modal = Modal;
|
exports.Modal = Modal;
|
||||||
|
@ -1,33 +1,28 @@
|
|||||||
/*\
|
/*\
|
||||||
title: $:/core/modules/startup/CSSescape.js
|
title: $:/core/modules/utils/escapecss.js
|
||||||
type: application/javascript
|
type: application/javascript
|
||||||
module-type: startup
|
module-type: utils
|
||||||
|
|
||||||
Polyfill for CSS.escape()
|
Provides CSS.escape() functionality.
|
||||||
|
|
||||||
\*/
|
\*/
|
||||||
(function(root,factory){
|
(function(){
|
||||||
|
|
||||||
/*jslint node: true, browser: true */
|
/*jslint node: true, browser: true */
|
||||||
/*global $tw: false */
|
/*global $tw: false, window: false */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// Export name and synchronous status
|
exports.escapeCSS = (function() {
|
||||||
exports.name = "css-escape";
|
// use browser's native CSS.escape() function if available
|
||||||
exports.platforms = ["browser"];
|
if ($tw.browser && window.CSS && window.CSS.escape) {
|
||||||
exports.after = ["startup"];
|
return window.CSS.escape;
|
||||||
exports.synchronous = true;
|
|
||||||
|
|
||||||
/*! https://mths.be/cssescape v1.5.1 by @mathias | MIT license */
|
|
||||||
// https://github.com/umdjs/umd/blob/master/returnExports.js
|
|
||||||
exports.startup = function() {factory(root);};
|
|
||||||
}(typeof global != 'undefined' ? global : this, function(root) {
|
|
||||||
|
|
||||||
if (root.CSS && root.CSS.escape) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.csswg.org/cssom/#serialize-an-identifier
|
// otherwise, a utility method is provided
|
||||||
var cssEscape = function(value) {
|
// see also https://drafts.csswg.org/cssom/#serialize-an-identifier
|
||||||
|
|
||||||
|
/*! https://mths.be/cssescape v1.5.1 by @mathias | MIT license */
|
||||||
|
return function(value) {
|
||||||
if (arguments.length == 0) {
|
if (arguments.length == 0) {
|
||||||
throw new TypeError('`CSS.escape` requires an argument.');
|
throw new TypeError('`CSS.escape` requires an argument.');
|
||||||
}
|
}
|
||||||
@ -104,11 +99,6 @@ exports.startup = function() {factory(root);};
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
if (!root.CSS) {
|
})();
|
||||||
root.CSS = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.getPrototypeOf(root.CSS).escape = cssEscape;
|
|
||||||
|
|
||||||
}));
|
|
@ -235,7 +235,7 @@ Object.defineProperty(TW_Element.prototype, "innerHTML", {
|
|||||||
if(node instanceof TW_Element) {
|
if(node instanceof TW_Element) {
|
||||||
b.push(node.outerHTML);
|
b.push(node.outerHTML);
|
||||||
} else if(node instanceof TW_TextNode) {
|
} else if(node instanceof TW_TextNode) {
|
||||||
b.push($tw.utils.htmlEncode(node.textContent));
|
b.push($tw.utils.htmlTextEncode(node.textContent));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return b.join("");
|
return b.join("");
|
||||||
|
@ -228,6 +228,7 @@ exports.generateTiddlerFileInfo = function(tiddler,options) {
|
|||||||
hasUnsafeFields = hasUnsafeFields || /[\x00-\x1F]/mg.test(value);
|
hasUnsafeFields = hasUnsafeFields || /[\x00-\x1F]/mg.test(value);
|
||||||
hasUnsafeFields = hasUnsafeFields || ($tw.utils.trim(value) !== value);
|
hasUnsafeFields = hasUnsafeFields || ($tw.utils.trim(value) !== value);
|
||||||
}
|
}
|
||||||
|
hasUnsafeFields = hasUnsafeFields || /:/mg.test(fieldName);
|
||||||
});
|
});
|
||||||
// Check for field values
|
// Check for field values
|
||||||
if(hasUnsafeFields) {
|
if(hasUnsafeFields) {
|
||||||
|
@ -95,6 +95,15 @@ LinkedList.prototype.toArray = function() {
|
|||||||
return output;
|
return output;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LinkedList.prototype.makeTiddlerIterator = function(wiki) {
|
||||||
|
var self = this;
|
||||||
|
return function(callback) {
|
||||||
|
self.each(function(title) {
|
||||||
|
callback(wiki.getTiddler(title),title);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
function _removeOne(list,value) {
|
function _removeOne(list,value) {
|
||||||
var prevEntry = list.prev[value],
|
var prevEntry = list.prev[value],
|
||||||
nextEntry = list.next[value],
|
nextEntry = list.next[value],
|
||||||
|
@ -199,6 +199,8 @@ exports.transliterationPairs = {
|
|||||||
"Nj":"N",
|
"Nj":"N",
|
||||||
"Ñ":"N",
|
"Ñ":"N",
|
||||||
"NJ":"NJ",
|
"NJ":"NJ",
|
||||||
|
"ð":"d",
|
||||||
|
"Ð":"D",
|
||||||
"Ó":"O",
|
"Ó":"O",
|
||||||
"Ŏ":"O",
|
"Ŏ":"O",
|
||||||
"Ǒ":"O",
|
"Ǒ":"O",
|
||||||
@ -265,6 +267,8 @@ exports.transliterationPairs = {
|
|||||||
"Ɽ":"R",
|
"Ɽ":"R",
|
||||||
"Ꜿ":"C",
|
"Ꜿ":"C",
|
||||||
"Ǝ":"E",
|
"Ǝ":"E",
|
||||||
|
"ß":"ss",
|
||||||
|
"ẞ":"SS",
|
||||||
"Ś":"S",
|
"Ś":"S",
|
||||||
"Ṥ":"S",
|
"Ṥ":"S",
|
||||||
"Š":"S",
|
"Š":"S",
|
||||||
@ -275,6 +279,8 @@ exports.transliterationPairs = {
|
|||||||
"Ṡ":"S",
|
"Ṡ":"S",
|
||||||
"Ṣ":"S",
|
"Ṣ":"S",
|
||||||
"Ṩ":"S",
|
"Ṩ":"S",
|
||||||
|
"þ": "th",
|
||||||
|
"Þ": "TH",
|
||||||
"Ť":"T",
|
"Ť":"T",
|
||||||
"Ţ":"T",
|
"Ţ":"T",
|
||||||
"Ṱ":"T",
|
"Ṱ":"T",
|
||||||
@ -907,7 +913,8 @@ exports.transliterationPairs = {
|
|||||||
"т":"t",
|
"т":"t",
|
||||||
"ь":"'",
|
"ь":"'",
|
||||||
"б":"b",
|
"б":"b",
|
||||||
"ю":"yu"
|
"ю":"yu",
|
||||||
|
"…":"..."
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.transliterate = function(str) {
|
exports.transliterate = function(str) {
|
||||||
|
@ -223,6 +223,7 @@ exports.removeArrayEntries = function(array,value) {
|
|||||||
array.splice(p,1);
|
array.splice(p,1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return array;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -294,6 +295,47 @@ exports.slowInSlowOut = function(t) {
|
|||||||
return (1 - ((Math.cos(t * Math.PI) + 1) / 2));
|
return (1 - ((Math.cos(t * Math.PI) + 1) / 2));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.formatTitleString = function(template,options) {
|
||||||
|
var base = options.base || "",
|
||||||
|
separator = options.separator || "",
|
||||||
|
counter = options.counter || "";
|
||||||
|
var result = "",
|
||||||
|
t = template,
|
||||||
|
matches = [
|
||||||
|
[/^\$basename\$/i, function() {
|
||||||
|
return base;
|
||||||
|
}],
|
||||||
|
[/^\$count:(\d+)\$/i, function(match) {
|
||||||
|
return $tw.utils.pad(counter,match[1]);
|
||||||
|
}],
|
||||||
|
[/^\$separator\$/i, function() {
|
||||||
|
return separator;
|
||||||
|
}],
|
||||||
|
[/^\$count\$/i, function() {
|
||||||
|
return counter + "";
|
||||||
|
}]
|
||||||
|
];
|
||||||
|
while(t.length){
|
||||||
|
var matchString = "";
|
||||||
|
$tw.utils.each(matches, function(m) {
|
||||||
|
var match = m[0].exec(t);
|
||||||
|
if(match) {
|
||||||
|
matchString = m[1].call(null,match);
|
||||||
|
t = t.substr(match[0].length);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(matchString) {
|
||||||
|
result += matchString;
|
||||||
|
} else {
|
||||||
|
result += t.charAt(0);
|
||||||
|
t = t.substr(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = result.replace(/\\(.)/g,"$1");
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
exports.formatDateString = function(date,template) {
|
exports.formatDateString = function(date,template) {
|
||||||
var result = "",
|
var result = "",
|
||||||
t = template,
|
t = template,
|
||||||
@ -341,6 +383,15 @@ exports.formatDateString = function(date,template) {
|
|||||||
[/^0WW/, function() {
|
[/^0WW/, function() {
|
||||||
return $tw.utils.pad($tw.utils.getWeek(date));
|
return $tw.utils.pad($tw.utils.getWeek(date));
|
||||||
}],
|
}],
|
||||||
|
[/^0ddddd/, function() {
|
||||||
|
return $tw.utils.pad(Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24),3);
|
||||||
|
}],
|
||||||
|
[/^ddddd/, function() {
|
||||||
|
return Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24);
|
||||||
|
}],
|
||||||
|
[/^dddd/, function() {
|
||||||
|
return [7,1,2,3,4,5,6][date.getDay()];
|
||||||
|
}],
|
||||||
[/^ddd/, function() {
|
[/^ddd/, function() {
|
||||||
return $tw.language.getString("Date/Short/Day/" + date.getDay());
|
return $tw.language.getString("Date/Short/Day/" + date.getDay());
|
||||||
}],
|
}],
|
||||||
@ -515,6 +566,15 @@ exports.htmlEncode = function(s) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Converts like htmlEncode, but forgets the double quote for brevity
|
||||||
|
exports.htmlTextEncode = function(s) {
|
||||||
|
if(s) {
|
||||||
|
return s.toString().replace(/&/mg,"&").replace(/</mg,"<").replace(/>/mg,">");
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Converts all HTML entities to their character equivalents
|
// Converts all HTML entities to their character equivalents
|
||||||
exports.entityDecode = function(s) {
|
exports.entityDecode = function(s) {
|
||||||
var converter = String.fromCodePoint || String.fromCharCode,
|
var converter = String.fromCodePoint || String.fromCharCode,
|
||||||
@ -690,9 +750,8 @@ exports.isValidFieldName = function(name) {
|
|||||||
if(!name || typeof name !== "string") {
|
if(!name || typeof name !== "string") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
name = name.toLowerCase().trim();
|
// Since v5.2.x, there are no restrictions on characters in field names
|
||||||
var fieldValidatorRegEx = /^[a-z0-9\-\._]+$/mg;
|
return name;
|
||||||
return fieldValidatorRegEx.test(name);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -867,7 +926,9 @@ exports.stringifyNumber = function(num) {
|
|||||||
|
|
||||||
exports.makeCompareFunction = function(type,options) {
|
exports.makeCompareFunction = function(type,options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
var gt = options.invert ? -1 : +1,
|
// set isCaseSensitive to true if not defined in options
|
||||||
|
var isCaseSensitive = (options.isCaseSensitive === false) ? false : true,
|
||||||
|
gt = options.invert ? -1 : +1,
|
||||||
lt = options.invert ? +1 : -1,
|
lt = options.invert ? +1 : -1,
|
||||||
compare = function(a,b) {
|
compare = function(a,b) {
|
||||||
if(a > b) {
|
if(a > b) {
|
||||||
@ -886,6 +947,10 @@ exports.makeCompareFunction = function(type,options) {
|
|||||||
return compare($tw.utils.parseInt(a),$tw.utils.parseInt(b));
|
return compare($tw.utils.parseInt(a),$tw.utils.parseInt(b));
|
||||||
},
|
},
|
||||||
"string": function(a,b) {
|
"string": function(a,b) {
|
||||||
|
if(!isCaseSensitive) {
|
||||||
|
a = a.toLowerCase();
|
||||||
|
b = b.toLowerCase();
|
||||||
|
}
|
||||||
return compare("" + a,"" + b);
|
return compare("" + a,"" + b);
|
||||||
},
|
},
|
||||||
"date": function(a,b) {
|
"date": function(a,b) {
|
||||||
@ -901,6 +966,13 @@ exports.makeCompareFunction = function(type,options) {
|
|||||||
},
|
},
|
||||||
"version": function(a,b) {
|
"version": function(a,b) {
|
||||||
return $tw.utils.compareVersions(a,b);
|
return $tw.utils.compareVersions(a,b);
|
||||||
|
},
|
||||||
|
"alphanumeric": function(a,b) {
|
||||||
|
if(!isCaseSensitive) {
|
||||||
|
a = a.toLowerCase();
|
||||||
|
b = b.toLowerCase();
|
||||||
|
}
|
||||||
|
return options.invert ? b.localeCompare(a,undefined,{numeric: true,sensitivity: "base"}) : a.localeCompare(b,undefined,{numeric: true,sensitivity: "base"});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (types[type] || types[options.defaultType] || types.number);
|
return (types[type] || types[options.defaultType] || types.number);
|
||||||
|
@ -58,9 +58,10 @@ Invoke the action associated with this widget
|
|||||||
*/
|
*/
|
||||||
ConfirmWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
ConfirmWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||||
var invokeActions = true,
|
var invokeActions = true,
|
||||||
handled = true;
|
handled = true,
|
||||||
|
win = event && event.event && event.event.view ? event.event.view : window;
|
||||||
if(this.prompt) {
|
if(this.prompt) {
|
||||||
invokeActions = confirm(this.message);
|
invokeActions = win.confirm(this.message);
|
||||||
}
|
}
|
||||||
if(invokeActions) {
|
if(invokeActions) {
|
||||||
handled = this.invokeActions(triggeringWidget,event);
|
handled = this.invokeActions(triggeringWidget,event);
|
||||||
|
@ -27,8 +27,11 @@ CreateTiddlerWidget.prototype = new Widget();
|
|||||||
Render this widget into the DOM
|
Render this widget into the DOM
|
||||||
*/
|
*/
|
||||||
CreateTiddlerWidget.prototype.render = function(parent,nextSibling) {
|
CreateTiddlerWidget.prototype.render = function(parent,nextSibling) {
|
||||||
|
this.parentDomNode = parent;
|
||||||
this.computeAttributes();
|
this.computeAttributes();
|
||||||
this.execute();
|
this.execute();
|
||||||
|
// Render children
|
||||||
|
this.renderChildren(parent,nextSibling);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -44,7 +47,8 @@ CreateTiddlerWidget.prototype.execute = function() {
|
|||||||
this.actionTemplate = this.getAttribute("$template");
|
this.actionTemplate = this.getAttribute("$template");
|
||||||
this.useTemplate = !!this.actionTemplate;
|
this.useTemplate = !!this.actionTemplate;
|
||||||
this.actionOverwrite = this.getAttribute("$overwrite","no");
|
this.actionOverwrite = this.getAttribute("$overwrite","no");
|
||||||
|
// Construct the child widgets
|
||||||
|
this.makeChildWidgets();
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -86,18 +90,21 @@ CreateTiddlerWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
|||||||
if (!this.hasBase && this.useTemplate) {
|
if (!this.hasBase && this.useTemplate) {
|
||||||
title = this.wiki.generateNewTitle(this.actionTemplate);
|
title = this.wiki.generateNewTitle(this.actionTemplate);
|
||||||
} else if (!this.hasBase && !this.useTemplate) {
|
} else if (!this.hasBase && !this.useTemplate) {
|
||||||
// If NO $basetitle AND NO $template use initial title
|
// If no $basetitle and no $template then use initial title
|
||||||
// DON'T overwrite any stuff
|
|
||||||
title = this.wiki.generateNewTitle(title);
|
title = this.wiki.generateNewTitle(title);
|
||||||
}
|
}
|
||||||
var templateTiddler = this.wiki.getTiddler(this.actionTemplate) || {};
|
var templateTiddler = this.wiki.getTiddler(this.actionTemplate) || {};
|
||||||
var tiddler = this.wiki.addTiddler(new $tw.Tiddler(templateTiddler.fields,creationFields,fields,modificationFields,{title: title}));
|
this.wiki.addTiddler(new $tw.Tiddler(templateTiddler.fields,creationFields,fields,modificationFields,{title: title}));
|
||||||
|
var draftTitle = this.wiki.generateDraftTitle(title);
|
||||||
if(this.actionSaveTitle) {
|
if(this.actionSaveTitle) {
|
||||||
this.wiki.setTextReference(this.actionSaveTitle,title,this.getVariable("currentTiddler"));
|
this.wiki.setTextReference(this.actionSaveTitle,title,this.getVariable("currentTiddler"));
|
||||||
}
|
}
|
||||||
if(this.actionSaveDraftTitle) {
|
if(this.actionSaveDraftTitle) {
|
||||||
this.wiki.setTextReference(this.actionSaveDraftTitle,this.wiki.generateDraftTitle(title),this.getVariable("currentTiddler"));
|
this.wiki.setTextReference(this.actionSaveDraftTitle,draftTitle,this.getVariable("currentTiddler"));
|
||||||
}
|
}
|
||||||
|
this.setVariable("createTiddler-title",title);
|
||||||
|
this.setVariable("createTiddler-draftTitle",draftTitle);
|
||||||
|
this.refreshChildren();
|
||||||
return true; // Action was invoked
|
return true; // Action was invoked
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -44,9 +44,7 @@ ActionListopsWidget.prototype.execute = function() {
|
|||||||
*/
|
*/
|
||||||
ActionListopsWidget.prototype.refresh = function(changedTiddlers) {
|
ActionListopsWidget.prototype.refresh = function(changedTiddlers) {
|
||||||
var changedAttributes = this.computeAttributes();
|
var changedAttributes = this.computeAttributes();
|
||||||
if(changedAttributes.$tiddler || changedAttributes.$filter ||
|
if($tw.utils.count(changedAttributes) > 0) {
|
||||||
changedAttributes.$subfilter || changedAttributes.$field ||
|
|
||||||
changedAttributes.$index || changedAttributes.$tags) {
|
|
||||||
this.refreshSelf();
|
this.refreshSelf();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -60,12 +58,10 @@ ActionListopsWidget.prototype.invokeAction = function(triggeringWidget,
|
|||||||
//Apply the specified filters to the lists
|
//Apply the specified filters to the lists
|
||||||
var field = this.listField,
|
var field = this.listField,
|
||||||
index,
|
index,
|
||||||
type = "!!",
|
|
||||||
list = this.listField;
|
list = this.listField;
|
||||||
if(this.listIndex) {
|
if(this.listIndex) {
|
||||||
field = undefined;
|
field = undefined;
|
||||||
index = this.listIndex;
|
index = this.listIndex;
|
||||||
type = "##";
|
|
||||||
list = this.listIndex;
|
list = this.listIndex;
|
||||||
}
|
}
|
||||||
if(this.filter) {
|
if(this.filter) {
|
||||||
@ -74,15 +70,14 @@ ActionListopsWidget.prototype.invokeAction = function(triggeringWidget,
|
|||||||
.filterTiddlers(this.filter, this)));
|
.filterTiddlers(this.filter, this)));
|
||||||
}
|
}
|
||||||
if(this.subfilter) {
|
if(this.subfilter) {
|
||||||
var subfilter = "[list[" + this.target + type + list + "]] " + this.subfilter;
|
var inputList = this.wiki.getTiddlerList(this.target,field,index),
|
||||||
this.wiki.setText(this.target, field, index, $tw.utils.stringifyList(
|
subfilter = $tw.utils.stringifyList(inputList) + " " + this.subfilter;
|
||||||
this.wiki
|
this.wiki.setText(this.target, field, index, $tw.utils.stringifyList(this.wiki.filterTiddlers(subfilter,this)));
|
||||||
.filterTiddlers(subfilter, this)));
|
|
||||||
}
|
}
|
||||||
if(this.filtertags) {
|
if(this.filtertags) {
|
||||||
var tiddler = this.wiki.getTiddler(this.target),
|
var tiddler = this.wiki.getTiddler(this.target),
|
||||||
oldtags = tiddler ? (tiddler.fields.tags || []).slice(0) : [],
|
oldtags = tiddler ? (tiddler.fields.tags || []).slice(0) : [],
|
||||||
tagfilter = "[list[" + this.target + "!!tags]] " + this.filtertags,
|
tagfilter = $tw.utils.stringifyList(oldtags) + " " + this.filtertags,
|
||||||
newtags = this.wiki.filterTiddlers(tagfilter,this);
|
newtags = this.wiki.filterTiddlers(tagfilter,this);
|
||||||
if($tw.utils.stringifyList(oldtags.sort()) !== $tw.utils.stringifyList(newtags.sort())) {
|
if($tw.utils.stringifyList(oldtags.sort()) !== $tw.utils.stringifyList(newtags.sort())) {
|
||||||
this.wiki.setText(this.target,"tags",undefined,$tw.utils.stringifyList(newtags));
|
this.wiki.setText(this.target,"tags",undefined,$tw.utils.stringifyList(newtags));
|
||||||
|
@ -70,7 +70,18 @@ NavigateWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
|||||||
navigateFromNode: triggeringWidget,
|
navigateFromNode: triggeringWidget,
|
||||||
navigateFromClientRect: bounds && { top: bounds.top, left: bounds.left, width: bounds.width, right: bounds.right, bottom: bounds.bottom, height: bounds.height
|
navigateFromClientRect: bounds && { top: bounds.top, left: bounds.left, width: bounds.width, right: bounds.right, bottom: bounds.bottom, height: bounds.height
|
||||||
},
|
},
|
||||||
navigateSuppressNavigation: suppressNavigation
|
navigateFromClientTop: bounds && bounds.top,
|
||||||
|
navigateFromClientLeft: bounds && bounds.left,
|
||||||
|
navigateFromClientWidth: bounds && bounds.width,
|
||||||
|
navigateFromClientRight: bounds && bounds.right,
|
||||||
|
navigateFromClientBottom: bounds && bounds.bottom,
|
||||||
|
navigateFromClientHeight: bounds && bounds.height,
|
||||||
|
navigateSuppressNavigation: suppressNavigation,
|
||||||
|
metaKey: event.metaKey,
|
||||||
|
ctrlKey: event.ctrlKey,
|
||||||
|
altKey: event.altKey,
|
||||||
|
shiftKey: event.shiftKey,
|
||||||
|
event: event
|
||||||
});
|
});
|
||||||
return true; // Action was invoked
|
return true; // Action was invoked
|
||||||
};
|
};
|
||||||
|
@ -37,6 +37,7 @@ Compute the internal state of the widget
|
|||||||
ActionPopupWidget.prototype.execute = function() {
|
ActionPopupWidget.prototype.execute = function() {
|
||||||
this.actionState = this.getAttribute("$state");
|
this.actionState = this.getAttribute("$state");
|
||||||
this.actionCoords = this.getAttribute("$coords");
|
this.actionCoords = this.getAttribute("$coords");
|
||||||
|
this.floating = this.getAttribute("$floating","no") === "yes";
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -68,7 +69,8 @@ ActionPopupWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
|||||||
height: parseFloat(match[4])
|
height: parseFloat(match[4])
|
||||||
},
|
},
|
||||||
title: this.actionState,
|
title: this.actionState,
|
||||||
wiki: this.wiki
|
wiki: this.wiki,
|
||||||
|
floating: this.floating
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$tw.popup.cancel(0);
|
$tw.popup.cancel(0);
|
||||||
|
@ -39,6 +39,8 @@ SendMessageWidget.prototype.execute = function() {
|
|||||||
this.actionParam = this.getAttribute("$param");
|
this.actionParam = this.getAttribute("$param");
|
||||||
this.actionName = this.getAttribute("$name");
|
this.actionName = this.getAttribute("$name");
|
||||||
this.actionValue = this.getAttribute("$value","");
|
this.actionValue = this.getAttribute("$value","");
|
||||||
|
this.actionNames = this.getAttribute("$names");
|
||||||
|
this.actionValues = this.getAttribute("$values");
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -59,13 +61,20 @@ Invoke the action associated with this widget
|
|||||||
SendMessageWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
SendMessageWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||||
// Get the string parameter
|
// Get the string parameter
|
||||||
var param = this.actionParam;
|
var param = this.actionParam;
|
||||||
// Assemble the attributes as a hashmap
|
// Assemble the parameters as a hashmap
|
||||||
var paramObject = Object.create(null);
|
var paramObject = Object.create(null);
|
||||||
var count = 0;
|
// Add names/values pairs if present
|
||||||
|
if(this.actionNames && this.actionValues) {
|
||||||
|
var names = this.wiki.filterTiddlers(this.actionNames,this),
|
||||||
|
values = this.wiki.filterTiddlers(this.actionValues,this);
|
||||||
|
$tw.utils.each(names,function(name,index) {
|
||||||
|
paramObject[name] = values[index] || "";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Add raw parameters
|
||||||
$tw.utils.each(this.attributes,function(attribute,name) {
|
$tw.utils.each(this.attributes,function(attribute,name) {
|
||||||
if(name.charAt(0) !== "$") {
|
if(name.charAt(0) !== "$") {
|
||||||
paramObject[name] = attribute;
|
paramObject[name] = attribute;
|
||||||
count++;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Add name/value pair if present
|
// Add name/value pair if present
|
||||||
@ -73,14 +82,15 @@ SendMessageWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
|||||||
paramObject[this.actionName] = this.actionValue;
|
paramObject[this.actionName] = this.actionValue;
|
||||||
}
|
}
|
||||||
// Dispatch the message
|
// Dispatch the message
|
||||||
this.dispatchEvent({
|
var params = {
|
||||||
type: this.actionMessage,
|
type: this.actionMessage,
|
||||||
param: param,
|
param: param,
|
||||||
paramObject: paramObject,
|
paramObject: paramObject,
|
||||||
tiddlerTitle: this.getVariable("currentTiddler"),
|
event: event,
|
||||||
navigateFromTitle: this.getVariable("storyTiddler"),
|
currentTiddler: this.getVariable("currentTiddler"),
|
||||||
event: event
|
navigateFromTitle: this.getVariable("storyTiddler")
|
||||||
});
|
};
|
||||||
|
this.dispatchEvent(params);
|
||||||
return true; // Action was invoked
|
return true; // Action was invoked
|
||||||
};
|
};
|
||||||
|
|
||||||
|
86
core/modules/widgets/action-setmultiplefields.js
Normal file
86
core/modules/widgets/action-setmultiplefields.js
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/widgets/action-setmultiplefields.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: widget
|
||||||
|
|
||||||
|
Action widget to set multiple fields or indexes on a tiddler
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||||
|
|
||||||
|
var SetMultipleFieldsWidget = function(parseTreeNode,options) {
|
||||||
|
this.initialise(parseTreeNode,options);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Inherit from the base widget class
|
||||||
|
*/
|
||||||
|
SetMultipleFieldsWidget.prototype = new Widget();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Render this widget into the DOM
|
||||||
|
*/
|
||||||
|
SetMultipleFieldsWidget.prototype.render = function(parent,nextSibling) {
|
||||||
|
this.computeAttributes();
|
||||||
|
this.execute();
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Compute the internal state of the widget
|
||||||
|
*/
|
||||||
|
SetMultipleFieldsWidget.prototype.execute = function() {
|
||||||
|
this.actionTiddler = this.getAttribute("$tiddler",this.getVariable("currentTiddler"));
|
||||||
|
this.actionFields = this.getAttribute("$fields");
|
||||||
|
this.actionIndexes = this.getAttribute("$indexes");
|
||||||
|
this.actionValues = this.getAttribute("$values");
|
||||||
|
this.actionTimestamp = this.getAttribute("$timestamp","yes") === "yes";
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Refresh the widget by ensuring our attributes are up to date
|
||||||
|
*/
|
||||||
|
SetMultipleFieldsWidget.prototype.refresh = function(changedTiddlers) {
|
||||||
|
var changedAttributes = this.computeAttributes();
|
||||||
|
if(changedAttributes["$tiddler"] || changedAttributes["$fields"] || changedAttributes["$indexes"] || changedAttributes["$values"] || changedAttributes["$timestamp"]) {
|
||||||
|
this.refreshSelf();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return this.refreshChildren(changedTiddlers);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Invoke the action associated with this widget
|
||||||
|
*/
|
||||||
|
SetMultipleFieldsWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||||
|
var tiddler = this.wiki.getTiddler(this.actionTiddler),
|
||||||
|
names, values = this.wiki.filterTiddlers(this.actionValues,this);
|
||||||
|
if(this.actionFields) {
|
||||||
|
var additions = {};
|
||||||
|
names = this.wiki.filterTiddlers(this.actionFields,this);
|
||||||
|
$tw.utils.each(names,function(fieldname,index) {
|
||||||
|
additions[fieldname] = values[index] || "";
|
||||||
|
});
|
||||||
|
var creationFields = this.actionTimestamp ? this.wiki.getCreationFields() : undefined,
|
||||||
|
modificationFields = this.actionTimestamp ? this.wiki.getModificationFields() : undefined;
|
||||||
|
this.wiki.addTiddler(new $tw.Tiddler(creationFields,tiddler,{title: this.actionTiddler},modificationFields,additions));
|
||||||
|
} else if(this.actionIndexes) {
|
||||||
|
var data = this.wiki.getTiddlerData(this.actionTiddler,Object.create(null));
|
||||||
|
names = this.wiki.filterTiddlers(this.actionIndexes,this);
|
||||||
|
$tw.utils.each(names,function(name,index) {
|
||||||
|
data[name] = values[index] || "";
|
||||||
|
});
|
||||||
|
this.wiki.setTiddlerData(this.actionTiddler,data,{},{suppressTimestamp: !this.actionTimestamp});
|
||||||
|
}
|
||||||
|
return true; // Action was invoked
|
||||||
|
};
|
||||||
|
|
||||||
|
exports["action-setmultiplefields"] = SetMultipleFieldsWidget;
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
@ -54,6 +54,7 @@ DraggableWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
dragFilterFn: function() {return self.getAttribute("filter");},
|
dragFilterFn: function() {return self.getAttribute("filter");},
|
||||||
startActions: self.startActions,
|
startActions: self.startActions,
|
||||||
endActions: self.endActions,
|
endActions: self.endActions,
|
||||||
|
dragImageType: self.dragImageType,
|
||||||
widget: this
|
widget: this
|
||||||
});
|
});
|
||||||
// Insert the link into the DOM and render any children
|
// Insert the link into the DOM and render any children
|
||||||
@ -71,6 +72,7 @@ DraggableWidget.prototype.execute = function() {
|
|||||||
this.draggableClasses = this.getAttribute("class");
|
this.draggableClasses = this.getAttribute("class");
|
||||||
this.startActions = this.getAttribute("startactions");
|
this.startActions = this.getAttribute("startactions");
|
||||||
this.endActions = this.getAttribute("endactions");
|
this.endActions = this.getAttribute("endactions");
|
||||||
|
this.dragImageType = this.getAttribute("dragimagetype");
|
||||||
// Make the child widgets
|
// Make the child widgets
|
||||||
this.makeChildWidgets();
|
this.makeChildWidgets();
|
||||||
};
|
};
|
||||||
|
@ -12,6 +12,8 @@ Dropzone widget
|
|||||||
/*global $tw: false */
|
/*global $tw: false */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
var IMPORT_TITLE = "$:/Import";
|
||||||
|
|
||||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||||
|
|
||||||
var DropZoneWidget = function(parseTreeNode,options) {
|
var DropZoneWidget = function(parseTreeNode,options) {
|
||||||
@ -35,6 +37,7 @@ DropZoneWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
this.execute();
|
this.execute();
|
||||||
// Create element
|
// Create element
|
||||||
var domNode = this.document.createElement("div");
|
var domNode = this.document.createElement("div");
|
||||||
|
this.domNode = domNode;
|
||||||
domNode.className = this.dropzoneClass || "tc-dropzone";
|
domNode.className = this.dropzoneClass || "tc-dropzone";
|
||||||
// Add event handlers
|
// Add event handlers
|
||||||
if(this.dropzoneEnable) {
|
if(this.dropzoneEnable) {
|
||||||
@ -47,8 +50,6 @@ DropZoneWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
{name: "dragend", handlerObject: this, handlerMethod: "handleDragEndEvent"}
|
{name: "dragend", handlerObject: this, handlerMethod: "handleDragEndEvent"}
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
domNode.addEventListener("click",function (event) {
|
|
||||||
},false);
|
|
||||||
// Insert element
|
// Insert element
|
||||||
parent.insertBefore(domNode,nextSibling);
|
parent.insertBefore(domNode,nextSibling);
|
||||||
this.renderChildren(domNode,null);
|
this.renderChildren(domNode,null);
|
||||||
@ -57,12 +58,46 @@ DropZoneWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
this.currentlyEntered = [];
|
this.currentlyEntered = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handler for transient event listeners added when the dropzone has an active drag in progress
|
||||||
|
DropZoneWidget.prototype.handleEvent = function(event) {
|
||||||
|
if(event.type === "click") {
|
||||||
|
if(this.currentlyEntered.length) {
|
||||||
|
this.resetState();
|
||||||
|
}
|
||||||
|
} else if(event.type === "dragenter") {
|
||||||
|
if(event.target && event.target !== this.domNode && !$tw.utils.domContains(this.domNode,event.target)) {
|
||||||
|
this.resetState();
|
||||||
|
}
|
||||||
|
} else if(event.type === "dragleave") {
|
||||||
|
// Check if drag left the window
|
||||||
|
if(event.relatedTarget === null || (event.relatedTarget && event.relatedTarget.nodeName === "HTML")) {
|
||||||
|
this.resetState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Reset the state of the dropzone after a drag has ended
|
||||||
|
DropZoneWidget.prototype.resetState = function() {
|
||||||
|
$tw.utils.removeClass(this.domNode,"tc-dragover");
|
||||||
|
this.currentlyEntered = [];
|
||||||
|
this.document.body.removeEventListener("click",this,true);
|
||||||
|
this.document.body.removeEventListener("dragenter",this,true);
|
||||||
|
this.document.body.removeEventListener("dragleave",this,true);
|
||||||
|
this.dragInProgress = false;
|
||||||
|
};
|
||||||
|
|
||||||
DropZoneWidget.prototype.enterDrag = function(event) {
|
DropZoneWidget.prototype.enterDrag = function(event) {
|
||||||
if(this.currentlyEntered.indexOf(event.target) === -1) {
|
if(this.currentlyEntered.indexOf(event.target) === -1) {
|
||||||
this.currentlyEntered.push(event.target);
|
this.currentlyEntered.push(event.target);
|
||||||
}
|
}
|
||||||
|
if(!this.dragInProgress) {
|
||||||
|
this.dragInProgress = true;
|
||||||
// If we're entering for the first time we need to apply highlighting
|
// If we're entering for the first time we need to apply highlighting
|
||||||
$tw.utils.addClass(this.domNodes[0],"tc-dragover");
|
$tw.utils.addClass(this.domNodes[0],"tc-dragover");
|
||||||
|
this.document.body.addEventListener("click",this,true);
|
||||||
|
this.document.body.addEventListener("dragenter",this,true);
|
||||||
|
this.document.body.addEventListener("dragleave",this,true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
DropZoneWidget.prototype.leaveDrag = function(event) {
|
DropZoneWidget.prototype.leaveDrag = function(event) {
|
||||||
@ -72,15 +107,17 @@ DropZoneWidget.prototype.leaveDrag = function(event) {
|
|||||||
}
|
}
|
||||||
// Remove highlighting if we're leaving externally
|
// Remove highlighting if we're leaving externally
|
||||||
if(this.currentlyEntered.length === 0) {
|
if(this.currentlyEntered.length === 0) {
|
||||||
$tw.utils.removeClass(this.domNodes[0],"tc-dragover");
|
this.resetState();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
DropZoneWidget.prototype.handleDragEnterEvent = function(event) {
|
DropZoneWidget.prototype.handleDragEnterEvent = function(event) {
|
||||||
// Check for this window being the source of the drag
|
|
||||||
if($tw.dragInProgress) {
|
if($tw.dragInProgress) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if(this.filesOnly && !$tw.utils.dragEventContainsFiles(event)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
this.enterDrag(event);
|
this.enterDrag(event);
|
||||||
// Tell the browser that we're ready to handle the drop
|
// Tell the browser that we're ready to handle the drop
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@ -99,7 +136,10 @@ DropZoneWidget.prototype.handleDragOverEvent = function(event) {
|
|||||||
}
|
}
|
||||||
// Tell the browser that we're still interested in the drop
|
// Tell the browser that we're still interested in the drop
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
// Check if this is a synthetic event, IE does not allow accessing dropEffect outside of original event handler
|
||||||
|
if(event.isTrusted) {
|
||||||
event.dataTransfer.dropEffect = "copy"; // Explicitly show this is a copy
|
event.dataTransfer.dropEffect = "copy"; // Explicitly show this is a copy
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
DropZoneWidget.prototype.handleDragLeaveEvent = function(event) {
|
DropZoneWidget.prototype.handleDragLeaveEvent = function(event) {
|
||||||
@ -107,13 +147,41 @@ DropZoneWidget.prototype.handleDragLeaveEvent = function(event) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
DropZoneWidget.prototype.handleDragEndEvent = function(event) {
|
DropZoneWidget.prototype.handleDragEndEvent = function(event) {
|
||||||
$tw.utils.removeClass(this.domNodes[0],"tc-dragover");
|
this.resetState();
|
||||||
|
};
|
||||||
|
|
||||||
|
DropZoneWidget.prototype.filterByContentTypes = function(tiddlerFieldsArray) {
|
||||||
|
var filteredTypes,
|
||||||
|
filtered = [],
|
||||||
|
types = [];
|
||||||
|
$tw.utils.each(tiddlerFieldsArray,function(tiddlerFields) {
|
||||||
|
types.push(tiddlerFields.type || "");
|
||||||
|
});
|
||||||
|
filteredTypes = this.wiki.filterTiddlers(this.contentTypesFilter,this,this.wiki.makeTiddlerIterator(types));
|
||||||
|
$tw.utils.each(tiddlerFieldsArray,function(tiddlerFields) {
|
||||||
|
if(filteredTypes.indexOf(tiddlerFields.type) !== -1) {
|
||||||
|
filtered.push(tiddlerFields);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return filtered;
|
||||||
|
};
|
||||||
|
|
||||||
|
DropZoneWidget.prototype.readFileCallback = function(tiddlerFieldsArray) {
|
||||||
|
if(this.contentTypesFilter) {
|
||||||
|
tiddlerFieldsArray = this.filterByContentTypes(tiddlerFieldsArray);
|
||||||
|
}
|
||||||
|
if(tiddlerFieldsArray.length) {
|
||||||
|
this.dispatchEvent({type: "tm-import-tiddlers", param: JSON.stringify(tiddlerFieldsArray), autoOpenOnImport: this.autoOpenOnImport, importTitle: this.importTitle});
|
||||||
|
if(this.actions) {
|
||||||
|
this.invokeActionString(this.actions,this,event,{importTitle: this.importTitle});
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
DropZoneWidget.prototype.handleDropEvent = function(event) {
|
DropZoneWidget.prototype.handleDropEvent = function(event) {
|
||||||
var self = this,
|
var self = this,
|
||||||
readFileCallback = function(tiddlerFieldsArray) {
|
readFileCallback = function(tiddlerFieldsArray) {
|
||||||
self.dispatchEvent({type: "tm-import-tiddlers", param: JSON.stringify(tiddlerFieldsArray), autoOpenOnImport: self.autoOpenOnImport, importTitle: self.importTitle});
|
self.readFileCallback(tiddlerFieldsArray);
|
||||||
};
|
};
|
||||||
this.leaveDrag(event);
|
this.leaveDrag(event);
|
||||||
// Check for being over a TEXTAREA or INPUT
|
// Check for being over a TEXTAREA or INPUT
|
||||||
@ -127,7 +195,7 @@ DropZoneWidget.prototype.handleDropEvent = function(event) {
|
|||||||
var self = this,
|
var self = this,
|
||||||
dataTransfer = event.dataTransfer;
|
dataTransfer = event.dataTransfer;
|
||||||
// Remove highlighting
|
// Remove highlighting
|
||||||
$tw.utils.removeClass(this.domNodes[0],"tc-dragover");
|
this.resetState();
|
||||||
// Import any files in the drop
|
// Import any files in the drop
|
||||||
var numFiles = 0;
|
var numFiles = 0;
|
||||||
if(dataTransfer.files) {
|
if(dataTransfer.files) {
|
||||||
@ -138,7 +206,23 @@ DropZoneWidget.prototype.handleDropEvent = function(event) {
|
|||||||
}
|
}
|
||||||
// Try to import the various data types we understand
|
// Try to import the various data types we understand
|
||||||
if(numFiles === 0) {
|
if(numFiles === 0) {
|
||||||
$tw.utils.importDataTransfer(dataTransfer,this.wiki.generateNewTitle("Untitled"),readFileCallback);
|
var fallbackTitle = self.wiki.generateNewTitle("Untitled");
|
||||||
|
//Use the deserializer specified if any
|
||||||
|
if(this.dropzoneDeserializer) {
|
||||||
|
for(var t= 0; t<dataTransfer.items.length; t++) {
|
||||||
|
var item = dataTransfer.items[t];
|
||||||
|
if(item.kind === "string") {
|
||||||
|
item.getAsString(function(str){
|
||||||
|
var tiddlerFields = self.wiki.deserializeTiddlers(null,str,{title: fallbackTitle},{deserializer:self.dropzoneDeserializer});
|
||||||
|
if(tiddlerFields && tiddlerFields.length) {
|
||||||
|
readFileCallback(tiddlerFields);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$tw.utils.importDataTransfer(dataTransfer,fallbackTitle,readFileCallback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Tell the browser that we handled the drop
|
// Tell the browser that we handled the drop
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@ -149,7 +233,7 @@ DropZoneWidget.prototype.handleDropEvent = function(event) {
|
|||||||
DropZoneWidget.prototype.handlePasteEvent = function(event) {
|
DropZoneWidget.prototype.handlePasteEvent = function(event) {
|
||||||
var self = this,
|
var self = this,
|
||||||
readFileCallback = function(tiddlerFieldsArray) {
|
readFileCallback = function(tiddlerFieldsArray) {
|
||||||
self.dispatchEvent({type: "tm-import-tiddlers", param: JSON.stringify(tiddlerFieldsArray), autoOpenOnImport: self.autoOpenOnImport, importTitle: self.importTitle});
|
self.readFileCallback(tiddlerFieldsArray);
|
||||||
};
|
};
|
||||||
// Let the browser handle it if we're in a textarea or input box
|
// Let the browser handle it if we're in a textarea or input box
|
||||||
if(["TEXTAREA","INPUT"].indexOf(event.target.tagName) == -1 && !event.target.isContentEditable) {
|
if(["TEXTAREA","INPUT"].indexOf(event.target.tagName) == -1 && !event.target.isContentEditable) {
|
||||||
@ -166,9 +250,17 @@ DropZoneWidget.prototype.handlePasteEvent = function(event) {
|
|||||||
});
|
});
|
||||||
} else if(item.kind === "string") {
|
} else if(item.kind === "string") {
|
||||||
// Create tiddlers from string items
|
// Create tiddlers from string items
|
||||||
var type = item.type;
|
var tiddlerFields,
|
||||||
|
type = item.type;
|
||||||
item.getAsString(function(str) {
|
item.getAsString(function(str) {
|
||||||
var tiddlerFields = {
|
// Use the deserializer specified if any
|
||||||
|
if(self.dropzoneDeserializer) {
|
||||||
|
tiddlerFields = self.wiki.deserializeTiddlers(null,str,{title: self.wiki.generateNewTitle("Untitled")},{deserializer:self.dropzoneDeserializer});
|
||||||
|
if(tiddlerFields && tiddlerFields.length) {
|
||||||
|
readFileCallback(tiddlerFields);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tiddlerFields = {
|
||||||
title: self.wiki.generateNewTitle("Untitled"),
|
title: self.wiki.generateNewTitle("Untitled"),
|
||||||
text: str,
|
text: str,
|
||||||
type: type
|
type: type
|
||||||
@ -176,7 +268,8 @@ DropZoneWidget.prototype.handlePasteEvent = function(event) {
|
|||||||
if($tw.log.IMPORT) {
|
if($tw.log.IMPORT) {
|
||||||
console.log("Importing string '" + str + "', type: '" + type + "'");
|
console.log("Importing string '" + str + "', type: '" + type + "'");
|
||||||
}
|
}
|
||||||
self.dispatchEvent({type: "tm-import-tiddlers", param: JSON.stringify([tiddlerFields]), autoOpenOnImport: self.autoOpenOnImport, importTitle: self.importTitle});
|
readFileCallback([tiddlerFields]);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -194,7 +287,10 @@ DropZoneWidget.prototype.execute = function() {
|
|||||||
this.dropzoneDeserializer = this.getAttribute("deserializer");
|
this.dropzoneDeserializer = this.getAttribute("deserializer");
|
||||||
this.dropzoneEnable = (this.getAttribute("enable") || "yes") === "yes";
|
this.dropzoneEnable = (this.getAttribute("enable") || "yes") === "yes";
|
||||||
this.autoOpenOnImport = this.getAttribute("autoOpenOnImport");
|
this.autoOpenOnImport = this.getAttribute("autoOpenOnImport");
|
||||||
this.importTitle = this.getAttribute("importTitle");
|
this.importTitle = this.getAttribute("importTitle",IMPORT_TITLE);
|
||||||
|
this.actions = this.getAttribute("actions");
|
||||||
|
this.contentTypesFilter = this.getAttribute("contentTypesFilter");
|
||||||
|
this.filesOnly = this.getAttribute("filesOnly","no") === "yes";
|
||||||
// Make child widgets
|
// Make child widgets
|
||||||
this.makeChildWidgets();
|
this.makeChildWidgets();
|
||||||
};
|
};
|
||||||
@ -204,7 +300,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
|||||||
*/
|
*/
|
||||||
DropZoneWidget.prototype.refresh = function(changedTiddlers) {
|
DropZoneWidget.prototype.refresh = function(changedTiddlers) {
|
||||||
var changedAttributes = this.computeAttributes();
|
var changedAttributes = this.computeAttributes();
|
||||||
if(changedAttributes.enable || changedAttributes.autoOpenOnImport || changedAttributes.importTitle || changedAttributes.deserializer || changedAttributes.class) {
|
if($tw.utils.count(changedAttributes) > 0) {
|
||||||
this.refreshSelf();
|
this.refreshSelf();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -46,18 +46,25 @@ EventWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
$tw.utils.each(this.types,function(type) {
|
$tw.utils.each(this.types,function(type) {
|
||||||
domNode.addEventListener(type,function(event) {
|
domNode.addEventListener(type,function(event) {
|
||||||
var selector = self.getAttribute("selector"),
|
var selector = self.getAttribute("selector"),
|
||||||
actions = self.getAttribute("actions-"+type),
|
actions = self.getAttribute("$"+type) || self.getAttribute("actions-"+type),
|
||||||
|
stopPropagation = self.getAttribute("stopPropagation","onaction"),
|
||||||
selectedNode = event.target,
|
selectedNode = event.target,
|
||||||
selectedNodeRect,
|
selectedNodeRect,
|
||||||
catcherNodeRect,
|
catcherNodeRect,
|
||||||
variables = {};
|
variables = {};
|
||||||
|
// Firefox can fire dragover and dragenter events on text nodes instead of their parents
|
||||||
|
if(selectedNode.nodeType === 3) {
|
||||||
|
selectedNode = selectedNode.parentNode;
|
||||||
|
}
|
||||||
if(selector) {
|
if(selector) {
|
||||||
// Search ancestors for a node that matches the selector
|
// Search ancestors for a node that matches the selector
|
||||||
while(!selectedNode.matches(selector) && selectedNode !== domNode) {
|
while(!$tw.utils.domMatchesSelector(selectedNode,selector) && selectedNode !== domNode) {
|
||||||
selectedNode = selectedNode.parentNode;
|
selectedNode = selectedNode.parentNode;
|
||||||
}
|
}
|
||||||
// If we found one, copy the attributes as variables, otherwise exit
|
// If we found one, copy the attributes as variables, otherwise exit
|
||||||
if(selectedNode.matches(selector)) {
|
if($tw.utils.domMatchesSelector(selectedNode,selector)) {
|
||||||
|
// Only set up variables if we have actions to invoke
|
||||||
|
if(actions) {
|
||||||
$tw.utils.each(selectedNode.attributes,function(attribute) {
|
$tw.utils.each(selectedNode.attributes,function(attribute) {
|
||||||
variables["dom-" + attribute.name] = attribute.value.toString();
|
variables["dom-" + attribute.name] = attribute.value.toString();
|
||||||
});
|
});
|
||||||
@ -70,6 +77,7 @@ EventWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
variables["tv-selectednode-width"] = selectedNode.offsetWidth.toString();
|
variables["tv-selectednode-width"] = selectedNode.offsetWidth.toString();
|
||||||
variables["tv-selectednode-height"] = selectedNode.offsetHeight.toString();
|
variables["tv-selectednode-height"] = selectedNode.offsetHeight.toString();
|
||||||
|
|
||||||
|
if(event.clientX && event.clientY) {
|
||||||
//Add variables for event X and Y position relative to selected node
|
//Add variables for event X and Y position relative to selected node
|
||||||
selectedNodeRect = selectedNode.getBoundingClientRect();
|
selectedNodeRect = selectedNode.getBoundingClientRect();
|
||||||
variables["event-fromselected-posx"] = (event.clientX - selectedNodeRect.left).toString();
|
variables["event-fromselected-posx"] = (event.clientX - selectedNodeRect.left).toString();
|
||||||
@ -79,6 +87,12 @@ EventWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
catcherNodeRect = self.domNode.getBoundingClientRect();
|
catcherNodeRect = self.domNode.getBoundingClientRect();
|
||||||
variables["event-fromcatcher-posx"] = (event.clientX - catcherNodeRect.left).toString();
|
variables["event-fromcatcher-posx"] = (event.clientX - catcherNodeRect.left).toString();
|
||||||
variables["event-fromcatcher-posy"] = (event.clientY - catcherNodeRect.top).toString();
|
variables["event-fromcatcher-posy"] = (event.clientY - catcherNodeRect.top).toString();
|
||||||
|
|
||||||
|
//Add variables for event X and Y position relative to the viewport
|
||||||
|
variables["event-fromviewport-posx"] = event.clientX.toString();
|
||||||
|
variables["event-fromviewport-posy"] = event.clientY.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -106,6 +120,8 @@ EventWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
variables["event-detail"] = event.detail.toString();
|
variables["event-detail"] = event.detail.toString();
|
||||||
}
|
}
|
||||||
self.invokeActionString(actions,self,event,variables);
|
self.invokeActionString(actions,self,event,variables);
|
||||||
|
}
|
||||||
|
if((actions && stopPropagation === "onaction") || stopPropagation === "always") {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
return true;
|
return true;
|
||||||
@ -125,7 +141,15 @@ Compute the internal state of the widget
|
|||||||
EventWidget.prototype.execute = function() {
|
EventWidget.prototype.execute = function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
// Get attributes that require a refresh on change
|
// Get attributes that require a refresh on change
|
||||||
|
this.types = [];
|
||||||
|
$tw.utils.each(this.attributes,function(value,key) {
|
||||||
|
if(key.charAt(0) === "$") {
|
||||||
|
self.types.push(key.slice(1));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(!this.types.length) {
|
||||||
this.types = this.getAttribute("events","").split(" ");
|
this.types = this.getAttribute("events","").split(" ");
|
||||||
|
}
|
||||||
this.elementTag = this.getAttribute("tag");
|
this.elementTag = this.getAttribute("tag");
|
||||||
// Make child widgets
|
// Make child widgets
|
||||||
this.makeChildWidgets();
|
this.makeChildWidgets();
|
||||||
@ -141,12 +165,13 @@ EventWidget.prototype.assignDomNodeClasses = function() {
|
|||||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||||
*/
|
*/
|
||||||
EventWidget.prototype.refresh = function(changedTiddlers) {
|
EventWidget.prototype.refresh = function(changedTiddlers) {
|
||||||
var changedAttributes = this.computeAttributes();
|
var changedAttributes = this.computeAttributes(),
|
||||||
if(changedAttributes["events"] || changedAttributes["tag"]) {
|
changedAttributesCount = $tw.utils.count(changedAttributes);
|
||||||
|
if(changedAttributesCount === 1 && changedAttributes["class"]) {
|
||||||
|
this.assignDomNodeClasses();
|
||||||
|
} else if(changedAttributesCount > 0) {
|
||||||
this.refreshSelf();
|
this.refreshSelf();
|
||||||
return true;
|
return true;
|
||||||
} else if(changedAttributes["class"]) {
|
|
||||||
this.assignDomNodeClasses();
|
|
||||||
}
|
}
|
||||||
return this.refreshChildren(changedTiddlers);
|
return this.refreshChildren(changedTiddlers);
|
||||||
};
|
};
|
||||||
|
@ -67,32 +67,18 @@ FieldManglerWidget.prototype.handleRemoveFieldEvent = function(event) {
|
|||||||
deletion = {};
|
deletion = {};
|
||||||
deletion[event.param] = undefined;
|
deletion[event.param] = undefined;
|
||||||
this.wiki.addTiddler(new $tw.Tiddler(tiddler,deletion));
|
this.wiki.addTiddler(new $tw.Tiddler(tiddler,deletion));
|
||||||
return true;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
FieldManglerWidget.prototype.handleAddFieldEvent = function(event) {
|
FieldManglerWidget.prototype.handleAddFieldEvent = function(event) {
|
||||||
var tiddler = this.wiki.getTiddler(this.mangleTitle),
|
var tiddler = this.wiki.getTiddler(this.mangleTitle),
|
||||||
addition = this.wiki.getModificationFields(),
|
addition = this.wiki.getModificationFields(),
|
||||||
hadInvalidFieldName = false,
|
|
||||||
addField = function(name,value) {
|
addField = function(name,value) {
|
||||||
var trimmedName = name.toLowerCase().trim();
|
var trimmedName = name.trim();
|
||||||
if(!$tw.utils.isValidFieldName(trimmedName)) {
|
|
||||||
if(!hadInvalidFieldName) {
|
|
||||||
alert($tw.language.getString(
|
|
||||||
"InvalidFieldName",
|
|
||||||
{variables:
|
|
||||||
{fieldName: trimmedName}
|
|
||||||
}
|
|
||||||
));
|
|
||||||
hadInvalidFieldName = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(!value && tiddler) {
|
if(!value && tiddler) {
|
||||||
value = tiddler.fields[trimmedName];
|
value = tiddler.fields[trimmedName];
|
||||||
}
|
}
|
||||||
addition[trimmedName] = value || "";
|
addition[trimmedName] = value || "";
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
addition.title = this.mangleTitle;
|
addition.title = this.mangleTitle;
|
||||||
@ -105,7 +91,7 @@ FieldManglerWidget.prototype.handleAddFieldEvent = function(event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.wiki.addTiddler(new $tw.Tiddler(tiddler,addition));
|
this.wiki.addTiddler(new $tw.Tiddler(tiddler,addition));
|
||||||
return true;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
FieldManglerWidget.prototype.handleRemoveTagEvent = function(event) {
|
FieldManglerWidget.prototype.handleRemoveTagEvent = function(event) {
|
||||||
@ -122,7 +108,7 @@ FieldManglerWidget.prototype.handleRemoveTagEvent = function(event) {
|
|||||||
this.wiki.addTiddler(new $tw.Tiddler(tiddler,modification));
|
this.wiki.addTiddler(new $tw.Tiddler(tiddler,modification));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
FieldManglerWidget.prototype.handleAddTagEvent = function(event) {
|
FieldManglerWidget.prototype.handleAddTagEvent = function(event) {
|
||||||
@ -140,7 +126,7 @@ FieldManglerWidget.prototype.handleAddTagEvent = function(event) {
|
|||||||
tag.push(event.param.trim());
|
tag.push(event.param.trim());
|
||||||
this.wiki.addTiddler(new $tw.Tiddler({title: this.mangleTitle, tags: tag},modification));
|
this.wiki.addTiddler(new $tw.Tiddler({title: this.mangleTitle, tags: tag},modification));
|
||||||
}
|
}
|
||||||
return true;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.fieldmangler = FieldManglerWidget;
|
exports.fieldmangler = FieldManglerWidget;
|
||||||
|
91
core/modules/widgets/jsontiddler.js
Normal file
91
core/modules/widgets/jsontiddler.js
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/widgets/jsontiddler.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: widget
|
||||||
|
|
||||||
|
Render a tiddler as JSON text
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||||
|
|
||||||
|
var JSONTiddlerWidget = function(parseTreeNode,options) {
|
||||||
|
this.initialise(parseTreeNode,options);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Inherit from the base widget class
|
||||||
|
*/
|
||||||
|
JSONTiddlerWidget.prototype = new Widget();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Render this widget into the DOM
|
||||||
|
*/
|
||||||
|
JSONTiddlerWidget.prototype.render = function(parent,nextSibling) {
|
||||||
|
var self = this;
|
||||||
|
this.parentDomNode = parent;
|
||||||
|
this.computeAttributes();
|
||||||
|
this.execute();
|
||||||
|
// Collect the fields from the optional base tiddler
|
||||||
|
var fields = this.getTiddlerFields();
|
||||||
|
// Add custom fields specified in attributes starting with $
|
||||||
|
$tw.utils.each(this.attributes,function(attribute,name) {
|
||||||
|
if(name.charAt(0) === "$") {
|
||||||
|
fields[name.slice(1)] = attribute;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// JSONify
|
||||||
|
var json = JSON.stringify(fields);
|
||||||
|
// Escape unsafe script characters
|
||||||
|
if(this.attEscapeUnsafeScriptChars) {
|
||||||
|
json = json.replace(/</g,"\\u003C");
|
||||||
|
}
|
||||||
|
// Update the DOM
|
||||||
|
var textNode = this.document.createTextNode(json);
|
||||||
|
parent.insertBefore(textNode,nextSibling);
|
||||||
|
this.domNodes.push(textNode);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Compute the internal state of the widget
|
||||||
|
*/
|
||||||
|
JSONTiddlerWidget.prototype.execute = function() {
|
||||||
|
this.attTiddler = this.getAttribute("tiddler");
|
||||||
|
this.attExclude = this.getAttribute("exclude","");
|
||||||
|
this.attEscapeUnsafeScriptChars = this.getAttribute("escapeUnsafeScriptChars","no") === "yes";
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||||
|
*/
|
||||||
|
JSONTiddlerWidget.prototype.refresh = function(changedTiddlers) {
|
||||||
|
var changedAttributes = this.computeAttributes();
|
||||||
|
if($tw.utils.count(changedAttributes) > 0 || (this.attTiddler && changedTiddlers[this.attTiddler])) {
|
||||||
|
this.refreshSelf();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
JSONTiddlerWidget.prototype.getTiddlerFields = function() {
|
||||||
|
var fields = {};
|
||||||
|
if(this.attTiddler) {
|
||||||
|
var tiddler = this.wiki.getTiddler(this.attTiddler);
|
||||||
|
if(tiddler) {
|
||||||
|
fields = tiddler.getFieldStrings({exclude: this.attExclude.split(" ")});
|
||||||
|
} else {
|
||||||
|
fields = {title: this.attTiddler};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fields;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.jsontiddler = JSONTiddlerWidget;
|
||||||
|
|
||||||
|
})();
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user