mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-01-22 19:04:38 +00:00
Compare commits
17 Commits
v5.2.0
...
publishing
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbdf9bae89 | ||
|
|
f1d76a1eee | ||
|
|
160c154ef1 | ||
|
|
184083ad1a | ||
|
|
9c62bd8030 | ||
|
|
b7419dec3a | ||
|
|
02d390a673 | ||
|
|
c4cdb1ed8c | ||
|
|
5fcff1f1a3 | ||
|
|
a8770d7645 | ||
|
|
df2a3fdefd | ||
|
|
a8c248eb3d | ||
|
|
96103d5d4c | ||
|
|
a025bce21f | ||
|
|
45cdd7bdf7 | ||
|
|
509356c696 | ||
|
|
42e10d030a |
46
boot/boot.js
46
boot/boot.js
@@ -757,7 +757,12 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
|
||||
tiddler = $tw.wiki.getTiddler(name),
|
||||
_exports = {},
|
||||
sandbox = {
|
||||
module: {exports: _exports},
|
||||
module: {
|
||||
exports: _exports,
|
||||
setStringHandler: function(handler) {
|
||||
moduleInfo.stringHandler = handler;
|
||||
}
|
||||
},
|
||||
//moduleInfo: moduleInfo,
|
||||
exports: _exports,
|
||||
console: console,
|
||||
@@ -821,7 +826,7 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
|
||||
moduleInfo.definition(moduleInfo,moduleInfo.exports,sandbox.require);
|
||||
} else if(typeof moduleInfo.definition === "string") { // String
|
||||
moduleInfo.exports = _exports;
|
||||
$tw.utils.evalSandboxed(moduleInfo.definition,sandbox,tiddler.fields.title);
|
||||
$tw.utils.evalSandboxed(moduleInfo.definition,sandbox,name);
|
||||
if(sandbox.module.exports) {
|
||||
moduleInfo.exports = sandbox.module.exports; //more codemirror workaround
|
||||
}
|
||||
@@ -918,6 +923,20 @@ $tw.modules.createClassesFromModules = function(moduleType,subType,baseClass) {
|
||||
return classes;
|
||||
};
|
||||
|
||||
/*
|
||||
Return a specified module string for a module, null if the module or string is missing
|
||||
*/
|
||||
$tw.modules.getModuleString = function(moduleName,stringName,language) {
|
||||
if(moduleName in $tw.modules.titles) {
|
||||
$tw.modules.execute(moduleName);
|
||||
var stringHandler = $tw.modules.titles[moduleName].stringHandler;
|
||||
if(stringHandler) {
|
||||
return stringHandler(stringName,language);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/////////////////////////// Barebones tiddler object
|
||||
|
||||
/*
|
||||
@@ -1212,12 +1231,8 @@ $tw.Wiki = function(options) {
|
||||
index,titlesLength,title;
|
||||
for(index = 0, titlesLength = titles.length; index < titlesLength; index++) {
|
||||
title = titles[index];
|
||||
if(tiddlers[title]) {
|
||||
callback(tiddlers[title],title);
|
||||
} else {
|
||||
var shadowInfo = shadowTiddlers[title];
|
||||
callback(shadowInfo.tiddler,title);
|
||||
}
|
||||
var shadowInfo = shadowTiddlers[title];
|
||||
callback(shadowInfo.tiddler,title);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1606,8 +1621,8 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/json","tiddlerdeserializer",{
|
||||
}
|
||||
for(var f in data) {
|
||||
if($tw.utils.hop(data,f)) {
|
||||
// Check field name doesn't contain control characters
|
||||
if(typeof(data[f]) !== "string" || /[\x00-\x1F]/.test(f)) {
|
||||
// Check field name doesn't contain whitespace or control characters
|
||||
if(typeof(data[f]) !== "string" || /[\x00-\x1F\s]/.test(f)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1622,12 +1637,7 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/json","tiddlerdeserializer",{
|
||||
}
|
||||
return true;
|
||||
},
|
||||
data = {};
|
||||
try {
|
||||
data = JSON.parse(text);
|
||||
} catch(e) {
|
||||
// Ignore JSON parse errors
|
||||
}
|
||||
data = JSON.parse(text);
|
||||
if($tw.utils.isArray(data) && isTiddlerArrayValid(data)) {
|
||||
return data;
|
||||
} else if(isTiddlerValid(data)) {
|
||||
@@ -1894,13 +1904,13 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
value = path.basename(filename);
|
||||
break;
|
||||
case "filename-uri-decoded":
|
||||
value = $tw.utils.decodeURIComponentSafe(path.basename(filename));
|
||||
value = decodeURIComponent(path.basename(filename));
|
||||
break;
|
||||
case "basename":
|
||||
value = path.basename(filename,path.extname(filename));
|
||||
break;
|
||||
case "basename-uri-decoded":
|
||||
value = $tw.utils.decodeURIComponentSafe(path.basename(filename,path.extname(filename)));
|
||||
value = decodeURIComponent(path.basename(filename,path.extname(filename)));
|
||||
break;
|
||||
case "extname":
|
||||
value = path.extname(filename);
|
||||
|
||||
File diff suppressed because one or more lines are too long
7
core/images/publish.tid
Normal file
7
core/images/publish.tid
Normal file
@@ -0,0 +1,7 @@
|
||||
title: $:/core/images/publish
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg width="22pt" height="22pt" class="tc-image-publish tc-image-button" viewBox="0 0 128 128"><g fill-rule="evenodd">
|
||||
<path d="M64.0434107,46.2358498 C65.8048912,45.8955184 67.6195684,46.7809274 68.4102078,48.4458716 L68.4937877,48.6340507 L98.8972485,122.034498 C99.7426494,124.075476 98.7734424,126.415349 96.7324641,127.26075 C94.7552664,128.079732 92.4975633,127.195747 91.5897922,125.284145 L91.5062123,125.095966 L88.403,117.605598 L79.5048497,126.50485 C78.775871,127.233828 77.8355254,127.622617 76.8810886,127.671216 L76.6764226,127.676423 C75.6527333,127.676423 74.6290441,127.285898 73.8479955,126.50485 L63.999,116.656598 L54.1520045,126.50485 C53.4230259,127.233828 52.4826802,127.622617 51.5282434,127.671216 L51.3235774,127.676423 C50.2998881,127.676423 49.2761989,127.285898 48.4951503,126.50485 L39.596,117.605598 L36.4937877,125.095966 C35.6483868,127.136944 33.3085142,128.106151 31.2675359,127.26075 C29.2265576,126.415349 28.2573506,124.075476 29.1027515,122.034498 L59.5062123,48.6340507 C60.2518688,46.8338766 62.1601511,45.867488 64.0005148,46.2445933 L64.0434107,46.2358498 Z M77.679,102.976598 L69.656,110.999598 L76.676,118.018598 L84.699,109.996598 L77.679,102.976598 Z M50.326,102.983598 L43.307,110.002598 L51.323,118.018598 L58.342,110.999598 L50.326,102.983598 Z M64.006,89.3035977 L55.983,97.3265977 L63.999,105.342598 L72.022,97.3195977 L64.006,89.3035977 Z M55.035,80.3325977 L50.348,91.6475977 L58.349,83.6465977 L55.035,80.3325977 Z M72.968,80.3415977 L69.663,83.6465977 L77.642,91.6255977 L72.968,80.3415977 Z M64,58.6895977 L58.3344072,72.3699713 C58.4295481,72.4423583 58.5221874,72.5195778 58.6119911,72.6016299 L58.7445283,72.7283325 L64.006,77.9895977 L69.2684411,72.7283325 C69.3957231,72.6010505 69.5294489,72.4841397 69.6685683,72.3775999 L64,58.6895977 Z M38.5026635,2.59571369 C40.7118025,2.59571369 42.5026635,4.38657469 42.5026635,6.59571369 C42.5026635,7.7643162 42.0015346,8.8158738 41.2024517,9.54721162 L41.372583,9.372583 C35.581722,15.163444 32,23.163444 32,32 C32,40.8370609 35.5821314,48.8374703 41.3735757,54.6284097 C42.0884306,55.3520538 42.531226,56.3471171 42.531226,57.4456008 C42.531226,59.6547398 40.740365,61.4456008 38.531226,61.4456008 C37.4327422,61.4456008 36.4376789,61.0028055 35.7147885,60.2859673 L35.7048234,60.2963403 C28.472656,53.0586276 24,43.0631255 24,32.0229786 C24,21.1046577 28.3744907,11.2080539 35.4664167,3.99022262 C36.2004724,3.13678606 37.2883808,2.59571369 38.5026635,2.59571369 Z M89.3688013,2.48959773 C90.5097745,2.48959773 91.5391719,2.96731026 92.2678917,3.73363348 L92.2733617,3.72780197 C99.5183488,10.9672382 104,20.9717355 104,32.0229786 C104,42.8488024 99.6993143,52.6701472 92.7132398,59.8717162 C91.9816831,60.8152368 90.8371876,61.4223982 89.5508819,61.4223982 C87.3417429,61.4223982 85.5508819,59.6315372 85.5508819,57.4223982 C85.5508819,56.3502862 85.9726717,55.3766885 86.6593633,54.6584932 L86.627417,54.627417 C92.418278,48.836556 96,40.836556 96,32 C96,23.2702193 92.5043135,15.3568999 86.8363661,9.5834674 C85.9399594,8.85136737 85.3688013,7.73718311 85.3688013,6.48959773 C85.3688013,4.28045873 87.1596623,2.48959773 89.3688013,2.48959773 Z M50.0871028,13.6297119 C52.2962418,13.6297119 54.0871028,15.4205729 54.0871028,17.6297119 C54.0871028,18.8506134 53.5401157,19.9437593 52.6778337,20.6774573 L52.6862915,20.6862915 C49.790861,23.581722 48,27.581722 48,32 C48,36.4187838 49.791271,40.4191937 52.6872859,43.3147028 L52.6777105,43.3251493 C53.4423082,44.0537041 53.918794,45.0819221 53.918794,46.2214294 C53.918794,48.4305684 52.127933,50.2214294 49.918794,50.2214294 C48.6900999,50.2214294 47.5907975,49.6674376 46.8570439,48.7956109 L47.0304281,48.9715536 C42.6867001,44.6283295 40,38.627921 40,32 C40,25.372583 42.6862915,19.372583 47.0294373,15.0294373 L47.0395567,15.0387468 C47.7732533,14.1766 48.8663118,13.6297119 50.0871028,13.6297119 Z M77.9823819,13.700452 C79.1679628,13.700452 80.2330731,14.2162483 80.9655529,15.0356811 L80.9715536,15.0304281 C85.314117,19.3734956 88,25.373087 88,32 C88,38.4619387 85.4461804,44.3274009 81.2927766,48.6421512 L80.9933974,48.9476975 C80.2638884,49.7186971 79.2309977,50.2000547 78.08568,50.2000547 C75.876541,50.2000547 74.08568,48.4091937 74.08568,46.2000547 C74.08568,45.0665777 74.557136,44.0432152 75.314649,43.3153662 L75.3137085,43.3137085 C78.209139,40.418278 80,36.418278 80,32 C80,27.5822253 78.209547,23.5826334 75.314698,20.6872811 C74.4981782,19.9511432 73.9823819,18.8860329 73.9823819,17.700452 C73.9823819,15.491313 75.7732429,13.700452 77.9823819,13.700452 Z M64,24 C68.418278,24 72,27.581722 72,32 C72,36.418278 68.418278,40 64,40 C59.581722,40 56,36.418278 56,32 C56,27.581722 59.581722,24 64,24 Z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
@@ -32,6 +32,8 @@ ExportTiddler/Caption: export tiddler
|
||||
ExportTiddler/Hint: Export tiddler
|
||||
ExportTiddlers/Caption: export tiddlers
|
||||
ExportTiddlers/Hint: Export tiddlers
|
||||
ExportTiddlyWikiCore/Caption: export TiddlyWiki core
|
||||
ExportTiddlyWikiCore/Hint: Export the ~TiddlyWiki core code for running with external ~JavaScript
|
||||
SidebarSearch/Hint: Select the sidebar search field
|
||||
Fold/Caption: fold tiddler
|
||||
Fold/Hint: Fold the body of this tiddler
|
||||
@@ -83,6 +85,8 @@ Permaview/Caption: permaview
|
||||
Permaview/Hint: Set browser address bar to a direct link to all the tiddlers in this story
|
||||
Print/Caption: print page
|
||||
Print/Hint: Print the current page
|
||||
Publish/Caption: publish
|
||||
Publish/Hint: Publish from the wiki
|
||||
Refresh/Caption: refresh
|
||||
Refresh/Hint: Perform a full refresh of the wiki
|
||||
Save/Caption: ok
|
||||
|
||||
@@ -96,6 +96,8 @@ Plugins/Updates/Caption: Updates
|
||||
Plugins/Updates/Hint: Available updates to installed plugins
|
||||
Plugins/Updates/UpdateAll/Caption: Update <<update-count>> plugins
|
||||
Plugins/SubPluginPrompt: With <<count>> sub-plugins available
|
||||
Publishing/Caption: Publishing
|
||||
Publishing/Hint: Settings used for publishing extracts from this TiddlyWiki as separate files through a "publisher" module
|
||||
Saving/Caption: Saving
|
||||
Saving/DownloadSaver/AutoSave/Description: Permit automatic saving for the download saver
|
||||
Saving/DownloadSaver/AutoSave/Hint: Enable Autosave for Download Saver
|
||||
|
||||
@@ -22,6 +22,8 @@ All parameters are optional with safe defaults, and can be specified in any orde
|
||||
* ''readers'' - comma-separated list of principals allowed to read from this wiki
|
||||
* ''writers'' - comma-separated list of principals allowed to write to this wiki
|
||||
* ''csrf-disable'' - set to "yes" to disable CSRF checks (defaults to "no")
|
||||
* ''sse-enabled'' - set to "yes" to enable Server-sent events (defaults to "no")
|
||||
* ''sitemap'' - optional sitemap describing how the tiddlers will be served. See [[Publishing]] for more details
|
||||
* ''root-tiddler'' - the tiddler to serve at the root (defaults to "$:/core/save/all")
|
||||
* ''root-render-type'' - the content type to which the root tiddler should be rendered (defaults to "text/plain")
|
||||
* ''root-serve-type'' - the content type with which the root tiddler should be served (defaults to "text/html")
|
||||
|
||||
@@ -30,5 +30,5 @@ Upgrader/System/Warning: Core module tiddler.
|
||||
Upgrader/System/Alert: You are about to import a tiddler that will overwrite a core module tiddler. This is not recommended as it may make the system unstable.
|
||||
Upgrader/ThemeTweaks/Created: Migrated theme tweak from <$text text=<<from>>/>.
|
||||
Upgrader/Tiddler/Disabled: Disabled tiddler.
|
||||
Upgrader/Tiddler/Selected: Selected tiddler.
|
||||
Upgrader/Tiddler/Selected: User selected.
|
||||
Upgrader/Tiddler/Unselected: Unselected tiddler.
|
||||
|
||||
5
core/language/en-GB/Publishing/Modal.tid
Normal file
5
core/language/en-GB/Publishing/Modal.tid
Normal file
@@ -0,0 +1,5 @@
|
||||
title: $:/language/Publishing/Modal
|
||||
subtitle: Publishing: ''<$transclude field="caption"><$view field="title"/></$transclude>''
|
||||
footer: <$button message="tm-close-tiddler">Cancel</$button>
|
||||
|
||||
Publishing <$text text=<<totalFiles>>/> files via the "{{!!publisher}}" publisher.
|
||||
46
core/modules/commands/publish.js
Normal file
46
core/modules/commands/publish.js
Normal file
@@ -0,0 +1,46 @@
|
||||
/*\
|
||||
title: $:/core/modules/commands/publish.js
|
||||
type: application/javascript
|
||||
module-type: command
|
||||
|
||||
Publish static files
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.info = {
|
||||
name: "publish",
|
||||
synchronous: false
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
if(this.params.length < 1) {
|
||||
return "Missing filename filter";
|
||||
}
|
||||
var self = this,
|
||||
wiki = this.commander.wiki,
|
||||
jobTiddler = this.params[0],
|
||||
variableList = this.params.slice(1),
|
||||
variables = Object.create(null);
|
||||
while(variableList.length >= 2) {
|
||||
variables[variableList[0]] = variableList[1];
|
||||
variableList = variableList.slice(2);
|
||||
}
|
||||
$tw.publisherHandler.publish(jobTiddler,this.callback,{commander: this.commander,variables: variables});
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
})();
|
||||
|
||||
@@ -8,59 +8,58 @@ Render individual tiddlers and save the results to the specified files
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
|
||||
exports.info = {
|
||||
name: "render",
|
||||
synchronous: true
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
if(this.params.length < 1) {
|
||||
return "Missing tiddler filter";
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
|
||||
exports.info = {
|
||||
name: "render",
|
||||
synchronous: true
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
if(this.params.length < 1) {
|
||||
return "Missing tiddler filter";
|
||||
}
|
||||
var self = this,
|
||||
fs = require("fs"),
|
||||
path = require("path"),
|
||||
wiki = this.commander.wiki,
|
||||
tiddlerFilter = this.params[0],
|
||||
filenameFilter = this.params[1] || "[is[tiddler]addsuffix[.html]]",
|
||||
type = this.params[2] || "text/html",
|
||||
template = this.params[3],
|
||||
variableList = this.params.slice(4),
|
||||
tiddlers = wiki.filterTiddlers(tiddlerFilter),
|
||||
variables = Object.create(null);
|
||||
while(variableList.length >= 2) {
|
||||
variables[variableList[0]] = variableList[1];
|
||||
variableList = variableList.slice(2);
|
||||
}
|
||||
$tw.utils.each(tiddlers,function(title) {
|
||||
var parser = wiki.parseTiddler(template || title);
|
||||
var widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title})}),
|
||||
container = $tw.fakeDocument.createElement("div");
|
||||
widgetNode.render(container,null);
|
||||
var text = type === "text/html" ? container.innerHTML : container.textContent,
|
||||
filepath = path.resolve(self.commander.outputPath,wiki.filterTiddlers(filenameFilter,$tw.rootWidget,wiki.makeTiddlerIterator([title]))[0]);
|
||||
if(self.commander.verbose) {
|
||||
console.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
|
||||
}
|
||||
var self = this,
|
||||
fs = require("fs"),
|
||||
path = require("path"),
|
||||
wiki = this.commander.wiki,
|
||||
tiddlerFilter = this.params[0],
|
||||
filenameFilter = this.params[1] || "[is[tiddler]addsuffix[.html]]",
|
||||
type = this.params[2] || "text/html",
|
||||
template = this.params[3],
|
||||
variableList = this.params.slice(4),
|
||||
tiddlers = wiki.filterTiddlers(tiddlerFilter),
|
||||
variables = Object.create(null);
|
||||
while(variableList.length >= 2) {
|
||||
variables[variableList[0]] = variableList[1];
|
||||
variableList = variableList.slice(2);
|
||||
}
|
||||
$tw.utils.each(tiddlers,function(title) {
|
||||
var filepath = path.resolve(self.commander.outputPath,wiki.filterTiddlers(filenameFilter,$tw.rootWidget,wiki.makeTiddlerIterator([title]))[0]);
|
||||
if(self.commander.verbose) {
|
||||
console.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
|
||||
}
|
||||
var parser = wiki.parseTiddler(template || title),
|
||||
widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title})}),
|
||||
container = $tw.fakeDocument.createElement("div");
|
||||
widgetNode.render(container,null);
|
||||
var text = type === "text/html" ? container.innerHTML : container.textContent;
|
||||
$tw.utils.createFileDirectories(filepath);
|
||||
fs.writeFileSync(filepath,text,"utf8");
|
||||
});
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
})();
|
||||
|
||||
$tw.utils.createFileDirectories(filepath);
|
||||
fs.writeFileSync(filepath,text,"utf8");
|
||||
});
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
})();
|
||||
|
||||
@@ -135,11 +135,7 @@ FramedEngine.prototype.setText = function(text,type) {
|
||||
Update the DomNode with the new text
|
||||
*/
|
||||
FramedEngine.prototype.updateDomNodeText = function(text) {
|
||||
try {
|
||||
this.domNode.value = text;
|
||||
} catch(e) {
|
||||
// Ignore
|
||||
}
|
||||
this.domNode.value = text;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -85,11 +85,7 @@ SimpleEngine.prototype.setText = function(text,type) {
|
||||
Update the DomNode with the new text
|
||||
*/
|
||||
SimpleEngine.prototype.updateDomNodeText = function(text) {
|
||||
try {
|
||||
this.domNode.value = text;
|
||||
} catch(e) {
|
||||
// Ignore
|
||||
}
|
||||
this.domNode.value = text;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -332,7 +332,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
};
|
||||
|
||||
EditTextWidget.prototype.handlePasteEvent = function(event) {
|
||||
if(event.clipboardData && event.clipboardData.files && event.clipboardData.files.length) {
|
||||
if(event.clipboardData.files.length) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.dispatchDOMEvent(this.cloneEvent(event,["clipboardData"]));
|
||||
|
||||
@@ -52,7 +52,7 @@ exports.all = function(source,operator,options) {
|
||||
results.pushTop(subop(source,operator.prefix,options));
|
||||
}
|
||||
}
|
||||
return results.makeTiddlerIterator(options.wiki);
|
||||
return results.toArray();
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -16,11 +16,11 @@ Filter operator for returning all the backlinks from a tiddler
|
||||
Export our filter function
|
||||
*/
|
||||
exports.backlinks = function(source,operator,options) {
|
||||
var results = new $tw.utils.LinkedList();
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.pushTop(options.wiki.getTiddlerBacklinks(title));
|
||||
$tw.utils.pushTop(results,options.wiki.getTiddlerBacklinks(title));
|
||||
});
|
||||
return results.makeTiddlerIterator(options.wiki);
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -19,7 +19,12 @@ Export our filter functions
|
||||
exports.decodeuricomponent = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push($tw.utils.decodeURIComponentSafe(title));
|
||||
var value = title;
|
||||
try {
|
||||
value = decodeURIComponent(title);
|
||||
} catch(e) {
|
||||
}
|
||||
results.push(value);
|
||||
});
|
||||
return results;
|
||||
};
|
||||
@@ -35,7 +40,12 @@ exports.encodeuricomponent = function(source,operator,options) {
|
||||
exports.decodeuri = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push($tw.utils.decodeURISafe(title));
|
||||
var value = title;
|
||||
try {
|
||||
value = decodeURI(title);
|
||||
} catch(e) {
|
||||
}
|
||||
results.push(value);
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -20,7 +20,7 @@ exports.links = function(source,operator,options) {
|
||||
source(function(tiddler,title) {
|
||||
results.pushTop(options.wiki.getTiddlerLinks(title));
|
||||
});
|
||||
return results.makeTiddlerIterator(options.wiki);
|
||||
return results.toArray();
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -17,7 +17,14 @@ Export our filter function
|
||||
*/
|
||||
exports.modules = function(source,operator,options) {
|
||||
var results = [];
|
||||
if(operator.operands.length >= 2) {
|
||||
if(operator.operands.length === 1) {
|
||||
// Return all the module names without filtering
|
||||
source(function(tiddler,title) {
|
||||
$tw.utils.each($tw.modules.types[title],function(moduleInfo,moduleName) {
|
||||
results.push(moduleName);
|
||||
});
|
||||
});
|
||||
} else if(operator.operands.length >= 2) {
|
||||
// Return the modules that have the module property specified in the first operand with the value in the second operand
|
||||
source(function(tiddler,title) {
|
||||
$tw.utils.each($tw.modules.types[title],function(moduleInfo,moduleName) {
|
||||
@@ -26,13 +33,6 @@ exports.modules = function(source,operator,options) {
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Return all the module names without filtering
|
||||
source(function(tiddler,title) {
|
||||
$tw.utils.each($tw.modules.types[title],function(moduleInfo,moduleName) {
|
||||
results.push(moduleName);
|
||||
});
|
||||
});
|
||||
}
|
||||
results.sort();
|
||||
return results;
|
||||
|
||||
30
core/modules/filters/modulestring.js
Normal file
30
core/modules/filters/modulestring.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/modulestring.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter [[module-name]modulestring[en-gb]] retrieve a module strings in a particular language
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.modulestring = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var s = $tw.modules.getModuleString(title,operator.operands[0] || "",operator.operands[1] || "");
|
||||
if(s !== null) {
|
||||
results.push(s);
|
||||
}
|
||||
});
|
||||
results.sort();
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -17,13 +17,9 @@ Export our filter function
|
||||
*/
|
||||
exports.range = function(source,operator,options) {
|
||||
var results = [];
|
||||
// For backwards compatibility, if there is only one operand, try to split it using one of the delimiters
|
||||
var parts = operator.operands || [];
|
||||
if(parts.length === 1) {
|
||||
parts = operator.operand.split(/[,:;]/g);
|
||||
}
|
||||
// Process the parts
|
||||
var beg, end, inc, i, fixed = 0;
|
||||
// Split the operand into numbers delimited by these symbols
|
||||
var parts = operator.operand.split(/[,:;]/g),
|
||||
beg, end, inc, i, fixed = 0;
|
||||
for (i=0; i<parts.length; i++) {
|
||||
// Validate real number
|
||||
if(!/^\s*[+-]?((\d+(\.\d*)?)|(\.\d+))\s*$/.test(parts[i])) {
|
||||
|
||||
@@ -119,7 +119,7 @@ exports["search-replace"] = function(source,operator,options) {
|
||||
var results = [],
|
||||
suffixes = operator.suffixes || [],
|
||||
flagSuffix = (suffixes[0] ? (suffixes[0][0] || "") : ""),
|
||||
flags = (flagSuffix.indexOf("g") !== -1 ? "g" : "") + (flagSuffix.indexOf("i") !== -1 ? "i" : "") + (flagSuffix.indexOf("m") !== -1 ? "m" : ""),
|
||||
flags = (flagSuffix.indexOf("g") !== -1 ? "g" : "") + (flagSuffix.indexOf("i") !== -1 ? "i" : ""),
|
||||
isRegExp = (suffixes[1] && suffixes[1][0] === "regexp") ? true : false,
|
||||
searchTerm,
|
||||
regExp;
|
||||
|
||||
@@ -16,13 +16,20 @@ Filter operator returning all the selected tiddlers that are untagged
|
||||
Export our filter function
|
||||
*/
|
||||
exports.untagged = function(source,operator,options) {
|
||||
var results = [],
|
||||
expected = (operator.prefix === "!");
|
||||
source(function(tiddler,title) {
|
||||
if((tiddler && $tw.utils.isArray(tiddler.fields.tags) && tiddler.fields.tags.length > 0) === expected) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
var results = [];
|
||||
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 {
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
181
core/modules/publisher-handler.js
Normal file
181
core/modules/publisher-handler.js
Normal file
@@ -0,0 +1,181 @@
|
||||
/*\
|
||||
title: $:/core/modules/publisherhandler.js
|
||||
type: application/javascript
|
||||
module-type: global
|
||||
|
||||
The publisher manages publishing extracts of wikis as external files
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var PUBLISHING_MODAL_TITLE = "$:/language/Publishing/Modal";
|
||||
|
||||
/*
|
||||
Instantiate the publisher manager with the following options
|
||||
wiki: wiki object to be used
|
||||
commander: commander object to be used for output
|
||||
*/
|
||||
function PublisherHandler(options) {
|
||||
this.wiki = options.wiki;
|
||||
this.commander = options.commander;
|
||||
}
|
||||
|
||||
/*
|
||||
Publish a job
|
||||
|
||||
jobTitle: title of tiddler containing details of the job
|
||||
callback: completion callback invoked callback(err)
|
||||
options: Include:
|
||||
|
||||
commander: commander object associated with publishing under Node.js
|
||||
variables: hashmap of variables to be passed to renderings
|
||||
*/
|
||||
PublisherHandler.prototype.publish = function(jobTitle,callback,options) {
|
||||
if(jobTitle) {
|
||||
var job = new PublishingJob(jobTitle,this,options);
|
||||
job.publish(callback);
|
||||
}
|
||||
};
|
||||
|
||||
function PublishingJob(jobTitle,publisherHandler,options) {
|
||||
options = options || {};
|
||||
// Save params
|
||||
this.jobTitle = jobTitle;
|
||||
this.publisherHandler = publisherHandler;
|
||||
this.commander = options.commander;
|
||||
this.publishVariables = options.variables || Object.create(null);
|
||||
}
|
||||
|
||||
/*
|
||||
Start publishing
|
||||
*/
|
||||
PublishingJob.prototype.publish = function(callback) {
|
||||
var self = this;
|
||||
// Get the job tiddler and check it is enabled
|
||||
this.jobTiddler = this.publisherHandler.wiki.getTiddler(this.jobTitle);
|
||||
if(this.jobTiddler && this.jobTiddler.fields.enabled === "yes") {
|
||||
// Get the list of tiddlers to be exported, defaulting to all non-system tiddlers
|
||||
this.exportList = this.publisherHandler.wiki.filterTiddlers(this.jobTiddler.fields["export-filter"] || "[!is[system]]");
|
||||
// Get publisher
|
||||
this.publisher = this.getPublisher(this.jobTiddler.fields.publisher);
|
||||
if(this.publisher) {
|
||||
// Get the sitemap
|
||||
this.sitemap = new $tw.Sitemap(this.jobTiddler.fields.sitemap,{
|
||||
wiki: this.publisherHandler.wiki,
|
||||
variables: this.publishVariables
|
||||
});
|
||||
this.sitemap.load();
|
||||
// Get the output operations
|
||||
this.operations = this.sitemap.getAllFileDetails(this.exportList);
|
||||
// Display the progress modal
|
||||
if($tw.modal) {
|
||||
this.progressModal = $tw.modal.display(PUBLISHING_MODAL_TITLE,{
|
||||
progress: true,
|
||||
variables: {
|
||||
currentTiddler: this.jobTitle,
|
||||
totalFiles: this.operations.length + ""
|
||||
},
|
||||
onclose: function(event) {
|
||||
if(event !== self) {
|
||||
// The modal was closed other than by us programmatically
|
||||
self.isCancelled = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// Send the operations to the publisher
|
||||
this.executeOperations(function(err) {
|
||||
if(self.progressModal) {
|
||||
self.progressModal.closeHandler(self);
|
||||
}
|
||||
callback(err);
|
||||
});
|
||||
} else {
|
||||
return callback("Unrecognised publisher");
|
||||
}
|
||||
} else {
|
||||
return callback("Missing or disabled job tiddler");
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Instantiate the required publisher object
|
||||
*/
|
||||
PublishingJob.prototype.getPublisher = function(publisherName) {
|
||||
var publisher;
|
||||
$tw.modules.forEachModuleOfType("publisher",function(title,module) {
|
||||
if(module.name === publisherName) {
|
||||
publisher = module;
|
||||
}
|
||||
});
|
||||
return publisher && publisher.create(this.jobTiddler.fields,this.publisherHandler,this);
|
||||
};
|
||||
|
||||
/*
|
||||
Execute the operations for this job
|
||||
*/
|
||||
PublishingJob.prototype.executeOperations = function(callback) {
|
||||
var self = this,
|
||||
report = {overwrites: []},
|
||||
nextOperation = 0,
|
||||
performNextOperation = function() {
|
||||
// Check for having been cancelled
|
||||
if(self.isCancelled) {
|
||||
if(self.publisher.publishCancel) {
|
||||
self.publisher.publishCancel();
|
||||
}
|
||||
return callback("CANCELLED");
|
||||
}
|
||||
// Update progress
|
||||
if(self.progressModal) {
|
||||
self.progressModal.setProgress(nextOperation,self.operations.length);
|
||||
}
|
||||
// Check for having finished
|
||||
if(nextOperation >= self.operations.length) {
|
||||
$tw.utils.nextTick(function() {
|
||||
self.publisher.publishEnd(callback);
|
||||
});
|
||||
} else {
|
||||
// Execute this operation
|
||||
var fileDetails = self.operations[nextOperation]();
|
||||
nextOperation += 1;
|
||||
self.publisher.publishFile(fileDetails,function() {
|
||||
$tw.utils.nextTick(performNextOperation);
|
||||
});
|
||||
}
|
||||
};
|
||||
// Tell the publisher to start, and get back an array of the existing paths
|
||||
self.publisher.publishStart(function(existingPaths) {
|
||||
var paths = {};
|
||||
$tw.utils.each(self.operations,function(operation) {
|
||||
if(operation.path in paths) {
|
||||
report.overwrites.push(operation.path);
|
||||
}
|
||||
paths[operation.path] = true;
|
||||
});
|
||||
// Run the operations
|
||||
performNextOperation();
|
||||
});
|
||||
};
|
||||
|
||||
PublishingJob.prototype.saveReport = function(report) {
|
||||
// Create the report tiddler
|
||||
var reportTitle = this.wiki.generateNewTitle("$:/temp/publish-report");
|
||||
$tw.wiki.addTiddler({
|
||||
title: reportTitle,
|
||||
text: "* " + report.overwrites.join("\n* ")
|
||||
});
|
||||
// Add the report tiddler title to the list field of the publisher parameters tiddler
|
||||
var paramsTiddler = $tw.wiki.getTiddler(this.publisherParamsTitle),
|
||||
list = (paramsTiddler.fields.list || []).slice(0);
|
||||
list.unshift(reportTitle);
|
||||
$tw.wiki.addTiddler(new $tw.Tiddler(paramsTiddler,{list: list}));
|
||||
};
|
||||
|
||||
exports.PublisherHandler = PublisherHandler;
|
||||
|
||||
})();
|
||||
52
core/modules/publishers/filesystem.js
Normal file
52
core/modules/publishers/filesystem.js
Normal file
@@ -0,0 +1,52 @@
|
||||
/*\
|
||||
title: $:/core/modules/publishers/filesystem.js
|
||||
type: application/javascript
|
||||
module-type: publisher
|
||||
|
||||
Handles publishing to the Node.js filesystem
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.name = "filesystem";
|
||||
|
||||
exports.create = function(params,publisherHandler,publishingJob) {
|
||||
return new FileSystemPublisher(params,publisherHandler,publishingJob);
|
||||
};
|
||||
|
||||
function FileSystemPublisher(params,publisherHandler,publishingJob) {
|
||||
this.params = params;
|
||||
this.publisherHandler = publisherHandler;
|
||||
this.publishingJob = publishingJob;
|
||||
};
|
||||
|
||||
FileSystemPublisher.prototype.publishStart = function(callback) {
|
||||
console.log("publishStart");
|
||||
// Returns a list of the previously published files
|
||||
callback([]);
|
||||
};
|
||||
|
||||
FileSystemPublisher.prototype.publishFile = function(item,callback) {
|
||||
var fs = require("fs"),
|
||||
path = require("path"),
|
||||
filepath = path.resolve(this.publishingJob.commander.outputPath,item.path);
|
||||
$tw.utils.createFileDirectories(filepath);
|
||||
fs.writeFile(filepath,item.text,item.isBase64 ? "base64" : "utf8",function(err) {
|
||||
if(err) {
|
||||
console.log("File writing error",err)
|
||||
}
|
||||
callback(err);
|
||||
});
|
||||
};
|
||||
|
||||
FileSystemPublisher.prototype.publishEnd = function(callback) {
|
||||
console.log("publishEnd");
|
||||
callback(null);
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -42,7 +42,7 @@ AndTidWiki.prototype.save = function(text,method,callback,options) {
|
||||
window.twi.saveWiki(text);
|
||||
} else {
|
||||
// Get the pathname of this document
|
||||
var pathname = $tw.utils.decodeURIComponentSafe(document.location.toString().split("#")[0]);
|
||||
var pathname = decodeURIComponent(document.location.toString().split("#")[0]);
|
||||
// Strip the file://
|
||||
if(pathname.indexOf("file://") === 0) {
|
||||
pathname = pathname.substr(7);
|
||||
|
||||
@@ -26,7 +26,7 @@ DownloadSaver.prototype.save = function(text,method,callback,options) {
|
||||
var p = document.location.pathname.lastIndexOf("/");
|
||||
if(p !== -1) {
|
||||
// We decode the pathname because document.location is URL encoded by the browser
|
||||
filename = $tw.utils.decodeURIComponentSafe(document.location.pathname.substr(p+1));
|
||||
filename = decodeURIComponent(document.location.pathname.substr(p+1));
|
||||
}
|
||||
}
|
||||
if(!filename) {
|
||||
|
||||
@@ -72,7 +72,7 @@ GiteaSaver.prototype.save = function(text,method,callback) {
|
||||
}
|
||||
}
|
||||
var data = {
|
||||
message: $tw.language.getString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||
message: $tw.language.getRawString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||
content: $tw.utils.base64Encode(text),
|
||||
sha: sha
|
||||
};
|
||||
|
||||
@@ -69,7 +69,7 @@ GitHubSaver.prototype.save = function(text,method,callback) {
|
||||
});
|
||||
}
|
||||
var data = {
|
||||
message: $tw.language.getString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||
message: $tw.language.getRawString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||
content: $tw.utils.base64Encode(text),
|
||||
branch: branch,
|
||||
sha: sha
|
||||
|
||||
@@ -67,7 +67,7 @@ GitLabSaver.prototype.save = function(text,method,callback) {
|
||||
});
|
||||
}
|
||||
var data = {
|
||||
commit_message: $tw.language.getString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||
commit_message: $tw.language.getRawString("ControlPanel/Saving/GitService/CommitMessage"),
|
||||
content: text,
|
||||
branch: branch,
|
||||
sha: sha
|
||||
|
||||
@@ -43,7 +43,7 @@ TiddlyFoxSaver.prototype.save = function(text,method,callback) {
|
||||
}
|
||||
// Create the message element and put it in the message box
|
||||
var message = document.createElement("div");
|
||||
message.setAttribute("data-tiddlyfox-path",$tw.utils.decodeURIComponentSafe(pathname));
|
||||
message.setAttribute("data-tiddlyfox-path",decodeURIComponent(pathname));
|
||||
message.setAttribute("data-tiddlyfox-content",text);
|
||||
messageBox.appendChild(message);
|
||||
// Add an event handler for when the file has been saved
|
||||
|
||||
@@ -21,7 +21,7 @@ TWEditSaver.prototype.save = function(text,method,callback) {
|
||||
return false;
|
||||
}
|
||||
// Get the pathname of this document
|
||||
var pathname = $tw.utils.decodeURIComponentSafe(document.location.pathname);
|
||||
var pathname = decodeURIComponent(document.location.pathname);
|
||||
// Strip any query or location part
|
||||
var p = pathname.indexOf("?");
|
||||
if(p !== -1) {
|
||||
|
||||
@@ -17,7 +17,7 @@ exports.method = "DELETE";
|
||||
exports.path = /^\/bags\/default\/tiddlers\/(.+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]);
|
||||
var title = decodeURIComponent(state.params[0]);
|
||||
state.wiki.deleteTiddler(title);
|
||||
response.writeHead(204, "OK", {
|
||||
"Content-Type": "text/plain"
|
||||
|
||||
@@ -20,29 +20,22 @@ exports.handler = function(request,response,state) {
|
||||
var path = require("path"),
|
||||
fs = require("fs"),
|
||||
util = require("util"),
|
||||
suppliedFilename = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
baseFilename = path.resolve(state.boot.wikiPath,"files"),
|
||||
filename = path.resolve(baseFilename,suppliedFilename),
|
||||
suppliedFilename = decodeURIComponent(state.params[0]),
|
||||
filename = path.resolve(state.boot.wikiPath,"files",suppliedFilename),
|
||||
extension = path.extname(filename);
|
||||
// Check that the filename is inside the wiki files folder
|
||||
if(path.relative(baseFilename,filename).indexOf("..") !== 0) {
|
||||
// Send the file
|
||||
fs.readFile(filename,function(err,content) {
|
||||
var status,content,type = "text/plain";
|
||||
if(err) {
|
||||
console.log("Error accessing file " + filename + ": " + err.toString());
|
||||
status = 404;
|
||||
content = "File '" + suppliedFilename + "' not found";
|
||||
} else {
|
||||
status = 200;
|
||||
content = content;
|
||||
type = ($tw.config.fileExtensionInfo[extension] ? $tw.config.fileExtensionInfo[extension].type : "application/octet-stream");
|
||||
}
|
||||
state.sendResponse(status,{"Content-Type": type},content);
|
||||
});
|
||||
} else {
|
||||
state.sendResponse(404,{"Content-Type": "text/plain"},"File '" + suppliedFilename + "' not found");
|
||||
}
|
||||
fs.readFile(filename,function(err,content) {
|
||||
var status,content,type = "text/plain";
|
||||
if(err) {
|
||||
console.log("Error accessing file " + filename + ": " + err.toString());
|
||||
status = 404;
|
||||
content = "File '" + suppliedFilename + "' not found";
|
||||
} else {
|
||||
status = 200;
|
||||
content = content;
|
||||
type = ($tw.config.fileExtensionInfo[extension] ? $tw.config.fileExtensionInfo[extension].type : "application/octet-stream");
|
||||
}
|
||||
state.sendResponse(status,{"Content-Type": type},content);
|
||||
});
|
||||
};
|
||||
|
||||
}());
|
||||
|
||||
@@ -14,7 +14,7 @@ GET /
|
||||
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/$/;
|
||||
exports.path = /^\/index.html$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var text = state.wiki.renderTiddler(state.server.get("root-render-type"),state.server.get("root-tiddler")),
|
||||
|
||||
@@ -21,6 +21,7 @@ exports.handler = function(request,response,state) {
|
||||
username: state.authenticatedUsername || state.server.get("anon-username") || "",
|
||||
anonymous: !state.authenticatedUsername,
|
||||
read_only: !state.server.isAuthorized("writers",state.authenticatedUsername),
|
||||
sse_enabled: state.server.get("sse-enabled") === "yes",
|
||||
space: {
|
||||
recipe: "default"
|
||||
},
|
||||
|
||||
@@ -17,7 +17,7 @@ exports.method = "GET";
|
||||
exports.path = /^\/([^\/]+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
var title = decodeURIComponent(state.params[0]),
|
||||
tiddler = state.wiki.getTiddler(title);
|
||||
if(tiddler) {
|
||||
var renderType = tiddler.getFieldString("_render_type"),
|
||||
|
||||
@@ -17,7 +17,7 @@ exports.method = "GET";
|
||||
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
var title = decodeURIComponent(state.params[0]),
|
||||
tiddler = state.wiki.getTiddler(title),
|
||||
tiddlerFields = {},
|
||||
knownFields = [
|
||||
|
||||
@@ -17,7 +17,7 @@ exports.method = "PUT";
|
||||
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
var title = decodeURIComponent(state.params[0]),
|
||||
fields = JSON.parse(state.data);
|
||||
// Pull up any subfields in the `fields` object
|
||||
if(fields.fields) {
|
||||
|
||||
70
core/modules/server/server-sent-events.js
Normal file
70
core/modules/server/server-sent-events.js
Normal file
@@ -0,0 +1,70 @@
|
||||
/*\
|
||||
title: $:/core/modules/server/server-sent-events.js
|
||||
type: application/javascript
|
||||
module-type: library
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
parameters:
|
||||
prefix - usually the plugin path, such as `plugins/tiddlywiki/tiddlyweb`. The
|
||||
route will match `/events/${prefix}` exactly.
|
||||
|
||||
handler - a function that will be called each time a request comes in with the
|
||||
request and state from the route and an emit function to call.
|
||||
*/
|
||||
|
||||
var ServerSentEvents = function ServerSentEvents(prefix, handler) {
|
||||
this.handler = handler;
|
||||
this.prefix = prefix;
|
||||
};
|
||||
|
||||
ServerSentEvents.prototype.getExports = function() {
|
||||
return {
|
||||
bodyFormat: "stream",
|
||||
method: "GET",
|
||||
path: new RegExp("^/events/" + this.prefix + "$"),
|
||||
handler: this.handleEventRequest.bind(this)
|
||||
};
|
||||
};
|
||||
|
||||
ServerSentEvents.prototype.handleEventRequest = function(request,response,state) {
|
||||
if(ServerSentEvents.prototype.isEventStreamRequest(request)) {
|
||||
response.writeHead(200, {
|
||||
"Content-Type": "text/event-stream",
|
||||
"Cache-Control": "no-cache",
|
||||
"Connection": "keep-alive"
|
||||
});
|
||||
this.handler(request,state,this.emit.bind(this,response),this.end.bind(this,response));
|
||||
} else {
|
||||
response.writeHead(406,"Not Acceptable",{});
|
||||
response.end();
|
||||
}
|
||||
};
|
||||
|
||||
ServerSentEvents.prototype.isEventStreamRequest = function(request) {
|
||||
return request.headers.accept &&
|
||||
request.headers.accept.match(/^text\/event-stream/);
|
||||
};
|
||||
|
||||
ServerSentEvents.prototype.emit = function(response,event,data) {
|
||||
if(typeof event !== "string" || event.indexOf("\n") !== -1) {
|
||||
throw new Error("Type must be a single-line string");
|
||||
}
|
||||
if(typeof data !== "string" || data.indexOf("\n") !== -1) {
|
||||
throw new Error("Data must be a single-line string");
|
||||
}
|
||||
response.write("event: " + event + "\ndata: " + data + "\n\n", "utf8");
|
||||
};
|
||||
|
||||
ServerSentEvents.prototype.end = function(response) {
|
||||
response.end();
|
||||
};
|
||||
|
||||
exports.ServerSentEvents = ServerSentEvents;
|
||||
|
||||
})();
|
||||
@@ -63,10 +63,7 @@ function Server(options) {
|
||||
self.addAuthenticator(authenticatorDefinition.AuthenticatorClass);
|
||||
});
|
||||
// Load route handlers
|
||||
$tw.modules.forEachModuleOfType("route", function(title,routeDefinition) {
|
||||
// console.log("Loading server route " + title);
|
||||
self.addRoute(routeDefinition);
|
||||
});
|
||||
this.addRouteHandlers();
|
||||
// Initialise the http vs https
|
||||
this.listenOptions = null;
|
||||
this.protocol = "http";
|
||||
@@ -182,11 +179,43 @@ Server.prototype.addAuthenticator = function(AuthenticatorClass) {
|
||||
}
|
||||
};
|
||||
|
||||
Server.prototype.findMatchingRoute = function(request,state) {
|
||||
Server.prototype.addRouteHandlers = function() {
|
||||
var self = this;
|
||||
// Load route handlers from sitemap if present, or just load all route modules
|
||||
if(this.variables.sitemap) {
|
||||
this.sitemap = new $tw.Sitemap(this.variables.sitemap,{
|
||||
wiki: this.wiki,
|
||||
variables: {}
|
||||
});
|
||||
this.sitemap.load();
|
||||
$tw.utils.each(this.sitemap.getServerRoutes(),function(routeInfo) {
|
||||
self.addRoute({
|
||||
method: "GET",
|
||||
path: routeInfo.regexp,
|
||||
handler: function(request,response,state) {
|
||||
var fileDetails = routeInfo.handler(state.params);
|
||||
if(fileDetails) {
|
||||
response.writeHead(200, {"Content-Type": fileDetails.type});
|
||||
response.end(fileDetails.text,fileDetails.isBase64 ? "base64" : "utf8");
|
||||
} else {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
$tw.modules.forEachModuleOfType("route",function(title,routeDefinition) {
|
||||
self.addRoute(routeDefinition);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Server.prototype.findMatchingRoute = function(request,state,options) {
|
||||
options = options || {};
|
||||
for(var t=0; t<this.routes.length; t++) {
|
||||
var potentialRoute = this.routes[t],
|
||||
pathRegExp = potentialRoute.path,
|
||||
pathname = state.urlInfo.pathname,
|
||||
pathname = options.pathname || state.urlInfo.pathname,
|
||||
match;
|
||||
if(state.pathPrefix) {
|
||||
if(pathname.substr(0,state.pathPrefix.length) === state.pathPrefix) {
|
||||
@@ -263,6 +292,15 @@ Server.prototype.requestHandler = function(request,response,options) {
|
||||
}
|
||||
// Find the route that matches this path
|
||||
var route = self.findMatchingRoute(request,state);
|
||||
if(!route) {
|
||||
// Try with the default document
|
||||
var defaultDocumentPathname = state.urlInfo.pathname;
|
||||
if(defaultDocumentPathname.substr(-1) !== "/") {
|
||||
defaultDocumentPathname = defaultDocumentPathname + "/";
|
||||
}
|
||||
defaultDocumentPathname = defaultDocumentPathname + "index.html";
|
||||
route = self.findMatchingRoute(request,state,{pathname: defaultDocumentPathname});
|
||||
}
|
||||
// Optionally output debug info
|
||||
if(self.get("debug-level") !== "none") {
|
||||
console.log("Request path:",JSON.stringify(state.urlInfo));
|
||||
|
||||
236
core/modules/sitemap.js
Normal file
236
core/modules/sitemap.js
Normal file
@@ -0,0 +1,236 @@
|
||||
/*\
|
||||
title: $:/core/modules/sitemap.js
|
||||
type: application/javascript
|
||||
module-type: global
|
||||
|
||||
Sitemaps are used for static publishing and web serving
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
function Sitemap(sitemapTitle,options) {
|
||||
options = options || {};
|
||||
this.sitemapTitle = sitemapTitle;
|
||||
this.wiki = options.wiki;
|
||||
this.routes = [];
|
||||
this.variables = $tw.utils.extend({},options.variables);
|
||||
}
|
||||
|
||||
Sitemap.prototype.load = function(sitemapTitle) {
|
||||
var self = this;
|
||||
// Get the sitemap
|
||||
var sitemapTiddler = this.wiki.getTiddler(this.sitemapTitle);
|
||||
if(sitemapTiddler) {
|
||||
// Collect each route
|
||||
$tw.utils.each(sitemapTiddler.fields.list,function(routeTitle) {
|
||||
var routeTiddler = self.wiki.getTiddler(routeTitle);
|
||||
if(routeTiddler) {
|
||||
// Convert the path into a regexp and an array of {field:,function:} for each capture group
|
||||
var regexpurgatedParameterisedPath = self.regexpurgateParameterisedPath(routeTiddler.fields["route-path"]);
|
||||
self.routes.push({
|
||||
title: routeTitle,
|
||||
params: routeTiddler.getFieldStrings({prefix: "route-"}),
|
||||
variables: routeTiddler.getFieldStrings({prefix: "var-"}),
|
||||
regexp: regexpurgatedParameterisedPath.regexp,
|
||||
captureGroups: regexpurgatedParameterisedPath.captureGroups
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Sitemap.prototype.renderRoute = function(title,route) {
|
||||
var tiddler = this.wiki.getTiddler(title);
|
||||
switch(route.params.type) {
|
||||
case "raw":
|
||||
return {
|
||||
path: this.resolveParameterisedPath(route.params.path,title),
|
||||
text: tiddler.fields.text || "",
|
||||
type: tiddler.fields.type || "",
|
||||
isBase64: ($tw.config.contentTypeInfo[tiddler.fields.type] || {}).encoding === "base64"
|
||||
};
|
||||
break;
|
||||
case "render":
|
||||
var parser = {
|
||||
tree: [
|
||||
{
|
||||
"type": "importvariables",
|
||||
"attributes": {
|
||||
"tiddler": {
|
||||
"name": "tiddler",
|
||||
"type": "string",
|
||||
"value": this.sitemapTitle,
|
||||
}
|
||||
},
|
||||
"tag": "$importvariables",
|
||||
"isBlock": false,
|
||||
"children": [
|
||||
{
|
||||
"type": "importvariables",
|
||||
"attributes": {
|
||||
"tiddler": {
|
||||
"name": "tiddler",
|
||||
"type": "string",
|
||||
"value": route.title,
|
||||
}
|
||||
},
|
||||
"tag": "$importvariables",
|
||||
"isBlock": false,
|
||||
"children": this.wiki.parseTiddler(route.params.template,{parseAsInline: true}).tree
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
widgetNode = this.wiki.makeWidget(parser,{
|
||||
variables: $tw.utils.extend({},this.variables,{currentTiddler: title})
|
||||
}),
|
||||
container = $tw.fakeDocument.createElement("div");
|
||||
widgetNode.render(container,null);
|
||||
return {
|
||||
path: this.resolveParameterisedPath(route.params.path,title),
|
||||
text: container.textContent,
|
||||
type: route.params["output-type"] || "text/html"
|
||||
};
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Returns an array of functions that return {path:,text:,type:,isBase64:} for each path
|
||||
*/
|
||||
Sitemap.prototype.getAllFileDetails = function(exportTiddlers) {
|
||||
var self = this,
|
||||
output = [];
|
||||
$tw.utils.each(this.routes,function(route) {
|
||||
var routeFilter = route.params["tiddler-filter"] || "DUMMY_RESULT", // If no filter is provided, use a dummy filter that returns a single result
|
||||
routeTiddlers = self.wiki.filterTiddlers(routeFilter,null,self.wiki.makeTiddlerIterator(exportTiddlers));
|
||||
$tw.utils.each(routeTiddlers,function(title) {
|
||||
output.push(self.renderRoute.bind(self,title,route));
|
||||
});
|
||||
});
|
||||
return output;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Returns an array of server routes {regexp:, handler:}
|
||||
*/
|
||||
Sitemap.prototype.getServerRoutes = function() {
|
||||
var self = this,
|
||||
output = [];
|
||||
$tw.utils.each(this.routes,function(route) {
|
||||
output.push({
|
||||
regexp: route.regexp,
|
||||
handler: function(params) {
|
||||
// Locate the tiddler identified by the capture groups, if any
|
||||
var title = null,
|
||||
nextParam = 0;
|
||||
$tw.utils.each(route.captureGroups,function(captureGroup) {
|
||||
var param = params[nextParam++];
|
||||
if(captureGroup.field === "title") {
|
||||
switch(captureGroup.function) {
|
||||
case "slugify":
|
||||
var titles = self.wiki.unslugify(param);
|
||||
if(titles && titles.length > 0) {
|
||||
title = titles[0];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
// Check that the tiddler passes the route filter
|
||||
if(route.params["tiddler-filter"]) {
|
||||
if(!title) {
|
||||
return null;
|
||||
}
|
||||
var routeTiddlers = self.wiki.filterTiddlers(route.params["tiddler-filter"],null,self.wiki.makeTiddlerIterator([title]));
|
||||
if(routeTiddlers.indexOf(title) === -1) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// Return the rendering or raw tiddler
|
||||
return self.renderRoute(title,route);
|
||||
}
|
||||
});
|
||||
});
|
||||
return output;
|
||||
};
|
||||
|
||||
/*
|
||||
Apply a tiddler to a parameterised path to create a usable path
|
||||
*/
|
||||
Sitemap.prototype.resolveParameterisedPath = function(parameterisedPath,title) {
|
||||
var self = this;
|
||||
// Split the path on $*_*$ markers
|
||||
var tiddler = this.wiki.getTiddler(title),
|
||||
output = [];
|
||||
$tw.utils.each(parameterisedPath.split(/(\$[a-z_]+\$)/),function(part) {
|
||||
var match = part.match(/\$([a-z]+)_([a-z]+)\$/);
|
||||
if(match) {
|
||||
var value;
|
||||
// Get the base value
|
||||
switch(match[1]) {
|
||||
case "uri":
|
||||
case "title":
|
||||
value = title;
|
||||
break;
|
||||
case "type":
|
||||
value = tiddler.fields.type || "text/vnd.tiddlywiki";
|
||||
break;
|
||||
}
|
||||
// Apply the encoding function
|
||||
switch(match[2]) {
|
||||
case "encoded":
|
||||
value = encodeURIComponent(value);
|
||||
break;
|
||||
case "doubleencoded":
|
||||
value = encodeURIComponent(encodeURIComponent(value));
|
||||
break;
|
||||
case "slugify":
|
||||
value = self.wiki.slugify(value);
|
||||
break;
|
||||
case "extension":
|
||||
value = ($tw.config.contentTypeInfo[value] || {extension: "."}).extension.slice(1);
|
||||
break;
|
||||
}
|
||||
output.push(value);
|
||||
} else {
|
||||
output.push(part);
|
||||
}
|
||||
});
|
||||
return output.join("");
|
||||
};
|
||||
|
||||
/*
|
||||
// Convert the path into a regexp and an array of {field:,function:} for each capture group
|
||||
*/
|
||||
Sitemap.prototype.regexpurgateParameterisedPath = function(parameterisedPath) {
|
||||
var regexpParts = ["\\/"],
|
||||
captureGroups = [];
|
||||
$tw.utils.each(parameterisedPath.split(/(\$[a-z_]+\$)/),function(part) {
|
||||
var match = part.match(/\$([a-z]+)_([a-z]+)\$/);
|
||||
if(match) {
|
||||
regexpParts.push("(.+)");
|
||||
captureGroups.push({
|
||||
field: match[1],
|
||||
function: match[2]
|
||||
});
|
||||
} else {
|
||||
regexpParts.push($tw.utils.escapeRegExp(part));
|
||||
}
|
||||
});
|
||||
return {
|
||||
regexp: new RegExp("^" + regexpParts.join("") + "$"),
|
||||
captureGroups: captureGroups
|
||||
};
|
||||
};
|
||||
|
||||
exports.Sitemap = Sitemap;
|
||||
|
||||
})();
|
||||
|
||||
@@ -73,6 +73,12 @@ exports.startup = function() {
|
||||
}
|
||||
});
|
||||
}
|
||||
// Hook up events for the publisher handler
|
||||
$tw.rootWidget.addEventListener("tm-publish",function(event) {
|
||||
$tw.publisherHandler.publish(event.paramObject.job,function(err) {
|
||||
console.log("Finished publishing with result:",err);
|
||||
});
|
||||
});
|
||||
// If we're being viewed on a data: URI then give instructions for how to save
|
||||
if(document.location.protocol === "data:") {
|
||||
$tw.rootWidget.dispatchEvent({
|
||||
|
||||
@@ -129,6 +129,10 @@ exports.startup = function() {
|
||||
dirtyTracking: !$tw.syncadaptor,
|
||||
preloadDirty: $tw.boot.preloadDirty || []
|
||||
});
|
||||
// Install the publisher handler
|
||||
$tw.publisherHandler = new $tw.PublisherHandler({
|
||||
wiki: $tw.wiki
|
||||
});
|
||||
// Host-specific startup
|
||||
if($tw.browser) {
|
||||
// Install the popup manager
|
||||
|
||||
@@ -120,10 +120,10 @@ function openStartupTiddlers(options) {
|
||||
var hash = $tw.locationHash.substr(1),
|
||||
split = hash.indexOf(":");
|
||||
if(split === -1) {
|
||||
target = $tw.utils.decodeURIComponentSafe(hash.trim());
|
||||
target = decodeURIComponent(hash.trim());
|
||||
} else {
|
||||
target = $tw.utils.decodeURIComponentSafe(hash.substr(0,split).trim());
|
||||
storyFilter = $tw.utils.decodeURIComponentSafe(hash.substr(split + 1).trim());
|
||||
target = decodeURIComponent(hash.substr(0,split).trim());
|
||||
storyFilter = decodeURIComponent(hash.substr(split + 1).trim());
|
||||
}
|
||||
}
|
||||
// If the story wasn't specified use the current tiddlers or a blank story
|
||||
|
||||
@@ -20,6 +20,7 @@ Syncer.prototype.titleIsAnonymous = "$:/status/IsAnonymous";
|
||||
Syncer.prototype.titleIsReadOnly = "$:/status/IsReadOnly";
|
||||
Syncer.prototype.titleUserName = "$:/status/UserName";
|
||||
Syncer.prototype.titleSyncFilter = "$:/config/SyncFilter";
|
||||
Syncer.prototype.titleSyncDisablePolling = "$:/config/SyncDisablePolling";
|
||||
Syncer.prototype.titleSyncPollingInterval = "$:/config/SyncPollingInterval";
|
||||
Syncer.prototype.titleSyncDisableLazyLoading = "$:/config/SyncDisableLazyLoading";
|
||||
Syncer.prototype.titleSavedNotification = "$:/language/Notifications/Save/Done";
|
||||
@@ -89,7 +90,7 @@ function Syncer(options) {
|
||||
if(filteredChanges.length > 0) {
|
||||
self.processTaskQueue();
|
||||
} else {
|
||||
// Look for deletions of tiddlers we're already syncing
|
||||
// Look for deletions of tiddlers we're already syncing
|
||||
var outstandingDeletion = false
|
||||
$tw.utils.each(changes,function(change,title,object) {
|
||||
if(change.deleted && $tw.utils.hop(self.tiddlerInfo,title)) {
|
||||
@@ -121,7 +122,7 @@ function Syncer(options) {
|
||||
self.login(username,password,function() {});
|
||||
} else {
|
||||
// No username and password, so we display a prompt
|
||||
self.handleLoginEvent();
|
||||
self.handleLoginEvent();
|
||||
}
|
||||
});
|
||||
$tw.rootWidget.addEventListener("tm-logout",function() {
|
||||
@@ -138,7 +139,7 @@ function Syncer(options) {
|
||||
if(!this.disableUI && this.wiki.getTiddlerText(this.titleSyncDisableLazyLoading) !== "yes") {
|
||||
this.wiki.addEventListener("lazyLoad",function(title) {
|
||||
self.handleLazyLoadEvent(title);
|
||||
});
|
||||
});
|
||||
}
|
||||
// Get the login status
|
||||
this.getStatus(function(err,isLoggedIn) {
|
||||
@@ -173,8 +174,8 @@ Syncer.prototype.getTiddlerRevision = function(title) {
|
||||
if(this.syncadaptor && this.syncadaptor.getTiddlerRevision) {
|
||||
return this.syncadaptor.getTiddlerRevision(title);
|
||||
} else {
|
||||
return this.wiki.getTiddler(title).fields.revision;
|
||||
}
|
||||
return this.wiki.getTiddler(title).fields.revision;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -267,9 +268,9 @@ Syncer.prototype.getStatus = function(callback) {
|
||||
// Mark us as not logged in
|
||||
this.wiki.addTiddler({title: this.titleIsLoggedIn,text: "no"});
|
||||
// Get login status
|
||||
this.syncadaptor.getStatus(function(err,isLoggedIn,username,isReadOnly,isAnonymous) {
|
||||
this.syncadaptor.getStatus(function(err,isLoggedIn,username,isReadOnly,isAnonymous,isPollingDisabled) {
|
||||
if(err) {
|
||||
self.displayError("Get Status Error",err);
|
||||
self.logger.alert(err);
|
||||
} else {
|
||||
// Set the various status tiddlers
|
||||
self.wiki.addTiddler({title: self.titleIsReadOnly,text: isReadOnly ? "yes" : "no"});
|
||||
@@ -278,6 +279,9 @@ Syncer.prototype.getStatus = function(callback) {
|
||||
if(isLoggedIn) {
|
||||
self.wiki.addTiddler({title: self.titleUserName,text: username || ""});
|
||||
}
|
||||
if(isPollingDisabled) {
|
||||
self.wiki.addTiddler({title: self.titleSyncDisablePolling, text: "yes"});
|
||||
}
|
||||
}
|
||||
// Invoke the callback
|
||||
if(callback) {
|
||||
@@ -301,12 +305,15 @@ Syncer.prototype.syncFromServer = function() {
|
||||
}
|
||||
},
|
||||
triggerNextSync = function() {
|
||||
self.pollTimerId = setTimeout(function() {
|
||||
self.pollTimerId = null;
|
||||
self.syncFromServer.call(self);
|
||||
},self.pollTimerInterval);
|
||||
if(pollingEnabled) {
|
||||
self.pollTimerId = setTimeout(function() {
|
||||
self.pollTimerId = null;
|
||||
self.syncFromServer.call(self);
|
||||
},self.pollTimerInterval);
|
||||
}
|
||||
},
|
||||
syncSystemFromServer = (self.wiki.getTiddlerText("$:/config/SyncSystemTiddlersFromServer") === "yes" ? true : false);
|
||||
syncSystemFromServer = (self.wiki.getTiddlerText("$:/config/SyncSystemTiddlersFromServer") === "yes"),
|
||||
pollingEnabled = (self.wiki.getTiddlerText(self.titleSyncDisablePolling) !== "yes");
|
||||
if(this.syncadaptor && this.syncadaptor.getUpdatedTiddlers) {
|
||||
this.logger.log("Retrieving updated tiddler list");
|
||||
cancelNextSync();
|
||||
@@ -329,7 +336,7 @@ Syncer.prototype.syncFromServer = function() {
|
||||
});
|
||||
if(updates.modifications.length > 0 || updates.deletions.length > 0) {
|
||||
self.processTaskQueue();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if(this.syncadaptor && this.syncadaptor.getSkinnyTiddlers) {
|
||||
@@ -472,7 +479,7 @@ Syncer.prototype.handleLogoutEvent = function() {
|
||||
if(this.syncadaptor.logout) {
|
||||
this.syncadaptor.logout(function(err) {
|
||||
if(err) {
|
||||
self.displayError("Logout Error",err);
|
||||
self.logger.alert(err);
|
||||
} else {
|
||||
self.getStatus();
|
||||
}
|
||||
@@ -509,7 +516,7 @@ Syncer.prototype.processTaskQueue = function() {
|
||||
} else {
|
||||
self.updateDirtyStatus();
|
||||
// Process the next task
|
||||
self.processTaskQueue.call(self);
|
||||
self.processTaskQueue.call(self);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -517,11 +524,11 @@ Syncer.prototype.processTaskQueue = function() {
|
||||
this.updateDirtyStatus();
|
||||
// And trigger a timeout if there is a pending task
|
||||
if(task === true) {
|
||||
this.triggerTimeout();
|
||||
this.triggerTimeout();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.updateDirtyStatus();
|
||||
this.updateDirtyStatus();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -555,7 +562,7 @@ Syncer.prototype.chooseNextTask = function() {
|
||||
isReadyToSave = !tiddlerInfo || !tiddlerInfo.timestampLastSaved || tiddlerInfo.timestampLastSaved < thresholdLastSaved;
|
||||
if(hasChanged) {
|
||||
if(isReadyToSave) {
|
||||
return new SaveTiddlerTask(this,title);
|
||||
return new SaveTiddlerTask(this,title);
|
||||
} else {
|
||||
havePending = true;
|
||||
}
|
||||
|
||||
@@ -54,15 +54,27 @@ exports.getFieldList = function(field) {
|
||||
/*
|
||||
Get all the fields as a hashmap of strings. Options:
|
||||
exclude: an array of field names to exclude
|
||||
prefix: an optional field name prefix. Only fields with the prefix are included, and the prefix is stripped from the name
|
||||
*/
|
||||
exports.getFieldStrings = function(options) {
|
||||
options = options || {};
|
||||
var exclude = options.exclude || [];
|
||||
var fields = {};
|
||||
for(var field in this.fields) {
|
||||
if($tw.utils.hop(this.fields,field)) {
|
||||
if(exclude.indexOf(field) === -1) {
|
||||
fields[field] = this.getFieldString(field);
|
||||
var exclude = options.exclude || [],
|
||||
fields = {},
|
||||
field;
|
||||
if(options.prefix) {
|
||||
for(field in this.fields) {
|
||||
if($tw.utils.hop(this.fields,field)) {
|
||||
if(exclude.indexOf(field) === -1 && field.substring(0,options.prefix.length) === options.prefix) {
|
||||
fields[field.substring(options.prefix.length)] = this.getFieldString(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(field in this.fields) {
|
||||
if($tw.utils.hop(this.fields,field)) {
|
||||
if(exclude.indexOf(field) === -1) {
|
||||
fields[field] = this.getFieldString(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ Browser data transfer utilities, used with the clipboard and drag and drop
|
||||
Options:
|
||||
|
||||
domNode: dom node to make draggable
|
||||
dragImageType: "pill", "blank" or "dom" (the default)
|
||||
dragImageType: "pill" or "dom"
|
||||
dragTiddlerFn: optional function to retrieve the title of tiddler to drag
|
||||
dragFilterFn: optional function to retreive the filter defining a list of tiddlers to drag
|
||||
widget: widget to use as the contect for the filter
|
||||
@@ -73,9 +73,6 @@ exports.makeDraggable = function(options) {
|
||||
if(dataTransfer.setDragImage) {
|
||||
if(dragImageType === "pill") {
|
||||
dataTransfer.setDragImage(dragImage.firstChild,-16,-16);
|
||||
} else if (dragImageType === "blank") {
|
||||
dragImage.removeChild(dragImage.firstChild);
|
||||
dataTransfer.setDragImage(dragImage,0,0);
|
||||
} else {
|
||||
var r = domNode.getBoundingClientRect();
|
||||
dataTransfer.setDragImage(domNode,event.clientX-r.left,event.clientY-r.top);
|
||||
@@ -167,7 +164,7 @@ var importDataTypes = [
|
||||
}},
|
||||
{type: "URL", IECompatible: true, toTiddlerFieldsArray: function(data,fallbackTitle) {
|
||||
// Check for tiddler data URI
|
||||
var match = $tw.utils.decodeURIComponentSafe(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
|
||||
var match = decodeURIComponent(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
|
||||
if(match) {
|
||||
return parseJSONTiddlers(match[1],fallbackTitle);
|
||||
} else {
|
||||
@@ -176,7 +173,7 @@ var importDataTypes = [
|
||||
}},
|
||||
{type: "text/x-moz-url", IECompatible: false, toTiddlerFieldsArray: function(data,fallbackTitle) {
|
||||
// Check for tiddler data URI
|
||||
var match = $tw.utils.decodeURIComponentSafe(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
|
||||
var match = decodeURIComponent(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
|
||||
if(match) {
|
||||
return parseJSONTiddlers(match[1],fallbackTitle);
|
||||
} else {
|
||||
|
||||
@@ -34,23 +34,6 @@ exports.httpRequest = function(options) {
|
||||
});
|
||||
return result;
|
||||
},
|
||||
getHeader = function(targetHeader) {
|
||||
return headers[targetHeader] || headers[targetHeader.toLowerCase()];
|
||||
},
|
||||
isSimpleRequest = function(type,headers) {
|
||||
if(["GET","HEAD","POST"].indexOf(type) === -1) {
|
||||
return false;
|
||||
}
|
||||
for(var header in headers) {
|
||||
if(["accept","accept-language","content-language","content-type"].indexOf(header.toLowerCase()) === -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(hasHeader("Content-Type") && ["application/x-www-form-urlencoded","multipart/form-data","text/plain"].indexOf(getHeader["Content-Type"]) === -1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
returnProp = options.returnProp || "responseText",
|
||||
request = new XMLHttpRequest(),
|
||||
data = "",
|
||||
@@ -93,7 +76,7 @@ exports.httpRequest = function(options) {
|
||||
if(data && !hasHeader("Content-Type")) {
|
||||
request.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
|
||||
}
|
||||
if(!hasHeader("X-Requested-With") && !isSimpleRequest(type,headers)) {
|
||||
if(!hasHeader("X-Requested-With")) {
|
||||
request.setRequestHeader("X-Requested-With","TiddlyWiki");
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -12,8 +12,9 @@ Modal message mechanism
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
var navigator = require("$:/core/modules/widgets/navigator.js");
|
||||
var widget = require("$:/core/modules/widgets/widget.js"),
|
||||
navigator = require("$:/core/modules/widgets/navigator.js"),
|
||||
dm = $tw.utils.domMaker;
|
||||
|
||||
var Modal = function(wiki) {
|
||||
this.wiki = wiki;
|
||||
@@ -26,6 +27,10 @@ Display a modal dialogue
|
||||
options: see below
|
||||
Options include:
|
||||
downloadLink: Text of a big download link to include
|
||||
variables: variables to be passed to the modal
|
||||
event: optional DOM event that initiated the modal
|
||||
progress: set to true to add a progress bar
|
||||
onclose: callback for when the modal is closed
|
||||
*/
|
||||
Modal.prototype.display = function(title,options) {
|
||||
options = options || {};
|
||||
@@ -47,7 +52,6 @@ Modal.prototype.display = function(title,options) {
|
||||
"tv-story-list": (options.event && options.event.widget ? options.event.widget.getVariable("tv-story-list") : ""),
|
||||
"tv-history-list": (options.event && options.event.widget ? options.event.widget.getVariable("tv-history-list") : "")
|
||||
},options.variables);
|
||||
|
||||
// Create the wrapper divs
|
||||
var wrapper = this.srcDocument.createElement("div"),
|
||||
modalBackdrop = this.srcDocument.createElement("div"),
|
||||
@@ -55,6 +59,7 @@ Modal.prototype.display = function(title,options) {
|
||||
modalHeader = this.srcDocument.createElement("div"),
|
||||
headerTitle = this.srcDocument.createElement("h3"),
|
||||
modalBody = this.srcDocument.createElement("div"),
|
||||
modalProgress = this.srcDocument.createElement("div"),
|
||||
modalLink = this.srcDocument.createElement("a"),
|
||||
modalFooter = this.srcDocument.createElement("div"),
|
||||
modalFooterHelp = this.srcDocument.createElement("span"),
|
||||
@@ -71,6 +76,7 @@ Modal.prototype.display = function(title,options) {
|
||||
$tw.utils.addClass(modalWrapper,"tc-modal");
|
||||
$tw.utils.addClass(modalHeader,"tc-modal-header");
|
||||
$tw.utils.addClass(modalBody,"tc-modal-body");
|
||||
$tw.utils.addClass(modalProgress,"tc-modal-progress");
|
||||
$tw.utils.addClass(modalFooter,"tc-modal-footer");
|
||||
// Join them together
|
||||
wrapper.appendChild(modalBackdrop);
|
||||
@@ -78,6 +84,15 @@ Modal.prototype.display = function(title,options) {
|
||||
modalHeader.appendChild(headerTitle);
|
||||
modalWrapper.appendChild(modalHeader);
|
||||
modalWrapper.appendChild(modalBody);
|
||||
if(options.progress) {
|
||||
var modalProgressBar = this.srcDocument.createElement("div");
|
||||
modalProgressBar.className = "tc-modal-progress-bar";
|
||||
modalProgress.appendChild(modalProgressBar);
|
||||
var modalProgressPercent = this.srcDocument.createElement("div");
|
||||
modalProgressPercent.className = "tc-modal-progress-percent";
|
||||
modalProgress.appendChild(modalProgressPercent);
|
||||
modalWrapper.appendChild(modalProgress);
|
||||
}
|
||||
modalFooter.appendChild(modalFooterHelp);
|
||||
modalFooter.appendChild(modalFooterButtons);
|
||||
modalWrapper.appendChild(modalFooter);
|
||||
@@ -105,7 +120,6 @@ Modal.prototype.display = function(title,options) {
|
||||
parentWidget: $tw.rootWidget
|
||||
});
|
||||
navigatorWidgetNode.render(modalBody,null);
|
||||
|
||||
// Render the title of the message
|
||||
var headerWidgetNode = this.wiki.makeTranscludeWidget(title,{
|
||||
field: "subtitle",
|
||||
@@ -182,6 +196,10 @@ Modal.prototype.display = function(title,options) {
|
||||
this.wiki.addEventListener("change",refreshHandler);
|
||||
// Add the close event handler
|
||||
var closeHandler = function(event) {
|
||||
// Call the onclose handler
|
||||
if(options.onclose) {
|
||||
options.onclose(event);
|
||||
}
|
||||
// Remove our refresh handler
|
||||
self.wiki.removeEventListener("change",refreshHandler);
|
||||
// Decrease the modal count and adjust the body class
|
||||
@@ -236,6 +254,22 @@ Modal.prototype.display = function(title,options) {
|
||||
$tw.utils.setStyle(modalWrapper,[
|
||||
{transform: "translateY(0px)"}
|
||||
]);
|
||||
// Return the wrapper node
|
||||
return {
|
||||
domNode: wrapper,
|
||||
closeHandler: closeHandler,
|
||||
setProgress: function(numerator,denominator) {
|
||||
// Remove old progress
|
||||
while(modalProgressPercent.hasChildNodes()) {
|
||||
modalProgressPercent.removeChild(modalProgressPercent.firstChild);
|
||||
}
|
||||
// Set new text
|
||||
var percent = (numerator * 100 /denominator).toFixed(2) + "%";
|
||||
modalProgressPercent.appendChild(self.srcDocument.createTextNode(percent));
|
||||
// Set bar width
|
||||
modalProgressBar.style.width = percent;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Modal.prototype.adjustPageClass = function() {
|
||||
|
||||
@@ -235,7 +235,7 @@ Object.defineProperty(TW_Element.prototype, "innerHTML", {
|
||||
if(node instanceof TW_Element) {
|
||||
b.push(node.outerHTML);
|
||||
} else if(node instanceof TW_TextNode) {
|
||||
b.push($tw.utils.htmlTextEncode(node.textContent));
|
||||
b.push($tw.utils.htmlEncode(node.textContent));
|
||||
}
|
||||
});
|
||||
return b.join("");
|
||||
|
||||
@@ -95,15 +95,6 @@ LinkedList.prototype.toArray = function() {
|
||||
return output;
|
||||
};
|
||||
|
||||
LinkedList.prototype.makeTiddlerIterator = function(wiki) {
|
||||
var self = this;
|
||||
return function(callback) {
|
||||
self.each(function(title) {
|
||||
callback(wiki.getTiddler(title),title);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
function _removeOne(list,value) {
|
||||
var prevEntry = list.prev[value],
|
||||
nextEntry = list.next[value],
|
||||
|
||||
@@ -199,8 +199,6 @@ exports.transliterationPairs = {
|
||||
"Nj":"N",
|
||||
"Ñ":"N",
|
||||
"NJ":"NJ",
|
||||
"ð":"d",
|
||||
"Ð":"D",
|
||||
"Ó":"O",
|
||||
"Ŏ":"O",
|
||||
"Ǒ":"O",
|
||||
@@ -267,8 +265,6 @@ exports.transliterationPairs = {
|
||||
"Ɽ":"R",
|
||||
"Ꜿ":"C",
|
||||
"Ǝ":"E",
|
||||
"ß":"ss",
|
||||
"ẞ":"SS",
|
||||
"Ś":"S",
|
||||
"Ṥ":"S",
|
||||
"Š":"S",
|
||||
@@ -279,8 +275,6 @@ exports.transliterationPairs = {
|
||||
"Ṡ":"S",
|
||||
"Ṣ":"S",
|
||||
"Ṩ":"S",
|
||||
"þ": "th",
|
||||
"Þ": "TH",
|
||||
"Ť":"T",
|
||||
"Ţ":"T",
|
||||
"Ṱ":"T",
|
||||
@@ -913,8 +907,7 @@ exports.transliterationPairs = {
|
||||
"т":"t",
|
||||
"ь":"'",
|
||||
"б":"b",
|
||||
"ю":"yu",
|
||||
"…":"..."
|
||||
"ю":"yu"
|
||||
};
|
||||
|
||||
exports.transliterate = function(str) {
|
||||
|
||||
@@ -383,15 +383,6 @@ exports.formatDateString = function(date,template) {
|
||||
[/^0WW/, function() {
|
||||
return $tw.utils.pad($tw.utils.getWeek(date));
|
||||
}],
|
||||
[/^0ddddd/, function() {
|
||||
return $tw.utils.pad(Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24),3);
|
||||
}],
|
||||
[/^ddddd/, function() {
|
||||
return Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24);
|
||||
}],
|
||||
[/^dddd/, function() {
|
||||
return [7,1,2,3,4,5,6][date.getDay()];
|
||||
}],
|
||||
[/^ddd/, function() {
|
||||
return $tw.language.getString("Date/Short/Day/" + date.getDay());
|
||||
}],
|
||||
@@ -978,22 +969,4 @@ exports.makeCompareFunction = function(type,options) {
|
||||
return (types[type] || types[options.defaultType] || types.number);
|
||||
};
|
||||
|
||||
exports.decodeURIComponentSafe = function(str) {
|
||||
var value = str;
|
||||
try {
|
||||
value = decodeURIComponent(str);
|
||||
} catch(e) {
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
exports.decodeURISafe = function(str) {
|
||||
var value = str;
|
||||
try {
|
||||
value = decodeURI(str);
|
||||
} catch(e) {
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -59,7 +59,7 @@ Invoke the action associated with this widget
|
||||
ConfirmWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
var invokeActions = true,
|
||||
handled = true,
|
||||
win = event && event.event && event.event.view ? event.event.view : window;
|
||||
win = event.event && event.event.view ? event.event.view : window;
|
||||
if(this.prompt) {
|
||||
invokeActions = win.confirm(this.message);
|
||||
}
|
||||
|
||||
@@ -54,7 +54,6 @@ DraggableWidget.prototype.render = function(parent,nextSibling) {
|
||||
dragFilterFn: function() {return self.getAttribute("filter");},
|
||||
startActions: self.startActions,
|
||||
endActions: self.endActions,
|
||||
dragImageType: self.dragImageType,
|
||||
widget: this
|
||||
});
|
||||
// Insert the link into the DOM and render any children
|
||||
@@ -72,7 +71,6 @@ DraggableWidget.prototype.execute = function() {
|
||||
this.draggableClasses = this.getAttribute("class");
|
||||
this.startActions = this.getAttribute("startactions");
|
||||
this.endActions = this.getAttribute("endactions");
|
||||
this.dragImageType = this.getAttribute("dragimagetype");
|
||||
// Make the child widgets
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
||||
@@ -76,22 +76,16 @@ EventWidget.prototype.render = function(parent,nextSibling) {
|
||||
variables["tv-selectednode-posy"] = selectedNode.offsetTop.toString();
|
||||
variables["tv-selectednode-width"] = selectedNode.offsetWidth.toString();
|
||||
variables["tv-selectednode-height"] = selectedNode.offsetHeight.toString();
|
||||
|
||||
if(event.clientX && event.clientY) {
|
||||
//Add variables for event X and Y position relative to selected node
|
||||
selectedNodeRect = selectedNode.getBoundingClientRect();
|
||||
variables["event-fromselected-posx"] = (event.clientX - selectedNodeRect.left).toString();
|
||||
variables["event-fromselected-posy"] = (event.clientY - selectedNodeRect.top).toString();
|
||||
|
||||
//Add variables for event X and Y position relative to event catcher node
|
||||
catcherNodeRect = self.domNode.getBoundingClientRect();
|
||||
variables["event-fromcatcher-posx"] = (event.clientX - catcherNodeRect.left).toString();
|
||||
variables["event-fromcatcher-posy"] = (event.clientY - catcherNodeRect.top).toString();
|
||||
//Add variables for event X and Y position relative to selected node
|
||||
selectedNodeRect = selectedNode.getBoundingClientRect();
|
||||
variables["event-fromselected-posx"] = (event.clientX - selectedNodeRect.left).toString();
|
||||
variables["event-fromselected-posy"] = (event.clientY - selectedNodeRect.top).toString();
|
||||
|
||||
//Add variables for event X and Y position relative to the viewport
|
||||
variables["event-fromviewport-posx"] = event.clientX.toString();
|
||||
variables["event-fromviewport-posy"] = event.clientY.toString();
|
||||
}
|
||||
//Add variables for event X and Y position relative to event catcher node
|
||||
catcherNodeRect = self.domNode.getBoundingClientRect();
|
||||
variables["event-fromcatcher-posx"] = (event.clientX - catcherNodeRect.left).toString();
|
||||
variables["event-fromcatcher-posy"] = (event.clientY - catcherNodeRect.top).toString();
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@@ -40,10 +40,8 @@ ImportVariablesWidget.prototype.execute = function(tiddlerList) {
|
||||
var widgetPointer = this;
|
||||
// Got to flush all the accumulated variables
|
||||
this.variables = new this.variablesConstructor();
|
||||
// Get our parameters
|
||||
this.filter = this.getAttribute("filter");
|
||||
// Compute the filter
|
||||
this.tiddlerList = tiddlerList || this.wiki.filterTiddlers(this.filter,this);
|
||||
this.tiddlerList = tiddlerList || this.getTiddlerList();
|
||||
// Accumulate the <$set> widgets from each tiddler
|
||||
$tw.utils.each(this.tiddlerList,function(title) {
|
||||
var parser = widgetPointer.wiki.parseTiddler(title);
|
||||
@@ -86,7 +84,6 @@ ImportVariablesWidget.prototype.execute = function(tiddlerList) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (widgetPointer != this) {
|
||||
widgetPointer.parseTreeNode.children = this.parseTreeNode.children;
|
||||
} else {
|
||||
@@ -94,13 +91,21 @@ ImportVariablesWidget.prototype.execute = function(tiddlerList) {
|
||||
}
|
||||
};
|
||||
|
||||
ImportVariablesWidget.prototype.getTiddlerList = function() {
|
||||
var filter = this.getAttribute("filter"),
|
||||
title = this.getAttribute("tiddler");
|
||||
return (filter && this.wiki.filterTiddlers(filter,this)) || (title && [title]) || [];
|
||||
};
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
ImportVariablesWidget.prototype.refresh = function(changedTiddlers) {
|
||||
// Recompute our attributes and the filter list
|
||||
var changedAttributes = this.computeAttributes(),
|
||||
tiddlerList = this.wiki.filterTiddlers(this.getAttribute("filter"),this);
|
||||
filter = this.getAttribute("filter"),
|
||||
title = this.getAttribute("tiddler"),
|
||||
tiddlerList = this.getTiddlerList();
|
||||
// Refresh if the filter has changed, or the list of tiddlers has changed, or any of the tiddlers in the list has changed
|
||||
function haveListedTiddlersChanged() {
|
||||
var changed = false;
|
||||
@@ -111,7 +116,7 @@ ImportVariablesWidget.prototype.refresh = function(changedTiddlers) {
|
||||
});
|
||||
return changed;
|
||||
}
|
||||
if(changedAttributes.filter || !$tw.utils.isArrayEqual(this.tiddlerList,tiddlerList) || haveListedTiddlersChanged()) {
|
||||
if(changedAttributes.filter || changedAttributes.tiddler || !$tw.utils.isArrayEqual(this.tiddlerList,tiddlerList) || haveListedTiddlersChanged()) {
|
||||
// Compute the filter
|
||||
this.removeChildDomNodes();
|
||||
this.execute(tiddlerList);
|
||||
|
||||
@@ -32,7 +32,13 @@ JSONTiddlerWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
// Collect the fields from the optional base tiddler
|
||||
var fields = this.getTiddlerFields();
|
||||
var fields = {};
|
||||
if(this.attTiddler) {
|
||||
var tiddler = this.wiki.getTiddler(this.attTiddler);
|
||||
if(tiddler) {
|
||||
fields = tiddler.getFieldStrings({exclude: this.attExclude.split(" ")});
|
||||
}
|
||||
}
|
||||
// Add custom fields specified in attributes starting with $
|
||||
$tw.utils.each(this.attributes,function(attribute,name) {
|
||||
if(name.charAt(0) === "$") {
|
||||
@@ -73,19 +79,6 @@ JSONTiddlerWidget.prototype.refresh = function(changedTiddlers) {
|
||||
}
|
||||
};
|
||||
|
||||
JSONTiddlerWidget.prototype.getTiddlerFields = function() {
|
||||
var fields = {};
|
||||
if(this.attTiddler) {
|
||||
var tiddler = this.wiki.getTiddler(this.attTiddler);
|
||||
if(tiddler) {
|
||||
fields = tiddler.getFieldStrings({exclude: this.attExclude.split(" ")});
|
||||
} else {
|
||||
fields = {title: this.attTiddler};
|
||||
}
|
||||
}
|
||||
return fields;
|
||||
};
|
||||
|
||||
exports.jsontiddler = JSONTiddlerWidget;
|
||||
|
||||
})();
|
||||
@@ -98,6 +98,7 @@ LinkWidget.prototype.renderLink = function(parent,nextSibling) {
|
||||
var wikiLinkTemplateMacro = this.getVariable("tv-wikilink-template"),
|
||||
wikiLinkTemplate = wikiLinkTemplateMacro ? wikiLinkTemplateMacro.trim() : "#$uri_encoded$";
|
||||
wikiLinkText = $tw.utils.replaceString(wikiLinkTemplate,"$uri_encoded$",encodeURIComponent(this.to));
|
||||
wikiLinkText = $tw.utils.replaceString(wikiLinkText,"$title_slugify$",this.wiki.slugify(this.to));
|
||||
wikiLinkText = $tw.utils.replaceString(wikiLinkText,"$uri_doubleencoded$",encodeURIComponent(encodeURIComponent(this.to)));
|
||||
}
|
||||
// Override with the value of tv-get-export-link if defined
|
||||
|
||||
@@ -236,11 +236,6 @@ ListWidget.prototype.handleListChanges = function(changedTiddlers) {
|
||||
hasRefreshed = hasRefreshed || refreshed;
|
||||
}
|
||||
}
|
||||
// If there are items to remove and we have not refreshed then recreate the item that will now be at the last position
|
||||
if(!hasRefreshed && this.children.length > this.list.length) {
|
||||
this.removeListItem(this.list.length-1);
|
||||
this.insertListItem(this.list.length-1,this.list[this.list.length-1]);
|
||||
}
|
||||
} else {
|
||||
// Cycle through the list, inserting and removing list items as needed
|
||||
for(t=0; t<this.list.length; t++) {
|
||||
|
||||
@@ -36,38 +36,28 @@ MessageCatcherWidget.prototype.render = function(parent,nextSibling) {
|
||||
// Helper to add an event handler
|
||||
var addEventHandler = function(type,actions) {
|
||||
if(type && actions) {
|
||||
var isActionStringExecuting = false;
|
||||
self.addEventListener(
|
||||
type,
|
||||
function(event) {
|
||||
// Don't trap the event if it came from one of our action handlers
|
||||
if(isActionStringExecuting) {
|
||||
return true;
|
||||
}
|
||||
// Collect all the event properties into variables
|
||||
var collectProps = function(obj,prefix) {
|
||||
prefix = prefix || "";
|
||||
var props = {},
|
||||
names = [];
|
||||
var props = {};
|
||||
$tw.utils.each(obj,function(value,name) {
|
||||
if(["string","boolean","number"].indexOf(typeof value) !== -1) {
|
||||
names.push(name);
|
||||
props[prefix + "-" + name] = value.toString();
|
||||
props[prefix + name] = value.toString();
|
||||
}
|
||||
});
|
||||
props["list-" + prefix] = $tw.utils.stringifyList(names);
|
||||
return props;
|
||||
};
|
||||
var variables = $tw.utils.extend(
|
||||
{},
|
||||
collectProps(event.paramObject,"event-paramObject"),
|
||||
collectProps(event,"event"),
|
||||
collectProps(event.paramObject,"event-paramObject-"),
|
||||
collectProps(event,"event-"),
|
||||
{
|
||||
modifier: $tw.keyboardManager.getEventModifierKeyDescriptor(event)
|
||||
});
|
||||
isActionStringExecuting = true;
|
||||
self.invokeActionString(actions,self,event,variables);
|
||||
isActionStringExecuting = false;
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -122,7 +122,6 @@ RadioWidget.prototype.refresh = function(changedTiddlers) {
|
||||
return true;
|
||||
} else if(changedTiddlers[this.radioTitle]) {
|
||||
this.inputDomNode.checked = this.getValue() === this.radioValue;
|
||||
$tw.utils.toggleClass(this.labelDomNode,"tc-radio-selected",this.inputDomNode.checked);
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
} else {
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
|
||||
@@ -226,7 +226,7 @@ RevealWidget.prototype.refresh = function(changedTiddlers) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
} else if(this.type === "popup" && this.isOpen && this.updatePopupPosition && (changedTiddlers[this.state] || changedTiddlers[this.stateTitle])) {
|
||||
} else if(this.type === "popup" && this.updatePopupPosition && (changedTiddlers[this.state] || changedTiddlers[this.stateTitle])) {
|
||||
this.positionPopup(this.domNode);
|
||||
}
|
||||
if(changedAttributes.style) {
|
||||
|
||||
@@ -365,108 +365,47 @@ Sort an array of tiddler titles by a specified field
|
||||
*/
|
||||
exports.sortTiddlers = function(titles,sortField,isDescending,isCaseSensitive,isNumeric,isAlphaNumeric) {
|
||||
var self = this;
|
||||
if(sortField === "title") {
|
||||
if(!isNumeric && !isAlphaNumeric) {
|
||||
if(isCaseSensitive) {
|
||||
if(isDescending) {
|
||||
titles.sort(function(a,b) {
|
||||
return b.localeCompare(a);
|
||||
});
|
||||
} else {
|
||||
titles.sort(function(a,b) {
|
||||
return a.localeCompare(b);
|
||||
});
|
||||
}
|
||||
titles.sort(function(a,b) {
|
||||
var x,y,
|
||||
compareNumbers = function(x,y) {
|
||||
var result =
|
||||
isNaN(x) && !isNaN(y) ? (isDescending ? -1 : 1) :
|
||||
!isNaN(x) && isNaN(y) ? (isDescending ? 1 : -1) :
|
||||
(isDescending ? y - x : x - y);
|
||||
return result;
|
||||
};
|
||||
if(sortField !== "title") {
|
||||
var tiddlerA = self.getTiddler(a),
|
||||
tiddlerB = self.getTiddler(b);
|
||||
if(tiddlerA) {
|
||||
a = tiddlerA.getFieldString(sortField) || "";
|
||||
} else {
|
||||
if(isDescending) {
|
||||
titles.sort(function(a,b) {
|
||||
return b.toLowerCase().localeCompare(a.toLowerCase());
|
||||
});
|
||||
} else {
|
||||
titles.sort(function(a,b) {
|
||||
return a.toLowerCase().localeCompare(b.toLowerCase());
|
||||
});
|
||||
}
|
||||
a = "";
|
||||
}
|
||||
if(tiddlerB) {
|
||||
b = tiddlerB.getFieldString(sortField) || "";
|
||||
} else {
|
||||
b = "";
|
||||
}
|
||||
} else {
|
||||
titles.sort(function(a,b) {
|
||||
var x,y;
|
||||
if(isNumeric) {
|
||||
x = Number(a);
|
||||
y = Number(b);
|
||||
if(isNaN(x)) {
|
||||
if(isNaN(y)) {
|
||||
// If neither value is a number then fall through to a textual comparison
|
||||
} else {
|
||||
return isDescending ? -1 : 1;
|
||||
}
|
||||
} else {
|
||||
if(isNaN(y)) {
|
||||
return isDescending ? 1 : -1;
|
||||
} else {
|
||||
return isDescending ? y - x : x - y;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(isAlphaNumeric) {
|
||||
return isDescending ? b.localeCompare(a,undefined,{numeric: true,sensitivity: "base"}) : a.localeCompare(b,undefined,{numeric: true,sensitivity: "base"});
|
||||
}
|
||||
if(!isCaseSensitive) {
|
||||
a = a.toLowerCase();
|
||||
b = b.toLowerCase();
|
||||
}
|
||||
return isDescending ? b.localeCompare(a) : a.localeCompare(b);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
titles.sort(function(a,b) {
|
||||
var x,y;
|
||||
if(sortField !== "title") {
|
||||
var tiddlerA = self.getTiddler(a),
|
||||
tiddlerB = self.getTiddler(b);
|
||||
if(tiddlerA) {
|
||||
a = tiddlerA.fields[sortField] || "";
|
||||
} else {
|
||||
a = "";
|
||||
}
|
||||
if(tiddlerB) {
|
||||
b = tiddlerB.fields[sortField] || "";
|
||||
} else {
|
||||
b = "";
|
||||
}
|
||||
}
|
||||
if(isNumeric) {
|
||||
x = Number(a);
|
||||
y = Number(b);
|
||||
if(isNaN(x)) {
|
||||
if(isNaN(y)) {
|
||||
// If neither value is a number then fall through to a textual comparison
|
||||
} else {
|
||||
return isDescending ? -1 : 1;
|
||||
}
|
||||
} else {
|
||||
if(isNaN(y)) {
|
||||
return isDescending ? 1 : -1;
|
||||
} else {
|
||||
return isDescending ? y - x : x - y;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(Object.prototype.toString.call(a) === "[object Date]" && Object.prototype.toString.call(b) === "[object Date]") {
|
||||
return isDescending ? b - a : a - b;
|
||||
}
|
||||
x = Number(a);
|
||||
y = Number(b);
|
||||
if(isNumeric && (!isNaN(x) || !isNaN(y))) {
|
||||
return compareNumbers(x,y);
|
||||
} else if($tw.utils.isDate(a) && $tw.utils.isDate(b)) {
|
||||
return isDescending ? b - a : a - b;
|
||||
} else if(isAlphaNumeric) {
|
||||
return isDescending ? b.localeCompare(a,undefined,{numeric: true,sensitivity: "base"}) : a.localeCompare(b,undefined,{numeric: true,sensitivity: "base"});
|
||||
} else {
|
||||
a = String(a);
|
||||
b = String(b);
|
||||
if(isAlphaNumeric) {
|
||||
return isDescending ? b.localeCompare(a,undefined,{numeric: true,sensitivity: "base"}) : a.localeCompare(b,undefined,{numeric: true,sensitivity: "base"});
|
||||
}
|
||||
if(!isCaseSensitive) {
|
||||
a = a.toLowerCase();
|
||||
b = b.toLowerCase();
|
||||
}
|
||||
return isDescending ? b.localeCompare(a) : a.localeCompare(b);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -905,7 +844,7 @@ exports.clearGlobalCache = function() {
|
||||
exports.getCacheForTiddler = function(title,cacheName,initializer) {
|
||||
this.caches = this.caches || Object.create(null);
|
||||
var caches = this.caches[title];
|
||||
if(caches && caches[cacheName] !== undefined) {
|
||||
if(caches && caches[cacheName]) {
|
||||
return caches[cacheName];
|
||||
} else {
|
||||
if(!caches) {
|
||||
@@ -1636,4 +1575,23 @@ exports.slugify = function(title,options) {
|
||||
return slug;
|
||||
};
|
||||
|
||||
/*
|
||||
Return an array of the titles that would generate a specified slug, if any. Options include:
|
||||
*/
|
||||
exports.unslugify = function(slug) {
|
||||
var self = this,
|
||||
slugToTitle = this.getGlobalCache("slugs",function() {
|
||||
var map = {};
|
||||
$tw.utils.each($tw.wiki.allTitles(),function(title) {
|
||||
var slug = self.slugify(title);
|
||||
if(!(slug in map)) {
|
||||
map[slug] = [];
|
||||
}
|
||||
map[slug].push(title);
|
||||
});
|
||||
return map;
|
||||
});
|
||||
return slugToTitle[slug];
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -19,73 +19,71 @@ $:/config/Plugins/Disabled/$(currentTiddler)$
|
||||
\end
|
||||
|
||||
\define plugin-table-body(type,disabledMessage,default-popup-state)
|
||||
\whitespace trim
|
||||
<div class="tc-plugin-info-chunk tc-plugin-info-toggle">
|
||||
<$reveal type="nomatch" state=<<popup-state>> text="yes" default="""$default-popup-state$""">
|
||||
<$button class="tc-btn-invisible tc-btn-dropdown" set=<<popup-state>> setTo="yes">
|
||||
{{$:/core/images/chevron-right}}
|
||||
</$button>
|
||||
</$reveal>
|
||||
<$reveal type="match" state=<<popup-state>> text="yes" default="""$default-popup-state$""">
|
||||
<$button class="tc-btn-invisible tc-btn-dropdown" set=<<popup-state>> setTo="no">
|
||||
{{$:/core/images/chevron-down}}
|
||||
</$button>
|
||||
</$reveal>
|
||||
<$reveal type="nomatch" state=<<popup-state>> text="yes" default="""$default-popup-state$""">
|
||||
<$button class="tc-btn-invisible tc-btn-dropdown" set=<<popup-state>> setTo="yes">
|
||||
{{$:/core/images/chevron-right}}
|
||||
</$button>
|
||||
</$reveal>
|
||||
<$reveal type="match" state=<<popup-state>> text="yes" default="""$default-popup-state$""">
|
||||
<$button class="tc-btn-invisible tc-btn-dropdown" set=<<popup-state>> setTo="no">
|
||||
{{$:/core/images/chevron-down}}
|
||||
</$button>
|
||||
</$reveal>
|
||||
</div>
|
||||
<div class="tc-plugin-info-chunk tc-plugin-info-icon">
|
||||
<$transclude tiddler=<<currentTiddler>> subtiddler=<<plugin-icon-title>>>
|
||||
<$transclude tiddler="$:/core/images/plugin-generic-$type$"/>
|
||||
</$transclude>
|
||||
<$transclude tiddler=<<currentTiddler>> subtiddler=<<plugin-icon-title>>>
|
||||
<$transclude tiddler="$:/core/images/plugin-generic-$type$"/>
|
||||
</$transclude>
|
||||
</div>
|
||||
<div class="tc-plugin-info-chunk tc-plugin-info-description">
|
||||
<h1>
|
||||
''<$text text={{{ [<currentTiddler>get[name]] ~[<currentTiddler>split[/]last[1]] }}}/>'': <$view field="description"><$view field="title"/></$view> $disabledMessage$
|
||||
</h1>
|
||||
<h2>
|
||||
<$view field="title"/>
|
||||
</h2>
|
||||
<h2>
|
||||
<div><em><$view field="version"/></em></div>
|
||||
</h2>
|
||||
<h1>
|
||||
''<$text text={{{ [<currentTiddler>get[name]] ~[<currentTiddler>split[/]last[1]] }}}/>'': <$view field="description"><$view field="title"/></$view> $disabledMessage$
|
||||
</h1>
|
||||
<h2>
|
||||
<$view field="title"/>
|
||||
</h2>
|
||||
<h2>
|
||||
<div><em><$view field="version"/></em></div>
|
||||
</h2>
|
||||
</div>
|
||||
\end
|
||||
|
||||
\define plugin-info(type,default-popup-state)
|
||||
\whitespace trim
|
||||
<$set name="popup-state" value=<<popup-state-macro>>>
|
||||
<$reveal type="nomatch" state=<<plugin-disable-title>> text="yes">
|
||||
<$link to={{!!title}} class="tc-plugin-info">
|
||||
<<plugin-table-body type:"$type$" default-popup-state:"""$default-popup-state$""">>
|
||||
</$link>
|
||||
</$reveal>
|
||||
<$reveal type="match" state=<<plugin-disable-title>> text="yes">
|
||||
<$link to={{!!title}} class="tc-plugin-info tc-plugin-info-disabled">
|
||||
<<plugin-table-body type:"$type$" default-popup-state:"""$default-popup-state$""" disabledMessage:"<$macrocall $name='lingo' title='Disabled/Status'/>">>
|
||||
</$link>
|
||||
</$reveal>
|
||||
<$reveal type="match" text="yes" state=<<popup-state>> default="""$default-popup-state$""">
|
||||
<div class="tc-plugin-info-dropdown">
|
||||
<div class="tc-plugin-info-dropdown-body">
|
||||
<$list filter="[all[current]] -[[$:/core]]">
|
||||
<div style="float:right;">
|
||||
<$reveal type="nomatch" state=<<plugin-disable-title>> text="yes">
|
||||
<$button set=<<plugin-disable-title>> setTo="yes" tooltip={{$:/language/ControlPanel/Plugins/Disable/Hint}} aria-label={{$:/language/ControlPanel/Plugins/Disable/Caption}}>
|
||||
<<lingo Disable/Caption>>
|
||||
</$button>
|
||||
</$reveal>
|
||||
<$reveal type="match" state=<<plugin-disable-title>> text="yes">
|
||||
<$button set=<<plugin-disable-title>> setTo="no" tooltip={{$:/language/ControlPanel/Plugins/Enable Hint}} aria-label={{$:/language/ControlPanel/Plugins/Enable/Caption}}>
|
||||
<<lingo Enable/Caption>>
|
||||
</$button>
|
||||
</$reveal>
|
||||
</div>
|
||||
</$list>
|
||||
<$set name="tabsList" filter="[<currentTiddler>list[]] contents">
|
||||
<$macrocall $name="tabs" state=<<tabs-state-macro>> tabsList=<<tabsList>> default={{{ [enlist<tabsList>] }}} template="$:/core/ui/PluginInfo"/>
|
||||
</$set>
|
||||
</div>
|
||||
</div>
|
||||
</$reveal>
|
||||
<$reveal type="nomatch" state=<<plugin-disable-title>> text="yes">
|
||||
<$link to={{!!title}} class="tc-plugin-info">
|
||||
<<plugin-table-body type:"$type$" default-popup-state:"""$default-popup-state$""">>
|
||||
</$link>
|
||||
</$reveal>
|
||||
<$reveal type="match" state=<<plugin-disable-title>> text="yes">
|
||||
<$link to={{!!title}} class="tc-plugin-info tc-plugin-info-disabled">
|
||||
<<plugin-table-body type:"$type$" default-popup-state:"""$default-popup-state$""" disabledMessage:"<$macrocall $name='lingo' title='Disabled/Status'/>">>
|
||||
</$link>
|
||||
</$reveal>
|
||||
<$reveal type="match" text="yes" state=<<popup-state>> default="""$default-popup-state$""">
|
||||
<div class="tc-plugin-info-dropdown">
|
||||
<div class="tc-plugin-info-dropdown-body">
|
||||
<$list filter="[all[current]] -[[$:/core]]">
|
||||
<div style="float:right;">
|
||||
<$reveal type="nomatch" state=<<plugin-disable-title>> text="yes">
|
||||
<$button set=<<plugin-disable-title>> setTo="yes" tooltip={{$:/language/ControlPanel/Plugins/Disable/Hint}} aria-label={{$:/language/ControlPanel/Plugins/Disable/Caption}}>
|
||||
<<lingo Disable/Caption>>
|
||||
</$button>
|
||||
</$reveal>
|
||||
<$reveal type="match" state=<<plugin-disable-title>> text="yes">
|
||||
<$button set=<<plugin-disable-title>> setTo="no" tooltip={{$:/language/ControlPanel/Plugins/Enable/Hint}} aria-label={{$:/language/ControlPanel/Plugins/Enable/Caption}}>
|
||||
<<lingo Enable/Caption>>
|
||||
</$button>
|
||||
</$reveal>
|
||||
</div>
|
||||
</$list>
|
||||
<$set name="tabsList" filter="[<currentTiddler>list[]] contents">
|
||||
<$macrocall $name="tabs" state=<<tabs-state-macro>> tabsList=<<tabsList>> default={{{ [enlist<tabsList>] }}} template="$:/core/ui/PluginInfo"/>
|
||||
</$set>
|
||||
</div>
|
||||
</div>
|
||||
</$reveal>
|
||||
</$set>
|
||||
\end
|
||||
|
||||
|
||||
@@ -16,4 +16,4 @@ caption: {{$:/language/ControlPanel/Plugins/Caption}}
|
||||
|
||||
<<lingo Installed/Hint>>
|
||||
|
||||
<$macrocall $name="tabs" tabsList="[all[tiddlers+shadows]tag[$:/tags/ControlPanel/Plugins]!has[draft.of]]" default="$:/core/ui/ControlPanel/Plugins/Installed/Plugins" explicitState="$:/state/tab--86143343"/>
|
||||
<$macrocall $name="tabs" tabsList="[[$:/core/ui/ControlPanel/Plugins/Installed/Plugins]] [[$:/core/ui/ControlPanel/Plugins/Installed/Themes]] [[$:/core/ui/ControlPanel/Plugins/Installed/Languages]]" default="$:/core/ui/ControlPanel/Plugins/Installed/Plugins" explicitState="$:/state/tab--86143343"/>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
title: $:/core/ui/ControlPanel/Plugins/Installed/Languages
|
||||
tags: $:/tags/ControlPanel/Plugins
|
||||
caption: {{$:/language/ControlPanel/Plugins/Languages/Caption}} (<$count filter="[!has[draft.of]plugin-type[language]]"/>)
|
||||
|
||||
<<plugin-table language>>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
title: $:/core/ui/ControlPanel/Plugins/Installed/Plugins
|
||||
tags: $:/tags/ControlPanel/Plugins
|
||||
caption: {{$:/language/ControlPanel/Plugins/Plugins/Caption}} (<$count filter="[!has[draft.of]plugin-type[plugin]]"/>)
|
||||
|
||||
<<plugin-table plugin>>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
title: $:/core/ui/ControlPanel/Plugins/Installed/Themes
|
||||
tags: $:/tags/ControlPanel/Plugins
|
||||
caption: {{$:/language/ControlPanel/Plugins/Themes/Caption}} (<$count filter="[!has[draft.of]plugin-type[theme]]"/>)
|
||||
|
||||
<<plugin-table theme>>
|
||||
|
||||
81
core/ui/ControlPanel/Publishing.tid
Normal file
81
core/ui/ControlPanel/Publishing.tid
Normal file
@@ -0,0 +1,81 @@
|
||||
title: $:/core/ui/ControlPanel/Publishing
|
||||
tags: $:/tags/ControlPanel
|
||||
caption: {{$:/language/ControlPanel/Publishing/Caption}}
|
||||
|
||||
{{$:/language/ControlPanel/Publishing/Hint}}
|
||||
|
||||
<div class="tc-publishing-job-listing">
|
||||
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/PublishingJob]]" variable="job">
|
||||
|
||||
<div class="tc-publishing-job">
|
||||
|
||||
<h2>Job: <$link to=<<job>>><$transclude tiddler=<<job>> field="caption" mode="inline"/></$link></h2>
|
||||
|
||||
Publisher: <$select tiddler=<<job>> field="publisher">
|
||||
<$list filter="[[publisher]modules[]moduleproperty[name]]">
|
||||
<option value=<<currentTiddler>>><$text text=<<currentTiddler>>/></option>
|
||||
</$list>
|
||||
</$select>
|
||||
|
||||
Base URL: <$edit-text tiddler=<<job>> size="50" field="baseurl"/>
|
||||
|
||||
Logs: <$view tiddler=<<job>> field="list"/>
|
||||
|
||||
<$set name="publisher-name" value={{{ [<job>get[publisher]] }}}>
|
||||
|
||||
<$set name="publisher-module" value={{{ [[publisher]modules[name],<publisher-name>] }}}>
|
||||
|
||||
<div class="tc-publishing-job-publisher">
|
||||
|
||||
<h2>Publisher: <$text text=<<publisher-name>>/></h2>
|
||||
|
||||
<$set name="publisher-ui" value={{{ [<publisher-module>modulestring[ui],{$:/language}] }}}>
|
||||
|
||||
<$tiddler tiddler=<<job>>>
|
||||
|
||||
<<publisher-ui>>
|
||||
|
||||
</$tiddler>
|
||||
|
||||
</$set>
|
||||
|
||||
</div>
|
||||
|
||||
<$vars sitemap={{{ [<job>get[sitemap]] }}}>
|
||||
|
||||
<div class="tc-publishing-sitemap">
|
||||
|
||||
<h2>Sitemap: <$link to=<<sitemap>>><$view tiddler=<<sitemap>> field="caption"><$text text=<<sitemap>>/></$view></$link></h2>
|
||||
|
||||
<$list filter="[<sitemap>get[list]enlist-input[]]" variable="route">
|
||||
|
||||
<div class="tc-publishing-route">
|
||||
|
||||
<h2>Route: <$link to=<<route>>><$view tiddler=<<route>> field="caption"><$text text=<<route>>/></$view></$link></h2>
|
||||
|
||||
route type: <$view tiddler=<<route>> field="route-type"/>
|
||||
|
||||
path: <$edit-text tiddler=<<route>> size="50" field="route-path"/>
|
||||
|
||||
filter: <$edit-text tiddler=<<route>> size="50" field="route-tiddler-filter"/>
|
||||
|
||||
template: <$edit-text tiddler=<<route>> size="50" field="route-template"/>
|
||||
|
||||
</div>
|
||||
|
||||
</$list>
|
||||
|
||||
</div>
|
||||
|
||||
</$vars>
|
||||
|
||||
</$set>
|
||||
|
||||
</$set>
|
||||
|
||||
</div>
|
||||
|
||||
</$list>
|
||||
|
||||
</div>
|
||||
@@ -1,53 +0,0 @@
|
||||
title: $:/core/ui/EditorToolbar/StampDropdown/ItemTemplate
|
||||
|
||||
<$linkcatcher actions="""
|
||||
|
||||
<$list filter="[<modifier>!match[ctrl]]" variable="ignore">
|
||||
|
||||
<$list filter="[<currentTiddler>addsuffix[/prefix]!is[tiddler]!is[shadow]removesuffix[/prefix]addsuffix[/suffix]!is[tiddler]!is[shadow]]" variable="ignore">
|
||||
|
||||
<$action-sendmessage
|
||||
$message="tm-edit-text-operation"
|
||||
$param="replace-selection"
|
||||
text={{{ [<currentTiddler>get[text]] }}}
|
||||
/>
|
||||
|
||||
</$list>
|
||||
|
||||
|
||||
<$list filter="[<currentTiddler>addsuffix[/prefix]] [<currentTiddler>addsuffix[/suffix]] +[is[shadow]] :else[is[tiddler]] +[limit[1]]" variable="ignore">
|
||||
|
||||
<$action-sendmessage
|
||||
$message="tm-edit-text-operation"
|
||||
$param="wrap-selection"
|
||||
prefix={{{ [<currentTiddler>addsuffix[/prefix]get[text]] }}}
|
||||
suffix={{{ [<currentTiddler>addsuffix[/suffix]get[text]] }}}
|
||||
/>
|
||||
|
||||
</$list>
|
||||
|
||||
</$list>
|
||||
|
||||
<$list filter="[<modifier>match[ctrl]]" variable="ignore">
|
||||
|
||||
<$action-sendmessage $message="tm-edit-tiddler"/>
|
||||
|
||||
</$list>
|
||||
|
||||
<$action-deletetiddler
|
||||
$tiddler=<<dropdown-state>>
|
||||
/>
|
||||
|
||||
""">
|
||||
|
||||
<$link tooltip={{{ [<currentTiddler>get[description]] }}}>
|
||||
|
||||
<$transclude tiddler=<<currentTiddler>> field="caption" mode="inline">
|
||||
|
||||
<$view tiddler=<<currentTiddler>> field="title" />
|
||||
|
||||
</$transclude>
|
||||
|
||||
</$link>
|
||||
|
||||
</$linkcatcher>
|
||||
@@ -1,6 +1,48 @@
|
||||
title: $:/core/ui/EditorToolbar/stamp-dropdown
|
||||
|
||||
<$macrocall $name="list-tagged-draggable" tag="$:/tags/TextEditor/Snippet" subFilter="!is[draft]" itemTemplate="$:/core/ui/EditorToolbar/StampDropdown/ItemTemplate"/>
|
||||
\define toolbar-button-stamp-inner()
|
||||
<$button tag="a">
|
||||
|
||||
<$list filter="[[$(snippetTitle)$]addsuffix[/prefix]is[missing]removesuffix[/prefix]addsuffix[/suffix]is[missing]]">
|
||||
|
||||
<$action-sendmessage
|
||||
$message="tm-edit-text-operation"
|
||||
$param="replace-selection"
|
||||
text={{$(snippetTitle)$}}
|
||||
/>
|
||||
|
||||
</$list>
|
||||
|
||||
|
||||
<$list filter="[[$(snippetTitle)$]addsuffix[/prefix]is[missing]removesuffix[/prefix]addsuffix[/suffix]!is[missing]] [[$(snippetTitle)$]addsuffix[/prefix]!is[missing]removesuffix[/prefix]addsuffix[/suffix]is[missing]] [[$(snippetTitle)$]addsuffix[/prefix]!is[missing]removesuffix[/prefix]addsuffix[/suffix]!is[missing]]">
|
||||
|
||||
<$action-sendmessage
|
||||
$message="tm-edit-text-operation"
|
||||
$param="wrap-selection"
|
||||
prefix={{{ [[$(snippetTitle)$]addsuffix[/prefix]get[text]] }}}
|
||||
suffix={{{ [[$(snippetTitle)$]addsuffix[/suffix]get[text]] }}}
|
||||
/>
|
||||
|
||||
</$list>
|
||||
|
||||
<$action-deletetiddler
|
||||
$tiddler=<<dropdown-state>>
|
||||
/>
|
||||
|
||||
<$transclude tiddler=<<snippetTitle>> field="caption" mode="inline">
|
||||
|
||||
<$view tiddler=<<snippetTitle>> field="title" />
|
||||
|
||||
</$transclude>
|
||||
|
||||
</$button>
|
||||
\end
|
||||
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/TextEditor/Snippet]!has[draft.of]sort[caption]]" variable="snippetTitle">
|
||||
|
||||
<<toolbar-button-stamp-inner>>
|
||||
|
||||
</$list>
|
||||
|
||||
----
|
||||
|
||||
|
||||
@@ -6,5 +6,4 @@ description: {{$:/language/Buttons/Stamp/Hint}}
|
||||
condition: [<targetTiddler>type[]] [<targetTiddler>get[type]prefix[text/]] [<targetTiddler>get[type]match[application/javascript]] [<targetTiddler>get[type]match[application/json]] [<targetTiddler>get[type]match[application/x-tiddler-dictionary]] [<targetTiddler>get[type]match[image/svg+xml]] +[first[]]
|
||||
shortcuts: ((stamp))
|
||||
dropdown: $:/core/ui/EditorToolbar/stamp-dropdown
|
||||
button-classes: tc-editortoolbar-stamp-button
|
||||
text:
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
title: $:/core/ui/ExportTiddlyWikiCore
|
||||
|
||||
\define jsFileName() tiddlywikicore-$(version)$.js
|
||||
\define noExportMsg()
|
||||
It appears that you have a wiki with an external ~TiddlyWiki core. The export action cannot be performed.
|
||||
<p>You will need to view the page source in your browser. Then go to the very bottom the the source, find the last `<script>`
|
||||
element, and right-click its `src` URI. Save the link as ''$(jsFileName)$''</p>
|
||||
\end
|
||||
|
||||
''For advanced users''
|
||||
|
||||
Export the ~TiddlyWiki core ~JavaScript code for running with external ~JavaScript:
|
||||
|
||||
<$button tooltip="Export the ~TiddlyWiki core code for running with external ~JavaScript" aria-label="export TiddlyWiki core" class="tc-btn-big-green">
|
||||
<$list filter="[[$:/boot/boot.js]is[missing]]" variable="ignore" emptyMessage="""<$action-sendmessage $message="tm-download-file" $param="$:/core/templates/tiddlywiki5.js" filename=<<jsFileName>>/>""" >
|
||||
<$action-setfield $tiddler=<<qualify "$:/temp/alert">> text=<<noExportMsg>> subtitle="Export ~TiddllyWiki Core"/>
|
||||
<$action-sendmessage $message="tm-modal" $param=<<qualify "$:/temp/alert">>/>
|
||||
</$list>
|
||||
{{$:/core/images/download-button}} Download ~TiddlyWiki core
|
||||
</$button>
|
||||
|
||||
[[Further information|https://tiddlywiki.com/#Using%20the%20external%20JavaScript%20template]]
|
||||
@@ -1,5 +1,9 @@
|
||||
title: $:/core/ui/ExportTiddlyWikiCore
|
||||
title: $:/core/ui/Buttons/export-tiddlywikicore
|
||||
tags: $:/tags/PageControls
|
||||
caption: {{$:/core/images/star-filled}} {{$:/language/Buttons/ExportTiddlyWikiCore/Caption}}
|
||||
description: {{$:/language/Buttons/ExportTiddlyWikiCore/Hint}}
|
||||
|
||||
\whitespace trim
|
||||
\define jsFileName() tiddlywikicore-$(version)$.js
|
||||
\define noExportMsg()
|
||||
It appears that you have a wiki with an external ~TiddlyWiki core. The export action cannot be performed.
|
||||
@@ -7,16 +11,15 @@ It appears that you have a wiki with an external ~TiddlyWiki core. The export ac
|
||||
element, and right-click its `src` URI. Save the link as ''$(jsFileName)$''</p>
|
||||
\end
|
||||
|
||||
''For advanced users''
|
||||
|
||||
Export the ~TiddlyWiki core ~JavaScript code for running with external ~JavaScript:
|
||||
|
||||
<$button tooltip="Export the ~TiddlyWiki core code for running with external ~JavaScript" aria-label="export TiddlyWiki core" class="tc-btn-big-green">
|
||||
<$button tooltip={{$:/language/Buttons/ExportTiddlyWikiCore/Hint}} aria-label={{$:/language/Buttons/ExportTiddlyWikiCore/Caption}} class=<<tv-config-toolbar-class>>>
|
||||
<$list filter="[[$:/boot/boot.js]is[missing]]" variable="ignore" emptyMessage="""<$action-sendmessage $message="tm-download-file" $param="$:/core/templates/tiddlywiki5.js" filename=<<jsFileName>>/>""" >
|
||||
<$action-setfield $tiddler=<<qualify "$:/temp/alert">> text=<<noExportMsg>> subtitle="Export ~TiddllyWiki Core"/>
|
||||
<$action-sendmessage $message="tm-modal" $param=<<qualify "$:/temp/alert">>/>
|
||||
</$list>
|
||||
{{$:/core/images/download-button}} Download ~TiddlyWiki core
|
||||
<$list filter="[<tv-config-toolbar-icons>match[yes]]" variable="listItem">
|
||||
{{$:/core/images/star-filled}}
|
||||
</$list>
|
||||
<$list filter="[<tv-config-toolbar-text>match[yes]]">
|
||||
<span class="tc-btn-text"><$text text={{$:/language/Buttons/ExportTiddlyWikiCore/Caption}}/></span>
|
||||
</$list>
|
||||
</$button>
|
||||
|
||||
[[Further information|https://tiddlywiki.com/#Using%20the%20external%20JavaScript%20template]]
|
||||
|
||||
19
core/ui/PageControls/publish.tid
Normal file
19
core/ui/PageControls/publish.tid
Normal file
@@ -0,0 +1,19 @@
|
||||
title: $:/core/ui/Buttons/publish
|
||||
tags: $:/tags/PageControls
|
||||
caption: {{$:/core/images/publish}} {{$:/language/Buttons/Publish/Caption}}
|
||||
description: {{$:/language/Buttons/Publish/Hint}}
|
||||
|
||||
\define publish-actions()
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/PublishingJob]has[enabled]field:enabled[yes]]" variable="job">
|
||||
<$action-sendmessage $message="tm-publish" job=<<job>>/>
|
||||
</$list>
|
||||
\end
|
||||
|
||||
<$button actions=<<publish-actions>> tooltip={{$:/language/Buttons/Publish/Hint}} aria-label={{$:/language/Buttons/Publish/Caption}} class=<<tv-config-toolbar-class>>>
|
||||
<$list filter="[<tv-config-toolbar-icons>match[yes]]">
|
||||
{{$:/core/images/publish}}
|
||||
</$list>
|
||||
<$list filter="[<tv-config-toolbar-text>match[yes]]">
|
||||
<span class="tc-btn-text"><$text text={{$:/language/Buttons/Publish/Caption}}/></span>
|
||||
</$list>
|
||||
</$button>
|
||||
@@ -1,15 +1,10 @@
|
||||
title: $:/core/ui/ViewTemplate
|
||||
|
||||
\whitespace trim
|
||||
\define folded-state()
|
||||
$:/state/folded/$(currentTiddler)$
|
||||
\end
|
||||
\define cancel-delete-tiddler-actions(message) <$action-sendmessage $message="tm-$message$-tiddler"/>
|
||||
\import [all[shadows+tiddlers]tag[$:/tags/Macro/View]!has[draft.of]]
|
||||
<$vars storyTiddler=<<currentTiddler>> tiddlerInfoState=<<qualify "$:/state/popup/tiddler-info">>>
|
||||
<div data-tiddler-title=<<currentTiddler>> data-tags={{!!tags}} class={{{ tc-tiddler-frame tc-tiddler-view-frame [<currentTiddler>is[tiddler]then[tc-tiddler-exists]] [<currentTiddler>is[missing]!is[shadow]then[tc-tiddler-missing]] [<currentTiddler>is[shadow]then[tc-tiddler-exists tc-tiddler-shadow]] [<currentTiddler>is[shadow]is[tiddler]then[tc-tiddler-overridden-shadow]] [<currentTiddler>is[system]then[tc-tiddler-system]] [{!!class}] [<currentTiddler>tags[]encodeuricomponent[]addprefix[tc-tagged-]] +[join[ ]] }}}>
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/ViewTemplate]!has[draft.of]]" variable="listItem">
|
||||
<$transclude tiddler=<<listItem>>/>
|
||||
</$list>
|
||||
<$vars storyTiddler=<<currentTiddler>> tiddlerInfoState=<<qualify "$:/state/popup/tiddler-info">>><div data-tiddler-title=<<currentTiddler>> data-tags={{!!tags}} class={{{ tc-tiddler-frame tc-tiddler-view-frame [<currentTiddler>is[tiddler]then[tc-tiddler-exists]] [<currentTiddler>is[missing]!is[shadow]then[tc-tiddler-missing]] [<currentTiddler>is[shadow]then[tc-tiddler-exists tc-tiddler-shadow]] [<currentTiddler>is[shadow]is[tiddler]then[tc-tiddler-overridden-shadow]] [<currentTiddler>is[system]then[tc-tiddler-system]] [{!!class}] [<currentTiddler>tags[]encodeuricomponent[]addprefix[tc-tagged-]] +[join[ ]] }}}><$list filter="[all[shadows+tiddlers]tag[$:/tags/ViewTemplate]!has[draft.of]]" variable="listItem"><$transclude tiddler=<<listItem>>/></$list>
|
||||
</div>
|
||||
</$vars>
|
||||
|
||||
@@ -5,10 +5,13 @@ tags: $:/tags/ViewTemplate
|
||||
\define title-styles()
|
||||
fill:$(foregroundColor)$;
|
||||
\end
|
||||
\define config-title()
|
||||
$:/config/ViewToolbarButtons/Visibility/$(listItem)$
|
||||
\end
|
||||
<div class="tc-tiddler-title">
|
||||
<div class="tc-titlebar">
|
||||
<span class="tc-tiddler-controls">
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/ViewToolbar]!has[draft.of]] :filter[lookup[$:/config/ViewToolbarButtons/Visibility/]!match[hide]]" storyview="pop" variable="listItem"><$set name="tv-config-toolbar-class" filter="[<tv-config-toolbar-class>] [<listItem>encodeuricomponent[]addprefix[tc-btn-]]"><$transclude tiddler=<<listItem>>/></$set></$list>
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/ViewToolbar]!has[draft.of]]" variable="listItem"><$reveal type="nomatch" state=<<config-title>> text="hide"><$set name="tv-config-toolbar-class" filter="[<tv-config-toolbar-class>] [<listItem>encodeuricomponent[]addprefix[tc-btn-]]"><$transclude tiddler=<<listItem>>/></$set></$reveal></$list>
|
||||
</span>
|
||||
<$set name="tv-wikilinks" value={{$:/config/Tiddlers/TitleLinks}}>
|
||||
<$link>
|
||||
@@ -40,4 +43,4 @@ fill:$(foregroundColor)$;
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/TiddlerInfoSegment]!has[draft.of]] [[$:/core/ui/TiddlerInfo]]" variable="listItem"><$transclude tiddler=<<listItem>> mode="block"/></$list>
|
||||
|
||||
</$reveal>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,2 +1,3 @@
|
||||
title: $:/config/EditTabIndex
|
||||
text: 1
|
||||
|
||||
1
|
||||
|
||||
@@ -4,6 +4,7 @@ core/ui/Buttons/advanced-search: hide
|
||||
core/ui/Buttons/close-all: hide
|
||||
core/ui/Buttons/encryption: hide
|
||||
core/ui/Buttons/export-page: hide
|
||||
core/ui/Buttons/export-tiddlywikicore: hide
|
||||
core/ui/Buttons/fold-all: hide
|
||||
core/ui/Buttons/full-screen: hide
|
||||
core/ui/Buttons/home: hide
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
title: $:/config/shortcuts-mac/
|
||||
|
||||
bold: meta-B
|
||||
input-tab-left: ctrl-Left
|
||||
input-tab-right: ctrl-Right
|
||||
italic: meta-I
|
||||
underline: meta-U
|
||||
new-image: ctrl-I
|
||||
|
||||
@@ -18,8 +18,8 @@ input-accept: Enter
|
||||
input-accept-variant: ctrl-Enter
|
||||
input-cancel: Escape
|
||||
input-down: Down
|
||||
input-tab-left: alt-ctrl-Left
|
||||
input-tab-right: alt-ctrl-Right
|
||||
input-tab-left: alt-Left
|
||||
input-tab-right: alt-Right
|
||||
input-up: Up
|
||||
layout-switcher: ctrl-shift-L
|
||||
link: ctrl-L
|
||||
|
||||
9
core/wiki/publishing-jobs/Default.tid
Normal file
9
core/wiki/publishing-jobs/Default.tid
Normal file
@@ -0,0 +1,9 @@
|
||||
title: $:/config/PublishingJobs/Default
|
||||
tags: $:/tags/PublishingJob
|
||||
caption: Demo static site
|
||||
publisher: filesystem
|
||||
sitemap: $:/core/sitemaps/StaticSite
|
||||
jszip-output-filename: myzipfile.zip
|
||||
baseurl: https://example.com
|
||||
enabled: yes
|
||||
export-filter: [!is[image]!is[system]] [is[image]!is[system]]
|
||||
7
core/wiki/routes/StaticSite/HTML.tid
Normal file
7
core/wiki/routes/StaticSite/HTML.tid
Normal file
@@ -0,0 +1,7 @@
|
||||
title: $:/core/routes/StaticSite/HTML
|
||||
caption: Static HTML
|
||||
tags: $:/tags/Route
|
||||
route-type: render
|
||||
route-path: static/$title_slugify$.html
|
||||
route-tiddler-filter: [!is[system]!is[image]]
|
||||
route-template: $:/core/templates/static.tiddler.html
|
||||
6
core/wiki/routes/StaticSite/Images.tid
Normal file
6
core/wiki/routes/StaticSite/Images.tid
Normal file
@@ -0,0 +1,6 @@
|
||||
title: $:/core/routes/StaticSite/Images
|
||||
caption: Images
|
||||
tags: $:/tags/Route
|
||||
route-type: raw
|
||||
route-path: images/$title_slugify$.$type_extension$
|
||||
route-tiddler-filter: [is[image]]
|
||||
6
core/wiki/routes/StaticSite/Index.tid
Normal file
6
core/wiki/routes/StaticSite/Index.tid
Normal file
@@ -0,0 +1,6 @@
|
||||
title: $:/core/routes/StaticSite/Index
|
||||
caption: Index
|
||||
tags: $:/tags/Route
|
||||
route-type: render
|
||||
route-path: index.html
|
||||
route-template: $:/core/save/all
|
||||
7
core/wiki/routes/StaticSite/Styles.tid
Normal file
7
core/wiki/routes/StaticSite/Styles.tid
Normal file
@@ -0,0 +1,7 @@
|
||||
title: $:/core/routes/StaticSite/Styles
|
||||
caption: Styles
|
||||
tags: $:/tags/Route
|
||||
route-type: render
|
||||
route-path: static/static.css
|
||||
route-template: $:/core/templates/static.template.css
|
||||
route-output-type: text/css
|
||||
9
core/wiki/sitemaps/StaticSite.tid
Normal file
9
core/wiki/sitemaps/StaticSite.tid
Normal file
@@ -0,0 +1,9 @@
|
||||
title: $:/core/sitemaps/StaticSite
|
||||
caption: Static site map
|
||||
description: The original TiddlyWiki 5 static file layout
|
||||
tags: $:/tags/SiteMap
|
||||
list: $:/core/routes/StaticSite/Index $:/core/routes/StaticSite/HTML $:/core/routes/StaticSite/Images $:/core/routes/StaticSite/Styles
|
||||
|
||||
\define tv-wikilink-template()
|
||||
$title_slugify$.html
|
||||
\end
|
||||
@@ -1,2 +1,2 @@
|
||||
title: $:/tags/ControlPanel/Plugins
|
||||
list: $:/core/ui/ControlPanel/Plugins/Installed/Plugins $:/core/ui/ControlPanel/Plugins/Installed/Themes $:/core/ui/ControlPanel/Plugins/Installed/Languages
|
||||
list: [[$:/core/ui/ControlPanel/Plugins/Installed]] [[$:/core/ui/ControlPanel/Plugins/Add]]
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
title: $:/tags/PageControls
|
||||
list: [[$:/core/ui/Buttons/home]] [[$:/core/ui/Buttons/close-all]] [[$:/core/ui/Buttons/fold-all]] [[$:/core/ui/Buttons/unfold-all]] [[$:/core/ui/Buttons/permaview]] [[$:/core/ui/Buttons/new-tiddler]] [[$:/core/ui/Buttons/new-journal]] [[$:/core/ui/Buttons/new-image]] [[$:/core/ui/Buttons/import]] [[$:/core/ui/Buttons/export-page]] [[$:/core/ui/Buttons/control-panel]] [[$:/core/ui/Buttons/advanced-search]] [[$:/core/ui/Buttons/manager]] [[$:/core/ui/Buttons/tag-manager]] [[$:/core/ui/Buttons/language]] [[$:/core/ui/Buttons/palette]] [[$:/core/ui/Buttons/theme]] [[$:/core/ui/Buttons/storyview]] [[$:/core/ui/Buttons/encryption]] [[$:/core/ui/Buttons/timestamp]] [[$:/core/ui/Buttons/full-screen]] [[$:/core/ui/Buttons/print]] [[$:/core/ui/Buttons/save-wiki]] [[$:/core/ui/Buttons/refresh]] [[$:/core/ui/Buttons/more-page-actions]]
|
||||
list: [[$:/core/ui/Buttons/home]] [[$:/core/ui/Buttons/close-all]] [[$:/core/ui/Buttons/fold-all]] [[$:/core/ui/Buttons/unfold-all]] [[$:/core/ui/Buttons/permaview]] [[$:/core/ui/Buttons/new-tiddler]] [[$:/core/ui/Buttons/new-journal]] [[$:/core/ui/Buttons/new-image]] [[$:/core/ui/Buttons/import]] [[$:/core/ui/Buttons/export-page]] [[$:/core/ui/Buttons/control-panel]] [[$:/core/ui/Buttons/advanced-search]] [[$:/core/ui/Buttons/manager]] [[$:/core/ui/Buttons/tag-manager]] [[$:/core/ui/Buttons/language]] [[$:/core/ui/Buttons/palette]] [[$:/core/ui/Buttons/theme]] [[$:/core/ui/Buttons/storyview]] [[$:/core/ui/Buttons/encryption]] [[$:/core/ui/Buttons/timestamp]] [[$:/core/ui/Buttons/full-screen]] [[$:/core/ui/Buttons/print]] [[$:/core/ui/Buttons/save-wiki]] [[$:/core/ui/Buttons/refresh]] [[$:/core/ui/Buttons/export-tiddlywikicore]] [[$:/core/ui/Buttons/more-page-actions]]
|
||||
|
||||
@@ -14,7 +14,6 @@ Welcome to the developer documentation for TiddlyWiki (https://tiddlywiki.com/).
|
||||
** HookMechanism
|
||||
** [[Using ES2016 for Writing Plugins]]
|
||||
** [[Adding Babel Polyfill to TiddlyWiki]]
|
||||
** [[TiddlyWiki Drag and Drop Interoperability]]
|
||||
* The original developer documentation from https://tiddlywiki.com:
|
||||
** [[TiddlyWiki for Developers]]
|
||||
** [[TiddlyWiki Coding Style Guidelines]]
|
||||
|
||||
@@ -37,6 +37,8 @@ Example:
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
|
||||
!!! With encryption
|
||||
|
||||
If the ~TiddlyWiki is configured to encrypt its content, the tiddlers are stored as as an encrypted JSON string in a `<pre>` tag with the `id` attribute "encryptedStoreArea".
|
||||
@@ -81,20 +83,15 @@ Any tiddlers in the older format `<div>` store area are also loaded before tiddl
|
||||
|
||||
Tiddlers from the new `<script>` tag store areas are loaded in the order of their store areas in the HTML file. Therefore if the same tiddler exists in two different `<script>` tag store areas, the tiddler from the later store area takes precedence. Note however that tiddlers from `<script>` tag store areas always take precedence over tiddlers from the older format `<div>` store area. Therefore a tiddler from the older `<div>` store area can never overwrite a tiddler from a `<script>` tag store area.
|
||||
|
||||
Note that all `<script>` tags with the `class` attribute "tiddlywiki-tiddler-store" that precede the `$:/boot.js` module in the HTML file will have their content parsed as JSON and loaded as tiddlers.
|
||||
|
||||
This allows external tools to easily insert tiddlers into an HTML file by prepending an additional `<script>` tag(s) at the very start of the HTML file:
|
||||
Note that all `<script>` tags with the `class` attribute "tiddlywiki-tiddler-store" have their content parsed as JSON and loaded as tiddlers. This allows external tools to easily insert tiddlers into an HTML file by appending additional `<script>` tag(s) at the very end of the HTML file:
|
||||
|
||||
```html
|
||||
</html>
|
||||
<script class="tiddlywiki-tiddler-store" type="application/json">[
|
||||
{"created":"20210525212411223","text":"This is some test text","tags":"[[test tag]] [[another tag]]","title":"My new tiddler to insert","modified":"20210525212430577"}
|
||||
]</script>
|
||||
<!doctype html>
|
||||
...
|
||||
```
|
||||
|
||||
Although invalid HTML, all known browsers will silently move the script tag to a valid position within the
|
||||
|
||||
Additional topics:
|
||||
|
||||
* [[Extracting tiddlers from a single file TiddlyWiki]]
|
||||
@@ -1,15 +0,0 @@
|
||||
title: TiddlyWiki Drag and Drop Interoperability
|
||||
|
||||
It is straightforward to allow any HTML file to interoperate with TiddlyWiki's drag and drop implementation.
|
||||
|
||||
This example shows how to attach draggable data to a DOM element. The data is provided in two different forms:
|
||||
|
||||
* the string data is used if the element is dragged onto a text editing area
|
||||
* the tiddler data is used if the element is dragged into TiddlyWiki's import area
|
||||
|
||||
<$button>
|
||||
<$action-sendmessage $message="tm-download-file" $param="$:/dev/save/dragndropinterop" filename="index.html"/>
|
||||
Download this sample code
|
||||
</$button>
|
||||
|
||||
<$codeblock code={{DragAndDropInterop}} language="text/html"/>
|
||||
@@ -1,35 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Drag and Drop Interoperability with TiddlyWiki Demo</title>
|
||||
<style>
|
||||
#draggable {
|
||||
padding: 1em;
|
||||
margin: 1em;
|
||||
background: #ecc;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="draggable" draggable="true">
|
||||
Drag me to a TiddlyWiki window
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
|
||||
var titleString = "This is the string that appears when the block is dragged to a text input";
|
||||
var tiddlerData = [
|
||||
{title: "Tiddler One", text: "This is one of the payload tiddlers"},
|
||||
{title: "Tiddler Two", text: "This is another of the payload tiddlers", "custom-field": "A custom field value"}
|
||||
];
|
||||
|
||||
document.getElementById("draggable").addEventListener("dragstart",function(event) {
|
||||
event.dataTransfer.setData("URL","data:text/vnd.tiddler," + encodeURIComponent(JSON.stringify(tiddlerData)));
|
||||
event.dataTransfer.setData("Text",titleString);
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
});
|
||||
|
||||
</script>
|
||||
</html>
|
||||
@@ -1,3 +0,0 @@
|
||||
title: DragAndDropInterop
|
||||
type: text/html
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
title: $:/dev/save/dragndropinterop
|
||||
|
||||
<$view tiddler="DragAndDropInterop" field="text"/>
|
||||
@@ -1,13 +1,15 @@
|
||||
title: $:/core/ui/ViewTemplate
|
||||
|
||||
\whitespace trim
|
||||
\define frame-classes()
|
||||
tc-tiddler-frame tc-tiddler-view-frame $(missingTiddlerClass)$ $(shadowTiddlerClass)$ $(systemTiddlerClass)$ $(tiddlerTagClasses)$ $(userClass)$
|
||||
\end
|
||||
\define folded-state()
|
||||
$:/state/folded/$(currentTiddler)$
|
||||
\end
|
||||
\define cancel-delete-tiddler-actions(message) <$action-sendmessage $message="tm-$message$-tiddler"/>
|
||||
\import [all[shadows+tiddlers]tag[$:/tags/Macro/View]!has[draft.of]]
|
||||
<$vars storyTiddler=<<currentTiddler>> tiddlerInfoState=<<qualify "$:/state/popup/tiddler-info">>>
|
||||
<div data-tiddler-title=<<currentTiddler>> data-tags={{!!tags}} class={{{ tc-tiddler-frame tc-tiddler-view-frame [<currentTiddler>is[tiddler]then[tc-tiddler-exists]] [<currentTiddler>is[missing]!is[shadow]then[tc-tiddler-missing]] [<currentTiddler>is[shadow]then[tc-tiddler-exists tc-tiddler-shadow]] [<currentTiddler>is[shadow]is[tiddler]then[tc-tiddler-overridden-shadow]] [<currentTiddler>is[system]then[tc-tiddler-system]] [{!!class}] [<currentTiddler>tags[]encodeuricomponent[]addprefix[tc-tagged-]] +[join[ ]] }}}>
|
||||
<$vars storyTiddler=<<currentTiddler>> tiddlerInfoState=<<qualify "$:/state/popup/tiddler-info">> userClass={{!!class}}>
|
||||
<$tiddler tiddler=<<currentTiddler>>>
|
||||
<div data-tiddler-title=<<currentTiddler>> data-tags={{!!tags}} class=<<frame-classes>>>
|
||||
<$set name="state" value={{{ [[$:/state/viewtemplate/visibility/]addsuffix<currentTiddler>] }}}>
|
||||
<$reveal stateTitle=<<state>> type="nomatch" text="" default="" tag="div">
|
||||
<div class="tc-dynaview-track-tiddler-when-visible" data-dynaview-track-tiddler=<<state>>>
|
||||
@@ -22,4 +24,5 @@ $:/state/folded/$(currentTiddler)$
|
||||
</$reveal>
|
||||
</$set>
|
||||
</div>
|
||||
</$tiddler>
|
||||
</$vars>
|
||||
|
||||
@@ -54,7 +54,7 @@ title="New tiddler"
|
||||
|
||||
#* Asígnale la etiqueta <<.tag ~$:/tags/ViewToolbar]]>>
|
||||
|
||||
# Hay que crear un tiddler que le diga a ~TiddlyWIki si el botón será o no visible en la barra. Llamémosle por ejemplo <<.tid "~$:/config/ViewToolbarButtons/Visibility/Receta"">>. Escribe `show` en el cuerpo y guárdalo.
|
||||
# Hay que crear un tiddler que le diga a ~TiddlyWIki si el botón será o no visible en la barra. Llamémosle por ejemplo <<.tid "~$:/config/ViewToolbarButtons/Visibility/Receta"">>. Escribe `reveal` en el cuerpo y guárdalo.
|
||||
|
||||
# Habrá que posicionar el botón adecuadamente. Abre el tiddler <<.tid ~$:/tags/ViewToolbar>> e inserta el nombre de tu botón en el lugar adecuado del campo <<.field list>>.
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ Imaginons que vous ayez un tiddler squelette appelé 'Modèle Recette', et que v
|
||||
|
||||
# Pour illustrer votre bouton, si aucune des images du noyau (tiddlers shadow préfixés par $:/core/images/ ) n'est à votre convenance, vous devrez la créer ou en obtenir une au format SVG (par exemple, une de celles de http://flaticon.com), glissez-la dans votre fichier pour la transformer en tiddler, modifiez le tiddler et ajustez sa hauteur et sa largeur à 22px
|
||||
#Passons au tiddler contenant votre tiddler. Créez-le, titrez-le et ajoutez le code du bouton (voir le code ci-dessous par exemple, en l'adaptant à vos besoins si nécessaire) Étiquetez-le par [[$:/tags/ViewToolbar]]
|
||||
#Contrôlons la visibilité de votre tiddler dans la barre d'outil par la création d'un tiddler à titrer [[$:/config/ViewToolbarButtons/Visibility/Recette]]. Saisissez `show`dans la zone texte et sauvegardez.
|
||||
#Contrôlons la visibilité de votre tiddler dans la barre d'outil par la création d'un tiddler à titrer [[$:/config/ViewToolbarButtons/Visibility/Recette]]. Saisissez `reveal`dans la zone texte et sauvegardez.
|
||||
#Enfin, positionnons le bouton proprement. Ouvrez le tiddler $:/tags/ViewToolbar et insérez le titre de votre tiddler bouton (cf. titre étape précédente) dans le champ field au bon endroit.
|
||||
|
||||
```
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
{
|
||||
"description": "Innerwiki Plugin Demo",
|
||||
"plugins": [
|
||||
"tiddlywiki/innerwiki",
|
||||
"tiddlywiki/railroad"
|
||||
"tiddlywiki/innerwiki"
|
||||
],
|
||||
"themes": [
|
||||
"tiddlywiki/vanilla",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user