mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-01-22 10:54:46 +00:00
Compare commits
295 Commits
v0.0.1
...
v5.0.10-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8756d25d78 | ||
|
|
8a27c2759b | ||
|
|
beddcd7138 | ||
|
|
2db90378a2 | ||
|
|
7684891285 | ||
|
|
821f1f1428 | ||
|
|
4538f081ee | ||
|
|
b4122be50c | ||
|
|
cd76514105 | ||
|
|
ba576d9f1b | ||
|
|
15d0c27e2a | ||
|
|
869cec1ccc | ||
|
|
d6054f1039 | ||
|
|
9fbe72a877 | ||
|
|
89165fc51d | ||
|
|
4758874d13 | ||
|
|
0153fd2a30 | ||
|
|
bb42c0ab36 | ||
|
|
95d291daac | ||
|
|
45b0966013 | ||
|
|
de07da3797 | ||
|
|
aebc1ea943 | ||
|
|
73cfd10218 | ||
|
|
d336ffea02 | ||
|
|
6da28e7365 | ||
|
|
d08a2d109f | ||
|
|
f57e047877 | ||
|
|
df5fe10a40 | ||
|
|
433ac8e96e | ||
|
|
ad4b03506a | ||
|
|
ace57dd205 | ||
|
|
bd4a031df8 | ||
|
|
6db94052c7 | ||
|
|
dd8797223a | ||
|
|
e54b0d7129 | ||
|
|
07ab8c75b8 | ||
|
|
0a6077286f | ||
|
|
634e76eb7f | ||
|
|
cd1463cbb0 | ||
|
|
4b8be85b88 | ||
|
|
d01f1020d2 | ||
|
|
f77de37a2f | ||
|
|
f3c5ce7ca4 | ||
|
|
6ed38389b0 | ||
|
|
5393fbee99 | ||
|
|
3b31c6fe3a | ||
|
|
9ba55c7e79 | ||
|
|
9323574efb | ||
|
|
f5cf8cba5c | ||
|
|
88be791e58 | ||
|
|
dad60cda05 | ||
|
|
fe0ed5e4ce | ||
|
|
aa243e4478 | ||
|
|
4c648e7cdc | ||
|
|
0aa559cd23 | ||
|
|
28db76ddb3 | ||
|
|
e366aa3746 | ||
|
|
22a529b28d | ||
|
|
c2d6086bd9 | ||
|
|
f1578d3409 | ||
|
|
93b9d16d6c | ||
|
|
13bb20cad4 | ||
|
|
bba7e97f60 | ||
|
|
cb32d187c5 | ||
|
|
8582e5ebe2 | ||
|
|
46969fbd3e | ||
|
|
260d3ad8c0 | ||
|
|
d9b87055bf | ||
|
|
4f4b743d9c | ||
|
|
ee2cd2056c | ||
|
|
be5f6f6700 | ||
|
|
be7822281a | ||
|
|
3afa26b9a3 | ||
|
|
2a2cc20601 | ||
|
|
400ab3b3c5 | ||
|
|
ebe7587aa0 | ||
|
|
c954ac01fe | ||
|
|
a3cf925e56 | ||
|
|
be7c33dc48 | ||
|
|
634f914610 | ||
|
|
7aaab03e03 | ||
|
|
fd1399f6d9 | ||
|
|
442bc35bcb | ||
|
|
1bc9bf541a | ||
|
|
ccf2cb36a1 | ||
|
|
18d14031b7 | ||
|
|
5fff6fc87f | ||
|
|
5a65898dbe | ||
|
|
cbf45a9982 | ||
|
|
7a4a00f6ca | ||
|
|
dfb367c104 | ||
|
|
7853b7f7b3 | ||
|
|
ccefc1b17b | ||
|
|
6786a1fd14 | ||
|
|
e73d2854f9 | ||
|
|
127cd70769 | ||
|
|
fc407d079c | ||
|
|
df6fe8f852 | ||
|
|
613f413942 | ||
|
|
70a2db34d1 | ||
|
|
5821165ec5 | ||
|
|
4888417a35 | ||
|
|
2aa1acb565 | ||
|
|
e5fe3f76ac | ||
|
|
ef03e5ce63 | ||
|
|
690c8fe9a0 | ||
|
|
6f1e8ee3a1 | ||
|
|
9b52ca7cc0 | ||
|
|
f9a274df85 | ||
|
|
776bf29afc | ||
|
|
f08c4aa525 | ||
|
|
0f07977930 | ||
|
|
362df18a19 | ||
|
|
426281539a | ||
|
|
dc5831a8a8 | ||
|
|
6d43b4e8dc | ||
|
|
3282bd948f | ||
|
|
7ec356ac80 | ||
|
|
688879e6fa | ||
|
|
9bdd7a4e19 | ||
|
|
78f81a6894 | ||
|
|
5ec0775d3e | ||
|
|
c4d0ee11d3 | ||
|
|
597b8ca4b1 | ||
|
|
ea46f85a8a | ||
|
|
1e960ffcac | ||
|
|
8a7d0f53d3 | ||
|
|
b51d851f93 | ||
|
|
e21d558ff0 | ||
|
|
c7b4febae3 | ||
|
|
4d91a7762e | ||
|
|
272a4bbe61 | ||
|
|
b7f674c51a | ||
|
|
14f90b9519 | ||
|
|
2f458e8573 | ||
|
|
3619eb1378 | ||
|
|
9bd626315e | ||
|
|
d3c0296a87 | ||
|
|
e397e4d159 | ||
|
|
93c29bd388 | ||
|
|
7985a808bf | ||
|
|
aced860d52 | ||
|
|
c1bb7b00c1 | ||
|
|
856b68a34d | ||
|
|
1940bd4dce | ||
|
|
d402d3c5a6 | ||
|
|
dcce487934 | ||
|
|
53ca7f6a2f | ||
|
|
c3e24c1228 | ||
|
|
6307293469 | ||
|
|
0d0679de1b | ||
|
|
09214d1c33 | ||
|
|
914a536d82 | ||
|
|
5a085f7927 | ||
|
|
0595619d39 | ||
|
|
776c9a2cad | ||
|
|
36dabd792e | ||
|
|
ec90ac99cf | ||
|
|
299007f08b | ||
|
|
49578bb144 | ||
|
|
ead5e607fa | ||
|
|
5c3c6cd7c0 | ||
|
|
818b29386e | ||
|
|
c0f78df48d | ||
|
|
c58852a67b | ||
|
|
bca1d55280 | ||
|
|
45a362c285 | ||
|
|
355f467465 | ||
|
|
871630be88 | ||
|
|
8b813ccb43 | ||
|
|
59ac38a3da | ||
|
|
80b65b1651 | ||
|
|
7dede861e1 | ||
|
|
514b8e1776 | ||
|
|
79d643775d | ||
|
|
945ad6792f | ||
|
|
7c235566c4 | ||
|
|
d3e178becc | ||
|
|
bc432d5e52 | ||
|
|
fa10801d72 | ||
|
|
87c8478c80 | ||
|
|
535837e017 | ||
|
|
20f6383528 | ||
|
|
26fd460670 | ||
|
|
20d7264e4b | ||
|
|
3ce2159a95 | ||
|
|
968d44e4be | ||
|
|
f46d445ba2 | ||
|
|
1b0a39cd1a | ||
|
|
cb2653aee0 | ||
|
|
34445dcc68 | ||
|
|
54abcdceeb | ||
|
|
cf7554a938 | ||
|
|
fb72b3b859 | ||
|
|
03cfa61ae8 | ||
|
|
4badabce4b | ||
|
|
3cb2b365c5 | ||
|
|
178cfb1084 | ||
|
|
920df5d2d4 | ||
|
|
7b57561160 | ||
|
|
d2a41b8486 | ||
|
|
aa63151815 | ||
|
|
ba6edd42c1 | ||
|
|
7616c4ce7d | ||
|
|
925b3d2a5b | ||
|
|
b8d0fd059b | ||
|
|
a19432541e | ||
|
|
b52299872a | ||
|
|
699b863588 | ||
|
|
bdbbf94326 | ||
|
|
cdf3e101a8 | ||
|
|
06500e5f71 | ||
|
|
9de17aa206 | ||
|
|
279626a3e3 | ||
|
|
721e333a20 | ||
|
|
499730c458 | ||
|
|
baa8cf3dd0 | ||
|
|
f649b5b037 | ||
|
|
afa677b9a0 | ||
|
|
6fe884bb8a | ||
|
|
00af144085 | ||
|
|
5d893397c4 | ||
|
|
42c67cfeb7 | ||
|
|
b714c67374 | ||
|
|
00cb2f4659 | ||
|
|
24b6603c42 | ||
|
|
a82e50c07f | ||
|
|
ebc77fbd09 | ||
|
|
96457d8011 | ||
|
|
3d9f61f041 | ||
|
|
f48701544e | ||
|
|
50cf9678cb | ||
|
|
c4119f4f93 | ||
|
|
cafe74fc89 | ||
|
|
2466389397 | ||
|
|
dd3ee2a603 | ||
|
|
8e17c1dfd5 | ||
|
|
9bd0174205 | ||
|
|
522dad95be | ||
|
|
87c4839fed | ||
|
|
22b6425bac | ||
|
|
5ba92fe274 | ||
|
|
91939d67ed | ||
|
|
d0caf21b2d | ||
|
|
0d18f3cc5d | ||
|
|
a3507bf611 | ||
|
|
62bc20a181 | ||
|
|
9ded88105b | ||
|
|
aec618793f | ||
|
|
fe33906ef0 | ||
|
|
6a17bad96e | ||
|
|
4f9fa5d66e | ||
|
|
0d7c4ae6c7 | ||
|
|
2608a323eb | ||
|
|
8d612aefdd | ||
|
|
ad96c48034 | ||
|
|
12e153ecff | ||
|
|
db35bc36aa | ||
|
|
af34fbbca3 | ||
|
|
8239275edb | ||
|
|
be6509a17f | ||
|
|
01e1133219 | ||
|
|
f04527ae32 | ||
|
|
98872bbe7c | ||
|
|
bc8b72e6eb | ||
|
|
127d547632 | ||
|
|
53755d87c8 | ||
|
|
289bec0fd5 | ||
|
|
8bd1fa50dc | ||
|
|
81af6bdd48 | ||
|
|
a5a2c718b1 | ||
|
|
6b67a3f3c2 | ||
|
|
1cea80a3ab | ||
|
|
b6a202f525 | ||
|
|
7b109506c8 | ||
|
|
c277370e48 | ||
|
|
f83443feac | ||
|
|
8529ad13d6 | ||
|
|
8deedf93a2 | ||
|
|
bdcfa75220 | ||
|
|
20d39588b5 | ||
|
|
67f3d58f71 | ||
|
|
bbfb855c2e | ||
|
|
6a63a45968 | ||
|
|
70d2d4b7a1 | ||
|
|
6aa21b3db6 | ||
|
|
ff32317f5b | ||
|
|
df6436a12c | ||
|
|
0200bc1b4e | ||
|
|
bd750a21e2 | ||
|
|
8c3782c1e2 | ||
|
|
2f2a257745 | ||
|
|
ab7d2d64e7 | ||
|
|
bc18501b59 | ||
|
|
0a5ce6d740 |
@@ -19,8 +19,6 @@ Error message and password prompt
|
||||
left: 50%;
|
||||
margin-left: -144px; /* - width/2 - paddingHorz/2 - border */
|
||||
padding: 16px 16px 16px 16px;
|
||||
-webkit-border-radius: 8px;
|
||||
-moz-border-radius: 8px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
|
||||
470
boot/boot.js
470
boot/boot.js
@@ -32,8 +32,8 @@ if(!$tw) {
|
||||
$tw = require("./bootprefix.js").bootprefix();
|
||||
}
|
||||
|
||||
$tw.utils = $tw.utils || {};
|
||||
$tw.boot = $tw.boot || {};
|
||||
$tw.utils = $tw.utils || Object.create(null);
|
||||
$tw.boot = $tw.boot || Object.create(null);
|
||||
|
||||
/////////////////////////// Standard node.js libraries
|
||||
|
||||
@@ -73,13 +73,11 @@ Iterate through all the own properties of an object or array. Callback is invoke
|
||||
$tw.utils.each = function(object,callback) {
|
||||
var f;
|
||||
if(object) {
|
||||
if($tw.utils.isArray(object)) {
|
||||
for(f=0; f<object.length; f++) {
|
||||
callback(object[f],f,object);
|
||||
}
|
||||
if(Object.prototype.toString.call(object) == "[object Array]") {
|
||||
object.forEach(callback);
|
||||
} else {
|
||||
for(f in object) {
|
||||
if($tw.utils.hop(object,f)) {
|
||||
if(Object.prototype.hasOwnProperty.call(object,f)) {
|
||||
callback(object[f],f,object);
|
||||
}
|
||||
}
|
||||
@@ -107,7 +105,7 @@ $tw.utils.domMaker = function(tag,options) {
|
||||
element.className = options["class"];
|
||||
}
|
||||
if(options.text) {
|
||||
element.appendChild(document.createTextNode(options.text));
|
||||
element.appendChild(doc.createTextNode(options.text));
|
||||
}
|
||||
$tw.utils.each(options.children,function(child) {
|
||||
element.appendChild(child);
|
||||
@@ -282,7 +280,7 @@ $tw.utils.parseStringArray = function(value) {
|
||||
|
||||
// Parse a block of name:value fields. The `fields` object is used as the basis for the return value
|
||||
$tw.utils.parseFields = function(text,fields) {
|
||||
fields = fields || {};
|
||||
fields = fields || Object.create(null);
|
||||
text.split(/\r?\n/mg).forEach(function(line) {
|
||||
if(line.charAt(0) !== "#") {
|
||||
var p = line.indexOf(":");
|
||||
@@ -354,11 +352,16 @@ $tw.utils.parseVersion = function(version) {
|
||||
};
|
||||
|
||||
/*
|
||||
Returns true if the version string A is greater than the version string B
|
||||
Returns true if the version string A is greater than the version string B. Returns true if the versions are the same
|
||||
*/
|
||||
$tw.utils.checkVersions = function(versionStringA,versionStringB) {
|
||||
var versionA = $tw.utils.parseVersion(versionStringA),
|
||||
versionB = $tw.utils.parseVersion(versionStringB),
|
||||
var defaultVersion = {
|
||||
major: 0,
|
||||
minor: 0,
|
||||
patch: 0
|
||||
},
|
||||
versionA = $tw.utils.parseVersion(versionStringA) || defaultVersion,
|
||||
versionB = $tw.utils.parseVersion(versionStringB) || defaultVersion,
|
||||
diff = [
|
||||
versionA.major - versionB.major,
|
||||
versionA.minor - versionB.minor,
|
||||
@@ -366,23 +369,38 @@ $tw.utils.checkVersions = function(versionStringA,versionStringB) {
|
||||
];
|
||||
return (diff[0] > 0) ||
|
||||
(diff[0] === 0 && diff[1] > 0) ||
|
||||
(diff[0] === 0 && diff[1] === 0 && diff[2] > 0);
|
||||
(diff[0] === 0 && diff[1] === 0 && diff[2] > 0) ||
|
||||
(diff[0] === 0 && diff[1] === 0 && diff[2] === 0);
|
||||
};
|
||||
|
||||
/*
|
||||
Register file type information
|
||||
flags: "image" for image types
|
||||
options: {flags: flags,deserializerType: deserializerType}
|
||||
flags:"image" for image types
|
||||
deserializerType: defaults to type if not specified
|
||||
*/
|
||||
$tw.utils.registerFileType = function(type,encoding,extension,flags) {
|
||||
$tw.config.fileExtensionInfo[extension] = {type: type};
|
||||
$tw.config.contentTypeInfo[type] = {encoding: encoding, extension: extension, flags: flags || []};
|
||||
$tw.utils.registerFileType = function(type,encoding,extension,options) {
|
||||
options = options || {};
|
||||
$tw.config.fileExtensionInfo[extension] = {type: type};
|
||||
$tw.config.contentTypeInfo[type] = {encoding: encoding, extension: extension, flags: options.flags || [], deserializerType: options.deserializerType || type};
|
||||
};
|
||||
|
||||
/*
|
||||
Given an extension, get the correct encoding for that file.
|
||||
defaults to utf8
|
||||
*/
|
||||
$tw.utils.getTypeEncoding = function(ext) {
|
||||
var extensionInfo = $tw.config.fileExtensionInfo[ext],
|
||||
type = extensionInfo ? extensionInfo.type : null,
|
||||
typeInfo = type ? $tw.config.contentTypeInfo[type] : null;
|
||||
return typeInfo ? typeInfo.encoding : "utf8";
|
||||
};
|
||||
|
||||
/*
|
||||
Run code globally with specified context variables in scope
|
||||
*/
|
||||
$tw.utils.evalGlobal = function(code,context,filename) {
|
||||
var contextCopy = $tw.utils.extend({},context);
|
||||
var contextCopy = $tw.utils.extend(Object.create(null),context);
|
||||
// Get the context variables as a pair of arrays of names and values
|
||||
var contextNames = [], contextValues = [];
|
||||
$tw.utils.each(contextCopy,function(value,name) {
|
||||
@@ -394,7 +412,7 @@ $tw.utils.evalGlobal = function(code,context,filename) {
|
||||
// Compile the code into a function
|
||||
var fn;
|
||||
if($tw.browser) {
|
||||
fn = window["eval"](code);
|
||||
fn = window["eval"](code + "\n\n//# sourceURL=" + filename);
|
||||
} else {
|
||||
fn = vm.runInThisContext(code,filename);
|
||||
}
|
||||
@@ -406,7 +424,7 @@ $tw.utils.evalGlobal = function(code,context,filename) {
|
||||
Run code in a sandbox with only the specified context variables in scope
|
||||
*/
|
||||
$tw.utils.evalSandboxed = $tw.browser ? $tw.utils.evalGlobal : function(code,context,filename) {
|
||||
var sandbox = $tw.utils.extend({},context);
|
||||
var sandbox = $tw.utils.extend(Object.create(null),context);
|
||||
vm.runInNewContext(code,sandbox,filename);
|
||||
return sandbox.exports;
|
||||
};
|
||||
@@ -669,7 +687,7 @@ Apply a callback to each module of a particular type
|
||||
*/
|
||||
$tw.modules.forEachModuleOfType = function(moduleType,callback) {
|
||||
var modules = $tw.modules.types[moduleType];
|
||||
$tw.utils.each(modules,function(element,title,object) {
|
||||
$tw.utils.each(modules,function(element,title) {
|
||||
callback(title,$tw.modules.execute(title));
|
||||
});
|
||||
};
|
||||
@@ -679,7 +697,7 @@ Get all the modules of a particular type in a hashmap by their `name` field
|
||||
*/
|
||||
$tw.modules.getModulesByTypeAsHashmap = function(moduleType,nameField) {
|
||||
nameField = nameField || "name";
|
||||
var results = {};
|
||||
var results = Object.create(null);
|
||||
$tw.modules.forEachModuleOfType(moduleType,function(title,module) {
|
||||
results[module[nameField]] = module;
|
||||
});
|
||||
@@ -691,7 +709,7 @@ Apply the exports of the modules of a particular type to a target object
|
||||
*/
|
||||
$tw.modules.applyMethods = function(moduleType,targetObject) {
|
||||
if(!targetObject) {
|
||||
targetObject = {};
|
||||
targetObject = Object.create(null);
|
||||
}
|
||||
$tw.modules.forEachModuleOfType(moduleType,function(title,module) {
|
||||
$tw.utils.each(module,function(element,title,object) {
|
||||
@@ -705,7 +723,7 @@ $tw.modules.applyMethods = function(moduleType,targetObject) {
|
||||
Return an array of classes created from the modules of a specified type. Each module should export the properties to be added to those of the optional base class
|
||||
*/
|
||||
$tw.modules.createClassesFromModules = function(moduleType,subType,baseClass) {
|
||||
var classes = {};
|
||||
var classes = Object.create(null);
|
||||
$tw.modules.forEachModuleOfType(moduleType,function(title,moduleExports) {
|
||||
if(!subType || moduleExports.types[subType]) {
|
||||
var newClass = function() {};
|
||||
@@ -727,26 +745,34 @@ Construct a tiddler object from a hashmap of tiddler fields. If multiple hasmaps
|
||||
taking precedence to the right
|
||||
*/
|
||||
$tw.Tiddler = function(/* [fields,] fields */) {
|
||||
this.fields = {};
|
||||
this.fields = Object.create(null);
|
||||
for(var c=0; c<arguments.length; c++) {
|
||||
var arg = arguments[c],
|
||||
src = (arg instanceof $tw.Tiddler) ? arg.fields : arg;
|
||||
for(var t in src) {
|
||||
if(src[t] === undefined) {
|
||||
if(src[t] === undefined || src[t] === null) {
|
||||
if(t in this.fields) {
|
||||
delete this.fields[t]; // If we get a field that's undefined, delete any previous field value
|
||||
}
|
||||
} else {
|
||||
// Parse the field with the associated field module (if any)
|
||||
var fieldModule = $tw.Tiddler.fieldModules[t];
|
||||
var fieldModule = $tw.Tiddler.fieldModules[t],
|
||||
value;
|
||||
if(fieldModule && fieldModule.parse) {
|
||||
this.fields[t] = fieldModule.parse.call(this,src[t]);
|
||||
value = fieldModule.parse.call(this,src[t]);
|
||||
} else {
|
||||
this.fields[t] = src[t];
|
||||
value = src[t];
|
||||
}
|
||||
// Freeze the field to keep it immutable
|
||||
if(typeof value === "object") {
|
||||
Object.freeze(value);
|
||||
}
|
||||
this.fields[t] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Freeze the tiddler against modification
|
||||
Object.freeze(this.fields);
|
||||
};
|
||||
|
||||
$tw.Tiddler.prototype.hasField = function(field) {
|
||||
@@ -785,115 +811,206 @@ $tw.modules.define("$:/boot/tiddlerfields/list","tiddlerfield",{
|
||||
/////////////////////////// Barebones wiki store
|
||||
|
||||
/*
|
||||
Construct a wiki store object
|
||||
Wiki constructor. State is stored in private members that only a small number of privileged accessor methods have direct access. Methods added via the prototype have to use these accessors and cannot access the state data directly.
|
||||
options include:
|
||||
shadowTiddlers: Array of shadow tiddlers to be added
|
||||
*/
|
||||
$tw.Wiki = function() {
|
||||
this.tiddlers = {};
|
||||
this.plugins = []; // Array of registered plugins, ordered by priority
|
||||
this.shadowTiddlers = {}; // Hashmap by title of {source:, tiddler:}
|
||||
$tw.Wiki = function(options) {
|
||||
options = options || {};
|
||||
var self = this,
|
||||
tiddlers = Object.create(null), // Hashmap of tiddlers
|
||||
pluginTiddlers = [], // Array of tiddlers containing registered plugins, ordered by priority
|
||||
pluginInfo = Object.create(null), // Hashmap of parsed plugin content
|
||||
shadowTiddlers = options.shadowTiddlers || Object.create(null); // Hashmap by title of {source:, tiddler:}
|
||||
|
||||
// Add a tiddler to the store
|
||||
this.addTiddler = function(tiddler) {
|
||||
if(!(tiddler instanceof $tw.Tiddler)) {
|
||||
tiddler = new $tw.Tiddler(tiddler);
|
||||
}
|
||||
// Save the tiddler
|
||||
if(tiddler) {
|
||||
var title = tiddler.fields.title;
|
||||
if(title) {
|
||||
tiddlers[title] = tiddler;
|
||||
this.clearCache(title);
|
||||
this.clearGlobalCache();
|
||||
this.enqueueTiddlerEvent(title);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Delete a tiddler
|
||||
this.deleteTiddler = function(title) {
|
||||
delete tiddlers[title];
|
||||
this.clearCache(title);
|
||||
this.clearGlobalCache();
|
||||
this.enqueueTiddlerEvent(title,true);
|
||||
};
|
||||
|
||||
// Get a tiddler from the store
|
||||
this.getTiddler = function(title) {
|
||||
var t = tiddlers[title];
|
||||
if(t instanceof $tw.Tiddler) {
|
||||
return t;
|
||||
} else if(title !== undefined && Object.prototype.hasOwnProperty.call(shadowTiddlers,title)) {
|
||||
return shadowTiddlers[title].tiddler;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
// Get an array of all tiddler titles
|
||||
this.allTitles = function() {
|
||||
return Object.keys(tiddlers);
|
||||
};
|
||||
|
||||
// Iterate through all tiddler titles
|
||||
this.each = function(callback) {
|
||||
for(var title in tiddlers) {
|
||||
callback(tiddlers[title],title);
|
||||
}
|
||||
};
|
||||
|
||||
// Get an array of all shadow tiddler titles
|
||||
this.allShadowTitles = function() {
|
||||
return Object.keys(shadowTiddlers);
|
||||
};
|
||||
|
||||
// Iterate through all shadow tiddler titles
|
||||
this.eachShadow = function(callback) {
|
||||
for(var title in shadowTiddlers) {
|
||||
var shadowInfo = shadowTiddlers[title];
|
||||
callback(shadowInfo.tiddler,title);
|
||||
}
|
||||
};
|
||||
|
||||
// Test for the existence of a tiddler
|
||||
this.tiddlerExists = function(title) {
|
||||
return !!$tw.utils.hop(tiddlers,title);
|
||||
};
|
||||
|
||||
// Determines if a tiddler is a shadow tiddler, regardless of whether it has been overridden by a real tiddler
|
||||
this.isShadowTiddler = function(title) {
|
||||
return $tw.utils.hop(shadowTiddlers,title);
|
||||
};
|
||||
|
||||
this.getShadowSource = function(title) {
|
||||
if($tw.utils.hop(shadowTiddlers,title)) {
|
||||
return shadowTiddlers[title].source;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// Read plugin info for all plugins
|
||||
this.readPluginInfo = function() {
|
||||
for(var title in tiddlers) {
|
||||
var tiddler = tiddlers[title];
|
||||
if(tiddler.fields.type === "application/json" && tiddler.hasField("plugin-type")) {
|
||||
pluginInfo[tiddler.fields.title] = JSON.parse(tiddler.fields.text);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// Get plugin info for a plugin
|
||||
this.getPluginInfo = function(title) {
|
||||
return pluginInfo[title];
|
||||
};
|
||||
|
||||
// Register the plugin tiddlers of a particular type, optionally restricting registration to an array of tiddler titles. Return the array of titles affected
|
||||
this.registerPluginTiddlers = function(pluginType,titles) {
|
||||
var self = this,
|
||||
registeredTitles = [],
|
||||
checkTiddler = function(tiddler) {
|
||||
if(tiddler && tiddler.fields.type === "application/json" && tiddler.fields["plugin-type"] === pluginType) {
|
||||
pluginTiddlers.push(tiddler);
|
||||
registeredTitles.push(tiddler.fields.title);
|
||||
}
|
||||
};
|
||||
if(titles) {
|
||||
$tw.utils.each(titles,function(title) {
|
||||
checkTiddler(self.getTiddler(title));
|
||||
});
|
||||
} else {
|
||||
this.each(function(tiddler,title) {
|
||||
checkTiddler(tiddler);
|
||||
});
|
||||
}
|
||||
return registeredTitles;
|
||||
};
|
||||
|
||||
// Unregister the plugin tiddlers of a particular type, returning an array of the titles affected
|
||||
this.unregisterPluginTiddlers = function(pluginType) {
|
||||
var self = this,
|
||||
titles = [];
|
||||
// Remove any previous registered plugins of this type
|
||||
for(var t=pluginTiddlers.length-1; t>=0; t--) {
|
||||
var tiddler = pluginTiddlers[t];
|
||||
if(tiddler.fields["plugin-type"] === pluginType) {
|
||||
titles.push(tiddler.fields.title);
|
||||
pluginTiddlers.splice(t,1);
|
||||
}
|
||||
}
|
||||
return titles;
|
||||
};
|
||||
|
||||
// Unpack the currently registered plugins, creating shadow tiddlers for their constituent tiddlers
|
||||
this.unpackPluginTiddlers = function() {
|
||||
var self = this;
|
||||
// Sort the plugin titles by the `plugin-priority` field
|
||||
pluginTiddlers.sort(function(a,b) {
|
||||
if("plugin-priority" in a.fields && "plugin-priority" in b.fields) {
|
||||
return a.fields["plugin-priority"] - b.fields["plugin-priority"];
|
||||
} else if("plugin-priority" in a.fields) {
|
||||
return -1;
|
||||
} else if("plugin-priority" in b.fields) {
|
||||
return +1;
|
||||
} else if(a.fields.title < b.fields.title) {
|
||||
return -1;
|
||||
} else if(a.fields.title === b.fields.title) {
|
||||
return 0;
|
||||
} else {
|
||||
return +1;
|
||||
}
|
||||
});
|
||||
// Now go through the plugins in ascending order and assign the shadows
|
||||
shadowTiddlers = Object.create(null);
|
||||
$tw.utils.each(pluginTiddlers,function(tiddler) {
|
||||
// Extract the constituent tiddlers
|
||||
if($tw.utils.hop(pluginInfo,tiddler.fields.title)) {
|
||||
$tw.utils.each(pluginInfo[tiddler.fields.title].tiddlers,function(constituentTiddler,constituentTitle) {
|
||||
// Save the tiddler object
|
||||
if(constituentTitle) {
|
||||
shadowTiddlers[constituentTitle] = {
|
||||
source: tiddler.fields.title,
|
||||
tiddler: new $tw.Tiddler(constituentTiddler,{title: constituentTitle})
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
$tw.Wiki.prototype.addTiddler = function(tiddler) {
|
||||
if(!(tiddler instanceof $tw.Tiddler)) {
|
||||
tiddler = new $tw.Tiddler(tiddler);
|
||||
}
|
||||
if(tiddler.fields.title) {
|
||||
this.tiddlers[tiddler.fields.title] = tiddler;
|
||||
}
|
||||
};
|
||||
// Dummy methods that will be filled in after boot
|
||||
$tw.Wiki.prototype.clearCache =
|
||||
$tw.Wiki.prototype.clearGlobalCache =
|
||||
$tw.Wiki.prototype.enqueueTiddlerEvent = function() {};
|
||||
|
||||
// Add an array of tiddlers
|
||||
$tw.Wiki.prototype.addTiddlers = function(tiddlers) {
|
||||
for(var t=0; t<tiddlers.length; t++) {
|
||||
this.addTiddler(tiddlers[t]);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Register the plugin tiddlers of a particular type, optionally restricting registration to an array of tiddler titles. Return the array of titles affected
|
||||
*/
|
||||
$tw.Wiki.prototype.registerPluginTiddlers = function(pluginType,titles) {
|
||||
var self = this,
|
||||
registeredTitles = [];
|
||||
// Go through the provided titles, or the entire tiddler list, looking for plugins of this type
|
||||
var checkTiddler = function(tiddler) {
|
||||
if(tiddler && tiddler.fields.type === "application/json" && tiddler.fields["plugin-type"] === pluginType) {
|
||||
self.plugins.push(tiddler);
|
||||
registeredTitles.push(tiddler.fields.title);
|
||||
}
|
||||
};
|
||||
if(titles) {
|
||||
$tw.utils.each(titles,function(title) {
|
||||
checkTiddler(self.getTiddler(title));
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(this.tiddlers,function(tiddler,title) {
|
||||
checkTiddler(tiddler);
|
||||
});
|
||||
}
|
||||
return registeredTitles;
|
||||
};
|
||||
|
||||
/*
|
||||
Unregister the plugin tiddlers of a particular type, returning an array of the titles affected
|
||||
*/
|
||||
$tw.Wiki.prototype.unregisterPluginTiddlers = function(pluginType) {
|
||||
var self = this,
|
||||
titles = [];
|
||||
// Remove any previous registered plugins of this type
|
||||
for(var t=this.plugins.length-1; t>=0; t--) {
|
||||
var tiddler = this.plugins[t];
|
||||
if(tiddler.fields["plugin-type"] === pluginType) {
|
||||
titles.push(tiddler.fields.title);
|
||||
this.plugins.splice(t,1);
|
||||
}
|
||||
}
|
||||
return titles;
|
||||
};
|
||||
|
||||
/*
|
||||
Unpack the currently registered plugins, creating shadow tiddlers for their constituent tiddlers
|
||||
*/
|
||||
$tw.Wiki.prototype.unpackPluginTiddlers = function() {
|
||||
var self = this;
|
||||
// Sort the plugin titles by the `plugin-priority` field
|
||||
this.plugins.sort(function(a,b) {
|
||||
if("plugin-priority" in a.fields && "plugin-priority" in b.fields) {
|
||||
return a.fields["plugin-priority"] - b.fields["plugin-priority"];
|
||||
} else if("plugin-priority" in a.fields) {
|
||||
return -1;
|
||||
} else if("plugin-priority" in b.fields) {
|
||||
return +1;
|
||||
} else if(a.fields.title < b.fields.title) {
|
||||
return -1;
|
||||
} else if(a.fields.title === b.fields.title) {
|
||||
return 0;
|
||||
} else {
|
||||
return +1;
|
||||
}
|
||||
});
|
||||
// Now go through the plugins in ascending order and assign the shadows
|
||||
this.shadowTiddlers = {};
|
||||
$tw.utils.each(this.plugins,function(tiddler) {
|
||||
// Get the plugin information
|
||||
var pluginInfo = JSON.parse(tiddler.fields.text);
|
||||
// Extract the constituent tiddlers
|
||||
$tw.utils.each(pluginInfo.tiddlers,function(constituentTiddler,constituentTitle) {
|
||||
// Save the tiddler object
|
||||
if(constituentTitle) {
|
||||
self.shadowTiddlers[constituentTitle] = {
|
||||
source: tiddler.fields.title,
|
||||
tiddler: new $tw.Tiddler(constituentTiddler,{title: constituentTitle})
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Define all modules stored in ordinary tiddlers
|
||||
*/
|
||||
$tw.Wiki.prototype.defineTiddlerModules = function() {
|
||||
$tw.utils.each(this.tiddlers,function(tiddler,title,object) {
|
||||
this.each(function(tiddler,title) {
|
||||
if(tiddler.hasField("module-type")) {
|
||||
switch (tiddler.fields.type) {
|
||||
case "application/javascript":
|
||||
@@ -918,40 +1035,63 @@ Register all the module tiddlers that have a module type
|
||||
*/
|
||||
$tw.Wiki.prototype.defineShadowModules = function() {
|
||||
var self = this;
|
||||
$tw.utils.each(this.shadowTiddlers,function(element,title) {
|
||||
var tiddler = self.getTiddler(title);
|
||||
if(!$tw.utils.hop(self.tiddlers,title)) { // Don't define the module if it is overidden by an ordinary tiddler
|
||||
if(tiddler.hasField("module-type")) {
|
||||
// Define the module
|
||||
$tw.modules.define(tiddler.fields.title,tiddler.fields["module-type"],tiddler.fields.text);
|
||||
}
|
||||
this.eachShadow(function(tiddler,title) {
|
||||
// Don't define the module if it is overidden by an ordinary tiddler
|
||||
if(!self.tiddlerExists(title) && tiddler.hasField("module-type")) {
|
||||
// Define the module
|
||||
$tw.modules.define(tiddler.fields.title,tiddler.fields["module-type"],tiddler.fields.text);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$tw.Wiki.prototype.getTiddler = function(title) {
|
||||
var t = this.tiddlers[title];
|
||||
if(t instanceof $tw.Tiddler) {
|
||||
return t;
|
||||
} else if(title !== undefined && $tw.utils.hop(this.shadowTiddlers,title)) {
|
||||
return this.shadowTiddlers[title].tiddler;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
/*
|
||||
Enable safe mode by deleting any tiddlers that override a shadow tiddler
|
||||
*/
|
||||
$tw.Wiki.prototype.processSafeMode = function() {
|
||||
var self = this,
|
||||
overrides = [];
|
||||
// Find the overriding tiddlers
|
||||
this.each(function(tiddler,title) {
|
||||
if(self.isShadowTiddler(title)) {
|
||||
console.log(title);
|
||||
overrides.push(title);
|
||||
}
|
||||
});
|
||||
// Assemble a report tiddler
|
||||
var titleReportTiddler = "TiddlyWiki Safe Mode",
|
||||
report = [];
|
||||
report.push("TiddlyWiki has been started in [[safe mode|http://tiddlywiki.com/static/SafeMode.html]]. Most customisations have been disabled by renaming the following tiddlers:")
|
||||
// Delete the overrides
|
||||
overrides.forEach(function(title) {
|
||||
var tiddler = self.getTiddler(title),
|
||||
newTitle = "SAFE: " + title;
|
||||
self.deleteTiddler(title);
|
||||
self.addTiddler(new $tw.Tiddler(tiddler, {title: newTitle}));
|
||||
report.push("* [[" + title + "|" + newTitle + "]]");
|
||||
});
|
||||
report.push()
|
||||
this.addTiddler(new $tw.Tiddler({title: titleReportTiddler, text: report.join("\n\n")}));
|
||||
// Set $:/DefaultTiddlers to point to our report
|
||||
this.addTiddler(new $tw.Tiddler({title: "$:/DefaultTiddlers", text: "[[" + titleReportTiddler + "]]"}));
|
||||
};
|
||||
|
||||
/*
|
||||
Extracts tiddlers from a typed block of text, specifying default field values
|
||||
*/
|
||||
$tw.Wiki.prototype.deserializeTiddlers = function(type,text,srcFields) {
|
||||
srcFields = srcFields || {};
|
||||
srcFields = srcFields || Object.create(null);
|
||||
var deserializer = $tw.Wiki.tiddlerDeserializerModules[type],
|
||||
fields = {};
|
||||
fields = Object.create(null);
|
||||
if(!deserializer && $tw.config.fileExtensionInfo[type]) {
|
||||
// If we didn't find the serializer, try converting it from an extension to a content type
|
||||
type = $tw.config.fileExtensionInfo[type].type;
|
||||
deserializer = $tw.Wiki.tiddlerDeserializerModules[type];
|
||||
}
|
||||
if(!deserializer && $tw.config.contentTypeInfo[type]) {
|
||||
// see if this type has a different deserializer registered with it
|
||||
type = $tw.config.contentTypeInfo[type].deserializerType;
|
||||
deserializer = $tw.Wiki.tiddlerDeserializerModules[type];
|
||||
}
|
||||
if(!deserializer) {
|
||||
// If we still don't have a deserializer, treat it as plain text
|
||||
deserializer = $tw.Wiki.tiddlerDeserializerModules["text/plain"];
|
||||
@@ -1009,7 +1149,7 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/tids","tiddlerdeserializer",{
|
||||
if(line.charAt(0) !== "#") {
|
||||
var colonPos= line.indexOf(": ");
|
||||
if(colonPos !== -1) {
|
||||
var tiddler = $tw.utils.extend({},fields);
|
||||
var tiddler = $tw.utils.extend(Object.create(null),fields);
|
||||
tiddler.title = (tiddler.title || "") + line.substr(0,colonPos);
|
||||
if(titles.indexOf(tiddler.title) !== -1) {
|
||||
console.log("Warning: .multids file contains multiple definitions for " + tiddler.title);
|
||||
@@ -1228,7 +1368,7 @@ $tw.loadTiddlersFromPath = function(filepath,excludeRegExp) {
|
||||
// Look for a tiddlywiki.files file
|
||||
if(files.indexOf("tiddlywiki.files") !== -1) {
|
||||
// If so, process the files it describes
|
||||
var filesInfo = JSON.parse(fs.readFileSync(filepath + "/tiddlywiki.files","utf8"));
|
||||
var filesInfo = JSON.parse(fs.readFileSync(filepath + path.sep + "tiddlywiki.files","utf8"));
|
||||
$tw.utils.each(filesInfo.tiddlers,function(tidInfo) {
|
||||
var typeInfo = $tw.config.contentTypeInfo[tidInfo.fields.type || "text/plain"],
|
||||
pathname = path.resolve(filepath,tidInfo.file),
|
||||
@@ -1246,7 +1386,7 @@ $tw.loadTiddlersFromPath = function(filepath,excludeRegExp) {
|
||||
// If not, read all the files in the directory
|
||||
$tw.utils.each(files,function(file) {
|
||||
if(!excludeRegExp.test(file)) {
|
||||
tiddlers.push.apply(tiddlers,$tw.loadTiddlersFromPath(filepath + "/" + file,excludeRegExp));
|
||||
tiddlers.push.apply(tiddlers,$tw.loadTiddlersFromPath(filepath + path.sep + file,excludeRegExp));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1267,20 +1407,20 @@ $tw.loadPluginFolder = function(filepath,excludeRegExp) {
|
||||
stat = fs.statSync(filepath);
|
||||
if(stat.isDirectory()) {
|
||||
// Read the plugin information
|
||||
pluginInfo = JSON.parse(fs.readFileSync(filepath + "/plugin.info","utf8"));
|
||||
pluginInfo = JSON.parse(fs.readFileSync(filepath + path.sep + "plugin.info","utf8"));
|
||||
// Read the plugin files
|
||||
files = fs.readdirSync(filepath);
|
||||
for(f=0; f<files.length; f++) {
|
||||
file = files[f];
|
||||
if(!excludeRegExp.test(file) && file !== "plugin.info" && file !== "tiddlywiki.files") {
|
||||
var tiddlerFiles = $tw.loadTiddlersFromPath(filepath + "/" + file,excludeRegExp);
|
||||
var tiddlerFiles = $tw.loadTiddlersFromPath(filepath + path.sep + file,excludeRegExp);
|
||||
$tw.utils.each(tiddlerFiles,function(tiddlerFile) {
|
||||
pluginTiddlers.push.apply(pluginTiddlers,tiddlerFile.tiddlers);
|
||||
});
|
||||
}
|
||||
}
|
||||
// Save the plugin tiddlers into the plugin info
|
||||
pluginInfo.tiddlers = pluginInfo.tiddlers || {};
|
||||
pluginInfo.tiddlers = pluginInfo.tiddlers || Object.create(null);
|
||||
for(t=0; t<pluginTiddlers.length; t++) {
|
||||
if(pluginTiddlers[t].title) {
|
||||
pluginInfo.tiddlers[pluginTiddlers[t].title] = pluginTiddlers[t];
|
||||
@@ -1454,10 +1594,12 @@ readBrowserTiddlers: whether to read tiddlers from the HTML file we're executing
|
||||
*/
|
||||
$tw.boot.startup = function(options) {
|
||||
options = options || {};
|
||||
// Check for safe mode
|
||||
$tw.safeMode = $tw.browser && location.hash === "#:safe";
|
||||
// Initialise some more $tw properties
|
||||
$tw.utils.deepDefaults($tw,{
|
||||
modules: { // Information about each module
|
||||
titles: {}, // hashmap by module title of {fn:, exports:, moduleType:}
|
||||
titles: Object.create(null), // hashmap by module title of {fn:, exports:, moduleType:}
|
||||
types: {} // hashmap by module type of hashmap of exports
|
||||
},
|
||||
config: { // Configuration overridables
|
||||
@@ -1471,16 +1613,20 @@ $tw.boot.startup = function(options) {
|
||||
wikiLanguagesSubDir: "./languages",
|
||||
wikiTiddlersSubDir: "./tiddlers",
|
||||
jsModuleHeaderRegExpString: "^\\/\\*\\\\(?:\\r?\\n)((?:^[^\\r\\n]*(?:\\r?\\n))+?)(^\\\\\\*\\/$(?:\\r?\\n)?)",
|
||||
fileExtensionInfo: {}, // Map file extension to {type:}
|
||||
contentTypeInfo: {} // Map type to {encoding:,extension:}
|
||||
fileExtensionInfo: Object.create(null), // Map file extension to {type:}
|
||||
contentTypeInfo: Object.create(null) // Map type to {encoding:,extension:}
|
||||
}
|
||||
});
|
||||
if(!options.readBrowserTiddlers) {
|
||||
// For writable tiddler files, a hashmap of title to {filepath:,type:,hasMetaFile:}
|
||||
$tw.boot.files = {};
|
||||
$tw.boot.files = Object.create(null);
|
||||
// System paths and filenames
|
||||
$tw.boot.bootPath = path.dirname(module.filename);
|
||||
$tw.boot.corePath = path.resolve($tw.boot.bootPath,"../core");
|
||||
// If there's no arguments then default to `--help`
|
||||
if($tw.boot.argv.length === 0) {
|
||||
$tw.boot.argv = ["--help"];
|
||||
}
|
||||
// If the first command line argument doesn't start with `--` then we
|
||||
// interpret it as the path to the wiki folder, which will otherwise default
|
||||
// to the current folder
|
||||
@@ -1506,21 +1652,22 @@ $tw.boot.startup = function(options) {
|
||||
$tw.utils.registerFileType("text/plain","utf8",".txt");
|
||||
$tw.utils.registerFileType("text/css","utf8",".css");
|
||||
$tw.utils.registerFileType("text/html","utf8",".html");
|
||||
$tw.utils.registerFileType("application/hta","utf16le",".hta",{deserializerType:"text/html"});
|
||||
$tw.utils.registerFileType("application/javascript","utf8",".js");
|
||||
$tw.utils.registerFileType("application/json","utf8",".json");
|
||||
$tw.utils.registerFileType("application/pdf","base64",".pdf",["image"]);
|
||||
$tw.utils.registerFileType("image/jpeg","base64",".jpg",["image"]);
|
||||
$tw.utils.registerFileType("image/png","base64",".png",["image"]);
|
||||
$tw.utils.registerFileType("image/gif","base64",".gif",["image"]);
|
||||
$tw.utils.registerFileType("image/svg+xml","utf8",".svg",["image"]);
|
||||
$tw.utils.registerFileType("image/x-icon","base64",".ico",["image"]);
|
||||
$tw.utils.registerFileType("application/pdf","base64",".pdf",{flags:["image"]});
|
||||
$tw.utils.registerFileType("image/jpeg","base64",".jpg",{flags:["image"]});
|
||||
$tw.utils.registerFileType("image/png","base64",".png",{flags:["image"]});
|
||||
$tw.utils.registerFileType("image/gif","base64",".gif",{flags:["image"]});
|
||||
$tw.utils.registerFileType("image/svg+xml","utf8",".svg",{flags:["image"]});
|
||||
$tw.utils.registerFileType("image/x-icon","base64",".ico",{flags:["image"]});
|
||||
$tw.utils.registerFileType("application/font-woff","base64",".woff");
|
||||
// Create the wiki store for the app
|
||||
$tw.wiki = new $tw.Wiki();
|
||||
// Install built in tiddler fields modules
|
||||
$tw.Tiddler.fieldModules = $tw.modules.getModulesByTypeAsHashmap("tiddlerfield");
|
||||
// Install the tiddler deserializer modules
|
||||
$tw.Wiki.tiddlerDeserializerModules = {};
|
||||
$tw.Wiki.tiddlerDeserializerModules = Object.create(null);
|
||||
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
|
||||
// Load tiddlers
|
||||
if(options.readBrowserTiddlers) {
|
||||
@@ -1529,8 +1676,13 @@ $tw.boot.startup = function(options) {
|
||||
$tw.loadTiddlersNode();
|
||||
}
|
||||
// Unpack plugin tiddlers
|
||||
$tw.wiki.readPluginInfo();
|
||||
$tw.wiki.registerPluginTiddlers("plugin");
|
||||
$tw.wiki.unpackPluginTiddlers();
|
||||
// Process "safe mode"
|
||||
if($tw.safeMode) {
|
||||
$tw.wiki.processSafeMode();
|
||||
}
|
||||
// Register typed modules from the tiddlers we've just loaded
|
||||
$tw.wiki.defineTiddlerModules();
|
||||
// And any modules within plugins
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,3 +1,4 @@
|
||||
title: $:/core/images/cancel-button
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tw-image-cancel-button tw-image-button" viewBox="366 150 58 58" width="22pt" height="22pt"><path d="M 414.76236 158.98764 C 403.77887 148.0041 385.97113 148.0041 374.98764 158.98764 C 364.0041 169.97113 364.0041 187.77887 374.98764 198.76236 C 385.97113 209.7459 403.77887 209.7459 414.76236 198.76236 C 425.7459 187.77887 425.7459 169.97113 414.76236 158.98764 M 385.3967 165.32954 L 385.3967 165.32954 L 394.77674 174.7096 L 404.3533 165.13303 C 405.53068 163.95566 407.4396 163.95566 408.61697 165.13303 C 409.79434 166.31041 409.79434 168.21932 408.61697 169.39669 L 399.0404 178.97325 L 408.42046 188.35331 C 409.59783 189.53068 409.59783 191.43959 408.42046 192.61697 L 408.42046 192.61697 C 407.24308 193.79434 405.33417 193.79434 404.1568 192.61697 L 394.77675 183.23692 L 385.5932 192.42046 C 384.41583 193.59783 382.50692 193.59783 381.32954 192.42046 L 381.32954 192.42046 C 380.15217 191.24308 380.15217 189.33417 381.32954 188.1568 C 381.32954 188.1568 381.32954 188.1568 381.32954 188.1568 L 381.32954 188.1568 L 381.32954 188.1568 L 390.51309 178.97326 L 381.13303 169.5932 C 379.95566 168.41583 379.95566 166.50692 381.13303 165.32954 L 381.13303 165.32954 C 382.3104 164.15217 384.21932 164.15217 385.3967 165.32954 C 385.3967 165.32954 385.3967 165.32954 385.3967 165.32954 Z"/></svg>
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/core/images/close-button
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tw-image-close-button tw-image-button" viewBox="222 150 56 56" width="22pt" height="22pt"><path d="M 249.56668 185.88827 L 267.06757 203.38916 C 269.26427 205.58586 272.82582 205.58586 275.02252 203.38916 L 275.02252 203.38916 C 277.21922 201.19246 277.21922 197.63091 275.02252 195.43421 L 257.52163 177.93332 L 275.38916 160.06579 C 277.58586 157.86909 277.58586 154.30754 275.38916 152.11084 C 273.19246 149.91414 269.63091 149.91414 267.43421 152.11084 L 249.56668 169.97837 L 232.06579 152.47748 L 232.06579 152.47748 C 232.06579 152.47748 232.06579 152.47748 232.06579 152.47748 C 229.86909 150.28078 226.30754 150.28078 224.11084 152.47748 L 224.11084 152.47748 C 221.91414 154.674175 221.91414 158.23573 224.11084 160.43243 L 241.61173 177.93332 L 224.47748 195.06757 L 224.47748 195.06757 L 224.47748 195.06757 C 224.47748 195.06757 224.47748 195.06757 224.47748 195.06757 C 222.28078 197.26427 222.28078 200.82583 224.47748 203.02252 L 224.47748 203.02252 C 226.67418 205.21922 230.23573 205.21922 232.43243 203.02252 Z"/></svg>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/core/images/delete-button
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tw-image-delete-button tw-image-button" viewBox="303 155 39 50" width="17pt" height="22pt"><path d="M 333 164.25 L 333 157.25 C 333 156.14543 332.10457 155.25 331 155.25 L 314.75 155.25 C 314.75 155.25 314.75 155.25 314.75 155.25 C 313.64543 155.25 312.75 156.14543 312.75 157.25 L 312.75 164.25 L 303.75 164.25 L 303.75 168.75 L 306 168.75 L 306 201.75 L 306 201.75 L 306 201.75 C 306 203.40685 307.34315 204.75 309 204.75 L 336.75 204.75 C 338.40685 204.75 339.75 203.40685 339.75 201.75 L 339.75 168.75 L 342 168.75 L 342 164.25 Z M 317.25 160.75 L 317.25 160.75 C 317.25 160.19772 317.69772 159.75 318.25 159.75 C 318.25 159.75 318.25 159.75 318.25 159.75 L 327.5 159.75 C 328.05228 159.75 328.5 160.19772 328.5 160.75 L 328.5 164.25 L 317.25 164.25 L 317.25 160.75 Z M 310.5 168.75 L 312.75 168.75 L 312.75 200.25 L 310.5 200.25 Z M 317.25 168.75 L 319.5 168.75 L 319.5 200.25 L 317.25 200.25 Z M 324 168.75 L 326.25 168.75 L 326.25 200.25 L 324 200.25 Z M 330.75 168.75 L 333 168.75 L 333 200.25 L 330.75 200.25 Z"/></svg>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/core/images/done-button
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tw-image-done-button tw-image-button" viewBox="434 150 68 55" width="22pt" height="18pt"><path d="M 438.49266 178.00797 L 439.00744 177.49319 C 441.35054 175.15008 445.14946 175.15004 447.49262 177.49309 L 452.50734 182.50757 C 454.8505 184.85063 458.6494 184.85058 460.99252 182.50748 L 488.50747 154.99255 C 490.85058 152.64944 494.6495 152.6494 496.99266 154.99246 L 497.50722 155.506995 C 499.8504 157.85009 499.8505 161.64908 497.5074 163.99228 C 497.50738 163.99229 497.50736 163.99231 497.50734 163.99233 L 460.9926 200.5077 C 458.64947 202.85087 454.85048 202.8509 452.50732 200.50778 C 452.5073 200.50777 452.5073 200.50777 452.5073 200.50776 L 438.49268 186.49327 C 436.14952 184.15013 436.1495 180.35114 438.49264 178.00799 C 438.49265 178.00798 438.49265 178.00797 438.49266 178.00797 Z"/></svg>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/core/images/down-arrow
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tw-image-down-arrow tw-image-button" viewBox="441 306 59 45" width="24pt" height="22pt"><path d="M 441 306 L 470.25 351 L 499.5 306 Z"/></svg>
|
||||
<svg class="tw-image-down-arrow tw-image-button" viewBox="63 152 64 64" width="22pt" height="22pt"><path d="M 98.001786 212.81802 L 123.45763 187.36218 C 125.21499 185.60482 125.21499 182.75557 123.45763 180.99821 C 121.70027 179.24086 118.85103 179.24086 117.09367 180.99821 L 94.819805 203.27208 L 72.54594 180.99821 C 70.788582 179.24086 67.93934 179.24086 66.18198 180.99821 C 64.42462 182.75557 64.42462 185.60482 66.18198 187.36218 L 91.637825 212.81802 C 93.395184 214.57538 96.244426 214.57538 98.001786 212.81802 Z"/></svg>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/core/images/edit-button
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tw-image-edit-button tw-image-button" viewBox="244 193 20 22" width="20pt" height="22pt"><path d="M 257.33334 196.80951 L 245.90476 207.2857 L 244 212.0476 L 248.7619 210.14284 L 260.19048 199.66665 Z M 259.2381 194.90475 L 258.28566 195.85716 L 261.14284 198.71428 L 262.09522 197.76187 Z M 261.14286 193 L 260.19042 193.95241 L 263.04762 196.80953 L 264 195.85714 Z M 244 213.72882 C 244 213.72882 247.4281 215.43353 250.8572 213.7288 C 254.28599 212.02405 261.14284 214.86531 261.14284 214.86531 L 261.14284 213.72884 C 261.14284 213.72884 254.28577 210.88755 250.8572 212.5923 C 247.42858 214.29712 244 212.59228 244 212.59228 Z"/></svg>
|
||||
|
||||
4
core/images/home-button.tid
Normal file
4
core/images/home-button.tid
Normal file
@@ -0,0 +1,4 @@
|
||||
title: $:/core/images/home-button
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tw-image-home-button tw-image-button" viewBox="81 513 64 54" width="22pt" height="22pt"><g><path d="M 97.04536 522.62083 L 81.364685 531.49067 L 87.85863 531.49067 L 87.85863 566.9699 L 107.49902 566.9699 L 107.49902 552.99265 L 117.95268 552.99265 L 117.95268 566.9699 L 137.59307 566.9699 L 137.59307 531.49067 L 144.086885 531.49067 L 112.72591 513.751 L 107.49902 516.70758 L 107.49902 513.751 L 97.04536 513.751 Z M 94.669443 534.17844 L 103.222493 534.17844 L 103.222493 545.19854 L 94.669443 545.19854 Z M 108.449266 534.17844 L 117.002435 534.17844 L 117.002435 545.19854 L 108.449266 545.19854 Z M 122.387575 534.17844 L 130.9405 534.17844 L 130.9405 545.19854 L 122.387575 545.19854 Z"/></g></svg>
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/core/images/info-button
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tw-image-info-button tw-image-button" viewBox="294 150 58 58" width="22pt" height="22pt"><path d="M 342.76236 158.98764 C 331.77887 148.0041 313.97113 148.0041 302.98764 158.98764 C 292.0041 169.97113 292.0041 187.77887 302.98764 198.76236 C 313.97113 209.7459 331.77887 209.7459 342.76236 198.76236 C 353.7459 187.77887 353.7459 169.97113 342.76236 158.98764 M 326.5425 157.5 L 326.5425 157.5 C 327.72545 157.5 328.72201 157.91022 329.5337 158.73088 C 330.34465 159.55157 330.75 160.54402 330.75 161.7075 C 330.75 162.87172 330.33979 163.86316 329.51911 164.68385 C 328.69842 165.5045 327.70674 165.91501 326.5425 165.91501 C 325.39801 165.91501 324.4153 165.5045 323.5946 164.68385 C 322.77393 163.86316 322.36372 162.87172 322.36372 161.7075 C 322.36372 160.54402 322.76906 159.55157 323.58 158.73088 C 324.39171 157.91022 325.3793 157.5 326.5425 157.5 Z M 327.80211 190.47259 C 324.91945 195.49132 321.85778 198 318.61462 198 C 317.37452 198 316.38691 197.65158 315.65186 196.9555 C 314.9176 196.25866 314.54943 195.37617 314.54943 194.30782 C 314.54943 193.60202 314.71223 192.70572 315.03629 191.61813 L 319.0151 177.93651 C 319.39685 176.61922 319.58735 175.62754 319.58735 174.95991 C 319.58735 174.53996 319.40582 174.16692 319.04356 173.84286 C 318.68052 173.51905 318.18469 173.35701 317.55527 173.35701 C 317.26861 173.35701 316.92506 173.36677 316.5246 173.38548 L 316.89661 172.2407 L 326.59967 170.66627 L 328.31744 170.66627 L 322.44986 191.01638 C 322.12503 192.18064 321.963 192.94337 321.963 193.30666 C 321.963 193.51588 322.04862 193.71121 322.2204 193.89273 C 322.39218 194.07425 322.5737 194.16554 322.7642 194.16477 C 323.08903 194.16554 323.4131 194.02221 323.73792 193.73559 C 324.59605 193.02976 325.6267 191.75142 326.82838 189.90008 Z"/></svg>
|
||||
|
||||
4
core/images/menu-button.tid
Normal file
4
core/images/menu-button.tid
Normal file
@@ -0,0 +1,4 @@
|
||||
title: $:/core/images/menu-button
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tw-image-menu-button tw-image-button" viewBox="216 585 63 45" width="22pt" height="22pt"><g><path d="M 274.5 585 L 229.5 585 C 227.01472 585 225 587.01472 225 589.5 L 225 589.5 C 225 591.98528 227.01472 594 229.5 594 L 274.5 594 C 276.98528 594 279 591.98528 279 589.5 L 279 589.5 C 279 587.01472 276.98528 585 274.5 585 Z"/><path d="M 274.5 603 L 229.5 603 C 227.01472 603 225 605.01472 225 607.5 L 225 607.5 C 225 609.98528 227.01472 612 229.5 612 L 274.5 612 C 276.98528 612 279 609.98528 279 607.5 L 279 607.5 C 279 605.01472 276.98528 603 274.5 603 Z"/><path d="M 274.5 621 L 229.5 621 C 227.01472 621 225 623.01472 225 625.5 L 225 625.5 C 225 627.9853 227.01472 630 229.5 630 L 274.5 630 C 276.98528 630 279 627.9853 279 625.5 L 279 625.5 C 279 623.01472 276.98528 621 274.5 621 Z"/></g></svg>
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/core/images/new-button
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tw-image-new-button tw-image-button" viewBox="83 81 50 50" width="22pt" height="22pt"><path d="M 101.25 112.5 L 101.25 127.5 C 101.25 127.5 101.25 127.5 101.25 127.5 L 101.25 127.5 C 101.25 129.156855 102.593146 130.5 104.25 130.5 L 111.75 130.5 C 113.406854 130.5 114.75 129.156854 114.75 127.5 L 114.75 112.5 L 129.75 112.5 C 131.406854 112.5 132.75 111.156854 132.75 109.5 L 132.75 102 C 132.75 100.343146 131.406854 99 129.75 99 L 114.75 99 L 114.75 84 C 114.75 82.343146 113.406854 81 111.75 81 L 104.25 81 C 104.25 81 104.25 81 104.25 81 C 102.593146 81 101.25 82.343146 101.25 84 L 101.25 99 L 86.25 99 C 86.25 99 86.25 99 86.25 99 C 84.593146 99 83.25 100.343146 83.25 102 L 83.25 109.5 C 83.25 109.5 83.25 109.5 83.25 109.5 L 83.25 109.5 C 83.25 111.156855 84.593146 112.5 86.25 112.5 Z"/></svg>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/core/images/options-button
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tw-image-options-button tw-image-button" viewBox="434 218 68 68" width="22pt" height="22pt"><path d="M 478.39696 232.53705 L 478.39696 232.53705 C 477.11453 231.85132 475.77877 231.30146 474.4106 230.88735 L 474.4106 218.24993 L 461.58944 218.24993 L 461.58944 230.88735 C 460.22126 231.30146 458.8855 231.85132 457.60308 232.53705 L 448.66825 223.60214 L 439.6022 232.66814 L 448.53716 241.60304 C 447.8515 242.88541 447.30158 244.22116 446.88747 245.58935 L 434.25 245.58935 L 434.25 258.41052 L 446.88747 258.41052 C 447.30158 259.7787 447.8515 261.11446 448.53716 262.39689 L 439.6022 271.33173 L 448.66825 280.39779 L 457.60308 271.46281 C 458.8855 272.14862 460.22126 272.69847 461.58944 273.11251 L 461.58944 285.74986 L 474.4106 285.74986 L 474.4106 273.11251 C 475.77877 272.69847 477.11453 272.14862 478.39696 271.46281 L 487.3318 280.39779 L 496.3977 271.33173 L 487.46287 262.39689 C 488.14854 261.11446 488.6984 259.7787 489.11257 258.41052 L 501.7499 258.41052 L 501.7499 245.58935 L 489.11257 245.58935 C 488.6984 244.22116 488.14854 242.88541 487.46287 241.60304 L 496.3977 232.66814 L 487.3318 223.60214 Z M 475.3328 244.66714 C 479.38253 248.71698 479.38253 255.2829 475.3328 259.33273 C 471.28297 263.3826 464.71706 263.3826 460.66723 259.33273 C 456.61737 255.2829 456.61737 248.71698 460.66723 244.66714 C 464.71706 240.61734 471.28297 240.61734 475.3328 244.66714"/></svg>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
title: $:/core/images/save-button
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tw-image-save-button tw-image-button" viewBox="4 512 64 60" width="22pt" height="21pt"><path d="M 13.5 537.75 L 11.5 537.75 C 11.5 537.75 11.5 537.75 11.5 537.75 C 7.6340064 537.75 4.4999994 540.884 4.5 544.75 L 4.5 564.5 L 4.5 564.5 C 4.5 564.5 4.5 564.5 4.5 564.5 L 4.5 564.5 C 4.5000006 568.366 7.634007 571.5 11.5 571.5 L 60.5 571.5 C 64.365993 571.5 67.5 568.366 67.5 564.5 L 67.5 544.75 C 67.5 540.884 64.365993 537.75 60.5 537.75 L 58.5 537.75 L 49.5 546.75 L 50 546.75 C 52.20914 546.75 54 548.54086 54 550.75 L 54 556.25 C 54 558.45914 52.20914 560.25 50 560.25 L 36 560.25 L 22 560.25 C 19.790861 560.25 18 558.45914 18 556.25 L 18 556.25 C 18 556.25 18 556.25 18 556.25 L 18 550.75 C 18 548.54086 19.790861 546.75 22 546.75 C 22 546.75 22 546.75 22 546.75 L 22.5 546.75 Z"/><path d="M 16.37132 533.87132 L 33.87868 551.37868 C 35.050253 552.55025 36.949747 552.55025 38.12132 551.37868 L 55.62868 533.87132 C 56.800252 532.69975 56.800252 530.80025 55.62868 529.62868 C 55.06607 529.06607 54.30301 528.75 53.50736 528.75 L 48 528.75 C 46.343146 528.75 45 527.40685 45 525.75 L 45 516 C 45 514.34315 43.656854 513 42 513 L 30 513 C 28.343146 513 27 514.34315 27 516 L 27 525.75 C 27 527.40685 25.656854 528.75 24 528.75 L 18.492641 528.75 C 16.835786 528.75 15.492641 530.09315 15.492641 531.75 C 15.492641 532.54565 15.808711 533.3087 16.37132 533.87132 Z"/></svg>
|
||||
|
||||
@@ -14,9 +14,9 @@ Appearance/Palette/Editor/Clone/Prompt: It is recommended that you clone this sh
|
||||
Appearance/Palette/Editor/Prompt/Modified: This shadow palette has been modified
|
||||
Appearance/Palette/Editor/Prompt: Editing
|
||||
Appearance/Palette/Editor/Reset/Caption: reset
|
||||
Appearance/Palette/ShowEditor/Caption: show editor
|
||||
Appearance/Palette/HideEditor/Caption: hide editor
|
||||
Appearance/Palette/Prompt: Current palette:
|
||||
Appearance/Palette/ShowEditor/Caption: show editor
|
||||
Appearance/StoryView/Caption: Story View
|
||||
Appearance/StoryView/Prompt: Current view:
|
||||
Appearance/Theme/Caption: Theme
|
||||
@@ -40,6 +40,9 @@ Plugins/Caption: Plugins
|
||||
Plugins/Fields/Description: Description
|
||||
Plugins/Fields/Title: Title
|
||||
Plugins/Fields/Version: Version
|
||||
Plugins/Language/Prompt: Languages
|
||||
Plugins/Plugin/Prompt: Plugins
|
||||
Plugins/Theme/Prompt: Themes
|
||||
Saving/AutoSave/Disabled/Button: enable
|
||||
Saving/AutoSave/Disabled/Prompt: Autosave is currently disabled
|
||||
Saving/AutoSave/Enabled/Button: disable
|
||||
|
||||
100
core/language/en-GB/Docs/PaletteColours.multids
Normal file
100
core/language/en-GB/Docs/PaletteColours.multids
Normal file
@@ -0,0 +1,100 @@
|
||||
title: $:/language/Docs/PaletteColours/
|
||||
|
||||
alert-background: Alert background
|
||||
alert-border: Alert border
|
||||
alert-highlight: Alert highlight
|
||||
alert-muted-foreground: Alert muted foreground
|
||||
background: General background
|
||||
blockquote-bar: Blockquote bar
|
||||
code-background: Code background
|
||||
code-border: Code border
|
||||
code-foreground: Code foreground
|
||||
download-background: Download button background
|
||||
download-foreground: Download button foreground
|
||||
dragger-background: Dragger background
|
||||
dragger-foreground: Dragger foreground
|
||||
dropdown-background: Dropdown background
|
||||
dropdown-border: Dropdown border
|
||||
dropdown-tab-background-selected: Dropdown tab background for selected tabs
|
||||
dropdown-tab-background: Dropdown tab background
|
||||
dropzone-background: Dropzone background
|
||||
external-link-background-hover: External link background hover
|
||||
external-link-background-visited: External link background visited
|
||||
external-link-background: External link background
|
||||
external-link-foreground-hover: External link foreground hover
|
||||
external-link-foreground-visited: External link foreground visited
|
||||
external-link-foreground: External link foreground
|
||||
foreground: General foreground
|
||||
message-background: Message box background
|
||||
message-border: Message box border
|
||||
message-foreground: Message box foreground
|
||||
modal-backdrop: Modal backdrop
|
||||
modal-background: Modal background
|
||||
modal-border: Modal border
|
||||
modal-footer-background: Modal footer background
|
||||
modal-footer-border: Modal footer border
|
||||
modal-header-border: Modal header border
|
||||
muted-foreground: General muted foreground
|
||||
notification-background: Notification background
|
||||
notification-border: Notification border
|
||||
page-background: Page background
|
||||
pre-background: Preformatted code background
|
||||
pre-border: Preformatted code border
|
||||
primary: General primary
|
||||
sidebar-button-foreground: Sidebar button foreground
|
||||
sidebar-controls-foreground-hover: Sidebar controls foreground hover
|
||||
sidebar-controls-foreground: Sidebar controls foreground
|
||||
sidebar-foreground-shadow: Sidebar foreground shadow
|
||||
sidebar-foreground: Sidebar foreground
|
||||
sidebar-muted-foreground-hover: Sidebar muted foreground hover
|
||||
sidebar-muted-foreground: Sidebar muted foreground
|
||||
sidebar-tab-background-selected: Sidebar tab background for selected tabs
|
||||
sidebar-tab-background: Sidebar tab background
|
||||
sidebar-tab-border-selected: Sidebar tab border for selected tabs
|
||||
sidebar-tab-border: Sidebar tab border
|
||||
sidebar-tab-divider: Sidebar tab divider
|
||||
sidebar-tab-foreground-selected: Sidebar tab foreground for selected tabs
|
||||
sidebar-tab-foreground: Sidebar tab foreground
|
||||
sidebar-tiddler-link-foreground-hover: Sidebar tiddler link foreground hover
|
||||
sidebar-tiddler-link-foreground: Sidebar tiddler link foreground
|
||||
static-alert-foreground: Static alert foreground
|
||||
tab-background-selected: Tab background for selected tabs
|
||||
tab-background: Tab background
|
||||
tab-border-selected: Tab border for selected tabs
|
||||
tab-border: Tab border
|
||||
tab-divider: Tab divider
|
||||
tab-foreground-selected: Tab foreground for selected tabs
|
||||
tab-foreground: Tab foreground
|
||||
table-border: Table border
|
||||
table-footer-background: Table footer background
|
||||
table-header-background: Table header background
|
||||
tag-background: Tag background
|
||||
tag-foreground: Tag foreground
|
||||
tiddler-background: Tiddler background
|
||||
tiddler-border: Tiddler border
|
||||
tiddler-controls-foreground-hover: Tiddler controls foreground hover
|
||||
tiddler-controls-foreground-selected: Tiddler controls foreground for selected controls
|
||||
tiddler-controls-foreground: Tiddler controls foreground
|
||||
tiddler-editor-background: Tiddler editor background
|
||||
tiddler-editor-border-image: Tiddler editor border image
|
||||
tiddler-editor-border: Tiddler editor border
|
||||
tiddler-editor-fields-even: Tiddler editor background for even fields
|
||||
tiddler-editor-fields-odd: Tiddler editor background for odd fields
|
||||
tiddler-info-background: Tiddler info panel background
|
||||
tiddler-info-border: Tiddler info panel border
|
||||
tiddler-info-tab-background: Tiddler info panel tab background
|
||||
tiddler-link-background: Tiddler link background
|
||||
tiddler-link-foreground: Tiddler link foreground
|
||||
tiddler-subtitle-foreground: Tiddler subtitle foreground
|
||||
tiddler-title-foreground: Tiddler title foreground
|
||||
toolbar-new-button: Toolbar 'new tiddler' button foreground
|
||||
toolbar-options-button: Toolbar 'options' button foreground
|
||||
toolbar-save-button: Toolbar 'save' button foreground
|
||||
toolbar-info-button: Toolbar 'info' button foreground
|
||||
toolbar-edit-button: Toolbar 'edit' button foreground
|
||||
toolbar-close-button: Toolbar 'close' button foreground
|
||||
toolbar-delete-button: Toolbar 'delete' button foreground
|
||||
toolbar-cancel-button: Toolbar 'cancel' button foreground
|
||||
toolbar-done-button: Toolbar 'done' button foreground
|
||||
untagged-background: Untagged pill background
|
||||
very-muted-foreground: Very muted foreground
|
||||
@@ -1,6 +1,6 @@
|
||||
title: $:/language/EditTemplate/
|
||||
|
||||
Body/Hint: Use WikiText to add formatting, images, and dynamic features
|
||||
Body/Hint: Use [[wiki text|http://tiddlywiki.com/static/WikiText.html]] to add formatting, images, and dynamic features
|
||||
Body/Placeholder: Type the text for this tiddler
|
||||
Body/Preview/Button/Hide: hide preview
|
||||
Body/Preview/Button/Show: show preview
|
||||
|
||||
@@ -16,6 +16,8 @@ hack-to-give-us-something-to-compare-against: A temporary storage field used in
|
||||
icon: The title of the tiddler containing the icon associated with a tiddler
|
||||
library: If set to "yes" indicates that a tiddler should be saved as a JavaScript library
|
||||
list: An ordered list of tiddler titles associated with a tiddler
|
||||
list-before: If set, the title of a tiddler before which this tiddler should be added to the ordered list of tiddler titles, or at the start of the list if this field is present but empty
|
||||
list-after: If set, the title of the tiddler after which this tiddler should be added to the ordered list of tiddler titles
|
||||
modified: The date and time at which a tiddler was last modified
|
||||
modifier: The tiddler title associated with the person who last modified a tiddler
|
||||
name: The human readable name associated with a plugin tiddler
|
||||
@@ -29,4 +31,4 @@ tags: A list of tags associated with a tiddler
|
||||
text: The body text of a tiddler
|
||||
title: The unique name of a tiddler
|
||||
type: The content type of a tiddler
|
||||
version: Version information for a plugin
|
||||
version: Version information for a plugin
|
||||
|
||||
12
core/language/en-GB/Filters.multids
Normal file
12
core/language/en-GB/Filters.multids
Normal file
@@ -0,0 +1,12 @@
|
||||
title: $:/language/Filters/
|
||||
|
||||
AllTiddlers: All tiddlers except system tiddlers
|
||||
RecentTiddlers: Recently modified tiddlers
|
||||
AllTags: All tags except system tags
|
||||
Missing: Missing tiddlers
|
||||
Drafts: Draft tiddlers
|
||||
Orphans: Orphan tiddlers
|
||||
SystemTiddlers: System tiddlers
|
||||
ShadowTiddlers: Shadow tiddlers
|
||||
OverriddenShadowTiddlers: Overridden shadow tiddlers
|
||||
SystemTags: System tags
|
||||
@@ -12,3 +12,5 @@ To load tiddlers from an encrypted TiddlyWiki file you should first specify the
|
||||
```
|
||||
tiddlywiki ./MyWiki --password pa55w0rd --load my_encrypted_wiki.html
|
||||
```
|
||||
|
||||
Note that TiddlyWiki will not load an older version of an already loaded plugin.
|
||||
|
||||
@@ -1,4 +1,30 @@
|
||||
title: $:/language/
|
||||
|
||||
RecentChanges/DateFormat: DDth MMM YYYY
|
||||
ClassicWarning/Hint: This tiddler is written in TiddlyWiki Classic wiki text format, which is not fully compatible with TiddlyWiki version 5. See http://tiddlywiki.com/static/Upgrading.html for more details.
|
||||
ClassicWarning/Upgrade/Caption: upgrade
|
||||
CloseAll/Button: close all
|
||||
ConfirmCancelTiddler: Do you wish to discard changes to the tiddler "<$text text=<<title>>/>"?
|
||||
ConfirmDeleteTiddler: Do you wish to delete the tiddler "<$text text=<<title>>/>"?
|
||||
ConfirmOverwriteTiddler: Do you wish to overwrite the tiddler "<$text text=<<title>>/>"?
|
||||
InvalidFieldName: Illegal characters in field name "<$text text=<<fieldName>>/>". Fields can only contain lowercase letters and the characters underscore (`_`), hyphen (`-`) and period (`.`)
|
||||
MissingTiddler/Hint: Missing tiddler "<$text text=<<currentTiddler>>/>" - click {{$:/core/images/edit-button}} to create
|
||||
RecentChanges/DateFormat: DDth MMM YYYY
|
||||
RelativeDate/Future/Days: <<period>> days from now
|
||||
RelativeDate/Future/Hours: <<period>> hours from now
|
||||
RelativeDate/Future/Minutes: <<period>> minutes from now
|
||||
RelativeDate/Future/Months: <<period>> months from now
|
||||
RelativeDate/Future/Second: 1 second from now
|
||||
RelativeDate/Future/Seconds: <<period>> seconds from now
|
||||
RelativeDate/Future/Years: <<period>> years from now
|
||||
RelativeDate/Past/Days: <<period>> days ago
|
||||
RelativeDate/Past/Hours: <<period>> hours ago
|
||||
RelativeDate/Past/Minutes: <<period>> minutes ago
|
||||
RelativeDate/Past/Months: <<period>> months ago
|
||||
RelativeDate/Past/Second: 1 second ago
|
||||
RelativeDate/Past/Seconds: <<period>> seconds ago
|
||||
RelativeDate/Past/Years: <<period>> years ago
|
||||
SystemTiddler/Tooltip: This is a system tiddler
|
||||
TagManager/Colour/Heading: Colour
|
||||
TagManager/Count/Heading: Count
|
||||
TagManager/Icon/Heading: Icon
|
||||
TagManager/Tag/Heading: Tag
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
title: $:/language/TiddlerInfo/
|
||||
|
||||
Advanced/Caption: Advanced
|
||||
Advanced/PluginInfo/Empty/Hint: none
|
||||
Advanced/PluginInfo/Heading: Plugin Details
|
||||
Advanced/PluginInfo/Hint: This plugin contains the following shadow tiddlers:
|
||||
Advanced/ShadowInfo/Heading: Shadow Status
|
||||
Advanced/ShadowInfo/NotShadow/Hint: The tiddler <$link to=<<infoTiddler>>><$text text=<<infoTiddler>>/></$link> is not a shadow tiddler
|
||||
Advanced/ShadowInfo/Shadow/Hint: The tiddler <$link to=<<infoTiddler>>><$text text=<<infoTiddler>>/></$link> is a shadow tiddler
|
||||
Advanced/ShadowInfo/Shadow/Source: It is defined in the plugin <$link to=<<pluginTiddler>>><$text text=<<pluginTiddler>>/></$link>
|
||||
Advanced/ShadowInfo/OverriddenShadow/Hint: It is overridden by an ordinary tiddler
|
||||
Fields/Caption: Fields
|
||||
List/Caption: List
|
||||
List/Empty: This tiddler does not have a list
|
||||
|
||||
3
core/language/en-GB/Types/text_html.tid
Normal file
3
core/language/en-GB/Types/text_html.tid
Normal file
@@ -0,0 +1,3 @@
|
||||
title: $:/language/Docs/Types/text/html
|
||||
description: HTML markup
|
||||
name: text/html
|
||||
@@ -34,7 +34,7 @@ Command.prototype.execute = function() {
|
||||
for(var editionIndex=0; editionIndex<editions.length; editionIndex++) {
|
||||
var editionName = editions[editionIndex];
|
||||
// Check the edition exists
|
||||
var editionPath = path.resolve($tw.boot.corePath,$tw.config.editionsPath) + "/" + editionName;
|
||||
var editionPath = path.resolve($tw.boot.corePath,$tw.config.editionsPath) + path.sep + editionName;
|
||||
if(!$tw.utils.isDirectory(editionPath)) {
|
||||
return "Edition '" + editionName + "' not found";
|
||||
}
|
||||
|
||||
@@ -30,8 +30,9 @@ Command.prototype.execute = function() {
|
||||
if(this.params.length < 1) {
|
||||
return "Missing filename";
|
||||
}
|
||||
fs.readFile(this.params[0],"utf8",function(err,data) {
|
||||
if(err) {
|
||||
var ext = path.extname(self.params[0]);
|
||||
fs.readFile(this.params[0],$tw.utils.getTypeEncoding(ext),function(err,data) {
|
||||
if (err) {
|
||||
self.callback(err);
|
||||
} else {
|
||||
var fields = {title: self.params[0]},
|
||||
@@ -41,7 +42,7 @@ Command.prototype.execute = function() {
|
||||
self.callback("No tiddlers found in file \"" + self.params[0] + "\"");
|
||||
} else {
|
||||
for(var t=0; t<tiddlers.length; t++) {
|
||||
self.commander.wiki.addTiddler(new $tw.Tiddler(tiddlers[t]));
|
||||
self.commander.wiki.importTiddler(new $tw.Tiddler(tiddlers[t]));
|
||||
}
|
||||
self.callback(null);
|
||||
}
|
||||
|
||||
@@ -95,8 +95,9 @@ SimpleServer.prototype.listen = function(port,host) {
|
||||
if(username && password) {
|
||||
// Check they match
|
||||
if(self.checkCredentials(request,username,password) !== "ALLOWED") {
|
||||
var servername = state.wiki.getTiddlerText("$:/SiteTitle") || "TiddlyWiki5";
|
||||
response.writeHead(401,"Authentication required",{
|
||||
"WWW-Authenticate": 'Basic realm="Please provide your username and password to login to TiddlyWiki5"'
|
||||
"WWW-Authenticate": 'Basic realm="Please provide your username and password to login to ' + servername + '"'
|
||||
});
|
||||
response.end();
|
||||
return;
|
||||
|
||||
@@ -37,4 +37,6 @@ exports.htmlVoidElements = "area,base,br,col,command,embed,hr,img,input,keygen,l
|
||||
|
||||
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.htmlUnsafeElements = "script".split(",");
|
||||
|
||||
})();
|
||||
|
||||
@@ -3,7 +3,7 @@ title: $:/core/modules/filters.js
|
||||
type: application/javascript
|
||||
module-type: wikimethod
|
||||
|
||||
Adds tiddler filtering to the $tw.Wiki object.
|
||||
Adds tiddler filtering methods to the $tw.Wiki object.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
@@ -149,11 +149,16 @@ exports.getFilterOperators = function() {
|
||||
return this.filterOperators;
|
||||
};
|
||||
|
||||
exports.filterTiddlers = function(filterString,currTiddlerTitle,tiddlerList) {
|
||||
exports.filterTiddlers = function(filterString,currTiddlerTitle,source) {
|
||||
var fn = this.compileFilter(filterString);
|
||||
return fn.call(this,tiddlerList || this.tiddlers,currTiddlerTitle);
|
||||
return fn.call(this,source,currTiddlerTitle);
|
||||
};
|
||||
|
||||
/*
|
||||
Compile a filter into a function with the signature fn(source,currTiddlerTitle) where:
|
||||
source: an iterator function for the source tiddlers, called source(iterator), where iterator is called as iterator(tiddler,title)
|
||||
currTiddlerTitle: the optional name of the current tiddler
|
||||
*/
|
||||
exports.compileFilter = function(filterString) {
|
||||
var filterParseTree;
|
||||
try {
|
||||
@@ -175,10 +180,15 @@ exports.compileFilter = function(filterString) {
|
||||
var accumulator = source,
|
||||
results = [];
|
||||
$tw.utils.each(operation.operators,function(operator) {
|
||||
var operatorFunction = filterOperators[operator.operator] || filterOperators.field || function(source,operator,operations) {
|
||||
return ["Filter Error: unknown operator '" + operator.operator + "'"];
|
||||
},
|
||||
operand = operator.operand;
|
||||
var operand = operator.operand,
|
||||
operatorFunction;
|
||||
if(!operator.operator) {
|
||||
operatorFunction = filterOperators.title;
|
||||
} else if(!filterOperators[operator.operator]) {
|
||||
operatorFunction = filterOperators.field;
|
||||
} else {
|
||||
operatorFunction = filterOperators[operator.operator];
|
||||
}
|
||||
if(operator.indirect) {
|
||||
operand = self.getTextReference(operator.operand,"",currTiddlerTitle);
|
||||
}
|
||||
@@ -192,7 +202,7 @@ exports.compileFilter = function(filterString) {
|
||||
wiki: self,
|
||||
currTiddlerTitle: currTiddlerTitle
|
||||
});
|
||||
accumulator = results;
|
||||
accumulator = self.makeTiddlerIterator(results);
|
||||
});
|
||||
return results;
|
||||
};
|
||||
@@ -210,22 +220,26 @@ exports.compileFilter = function(filterString) {
|
||||
case "+": // This operation is applied to the main results so far
|
||||
return function(results,source,currTiddlerTitle) {
|
||||
// This replaces all the elements of the array, but keeps the actual array so that references to it are preserved
|
||||
source = results.slice(0);
|
||||
source = self.makeTiddlerIterator(results);
|
||||
results.splice(0,results.length);
|
||||
$tw.utils.pushTop(results,operationSubFunction(source,currTiddlerTitle));
|
||||
};
|
||||
}
|
||||
})());
|
||||
});
|
||||
// Return a function that applies the operations to a source array/hashmap of tiddler titles
|
||||
return function(source,currTiddlerTitle) {
|
||||
source = source || self.tiddlers;
|
||||
// Return a function that applies the operations to a source iterator of tiddler titles
|
||||
return $tw.perf.measure("filter",function filterFunction(source,currTiddlerTitle) {
|
||||
if(!source) {
|
||||
source = self.each;
|
||||
} else if(typeof source === "object") { // Array or hashmap
|
||||
source = self.makeTiddlerIterator(source);
|
||||
}
|
||||
var results = [];
|
||||
$tw.utils.each(operationFunctions,function(operationFunction) {
|
||||
operationFunction(results,source,currTiddlerTitle);
|
||||
});
|
||||
return results;
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
45
core/modules/filters/all.js
Normal file
45
core/modules/filters/all.js
Normal file
@@ -0,0 +1,45 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/all.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for selecting tiddlers
|
||||
|
||||
[all[shadows+tiddlers]]
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var allFilterOperators;
|
||||
|
||||
function getAllFilterOperators() {
|
||||
if(!allFilterOperators) {
|
||||
allFilterOperators = {};
|
||||
$tw.modules.applyMethods("allfilteroperator",allFilterOperators);
|
||||
}
|
||||
return allFilterOperators;
|
||||
}
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.all = function(source,operator,options) {
|
||||
// Get our suboperators
|
||||
var allFilterOperators = getAllFilterOperators();
|
||||
// Cycle through the suboperators accumulating their results
|
||||
var results = [],
|
||||
subops = operator.operand.split("+");
|
||||
for(var t=0; t<subops.length; t++) {
|
||||
var subop = allFilterOperators[subops[t]];
|
||||
if(subop) {
|
||||
$tw.utils.pushTop(results,subop(source,operator.prefix,options));
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
26
core/modules/filters/all/current.js
Normal file
26
core/modules/filters/all/current.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/all/current.js
|
||||
type: application/javascript
|
||||
module-type: allfilteroperator
|
||||
|
||||
Filter function for [all[current]]
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.current = function(source,prefix,options) {
|
||||
if(options.currTiddlerTitle) {
|
||||
return [options.currTiddlerTitle];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
22
core/modules/filters/all/missing.js
Normal file
22
core/modules/filters/all/missing.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/all/missing.js
|
||||
type: application/javascript
|
||||
module-type: allfilteroperator
|
||||
|
||||
Filter function for [all[missing]]
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.missing = function(source,prefix,options) {
|
||||
return options.wiki.getMissingTitles();
|
||||
};
|
||||
|
||||
})();
|
||||
22
core/modules/filters/all/orphans.js
Normal file
22
core/modules/filters/all/orphans.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/all/orphans.js
|
||||
type: application/javascript
|
||||
module-type: allfilteroperator
|
||||
|
||||
Filter function for [all[orphans]]
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.orphans = function(source,prefix,options) {
|
||||
return options.wiki.getOrphanTitles();
|
||||
};
|
||||
|
||||
})();
|
||||
22
core/modules/filters/all/shadows.js
Normal file
22
core/modules/filters/all/shadows.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/all/shadows.js
|
||||
type: application/javascript
|
||||
module-type: allfilteroperator
|
||||
|
||||
Filter function for [all[shadows]]
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.shadows = function(source,prefix,options) {
|
||||
return options.wiki.allShadowTitles();
|
||||
};
|
||||
|
||||
})();
|
||||
22
core/modules/filters/all/tiddlers.js
Normal file
22
core/modules/filters/all/tiddlers.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/all/tiddlers.js
|
||||
type: application/javascript
|
||||
module-type: allfilteroperator
|
||||
|
||||
Filter function for [all[tiddlers]]
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.tiddlers = function(source,prefix,options) {
|
||||
return options.wiki.allTitles();
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -17,20 +17,9 @@ Export our filter function
|
||||
*/
|
||||
exports.backlinks = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
source(function(tiddler,title) {
|
||||
$tw.utils.pushTop(results,options.wiki.getTiddlerBacklinks(title));
|
||||
}
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
@@ -16,18 +16,9 @@ Filter operator that selects one tiddler for each unique value of the specified
|
||||
Export our filter function
|
||||
*/
|
||||
exports.each = function(source,operator,options) {
|
||||
// Convert the source to an array if necessary
|
||||
if(!$tw.utils.isArray(source)) {
|
||||
var copy = [];
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
copy.push(title);
|
||||
});
|
||||
source = copy;
|
||||
}
|
||||
// Collect up the first tiddler with each unique value of the specified field
|
||||
var results = [],values = {};
|
||||
$tw.utils.each(source,function(title) {
|
||||
var tiddler = options.wiki.getTiddler(title);
|
||||
var results = [],
|
||||
values = {};
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler) {
|
||||
var value = tiddler.getFieldString(operator.operand);
|
||||
if(!$tw.utils.hop(values,value)) {
|
||||
|
||||
@@ -16,23 +16,14 @@ Filter operator that selects one tiddler for each unique day covered by the spec
|
||||
Export our filter function
|
||||
*/
|
||||
exports.eachday = function(source,operator,options) {
|
||||
var results = [],
|
||||
values = [];
|
||||
// Function to convert a date/time to a date integer
|
||||
var toDate = function(value) {
|
||||
value = (new Date(value)).setHours(0,0,0,0);
|
||||
return value+0;
|
||||
};
|
||||
// Convert the source to an array if necessary
|
||||
if(!$tw.utils.isArray(source)) {
|
||||
var copy = [];
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
copy.push(title);
|
||||
});
|
||||
source = copy;
|
||||
}
|
||||
// Collect up the first tiddler with each unique day value of the specified field
|
||||
var results = [],values = [];
|
||||
$tw.utils.each(source,function(title) {
|
||||
var tiddler = options.wiki.getTiddler(title);
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && tiddler.fields[operator.operand]) {
|
||||
var value = toDate(tiddler.fields[operator.operand]);
|
||||
if(values.indexOf(value) === -1) {
|
||||
|
||||
@@ -17,36 +17,47 @@ Export our filter function
|
||||
*/
|
||||
exports.field = function(source,operator,options) {
|
||||
var results = [],
|
||||
fieldname = (operator.suffix || operator.operator).toLowerCase(),
|
||||
isTitle = fieldname === "title";
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
var tiddler = options.wiki.getTiddler(title),
|
||||
text = tiddler ? tiddler.getFieldString(fieldname) : (isTitle ? title : null),
|
||||
match;
|
||||
if(text !== null) {
|
||||
if(operator.regexp) {
|
||||
match = !!operator.regexp.exec(text);
|
||||
} else {
|
||||
match = text === operator.operand;
|
||||
}
|
||||
if(operator.prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
results.push(title);
|
||||
}
|
||||
fieldname = (operator.suffix || operator.operator || "title").toLowerCase();
|
||||
if(operator.prefix === "!") {
|
||||
if(operator.regexp) {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler) {
|
||||
var text = tiddler.getFieldString(fieldname);
|
||||
if(text !== null && !operator.regexp.exec(text)) {
|
||||
results.push(title);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler) {
|
||||
var text = tiddler.getFieldString(fieldname);
|
||||
if(text !== null && text !== operator.operand) {
|
||||
results.push(title);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
if(operator.regexp) {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler) {
|
||||
var text = tiddler.getFieldString(fieldname);
|
||||
if(text !== null && !!operator.regexp.exec(text)) {
|
||||
results.push(title);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler) {
|
||||
var text = tiddler.getFieldString(fieldname);
|
||||
if(text !== null && text === operator.operand) {
|
||||
results.push(title);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -16,28 +16,14 @@ Filter operator for returning the names of the fields on the selected tiddlers
|
||||
Export our filter function
|
||||
*/
|
||||
exports.fields = function(source,operator,options) {
|
||||
var self = this,
|
||||
results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
// Return the fields on the specified tiddler
|
||||
var tiddler = options.wiki.getTiddler(title);
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler) {
|
||||
for(var fieldName in tiddler.fields) {
|
||||
$tw.utils.pushTop(results,fieldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
@@ -17,27 +17,17 @@ Export our filter function
|
||||
*/
|
||||
exports.has = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
var tiddler = options.wiki.getTiddler(title);
|
||||
if(tiddler) {
|
||||
var match = $tw.utils.hop(tiddler.fields,operator.operand) && tiddler.fields[operator.operand] !== "";
|
||||
if(operator.prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
if(operator.prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && (!$tw.utils.hop(tiddler.fields,operator.operand) || tiddler.fields[operator.operand] === "")) {
|
||||
results.push(title);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && $tw.utils.hop(tiddler.fields,operator.operand) && tiddler.fields[operator.operand] !== "") {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
return results;
|
||||
|
||||
@@ -16,26 +16,13 @@ Filter operator for returning the indexes of a data tiddler
|
||||
Export our filter function
|
||||
*/
|
||||
exports.indexes = function(source,operator,options) {
|
||||
var self = this,
|
||||
results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
// Return the fields on the specified tiddler
|
||||
var data = options.wiki.getTiddlerData(title,{});
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var data = options.wiki.getTiddlerData(title);
|
||||
if(data) {
|
||||
$tw.utils.pushTop(results,Object.keys(data));
|
||||
}
|
||||
}
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
});
|
||||
results.sort();
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -17,31 +17,18 @@ Export our filter function
|
||||
*/
|
||||
exports.current = function(source,prefix,options) {
|
||||
var results = [];
|
||||
// Function to check a tiddler
|
||||
function checkTiddler(title) {
|
||||
if(title !== options.currTiddlerTitle) {
|
||||
results.push(title);
|
||||
}
|
||||
};
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
if(prefix === "!") {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
if(source.indexOf(options.currTiddlerTitle) !== -1) {
|
||||
results.push(options.currTiddlerTitle);
|
||||
if(prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(title !== options.currTiddlerTitle) {
|
||||
results.push(title);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if(prefix === "!") {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
results.push(options.currTiddlerTitle);
|
||||
}
|
||||
source(function(tiddler,title) {
|
||||
if(title === options.currTiddlerTitle) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -17,24 +17,17 @@ Export our filter function
|
||||
*/
|
||||
exports.image = function(source,prefix,options) {
|
||||
var results = [];
|
||||
// Function to check a tiddler
|
||||
function checkTiddler(title) {
|
||||
var match = options.wiki.isImageTiddler(title);
|
||||
if(prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
results.push(title);
|
||||
}
|
||||
};
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
if(prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(!options.wiki.isImageTiddler(title)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
source(function(tiddler,title) {
|
||||
if(options.wiki.isImageTiddler(title)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
return results;
|
||||
|
||||
@@ -16,31 +16,19 @@ Filter function for [is[missing]]
|
||||
Export our filter function
|
||||
*/
|
||||
exports.missing = function(source,prefix,options) {
|
||||
var results = [],
|
||||
missingTitles;
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
missingTitles = options.wiki.getMissingTitles();
|
||||
$tw.utils.each(source,function(title) {
|
||||
var match = missingTitles.indexOf(title) !== -1;
|
||||
if(prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
var results = [];
|
||||
if(prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(options.wiki.tiddlerExists(title)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if(prefix !== "!") {
|
||||
missingTitles = options.wiki.getMissingTitles();
|
||||
$tw.utils.each(missingTitles,function(title) {
|
||||
source(function(tiddler,title) {
|
||||
if(!options.wiki.tiddlerExists(title)) {
|
||||
results.push(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
results.push(title);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -18,24 +18,15 @@ Export our filter function
|
||||
exports.orphan = function(source,prefix,options) {
|
||||
var results = [],
|
||||
orphanTitles = options.wiki.getOrphanTitles();
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
var match = orphanTitles.indexOf(title) !== -1;
|
||||
if(prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
if(prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(orphanTitles.indexOf(title) === -1) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
var match = orphanTitles.indexOf(title) !== -1;
|
||||
if(prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
source(function(tiddler,title) {
|
||||
if(orphanTitles.indexOf(title) !== -1) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -17,31 +17,18 @@ Export our filter function
|
||||
*/
|
||||
exports.shadow = function(source,prefix,options) {
|
||||
var results = [];
|
||||
// Function to check a tiddler
|
||||
function checkTiddler(title) {
|
||||
var match = options.wiki.isShadowTiddler(title);
|
||||
if(prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
results.push(title);
|
||||
}
|
||||
};
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
if(prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(!options.wiki.isShadowTiddler(title)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if(prefix !== "!") {
|
||||
$tw.utils.each(options.wiki.shadowTiddlers,function(tiddler,title) {
|
||||
source(function(tiddler,title) {
|
||||
if(options.wiki.isShadowTiddler(title)) {
|
||||
results.push(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -17,24 +17,17 @@ Export our filter function
|
||||
*/
|
||||
exports.system = function(source,prefix,options) {
|
||||
var results = [];
|
||||
// Function to check a tiddler
|
||||
function checkTiddler(title) {
|
||||
var match = options.wiki.isSystemTiddler(title);
|
||||
if(prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
results.push(title);
|
||||
}
|
||||
};
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
if(prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(!options.wiki.isSystemTiddler(title)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
source(function(tiddler,title) {
|
||||
if(options.wiki.isSystemTiddler(title)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
return results;
|
||||
|
||||
37
core/modules/filters/is/tag.js
Normal file
37
core/modules/filters/is/tag.js
Normal file
@@ -0,0 +1,37 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/is/tag.js
|
||||
type: application/javascript
|
||||
module-type: isfilteroperator
|
||||
|
||||
Filter function for [is[tag]]
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.tag = function(source,prefix,options) {
|
||||
var results = [],
|
||||
tagMap = options.wiki.getTagMap();
|
||||
if(prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(!$tw.utils.hop(tagMap,title)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
if($tw.utils.hop(tagMap,title)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -17,24 +17,17 @@ Export our filter function
|
||||
*/
|
||||
exports.tiddler = function(source,prefix,options) {
|
||||
var results = [];
|
||||
// Function to check a tiddler
|
||||
function checkTiddler(title) {
|
||||
var match = options.wiki.tiddlerExists(title);
|
||||
if(prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
results.push(title);
|
||||
}
|
||||
};
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
if(prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(!options.wiki.tiddlerExists(title)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
source(function(tiddler,title) {
|
||||
if(options.wiki.tiddlerExists(title)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
return results;
|
||||
|
||||
@@ -17,20 +17,16 @@ Export our filter function
|
||||
*/
|
||||
exports.limit = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Convert to an array if necessary
|
||||
if(!$tw.utils.isArray(source)) {
|
||||
var copy = [];
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
copy.push(title);
|
||||
});
|
||||
source = copy;
|
||||
}
|
||||
// Convert to an array
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
// Slice the array if necessary
|
||||
var limit = Math.min(source.length,parseInt(operator.operand,10));
|
||||
var limit = Math.min(results.length,parseInt(operator.operand,10));
|
||||
if(operator.prefix === "!") {
|
||||
results = source.slice(source.length - limit);
|
||||
results = results.slice(-limit);
|
||||
} else {
|
||||
results = source.slice(0,limit);
|
||||
results = results.slice(0,limit);
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -17,20 +17,9 @@ Export our filter function
|
||||
*/
|
||||
exports.links = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
source(function(tiddler,title) {
|
||||
$tw.utils.pushTop(results,options.wiki.getTiddlerLinks(title));
|
||||
}
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
@@ -19,28 +19,14 @@ exports.list = function(source,operator,options) {
|
||||
var results = [],
|
||||
tr = $tw.utils.parseTextReference(operator.operand),
|
||||
list = options.wiki.getTiddlerList(tr.title || options.currTiddlerTitle,tr.field,tr.index);
|
||||
function checkTiddler(title) {
|
||||
var match = list.indexOf(title) !== -1;
|
||||
if(operator.prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
results.push(title);
|
||||
}
|
||||
}
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
if(operator.prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(list.indexOf(title) === -1) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if(operator.prefix !== "!") {
|
||||
results = list;
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
results = list;
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -17,20 +17,9 @@ Export our filter function
|
||||
*/
|
||||
exports.listed = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
source(function(tiddler,title) {
|
||||
$tw.utils.pushTop(results,options.wiki.findListingsOfTiddler(title));
|
||||
}
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
@@ -17,10 +17,7 @@ Reverse list
|
||||
*/
|
||||
exports.reverse = function(source,operator,options) {
|
||||
var results = [];
|
||||
if(!$tw.utils.isArray(source)) {
|
||||
source = Object.keys(source).sort();
|
||||
}
|
||||
$tw.utils.each(source,function(title) {
|
||||
source(function(tiddler,title) {
|
||||
results.unshift(title);
|
||||
});
|
||||
return results;
|
||||
@@ -30,33 +27,36 @@ exports.reverse = function(source,operator,options) {
|
||||
First entry/entries in list
|
||||
*/
|
||||
exports.first = function(source,operator,options) {
|
||||
var count = parseInt(operator.operand) || 1;
|
||||
if(!$tw.utils.isArray(source)) {
|
||||
source = Object.keys(source).sort();
|
||||
}
|
||||
return source.slice(0,Math.min(count,source.length));
|
||||
var count = parseInt(operator.operand) || 1,
|
||||
results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
return results.slice(0,count);
|
||||
};
|
||||
|
||||
/*
|
||||
Last entry/entries in list
|
||||
*/
|
||||
exports.last = function(source,operator,options) {
|
||||
var count = parseInt(operator.operand) || 1;
|
||||
if(!$tw.utils.isArray(source)) {
|
||||
source = Object.keys(source).sort();
|
||||
}
|
||||
return source.slice(-count);
|
||||
var count = parseInt(operator.operand) || 1,
|
||||
results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
return results.slice(-count);
|
||||
};
|
||||
|
||||
/*
|
||||
All but the first entry/entries of the list
|
||||
*/
|
||||
exports.rest = function(source,operator,options) {
|
||||
var count = parseInt(operator.operand) || 1;
|
||||
if(!$tw.utils.isArray(source)) {
|
||||
source = Object.keys(source).sort();
|
||||
}
|
||||
return source.slice(count);
|
||||
var count = parseInt(operator.operand) || 1,
|
||||
results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
return results.slice(count);
|
||||
};
|
||||
exports.butfirst = exports.rest;
|
||||
exports.bf = exports.rest;
|
||||
@@ -65,11 +65,12 @@ exports.bf = exports.rest;
|
||||
All but the last entry/entries of the list
|
||||
*/
|
||||
exports.butlast = function(source,operator,options) {
|
||||
var count = parseInt(operator.operand) || 1;
|
||||
if(!$tw.utils.isArray(source)) {
|
||||
source = Object.keys(source).sort();
|
||||
}
|
||||
return source.slice(0,-count);
|
||||
var count = parseInt(operator.operand) || 1,
|
||||
results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
return results.slice(0,-count);
|
||||
};
|
||||
exports.bl = exports.butlast;
|
||||
|
||||
@@ -77,11 +78,12 @@ exports.bl = exports.butlast;
|
||||
The nth member of the list
|
||||
*/
|
||||
exports.nth = function(source,operator,options) {
|
||||
var count = parseInt(operator.operand) || 1;
|
||||
if(!$tw.utils.isArray(source)) {
|
||||
source = Object.keys(source).sort();
|
||||
}
|
||||
return source.slice(count-1,count);
|
||||
var count = parseInt(operator.operand) || 1,
|
||||
results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
return results.slice(count - 1,count);
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -16,22 +16,12 @@ Filter operator for returning the titles of the modules of a given type in this
|
||||
Export our filter function
|
||||
*/
|
||||
exports.modules = function(source,operator,options) {
|
||||
var results = [],
|
||||
pushModules = function(type) {
|
||||
$tw.utils.each($tw.modules.types[type],function(moduleInfo,moduleName) {
|
||||
results.push(moduleName);
|
||||
});
|
||||
};
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
pushModules(title);
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
$tw.utils.each($tw.modules.types[title],function(moduleInfo,moduleName) {
|
||||
results.push(moduleName);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
pushModules(title);
|
||||
});
|
||||
}
|
||||
});
|
||||
results.sort();
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -18,25 +18,14 @@ Export our filter function
|
||||
exports.next = function(source,operator,options) {
|
||||
var results = [],
|
||||
list = options.wiki.getTiddlerList(operator.operand);
|
||||
|
||||
function checkTiddler(title) {
|
||||
source(function(tiddler,title) {
|
||||
var match = list.indexOf(title);
|
||||
// increment match and then test if result is in range
|
||||
match++;
|
||||
if(match > 0 && match < list.length) {
|
||||
results.push(list[match]);
|
||||
}
|
||||
}
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
32
core/modules/filters/plugintiddlers.js
Normal file
32
core/modules/filters/plugintiddlers.js
Normal file
@@ -0,0 +1,32 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/plugintiddlers.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for returning the titles of the shadow tiddlers within a plugin
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.plugintiddlers = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var pluginInfo = options.wiki.getPluginInfo(title);
|
||||
if(pluginInfo) {
|
||||
$tw.utils.each(pluginInfo.tiddlers,function(fields,title) {
|
||||
results.push(title);
|
||||
});
|
||||
}
|
||||
});
|
||||
results.sort();
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -17,24 +17,17 @@ Export our filter function
|
||||
*/
|
||||
exports.prefix = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
var match = title.substr(0,operator.operand.length).toLowerCase() === operator.operand.toLowerCase();
|
||||
if(operator.prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
results.push(title);
|
||||
}
|
||||
}
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
if(operator.prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(title.substr(0,operator.operand.length).toLowerCase() !== operator.operand.toLowerCase()) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
source(function(tiddler,title) {
|
||||
if(title.substr(0,operator.operand.length).toLowerCase() === operator.operand.toLowerCase()) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
return results;
|
||||
|
||||
@@ -18,25 +18,14 @@ Export our filter function
|
||||
exports.previous = function(source,operator,options) {
|
||||
var results = [],
|
||||
list = options.wiki.getTiddlerList(operator.operand);
|
||||
|
||||
function checkTiddler(title) {
|
||||
source(function(tiddler,title) {
|
||||
var match = list.indexOf(title);
|
||||
// decrement match and then test if result is in range
|
||||
// increment match and then test if result is in range
|
||||
match--;
|
||||
if( match >= 0 ) {
|
||||
if(match >= 0) {
|
||||
results.push(list[match]);
|
||||
}
|
||||
}
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
28
core/modules/filters/removeprefix.js
Normal file
28
core/modules/filters/removeprefix.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/removeprefix.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for removing a prefix from each title in the list. Titles that do not start with the prefix are removed.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.removeprefix = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
if(title.substr(0,operator.operand.length).toLowerCase() === operator.operand.toLowerCase()) {
|
||||
results.push(title.substr(operator.operand.length));
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -17,34 +17,19 @@ Export our filter function
|
||||
*/
|
||||
exports.sameday = function(source,operator,options) {
|
||||
var results = [],
|
||||
isSameDay = function(dateField,dateString) {
|
||||
var date1 = (new Date(dateField)).setHours(0,0,0,0),
|
||||
date2 = (new Date($tw.utils.parseDate(dateString))).setHours(0,0,0,0);
|
||||
return date1 === date2;
|
||||
fieldName = operator.suffix || "modified",
|
||||
targetDate = (new Date($tw.utils.parseDate(operator.operand))).setHours(0,0,0,0);
|
||||
// Function to convert a date/time to a date integer
|
||||
var isSameDay = function(dateField) {
|
||||
return (new Date(dateField)).setHours(0,0,0,0) === targetDate;
|
||||
};
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
var tiddler = options.wiki.getTiddler(title);
|
||||
if(tiddler) {
|
||||
var match = isSameDay(tiddler.fields.modified,operator.operand);
|
||||
if(operator.prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && tiddler.fields[fieldName]) {
|
||||
if(isSameDay(tiddler.fields[fieldName])) {
|
||||
results.push(title);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ Export our filter function
|
||||
exports.search = function(source,operator,options) {
|
||||
var invert = operator.prefix === "!";
|
||||
return options.wiki.search(operator.operand,{
|
||||
titles: source,
|
||||
source: source,
|
||||
invert: invert
|
||||
});
|
||||
};
|
||||
|
||||
30
core/modules/filters/shadowsource.js
Normal file
30
core/modules/filters/shadowsource.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/shadowsource.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for returning the source plugins for shadow tiddlers
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.shadowsource = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var source = options.wiki.getShadowSource(title);
|
||||
if(source) {
|
||||
$tw.utils.pushTop(results,source);
|
||||
}
|
||||
});
|
||||
results.sort();
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -17,38 +17,33 @@ Export our filter function
|
||||
*/
|
||||
exports.sort = function(source,operator,options) {
|
||||
var results = prepare_results(source);
|
||||
options.wiki.sortTiddlers(results,operator.operand,operator.prefix === "!",false,false);
|
||||
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",false,false);
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.nsort = function(source,operator,options) {
|
||||
var results = prepare_results(source);
|
||||
options.wiki.sortTiddlers(results,operator.operand,operator.prefix === "!",false,true);
|
||||
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",false,true);
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.sortcs = function(source,operator,options) {
|
||||
var results = prepare_results(source);
|
||||
options.wiki.sortTiddlers(results,operator.operand,operator.prefix === "!",true,false);
|
||||
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",true,false);
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.nsortcs = function(source,operator,options) {
|
||||
var results = prepare_results(source);
|
||||
options.wiki.sortTiddlers(results,operator.operand,operator.prefix === "!",true,true);
|
||||
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",true,true);
|
||||
return results;
|
||||
};
|
||||
|
||||
var prepare_results = function (source) {
|
||||
var results;
|
||||
if($tw.utils.isArray(source)) {
|
||||
results = source;
|
||||
} else {
|
||||
results = [];
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
results.push(title);
|
||||
});
|
||||
}
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,31 +17,18 @@ Export our filter function
|
||||
*/
|
||||
exports.tag = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
var tiddler = options.wiki.getTiddler(title);
|
||||
if(tiddler) {
|
||||
var match = tiddler.hasTag(operator.operand);
|
||||
if(operator.prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
if(operator.prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && !tiddler.hasTag(operator.operand)) {
|
||||
results.push(title);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && tiddler.hasTag(operator.operand)) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
// Sort the results if we are matching a tag
|
||||
if(operator.prefix !== "!") {
|
||||
results = options.wiki.sortByList(results,operator.operand);
|
||||
}
|
||||
return results;
|
||||
|
||||
@@ -17,20 +17,9 @@ Export our filter function
|
||||
*/
|
||||
exports.tagging = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
source(function(tiddler,title) {
|
||||
$tw.utils.pushTop(results,options.wiki.getTiddlersWithTag(title));
|
||||
}
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
@@ -17,23 +17,11 @@ Export our filter function
|
||||
*/
|
||||
exports.tags = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
var tiddler = options.wiki.getTiddler(title);
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && tiddler.fields.tags) {
|
||||
$tw.utils.pushTop(results,tiddler.fields.tags);
|
||||
}
|
||||
}
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
@@ -17,35 +17,14 @@ Export our filter function
|
||||
*/
|
||||
exports.title = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
var tiddler = options.wiki.getTiddler(title);
|
||||
if(tiddler) {
|
||||
var match = tiddler.fields[operator.operator] === operator.operand;
|
||||
if(operator.prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
if(operator.prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && tiddler.fields.title !== operator.operand) {
|
||||
results.push(title);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
// If we're filtering a hashmap we change the behaviour to pass through missing tiddlers
|
||||
if(operator.prefix !== "!") {
|
||||
results.push(operator.operand);
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
if(title !== operator.operand) {
|
||||
checkTiddler(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
results.push(operator.operand);
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -17,25 +17,17 @@ Export our filter function
|
||||
*/
|
||||
exports.untagged = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
var tiddler = options.wiki.getTiddler(title),
|
||||
match = tiddler && $tw.utils.isArray(tiddler.fields.tags) && tiddler.fields.tags.length > 0;
|
||||
if(operator.prefix !== "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
$tw.utils.pushTop(results,title);
|
||||
}
|
||||
}
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
if(operator.prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && $tw.utils.isArray(tiddler.fields.tags) && tiddler.fields.tags.length > 0) {
|
||||
$tw.utils.pushTop(results,title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
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;
|
||||
|
||||
37
core/modules/language.js
Normal file
37
core/modules/language.js
Normal file
@@ -0,0 +1,37 @@
|
||||
/*\
|
||||
title: $:/core/modules/language.js
|
||||
type: application/javascript
|
||||
module-type: global
|
||||
|
||||
The $tw.Language() manages translateable strings
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Create an instance of the language manager. Options include:
|
||||
wiki: wiki from which to retrieve translation tiddlers
|
||||
*/
|
||||
function Language(options) {
|
||||
options = options || "";
|
||||
this.wiki = options.wiki || $tw.wiki;
|
||||
}
|
||||
|
||||
/*
|
||||
Return a single translateable string. The title is automatically prefixed with "$:/language/"
|
||||
Options include:
|
||||
variables: optional hashmap of variables to supply to the language wikification
|
||||
*/
|
||||
Language.prototype.getString = function(title,options) {
|
||||
options = options || {};
|
||||
title = "$:/language/" + title;
|
||||
return this.wiki.renderTiddler("text/plain",title,{variables: options.variables});
|
||||
};
|
||||
|
||||
exports.Language = Language;
|
||||
|
||||
})();
|
||||
53
core/modules/parsers/csvparser.js
Normal file
53
core/modules/parsers/csvparser.js
Normal file
@@ -0,0 +1,53 @@
|
||||
/*\
|
||||
title: $:/core/modules/parsers/csvparser.js
|
||||
type: application/javascript
|
||||
module-type: parser
|
||||
|
||||
The CSV text parser processes CSV files into a table wrapped in a scrollable widget
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var CsvParser = function(type,text,options) {
|
||||
// Table framework
|
||||
this.tree = [{
|
||||
"type": "element", "tag": "$scrollable", "children": [{
|
||||
"type": "element", "tag": "table", "children": [{
|
||||
"type": "element", "tag": "tbody", "children": []
|
||||
}], "attributes": {
|
||||
"class": {"type": "string", "value": "tw-csv-table"}
|
||||
}
|
||||
}]
|
||||
}];
|
||||
// Split the text into lines
|
||||
var lines = text.split(/\r?\n/mg),
|
||||
tag = "th";
|
||||
for(var line=0; line<lines.length; line++) {
|
||||
var lineText = lines[line];
|
||||
if(lineText) {
|
||||
var row = {
|
||||
"type": "element", "tag": "tr", "children": []
|
||||
};
|
||||
var columns = lineText.split(",");
|
||||
for(var column=0; column<columns.length; column++) {
|
||||
row.children.push({
|
||||
"type": "element", "tag": tag, "children": [{
|
||||
"type": "text",
|
||||
"text": columns[column]
|
||||
}]
|
||||
});
|
||||
}
|
||||
tag = "td";
|
||||
this.tree[0].children[0].children[0].children.push(row);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports["text/csv"] = CsvParser;
|
||||
|
||||
})();
|
||||
|
||||
268
core/modules/parsers/parseutils.js
Normal file
268
core/modules/parsers/parseutils.js
Normal file
@@ -0,0 +1,268 @@
|
||||
/*\
|
||||
title: $:/core/modules/utils/parseutils.js
|
||||
type: application/javascript
|
||||
module-type: utils
|
||||
|
||||
Utility functions concerned with parsing text into tokens.
|
||||
|
||||
Most functions have the following pattern:
|
||||
|
||||
* The parameters are:
|
||||
** `source`: the source string being parsed
|
||||
** `pos`: the current parse position within the string
|
||||
** Any further parameters are used to identify the token that is being parsed
|
||||
* The return value is:
|
||||
** null if the token was not found at the specified position
|
||||
** an object representing the token with the following standard fields:
|
||||
*** `type`: string indicating the type of the token
|
||||
*** `start`: start position of the token in the source string
|
||||
*** `end`: end position of the token in the source string
|
||||
*** Any further fields required to describe the token
|
||||
|
||||
The exception is `skipWhiteSpace`, which just returns the position after the whitespace.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Look for a whitespace token. Returns null if not found, otherwise returns {type: "whitespace", start:, end:,}
|
||||
*/
|
||||
exports.parseWhiteSpace = function(source,pos) {
|
||||
var node = {
|
||||
type: "whitespace",
|
||||
start: pos
|
||||
};
|
||||
var re = /(\s)+/g;
|
||||
re.lastIndex = pos;
|
||||
var match = re.exec(source);
|
||||
if(match && match.index === pos) {
|
||||
node.end = pos + match[0].length;
|
||||
return node;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/*
|
||||
Convenience wrapper for parseWhiteSpace. Returns the position after the whitespace
|
||||
*/
|
||||
exports.skipWhiteSpace = function(source,pos) {
|
||||
var whitespace = $tw.utils.parseWhiteSpace(source,pos);
|
||||
if(whitespace) {
|
||||
return whitespace.end;
|
||||
}
|
||||
return pos;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a given string token. Returns null if not found, otherwise returns {type: "token", value:, start:, end:,}
|
||||
*/
|
||||
exports.parseTokenString = function(source,pos,token) {
|
||||
var match = source.indexOf(token,pos) === pos;
|
||||
if(match) {
|
||||
return {
|
||||
type: "token",
|
||||
value: token,
|
||||
start: pos,
|
||||
end: pos + token.length
|
||||
};
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a token matching a regex. Returns null if not found, otherwise returns {type: "regexp", match:, start:, end:,}
|
||||
*/
|
||||
exports.parseTokenRegExp = function(source,pos,reToken) {
|
||||
var node = {
|
||||
type: "regexp",
|
||||
start: pos
|
||||
};
|
||||
reToken.lastIndex = pos;
|
||||
node.match = reToken.exec(source);
|
||||
if(node.match && node.match.index === pos) {
|
||||
node.end = pos + node.match[0].length;
|
||||
return node;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a string literal. Returns null if not found, otherwise returns {type: "string", value:, start:, end:,}
|
||||
*/
|
||||
exports.parseStringLiteral = function(source,pos) {
|
||||
var node = {
|
||||
type: "string",
|
||||
start: pos
|
||||
};
|
||||
var reString = /(?:"([^"]*)")|(?:'([^']*)')/g;
|
||||
reString.lastIndex = pos;
|
||||
var match = reString.exec(source);
|
||||
if(match && match.index === pos) {
|
||||
node.value = match[1] === undefined ? match[2] : match[1];
|
||||
node.end = pos + match[0].length;
|
||||
return node;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a macro invocation parameter. Returns null if not found, or {type: "macro-parameter", name:, value:, start:, end:}
|
||||
*/
|
||||
exports.parseMacroParameter = function(source,pos) {
|
||||
var node = {
|
||||
type: "macro-parameter",
|
||||
start: pos
|
||||
};
|
||||
// Define our regexp
|
||||
var reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|([^\s>"'=]+)))/g;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for the parameter
|
||||
var token = $tw.utils.parseTokenRegExp(source,pos,reMacroParameter);
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Get the parameter details
|
||||
node.value = token.match[2] !== undefined ? token.match[2] : (
|
||||
token.match[3] !== undefined ? token.match[3] : (
|
||||
token.match[4] !== undefined ? token.match[4] : (
|
||||
token.match[5] !== undefined ? token.match[5] : (
|
||||
""
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
if(token.match[1]) {
|
||||
node.name = token.match[1];
|
||||
}
|
||||
// Update the end position
|
||||
node.end = pos;
|
||||
return node;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a macro invocation. Returns null if not found, or {type: "macrocall", name:, parameters:, start:, end:}
|
||||
*/
|
||||
exports.parseMacroInvocation = function(source,pos) {
|
||||
var node = {
|
||||
type: "macrocall",
|
||||
start: pos,
|
||||
params: []
|
||||
};
|
||||
// Define our regexps
|
||||
var reMacroName = /([^\s>"'=]+)/g;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a double less than sign
|
||||
var token = $tw.utils.parseTokenString(source,pos,"<<");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Get the macro name
|
||||
var name = $tw.utils.parseTokenRegExp(source,pos,reMacroName);
|
||||
if(!name) {
|
||||
return null;
|
||||
}
|
||||
node.name = name.match[1];
|
||||
pos = name.end;
|
||||
// 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);
|
||||
}
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a double greater than sign
|
||||
token = $tw.utils.parseTokenString(source,pos,">>");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Update the end position
|
||||
node.end = pos;
|
||||
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:,}
|
||||
*/
|
||||
exports.parseAttribute = function(source,pos) {
|
||||
var node = {
|
||||
start: pos
|
||||
};
|
||||
// Define our regexps
|
||||
var reAttributeName = /([^\/\s>"'=]+)/g,
|
||||
reUnquotedAttribute = /([^\/\s<>"'=]+)/g,
|
||||
reIndirectValue = /\{\{([^\}]+)\}\}/g;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Get the attribute name
|
||||
var name = $tw.utils.parseTokenRegExp(source,pos,reAttributeName);
|
||||
if(!name) {
|
||||
return null;
|
||||
}
|
||||
node.name = name.match[1];
|
||||
pos = name.end;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for an equals sign
|
||||
var token = $tw.utils.parseTokenString(source,pos,"=");
|
||||
if(token) {
|
||||
pos = token.end;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a string literal
|
||||
var stringLiteral = $tw.utils.parseStringLiteral(source,pos);
|
||||
if(stringLiteral) {
|
||||
pos = stringLiteral.end;
|
||||
node.type = "string";
|
||||
node.value = stringLiteral.value;
|
||||
} else {
|
||||
// Look for an indirect value
|
||||
var indirectValue = $tw.utils.parseTokenRegExp(source,pos,reIndirectValue);
|
||||
if(indirectValue) {
|
||||
pos = indirectValue.end;
|
||||
node.type = "indirect";
|
||||
node.textReference = indirectValue.match[1];
|
||||
} else {
|
||||
// Look for a unquoted value
|
||||
var unquotedValue = $tw.utils.parseTokenRegExp(source,pos,reUnquotedAttribute);
|
||||
if(unquotedValue) {
|
||||
pos = unquotedValue.end;
|
||||
node.type = "string";
|
||||
node.value = unquotedValue.match[1];
|
||||
} else {
|
||||
// Look for a macro invocation value
|
||||
var macroInvocation = $tw.utils.parseMacroInvocation(source,pos);
|
||||
if(macroInvocation) {
|
||||
pos = macroInvocation.end;
|
||||
node.type = "macro";
|
||||
node.value = macroInvocation;
|
||||
} else {
|
||||
node.type = "string";
|
||||
node.value = "true";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
node.type = "string";
|
||||
node.value = "true";
|
||||
}
|
||||
// Update the end position
|
||||
node.end = pos;
|
||||
return node;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -26,7 +26,7 @@ exports.types = {inline: true};
|
||||
exports.init = function(parser) {
|
||||
this.parser = parser;
|
||||
// Regexp to match
|
||||
this.matchRegExp = /~?(?:file|http|https|mailto|ftp|irc|news|data|skype):[^\s'"<>]+(?:\/|\b)/mg;
|
||||
this.matchRegExp = /~?(?:file|http|https|mailto|ftp|irc|news|data|skype):[^\s<>{}\[\]`|'"\\^~]+(?:\/|\b)/mg;
|
||||
};
|
||||
|
||||
exports.parse = function() {
|
||||
|
||||
@@ -36,7 +36,7 @@ exports.parse = function() {
|
||||
// Return the heading
|
||||
return [{
|
||||
type: "element",
|
||||
tag: "h" + this.match[1].length,
|
||||
tag: "h" + headingLevel,
|
||||
attributes: {
|
||||
"class": {type: "string", value: classes.join(" ")}
|
||||
},
|
||||
|
||||
@@ -48,7 +48,7 @@ exports.parse = function() {
|
||||
// Advance the parser position to past the tag
|
||||
this.parser.pos = tag.end;
|
||||
// Check for an immediately following double linebreak
|
||||
var hasLineBreak = !tag.isSelfClosing && !!this.parseTokenRegExp(this.parser.source,this.parser.pos,/(\r?\n(?:\r?\n|$))/g);
|
||||
var hasLineBreak = !tag.isSelfClosing && !!$tw.utils.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n]*\r?\n(?:[^\S\n]*\r?\n|$))/g);
|
||||
// Set whether we're in block mode
|
||||
tag.isBlock = this.is.block || hasLineBreak;
|
||||
// Parse the body if we need to
|
||||
@@ -71,244 +71,7 @@ exports.parse = function() {
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a whitespace token. Returns null if not found, otherwise returns {type: "whitespace", start:, end:,}
|
||||
*/
|
||||
exports.parseWhiteSpace = function(source,pos) {
|
||||
var node = {
|
||||
type: "whitespace",
|
||||
start: pos
|
||||
};
|
||||
var re = /(\s)+/g;
|
||||
re.lastIndex = pos;
|
||||
var match = re.exec(source);
|
||||
if(match && match.index === pos) {
|
||||
node.end = pos + match[0].length;
|
||||
return node;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/*
|
||||
Convenience wrapper for parseWhiteSpace
|
||||
*/
|
||||
exports.skipWhiteSpace = function(source,pos) {
|
||||
var whitespace = this.parseWhiteSpace(source,pos);
|
||||
if(whitespace) {
|
||||
return whitespace.end;
|
||||
}
|
||||
return pos;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a given string token. Returns null if not found, otherwise returns {type: "token", value:, start:, end:,}
|
||||
*/
|
||||
exports.parseTokenString = function(source,pos,token) {
|
||||
var match = source.indexOf(token,pos) === pos;
|
||||
if(match) {
|
||||
return {
|
||||
type: "token",
|
||||
value: token,
|
||||
start: pos,
|
||||
end: pos + token.length
|
||||
};
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a token matching a regex. Returns null if not found, otherwise returns {type: "regexp", match:, start:, end:,}
|
||||
*/
|
||||
exports.parseTokenRegExp = function(source,pos,reToken) {
|
||||
var node = {
|
||||
type: "regexp",
|
||||
start: pos
|
||||
};
|
||||
reToken.lastIndex = pos;
|
||||
node.match = reToken.exec(source);
|
||||
if(node.match && node.match.index === pos) {
|
||||
node.end = pos + node.match[0].length;
|
||||
return node;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a string literal. Returns null if not found, otherwise returns {type: "string", value:, start:, end:,}
|
||||
*/
|
||||
exports.parseStringLiteral = function(source,pos) {
|
||||
var node = {
|
||||
type: "string",
|
||||
start: pos
|
||||
};
|
||||
var reString = /(?:"([^"]*)")|(?:'([^']*)')/g;
|
||||
reString.lastIndex = pos;
|
||||
var match = reString.exec(source);
|
||||
if(match && match.index === pos) {
|
||||
node.value = match[1] === undefined ? match[2] : match[1];
|
||||
node.end = pos + match[0].length;
|
||||
return node;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a macro invocation parameter. Returns null if not found, or {type: "macro-parameter", name:, value:, start:, end:}
|
||||
*/
|
||||
exports.parseMacroParameter = function(source,pos) {
|
||||
var node = {
|
||||
type: "macro-parameter",
|
||||
start: pos
|
||||
};
|
||||
// Define our regexp
|
||||
var reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|([^\s>"'=]+)))/g;
|
||||
// Skip whitespace
|
||||
pos = this.skipWhiteSpace(source,pos);
|
||||
// Look for the parameter
|
||||
var token = this.parseTokenRegExp(source,pos,reMacroParameter);
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Get the parameter details
|
||||
node.value = token.match[2] !== undefined ? token.match[2] : (
|
||||
token.match[3] !== undefined ? token.match[3] : (
|
||||
token.match[4] !== undefined ? token.match[4] : (
|
||||
token.match[5] !== undefined ? token.match[5] : (
|
||||
""
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
if(token.match[1]) {
|
||||
node.name = token.match[1];
|
||||
}
|
||||
// Update the end position
|
||||
node.end = pos;
|
||||
return node;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a macro invocation. Returns null if not found, or {type: "macrocall", name:, parameters:, start:, end:}
|
||||
*/
|
||||
exports.parseMacroInvocation = function(source,pos) {
|
||||
var node = {
|
||||
type: "macrocall",
|
||||
start: pos,
|
||||
params: []
|
||||
};
|
||||
// Define our regexps
|
||||
var reMacroName = /([^\s>"'=]+)/g;
|
||||
// Skip whitespace
|
||||
pos = this.skipWhiteSpace(source,pos);
|
||||
// Look for a double less than sign
|
||||
var token = this.parseTokenString(source,pos,"<<");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Get the macro name
|
||||
var name = this.parseTokenRegExp(source,pos,reMacroName);
|
||||
if(!name) {
|
||||
return null;
|
||||
}
|
||||
node.name = name.match[1];
|
||||
pos = name.end;
|
||||
// Process parameters
|
||||
var parameter = this.parseMacroParameter(source,pos);
|
||||
while(parameter) {
|
||||
node.params.push(parameter);
|
||||
pos = parameter.end;
|
||||
// Get the next parameter
|
||||
parameter = this.parseMacroParameter(source,pos);
|
||||
}
|
||||
// Skip whitespace
|
||||
pos = this.skipWhiteSpace(source,pos);
|
||||
// Look for a double greater than sign
|
||||
token = this.parseTokenString(source,pos,">>");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Update the end position
|
||||
node.end = pos;
|
||||
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:,}
|
||||
*/
|
||||
exports.parseAttribute = function(source,pos) {
|
||||
var node = {
|
||||
start: pos
|
||||
};
|
||||
// Define our regexps
|
||||
var reAttributeName = /([^\/\s>"'=]+)/g,
|
||||
reUnquotedAttribute = /([^\/\s<>"'=]+)/g,
|
||||
reIndirectValue = /\{\{([^\}]+)\}\}/g;
|
||||
// Skip whitespace
|
||||
pos = this.skipWhiteSpace(source,pos);
|
||||
// Get the attribute name
|
||||
var name = this.parseTokenRegExp(source,pos,reAttributeName);
|
||||
if(!name) {
|
||||
return null;
|
||||
}
|
||||
node.name = name.match[1];
|
||||
pos = name.end;
|
||||
// Skip whitespace
|
||||
pos = this.skipWhiteSpace(source,pos);
|
||||
// Look for an equals sign
|
||||
var token = this.parseTokenString(source,pos,"=");
|
||||
if(token) {
|
||||
pos = token.end;
|
||||
// Skip whitespace
|
||||
pos = this.skipWhiteSpace(source,pos);
|
||||
// Look for a string literal
|
||||
var stringLiteral = this.parseStringLiteral(source,pos);
|
||||
if(stringLiteral) {
|
||||
pos = stringLiteral.end;
|
||||
node.type = "string";
|
||||
node.value = stringLiteral.value;
|
||||
} else {
|
||||
// Look for an indirect value
|
||||
var indirectValue = this.parseTokenRegExp(source,pos,reIndirectValue);
|
||||
if(indirectValue) {
|
||||
pos = indirectValue.end;
|
||||
node.type = "indirect";
|
||||
node.textReference = indirectValue.match[1];
|
||||
} else {
|
||||
// Look for a unquoted value
|
||||
var unquotedValue = this.parseTokenRegExp(source,pos,reUnquotedAttribute);
|
||||
if(unquotedValue) {
|
||||
pos = unquotedValue.end;
|
||||
node.type = "string";
|
||||
node.value = unquotedValue.match[1];
|
||||
} else {
|
||||
// Look for a macro invocation value
|
||||
var macroInvocation = this.parseMacroInvocation(source,pos);
|
||||
if(macroInvocation) {
|
||||
pos = macroInvocation.end;
|
||||
node.type = "macro";
|
||||
node.value = macroInvocation;
|
||||
} else {
|
||||
node.type = "string";
|
||||
node.value = "true";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
node.type = "string";
|
||||
node.value = "true";
|
||||
}
|
||||
// Update the end position
|
||||
node.end = pos;
|
||||
return node;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for an HTML tag. Returns null if not found, otherwise returns {type: "tag", name:, attributes: [], isSelfClosing:, start:, end:,}
|
||||
Look for an HTML tag. Returns null if not found, otherwise returns {type: "element", name:, attributes: [], isSelfClosing:, start:, end:,}
|
||||
*/
|
||||
exports.parseTag = function(source,pos,options) {
|
||||
options = options || {};
|
||||
@@ -321,45 +84,45 @@ exports.parseTag = function(source,pos,options) {
|
||||
// Define our regexps
|
||||
var reTagName = /([a-zA-Z0-9\-\$]+)/g;
|
||||
// Skip whitespace
|
||||
pos = this.skipWhiteSpace(source,pos);
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a less than sign
|
||||
token = this.parseTokenString(source,pos,"<");
|
||||
token = $tw.utils.parseTokenString(source,pos,"<");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Get the tag name
|
||||
token = this.parseTokenRegExp(source,pos,reTagName);
|
||||
token = $tw.utils.parseTokenRegExp(source,pos,reTagName);
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
node.tag = token.match[1];
|
||||
pos = token.end;
|
||||
// Process attributes
|
||||
var attribute = this.parseAttribute(source,pos);
|
||||
var attribute = $tw.utils.parseAttribute(source,pos);
|
||||
while(attribute) {
|
||||
node.attributes[attribute.name] = attribute;
|
||||
pos = attribute.end;
|
||||
// Get the next attribute
|
||||
attribute = this.parseAttribute(source,pos);
|
||||
attribute = $tw.utils.parseAttribute(source,pos);
|
||||
}
|
||||
// Skip whitespace
|
||||
pos = this.skipWhiteSpace(source,pos);
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a closing slash
|
||||
token = this.parseTokenString(source,pos,"/");
|
||||
token = $tw.utils.parseTokenString(source,pos,"/");
|
||||
if(token) {
|
||||
pos = token.end;
|
||||
node.isSelfClosing = true;
|
||||
}
|
||||
// Look for a greater than sign
|
||||
token = this.parseTokenString(source,pos,">");
|
||||
token = $tw.utils.parseTokenString(source,pos,">");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Check for a required line break
|
||||
if(options.requireLineBreak) {
|
||||
token = this.parseTokenRegExp(source,pos,/(\r?\n(?:\r?\n|$))/g);
|
||||
token = $tw.utils.parseTokenRegExp(source,pos,/([^\S\n]*\r?\n(?:[^\S\n]*\r?\n|$))/g);
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
137
core/modules/parsers/wikiparser/rules/image.js
Normal file
137
core/modules/parsers/wikiparser/rules/image.js
Normal file
@@ -0,0 +1,137 @@
|
||||
/*\
|
||||
title: $:/core/modules/parsers/wikiparser/rules/image.js
|
||||
type: application/javascript
|
||||
module-type: wikirule
|
||||
|
||||
Wiki text inline rule for embedding images. For example:
|
||||
|
||||
```
|
||||
[img[http://tiddlywiki.com/fractalveg.jpg]]
|
||||
[img width=23 height=24 [http://tiddlywiki.com/fractalveg.jpg]]
|
||||
[img 23x24 [http://tiddlywiki.com/fractalveg.jpg]]
|
||||
[img width={{!!width}} height={{!!height}} [http://tiddlywiki.com/fractalveg.jpg]]
|
||||
[img {{!!width}}x{{!!height}} [http://tiddlywiki.com/fractalveg.jpg]]
|
||||
[img[Description of image|http://tiddlywiki.com/fractalveg.jpg]]
|
||||
[img[TiddlerTitle]]
|
||||
[img[Description of image|TiddlerTitle]]
|
||||
```
|
||||
|
||||
Generates the `<$image>` widget.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.name = "image";
|
||||
exports.types = {inline: true};
|
||||
|
||||
exports.init = function(parser) {
|
||||
this.parser = parser;
|
||||
};
|
||||
|
||||
exports.findNextMatch = function(startPos) {
|
||||
// Find the next tag
|
||||
this.nextImage = this.findNextImage(this.parser.source,startPos);
|
||||
return this.nextImage ? this.nextImage.start : undefined;
|
||||
};
|
||||
|
||||
exports.parse = function() {
|
||||
// Move past the match
|
||||
this.parser.pos = this.nextImage.end;
|
||||
var node = {
|
||||
type: "element",
|
||||
tag: "$image",
|
||||
attributes: this.nextImage.attributes
|
||||
};
|
||||
return [node];
|
||||
};
|
||||
|
||||
/*
|
||||
Find the next image from the current position
|
||||
*/
|
||||
exports.findNextImage = function(source,pos) {
|
||||
// A regexp for finding candidate HTML tags
|
||||
var reLookahead = /(\[img)/g;
|
||||
// Find the next candidate
|
||||
reLookahead.lastIndex = pos;
|
||||
var match = reLookahead.exec(source);
|
||||
while(match) {
|
||||
// Try to parse the candidate as a tag
|
||||
var tag = this.parseImage(source,match.index);
|
||||
// Return success
|
||||
if(tag) {
|
||||
return tag;
|
||||
}
|
||||
// Look for the next match
|
||||
reLookahead.lastIndex = match.index + 1;
|
||||
match = reLookahead.exec(source);
|
||||
}
|
||||
// Failed
|
||||
return null;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for an image at the specified position. Returns null if not found, otherwise returns {type: "element", name: "$image", attributes: [], isSelfClosing:, start:, end:,}
|
||||
*/
|
||||
exports.parseImage = function(source,pos) {
|
||||
var token,
|
||||
node = {
|
||||
type: "element",
|
||||
name: "$image",
|
||||
start: pos,
|
||||
attributes: {}
|
||||
};
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for the `[img`
|
||||
token = $tw.utils.parseTokenString(source,pos,"[img");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Process attributes
|
||||
if(source.charAt(pos) !== "[") {
|
||||
var attribute = $tw.utils.parseAttribute(source,pos);
|
||||
while(attribute) {
|
||||
node.attributes[attribute.name] = attribute;
|
||||
pos = attribute.end;
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
if(source.charAt(pos) !== "[") {
|
||||
// Get the next attribute
|
||||
attribute = $tw.utils.parseAttribute(source,pos);
|
||||
} else {
|
||||
attribute = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for the `[` after the attributes
|
||||
token = $tw.utils.parseTokenString(source,pos,"[");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Get the source up to the terminating `]]`
|
||||
token = $tw.utils.parseTokenRegExp(source,pos,/(?:([^|\]]*?)\|)?([^\]]+?)\]\]/g);
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
if(token.match[1]) {
|
||||
node.attributes.tooltip = {type: "string", value: token.match[1].trim()};
|
||||
}
|
||||
node.attributes.source = {type: "string", value: (token.match[2] || "").trim()};
|
||||
// Update the end position
|
||||
node.end = pos;
|
||||
return node;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -28,7 +28,7 @@ exports.init = function(parser) {
|
||||
};
|
||||
|
||||
var isLinkExternal = function(to) {
|
||||
var externalRegExp = /(?:file|http|https|mailto|ftp|irc|news|data|skype):[^\s'"]+(?:\/|\b)/i;
|
||||
var externalRegExp = /(?:file|http|https|mailto|ftp|irc|news|data|skype):[^\s<>{}\[\]`|'"\\^~]+(?:\/|\b)/i;
|
||||
return externalRegExp.test(to);
|
||||
};
|
||||
|
||||
|
||||
@@ -23,19 +23,17 @@ exports.types = {block: true};
|
||||
exports.init = function(parser) {
|
||||
this.parser = parser;
|
||||
// Regexp to match
|
||||
this.matchRegExp = /\{\{([^\{\}\|]+)(?:\|\|([^\|\{\}]+))?\}\}(?:\r?\n|$)/mg;
|
||||
this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?\}\}(?:\r?\n|$)/mg;
|
||||
};
|
||||
|
||||
exports.parse = function() {
|
||||
// Move past the match
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
// Move past the match
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
// Get the match details
|
||||
var textRef = $tw.utils.trim(this.match[1]),
|
||||
tr = $tw.utils.parseTextReference(textRef),
|
||||
targetTitle = tr.title,
|
||||
targetField = tr.field,
|
||||
targetIndex = tr.index,
|
||||
template = $tw.utils.trim(this.match[2]);
|
||||
var template = $tw.utils.trim(this.match[2]),
|
||||
textRef = $tw.utils.trim(this.match[1]);
|
||||
// Prepare the transclude widget
|
||||
var transcludeNode = {
|
||||
type: "element",
|
||||
@@ -43,27 +41,43 @@ exports.parse = function() {
|
||||
attributes: {},
|
||||
isBlock: true
|
||||
};
|
||||
var tiddlerNode = {
|
||||
type: "element",
|
||||
tag: "$tiddler",
|
||||
attributes: {
|
||||
tiddler: {type: "string", value: targetTitle}
|
||||
},
|
||||
isBlock: true,
|
||||
children: [transcludeNode]
|
||||
};
|
||||
// Prepare the tiddler widget
|
||||
if(textRef) {
|
||||
var tr = $tw.utils.parseTextReference(textRef),
|
||||
targetTitle = tr.title,
|
||||
targetField = tr.field,
|
||||
targetIndex = tr.index,
|
||||
tiddlerNode = {
|
||||
type: "element",
|
||||
tag: "$tiddler",
|
||||
attributes: {
|
||||
tiddler: {type: "string", value: targetTitle}
|
||||
},
|
||||
isBlock: true,
|
||||
children: [transcludeNode]
|
||||
};
|
||||
}
|
||||
if(template) {
|
||||
transcludeNode.attributes.tiddler = {type: "string", value: template};
|
||||
} else {
|
||||
transcludeNode.attributes.tiddler = {type: "string", value: targetTitle};
|
||||
if(targetField) {
|
||||
transcludeNode.attributes.field = {type: "string", value: targetField};
|
||||
if(textRef) {
|
||||
return [tiddlerNode];
|
||||
} else {
|
||||
return [transcludeNode];
|
||||
}
|
||||
if(targetIndex) {
|
||||
transcludeNode.attributes.index = {type: "string", value: targetIndex};
|
||||
} else {
|
||||
if(textRef) {
|
||||
transcludeNode.attributes.tiddler = {type: "string", value: targetTitle};
|
||||
if(targetField) {
|
||||
transcludeNode.attributes.field = {type: "string", value: targetField};
|
||||
}
|
||||
if(targetIndex) {
|
||||
transcludeNode.attributes.index = {type: "string", value: targetIndex};
|
||||
}
|
||||
return [tiddlerNode];
|
||||
} else {
|
||||
return [transcludeNode];
|
||||
}
|
||||
}
|
||||
return [tiddlerNode];
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -23,45 +23,57 @@ exports.types = {inline: true};
|
||||
exports.init = function(parser) {
|
||||
this.parser = parser;
|
||||
// Regexp to match
|
||||
this.matchRegExp = /\{\{([^\{\}\|]+)(?:\|\|([^\|\{\}]+))?\}\}/mg;
|
||||
this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?\}\}/mg;
|
||||
};
|
||||
|
||||
exports.parse = function() {
|
||||
// Move past the match
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
// Get the match details
|
||||
var textRef = $tw.utils.trim(this.match[1]),
|
||||
tr = $tw.utils.parseTextReference(textRef),
|
||||
targetTitle = tr.title,
|
||||
targetField = tr.field,
|
||||
targetIndex = tr.index,
|
||||
template = $tw.utils.trim(this.match[2]);
|
||||
var template = $tw.utils.trim(this.match[2]),
|
||||
textRef = $tw.utils.trim(this.match[1]);
|
||||
// Prepare the transclude widget
|
||||
var transcludeNode = {
|
||||
type: "element",
|
||||
tag: "$transclude",
|
||||
attributes: {}
|
||||
};
|
||||
var tiddlerNode = {
|
||||
type: "element",
|
||||
tag: "$tiddler",
|
||||
attributes: {
|
||||
tiddler: {type: "string", value: targetTitle}
|
||||
},
|
||||
children: [transcludeNode]
|
||||
};
|
||||
// Prepare the tiddler widget
|
||||
if(textRef) {
|
||||
var tr = $tw.utils.parseTextReference(textRef),
|
||||
targetTitle = tr.title,
|
||||
targetField = tr.field,
|
||||
targetIndex = tr.index,
|
||||
tiddlerNode = {
|
||||
type: "element",
|
||||
tag: "$tiddler",
|
||||
attributes: {
|
||||
tiddler: {type: "string", value: targetTitle}
|
||||
},
|
||||
children: [transcludeNode]
|
||||
};
|
||||
}
|
||||
if(template) {
|
||||
transcludeNode.attributes.tiddler = {type: "string", value: template};
|
||||
} else {
|
||||
transcludeNode.attributes.tiddler = {type: "string", value: targetTitle};
|
||||
if(targetField) {
|
||||
transcludeNode.attributes.field = {type: "string", value: targetField};
|
||||
if(textRef) {
|
||||
return [tiddlerNode];
|
||||
} else {
|
||||
return [transcludeNode];
|
||||
}
|
||||
if(targetIndex) {
|
||||
transcludeNode.attributes.index = {type: "string", value: targetIndex};
|
||||
} else {
|
||||
if(textRef) {
|
||||
transcludeNode.attributes.tiddler = {type: "string", value: targetTitle};
|
||||
if(targetField) {
|
||||
transcludeNode.attributes.field = {type: "string", value: targetField};
|
||||
}
|
||||
if(targetIndex) {
|
||||
transcludeNode.attributes.index = {type: "string", value: targetIndex};
|
||||
}
|
||||
return [tiddlerNode];
|
||||
} else {
|
||||
return [transcludeNode];
|
||||
}
|
||||
}
|
||||
return [tiddlerNode];
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -62,8 +62,9 @@ PluginSwitcher.prototype.switchPlugins = function() {
|
||||
var unregisteredTiddlers = $tw.wiki.unregisterPluginTiddlers(this.pluginType);
|
||||
// Accumulate the titles of shadow tiddlers that have changed as a result of this switch
|
||||
var changedTiddlers = {};
|
||||
$tw.utils.each(this.wiki.shadowTiddlers,function(shadowInfo,title) {
|
||||
if(unregisteredTiddlers.indexOf(shadowInfo.source) !== -1) {
|
||||
this.wiki.eachShadow(function(tiddler,title) {
|
||||
var source = self.wiki.getShadowSource(title);
|
||||
if(unregisteredTiddlers.indexOf(source) !== -1) {
|
||||
changedTiddlers[title] = true; // isDeleted?
|
||||
}
|
||||
});
|
||||
@@ -72,8 +73,9 @@ PluginSwitcher.prototype.switchPlugins = function() {
|
||||
// Unpack the current theme tiddlers
|
||||
$tw.wiki.unpackPluginTiddlers();
|
||||
// Accumulate the affected shadow tiddlers
|
||||
$tw.utils.each(this.wiki.shadowTiddlers,function(shadowInfo,title) {
|
||||
if(registeredTiddlers.indexOf(shadowInfo.source) !== -1) {
|
||||
this.wiki.eachShadow(function(tiddler,title) {
|
||||
var source = self.wiki.getShadowSource(title);
|
||||
if(registeredTiddlers.indexOf(source) !== -1) {
|
||||
changedTiddlers[title] = false; // isDeleted?
|
||||
}
|
||||
});
|
||||
|
||||
@@ -19,13 +19,27 @@ TiddlyFoxSaver.prototype.save = function(text,method,callback) {
|
||||
var messageBox = document.getElementById("tiddlyfox-message-box");
|
||||
if(messageBox) {
|
||||
// Get the pathname of this document
|
||||
var pathname = document.location.pathname;
|
||||
// Test for a Windows path of the form /x:/blah/blah
|
||||
if(/^\/[A-Z]\:\//i.test(pathname)) {
|
||||
// Remove the leading slash
|
||||
pathname = pathname.substr(1);
|
||||
// Convert slashes to backslashes
|
||||
pathname = pathname.replace(/\//g,"\\");
|
||||
var pathname = document.location.toString();
|
||||
// Replace file://localhost/ with file:///
|
||||
if(pathname.indexOf("file://localhost/") == 0) {
|
||||
pathname = "file://" + pathname.substr(16);
|
||||
}
|
||||
// Windows path file:///x:/blah/blah --> x:\blah\blah
|
||||
if(/^file\:\/\/\/[A-Z]\:\//i.test(pathname)) {
|
||||
// Remove the leading slash and convert slashes to backslashes
|
||||
pathname = pathname.substr(8).replace(/\//g,"\\");
|
||||
// Firefox Windows network path file://///server/share/blah/blah --> //server/share/blah/blah
|
||||
} else if(pathname.indexOf("file://///") === 0) {
|
||||
pathname = "\\\\" + unescape(pathname.substr(10)).replace(/\//g,"\\");
|
||||
// Mac/Unix local path file:///path/path --> /path/path
|
||||
} else if(pathname.indexOf("file:///") == 0) {
|
||||
pathname = unescape(pathname.substr(7));
|
||||
// Mac/Unix local path file:/path/path --> /path/path
|
||||
} else if(pathname.indexOf("file:/") == 0) {
|
||||
pathname = unescape(pathname.substr(5));
|
||||
// Otherwise Windows networth path file://server/share/path/path --> \\server\share\path\path
|
||||
} else {
|
||||
pathname = "\\\\" + unescape(pathname.substr(7)).replace(new RegExp("/","g"),"\\");
|
||||
}
|
||||
// Create the message element and put it in the message box
|
||||
var message = document.createElement("div");
|
||||
|
||||
@@ -12,6 +12,12 @@ This is the main application logic for both the client and server
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
// Set to `true` to enable performance instrumentation
|
||||
var PERFORMANCE_INSTRUMENTATION = false;
|
||||
|
||||
// Time (in ms) that we defer refreshing changes to draft tiddlers
|
||||
var DRAFT_TIDDLER_TIMEOUT = 400;
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
|
||||
exports.startup = function() {
|
||||
@@ -32,14 +38,15 @@ exports.startup = function() {
|
||||
$tw.modules.applyMethods("wikimethod",$tw.Wiki.prototype);
|
||||
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
|
||||
$tw.macros = $tw.modules.getModulesByTypeAsHashmap("macro");
|
||||
// Set up the performance framework
|
||||
$tw.perf = new $tw.Performance(PERFORMANCE_INSTRUMENTATION);
|
||||
// Set up the parsers
|
||||
$tw.wiki.initParsers();
|
||||
// Set up the syncer object
|
||||
$tw.syncer = new $tw.Syncer({wiki: $tw.wiki});
|
||||
// Set up the command modules
|
||||
$tw.Commander.initCommands();
|
||||
// Kick off the language manager
|
||||
$tw.languageManager = new $tw.PluginSwitcher({
|
||||
// Kick off the language manager and switcher
|
||||
$tw.language = new $tw.Language();
|
||||
$tw.languageSwitcher = new $tw.PluginSwitcher({
|
||||
wiki: $tw.wiki,
|
||||
pluginType: "language",
|
||||
controllerTitle: "$:/language",
|
||||
@@ -57,25 +64,31 @@ exports.startup = function() {
|
||||
"$:/themes/tiddlywiki/vanilla"
|
||||
]
|
||||
});
|
||||
// Get the default tiddlers
|
||||
var defaultTiddlersTitle = "$:/DefaultTiddlers",
|
||||
defaultTiddlersTiddler = $tw.wiki.getTiddler(defaultTiddlersTitle),
|
||||
defaultTiddlers = [];
|
||||
if(defaultTiddlersTiddler) {
|
||||
defaultTiddlers = $tw.wiki.filterTiddlers(defaultTiddlersTiddler.fields.text);
|
||||
}
|
||||
// Initialise the story and history
|
||||
var storyTitle = "$:/StoryList",
|
||||
story = [];
|
||||
for(var t=0; t<defaultTiddlers.length; t++) {
|
||||
story[t] = defaultTiddlers[t];
|
||||
}
|
||||
$tw.wiki.addTiddler({title: storyTitle, text: "", list: story},$tw.wiki.getModificationFields());
|
||||
// Display the default tiddlers
|
||||
var displayDefaultTiddlers = function() {
|
||||
// Get the default tiddlers
|
||||
var defaultTiddlersTitle = "$:/DefaultTiddlers",
|
||||
defaultTiddlersTiddler = $tw.wiki.getTiddler(defaultTiddlersTitle),
|
||||
defaultTiddlers = [];
|
||||
if(defaultTiddlersTiddler) {
|
||||
defaultTiddlers = $tw.wiki.filterTiddlers(defaultTiddlersTiddler.fields.text);
|
||||
}
|
||||
// Initialise the story
|
||||
var storyTitle = "$:/StoryList",
|
||||
story = [];
|
||||
for(var t=0; t<defaultTiddlers.length; t++) {
|
||||
story[t] = defaultTiddlers[t];
|
||||
}
|
||||
$tw.wiki.addTiddler({title: storyTitle, text: "", list: story},$tw.wiki.getModificationFields());
|
||||
};
|
||||
displayDefaultTiddlers();
|
||||
// Set up the syncer object
|
||||
$tw.syncer = new $tw.Syncer({wiki: $tw.wiki});
|
||||
// Host-specific startup
|
||||
if($tw.browser) {
|
||||
// Set up our beforeunload handler
|
||||
window.addEventListener("beforeunload",function(event) {
|
||||
var confirmationMessage = null;
|
||||
var confirmationMessage = undefined;
|
||||
if($tw.syncer.isDirty()) {
|
||||
confirmationMessage = "You have unsaved changes in TiddlyWiki";
|
||||
event.returnValue = confirmationMessage; // Gecko
|
||||
@@ -111,6 +124,10 @@ exports.startup = function() {
|
||||
$tw.rootWidget.addEventListener("tw-scroll",function(event) {
|
||||
$tw.pageScroller.handleEvent(event);
|
||||
});
|
||||
// Listen for the tw-home message
|
||||
$tw.rootWidget.addEventListener("tw-home",function(event) {
|
||||
displayDefaultTiddlers();
|
||||
});
|
||||
// Install the save action handlers
|
||||
$tw.rootWidget.addEventListener("tw-save-wiki",function(event) {
|
||||
$tw.syncer.saveWiki({
|
||||
@@ -190,22 +207,13 @@ exports.startup = function() {
|
||||
$tw.styleElement = document.createElement("style");
|
||||
$tw.styleElement.innerHTML = $tw.styleContainer.textContent;
|
||||
document.head.insertBefore($tw.styleElement,document.head.firstChild);
|
||||
$tw.wiki.addEventListener("change",function(changes) {
|
||||
$tw.wiki.addEventListener("change",$tw.perf.report("styleRefresh",function(changes) {
|
||||
if($tw.styleWidgetNode.refresh(changes,$tw.styleContainer,null)) {
|
||||
$tw.styleElement.innerHTML = $tw.styleContainer.textContent;
|
||||
}
|
||||
});
|
||||
// Display the PageMacros, which includes the PageTemplate
|
||||
var templateTitle = "$:/core/ui/PageMacros",
|
||||
parser = $tw.wiki.parseTiddler(templateTitle);
|
||||
$tw.pageWidgetNode = $tw.wiki.makeWidget(parser,{document: document, parentWidget: $tw.rootWidget});
|
||||
$tw.pageContainer = document.createElement("div");
|
||||
$tw.utils.addClass($tw.pageContainer,"tw-page-container");
|
||||
document.body.insertBefore($tw.pageContainer,document.body.firstChild);
|
||||
$tw.pageWidgetNode.render($tw.pageContainer,null);
|
||||
$tw.wiki.addEventListener("change",function(changes) {
|
||||
$tw.pageWidgetNode.refresh(changes,$tw.pageContainer,null);
|
||||
});
|
||||
}));
|
||||
// Display the $:/PageMacros tiddler to kick off the display
|
||||
renderPage();
|
||||
// Fix up the link between the root widget and the page container
|
||||
$tw.rootWidget.domNodes = [$tw.pageContainer];
|
||||
$tw.rootWidget.children = [$tw.pageWidgetNode];
|
||||
@@ -235,7 +243,54 @@ exports.startup = function() {
|
||||
);
|
||||
commander.execute();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Main render function for PageMacros, which includes the PageTemplate
|
||||
*/
|
||||
function renderPage() {
|
||||
// Parse and render the template
|
||||
var templateTitle = "$:/core/ui/PageMacros",
|
||||
parser = $tw.wiki.parseTiddler(templateTitle);
|
||||
$tw.perf.report("mainRender",function() {
|
||||
$tw.pageWidgetNode = $tw.wiki.makeWidget(parser,{document: document, parentWidget: $tw.rootWidget});
|
||||
$tw.pageContainer = document.createElement("div");
|
||||
$tw.utils.addClass($tw.pageContainer,"tw-page-container-wrapper");
|
||||
document.body.insertBefore($tw.pageContainer,document.body.firstChild);
|
||||
$tw.pageWidgetNode.render($tw.pageContainer,null);
|
||||
})();
|
||||
// Prepare refresh mechanism
|
||||
var deferredChanges = Object.create(null),
|
||||
timerId;
|
||||
function refresh() {
|
||||
// Process the refresh
|
||||
$tw.pageWidgetNode.refresh(deferredChanges,$tw.pageContainer,null);
|
||||
deferredChanges = Object.create(null);
|
||||
}
|
||||
// Add the change event handler
|
||||
$tw.wiki.addEventListener("change",$tw.perf.report("mainRefresh",function(changes) {
|
||||
// Check if only drafts have changed
|
||||
var onlyDraftsHaveChanged = true;
|
||||
for(var title in changes) {
|
||||
var tiddler = $tw.wiki.getTiddler(title);
|
||||
if(!tiddler || !tiddler.hasField("draft.of")) {
|
||||
onlyDraftsHaveChanged = false;
|
||||
}
|
||||
}
|
||||
// Defer the change if only drafts have changed
|
||||
if(timerId) {
|
||||
clearTimeout(timerId);
|
||||
}
|
||||
timerId = null;
|
||||
if(onlyDraftsHaveChanged) {
|
||||
timerId = setTimeout(refresh,DRAFT_TIDDLER_TIMEOUT);
|
||||
$tw.utils.extend(deferredChanges,changes);
|
||||
} else {
|
||||
$tw.utils.extend(deferredChanges,changes);
|
||||
refresh();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
@@ -25,7 +25,7 @@ var ZoominListView = function(listWidget) {
|
||||
}
|
||||
domNode.style.position = "absolute";
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
ZoominListView.prototype.navigateTo = function(historyInfo) {
|
||||
var duration = $tw.utils.getAnimationDuration(),
|
||||
|
||||
@@ -267,8 +267,13 @@ Synchronise a set of changes to the server
|
||||
*/
|
||||
Syncer.prototype.syncToServer = function(changes) {
|
||||
var self = this,
|
||||
now = new Date(),
|
||||
filteredChanges = this.filterFn.call(this.wiki,changes);
|
||||
now = Date.now(),
|
||||
filteredChanges = this.filterFn.call(this.wiki,function(callback) {
|
||||
$tw.utils.each(changes,function(change,title) {
|
||||
var tiddler = self.wiki.getTiddler(title);
|
||||
callback(tiddler,title);
|
||||
});
|
||||
});
|
||||
$tw.utils.each(changes,function(change,title,object) {
|
||||
// Process the change if it is a deletion of a tiddler we're already syncing, or is on the filtered change list
|
||||
if((change.deleted && $tw.utils.hop(self.tiddlerInfo,title)) || filteredChanges.indexOf(title) !== -1) {
|
||||
@@ -366,7 +371,7 @@ Queue up a sync task. If there is already a pending task for the tiddler, just u
|
||||
*/
|
||||
Syncer.prototype.enqueueSyncTask = function(task) {
|
||||
var self = this,
|
||||
now = new Date();
|
||||
now = Date.now();
|
||||
// Set the timestamps on this task
|
||||
task.queueTime = now;
|
||||
task.lastModificationTime = now;
|
||||
@@ -469,7 +474,7 @@ Choose the next applicable task
|
||||
Syncer.prototype.chooseNextTask = function() {
|
||||
var self = this,
|
||||
candidateTask = null,
|
||||
now = new Date();
|
||||
now = Date.now();
|
||||
// Select the best candidate task
|
||||
$tw.utils.each(this.taskQueue,function(task,title) {
|
||||
// Exclude the task if there's one of the same name in progress
|
||||
@@ -514,6 +519,9 @@ Syncer.prototype.dispatchTask = function(task,callback) {
|
||||
// Invoke the callback
|
||||
callback(null);
|
||||
});
|
||||
} else {
|
||||
this.logger.log(" Not Dispatching 'save' task:",task.title,"tiddler does not exist");
|
||||
return callback(null);
|
||||
}
|
||||
} else if(task.type === "load") {
|
||||
// Load the tiddler
|
||||
|
||||
@@ -55,25 +55,20 @@ Handle a scroll event hitting the page document
|
||||
*/
|
||||
PageScroller.prototype.scrollIntoView = function(element) {
|
||||
var duration = $tw.utils.getAnimationDuration();
|
||||
// Get the offset bounds of the element
|
||||
var bounds = {
|
||||
left: element.offsetLeft,
|
||||
top: element.offsetTop,
|
||||
width: element.offsetWidth,
|
||||
height: element.offsetHeight
|
||||
};
|
||||
// Walk up the tree adjusting the offset bounds by each offsetParent
|
||||
while(element.offsetParent) {
|
||||
element = element.offsetParent;
|
||||
bounds.left += element.offsetLeft;
|
||||
bounds.top += element.offsetTop;
|
||||
}
|
||||
// Now get ready to scroll the body
|
||||
this.cancelScroll();
|
||||
this.startTime = new Date();
|
||||
var scrollPosition = $tw.utils.getScrollPosition(),
|
||||
// We'll consider the horizontal and vertical scroll directions separately via this function
|
||||
getEndPos = function(targetPos,targetSize,currentPos,currentSize) {
|
||||
this.startTime = Date.now();
|
||||
var scrollPosition = $tw.utils.getScrollPosition();
|
||||
// Get the client bounds of the element and adjust by the scroll position
|
||||
var clientBounds = element.getBoundingClientRect(),
|
||||
bounds = {
|
||||
left: clientBounds.left + scrollPosition.x,
|
||||
top: clientBounds.top + scrollPosition.y,
|
||||
width: clientBounds.width,
|
||||
height: clientBounds.height
|
||||
};
|
||||
// We'll consider the horizontal and vertical scroll directions separately via this function
|
||||
var getEndPos = function(targetPos,targetSize,currentPos,currentSize) {
|
||||
// If the target is above/left of the current view, then scroll to it's top/left
|
||||
if(targetPos <= currentPos) {
|
||||
return targetPos;
|
||||
@@ -99,7 +94,7 @@ PageScroller.prototype.scrollIntoView = function(element) {
|
||||
if(duration <= 0) {
|
||||
t = 1;
|
||||
} else {
|
||||
t = ((new Date()) - self.startTime) / duration;
|
||||
t = ((Date.now()) - self.startTime) / duration;
|
||||
}
|
||||
if(t >= 1) {
|
||||
self.cancelScroll();
|
||||
|
||||
@@ -219,6 +219,7 @@ var document = {
|
||||
createTextNode: function(text) {
|
||||
return new TW_TextNode(text);
|
||||
},
|
||||
isTiddlyWikiFakeDom: true
|
||||
};
|
||||
|
||||
exports.fakeDocument = document;
|
||||
|
||||
62
core/modules/utils/performance.js
Normal file
62
core/modules/utils/performance.js
Normal file
@@ -0,0 +1,62 @@
|
||||
/*\
|
||||
title: $:/core/modules/utils/performance.js
|
||||
type: application/javascript
|
||||
module-type: global
|
||||
|
||||
Performance measurement.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
function Performance(enabled) {
|
||||
this.enabled = !!enabled;
|
||||
this.measures = {}; // Hashmap of current values of measurements
|
||||
this.logger = new $tw.utils.Logger("performance");
|
||||
}
|
||||
|
||||
/*
|
||||
Wrap performance reporting around a top level function
|
||||
*/
|
||||
Performance.prototype.report = function(name,fn) {
|
||||
var self = this;
|
||||
if(this.enabled) {
|
||||
return function() {
|
||||
self.measures = {};
|
||||
var startTime = $tw.utils.timer(),
|
||||
result = fn.apply(this,arguments);
|
||||
self.logger.log(name + ": " + $tw.utils.timer(startTime) + "ms");
|
||||
for(var m in self.measures) {
|
||||
self.logger.log("+" + m + ": " + self.measures[m] + "ms");
|
||||
}
|
||||
return result;
|
||||
};
|
||||
} else {
|
||||
return fn;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Wrap performance measurements around a subfunction
|
||||
*/
|
||||
Performance.prototype.measure = function(name,fn) {
|
||||
var self = this;
|
||||
if(this.enabled) {
|
||||
return function() {
|
||||
var startTime = $tw.utils.timer(),
|
||||
result = fn.apply(this,arguments),
|
||||
value = self.measures[name] || 0;
|
||||
self.measures[name] = value + $tw.utils.timer(startTime);
|
||||
return result;
|
||||
};
|
||||
} else {
|
||||
return fn;
|
||||
}
|
||||
};
|
||||
|
||||
exports.Performance = Performance;
|
||||
|
||||
})();
|
||||
@@ -35,21 +35,34 @@ exports.count = function(object) {
|
||||
|
||||
/*
|
||||
Push entries onto an array, removing them first if they already exist in the array
|
||||
array: array to modify
|
||||
array: array to modify (assumed to be free of duplicates)
|
||||
value: a single value to push or an array of values to push
|
||||
*/
|
||||
exports.pushTop = function(array,value) {
|
||||
var t,p;
|
||||
if($tw.utils.isArray(value)) {
|
||||
// Remove any array entries that are duplicated in the new values
|
||||
for(t=0; t<value.length; t++) {
|
||||
p = array.indexOf(value[t]);
|
||||
if(p !== -1) {
|
||||
array.splice(p,1);
|
||||
if(value.length !== 0) {
|
||||
if(array.length !== 0) {
|
||||
if(value.length < array.length) {
|
||||
for(t=0; t<value.length; t++) {
|
||||
p = array.indexOf(value[t]);
|
||||
if(p !== -1) {
|
||||
array.splice(p,1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(t=array.length-1; t>=0; t--) {
|
||||
p = value.indexOf(array[t]);
|
||||
if(p !== -1) {
|
||||
array.splice(t,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Push the values on top of the main array
|
||||
array.push.apply(array,value);
|
||||
}
|
||||
// Push the values on top of the main array
|
||||
array.push.apply(array,value);
|
||||
} else {
|
||||
p = array.indexOf(value);
|
||||
if(p !== -1) {
|
||||
@@ -214,32 +227,36 @@ exports.getRelativeDate = function(delta) {
|
||||
futurep = true;
|
||||
}
|
||||
var units = [
|
||||
{name: "years", duration: 365 * 24 * 60 * 60 * 1000},
|
||||
{name: "months", duration: (365/12) * 24 * 60 * 60 * 1000},
|
||||
{name: "days", duration: 24 * 60 * 60 * 1000},
|
||||
{name: "hours", duration: 60 * 60 * 1000},
|
||||
{name: "minutes", duration: 60 * 1000},
|
||||
{name: "seconds", duration: 1000}
|
||||
{name: "Years", duration: 365 * 24 * 60 * 60 * 1000},
|
||||
{name: "Months", duration: (365/12) * 24 * 60 * 60 * 1000},
|
||||
{name: "Days", duration: 24 * 60 * 60 * 1000},
|
||||
{name: "Hours", duration: 60 * 60 * 1000},
|
||||
{name: "Minutes", duration: 60 * 1000},
|
||||
{name: "Seconds", duration: 1000}
|
||||
];
|
||||
for(var t=0; t<units.length; t++) {
|
||||
var result = Math.floor(delta / units[t].duration);
|
||||
if(result >= 2) {
|
||||
var desc = result + " " + units[t].name;
|
||||
if(futurep) {
|
||||
desc = desc + " from now";
|
||||
} else {
|
||||
desc = desc + " ago";
|
||||
}
|
||||
return {
|
||||
delta: delta,
|
||||
description: desc,
|
||||
description: $tw.language.getString(
|
||||
"RelativeDate/" + (futurep ? "Future" : "Past") + "/" + units[t].name,
|
||||
{variables:
|
||||
{period: result.toString()}
|
||||
}
|
||||
),
|
||||
updatePeriod: units[t].duration
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
delta: delta,
|
||||
description: "1 second ago",
|
||||
description: $tw.language.getString(
|
||||
"RelativeDate/" + (futurep ? "Future" : "Past") + "/Second",
|
||||
{variables:
|
||||
{period: "1"}
|
||||
}
|
||||
),
|
||||
updatePeriod: 1000
|
||||
};
|
||||
};
|
||||
@@ -362,7 +379,7 @@ Returns an object with the following fields, all optional:
|
||||
*/
|
||||
exports.parseTextReference = function(textRef) {
|
||||
// Separate out the title, field name and/or JSON indices
|
||||
var reTextRef = /^\s*([^!#]+)?(?:(?:!!([^\s]+))|(?:##([^\s]+)))?\s*/mg,
|
||||
var reTextRef = /^\s*([^!#]+)?(?:(?:!!([^\s]+))|(?:##(.+)))?\s*/mg,
|
||||
match = reTextRef.exec(textRef);
|
||||
if(match && reTextRef.lastIndex === textRef.length) {
|
||||
// Return the parts
|
||||
@@ -447,4 +464,23 @@ exports.makeTiddlerDictionary = function(data) {
|
||||
return output.join("\n");
|
||||
};
|
||||
|
||||
/*
|
||||
High resolution microsecond timer for profiling
|
||||
*/
|
||||
exports.timer = function(base) {
|
||||
var m;
|
||||
if($tw.node) {
|
||||
var r = process.hrtime();
|
||||
m = r[0] * 1e3 + (r[1] / 1e6);
|
||||
} else if(window.performance) {
|
||||
m = performance.now();
|
||||
} else {
|
||||
m = Date.now();
|
||||
}
|
||||
if(typeof base !== "undefined") {
|
||||
m = m - base;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
@@ -54,7 +54,7 @@ ButtonWidget.prototype.render = function(parent,nextSibling) {
|
||||
domNode.addEventListener("click",function (event) {
|
||||
var handled = false;
|
||||
if(self.to) {
|
||||
self.dispatchEvent({type: "tw-navigate", navigateTo: self.to, tiddlerTitle: self.getVariable("currentTiddler")});
|
||||
self.navigateTo(event);
|
||||
handled = true;
|
||||
}
|
||||
if(self.message) {
|
||||
@@ -92,6 +92,19 @@ ButtonWidget.prototype.isPoppedUp = function() {
|
||||
return result;
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.navigateTo = function(event) {
|
||||
var bounds = this.domNodes[0].getBoundingClientRect();
|
||||
this.dispatchEvent({
|
||||
type: "tw-navigate",
|
||||
navigateTo: this.to,
|
||||
navigateFromTitle: this.getVariable("storyTiddler"),
|
||||
navigateFromNode: this,
|
||||
navigateFromClientRect: { top: bounds.top, left: bounds.left, width: bounds.width, right: bounds.right, bottom: bounds.bottom, height: bounds.height
|
||||
},
|
||||
navigateSuppressNavigation: event.metaKey || event.ctrlKey || (event.button === 1)
|
||||
});
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.dispatchMessage = function(event) {
|
||||
this.dispatchEvent({type: this.message, param: this.param, tiddlerTitle: this.getVariable("currentTiddler")});
|
||||
};
|
||||
@@ -105,8 +118,7 @@ ButtonWidget.prototype.triggerPopup = function(event) {
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.setTiddler = function() {
|
||||
var tiddler = this.wiki.getTiddler(this.set);
|
||||
this.wiki.addTiddler(new $tw.Tiddler(tiddler,{title: this.set, text: this.setTo}));
|
||||
this.wiki.setTextReference(this.set,this.setTo,this.getVariable("currentTiddler"));
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -54,6 +54,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
||||
*/
|
||||
CountWidget.prototype.refresh = function(changedTiddlers) {
|
||||
// Re-execute the filter to get the count
|
||||
this.computeAttributes();
|
||||
var oldCount = this.currentCount;
|
||||
this.execute();
|
||||
if(this.currentCount !== oldCount) {
|
||||
|
||||
@@ -147,6 +147,11 @@ DropZoneWidget.prototype.importDataTypes = [
|
||||
};
|
||||
}
|
||||
}},
|
||||
{type: "text/html", IECompatible: false, convertToFields: function(data) {
|
||||
return {
|
||||
text: data
|
||||
};
|
||||
}},
|
||||
{type: "text/plain", IECompatible: false, convertToFields: function(data) {
|
||||
return {
|
||||
text: data
|
||||
|
||||
@@ -30,8 +30,13 @@ ElementWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
var domNode = this.document.createElementNS(this.namespace,this.parseTreeNode.tag);
|
||||
this.assignAttributes(domNode);
|
||||
// Neuter blacklisted elements
|
||||
var tag = this.parseTreeNode.tag;
|
||||
if($tw.config.htmlUnsafeElements.indexOf(tag) !== -1) {
|
||||
tag = "safe-" + tag;
|
||||
}
|
||||
var domNode = this.document.createElementNS(this.namespace,tag);
|
||||
this.assignAttributes(domNode,{excludeEventAttributes: true});
|
||||
parent.insertBefore(domNode,nextSibling);
|
||||
this.renderChildren(domNode,null);
|
||||
this.domNodes.push(domNode);
|
||||
@@ -65,7 +70,7 @@ ElementWidget.prototype.refresh = function(changedTiddlers) {
|
||||
hasChangedAttributes = $tw.utils.count(changedAttributes) > 0;
|
||||
if(hasChangedAttributes) {
|
||||
// Update our attributes
|
||||
this.assignAttributes(this.domNodes[0]);
|
||||
this.assignAttributes(this.domNodes[0],{excludeEventAttributes: true});
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers) || hasChangedAttributes;
|
||||
};
|
||||
|
||||
@@ -71,10 +71,20 @@ FieldManglerWidget.prototype.handleRemoveFieldEvent = function(event) {
|
||||
};
|
||||
|
||||
FieldManglerWidget.prototype.handleAddFieldEvent = function(event) {
|
||||
var tiddler = this.wiki.getTiddler(this.mangleTitle);
|
||||
var tiddler = this.wiki.getTiddler(this.mangleTitle),
|
||||
fieldValidatorRegEx = /^[a-z\-\._]+$/mg;
|
||||
if(tiddler && typeof event.param === "string") {
|
||||
var name = event.param.toLowerCase();
|
||||
var name = event.param.toLowerCase().trim();
|
||||
if(name !== "" && !$tw.utils.hop(tiddler.fields,name)) {
|
||||
if(!fieldValidatorRegEx.test(name)) {
|
||||
alert($tw.language.getString(
|
||||
"InvalidFieldName",
|
||||
{variables:
|
||||
{fieldName: name}
|
||||
}
|
||||
));
|
||||
return true;
|
||||
}
|
||||
var addition = this.wiki.getModificationFields();
|
||||
addition[name] = "";
|
||||
this.wiki.addTiddler(new $tw.Tiddler(tiddler,addition));
|
||||
@@ -102,11 +112,14 @@ FieldManglerWidget.prototype.handleRemoveTagEvent = function(event) {
|
||||
|
||||
FieldManglerWidget.prototype.handleAddTagEvent = function(event) {
|
||||
var tiddler = this.wiki.getTiddler(this.mangleTitle);
|
||||
if(tiddler && typeof event.param === "string" && event.param !== "") {
|
||||
var modification = this.wiki.getModificationFields();
|
||||
modification.tags = (tiddler.fields.tags || []).slice(0);
|
||||
$tw.utils.pushTop(modification.tags,event.param);
|
||||
this.wiki.addTiddler(new $tw.Tiddler(tiddler,modification));
|
||||
if(tiddler && typeof event.param === "string") {
|
||||
var tag = event.param.trim();
|
||||
if(tag !== "") {
|
||||
var modification = this.wiki.getModificationFields();
|
||||
modification.tags = (tiddler.fields.tags || []).slice(0);
|
||||
$tw.utils.pushTop(modification.tags,tag);
|
||||
this.wiki.addTiddler(new $tw.Tiddler(tiddler,modification));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
123
core/modules/widgets/image.js
Normal file
123
core/modules/widgets/image.js
Normal file
@@ -0,0 +1,123 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/image.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
The image widget displays an image referenced with an external URI or with a local tiddler title.
|
||||
|
||||
```
|
||||
<$image src="TiddlerTitle" width="320" height="400" class="classnames">
|
||||
```
|
||||
|
||||
The image source can be the title of an existing tiddler or the URL of an external image.
|
||||
|
||||
External images always generate an HTML `<img>` tag.
|
||||
|
||||
Tiddlers that have a _canonical_uri field generate an HTML `<img>` tag with the src attribute containing the URI.
|
||||
|
||||
Tiddlers that contain image data generate an HTML `<img>` tag with the src attribute containing a base64 representation of the image.
|
||||
|
||||
Tiddlers that contain wikitext could be rendered to a DIV of the usual size of a tiddler, and then transformed to the size requested.
|
||||
|
||||
The width and height attributes are interpreted as a number of pixels, and do not need to include the "px" suffix.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var ImageWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
ImageWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
ImageWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
// Create element
|
||||
// Determine what type of image it is
|
||||
var tag = "img", src = "",
|
||||
tiddler = this.wiki.getTiddler(this.imageSource);
|
||||
if(!tiddler) {
|
||||
// The source isn't the title of a tiddler, so we'll assume it's a URL
|
||||
src = this.imageSource;
|
||||
} else {
|
||||
// Check if it is an image tiddler
|
||||
if(this.wiki.isImageTiddler(this.imageSource)) {
|
||||
// Render the appropriate element for the image type
|
||||
var type = tiddler.fields.type,
|
||||
text = tiddler.fields.text;
|
||||
switch(type) {
|
||||
case "application/pdf":
|
||||
tag = "embed";
|
||||
src = "data:application/pdf;base64," + text;
|
||||
break;
|
||||
case "image/svg+xml":
|
||||
src = "data:image/svg+xml," + encodeURIComponent(text);
|
||||
break;
|
||||
default:
|
||||
src = "data:" + type + ";base64," + text;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Create the element and assign the attributes
|
||||
var domNode = this.document.createElement(tag);
|
||||
domNode.setAttribute("src",src);
|
||||
if(this.imageClass) {
|
||||
domNode.setAttribute("class",this.imageClass);
|
||||
}
|
||||
if(this.imageWidth) {
|
||||
domNode.setAttribute("width",parseInt(this.imageWidth,10) + "px");
|
||||
}
|
||||
if(this.imageHeight) {
|
||||
domNode.setAttribute("height",parseInt(this.imageHeight,10) + "px");
|
||||
}
|
||||
if(this.imageTooltip) {
|
||||
domNode.setAttribute("title",this.imageTooltip);
|
||||
}
|
||||
// Insert element
|
||||
parent.insertBefore(domNode,nextSibling);
|
||||
this.domNodes.push(domNode);
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
ImageWidget.prototype.execute = function() {
|
||||
// Get our parameters
|
||||
this.imageSource = this.getAttribute("source");
|
||||
this.imageWidth = this.getAttribute("width");
|
||||
this.imageHeight = this.getAttribute("height");
|
||||
this.imageClass = this.getAttribute("class");
|
||||
this.imageTooltip = this.getAttribute("tooltip");
|
||||
};
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
ImageWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.source || changedAttributes.width || changedAttributes.height || changedAttributes["class"] || changedAttributes.tooltip || changedTiddlers[this.imageSource]) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
exports.image = ImageWidget;
|
||||
|
||||
})();
|
||||
@@ -56,23 +56,37 @@ LinkWidget.prototype.renderLink = function(parent,nextSibling) {
|
||||
// Create our element
|
||||
var domNode = this.document.createElement("a");
|
||||
// Assign classes
|
||||
$tw.utils.addClass(domNode,"tw-tiddlylink");
|
||||
var classes = ["tw-tiddlylink"];
|
||||
if(this.isShadow) {
|
||||
$tw.utils.addClass(domNode,"tw-tiddlylink-shadow");
|
||||
classes.push("tw-tiddlylink-shadow");
|
||||
}
|
||||
if(this.isMissing && !this.isShadow) {
|
||||
$tw.utils.addClass(domNode,"tw-tiddlylink-missing");
|
||||
classes.push("tw-tiddlylink-missing");
|
||||
} else {
|
||||
if(!this.isMissing) {
|
||||
$tw.utils.addClass(domNode,"tw-tiddlylink-resolves");
|
||||
classes.push("tw-tiddlylink-resolves");
|
||||
}
|
||||
}
|
||||
domNode.setAttribute("class",classes.join(" "));
|
||||
// Set an href
|
||||
var wikiLinkTemplateMacro = this.getVariable("tw-wikilink-template"),
|
||||
wikiLinkTemplate = wikiLinkTemplateMacro ? wikiLinkTemplateMacro.trim() : "#$uri_encoded$",
|
||||
wikiLinkText = wikiLinkTemplate.replace("$uri_encoded$",encodeURIComponent(this.to));
|
||||
wikiLinkText = wikiLinkText.replace("$uri_doubleencoded$",encodeURIComponent(encodeURIComponent(this.to)));
|
||||
domNode.setAttribute("href",wikiLinkText);
|
||||
// Set the tooltip
|
||||
// HACK: Performance issues with re-parsing the tooltip prevent us defaulting the tooltip to "<$transclude field='tooltip'><$transclude field='title'/></$transclude>"
|
||||
var tooltipWikiText = this.tooltip || this.getVariable("tw-wikilink-tooltip");
|
||||
if(tooltipWikiText) {
|
||||
var tooltipText = this.wiki.renderText("text/plain","text/vnd.tiddlywiki",tooltipWikiText,{
|
||||
parseAsInline: true,
|
||||
variables: {
|
||||
currentTiddler: this.to
|
||||
},
|
||||
parentWidget: this
|
||||
});
|
||||
domNode.setAttribute("title",tooltipText);
|
||||
}
|
||||
// Add a click event handler
|
||||
$tw.utils.addEventListeners(domNode,[
|
||||
{name: "click", handlerObject: this, handlerMethod: "handleClickEvent"},
|
||||
@@ -95,7 +109,7 @@ LinkWidget.prototype.handleClickEvent = function (event) {
|
||||
navigateFromNode: this,
|
||||
navigateFromClientRect: { top: bounds.top, left: bounds.left, width: bounds.width, right: bounds.right, bottom: bounds.bottom, height: bounds.height
|
||||
},
|
||||
navigateSuppressNavigation: event.metaKey || event.ctrlKey
|
||||
navigateSuppressNavigation: event.metaKey || event.ctrlKey || (event.button === 1)
|
||||
});
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
@@ -162,6 +176,8 @@ Compute the internal state of the widget
|
||||
LinkWidget.prototype.execute = function() {
|
||||
// Get the target tiddler title
|
||||
this.to = this.getAttribute("to",this.getVariable("currentTiddler"));
|
||||
// Get the link title
|
||||
this.tooltip = this.getAttribute("tooltip");
|
||||
// Determine the link characteristics
|
||||
this.isMissing = !this.wiki.tiddlerExists(this.to);
|
||||
this.isShadow = this.wiki.isShadowTiddler(this.to);
|
||||
@@ -174,7 +190,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
||||
*/
|
||||
LinkWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.to || changedTiddlers[this.to]) {
|
||||
if(changedAttributes.to || changedTiddlers[this.to] || changedAttributes.tooltip) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -69,10 +69,11 @@ LinkCatcherWidget.prototype.handleNavigateEvent = function(event) {
|
||||
if(this.catchTo) {
|
||||
this.wiki.setTextReference(this.catchTo,event.navigateTo,this.getVariable("currentTiddler"));
|
||||
}
|
||||
if(this.catchMessage) {
|
||||
this.dispatchEvent({
|
||||
if(this.catchMessage && this.parentWidget) {
|
||||
this.parentWidget.dispatchEvent({
|
||||
type: this.catchMessage,
|
||||
param: event.navigateTo
|
||||
param: event.navigateTo,
|
||||
navigateTo: event.navigateTo
|
||||
});
|
||||
}
|
||||
if(this.catchSet) {
|
||||
|
||||
@@ -43,7 +43,11 @@ ListWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.renderChildren(parent,nextSibling);
|
||||
// Construct the storyview
|
||||
var StoryView = this.storyViews[this.storyViewName];
|
||||
this.storyview = StoryView ? new StoryView(this) : null;
|
||||
if(StoryView && !this.document.isTiddlyWikiFakeDom) {
|
||||
this.storyview = new StoryView(this)
|
||||
} else {
|
||||
this.storyview = null;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -26,7 +26,7 @@ var NavigatorWidget = function(parseTreeNode,options) {
|
||||
{type: "tw-close-all-tiddlers", handler: "handleCloseAllTiddlersEvent"},
|
||||
{type: "tw-close-other-tiddlers", handler: "handleCloseOtherTiddlersEvent"},
|
||||
{type: "tw-new-tiddler", handler: "handleNewTiddlerEvent"},
|
||||
{type: "tw-import-tiddlers", handler: "handleImportTiddlersEvent"},
|
||||
{type: "tw-import-tiddlers", handler: "handleImportTiddlersEvent"}
|
||||
]);
|
||||
};
|
||||
|
||||
@@ -198,15 +198,29 @@ NavigatorWidget.prototype.handleDeleteTiddlerEvent = function(event) {
|
||||
// Get the tiddler we're deleting
|
||||
var title = event.param || event.tiddlerTitle,
|
||||
tiddler = this.wiki.getTiddler(title),
|
||||
storyList = this.getStoryList();
|
||||
storyList = this.getStoryList(),
|
||||
originalTitle, confirmationTitle;
|
||||
// Check if the tiddler we're deleting is in draft mode
|
||||
if(tiddler.hasField("draft.title")) {
|
||||
// Delete the original tiddler
|
||||
var originalTitle = tiddler.fields["draft.of"];
|
||||
// Ask for confirmation if the tiddler has changed
|
||||
if(!confirm("Do you wish to delete the tiddler '" + originalTitle + "'")) {
|
||||
return false;
|
||||
}
|
||||
// If so, we'll prompt for confirmation referencing the original tiddler
|
||||
originalTitle = tiddler.fields["draft.of"];
|
||||
confirmationTitle = originalTitle;
|
||||
} else {
|
||||
// If not a draft, then prompt for confirmation referencing the specified tiddler
|
||||
originalTitle = null;
|
||||
confirmationTitle = title;
|
||||
}
|
||||
// Seek confirmation
|
||||
if(!confirm($tw.language.getString(
|
||||
"ConfirmDeleteTiddler",
|
||||
{variables:
|
||||
{title: confirmationTitle}
|
||||
}
|
||||
))) {
|
||||
return false;
|
||||
}
|
||||
// Delete the original tiddler
|
||||
if(originalTitle) {
|
||||
this.wiki.deleteTiddler(originalTitle);
|
||||
this.removeTitleFromStory(storyList,originalTitle);
|
||||
}
|
||||
@@ -277,7 +291,12 @@ NavigatorWidget.prototype.handleSaveTiddlerEvent = function(event) {
|
||||
var isRename = draftOf !== draftTitle,
|
||||
isConfirmed = true;
|
||||
if(isRename && this.wiki.tiddlerExists(draftTitle)) {
|
||||
isConfirmed = confirm("Do you wish to overwrite the tiddler '" + draftTitle + "'?");
|
||||
isConfirmed = confirm($tw.language.getString(
|
||||
"ConfirmOverwriteTiddler",
|
||||
{variables:
|
||||
{title: draftTitle}
|
||||
}
|
||||
));
|
||||
}
|
||||
if(isConfirmed) {
|
||||
// Save the draft tiddler as the real tiddler
|
||||
@@ -314,11 +333,23 @@ NavigatorWidget.prototype.handleCancelTiddlerEvent = function(event) {
|
||||
originalTitle = draftTiddler.fields["draft.of"],
|
||||
storyList = this.getStoryList();
|
||||
if(draftTiddler && originalTitle) {
|
||||
// Ask for confirmation if the tiddler text has changed
|
||||
var isConfirmed = true;
|
||||
if(this.wiki.getTiddlerText(draftTitle) !== this.wiki.getTiddlerText(originalTitle)) {
|
||||
isConfirmed = confirm($tw.language.getString(
|
||||
"ConfirmCancelTiddler",
|
||||
{variables:
|
||||
{title: draftTitle}
|
||||
}
|
||||
));
|
||||
}
|
||||
// Remove the draft tiddler
|
||||
this.wiki.deleteTiddler(draftTitle);
|
||||
this.replaceFirstTitleInStory(storyList,draftTitle,originalTitle);
|
||||
this.addToHistory(originalTitle,event.navigateFromClientRect);
|
||||
this.saveStoryList(storyList);
|
||||
if(isConfirmed) {
|
||||
this.wiki.deleteTiddler(draftTitle);
|
||||
this.replaceFirstTitleInStory(storyList,draftTitle,originalTitle);
|
||||
this.addToHistory(originalTitle,event.navigateFromClientRect);
|
||||
this.saveStoryList(storyList);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
184
core/modules/widgets/scrollable.js
Normal file
184
core/modules/widgets/scrollable.js
Normal file
@@ -0,0 +1,184 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/scrollable.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Scrollable widget
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var ScrollableWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
this.scaleFactor = 1;
|
||||
this.addEventListeners([
|
||||
{type: "tw-scroll", handler: "handleScrollEvent"}
|
||||
]);
|
||||
if($tw.browser) {
|
||||
this.requestAnimationFrame = window.requestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.mozRequestAnimationFrame ||
|
||||
function(callback) {
|
||||
return window.setTimeout(callback, 1000/60);
|
||||
};
|
||||
this.cancelAnimationFrame = window.cancelAnimationFrame ||
|
||||
window.webkitCancelAnimationFrame ||
|
||||
window.webkitCancelRequestAnimationFrame ||
|
||||
window.mozCancelAnimationFrame ||
|
||||
window.mozCancelRequestAnimationFrame ||
|
||||
function(id) {
|
||||
window.clearTimeout(id);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
ScrollableWidget.prototype = new Widget();
|
||||
|
||||
ScrollableWidget.prototype.cancelScroll = function() {
|
||||
if(this.idRequestFrame) {
|
||||
this.cancelAnimationFrame.call(window,this.idRequestFrame);
|
||||
this.idRequestFrame = null;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Handle a scroll event
|
||||
*/
|
||||
ScrollableWidget.prototype.handleScrollEvent = function(event) {
|
||||
// Pass the scroll event through if our offsetsize is larger than our scrollsize
|
||||
if(this.outerDomNode.scrollWidth <= this.outerDomNode.offsetWidth && this.outerDomNode.scrollHeight <= this.outerDomNode.offsetHeight && this.fallthrough === "yes") {
|
||||
return true;
|
||||
}
|
||||
this.scrollIntoView(event.target);
|
||||
return false; // Handled event
|
||||
};
|
||||
|
||||
/*
|
||||
Scroll an element into view
|
||||
*/
|
||||
ScrollableWidget.prototype.scrollIntoView = function(element) {
|
||||
var duration = $tw.utils.getAnimationDuration();
|
||||
this.cancelScroll();
|
||||
this.startTime = Date.now();
|
||||
var scrollPosition = {
|
||||
x: this.outerDomNode.scrollLeft,
|
||||
y: this.outerDomNode.scrollTop
|
||||
};
|
||||
// Get the client bounds of the element and adjust by the scroll position
|
||||
var scrollableBounds = this.outerDomNode.getBoundingClientRect(),
|
||||
clientTargetBounds = element.getBoundingClientRect(),
|
||||
bounds = {
|
||||
left: clientTargetBounds.left + scrollPosition.x - scrollableBounds.left,
|
||||
top: clientTargetBounds.top + scrollPosition.y - scrollableBounds.top,
|
||||
width: clientTargetBounds.width,
|
||||
height: clientTargetBounds.height
|
||||
};
|
||||
// We'll consider the horizontal and vertical scroll directions separately via this function
|
||||
var getEndPos = function(targetPos,targetSize,currentPos,currentSize) {
|
||||
// If the target is already visible then stay where we are
|
||||
if(targetPos >= currentPos && (targetPos + targetSize) <= (currentPos + currentSize)) {
|
||||
return currentPos;
|
||||
// If the target is above/left of the current view, then scroll to its top/left
|
||||
} else if(targetPos <= currentPos) {
|
||||
return targetPos;
|
||||
// If the target is smaller than the window and the scroll position is too far up, then scroll till the target is at the bottom of the window
|
||||
} else if(targetSize < currentSize && currentPos < (targetPos + targetSize - currentSize)) {
|
||||
return targetPos + targetSize - currentSize;
|
||||
// If the target is big, then just scroll to the top
|
||||
} else if(currentPos < targetPos) {
|
||||
return targetPos;
|
||||
// Otherwise, stay where we are
|
||||
} else {
|
||||
return currentPos;
|
||||
}
|
||||
},
|
||||
endX = getEndPos(bounds.left,bounds.width,scrollPosition.x,this.outerDomNode.offsetWidth),
|
||||
endY = getEndPos(bounds.top,bounds.height,scrollPosition.y,this.outerDomNode.offsetHeight);
|
||||
// Only scroll if necessary
|
||||
if(endX !== scrollPosition.x || endY !== scrollPosition.y) {
|
||||
var self = this,
|
||||
drawFrame;
|
||||
drawFrame = function () {
|
||||
var t;
|
||||
if(duration <= 0) {
|
||||
t = 1;
|
||||
} else {
|
||||
t = ((Date.now()) - self.startTime) / duration;
|
||||
}
|
||||
if(t >= 1) {
|
||||
self.cancelScroll();
|
||||
t = 1;
|
||||
}
|
||||
t = $tw.utils.slowInSlowOut(t);
|
||||
self.outerDomNode.scrollLeft = scrollPosition.x + (endX - scrollPosition.x) * t;
|
||||
self.outerDomNode.scrollTop = scrollPosition.y + (endY - scrollPosition.y) * t;
|
||||
if(t < 1) {
|
||||
self.idRequestFrame = self.requestAnimationFrame.call(window,drawFrame);
|
||||
}
|
||||
};
|
||||
drawFrame();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
ScrollableWidget.prototype.render = function(parent,nextSibling) {
|
||||
var self = this;
|
||||
// Remember parent
|
||||
this.parentDomNode = parent;
|
||||
// Compute attributes and execute state
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
// Create elements
|
||||
this.outerDomNode = this.document.createElement("div");
|
||||
$tw.utils.setStyle(this.outerDomNode,[
|
||||
{overflowY: "auto"},
|
||||
{overflowX: "auto"},
|
||||
{webkitOverflowScrolling: "touch"}
|
||||
]);
|
||||
this.innerDomNode = this.document.createElement("div");
|
||||
this.outerDomNode.appendChild(this.innerDomNode);
|
||||
// Assign classes
|
||||
this.outerDomNode.className = this["class"] || "";
|
||||
// Insert element
|
||||
parent.insertBefore(this.outerDomNode,nextSibling);
|
||||
this.renderChildren(this.innerDomNode,null);
|
||||
this.domNodes.push(this.outerDomNode);
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
ScrollableWidget.prototype.execute = function() {
|
||||
// Get attributes
|
||||
this.fallthrough = this.getAttribute("fallthrough","yes");
|
||||
this["class"] = this.getAttribute("class");
|
||||
// Make child widgets
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
ScrollableWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes["class"]) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
};
|
||||
|
||||
exports.scrollable = ScrollableWidget;
|
||||
|
||||
})();
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user