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();
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
120
boot/boot.js
120
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,8 +1234,12 @@ $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];
|
||||||
var shadowInfo = shadowTiddlers[title];
|
if(tiddlers[title]) {
|
||||||
callback(shadowInfo.tiddler,title);
|
callback(tiddlers[title],title);
|
||||||
|
} else {
|
||||||
|
var shadowInfo = shadowTiddlers[title];
|
||||||
|
callback(shadowInfo.tiddler,title);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -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,13 +1755,20 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/dom","tiddlerdeserializer",{
|
|||||||
},
|
},
|
||||||
t,result = [];
|
t,result = [];
|
||||||
if(node) {
|
if(node) {
|
||||||
for(t = 0; t < node.childNodes.length; t++) {
|
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++) {
|
||||||
var childNode = node.childNodes[t],
|
var childNode = node.childNodes[t],
|
||||||
tiddlers = extractTextTiddlers(childNode);
|
tiddlers = extractTextTiddlers(childNode);
|
||||||
tiddlers = tiddlers || extractModuleTiddlers(childNode);
|
tiddlers = tiddlers || extractModuleTiddlers(childNode);
|
||||||
if(tiddlers) {
|
if(tiddlers) {
|
||||||
result.push.apply(result,tiddlers);
|
result.push.apply(result,tiddlers);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -1739,17 +1777,23 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/dom","tiddlerdeserializer",{
|
|||||||
|
|
||||||
$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,16 +2526,29 @@ $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]) {
|
||||||
return false;
|
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 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.
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ Notes:
|
|||||||
|
|
||||||
* The output directory is not cleared of any existing files
|
* The output directory is not cleared of any existing files
|
||||||
* Any missing directories in the path to the filename are automatically created.
|
* Any missing directories in the path to the filename are automatically created.
|
||||||
* When referring to a tiddler with spaces in its title, take care to use both the quotes required by your shell and also TiddlyWiki's double square brackets : `--render "[[Motovun Jack.jpg]]"`
|
* When referring to a tiddler with spaces in its title, take care to use both the quotes required by your shell and also TiddlyWiki's double square brackets: `--render "[[Motovun Jack.jpg]]"`
|
||||||
* The filename filter is evaluated with the selected items being set to the title of the tiddler currently being rendered, allowing the title to be used as the basis for computing the filename. For example `[encodeuricomponent[]addprefix[static/]]` applies URI encoding to each title, and then adds the prefix `static/`
|
* The filename filter is evaluated with the selected items being set to the title of the tiddler currently being rendered, allowing the title to be used as the basis for computing the filename. For example `[encodeuricomponent[]addprefix[static/]]` applies URI encoding to each title, and then adds the prefix `static/`
|
||||||
* Multiple ''name''/''value'' pairs can be used to pass more than one variable
|
* Multiple ''name''/''value'' pairs can be used to pass more than one variable
|
||||||
* The `--render` command is a more flexible replacement for both the `--rendertiddler` and `--rendertiddlers` commands, which are deprecated
|
* The `--render` command is a more flexible replacement for both the `--rendertiddler` and `--rendertiddlers` commands, which are deprecated
|
||||||
|
@ -16,7 +16,7 @@ Notes:
|
|||||||
|
|
||||||
* The output directory is not cleared of any existing files
|
* The output directory is not cleared of any existing files
|
||||||
* Any missing directories in the path to the filename are automatically created.
|
* Any missing directories in the path to the filename are automatically created.
|
||||||
* When saving a tiddler with spaces in its title, take care to use both the quotes required by your shell and also TiddlyWiki's double square brackets : `--save "[[Motovun Jack.jpg]]"`
|
* When saving a tiddler with spaces in its title, take care to use both the quotes required by your shell and also TiddlyWiki's double square brackets: `--save "[[Motovun Jack.jpg]]"`
|
||||||
* The filename filter is evaluated with the selected items being set to the title of the tiddler currently being saved, allowing the title to be used as the basis for computing the filename. For example `[encodeuricomponent[]addprefix[static/]]` applies URI encoding to each title, and then adds the prefix `static/`
|
* The filename filter is evaluated with the selected items being set to the title of the tiddler currently being saved, allowing the title to be used as the basis for computing the filename. For example `[encodeuricomponent[]addprefix[static/]]` applies URI encoding to each title, and then adds the prefix `static/`
|
||||||
* The `--save` command is a more flexible replacement for both the `--savetiddler` and `--savetiddlers` commands, which are deprecated
|
* The `--save` command is a more flexible replacement for both the `--savetiddler` and `--savetiddlers` commands, which are deprecated
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -8,58 +8,59 @@ Render individual tiddlers and save the results to the specified files
|
|||||||
\*/
|
\*/
|
||||||
(function(){
|
(function(){
|
||||||
|
|
||||||
/*jslint node: true, browser: true */
|
/*jslint node: true, browser: true */
|
||||||
/*global $tw: false */
|
/*global $tw: false */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var widget = require("$:/core/modules/widgets/widget.js");
|
var widget = require("$:/core/modules/widgets/widget.js");
|
||||||
|
|
||||||
exports.info = {
|
exports.info = {
|
||||||
name: "render",
|
name: "render",
|
||||||
synchronous: true
|
synchronous: true
|
||||||
};
|
};
|
||||||
|
|
||||||
var Command = function(params,commander,callback) {
|
var Command = function(params,commander,callback) {
|
||||||
this.params = params;
|
this.params = params;
|
||||||
this.commander = commander;
|
this.commander = commander;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
Command.prototype.execute = function() {
|
Command.prototype.execute = function() {
|
||||||
if(this.params.length < 1) {
|
if(this.params.length < 1) {
|
||||||
return "Missing tiddler filter";
|
return "Missing tiddler filter";
|
||||||
}
|
|
||||||
var self = this,
|
|
||||||
fs = require("fs"),
|
|
||||||
path = require("path"),
|
|
||||||
wiki = this.commander.wiki,
|
|
||||||
tiddlerFilter = this.params[0],
|
|
||||||
filenameFilter = this.params[1] || "[is[tiddler]addsuffix[.html]]",
|
|
||||||
type = this.params[2] || "text/html",
|
|
||||||
template = this.params[3],
|
|
||||||
variableList = this.params.slice(4),
|
|
||||||
tiddlers = wiki.filterTiddlers(tiddlerFilter),
|
|
||||||
variables = Object.create(null);
|
|
||||||
while(variableList.length >= 2) {
|
|
||||||
variables[variableList[0]] = variableList[1];
|
|
||||||
variableList = variableList.slice(2);
|
|
||||||
}
|
}
|
||||||
$tw.utils.each(tiddlers,function(title) {
|
var self = this,
|
||||||
var parser = wiki.parseTiddler(template || title);
|
fs = require("fs"),
|
||||||
var widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title})}),
|
path = require("path"),
|
||||||
container = $tw.fakeDocument.createElement("div");
|
wiki = this.commander.wiki,
|
||||||
widgetNode.render(container,null);
|
tiddlerFilter = this.params[0],
|
||||||
var text = type === "text/html" ? container.innerHTML : container.textContent,
|
filenameFilter = this.params[1] || "[is[tiddler]addsuffix[.html]]",
|
||||||
filepath = path.resolve(self.commander.outputPath,wiki.filterTiddlers(filenameFilter,$tw.rootWidget,wiki.makeTiddlerIterator([title]))[0]);
|
type = this.params[2] || "text/html",
|
||||||
if(self.commander.verbose) {
|
template = this.params[3],
|
||||||
console.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
|
variableList = this.params.slice(4),
|
||||||
}
|
tiddlers = wiki.filterTiddlers(tiddlerFilter),
|
||||||
$tw.utils.createFileDirectories(filepath);
|
variables = Object.create(null);
|
||||||
fs.writeFileSync(filepath,text,"utf8");
|
while(variableList.length >= 2) {
|
||||||
});
|
variables[variableList[0]] = variableList[1];
|
||||||
return null;
|
variableList = variableList.slice(2);
|
||||||
};
|
}
|
||||||
|
$tw.utils.each(tiddlers,function(title) {
|
||||||
|
var filepath = path.resolve(self.commander.outputPath,wiki.filterTiddlers(filenameFilter,$tw.rootWidget,wiki.makeTiddlerIterator([title]))[0]);
|
||||||
|
if(self.commander.verbose) {
|
||||||
|
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);
|
||||||
|
fs.writeFileSync(filepath,text,"utf8");
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
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) {
|
||||||
this.domNode.value = text;
|
try {
|
||||||
|
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) {
|
||||||
this.domNode.value = text;
|
try {
|
||||||
|
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
|
||||||
value = tiddler.getFieldString(this.editField);
|
if(tiddler.hasField(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] || "");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
@ -19,23 +19,25 @@ exports.reduce = function(operationSubFunction,options) {
|
|||||||
var index = 0;
|
var index = 0;
|
||||||
results.each(function(title) {
|
results.each(function(title) {
|
||||||
var list = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
var list = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
||||||
getVariable: function(name) {
|
getVariable: function(name) {
|
||||||
switch(name) {
|
switch(name) {
|
||||||
case "currentTiddler":
|
case "currentTiddler":
|
||||||
return "" + title;
|
return "" + title;
|
||||||
case "accumulator":
|
case "..currentTiddler":
|
||||||
return "" + accumulator;
|
return widget.getVariable("currentTiddler");
|
||||||
case "index":
|
case "accumulator":
|
||||||
return "" + index;
|
return "" + accumulator;
|
||||||
case "revIndex":
|
case "index":
|
||||||
return "" + (results.length - 1 - index);
|
return "" + index;
|
||||||
case "length":
|
case "revIndex":
|
||||||
return "" + results.length;
|
return "" + (results.length - 1 - index);
|
||||||
default:
|
case "length":
|
||||||
return widget.getVariable(name);
|
return "" + results.length;
|
||||||
}
|
default:
|
||||||
|
return widget.getVariable(name);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
});
|
||||||
if(list.length > 0) {
|
if(list.length > 0) {
|
||||||
accumulator = "" + list[0];
|
accumulator = "" + list[0];
|
||||||
}
|
}
|
||||||
|
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 = [];
|
||||||
source(function(tiddler,title) {
|
if(operator.operands.length >= 2) {
|
||||||
$tw.utils.each($tw.modules.types[title],function(moduleInfo,moduleName) {
|
// Return the modules that have the module property specified in the first operand with the value in the second operand
|
||||||
results.push(moduleName);
|
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) {
|
||||||
|
$tw.utils.each($tw.modules.types[title],function(moduleInfo,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,10 +27,13 @@ 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;
|
||||||
return options.widget.getVariable(name);
|
case "..currentTiddler":
|
||||||
|
return options.widget.getVariable("currentTiddler");
|
||||||
|
default:
|
||||||
|
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,16 +280,20 @@ 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) {
|
||||||
return event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey ? "ctrl" :
|
return event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey ? "ctrl" :
|
||||||
event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey ? "shift" :
|
event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey ? "shift" :
|
||||||
event.ctrlKey && event.shiftKey && !event.altKey && !event.metaKey ? "ctrl-shift" :
|
event.ctrlKey && event.shiftKey && !event.altKey && !event.metaKey ? "ctrl-shift" :
|
||||||
event.altKey && !event.shiftKey && !event.ctrlKey && !event.metaKey ? "alt" :
|
event.altKey && !event.shiftKey && !event.ctrlKey && !event.metaKey ? "alt" :
|
||||||
@ -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,25 +20,29 @@ 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);
|
||||||
fs.readFile(filename,function(err,content) {
|
// Check that the filename is inside the wiki files folder
|
||||||
var status,content,type = "text/plain";
|
if(path.relative(baseFilename,filename).indexOf("..") !== 0) {
|
||||||
if(err) {
|
// Send the file
|
||||||
console.log("Error accessing file " + filename + ": " + err.toString());
|
fs.readFile(filename,function(err,content) {
|
||||||
status = 404;
|
var status,content,type = "text/plain";
|
||||||
content = "File '" + suppliedFilename + "' not found";
|
if(err) {
|
||||||
} else {
|
console.log("Error accessing file " + filename + ": " + err.toString());
|
||||||
status = 200;
|
status = 404;
|
||||||
content = content;
|
content = "File '" + suppliedFilename + "' not found";
|
||||||
type = ($tw.config.fileExtensionInfo[extension] ? $tw.config.fileExtensionInfo[extension].type : "application/octet-stream");
|
} else {
|
||||||
}
|
status = 200;
|
||||||
response.writeHead(status,{
|
content = content;
|
||||||
"Content-Type": type
|
type = ($tw.config.fileExtensionInfo[extension] ? $tw.config.fileExtensionInfo[extension].type : "application/octet-stream");
|
||||||
|
}
|
||||||
|
state.sendResponse(status,{"Content-Type": type},content);
|
||||||
});
|
});
|
||||||
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,7 +947,11 @@ 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) {
|
||||||
return compare("" + a,"" +b);
|
if(!isCaseSensitive) {
|
||||||
|
a = a.toLowerCase();
|
||||||
|
b = b.toLowerCase();
|
||||||
|
}
|
||||||
|
return compare("" + a,"" + b);
|
||||||
},
|
},
|
||||||
"date": function(a,b) {
|
"date": function(a,b) {
|
||||||
var dateA = $tw.utils.parseDate(a),
|
var dateA = $tw.utils.parseDate(a),
|
||||||
@ -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 we're entering for the first time we need to apply highlighting
|
if(!this.dragInProgress) {
|
||||||
$tw.utils.addClass(this.domNodes[0],"tc-dragover");
|
this.dragInProgress = true;
|
||||||
|
// If we're entering for the first time we need to apply highlighting
|
||||||
|
$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();
|
||||||
event.dataTransfer.dropEffect = "copy"; // Explicitly show this is a copy
|
// 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
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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,17 +250,26 @@ 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
|
||||||
title: self.wiki.generateNewTitle("Untitled"),
|
if(self.dropzoneDeserializer) {
|
||||||
text: str,
|
tiddlerFields = self.wiki.deserializeTiddlers(null,str,{title: self.wiki.generateNewTitle("Untitled")},{deserializer:self.dropzoneDeserializer});
|
||||||
type: type
|
if(tiddlerFields && tiddlerFields.length) {
|
||||||
};
|
readFileCallback(tiddlerFields);
|
||||||
if($tw.log.IMPORT) {
|
}
|
||||||
console.log("Importing string '" + str + "', type: '" + type + "'");
|
} else {
|
||||||
|
tiddlerFields = {
|
||||||
|
title: self.wiki.generateNewTitle("Untitled"),
|
||||||
|
text: str,
|
||||||
|
type: type
|
||||||
|
};
|
||||||
|
if($tw.log.IMPORT) {
|
||||||
|
console.log("Importing string '" + str + "', type: '" + type + "'");
|
||||||
|
}
|
||||||
|
readFileCallback([tiddlerFields]);
|
||||||
}
|
}
|
||||||
self.dispatchEvent({type: "tm-import-tiddlers", param: JSON.stringify([tiddlerFields]), autoOpenOnImport: self.autoOpenOnImport, importTitle: self.importTitle});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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,39 +46,53 @@ 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)) {
|
||||||
$tw.utils.each(selectedNode.attributes,function(attribute) {
|
// Only set up variables if we have actions to invoke
|
||||||
variables["dom-" + attribute.name] = attribute.value.toString();
|
if(actions) {
|
||||||
});
|
$tw.utils.each(selectedNode.attributes,function(attribute) {
|
||||||
//Add a variable with a popup coordinate string for the selected node
|
variables["dom-" + attribute.name] = attribute.value.toString();
|
||||||
variables["tv-popup-coords"] = "(" + selectedNode.offsetLeft + "," + selectedNode.offsetTop +"," + selectedNode.offsetWidth + "," + selectedNode.offsetHeight + ")";
|
});
|
||||||
|
//Add a variable with a popup coordinate string for the selected node
|
||||||
|
variables["tv-popup-coords"] = "(" + selectedNode.offsetLeft + "," + selectedNode.offsetTop +"," + selectedNode.offsetWidth + "," + selectedNode.offsetHeight + ")";
|
||||||
|
|
||||||
//Add variables for offset of selected node
|
//Add variables for offset of selected node
|
||||||
variables["tv-selectednode-posx"] = selectedNode.offsetLeft.toString();
|
variables["tv-selectednode-posx"] = selectedNode.offsetLeft.toString();
|
||||||
variables["tv-selectednode-posy"] = selectedNode.offsetTop.toString();
|
variables["tv-selectednode-posy"] = selectedNode.offsetTop.toString();
|
||||||
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();
|
||||||
|
|
||||||
//Add variables for event X and Y position relative to selected node
|
if(event.clientX && event.clientY) {
|
||||||
selectedNodeRect = selectedNode.getBoundingClientRect();
|
//Add variables for event X and Y position relative to selected node
|
||||||
variables["event-fromselected-posx"] = (event.clientX - selectedNodeRect.left).toString();
|
selectedNodeRect = selectedNode.getBoundingClientRect();
|
||||||
variables["event-fromselected-posy"] = (event.clientY - selectedNodeRect.top).toString();
|
variables["event-fromselected-posx"] = (event.clientX - selectedNodeRect.left).toString();
|
||||||
|
variables["event-fromselected-posy"] = (event.clientY - selectedNodeRect.top).toString();
|
||||||
|
|
||||||
//Add variables for event X and Y position relative to event catcher node
|
//Add variables for event X and Y position relative to event catcher node
|
||||||
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 = this.getAttribute("events","").split(" ");
|
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.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);
|
||||||
};
|
};
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user