1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-12-02 22:39:56 +00:00

Merge branch 'upstream/master'

# Conflicts:
#	core/modules/server/routes/get-tiddlers-json.js
This commit is contained in:
mrichter 2020-12-05 19:05:35 +01:00
commit 41bb3af451
191 changed files with 2967 additions and 528 deletions

View File

@ -305,13 +305,21 @@ $tw.utils.stringifyDate = function(value) {
// Parse a date from a UTC YYYYMMDDHHMMSSmmm format string
$tw.utils.parseDate = function(value) {
if(typeof value === "string") {
return new Date(Date.UTC(parseInt(value.substr(0,4),10),
var negative = 1;
if(value.charAt(0) === "-") {
negative = -1;
value = value.substr(1);
}
var year = parseInt(value.substr(0,4),10) * negative,
d = new Date(Date.UTC(year,
parseInt(value.substr(4,2),10)-1,
parseInt(value.substr(6,2),10),
parseInt(value.substr(8,2)||"00",10),
parseInt(value.substr(10,2)||"00",10),
parseInt(value.substr(12,2)||"00",10),
parseInt(value.substr(14,3)||"000",10)));
d.setUTCFullYear(year); // See https://stackoverflow.com/a/5870822
return d;
} else if($tw.utils.isDate(value)) {
return value;
} else {
@ -1886,7 +1894,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
});
});
if(isEditableFile) {
tiddlers.push({filepath: pathname, hasMetaFile: !!metadata && !isTiddlerFile, tiddlers: fileTiddlers});
tiddlers.push({filepath: pathname, hasMetaFile: !!metadata && !isTiddlerFile, isEditableFile: true, tiddlers: fileTiddlers});
} else {
tiddlers.push({tiddlers: fileTiddlers});
}
@ -1912,15 +1920,21 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
}
} else {
// Process directory specifier
var dirPath = path.resolve(filepath,dirSpec.path),
files = fs.readdirSync(dirPath),
fileRegExp = new RegExp(dirSpec.filesRegExp || "^.*$"),
metaRegExp = /^.*\.meta$/;
for(var t=0; t<files.length; t++) {
var filename = files[t];
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
processFile(dirPath + path.sep + filename,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile);
var dirPath = path.resolve(filepath,dirSpec.path);
if(fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
var files = fs.readdirSync(dirPath),
fileRegExp = new RegExp(dirSpec.filesRegExp || "^.*$"),
metaRegExp = /^.*\.meta$/;
for(var t=0; t<files.length; t++) {
var filename = files[t];
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
processFile(dirPath + path.sep + filename,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile);
}
}
} else {
console.log("Warning: a directory in a tiddlywiki.files file does not exist.");
console.log("dirPath: " + dirPath);
console.log("tiddlywiki.files location: " + filepath);
}
}
});
@ -2060,6 +2074,11 @@ $tw.loadWikiTiddlers = function(wikiPath,options) {
} else {
return null;
}
// Save the path to the tiddlers folder for the filesystemadaptor
var config = wikiInfo.config || {};
if($tw.boot.wikiPath == wikiPath) {
$tw.boot.wikiTiddlersPath = path.resolve($tw.boot.wikiPath,config["default-tiddler-location"] || $tw.config.wikiTiddlersSubDir);
}
// Load any parent wikis
if(wikiInfo.includeWikis) {
parentPaths = parentPaths.slice(0);
@ -2093,27 +2112,30 @@ $tw.loadWikiTiddlers = function(wikiPath,options) {
$tw.boot.files[tiddler.title] = {
filepath: tiddlerFile.filepath,
type: tiddlerFile.type,
hasMetaFile: tiddlerFile.hasMetaFile
hasMetaFile: tiddlerFile.hasMetaFile,
isEditableFile: config["retain-original-tiddler-path"] || tiddlerFile.isEditableFile || tiddlerFile.filepath.indexOf($tw.boot.wikiTiddlersPath) !== 0
};
});
}
$tw.wiki.addTiddlers(tiddlerFile.tiddlers);
});
// Save the original tiddler file locations if requested
var config = wikiInfo.config || {};
if(config["retain-original-tiddler-path"]) {
var output = {}, relativePath;
if ($tw.boot.wikiPath == wikiPath) {
// Save the original tiddler file locations if requested
var output = {}, relativePath, fileInfo;
for(var title in $tw.boot.files) {
relativePath = path.relative(resolvedWikiPath,$tw.boot.files[title].filepath);
output[title] =
path.sep === "/" ?
relativePath :
relativePath.split(path.sep).join("/");
fileInfo = $tw.boot.files[title];
if(fileInfo.isEditableFile) {
relativePath = path.relative($tw.boot.wikiTiddlersPath,fileInfo.filepath);
output[title] =
path.sep === "/" ?
relativePath :
relativePath.split(path.sep).join("/");
}
}
if(Object.keys(output).length > 0){
$tw.wiki.addTiddler({title: "$:/config/OriginalTiddlerPaths", type: "application/json", text: JSON.stringify(output)});
}
$tw.wiki.addTiddler({title: "$:/config/OriginalTiddlerPaths", type: "application/json", text: JSON.stringify(output)});
}
// Save the path to the tiddlers folder for the filesystemadaptor
$tw.boot.wikiTiddlersPath = path.resolve($tw.boot.wikiPath,config["default-tiddler-location"] || $tw.config.wikiTiddlersSubDir);
// Load any plugins within the wiki folder
var wikiPluginsPath = path.resolve(wikiPath,$tw.config.wikiPluginsSubDir);
if(fs.existsSync(wikiPluginsPath)) {
@ -2160,7 +2182,7 @@ $tw.loadTiddlersNode = function() {
// Load any extra plugins
$tw.utils.each($tw.boot.extraPlugins,function(name) {
if(name.charAt(0) === "+") { // Relative path to plugin
var pluginFields = $tw.loadPluginFolder(name.substring(1));;
var pluginFields = $tw.loadPluginFolder(name.substring(1));
if(pluginFields) {
$tw.wiki.addTiddler(pluginFields);
}

View File

@ -17,6 +17,8 @@ Basics/NewJournal/Tags/Prompt: Tags for new journal tiddlers
Basics/NewTiddler/Title/Prompt: Title of new tiddlers
Basics/NewTiddler/Tags/Prompt: Tags for new tiddlers
Basics/OverriddenShadowTiddlers/Prompt: Number of overridden shadow tiddlers
Basics/RemoveTags: Update to current format
Basics/RemoveTags/Hint: Update the tags configuration to the latest format
Basics/ShadowTiddlers/Prompt: Number of shadow tiddlers
Basics/Subtitle/Prompt: Subtitle
Basics/SystemTiddlers/Prompt: Number of system tiddlers
@ -44,6 +46,7 @@ KeyboardShortcuts/Platform/Linux: Linux platform only
KeyboardShortcuts/Platform/NonLinux: Non-Linux platforms only
KeyboardShortcuts/Platform/Windows: Windows platform only
KeyboardShortcuts/Platform/NonWindows: Non-Windows platforms only
LayoutSwitcher/Caption: Layout
LoadedModules/Caption: Loaded Modules
LoadedModules/Hint: These are the currently loaded tiddler modules linked to their source tiddlers. Any italicised modules lack a source tiddler, typically because they were setup during the boot process.
Palette/Caption: Palette
@ -125,6 +128,7 @@ Saving/TiddlySpot/Filename: Upload Filename
Saving/TiddlySpot/Heading: ~TiddlySpot
Saving/TiddlySpot/Hint: //The server URL defaults to `http://<wikiname>.tiddlyspot.com/store.cgi` and can be changed to use a custom server address, e.g. `http://example.com/store.php`.//
Saving/TiddlySpot/Password: Password
Saving/TiddlySpot/ReadOnly: ~TiddlySpot service may currently be available as read only. Please see http://tiddlyspot.com/ for details
Saving/TiddlySpot/ServerURL: Server URL
Saving/TiddlySpot/UploadDir: Upload Directory
Saving/TiddlySpot/UserName: Wiki Name

View File

@ -18,11 +18,11 @@ Listing/Rename/Prompt: Rename to:
Listing/Rename/ConfirmRename: Rename tiddler
Listing/Rename/CancelRename: Cancel
Listing/Rename/OverwriteWarning: A tiddler with this title already exists.
Upgrader/Plugins/Suppressed/Incompatible: Blocked incompatible or obsolete plugin
Upgrader/Plugins/Suppressed/Version: Blocked plugin (due to incoming <<incoming>> being older than existing <<existing>>)
Upgrader/Plugins/Upgraded: Upgraded plugin from <<incoming>> to <<upgraded>>
Upgrader/State/Suppressed: Blocked temporary state tiddler
Upgrader/System/Suppressed: Blocked system tiddler
Upgrader/System/Warning: Core module tiddler
Upgrader/System/Alert: You are about to import a tiddler that will overwrite a core module tiddler. This is not recommended as it may make the system unstable
Upgrader/ThemeTweaks/Created: Migrated theme tweak from <$text text=<<from>>/>
Upgrader/Plugins/Suppressed/Incompatible: Blocked incompatible or obsolete plugin.
Upgrader/Plugins/Suppressed/Version: Blocked plugin (due to incoming <<incoming>> not being newer than existing <<existing>>).
Upgrader/Plugins/Upgraded: Upgraded plugin from <<incoming>> to <<upgraded>>.
Upgrader/State/Suppressed: Blocked temporary state tiddler.
Upgrader/System/Suppressed: Blocked system tiddler.
Upgrader/System/Warning: Core module tiddler.
Upgrader/System/Alert: You are about to import a tiddler that will overwrite a core module tiddler. This is not recommended as it may make the system unstable.
Upgrader/ThemeTweaks/Created: Migrated theme tweak from <$text text=<<from>>/>.

View File

@ -40,6 +40,7 @@ Error/XMLHttpRequest: XMLHttpRequest error code
InternalJavaScriptError/Title: Internal JavaScript Error
InternalJavaScriptError/Hint: Well, this is embarrassing. It is recommended that you restart TiddlyWiki by refreshing your browser
InvalidFieldName: Illegal characters in field name "<$text text=<<fieldName>>/>". Fields can only contain lowercase letters, digits and the characters underscore (`_`), hyphen (`-`) and period (`.`)
LayoutSwitcher/Description: Open the layout switcher
LazyLoadingWarning: <p>Trying to load external content from ''<$text text={{!!_canonical_uri}}/>''</p><p>If this message doesn't disappear, either the tiddler content type doesn't match the type of the external content, or you may be using a browser that doesn't support external content for wikis loaded as standalone files. See https://tiddlywiki.com/#ExternalText</p>
LoginToTiddlySpace: Login to TiddlySpace
Manager/Controls/FilterByTag/None: (none)
@ -63,6 +64,8 @@ MissingTiddler/Hint: Missing tiddler "<$text text=<<currentTiddler>>/>" -- click
No: No
OfficialPluginLibrary: Official ~TiddlyWiki Plugin Library
OfficialPluginLibrary/Hint: The official ~TiddlyWiki plugin library at tiddlywiki.com. Plugins, themes and language packs are maintained by the core team.
PageTemplate/Description: the default ~TiddlyWiki layout
PageTemplate/Name: Default ~PageTemplate
PluginReloadWarning: Please save {{$:/core/ui/Buttons/save-wiki}} and reload {{$:/core/ui/Buttons/refresh}} to allow changes to ~JavaScript plugins to take effect
RecentChanges/DateFormat: DDth MMM YYYY
Shortcuts/Input/AdvancedSearch/Hint: Open the ~AdvancedSearch panel from within the sidebar search field
@ -74,6 +77,10 @@ Shortcuts/Input/Tab-Left/Hint: Select the previous Tab
Shortcuts/Input/Tab-Right/Hint: Select the next Tab
Shortcuts/Input/Up/Hint: Select the previous item
Shortcuts/SidebarLayout/Hint: Change the sidebar layout
Switcher/Subtitle/theme: Switch Theme
Switcher/Subtitle/layout: Switch Layout
Switcher/Subtitle/language: Switch Language
Switcher/Subtitle/palette: Switch Palette
SystemTiddler/Tooltip: This is a system tiddler
SystemTiddlers/Include/Prompt: Include system tiddlers
TagManager/Colour/Heading: Colour

View File

@ -14,7 +14,7 @@ List/Caption: List
List/Empty: This tiddler does not have a list
Listed/Caption: Listed
Listed/Empty: This tiddler is not listed by any others
References/Caption: References
References/Caption: Backlinks
References/Empty: No tiddlers link to this one
Tagging/Caption: Tagging
Tagging/Empty: No tiddlers are tagged with this one

View File

@ -42,7 +42,6 @@ function FramedEngine(options) {
this.iframeNode.style.border = "none";
this.iframeNode.style.padding = "0";
this.iframeNode.style.resize = "none";
this.iframeNode.style["background-color"] = this.widget.wiki.extractTiddlerDataItem(this.widget.wiki.getTiddlerText("$:/palette"),"tiddler-editor-background");
this.iframeDoc.body.style.margin = "0";
this.iframeDoc.body.style.padding = "0";
this.widget.domNodes.push(this.iframeNode);
@ -74,6 +73,9 @@ function FramedEngine(options) {
if(this.widget.editTabIndex) {
this.iframeNode.setAttribute("tabindex",this.widget.editTabIndex);
}
if(this.widget.editAutoComplete) {
this.domNode.setAttribute("autocomplete",this.widget.editAutoComplete);
}
if(this.widget.isDisabled === "yes") {
this.domNode.setAttribute("disabled",true);
}
@ -100,7 +102,6 @@ FramedEngine.prototype.copyStyles = function() {
this.domNode.style.display = "block";
this.domNode.style.width = "100%";
this.domNode.style.margin = "0";
this.domNode.style["background-color"] = this.widget.wiki.extractTiddlerDataItem(this.widget.wiki.getTiddlerText("$:/palette"),"tiddler-editor-background");
// In Chrome setting -webkit-text-fill-color overrides the placeholder text colour
this.domNode.style["-webkit-text-fill-color"] = "currentcolor";
};

View File

@ -52,6 +52,9 @@ function SimpleEngine(options) {
if(this.widget.editTabIndex) {
this.domNode.setAttribute("tabindex",this.widget.editTabIndex);
}
if(this.widget.editAutoComplete) {
this.domNode.setAttribute("autocomplete",this.widget.editAutoComplete);
}
if(this.widget.isDisabled === "yes") {
this.domNode.setAttribute("disabled",true);
}

View File

@ -180,6 +180,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
this.editCancelPopups = this.getAttribute("cancelPopups","") === "yes";
this.editInputActions = this.getAttribute("inputActions");
this.editRefreshTitle = this.getAttribute("refreshTitle");
this.editAutoComplete = this.getAttribute("autocomplete");
this.isDisabled = this.getAttribute("disabled","no");
// Get the default editor element tag and type
var tag,type;
@ -212,7 +213,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
EditTextWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
// Completely rerender if any of our attributes have changed
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedAttributes.disabled) {
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedAttributes.disabled) {
this.refreshSelf();
return true;
} else if (changedTiddlers[this.editRefreshTitle]) {

View File

@ -16,10 +16,10 @@ Equivalent to + filter run prefix.
/*
Export our filter prefix function
*/
exports.and = function(operationSubFunction) {
exports.and = function(operationSubFunction,options) {
return function(results,source,widget) {
// This replaces all the elements of the array, but keeps the actual array so that references to it are preserved
source = $tw.wiki.makeTiddlerIterator(results);
source = options.wiki.makeTiddlerIterator(results);
results.splice(0,results.length);
$tw.utils.pushTop(results,operationSubFunction(source,widget));
};

View File

@ -0,0 +1,49 @@
/*\
title: $:/core/modules/filterrunprefixes/reduce.js
type: application/javascript
module-type: filterrunprefix
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter prefix function
*/
exports.reduce = function(operationSubFunction,options) {
return function(results,source,widget) {
if(results.length > 0) {
var accumulator = "";
for(var index=0; index<results.length; index++) {
var title = results[index],
list = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
getVariable: function(name) {
switch(name) {
case "currentTiddler":
return "" + title;
case "accumulator":
return "" + accumulator;
case "index":
return "" + index;
case "revIndex":
return "" + (results.length - 1 - index);
case "length":
return "" + results.length;
default:
return widget.getVariable(name);
}
}
});
if(list.length > 0) {
accumulator = "" + list[0];
}
}
results.splice(0,results.length);
results.push(accumulator);
}
}
};
})();

View File

@ -188,7 +188,7 @@ exports.getFilterOperators = function() {
};
exports.getFilterRunPrefixes = function() {
if(!this.filterPrefixes) {
if(!this.filterRunPrefixes) {
$tw.Wiki.prototype.filterRunPrefixes = {};
$tw.modules.applyMethods("filterrunprefix",this.filterRunPrefixes);
}
@ -280,20 +280,21 @@ exports.compileFilter = function(filterString) {
var filterRunPrefixes = self.getFilterRunPrefixes();
// Wrap the operator functions in a wrapper function that depends on the prefix
operationFunctions.push((function() {
var options = {wiki: self};
switch(operation.prefix || "") {
case "": // No prefix means that the operation is unioned into the result
return filterRunPrefixes["or"](operationSubFunction);
return filterRunPrefixes["or"](operationSubFunction, options);
case "=": // The results of the operation are pushed into the result without deduplication
return filterRunPrefixes["all"](operationSubFunction);
return filterRunPrefixes["all"](operationSubFunction, options);
case "-": // The results of this operation are removed from the main result
return filterRunPrefixes["except"](operationSubFunction);
return filterRunPrefixes["except"](operationSubFunction, options);
case "+": // This operation is applied to the main results so far
return filterRunPrefixes["and"](operationSubFunction);
return filterRunPrefixes["and"](operationSubFunction, options);
case "~": // This operation is unioned into the result only if the main result so far is empty
return filterRunPrefixes["else"](operationSubFunction);
return filterRunPrefixes["else"](operationSubFunction, options);
default:
if(operation.namedPrefix && filterRunPrefixes[operation.namedPrefix]) {
return filterRunPrefixes[operation.namedPrefix](operationSubFunction);
return filterRunPrefixes[operation.namedPrefix](operationSubFunction, options);
} else {
return function(results,source,widget) {
results.splice(0,results.length);

View File

@ -77,7 +77,7 @@ exports.encodehtml = function(source,operator,options) {
exports.stringify = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
results.push($tw.utils.stringify(title));
results.push($tw.utils.stringify(title,(operator.suffix === "rawunicode")));
});
return results;
};
@ -85,7 +85,7 @@ exports.stringify = function(source,operator,options) {
exports.jsonstringify = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
results.push($tw.utils.jsonStringify(title));
results.push($tw.utils.jsonStringify(title,(operator.suffix === "rawunicode")));
});
return results;
};

View File

@ -22,7 +22,7 @@ Export our filter function
exports.lookup = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
results.push(options.wiki.getTiddlerText(operator.operand + title) || options.wiki.getTiddlerText(operator.operand + operator.suffix));
results.push(options.wiki.getTiddlerText(operator.operand + title) || operator.suffix);
});
return results;
};

View File

@ -91,6 +91,20 @@ exports.exponential = makeNumericBinaryOperator(
function(a,b) {return Number.prototype.toExponential.call(a,Math.min(Math.max(b,0),100));}
);
exports.power = makeNumericBinaryOperator(
function(a,b) {return Math.pow(a,b);}
);
exports.log = makeNumericBinaryOperator(
function(a,b) {
if(b) {
return Math.log(a)/Math.log(b);
} else {
return Math.log(a);
}
}
);
exports.sum = makeNumericReducingOperator(
function(accumulator,value) {return accumulator + value},
0 // Initial value

View File

@ -23,7 +23,7 @@ exports.reduce = function(source,operator,options) {
});
// Run the filter over each item
var filterFn = options.wiki.compileFilter(operator.operand),
accumulator = operator.suffix || "";
accumulator = operator.operands[1] || "";
for(var index=0; index<results.length; index++) {
var title = results[index],
list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),{

View File

@ -61,7 +61,7 @@ exports.split = makeStringBinaryOperator(
);
exports["enlist-input"] = makeStringBinaryOperator(
function(a) {return $tw.utils.parseStringArray("" + a);}
function(a,o,s) {return $tw.utils.parseStringArray("" + a,(s === "raw"));}
);
exports.join = makeStringReducingOperator(
@ -78,7 +78,7 @@ function makeStringBinaryOperator(fnCalc) {
return function(source,operator,options) {
var result = [];
source(function(tiddler,title) {
Array.prototype.push.apply(result,fnCalc(title,operator.operand || ""));
Array.prototype.push.apply(result,fnCalc(title,operator.operand || "",operator.suffix || ""));
});
return result;
};
@ -143,4 +143,33 @@ exports["search-replace"] = function(source,operator,options) {
return results;
};
exports.pad = function(source,operator,options) {
var results = [],
targetLength = operator.operand ? parseInt(operator.operand) : 0,
fill = operator.operands[1] || "0";
source(function(tiddler,title) {
if(title && title.length) {
if(title.length >= targetLength) {
results.push(title);
} else {
var padString = "",
padStringLength = targetLength - title.length;
while (padStringLength > padString.length) {
padString += fill;
}
//make sure we do not exceed the specified length
padString = padString.slice(0,padStringLength);
if(operator.suffix && (operator.suffix === "suffix")) {
title = title + padString;
} else {
title = padString + title;
}
results.push(title);
}
}
});
return results;
}
})();

View File

@ -188,23 +188,25 @@ Extended filter operators to manipulate the current list.
return set;
};
var cycleValueInArray = function(results,operands) {
var cycleValueInArray = function(results,operands,stepSize) {
var resultsIndex,
step = stepSize || 1,
i = 0,
opLength = operands.length,
nextOperandIndex;
for(i; i < operands.length; i++) {
for(i; i < opLength; i++) {
resultsIndex = results.indexOf(operands[i]);
if(resultsIndex !== -1) {
break;
}
}
if(resultsIndex !== -1) {
i++;
nextOperandIndex = (i === operands.length ? 0 : i);
i = i + step;
nextOperandIndex = (i < opLength ? i : i - opLength);
if(operands.length > 1) {
results.splice(resultsIndex,1,operands[nextOperandIndex]);
} else {
results.splice(resultsIndex,1,);
results.splice(resultsIndex,1);
}
} else {
results.push(operands[0]);
@ -221,11 +223,13 @@ Extended filter operators to manipulate the current list.
exports.cycle = function(source,operator) {
var results = prepare_results(source),
operands = (operator.operand.length ? $tw.utils.parseStringArray(operator.operand, "true") : [""]);
if(operator.suffix === "reverse") {
operands = (operator.operand.length ? $tw.utils.parseStringArray(operator.operand, "true") : [""]),
step = $tw.utils.getInt(operator.operands[1]||"",1);
if(step < 0) {
operands.reverse();
}
return cycleValueInArray(results,operands);
step = Math.abs(step);
}
return cycleValueInArray(results,operands,step);
}
})();
})();

View File

@ -12,7 +12,7 @@ Initialise basic platform $:/info/ tiddlers
/*global $tw: false */
"use strict";
exports.getInfoTiddlerFields = function() {
exports.getInfoTiddlerFields = function(updateInfoTiddlersCallback) {
var mapBoolean = function(value) {return value ? "yes" : "no";},
infoTiddlerFields = [];
// Basics
@ -36,6 +36,13 @@ exports.getInfoTiddlerFields = function() {
// Screen size
infoTiddlerFields.push({title: "$:/info/browser/screen/width", text: window.screen.width.toString()});
infoTiddlerFields.push({title: "$:/info/browser/screen/height", text: window.screen.height.toString()});
// Dark mode through event listener on MediaQueryList
var mqList = window.matchMedia("(prefers-color-scheme: dark)"),
getDarkModeTiddler = function() {return {title: "$:/info/darkmode", text: mqList.matches ? "yes" : "no"};};
infoTiddlerFields.push(getDarkModeTiddler());
mqList.addListener(function(event) {
updateInfoTiddlersCallback([getDarkModeTiddler()]);
});
// Language
infoTiddlerFields.push({title: "$:/info/browser/language", text: navigator.language || ""});
}

View File

@ -386,22 +386,18 @@ Amend the rules used by this instance of the parser
WikiParser.prototype.amendRules = function(type,names) {
names = names || [];
// Define the filter function
var keepFilter;
var target;
if(type === "only") {
keepFilter = function(name) {
return names.indexOf(name) !== -1;
};
target = true;
} else if(type === "except") {
keepFilter = function(name) {
return names.indexOf(name) === -1;
};
target = false;
} else {
return;
}
// Define a function to process each of our rule arrays
var processRuleArray = function(ruleArray) {
for(var t=ruleArray.length-1; t>=0; t--) {
if(!keepFilter(ruleArray[t].rule.name)) {
if((names.indexOf(ruleArray[t].rule.name) === -1) === target) {
ruleArray.splice(t,1);
}
}

View File

@ -197,8 +197,12 @@ SaverHandler.prototype.isDirty = function() {
Update the document body with the class "tc-dirty" if the wiki has unsaved/unsynced changes
*/
SaverHandler.prototype.updateDirtyStatus = function() {
var self = this;
if($tw.browser) {
$tw.utils.toggleClass(document.body,"tc-dirty",this.isDirty());
$tw.utils.each($tw.windows,function(win) {
$tw.utils.toggleClass(win.document.body,"tc-dirty",self.isDirty());
});
}
};

View File

@ -26,12 +26,13 @@ GitHubSaver.prototype.save = function(text,method,callback) {
repo = this.wiki.getTiddlerText("$:/GitHub/Repo"),
path = this.wiki.getTiddlerText("$:/GitHub/Path",""),
filename = this.wiki.getTiddlerText("$:/GitHub/Filename"),
branch = this.wiki.getTiddlerText("$:/GitHub/Branch") || "master",
branch = this.wiki.getTiddlerText("$:/GitHub/Branch") || "main",
endpoint = this.wiki.getTiddlerText("$:/GitHub/ServerURL") || "https://api.github.com",
headers = {
"Accept": "application/vnd.github.v3+json",
"Content-Type": "application/json;charset=UTF-8",
"Authorization": "Basic " + window.btoa(username + ":" + password)
"Authorization": "Basic " + window.btoa(username + ":" + password),
"If-None-Match": ""
};
// Bail if we don't have everything we need
if(!username || !password || !repo || !filename) {

View File

@ -29,6 +29,9 @@ exports.handler = function(request,response,state) {
}
}
filter = filter + "-[subfilter{$:/config/Server/GlobalExclusionFilter}]";
if(state.wiki.getTiddlerText("$:/config/SyncSystemTiddlersFromServer") === "no") {
filter += "+[!is[system]]";
}
var excludeFields = (state.queryParameters.exclude || "text").split(","),
titles = state.wiki.filterTiddlers(filter);
response.writeHead(200, {"Content-Type": "application/json"});

View File

@ -21,29 +21,37 @@ exports.synchronous = true;
var TITLE_INFO_PLUGIN = "$:/temp/info-plugin";
exports.startup = function() {
// Function to bake the info plugin with new tiddlers
var updateInfoPlugin = function(tiddlerFieldsArray) {
// Get the existing tiddlers
var json = $tw.wiki.getTiddlerData(TITLE_INFO_PLUGIN,{tiddlers: {}});
// Add the new ones
$tw.utils.each(tiddlerFieldsArray,function(fields) {
if(fields && fields.title) {
json.tiddlers[fields.title] = fields;
}
});
// Bake the info tiddlers into a plugin. We use the non-standard plugin-type "info" because ordinary plugins are only registered asynchronously after being loaded dynamically
var fields = {
title: TITLE_INFO_PLUGIN,
type: "application/json",
"plugin-type": "info",
text: JSON.stringify(json,null,$tw.config.preferences.jsonSpaces)
};
$tw.wiki.addTiddler(new $tw.Tiddler(fields));
};
// Collect up the info tiddlers
var infoTiddlerFields = {};
// Give each info module a chance to fill in as many info tiddlers as they want
var tiddlerFieldsArray = [];
// Give each info module a chance to provide as many info tiddlers as they want as an array, and give them a callback for dynamically updating them
$tw.modules.forEachModuleOfType("info",function(title,moduleExports) {
if(moduleExports && moduleExports.getInfoTiddlerFields) {
var tiddlerFieldsArray = moduleExports.getInfoTiddlerFields(infoTiddlerFields);
$tw.utils.each(tiddlerFieldsArray,function(fields) {
if(fields) {
infoTiddlerFields[fields.title] = fields;
}
});
Array.prototype.push.apply(tiddlerFieldsArray,moduleExports.getInfoTiddlerFields(updateInfoPlugin));
}
});
// Bake the info tiddlers into a plugin. We use the non-standard plugin-type "info" because ordinary plugins are only registered asynchronously after being loaded dynamically
var fields = {
title: TITLE_INFO_PLUGIN,
type: "application/json",
"plugin-type": "info",
text: JSON.stringify({tiddlers: infoTiddlerFields},null,$tw.config.preferences.jsonSpaces)
};
$tw.wiki.addTiddler(new $tw.Tiddler(fields));
$tw.wiki.readPluginInfo([TITLE_INFO_PLUGIN]);
$tw.wiki.registerPluginTiddlers("info");
updateInfoPlugin(tiddlerFieldsArray);
var changes = $tw.wiki.readPluginInfo([TITLE_INFO_PLUGIN]);
$tw.wiki.registerPluginTiddlers("info",[TITLE_INFO_PLUGIN]);
$tw.wiki.unpackPluginTiddlers();
};

View File

@ -24,6 +24,7 @@ var PREFIX_CONFIG_REGISTER_PLUGIN_TYPE = "$:/config/RegisterPluginType/";
exports.startup = function() {
$tw.wiki.addTiddler({title: TITLE_REQUIRE_RELOAD_DUE_TO_PLUGIN_CHANGE,text: "no"});
$tw.wiki.addEventListener("change",function(changes) {
// Work out which of the changed tiddlers are plugins that we need to reregister
var changesToProcess = [],
requireReloadDueToPluginChange = false;
$tw.utils.each(Object.keys(changes),function(title) {
@ -38,6 +39,7 @@ exports.startup = function() {
}
}
});
// Issue warning if any of the tiddlers require a reload
if(requireReloadDueToPluginChange) {
$tw.wiki.addTiddler({title: TITLE_REQUIRE_RELOAD_DUE_TO_PLUGIN_CHANGE,text: "yes"});
}
@ -45,12 +47,35 @@ exports.startup = function() {
if(changesToProcess.length > 0) {
var changes = $tw.wiki.readPluginInfo(changesToProcess);
if(changes.modifiedPlugins.length > 0 || changes.deletedPlugins.length > 0) {
var changedShadowTiddlers = {};
// Collect the shadow tiddlers of any deleted plugins
$tw.utils.each(changes.deletedPlugins,function(pluginTitle) {
var pluginInfo = $tw.wiki.getPluginInfo(pluginTitle);
if(pluginInfo) {
$tw.utils.each(Object.keys(pluginInfo.tiddlers),function(title) {
changedShadowTiddlers[title] = true;
});
}
});
// Collect the shadow tiddlers of any modified plugins
$tw.utils.each(changes.modifiedPlugins,function(pluginTitle) {
var pluginInfo = $tw.wiki.getPluginInfo(pluginTitle);
if(pluginInfo) {
$tw.utils.each(Object.keys(pluginInfo.tiddlers),function(title) {
changedShadowTiddlers[title] = false;
});
}
});
// (Re-)register any modified plugins
$tw.wiki.registerPluginTiddlers(null,changes.modifiedPlugins);
// Unregister any deleted plugins
$tw.wiki.unregisterPluginTiddlers(null,changes.deletedPlugins);
// Unpack the shadow tiddlers
$tw.wiki.unpackPluginTiddlers();
// Queue change events for the changed shadow tiddlers
$tw.utils.each(Object.keys(changedShadowTiddlers),function(title) {
$tw.wiki.enqueueTiddlerEvent(title,changedShadowTiddlers[title]);
});
}
}
});

View File

@ -107,7 +107,7 @@ exports.startup = function() {
$tw.rootWidget.domNodes = [$tw.pageContainer];
$tw.rootWidget.children = [$tw.pageWidgetNode];
// Run any post-render startup actions
$tw.rootWidget.executeStartupTiddlers("$:/tags/StartupAction/PostRender");
$tw.rootWidget.invokeActionsByTag("$:/tags/StartupAction/PostRender");
};
})();

View File

@ -25,6 +25,9 @@ exports.startup = function() {
$tw.rootWidget.addEventListener("tm-modal",function(event) {
$tw.modal.display(event.param,{variables: event.paramObject, event: event});
});
$tw.rootWidget.addEventListener("tm-show-switcher",function(event) {
$tw.modal.display("$:/core/ui/SwitcherModal",{variables: event.paramObject, event: event});
});
// Install the notification mechanism
$tw.notifier = new $tw.utils.Notifier($tw.wiki);
$tw.rootWidget.addEventListener("tm-notify",function(event) {

View File

@ -64,12 +64,12 @@ exports.startup = function() {
document: $tw.browser ? document : $tw.fakeDocument
});
// Execute any startup actions
$tw.rootWidget.executeStartupTiddlers("$:/tags/StartupAction");
$tw.rootWidget.invokeActionsByTag("$:/tags/StartupAction");
if($tw.browser) {
$tw.rootWidget.executeStartupTiddlers("$:/tags/StartupAction/Browser");
$tw.rootWidget.invokeActionsByTag("$:/tags/StartupAction/Browser");
}
if($tw.node) {
$tw.rootWidget.executeStartupTiddlers("$:/tags/StartupAction/Node");
$tw.rootWidget.invokeActionsByTag("$:/tags/StartupAction/Node");
}
// Kick off the language manager and switcher
$tw.language = new $tw.Language();

View File

@ -19,7 +19,7 @@ exports.after = ["startup"];
exports.synchronous = true;
// Global to keep track of open windows (hashmap by title)
var windows = {};
$tw.windows = {};
exports.startup = function() {
// Handle open window message
@ -44,7 +44,7 @@ exports.startup = function() {
catch(e) {
return;
}
windows[title] = srcWindow;
$tw.windows[title] = srcWindow;
// Check for reopening the same window
if(srcWindow.haveInitialisedWindow) {
return;
@ -54,7 +54,7 @@ exports.startup = function() {
srcDocument.close();
srcDocument.title = windowTitle;
srcWindow.addEventListener("beforeunload",function(event) {
delete windows[title];
delete $tw.windows[title];
$tw.wiki.removeEventListener("change",refreshHandler);
},false);
// Set up the styles
@ -84,16 +84,13 @@ exports.startup = function() {
name: "keydown",
handlerObject: $tw.keyboardManager,
handlerMethod: "handleKeydownEvent"
},{
name: "click",
handlerObject: $tw.popup,
handlerMethod: "handleEvent"
}]);
srcWindow.document.documentElement.addEventListener("click",$tw.popup,true);
srcWindow.haveInitialisedWindow = true;
});
// Close open windows when unloading main window
$tw.addUnloadTask(function() {
$tw.utils.each(windows,function(win) {
$tw.utils.each($tw.windows,function(win) {
win.close();
});
});

View File

@ -305,7 +305,8 @@ Syncer.prototype.syncFromServer = function() {
self.pollTimerId = null;
self.syncFromServer.call(self);
},self.pollTimerInterval);
};
},
syncSystemFromServer = (self.wiki.getTiddlerText("$:/config/SyncSystemTiddlersFromServer") === "yes" ? true : false);
if(this.syncadaptor && this.syncadaptor.getUpdatedTiddlers) {
this.logger.log("Retrieving updated tiddler list");
cancelNextSync();
@ -320,9 +321,11 @@ Syncer.prototype.syncFromServer = function() {
self.titlesToBeLoaded[title] = true;
});
$tw.utils.each(updates.deletions,function(title) {
delete self.tiddlerInfo[title];
self.logger.log("Deleting tiddler missing from server:",title);
self.wiki.deleteTiddler(title);
if(syncSystemFromServer || !self.wiki.isSystemTiddler(title)) {
delete self.tiddlerInfo[title];
self.logger.log("Deleting tiddler missing from server:",title);
self.wiki.deleteTiddler(title);
}
});
if(updates.modifications.length > 0 || updates.deletions.length > 0) {
self.processTaskQueue();
@ -365,9 +368,11 @@ Syncer.prototype.syncFromServer = function() {
}
// Delete any tiddlers that were previously reported but missing this time
$tw.utils.each(previousTitles,function(title) {
delete self.tiddlerInfo[title];
self.logger.log("Deleting tiddler missing from server:",title);
self.wiki.deleteTiddler(title);
if(syncSystemFromServer || !self.wiki.isSystemTiddler(title)) {
delete self.tiddlerInfo[title];
self.logger.log("Deleting tiddler missing from server:",title);
self.wiki.deleteTiddler(title);
}
});
self.processTaskQueue();
});
@ -628,6 +633,10 @@ DeleteTiddlerTask.prototype.run = function(callback) {
}
// Remove the info stored about this tiddler
delete self.syncer.tiddlerInfo[self.title];
if($tw.boot.files){
// Remove the tiddler from $tw.boot.files
delete $tw.boot.files[self.title];
}
// Invoke the callback
callback(null);
},{

View File

@ -57,7 +57,7 @@ exports.upgrade = function(wiki,titles,tiddlers) {
// Reject the incoming plugin by blanking all its fields
if($tw.utils.checkVersions(existingTiddler.fields.version,incomingTiddler.version)) {
tiddlers[title] = Object.create(null);
messages[title] = requiresReload + $tw.language.getString("Import/Upgrader/Plugins/Suppressed/Version",{variables: {incoming: incomingTiddler.version, existing: existingTiddler.fields.version}});
messages[title] = $tw.language.getString("Import/Upgrader/Plugins/Suppressed/Version",{variables: {incoming: incomingTiddler.version, existing: existingTiddler.fields.version}});
return;
}
}

View File

@ -204,15 +204,19 @@ exports.deleteEmptyDirs = function(dirpath,callback) {
/*
Create a fileInfo object for saving a tiddler:
filepath: the absolute path to the file containing the tiddler
type: the type of the tiddler file (NOT the type of the tiddler)
type: the type of the tiddler file on disk (NOT the type of the tiddler)
hasMetaFile: true if the file also has a companion .meta file
isEditableFile: true if the tiddler was loaded via non-standard options & marked editable
Options include:
directory: absolute path of root directory to which we are saving
pathFilters: optional array of filters to be used to generate the base path
wiki: optional wiki for evaluating the pathFilters
extFilters: optional array of filters to be used to generate the base path
wiki: optional wiki for evaluating the pathFilters,
fileInfo: an existing fileInfo to check against
originalpath: a preferred filepath if no pathFilters match
*/
exports.generateTiddlerFileInfo = function(tiddler,options) {
var fileInfo = {};
var fileInfo = {}, metaExt;
// Check if the tiddler has any unsafe fields that can't be expressed in a .tid or .meta file: containing control characters, or leading/trailing whitespace
var hasUnsafeFields = false;
$tw.utils.each(tiddler.getFieldStrings(),function(value,fieldName) {
@ -238,19 +242,71 @@ exports.generateTiddlerFileInfo = function(tiddler,options) {
fileInfo.type = tiddlerType;
fileInfo.hasMetaFile = true;
}
if(options.extFilters) {
// Check for extension override
metaExt = $tw.utils.generateTiddlerExtension(tiddler.fields.title,{
extFilters: options.extFilters,
wiki: options.wiki
});
if(metaExt === ".tid") {
// Overriding to the .tid extension needs special handling
fileInfo.type = "application/x-tiddler";
fileInfo.hasMetaFile = false;
} else if (metaExt === ".json") {
// Overriding to the .json extension needs special handling
fileInfo.type = "application/json";
fileInfo.hasMetaFile = false;
} else if (metaExt) {
//If the new type matches a known extention, use that MIME type's encoding
var extInfo = $tw.utils.getFileExtensionInfo(metaExt);
fileInfo.type = extInfo ? extInfo.type : null;
fileInfo.encoding = $tw.utils.getTypeEncoding(metaExt);
fileInfo.hasMetaFile = true;
}
}
}
// Take the file extension from the tiddler content type
// Take the file extension from the tiddler content type or metaExt
var contentTypeInfo = $tw.config.contentTypeInfo[fileInfo.type] || {extension: ""};
// Generate the filepath
fileInfo.filepath = $tw.utils.generateTiddlerFilepath(tiddler.fields.title,{
extension: contentTypeInfo.extension,
extension: metaExt || contentTypeInfo.extension,
directory: options.directory,
pathFilters: options.pathFilters,
wiki: options.wiki
wiki: options.wiki,
fileInfo: options.fileInfo,
originalpath: options.originalpath
});
// Propigate the isEditableFile flag
if(options.fileInfo) {
fileInfo.isEditableFile = options.fileInfo.isEditableFile || false;
}
return fileInfo;
};
/*
Generate the file extension for saving a tiddler
Options include:
extFilters: optional array of filters to be used to generate the extention
wiki: optional wiki for evaluating the extFilters
*/
exports.generateTiddlerExtension = function(title,options) {
var self = this,
extension;
// Check if any of the extFilters applies
if(options.extFilters && options.wiki) {
$tw.utils.each(options.extFilters,function(filter) {
if(!extension) {
var source = options.wiki.makeTiddlerIterator([title]),
result = options.wiki.filterTiddlers(filter,null,source);
if(result.length > 0) {
extension = result[0];
}
}
});
}
return extension;
};
/*
Generate the filepath for saving a tiddler
Options include:
@ -258,12 +314,14 @@ Options include:
directory: absolute path of root directory to which we are saving
pathFilters: optional array of filters to be used to generate the base path
wiki: optional wiki for evaluating the pathFilters
fileInfo: an existing fileInfo object to check against
*/
exports.generateTiddlerFilepath = function(title,options) {
var self = this,
directory = options.directory || "",
extension = options.extension || "",
filepath;
originalpath = options.originalpath || "",
filepath;
// Check if any of the pathFilters applies
if(options.pathFilters && options.wiki) {
$tw.utils.each(options.pathFilters,function(filter) {
@ -276,8 +334,11 @@ exports.generateTiddlerFilepath = function(title,options) {
}
});
}
// If not, generate a base pathname
if(!filepath) {
if(!filepath && originalpath !== "") {
//Use the originalpath without the extension
var ext = path.extname(originalpath);
filepath = originalpath.substring(0,originalpath.length - ext.length);;
} else if(!filepath) {
filepath = title;
// If the filepath already ends in the extension then remove it
if(filepath.substring(filepath.length - extension.length) === extension) {
@ -286,10 +347,13 @@ exports.generateTiddlerFilepath = function(title,options) {
// Remove any forward or backward slashes so we don't create directories
filepath = filepath.replace(/\/|\\/g,"_");
}
// Don't let the filename start with a dot because such files are invisible on *nix
filepath = filepath.replace(/^\./g,"_");
//If the path does not start with "." or ".." and a path seperator, then
if(!/^\.{1,2}[/\\]/g.test(filepath)) {
// Don't let the filename start with any dots because such files are invisible on *nix
filepath = filepath.replace(/^\.+/g,"_");
}
// Remove any characters that can't be used in cross-platform filenames
filepath = $tw.utils.transliterate(filepath.replace(/<|>|\:|\"|\||\?|\*|\^/g,"_"));
filepath = $tw.utils.transliterate(filepath.replace(/<|>|~|\:|\"|\||\?|\*|\^/g,"_"));
// Truncate the filename if it is too long
if(filepath.length > 200) {
filepath = filepath.substr(0,200);
@ -306,12 +370,21 @@ exports.generateTiddlerFilepath = function(title,options) {
});
}
// Add a uniquifier if the file already exists
var fullPath,
var fullPath, oldPath = (options.fileInfo) ? options.fileInfo.filepath : undefined,
count = 0;
do {
fullPath = path.resolve(directory,filepath + (count ? "_" + count : "") + extension);
if(oldPath && oldPath == fullPath) {
break;
}
count++;
} while(fs.existsSync(fullPath));
//If the path does not start with the wikiPath directory or the wikiTiddlersPath directory, or if the last write failed
var encode = !(fullPath.indexOf($tw.boot.wikiPath) == 0 || fullPath.indexOf($tw.boot.wikiTiddlersPath) == 0) || ((options.fileInfo || {writeError: false}).writeError == true);
if(encode){
//encodeURIComponent() and then resolve to tiddler directory
fullPath = path.resolve(directory, encodeURIComponent(fullPath));
}
// Return the full path to the file
return fullPath;
};
@ -366,4 +439,58 @@ exports.saveTiddlerToFileSync = function(tiddler,fileInfo) {
}
};
/*
Delete a file described by the fileInfo if it exits
*/
exports.deleteTiddlerFile = function(fileInfo, callback) {
//Only attempt to delete files that exist on disk
if(!fileInfo.filepath || !fs.existsSync(fileInfo.filepath)) {
return callback(null);
}
// Delete the file
fs.unlink(fileInfo.filepath,function(err) {
if(err) {
return callback(err);
}
// Delete the metafile if present
if(fileInfo.hasMetaFile && fs.existsSync(fileInfo.filepath + ".meta")) {
fs.unlink(fileInfo.filepath + ".meta",function(err) {
if(err) {
return callback(err);
}
return $tw.utils.deleteEmptyDirs(path.dirname(fileInfo.filepath),callback);
});
} else {
return $tw.utils.deleteEmptyDirs(path.dirname(fileInfo.filepath),callback);
}
});
};
/*
Cleanup old files on disk, by comparing the options values:
adaptorInfo from $tw.syncer.tiddlerInfo
bootInfo from $tw.boot.files
*/
exports.cleanupTiddlerFiles = function(options, callback) {
var adaptorInfo = options.adaptorInfo || {},
bootInfo = options.bootInfo || {},
title = options.title || "undefined";
if(adaptorInfo.filepath && bootInfo.filepath && adaptorInfo.filepath !== bootInfo.filepath) {
return $tw.utils.deleteTiddlerFile(adaptorInfo, function(err){
if(err) {
if ((err.code == "EPERM" || err.code == "EACCES") && err.syscall == "unlink") {
// Error deleting the previous file on disk, should fail gracefully
$tw.syncer.displayError("Server desynchronized. Error cleaning up previous file for tiddler: "+title, err);
return callback(null);
} else {
return callback(err);
}
}
return callback(null);
});
} else {
return callback(null);
}
};
})();

View File

@ -302,7 +302,7 @@ exports.formatDateString = function(date,template) {
return $tw.utils.pad($tw.utils.getHours12(date));
}],
[/^wYYYY/, function() {
return $tw.utils.getYearForWeekNo(date);
return $tw.utils.pad($tw.utils.getYearForWeekNo(date),4);
}],
[/^hh12/, function() {
return $tw.utils.getHours12(date);
@ -311,7 +311,14 @@ exports.formatDateString = function(date,template) {
return date.getDate() + $tw.utils.getDaySuffix(date);
}],
[/^YYYY/, function() {
return date.getFullYear();
return $tw.utils.pad(date.getFullYear(),4);
}],
[/^aYYYY/, function() {
return $tw.utils.pad(Math.abs(date.getFullYear()),4);
}],
[/^\{era:([^,\|}]*)\|([^}\|]*)\|([^}]*)\}/, function(match) {
var year = date.getFullYear();
return year === 0 ? match[2] : (year < 0 ? match[1] : match[3]);
}],
[/^0hh/, function() {
return $tw.utils.pad(date.getHours());
@ -400,7 +407,7 @@ exports.formatDateString = function(date,template) {
$tw.utils.each(matches, function(m) {
var match = m[0].exec(t);
if(match) {
matchString = m[1].call();
matchString = m[1].call(null,match);
t = t.substr(match[0].length);
return false;
}
@ -557,7 +564,7 @@ exports.escape = function(ch) {
// Turns a string into a legal JavaScript string
// Copied from peg.js, thanks to David Majda
exports.stringify = function(s) {
exports.stringify = function(s, rawUnicode) {
/*
* ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a string
* literal except for the closing quote character, backslash, carriage return,
@ -566,19 +573,21 @@ exports.stringify = function(s) {
*
* For portability, we also escape all non-ASCII characters.
*/
var regex = rawUnicode ? /[\x00-\x1f]/g : /[\x00-\x1f\x80-\uFFFF]/g;
return (s || "")
.replace(/\\/g, '\\\\') // backslash
.replace(/"/g, '\\"') // double quote character
.replace(/'/g, "\\'") // single quote character
.replace(/\r/g, '\\r') // carriage return
.replace(/\n/g, '\\n') // line feed
.replace(/[\x00-\x1f\x80-\uFFFF]/g, exports.escape); // non-ASCII characters
.replace(regex, exports.escape); // non-ASCII characters
};
// Turns a string into a legal JSON string
// Derived from peg.js, thanks to David Majda
exports.jsonStringify = function(s) {
exports.jsonStringify = function(s, rawUnicode) {
// See http://www.json.org/
var regex = rawUnicode ? /[\x00-\x1f]/g : /[\x00-\x1f\x80-\uFFFF]/g;
return (s || "")
.replace(/\\/g, '\\\\') // backslash
.replace(/"/g, '\\"') // double quote character
@ -587,7 +596,7 @@ exports.jsonStringify = function(s) {
.replace(/\x08/g, '\\b') // backspace
.replace(/\x0c/g, '\\f') // formfeed
.replace(/\t/g, '\\t') // tab
.replace(/[\x00-\x1f\x80-\uFFFF]/g,function(s) {
.replace(regex,function(s) {
return '\\u' + $tw.utils.pad(s.charCodeAt(0).toString(16).toUpperCase(),4);
}); // non-ASCII characters
};

View File

@ -28,23 +28,66 @@ Render this widget into the DOM
*/
LogWidget.prototype.render = function(parent,nextSibling) {
this.computeAttributes();
this.execute();
};
LogWidget.prototype.execute = function(){
this.message = this.getAttribute("$$message","debug");
this.logAll = this.getAttribute("$$all","no") === "yes" ? true : false;
this.filter = this.getAttribute("$$filter");
}
/*
Refresh the widget by ensuring our attributes are up to date
*/
LogWidget.prototype.refresh = function(changedTiddlers) {
return this.refreshChildren(changedTiddlers);
this.refreshSelf();
return true;
};
/*
Invoke the action associated with this widget
*/
LogWidget.prototype.invokeAction = function(triggeringWidget,event) {
$tw.utils.logTable(this.attributes,["attribute name","value"]);
this.log();
return true; // Action was invoked
};
LogWidget.prototype.log = function() {
var data = {},
dataCount,
allVars = {},
filteredVars;
$tw.utils.each(this.attributes,function(attribute,name) {
if(name.substring(0,2) !== "$$") {
data[name] = attribute;
}
});
for(var v in this.variables) {
allVars[v] = this.getVariable(v,{defaultValue:""});
}
if(this.filter) {
filteredVars = this.wiki.compileFilter(this.filter).call(this.wiki,this.wiki.makeTiddlerIterator(allVars));
$tw.utils.each(filteredVars,function(name) {
data[name] = allVars[name];
});
}
dataCount = $tw.utils.count(data);
console.group(this.message);
if(dataCount > 0) {
$tw.utils.logTable(data,["name","value"]);
}
if(this.logAll || !dataCount) {
console.groupCollapsed("All variables");
$tw.utils.logTable(allVars,["name","value"]);
console.groupEnd();
}
console.groupEnd();
}
exports["action-log"] = LogWidget;
})();

View File

@ -27,18 +27,20 @@ ButtonWidget.prototype = new Widget();
Render this widget into the DOM
*/
ButtonWidget.prototype.render = function(parent,nextSibling) {
var self = this;
var self = this,
tag = "button",
domNode;
// Remember parent
this.parentDomNode = parent;
// Compute attributes and execute state
this.computeAttributes();
this.execute();
// Create element
var tag = "button";
if(this.buttonTag && $tw.config.htmlUnsafeElements.indexOf(this.buttonTag) === -1) {
tag = this.buttonTag;
}
var domNode = this.document.createElement(tag);
domNode = this.document.createElement(tag);
this.domNode = domNode;
// Assign classes
var classes = this["class"].split(" ") || [],
isPoppedUp = (this.popup || this.popupTitle) && this.isPoppedUp();
@ -200,10 +202,10 @@ ButtonWidget.prototype.execute = function() {
this.setTo = this.getAttribute("setTo");
this.popup = this.getAttribute("popup");
this.hover = this.getAttribute("hover");
this["class"] = this.getAttribute("class","");
this["aria-label"] = this.getAttribute("aria-label");
this.tooltip = this.getAttribute("tooltip");
this.style = this.getAttribute("style");
this["class"] = this.getAttribute("class","");
this.selectedClass = this.getAttribute("selectedClass");
this.defaultSetValue = this.getAttribute("default","");
this.buttonTag = this.getAttribute("tag");
@ -219,14 +221,34 @@ ButtonWidget.prototype.execute = function() {
this.makeChildWidgets();
};
ButtonWidget.prototype.updateDomNodeClasses = function() {
var domNodeClasses = this.domNode.className.split(" "),
oldClasses = this.class.split(" "),
newClasses;
this["class"] = this.getAttribute("class","");
newClasses = this.class.split(" ");
//Remove classes assigned from the old value of class attribute
$tw.utils.each(oldClasses,function(oldClass){
var i = domNodeClasses.indexOf(oldClass);
if(i !== -1) {
domNodeClasses.splice(i,1);
}
});
//Add new classes from updated class attribute.
$tw.utils.pushTop(domNodeClasses,newClasses);
this.domNode.className = domNodeClasses.join(" ");
}
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
ButtonWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.actions || changedAttributes.to || changedAttributes.message || changedAttributes.param || changedAttributes.set || changedAttributes.setTo || changedAttributes.popup || changedAttributes.hover || changedAttributes["class"] || changedAttributes.selectedClass || changedAttributes.style || changedAttributes.dragFilter || changedAttributes.dragTiddler || (this.set && changedTiddlers[this.set]) || (this.popup && changedTiddlers[this.popup]) || (this.popupTitle && changedTiddlers[this.popupTitle]) || changedAttributes.setTitle || changedAttributes.setField || changedAttributes.setIndex || changedAttributes.popupTitle || changedAttributes.disabled) {
if(changedAttributes.actions || changedAttributes.to || changedAttributes.message || changedAttributes.param || changedAttributes.set || changedAttributes.setTo || changedAttributes.popup || changedAttributes.hover || changedAttributes.selectedClass || changedAttributes.style || changedAttributes.dragFilter || changedAttributes.dragTiddler || (this.set && changedTiddlers[this.set]) || (this.popup && changedTiddlers[this.popup]) || (this.popupTitle && changedTiddlers[this.popupTitle]) || changedAttributes.setTitle || changedAttributes.setField || changedAttributes.setIndex || changedAttributes.popupTitle || changedAttributes.disabled) {
this.refreshSelf();
return true;
} else if(changedAttributes["class"]) {
this.updateDomNodeClasses();
}
return this.refreshChildren(changedTiddlers);
};

View File

@ -27,21 +27,21 @@ DroppableWidget.prototype = new Widget();
Render this widget into the DOM
*/
DroppableWidget.prototype.render = function(parent,nextSibling) {
var self = this;
var self = this,
tag = this.parseTreeNode.isBlock ? "div" : "span",
domNode;
// Remember parent
this.parentDomNode = parent;
// Compute attributes and execute state
this.computeAttributes();
this.execute();
var tag = this.parseTreeNode.isBlock ? "div" : "span";
if(this.droppableTag && $tw.config.htmlUnsafeElements.indexOf(this.droppableTag) === -1) {
tag = this.droppableTag;
}
// Create element and assign classes
var domNode = this.document.createElement(tag),
classes = (this.droppableClass || "").split(" ");
classes.push("tc-droppable");
domNode.className = classes.join(" ");
domNode = this.document.createElement(tag);
this.domNode = domNode;
this.assignDomNodeClasses();
// Add event handlers
if(this.droppableEnable) {
$tw.utils.addEventListeners(domNode,[
@ -144,20 +144,27 @@ DroppableWidget.prototype.execute = function() {
this.droppableActions = this.getAttribute("actions");
this.droppableEffect = this.getAttribute("effect","copy");
this.droppableTag = this.getAttribute("tag");
this.droppableClass = this.getAttribute("class");
this.droppableEnable = (this.getAttribute("enable") || "yes") === "yes";
// Make child widgets
this.makeChildWidgets();
};
DroppableWidget.prototype.assignDomNodeClasses = function() {
var classes = this.getAttribute("class","").split(" ");
classes.push("tc-droppable");
this.domNode.className = classes.join(" ");
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
DroppableWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes["class"] || changedAttributes.tag || changedAttributes.enable) {
if(changedAttributes.tag || changedAttributes.enable) {
this.refreshSelf();
return true;
} else if(changedAttributes["class"]) {
this.assignDomNodeClasses();
}
return this.refreshChildren(changedTiddlers);
};

View File

@ -51,6 +51,7 @@ EditWidget.prototype.execute = function() {
this.editCancelPopups = this.getAttribute("cancelPopups","");
this.editInputActions = this.getAttribute("inputActions");
this.editRefreshTitle = this.getAttribute("refreshTitle");
this.editAutoComplete = this.getAttribute("autocomplete");
// Choose the appropriate edit widget
this.editorType = this.getEditorType();
// Make the child widgets
@ -89,7 +90,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
EditWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
// Refresh if an attribute has changed, or the type associated with the target tiddler has changed
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || (changedTiddlers[this.editTitle] && this.getEditorType() !== this.editorType)) {
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || (changedTiddlers[this.editTitle] && this.getEditorType() !== this.editorType)) {
this.refreshSelf();
return true;
} else {

View File

@ -0,0 +1,156 @@
/*\
title: $:/core/modules/widgets/eventcatcher.js
type: application/javascript
module-type: widget
Event handler widget
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var EventWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
};
/*
Inherit from the base widget class
*/
EventWidget.prototype = new Widget();
/*
Render this widget into the DOM
*/
EventWidget.prototype.render = function(parent,nextSibling) {
var self = this;
// Remember parent
this.parentDomNode = parent;
// Compute attributes and execute state
this.computeAttributes();
this.execute();
// Create element
var tag = this.parseTreeNode.isBlock ? "div" : "span";
if(this.elementTag && $tw.config.htmlUnsafeElements.indexOf(this.elementTag) === -1) {
tag = this.elementTag;
}
var domNode = this.document.createElement(tag);
this.domNode = domNode;
// Assign classes
this.assignDomNodeClasses();
// Add our event handler
$tw.utils.each(this.types,function(type) {
domNode.addEventListener(type,function(event) {
var selector = self.getAttribute("selector"),
actions = self.getAttribute("actions-"+type),
selectedNode = event.target,
selectedNodeRect,
catcherNodeRect,
variables = {};
if(selector) {
// Search ancestors for a node that matches the selector
while(!selectedNode.matches(selector) && selectedNode !== domNode) {
selectedNode = selectedNode.parentNode;
}
// If we found one, copy the attributes as variables, otherwise exit
if(selectedNode.matches(selector)) {
$tw.utils.each(selectedNode.attributes,function(attribute) {
variables["dom-" + attribute.name] = attribute.value.toString();
});
//Add a variable with a popup coordinate string for the selected node
variables["tv-popup-coords"] = "(" + selectedNode.offsetLeft + "," + selectedNode.offsetTop +"," + selectedNode.offsetWidth + "," + selectedNode.offsetHeight + ")";
//Add variables for offset of selected node
variables["tv-selectednode-posx"] = selectedNode.offsetLeft.toString();
variables["tv-selectednode-posy"] = selectedNode.offsetTop.toString();
variables["tv-selectednode-width"] = selectedNode.offsetWidth.toString();
variables["tv-selectednode-height"] = selectedNode.offsetHeight.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 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;
}
}
// Execute our actions with the variables
if(actions) {
// Add a variable for the modifier key
variables.modifier = $tw.keyboardManager.getEventModifierKeyDescriptor(event);
// Add a variable for the mouse button
if("button" in event) {
if(event.button === 0) {
variables["event-mousebutton"] = "left";
} else if(event.button === 1) {
variables["event-mousebutton"] = "middle";
} else if(event.button === 2) {
variables["event-mousebutton"] = "right";
}
}
variables["event-type"] = event.type.toString();
if(typeof event.detail === "object" && !!event.detail) {
$tw.utils.each(event.detail,function(detailValue,detail) {
variables["event-detail-" + detail] = detailValue.toString();
});
} else if(!!event.detail) {
variables["event-detail"] = event.detail.toString();
}
self.invokeActionString(actions,self,event,variables);
event.preventDefault();
event.stopPropagation();
return true;
}
return false;
},false);
});
// Insert element
parent.insertBefore(domNode,nextSibling);
this.renderChildren(domNode,null);
this.domNodes.push(domNode);
};
/*
Compute the internal state of the widget
*/
EventWidget.prototype.execute = function() {
var self = this;
// Get attributes that require a refresh on change
this.types = this.getAttribute("events","").split(" ");
this.elementTag = this.getAttribute("tag");
// Make child widgets
this.makeChildWidgets();
};
EventWidget.prototype.assignDomNodeClasses = function() {
var classes = this.getAttribute("class","").split(" ");
classes.push("tc-eventcatcher");
this.domNode.className = classes.join(" ");
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
EventWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes["events"] || changedAttributes["tag"]) {
this.refreshSelf();
return true;
} else if(changedAttributes["class"]) {
this.assignDomNodeClasses();
}
return this.refreshChildren(changedTiddlers);
};
exports.eventcatcher = EventWidget;
})();

View File

@ -0,0 +1,30 @@
/*\
title: $:/core/modules/widgets/log.js
type: application/javascript
module-type: widget-subclass
Widget to log debug messages
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.baseClass = "action-log";
exports.name = "log";
exports.constructor = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
}
exports.prototype = {};
exports.prototype.render = function(event) {
Object.getPrototypeOf(Object.getPrototypeOf(this)).render.call(this,event);
Object.getPrototypeOf(Object.getPrototypeOf(this)).log.call(this);
}
})();

View File

@ -128,7 +128,7 @@ NavigatorWidget.prototype.replaceFirstTitleInStory = function(storyList,oldTitle
NavigatorWidget.prototype.addToStory = function(title,fromTitle) {
if(this.storyTitle) {
this.story.addToStory(title,fromTitle,this.storyTitle,{
this.story.addToStory(title,fromTitle,{
openLinkFromInsideRiver: this.getAttribute("openLinkFromInsideRiver","top"),
openLinkFromOutsideRiver: this.getAttribute("openLinkFromOutsideRiver","top")
});
@ -529,6 +529,7 @@ NavigatorWidget.prototype.handleImportTiddlersEvent = function(event) {
$tw.utils.each(importData.tiddlers,function(tiddler,title) {
if($tw.utils.count(tiddler) === 0) {
newFields["selection-" + title] = "unchecked";
newFields["suppressed-" + title] = "yes";
}
});
// Save the $:/Import tiddler

View File

@ -13,7 +13,6 @@ Set a field or index at a given tiddler via radio buttons
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var RadioWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
};
@ -37,8 +36,8 @@ RadioWidget.prototype.render = function(parent,nextSibling) {
// Create our elements
this.labelDomNode = this.document.createElement("label");
this.labelDomNode.setAttribute("class",
"tc-radio " + this.radioClass + (isChecked ? " tc-radio-selected" : "")
);
"tc-radio " + this.radioClass + (isChecked ? " tc-radio-selected" : "")
);
this.inputDomNode = this.document.createElement("input");
this.inputDomNode.setAttribute("type","radio");
if(isChecked) {
@ -86,6 +85,10 @@ RadioWidget.prototype.handleChangeEvent = function(event) {
if(this.inputDomNode.checked) {
this.setValue();
}
// Trigger actions
if(this.radioActions) {
this.invokeActionString(this.radioActions,this,event,{"actionValue": this.radioValue});
}
};
/*
@ -99,6 +102,7 @@ RadioWidget.prototype.execute = function() {
this.radioValue = this.getAttribute("value");
this.radioClass = this.getAttribute("class","");
this.isDisabled = this.getAttribute("disabled","no");
this.radioActions = this.getAttribute("actions","");
// Make the child widgets
this.makeChildWidgets();
};
@ -108,16 +112,11 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
*/
RadioWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.value || changedAttributes["class"] || changedAttributes.disabled) {
if(($tw.utils.count(changedAttributes) > 0) || changedTiddlers[this.radioTitle]) {
this.refreshSelf();
return true;
} else {
var refreshed = false;
if(changedTiddlers[this.radioTitle]) {
this.inputDomNode.checked = this.getValue() === this.radioValue;
refreshed = true;
}
return this.refreshChildren(changedTiddlers) || refreshed;
return this.refreshChildren(changedTiddlers);
}
};

View File

@ -52,8 +52,10 @@ RangeWidget.prototype.render = function(parent,nextSibling) {
this.inputDomNode.value = this.getValue();
// Add a click event handler
$tw.utils.addEventListeners(this.inputDomNode,[
{name: "input", handlerObject: this, handlerMethod: "handleInputEvent"},
{name: "change", handlerObject: this, handlerMethod: "handleInputEvent"}
{name:"mousedown", handlerObject:this, handlerMethod:"handleMouseDownEvent"},
{name:"mouseup", handlerObject:this, handlerMethod:"handleMouseUpEvent"},
{name:"change", handlerObject:this, handlerMethod:"handleChangeEvent"},
{name:"input", handlerObject:this, handlerMethod:"handleInputEvent"},
]);
// Insert the label into the DOM and render any children
parent.insertBefore(this.inputDomNode,nextSibling);
@ -62,23 +64,77 @@ RangeWidget.prototype.render = function(parent,nextSibling) {
RangeWidget.prototype.getValue = function() {
var tiddler = this.wiki.getTiddler(this.tiddlerTitle),
fieldName = this.tiddlerField || "text",
value = this.defaultValue;
fieldName = this.tiddlerField,
value = this.defaultValue;
if(tiddler) {
if(this.tiddlerIndex) {
value = this.wiki.extractTiddlerDataItem(tiddler,this.tiddlerIndex,this.defaultValue || "");
value = this.wiki.extractTiddlerDataItem(tiddler,this.tiddlerIndex,this.defaultValue);
} else {
if($tw.utils.hop(tiddler.fields,fieldName)) {
value = tiddler.fields[fieldName] || "";
} else {
value = this.defaultValue || "";
value = this.defaultValue;
}
}
}
return value;
};
RangeWidget.prototype.getActionVariables = function(options) {
options = options || {};
var hasChanged = (this.startValue !== this.inputDomNode.value) ? "yes" : "no";
// Trigger actions. Use variables = {key:value, key:value ...}
// the "value" is needed.
return $tw.utils.extend({"actionValue": this.inputDomNode.value, "actionValueHasChanged": hasChanged}, options);
}
// actionsStart
RangeWidget.prototype.handleMouseDownEvent = function(event) {
this.mouseDown = true; // TODO remove once IE is gone.
this.startValue = this.inputDomNode.value; // TODO remove this line once IE is gone!
this.handleEvent(event);
// Trigger actions
if(this.actionsMouseDown) {
var variables = this.getActionVariables() // TODO this line will go into the function call below.
this.invokeActionString(this.actionsMouseDown,this,event,variables);
}
}
// actionsStop
RangeWidget.prototype.handleMouseUpEvent = function(event) {
this.mouseDown = false; // TODO remove once IE is gone.
this.handleEvent(event);
// Trigger actions
if(this.actionsMouseUp) {
var variables = this.getActionVariables()
this.invokeActionString(this.actionsMouseUp,this,event,variables);
}
// TODO remove the following if() once IE is gone!
if ($tw.browser.isIE) {
if (this.startValue !== this.inputDomNode.value) {
this.handleChangeEvent(event);
this.startValue = this.inputDomNode.value;
}
}
}
RangeWidget.prototype.handleChangeEvent = function(event) {
if (this.mouseDown) { // TODO refactor this function once IE is gone.
this.handleInputEvent(event);
}
};
RangeWidget.prototype.handleInputEvent = function(event) {
this.handleEvent(event);
// Trigger actions
if(this.actionsInput) {
// "tiddler" parameter may be missing. See .execute() below
var variables = this.getActionVariables({"actionValueHasChanged": "yes"}) // TODO this line will go into the function call below.
this.invokeActionString(this.actionsInput,this,event,variables);
}
};
RangeWidget.prototype.handleEvent = function(event) {
if(this.getValue() !== this.inputDomNode.value) {
if(this.tiddlerIndex) {
this.wiki.setText(this.tiddlerTitle,"",this.tiddlerIndex,this.inputDomNode.value);
@ -92,16 +148,24 @@ RangeWidget.prototype.handleInputEvent = function(event) {
Compute the internal state of the widget
*/
RangeWidget.prototype.execute = function() {
// TODO remove the next 1 lines once IE is gone!
this.mouseUp = true; // Needed for IE10
// Get the parameters from the attributes
this.tiddlerTitle = this.getAttribute("tiddler",this.getVariable("currentTiddler"));
this.tiddlerField = this.getAttribute("field");
this.tiddlerField = this.getAttribute("field","text");
this.tiddlerIndex = this.getAttribute("index");
this.minValue = this.getAttribute("min");
this.maxValue = this.getAttribute("max");
this.increment = this.getAttribute("increment");
this.defaultValue = this.getAttribute("default");
this.defaultValue = this.getAttribute("default","");
this.elementClass = this.getAttribute("class","");
this.isDisabled = this.getAttribute("disabled","no");
// Actions since 5.1.23
// Next 2 only fire once!
this.actionsMouseDown = this.getAttribute("actionsStart","");
this.actionsMouseUp = this.getAttribute("actionsStop","");
// Input fires very often!
this.actionsInput = this.getAttribute("actions","");
// Make the child widgets
this.makeChildWidgets();
};
@ -111,7 +175,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
*/
RangeWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes['min'] || changedAttributes['max'] || changedAttributes['increment'] || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.disabled) {
if($tw.utils.count(changedAttributes) > 0) {
this.refreshSelf();
return true;
} else {
@ -119,7 +183,7 @@ RangeWidget.prototype.refresh = function(changedTiddlers) {
if(changedTiddlers[this.tiddlerTitle]) {
var value = this.getValue();
if(this.inputDomNode.value !== value) {
this.inputDomNode.value = value;
this.inputDomNode.value = value;
}
refreshed = true;
}

View File

@ -70,6 +70,10 @@ RevealWidget.prototype.positionPopup = function(domNode) {
left = this.popup.left + this.popup.width;
top = this.popup.top + this.popup.height - domNode.offsetHeight;
break;
case "belowright":
left = this.popup.left + this.popup.width;
top = this.popup.top + this.popup.height;
break;
case "right":
left = this.popup.left + this.popup.width;
top = this.popup.top;
@ -78,6 +82,10 @@ RevealWidget.prototype.positionPopup = function(domNode) {
left = this.popup.left + this.popup.width - domNode.offsetWidth;
top = this.popup.top + this.popup.height;
break;
case "aboveleft":
left = this.popup.left - domNode.offsetWidth;
top = this.popup.top - domNode.offsetHeight;
break;
default: // Below
left = this.popup.left;
top = this.popup.top + this.popup.height;
@ -109,6 +117,7 @@ RevealWidget.prototype.execute = function() {
this.retain = this.getAttribute("retain","no");
this.openAnimation = this.animate === "no" ? undefined : "open";
this.closeAnimation = this.animate === "no" ? undefined : "close";
this.updatePopupPosition = this.getAttribute("updatePopupPosition","no") === "yes";
// Compute the title of the state tiddler and read it
this.stateTiddlerTitle = this.state;
this.stateTitle = this.getAttribute("stateTitle");
@ -212,6 +221,8 @@ RevealWidget.prototype.refresh = function(changedTiddlers) {
this.refreshSelf();
return true;
}
} else if(this.type === "popup" && this.updatePopupPosition && (changedTiddlers[this.state] || changedTiddlers[this.stateTitle])) {
this.positionPopup(this.domNodes[0]);
}
return this.refreshChildren(changedTiddlers);
}

View File

@ -574,10 +574,10 @@ Widget.prototype.invokeActionString = function(actions,triggeringWidget,event,va
/*
Execute action tiddlers by tag
*/
Widget.prototype.executeStartupTiddlers = function(tag) {
Widget.prototype.invokeActionsByTag = function(tag,event,variables) {
var self = this;
$tw.utils.each(self.wiki.filterTiddlers("[all[shadows+tiddlers]tag[" + tag + "]!has[draft.of]]"),function(title) {
self.invokeActionString(self.wiki.getTiddlerText(title),self);
self.invokeActionString(self.wiki.getTiddlerText(title),self,event,variables);
});
};

View File

@ -0,0 +1,129 @@
title: $:/palettes/CupertinoDark
tags: $:/tags/Palette
name: Cupertino Dark
description: A macOS inspired dark palette
type: application/x-tiddler-dictionary
alert-background: #FF453A
alert-border: #FF453A
alert-highlight: #FFD60A
alert-muted-foreground: <<colour muted-foreground>>
background: #282828
blockquote-bar: <<colour page-background>>
button-foreground: <<colour background>>
code-background: <<colour pre-background>>
code-border: <<colour pre-border>>
code-foreground: rgba(255, 255, 255, 0.54)
dirty-indicator: #FF453A
download-background: <<colour primary>>
download-foreground: <<colour foreground>>
dragger-background: <<colour foreground>>
dragger-foreground: <<colour background>>
dropdown-background: <<colour tiddler-info-background>>
dropdown-border: <<colour dropdown-background>>
dropdown-tab-background-selected: #3F638B
dropdown-tab-background: #323232
dropzone-background: #30D158
external-link-background-hover: transparent
external-link-background-visited: transparent
external-link-background: transparent
external-link-foreground-hover:
external-link-foreground-visited: #BF5AF2
external-link-foreground: #32D74B
foreground: #FFFFFF
menubar-background: #464646
menubar-foreground: #ffffff
message-background: <<colour background>>
message-border: <<colour very-muted-foreground>>
message-foreground: rgba(255, 255, 255, 0.54)
modal-backdrop: <<colour page-background>>
modal-background: <<colour background>>
modal-border: <<colour very-muted-foreground>>
modal-footer-background: <<colour background>>
modal-footer-border: <<colour background>>
modal-header-border: <<colour very-muted-foreground>>
muted-foreground: #98989D
notification-background: <<colour dropdown-background>>
notification-border: <<colour dropdown-background>>
page-background: #323232
pre-background: #464646
pre-border: transparent
primary: #0A84FF
select-tag-background: <<colour background>>
select-tag-foreground: <<colour foreground>>
sidebar-button-foreground: <<colour background>>
sidebar-controls-foreground-hover: #FF9F0A
sidebar-controls-foreground: #8E8E93
sidebar-foreground-shadow: transparent
sidebar-foreground: rgba(255, 255, 255, 0.54)
sidebar-muted-foreground-hover: rgba(255, 255, 255, 0.54)
sidebar-muted-foreground: rgba(255, 255, 255, 0.38)
sidebar-tab-background-selected: #3F638B
sidebar-tab-background: <<colour background>>
sidebar-tab-border-selected: <<colour background>>
sidebar-tab-border: <<colour background>>
sidebar-tab-divider: <<colour background>>
sidebar-tab-foreground-selected: rgba(255, 255, 255, 0.87)
sidebar-tab-foreground: rgba(255, 255, 255, 0.54)
sidebar-tiddler-link-foreground-hover: rgba(255, 255, 255, 0.7)
sidebar-tiddler-link-foreground: rgba(255, 255, 255, 0.54)
site-title-foreground: #ffffff
static-alert-foreground: #B4B4B4
tab-background-selected: #3F638B
tab-background: <<colour page-background>>
tab-border-selected: <<colour page-background>>
tab-border: <<colour page-background>>
tab-divider: <<colour page-background>>
tab-foreground-selected: rgba(255, 255, 255, 0.87)
tab-foreground: rgba(255, 255, 255, 0.54)
table-border: #464646
table-footer-background: <<colour tiddler-editor-fields-odd>>
table-header-background: <<colour tiddler-editor-fields-even>>
tag-background: #48484A
tag-foreground: #323232
tiddler-background: <<colour background>>
tiddler-border: transparent
tiddler-controls-foreground-hover: <<colour sidebar-controls-foreground-hover>>
tiddler-controls-foreground-selected: <<colour sidebar-controls-foreground-hover>>
tiddler-controls-foreground: #48484A
tiddler-editor-background: transparent
tiddler-editor-border-image:
tiddler-editor-border: rgba(255, 255, 255, 0.08)
tiddler-editor-fields-even: rgba(255, 255, 255, 0.1)
tiddler-editor-fields-odd: rgba(255, 255, 255, 0.04)
tiddler-info-background: #1E1E1E
tiddler-info-border: #1E1E1E
tiddler-info-tab-background: #3F638B
tiddler-link-background: <<colour background>>
tiddler-link-foreground: <<colour primary>>
tiddler-subtitle-foreground: <<colour muted-foreground>>
tiddler-title-foreground: #FFFFFF
toolbar-new-button:
toolbar-options-button:
toolbar-save-button:
toolbar-info-button:
toolbar-edit-button:
toolbar-close-button:
toolbar-delete-button:
toolbar-cancel-button:
toolbar-done-button:
untagged-background: <<colour very-muted-foreground>>
very-muted-foreground: #464646
selection-background: #3F638B
selection-foreground: #ffffff
wikilist-background: <<colour page-background>>
wikilist-button-background: <<colour button-background>>
wikilist-button-foreground: <<colour background>>
wikilist-button-open: #32D74B
wikilist-button-open-hover: #32D74B
wikilist-button-reveal: #0A84FF
wikilist-button-reveal-hover: #0A84FF
wikilist-button-remove: #FF453A
wikilist-button-remove-hover: #FF453A
wikilist-droplink-dragover: #32D74B
wikilist-item: <<colour background>>
wikilist-toolbar-background: <<colour background>>
wikilist-title: <<colour foreground>>
wikilist-title-svg: <<colour foreground>>
wikilist-toolbar-foreground: <<colour foreground>>
wikilist-url: <<colour muted-foreground>>

View File

@ -0,0 +1,138 @@
title: $:/palettes/DesertSand
tags: $:/tags/Palette
name: Desert Sand
description: A desert sand palette
type: application/x-tiddler-dictionary
alert-background: #ffe476
alert-border: #b99e2f
alert-highlight: #881122
alert-muted-foreground: #b99e2f
background: #E9E0C7
blockquote-bar: <<colour muted-foreground>>
button-foreground: <<colour foreground>>
code-background: #F3EDDF
code-border: #C3BAA1
code-foreground: #ab3250
diff-delete-background: #bd8b8b
diff-delete-foreground: <<colour foreground>>
diff-equal-background:
diff-equal-foreground: <<colour foreground>>
diff-insert-background: #91c093
diff-insert-foreground: <<colour foreground>>
diff-invisible-background:
diff-invisible-foreground: <<colour muted-foreground>>
dirty-indicator: #ad3434
download-background: #6ca16c
download-foreground: <<colour background>>
dragger-background: <<colour foreground>>
dragger-foreground: <<colour background>>
dropdown-background: <<colour background>>
dropdown-border: <<colour muted-foreground>>
dropdown-tab-background-selected: #E9E0C7
dropdown-tab-background: #BAB29C
dropzone-background: rgba(0,200,0,0.7)
external-link-background-hover: inherit
external-link-background-visited: inherit
external-link-background: inherit
external-link-foreground-hover: inherit
external-link-foreground-visited: #313163
external-link-foreground: #555592
foreground: #2D2A23
menubar-background: #CDC2A6
menubar-foreground: #5A5446
message-background: #ECE5CF
message-border: #D6CBAA
message-foreground: #5f6e7d
modal-backdrop: <<colour foreground>>
modal-background: <<colour background>>
modal-border: #8A8885
modal-footer-background: #CDC2A6
modal-footer-border: #9D998E
modal-header-border: #9D998E
muted-foreground: #9D998E
notification-background: #F0E9D7
notification-border: #939189
page-background: #e0d3af
pre-background: #D6CBAA
pre-border: #CDC2A6
primary: #5B6F55
selection-background: #9D947B
selection-foreground: <<colour foreground>>
select-tag-background: #F0E9D7
select-tag-foreground: #2D2A23
sidebar-button-foreground: <<colour foreground>>
sidebar-controls-foreground-hover: #2D2A23
sidebar-controls-foreground: #867F69
sidebar-foreground-shadow: transparent
sidebar-foreground: #867F69
sidebar-muted-foreground-hover: #706A58
sidebar-muted-foreground: #B3A98C
sidebar-tab-background-selected: #e0d3af
sidebar-tab-background: #A6A193
sidebar-tab-border-selected: #C3BAA1
sidebar-tab-border: #C3BAA1
sidebar-tab-divider: #CDC2A6
sidebar-tab-foreground-selected:
sidebar-tab-foreground: #2D2A23
sidebar-tiddler-link-foreground-hover: #433F35
sidebar-tiddler-link-foreground: #706A58
site-title-foreground: <<colour tiddler-title-foreground>>
static-alert-foreground: #A6A193
tab-background-selected: #E9E0C7
tab-background: #A6A193
tab-border-selected: #C3BAA1
tab-border: #C3BAA1
tab-divider: #CDC2A6
tab-foreground-selected: <<colour tab-foreground>>
tab-foreground: #2D2A23
table-border: #9D998E
table-footer-background: #8A8885
table-header-background: #B0AA98
tag-background: #706A58
tag-foreground: #E3D7B7
tiddler-background: <<colour background>>
tiddler-border: <<colour background>>
tiddler-controls-foreground-hover: #9D947B
tiddler-controls-foreground-selected: #706A58
tiddler-controls-foreground: #C3BAA1
tiddler-editor-background: #E9E0C7
tiddler-editor-border-image: #A6A193
tiddler-editor-border: #A6A193
tiddler-editor-fields-even: #D6CBAA
tiddler-editor-fields-odd: #C3BAA1
tiddler-info-background: #E3D7B7
tiddler-info-border: #BAB29C
tiddler-info-tab-background: #E9E0C7
tiddler-link-background: <<colour background>>
tiddler-link-foreground: <<colour primary>>
tiddler-subtitle-foreground: #867F69
tiddler-title-foreground: #374464
toolbar-new-button:
toolbar-options-button:
toolbar-save-button:
toolbar-info-button:
toolbar-edit-button:
toolbar-close-button:
toolbar-delete-button:
toolbar-cancel-button:
toolbar-done-button:
untagged-background: #8A8885
very-muted-foreground: #CDC2A6
wikilist-background: <<colour page-background>>
wikilist-item: #CDC2A6
wikilist-info: #161512
wikilist-title: #433F35
wikilist-title-svg: <<colour wikilist-title>>
wikilist-url: #706A58
wikilist-button-open: #7db66a
wikilist-button-open-hover: #56a556
wikilist-button-reveal: #5a6c9e
wikilist-button-reveal-hover: #454591
wikilist-button-remove: #bc5972
wikilist-button-remove-hover: #814040
wikilist-toolbar-background: #CDC2A6
wikilist-toolbar-foreground: #2D2A23
wikilist-droplink-dragover: rgba(255,192,192,0.5)
wikilist-button-background: #A6A193
wikilist-button-foreground: #161512

View File

@ -11,9 +11,7 @@ alert-highlight: #d79921
alert-muted-foreground: #504945
background: #3c3836
blockquote-bar: <<colour muted-foreground>>
button-background: #504945
button-foreground: #fbf1c7
button-border: transparent
button-foreground: <<colour page-background>>
code-background: #504945
code-border: #504945
code-foreground: #fb4934
@ -62,7 +60,9 @@ pre-border: #504945
primary: #d79921
select-tag-background: #665c54
select-tag-foreground: <<colour foreground>>
sidebar-button-foreground: <<colour foreground>>
selection-background: #458588
selection-foreground: <<colour foreground>>
sidebar-button-foreground: <<colour page-background>>
sidebar-controls-foreground-hover: #7c6f64
sidebar-controls-foreground: #504945
sidebar-foreground-shadow: transparent

View File

@ -11,9 +11,7 @@ alert-highlight: #B48EAD
alert-muted-foreground: #4C566A
background: #3b4252
blockquote-bar: <<colour muted-foreground>>
button-background: #4C566A
button-foreground: #D8DEE9
button-border: transparent
button-foreground: <<colour page-background>>
code-background: #2E3440
code-border: #2E3440
code-foreground: #BF616A
@ -62,7 +60,9 @@ pre-border: #2E3440
primary: #5E81AC
select-tag-background: #3b4252
select-tag-foreground: <<colour foreground>>
sidebar-button-foreground: <<colour foreground>>
selection-background: #5E81AC
selection-foreground: <<colour foreground>>
sidebar-button-foreground: <<colour page-background>>
sidebar-controls-foreground-hover: #D8DEE9
sidebar-controls-foreground: #4C566A
sidebar-foreground-shadow: transparent

View File

@ -26,7 +26,7 @@ extension: .html
</head>
<body class="tc-body">
{{$:/StaticBanner||$:/core/templates/html-tiddler}}
<section class="tc-story-river">
<section class="tc-story-river tc-static-story-river">
{{$:/core/templates/exporters/StaticRiver/Content||$:/core/templates/html-tiddler}}
</section>
</body>

View File

@ -22,9 +22,9 @@ title: $:/core/templates/static.tiddler.html
</head>
<body class="tc-body">
`{{$:/StaticBanner||$:/core/templates/html-tiddler}}`
<section class="tc-story-river">
<section class="tc-story-river tc-static-story-river">
`<$view tiddler="$:/core/ui/ViewTemplate" format="htmlwikified"/>`
</section>
</body>
</html>
`
`

View File

@ -5,6 +5,7 @@ description: create a new image tiddler
\define get-type()
image/$(imageType)$
\end
<$vars imageType={{$:/config/NewImageType}}>
<$action-sendmessage $message="tm-new-tiddler" type=<<get-type>> tags={{$:/config/NewTiddler/Tags}}/>
\define get-tags() $(textFieldTags)$ $(tagsFieldTags)$
<$vars imageType={{$:/config/NewImageType}} textFieldTags={{$:/config/NewJournal/Tags}} tagsFieldTags={{$:/config/NewJournal/Tags!!tags}}>
<$action-sendmessage $message="tm-new-tiddler" type=<<get-type>> tags=<<get-tags>>/>
</$vars>

View File

@ -2,13 +2,14 @@ title: $:/core/ui/Actions/new-journal
tags: $:/tags/Actions
description: create a new journal tiddler
<$vars journalTitleTemplate={{$:/config/NewJournal/Title}} journalTags={{$:/config/NewJournal/Tags}} journalText={{$:/config/NewJournal/Text}}>
\define get-tags() $(textFieldTags)$ $(tagsFieldTags)$
<$vars journalTitleTemplate={{$:/config/NewJournal/Title}} textFieldTags={{$:/config/NewJournal/Tags}} tagsFieldTags={{$:/config/NewJournal/Tags!!tags}} journalText={{$:/config/NewJournal/Text}}>
<$wikify name="journalTitle" text="""<$macrocall $name="now" format=<<journalTitleTemplate>>/>""">
<$reveal type="nomatch" state=<<journalTitle>> text="">
<$action-sendmessage $message="tm-new-tiddler" title=<<journalTitle>> tags=<<journalTags>> text={{{ [<journalTitle>get[]] }}}/>
<$action-sendmessage $message="tm-new-tiddler" title=<<journalTitle>> tags=<<get-tags>> text={{{ [<journalTitle>get[]] }}}/>
</$reveal>
<$reveal type="match" state=<<journalTitle>> text="">
<$action-sendmessage $message="tm-new-tiddler" title=<<journalTitle>> tags=<<journalTags>> text=<<journalText>>/>
<$action-sendmessage $message="tm-new-tiddler" title=<<journalTitle>> tags=<<get-tags>> text=<<journalText>>/>
</$reveal>
</$wikify>
</$vars>

View File

@ -2,4 +2,7 @@ title: $:/core/ui/Actions/new-tiddler
tags: $:/tags/Actions
description: create a new empty tiddler
<$action-sendmessage $message="tm-new-tiddler" tags={{$:/config/NewTiddler/Tags}}/>
\define get-tags() $(textFieldTags)$ $(tagsFieldTags)$
<$vars textFieldTags={{$:/config/NewTiddler/Tags}} tagsFieldTags={{$:/config/NewTiddler/Tags!!tags}}>
<$action-sendmessage $message="tm-new-tiddler" tags=<<get-tags>>/>
</$vars>

View File

@ -26,8 +26,8 @@ caption: {{$:/language/ControlPanel/Basics/Caption}}
|<$link to="$:/language/DefaultNewTiddlerTitle"><<lingo NewTiddler/Title/Prompt>></$link> |<$edit-text tiddler="$:/language/DefaultNewTiddlerTitle" default="" tag="input"/> |
|<$link to="$:/config/NewJournal/Title"><<lingo NewJournal/Title/Prompt>></$link> |<$edit-text tiddler="$:/config/NewJournal/Title" default="" tag="input"/> |
|<$link to="$:/config/NewJournal/Text"><<lingo NewJournal/Text/Prompt>></$link> |<$edit tiddler="$:/config/NewJournal/Text" tag="textarea" class="tc-edit-texteditor" default=""/> |
|<$link to="$:/config/NewTiddler/Tags"><<lingo NewTiddler/Tags/Prompt>></$link> |<$vars currentTiddler="$:/config/NewTiddler/Tags" tagField="text">{{||$:/core/ui/EditTemplate/tags}}</$vars> |
|<$link to="$:/config/NewJournal/Tags"><<lingo NewJournal/Tags/Prompt>></$link> |<$vars currentTiddler="$:/config/NewJournal/Tags" tagField="text">{{||$:/core/ui/EditTemplate/tags}}</$vars> |
|<$link to="$:/config/NewTiddler/Tags"><<lingo NewTiddler/Tags/Prompt>></$link> |<$vars currentTiddler="$:/config/NewTiddler/Tags" tagField="text">{{||$:/core/ui/EditTemplate/tags}}<$list filter="[<currentTiddler>tags[]] +[limit[1]]" variable="ignore"><$button tooltip={{$:/language/ControlPanel/Basics/RemoveTags/Hint}}><<lingo RemoveTags>><$action-listops $tiddler=<<currentTiddler>> $field="text" $subfilter={{{ [<currentTiddler>get[tags]] }}}/><$action-setfield $tiddler=<<currentTiddler>> tags=""/></$button></$list></$vars> |
|<$link to="$:/config/NewJournal/Tags"><<lingo NewJournal/Tags/Prompt>></$link> |<$vars currentTiddler="$:/config/NewJournal/Tags" tagField="text">{{||$:/core/ui/EditTemplate/tags}}<$list filter="[<currentTiddler>tags[]] +[limit[1]]" variable="ignore"><$button tooltip={{$:/language/ControlPanel/Basics/RemoveTags/Hint}}><<lingo RemoveTags>><$action-listops $tiddler=<<currentTiddler>> $field="text" $subfilter={{{ [<currentTiddler>get[tags]] }}}/><$action-setfield $tiddler=<<currentTiddler>> tags=""/></$button></$list></$vars> |
|<$link to="$:/config/AutoFocus"><<lingo AutoFocus/Prompt>></$link> |{{$:/snippets/minifocusswitcher}} |
|<<lingo Language/Prompt>> |{{$:/snippets/minilanguageswitcher}} |
|<<lingo Tiddlers/Prompt>> |<<show-filter-count "[!is[system]sort[title]]">> |

View File

@ -20,6 +20,12 @@ http://$(userName)$.tiddlyspot.com/$path$/
</$reveal>
\end
<div class="tc-message-box">
<<lingo ReadOnly>>
</div>
<<lingo Description>>
|<<lingo UserName>> |<$edit-text tiddler="$:/UploadName" default="" tag="input"/> |
@ -34,4 +40,4 @@ http://$(userName)$.tiddlyspot.com/$path$/
|<<lingo UploadDir>> |<$edit-text tiddler="$:/UploadDir" default="." tag="input"/> |
|<<lingo BackupDir>> |<$edit-text tiddler="$:/UploadBackupDir" default="." tag="input"/> |
<<lingo TiddlySpot/Hint>>
<<lingo TiddlySpot/Hint>>

View File

@ -57,7 +57,7 @@ $value={{{ [<newFieldValueTiddler>get[text]] }}}/>
\whitespace trim
<div class="tc-edit-fields">
<table class="tc-edit-fields">
<table class={{{ [all[current]fields[]] :filter[lookup[$:/config/EditTemplateFields/Visibility/]!match[hide]] +[count[]!match[0]] +[then[tc-edit-fields]] ~[[tc-edit-fields tc-edit-fields-small]] }}}>
<tbody>
<$list filter="[all[current]fields[]] +[sort[title]]" variable="currentField" storyview="pop">
<$list filter=<<config-filter>> variable="temp">

View File

@ -3,6 +3,7 @@ tags: $:/tags/EditToolbar
caption: {{$:/core/images/cancel-button}} {{$:/language/Buttons/Cancel/Caption}}
description: {{$:/language/Buttons/Cancel/Hint}}
\whitespace trim
<$button actions=<<cancel-delete-tiddler-actions "cancel">> tooltip={{$:/language/Buttons/Cancel/Hint}} aria-label={{$:/language/Buttons/Cancel/Caption}} class=<<tv-config-toolbar-class>>>
<$list filter="[<tv-config-toolbar-icons>match[yes]]">
{{$:/core/images/cancel-button}}

View File

@ -3,6 +3,7 @@ tags: $:/tags/EditToolbar $:/tags/ViewToolbar
caption: {{$:/core/images/delete-button}} {{$:/language/Buttons/Delete/Caption}}
description: {{$:/language/Buttons/Delete/Hint}}
\whitespace trim
<$button actions=<<cancel-delete-tiddler-actions "delete">> tooltip={{$:/language/Buttons/Delete/Hint}} aria-label={{$:/language/Buttons/Delete/Caption}} class=<<tv-config-toolbar-class>>>
<$list filter="[<tv-config-toolbar-icons>match[yes]]">
{{$:/core/images/delete-button}}

View File

@ -4,6 +4,7 @@ caption: {{$:/core/images/done-button}} {{$:/language/Buttons/Save/Caption}}
description: {{$:/language/Buttons/Save/Hint}}
\define save-tiddler-button()
\whitespace trim
<$fieldmangler><$button tooltip={{$:/language/Buttons/Save/Hint}} aria-label={{$:/language/Buttons/Save/Caption}} class=<<tv-config-toolbar-class>>>
<<save-tiddler-actions>>
<$list filter="[<tv-config-toolbar-icons>match[yes]]">

View File

@ -7,13 +7,17 @@ title: $:/core/ui/ImportListing
\define payloadTitleFilter() [<currentTiddler>get<renameField>minlength[1]else<payloadTiddler>]
\define overWriteWarning()
<$list filter="[<currentTiddler>!has<suppressedField>]">
<$text text={{{[subfilter<payloadTitleFilter>!is[tiddler]then[]] ~[<lingo-base>addsuffix[Listing/Rename/OverwriteWarning]get[text]]}}}/>
</$list>
\end
\define selectionField() selection-$(payloadTiddler)$
\define renameField() rename-$(payloadTiddler)$
\define suppressedField() suppressed-$(payloadTiddler)$
\define newImportTitleTiddler() $:/temp/NewImportTitle-$(payloadTiddler)$
\define previewPopupState() $(currentTiddler)$!!popup-$(payloadTiddler)$
@ -42,17 +46,17 @@ title: $:/core/ui/ImportListing
</th>
</tr>
<$list filter="[all[current]plugintiddlers[]sort[title]]" variable="payloadTiddler">
<tr>
<tr class={{{[<currentTiddler>has<suppressedField>then[tc-row-disabled]] ~[subfilter<payloadTitleFilter>is[tiddler]then[tc-row-warning]] }}}>
<td>
<$checkbox field=<<selectionField>> checked="checked" unchecked="unchecked" default="checked"/>
<$checkbox field=<<selectionField>> checked="checked" unchecked="unchecked" default="checked" disabled={{{[<currentTiddler>has<suppressedField>then[yes]else[no]]}}}/>
</td>
<td>
<$reveal type="nomatch" state=<<renameFieldState>> text="yes" tag="div">
<$reveal type="nomatch" state=<<previewPopupState>> text="yes" tag="div" class="tc-flex">
<$button class="tc-btn-invisible tc-btn-dropdown tc-flex-grow-1 tc-word-break" set=<<previewPopupState>> setTo="yes">
<$button class="tc-btn-invisible tc-btn-dropdown tc-flex-grow-1 tc-word-break" set=<<previewPopupState>> setTo="yes" disabled={{{[<currentTiddler>has<suppressedField>then[yes]else[no]]}}}>
<span class="tc-small-gap-right">{{$:/core/images/right-arrow}}</span><$text text={{{[subfilter<payloadTitleFilter>]}}}/>
</$button>
<$button class="tc-btn-invisible" set=<<renameFieldState>> setTo="yes" tooltip={{{[<lingo-base>addsuffix[Listing/Rename/Tooltip]get[text]]}}}>{{$:/core/images/edit-button}}</$button>
<$list filter="[<currentTiddler>!has<suppressedField>]"><$button class="tc-btn-invisible" set=<<renameFieldState>> setTo="yes" tooltip={{{[<lingo-base>addsuffix[Listing/Rename/Tooltip]get[text]]}}}>{{$:/core/images/edit-button}}</$button></$list>
</$reveal>
<$reveal type="match" state=<<previewPopupState>> text="yes" tag="div">
<$button class="tc-btn-invisible tc-btn-dropdown" set=<<previewPopupState>> setTo="no">

View File

@ -0,0 +1,5 @@
title: $:/core/ui/KeyboardShortcuts/switcher
tags: $:/tags/KeyboardShortcut
key: ((layout-switcher))
<$action-sendmessage $message="tm-show-switcher" switch="layout"/>

View File

@ -0,0 +1,17 @@
title: $:/snippets/LayoutSwitcher
tags: $:/tags/ControlPanel/Appearance
caption: {{$:/language/ControlPanel/LayoutSwitcher/Caption}}
<$linkcatcher to="$:/layout">
<div class="tc-chooser">
<$list filter="[all[tiddlers+shadows]tag[$:/tags/Layout]] [[$:/core/ui/PageTemplate]] +[!is[draft]sort[name]]">
<$list filter="[{$:/layout}!has[text]]" variable="ignore" emptyMessage="""
<$set name="cls" filter="[all[current]field:title{$:/layout}]" value="tc-chooser-item tc-chosen" emptyValue="tc-chooser-item"><div class=<<cls>>><$link to={{!!title}}>''<$transclude field="name"/>'' - <$transclude field="description"/></$link></div>
</$set>
""">
<$set name="cls" filter="[all[current]field:title[$:/core/ui/PageTemplate]]" value="tc-chooser-item tc-chosen" emptyValue="tc-chooser-item"><div class=<<cls>>><$link to={{!!title}}>''<$transclude field="name"/>'' - <$transclude field="description"/></$link></div>
</$set>
</$list>
</$list>
</div>
</$linkcatcher>

View File

@ -1,4 +1,6 @@
title: $:/core/ui/PageTemplate
name: {{$:/language/PageTemplate/Name}}
description: {{$:/language/PageTemplate/Description}}
\whitespace trim
\define containerClasses()

View File

@ -8,11 +8,13 @@ tags: $:/tags/SideBarSegment
<$button popup=<<qualify "$:/state/popup/search-dropdown">> class="tc-btn-invisible">
{{$:/core/images/down-arrow}}
<$list filter="[{$(searchTiddler)$}minlength{$:/config/Search/MinLength}limit[1]]" variable="listItem">
<$set name="searchTerm" value={{{ [<searchTiddler>get[text]] }}}>
<$set name="resultCount" value="""<$count filter="[!is[system]search<searchTerm>]"/>""">
<$vars userInput={{{ [<searchTiddler>get[text]] }}} configTiddler={{{ [[$:/state/search/currentTab]!is[missing]get[text]] ~[{$:/config/SearchResults/Default}] }}} replaceRegexp="limit\[\d+\]">
<$vars primaryListFilter={{{ [<configTiddler>get[first-search-filter]search-replace:g:regexp<replaceRegexp>,[]] }}} secondaryListFilter={{{ [<configTiddler>get[second-search-filter]search-replace:g:regexp<replaceRegexp>,[]] }}}>
<$set name="resultCount" value="""<$count filter="[subfilter<primaryListFilter>] [subfilter<secondaryListFilter>]"/>""">
{{$:/language/Search/Matches}}
</$set>
</$set>
</$vars>
</$vars>
</$list>
</$button>
\end

11
core/ui/SwitcherModal.tid Normal file
View File

@ -0,0 +1,11 @@
title: $:/core/ui/SwitcherModal
subtitle: <$text text={{{[<switch>lookup[$:/language/Switcher/Subtitle/]]}}}/>
class: tc-modal-centered
<$tiddler tiddler={{{[<switch>lookup[$:/config/SwitcherTargets/]]}}}>
<$transclude/>
</$tiddler>

View File

@ -0,0 +1,23 @@
title: $:/core/ui/TagPickerTagTemplate
\whitespace trim
<$button class=<<button-classes>> tag="a" tooltip={{$:/language/EditTemplate/Tags/Add/Button/Hint}}>
<$list filter="[<saveTiddler>minlength[1]]">
<$action-listops $tiddler=<<saveTiddler>> $field=<<tagField>> $subfilter="[<tag>]"/>
</$list>
<$set name="currentTiddlerCSSEscaped" value={{{ [<saveTiddler>escapecss[]] }}}>
<$action-sendmessage $message="tm-focus-selector" $param=<<get-tagpicker-focus-selector>> preventScroll="true"/>
</$set>
<<delete-tag-state-tiddlers>>
<$list filter="[<refreshTitle>minlength[1]]">
<$action-setfield $tiddler=<<refreshTitle>> text="yes"/>
</$list>
<<actions>>
<$set name="backgroundColor" value={{!!color}}>
<$wikify name="foregroundColor" text="""<$macrocall $name="contrastcolour" target={{!!color}} fallbackTarget=<<fallbackTarget>> colourA=<<colourA>> colourB=<<colourB>>/>""">
<span class="tc-tag-label tc-btn-invisible" style=<<tag-pill-styles>>>
<$transclude tiddler={{!!icon}}/><$view field="title" format="text"/>
</span>
</$wikify>
</$set>
</$button>

View File

@ -3,5 +3,5 @@ title: $:/config/RegisterPluginType/
plugin: yes
theme: no
language: no
info: no
info: yes
import: no

View File

@ -22,6 +22,7 @@ input-tab-left: {{$:/language/Shortcuts/Input/Tab-Left/Hint}}
input-tab-right: {{$:/language/Shortcuts/Input/Tab-Right/Hint}}
input-up: {{$:/language/Shortcuts/Input/Up/Hint}}
italic: {{$:/language/Buttons/Italic/Hint}}
layout-switcher: {{$:/language/LayoutSwitcher/Description}}
link: {{$:/language/Buttons/Link/Hint}}
linkify: {{$:/language/Buttons/Linkify/Hint}}
list-bullet: {{$:/language/Buttons/ListBullet/Hint}}

View File

@ -0,0 +1,6 @@
title: $:/config/SwitcherTargets/
layout: $:/snippets/LayoutSwitcher
language: $:/snippets/languageswitcher
palette: $:/core/ui/ControlPanel/Palette
theme: $:/core/ui/ControlPanel/Theme

View File

@ -1,3 +1,3 @@
title: $:/config/SyncFilter
[is[tiddler]] -[[$:/core]] -[prefix[$:/StoryList]] -[prefix[$:/HistoryList]] -[status[pending]plugin-type[import]] -[[$:/isEncrypted]] -[prefix[$:/status/]] -[prefix[$:/state/]] -[prefix[$:/temp/]]
[is[tiddler]] -[[$:/core]] -[[$:/library/sjcl.js]] -[prefix[$:/boot/]] -[prefix[$:/HistoryList]] -[status[pending]plugin-type[import]] -[[$:/isEncrypted]] -[prefix[$:/status/]] -[prefix[$:/state/]] -[prefix[$:/temp/]]

View File

@ -0,0 +1,3 @@
title: $:/config/SyncSystemTiddlersFromServer
no

View File

@ -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

View File

@ -21,6 +21,7 @@ input-down: Down
input-tab-left: alt-Left
input-tab-right: alt-Right
input-up: Up
layout-switcher: ctrl-shift-L
link: ctrl-L
linkify: alt-shift-L
list-bullet: ctrl-shift-L

View File

@ -39,7 +39,6 @@ tags: $:/tags/Macro
</div>
</$droppable>
</$list>
</$type$>
<$tiddler tiddler="">
<$droppable actions=<<list-links-draggable-drop-actions>> tag="div" enable=<<tv-enable-drag-and-drop>>>
<div class="tc-droppable-placeholder">
@ -48,6 +47,7 @@ tags: $:/tags/Macro
<div style="height:0.5em;"/>
</$droppable>
</$tiddler>
</$type$>
</$vars>
</span>
\end

View File

@ -20,19 +20,6 @@ $actions$
<$action-setfield $tiddler=<<refreshTitle>> text="yes"/>
\end
\define tag-button(actions,selectedClass,tagField:"tags")
<$button class="tc-btn-invisible $selectedClass$" tag="a" tooltip={{$:/language/EditTemplate/Tags/Add/Button/Hint}}>
<$action-listops $tiddler=<<saveTiddler>> $field=<<__tagField__>> $subfilter="[<tag>]"/>
<$set name="currentTiddlerCSSEscaped" value={{{ [<saveTiddler>escapecss[]] }}}>
<$action-sendmessage $message="tm-focus-selector" $param=<<get-tagpicker-focus-selector>> preventScroll="true"/>
</$set>
<<delete-tag-state-tiddlers>>
<$action-setfield $tiddler=<<refreshTitle>> text="yes"/>
$actions$
<$macrocall $name="tag-pill" tag=<<tag>>/>
</$button>
\end
\define clear-tags-actions-inner()
<$list filter="[<storeTitle>has[text]] [<newTagNameTiddler>has[text]]" variable="ignore" emptyMessage="""<<cancel-delete-tiddler-actions "cancel">>""">
<<delete-tag-state-tiddlers>>
@ -49,7 +36,7 @@ $actions$
\define tag-picker-inner(actions,tagField:"tags")
\whitespace trim
<$vars newTagNameInputTiddlerQualified=<<qualify "$:/temp/NewTagName/input">> newTagNameSelectionTiddlerQualified=<<qualify "$:/temp/NewTagName/selected-item">>>
<$vars newTagNameInputTiddlerQualified=<<qualify "$:/temp/NewTagName/input">> newTagNameSelectionTiddlerQualified=<<qualify "$:/temp/NewTagName/selected-item">> fallbackTarget={{$(palette)$##tag-background}} colourA={{$(palette)$##foreground}} colourB={{$(palette)$##background}}>
<$vars storeTitle={{{ [<newTagNameInputTiddler>!match[]] ~[<newTagNameInputTiddlerQualified>] }}} tagSelectionState={{{ [<newTagNameSelectionTiddler>!match[]] ~[<newTagNameSelectionTiddlerQualified>] }}}>
<$vars refreshTitle=<<qualify "$:/temp/NewTagName/refresh">> nonSystemTagsFilter="[tags[]!is[system]search:title<userInput>sort[]]" systemTagsFilter="[tags[]is[system]search:title<userInput>sort[]]">
<div class="tc-edit-add-tag">
@ -80,15 +67,15 @@ $actions$
<$set name="userInput" value={{{ [<storeTitle>get[text]] }}}>
<$list filter="[<userInput>minlength{$:/config/Tags/MinLength}limit[1]]" emptyMessage="""<div class="tc-search-results">{{$:/language/Search/Search/TooShort}}</div>""" variable="listItem">
<$list filter=<<nonSystemTagsFilter>> variable="tag">
<$list filter="[<tag>addsuffix[-primaryList]] -[<tagSelectionState>get[text]]" emptyMessage="""<$macrocall $name="tag-button" actions=<<__actions__>> selectedClass="tc-tag-button-selected"/>""">
<$macrocall $name="tag-button" actions=<<__actions__>> tagField=<<__tagField__>>/>
<$list filter="[<tag>addsuffix[-primaryList]] -[<tagSelectionState>get[text]]" emptyMessage="""<$vars button-classes="tc-btn-invisible tc-tag-button-selected" actions=<<__actions__>> tagField=<<__tagField__>> currentTiddler=<<tag>>>{{||$:/core/ui/TagPickerTagTemplate}}</$vars>""">
<$vars button-classes="tc-btn-invisible" actions=<<__actions__>> tagField=<<__tagField__>> currentTiddler=<<tag>>>{{||$:/core/ui/TagPickerTagTemplate}}</$vars>
</$list>
</$list></$list>
<hr>
<$list filter="[<userInput>minlength{$:/config/Tags/MinLength}limit[1]]" emptyMessage="""<div class="tc-search-results">{{$:/language/Search/Search/TooShort}}</div>""" variable="listItem">
<$list filter=<<systemTagsFilter>> variable="tag">
<$list filter="[<tag>addsuffix[-secondaryList]] -[<tagSelectionState>get[text]]" emptyMessage="""<$macrocall $name="tag-button" actions=<<__actions__>> selectedClass="tc-tag-button-selected"/>""">
<$macrocall $name="tag-button" actions=<<__actions__>> tagField=<<__tagField__>>/>
<$list filter="[<tag>addsuffix[-secondaryList]] -[<tagSelectionState>get[text]]" emptyMessage="""<$vars button-classes="tc-btn-invisible tc-tag-button-selected" actions=<<__actions__>> tagField=<<__tagField__>> currentTiddler=<<tag>>>{{||$:/core/ui/TagPickerTagTemplate}}</$vars>""">
<$vars button-classes="tc-btn-invisible" actions=<<__actions__>> tagField=<<__tagField__>> currentTiddler=<<tag>>>{{||$:/core/ui/TagPickerTagTemplate}}</$vars>
</$list>
</$list></$list>
</$set>
@ -102,11 +89,11 @@ $actions$
\end
\define tag-picker(actions,tagField:"tags")
\whitespace trim
<$set name="saveTiddler" value=<<currentTiddler>>>
<$vars saveTiddler=<<currentTiddler>> palette={{$:/palette}}>
<$list filter="[<newTagNameTiddler>match[]]" emptyMessage="""<$macrocall $name="tag-picker-inner" actions=<<__actions__>> tagField=<<__tagField__>>/>""">
<$set name="newTagNameTiddler" value=<<qualify "$:/temp/NewTagName">>>
<$macrocall $name="tag-picker-inner" actions=<<__actions__>> tagField=<<__tagField__>>/>
</$set>
</$list>
</$set>
</$vars>
\end

View File

@ -1,56 +0,0 @@
title: $:/themes/codemirror/tiddlywiki
tags: $:/tags/Stylesheet
module-type: codemirror-theme
name: tiddlywiki
.cm-s-tiddlywiki {
font-size: 1em;
line-height: 1.5em;
letter-spacing: 0.3px;
word-spacing: 1px;
background: <<colour page-background>>;
color: <<colour foreground>>;
}
.cm-s-tiddlywiki .CodeMirror-lines {
padding: 8px 0;
}
.cm-s-tiddlywiki .CodeMirror-gutters {
background-color: <<colour page-background>>;
padding-right: 10px;
z-index: 3;
border: none;
}
.cm-s-tiddlywiki div.CodeMirror-cursor {
border-left: 3px solid <<colour very-muted-foreground>>;
}
.cm-s-tiddlywiki .CodeMirror-activeline-background {
background: <<colour tiddler-editor-fields-even>>;
}
.cm-s-tiddlywiki .CodeMirror-selected {
background: <<colour muted-foreground>>;
}
.cm-s-tiddlywiki .cm-comment {
font-style: italic;
color: <<colour muted-foreground>>;
}
.cm-s-tiddlywiki .CodeMirror-linenumber {
color: italic;
}
.cm-s-tiddlywiki span.cm-atom, .cm-s-tiddlywiki span.cm-number, .cm-s-tiddlywiki span.cm-keyword, .cm-s-tiddlywiki span.cm-variable, .cm-s-tiddlywiki span.cm-attribute, .cm-s-tiddlywiki span.cm-quote, .cm-s-tiddlywiki-light span.cm-hr, .cm-s-tiddlywiki-light span.cm-link { color: #063289; }
.cm-s-tiddlywiki span.cm-property { color: #b29762; }
.cm-s-tiddlywiki span.cm-punctuation, .cm-s-tiddlywiki span.cm-unit, .cm-s-tiddlywiki span.cm-negative { color: #063289; }
.cm-s-tiddlywiki span.cm-string, .cm-s-tiddlywiki span.cm-operator { color: #1659df; }
.cm-s-tiddlywiki span.cm-positive { color: #896724; }
.cm-s-tiddlywiki span.cm-variable-2, .cm-s-tiddlywiki span.cm-variable-3, .cm-s-tiddlywiki span.cm-type, .cm-s-tiddlywiki span.cm-string-2, .cm-s-tiddlywiki span.cm-url { color: #896724; }
.cm-s-tiddlywiki span.cm-def, .cm-s-tiddlywiki span.cm-tag, .cm-s-tiddlywiki span.cm-builtin, .cm-s-tiddlywiki span.cm-qualifier, .cm-s-tiddlywiki span.cm-header, .cm-s-tiddlywiki span.cm-em { color: #2d2006; }
.cm-s-tiddlywiki span.cm-bracket, .cm-s-tiddlywiki span.cm-comment { color: #b6ad9a; }
/* using #f00 red for errors, don't think any of the colorscheme variables will stand out enough, ... maybe by giving it a background-color ... */
/* .cm-s-tiddlywiki span.cm-error { background: #896724; color: #728fcb; } */
.cm-s-tiddlywiki span.cm-error, .cm-s-tiddlywiki span.cm-invalidchar { color: #f00; }
.cm-s-tiddlywiki span.cm-header { font-weight: normal; }
.cm-s-tiddlywiki .CodeMirror-matchingbracket { text-decoration: underline; color: #faf8f5 !important; }

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,12 @@
{
"tiddlers": [
{
"file": "../../../tw5.com/tiddlers/images/New Release Banner.png",
"fields": {
"type": "image/jpg",
"title": "New Release Banner",
"tags": "picture"
}
}
]
}

View File

@ -1,7 +1,7 @@
caption: Was ist neu in <<version>>
color: #fff
created: 20150513145829381
image: New Release Banner.png
image: New Release Banner
link: Releases
modified: 20150518143526750
tags: HelloThumbnail

View File

@ -1,6 +1,6 @@
caption: 5.1.23
created: 20201018143621963
modified: 20201018143621963
created: 20201128173201204
modified: 20201128173201204
tags: ReleaseNotes
title: Release 5.1.23
type: text/vnd.tiddlywiki
@ -9,7 +9,7 @@ type: text/vnd.tiddlywiki
! Major Improvements
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4725]] support for navigating the search and new tag dropdowns via the keyboard. The [[keyboard-driven-input Macro]] can be used to add this capability to other dropdowns.
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4725]] support for navigating the search and new tag dropdowns via the keyboard. The [[keyboard-driven-input Macro]] can be used to add this capability to other dropdowns
* [[New|https://github.com/Jermolene/TiddlyWiki5/commit/4a84ed0018df7fd67000404bb5ef8a7ca50509c1]] [[Consent Banner Plugin]] to help make websites compliant with cookie legislation by displaying a consent banner
* [[Extended|https://github.com/Jermolene/TiddlyWiki5/commit/6a0ff7db1807f45b73061ced82f5a85f1a529bbf]] [[JSZip Plugin]] ability to dynamically create Zip files, giving TiddlyWiki the ability to build static sites within the browser
* [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/14a28b77796461c9167898793ab9851e029e0354]] new [[filter|filter Operator]] and [[reduce|reduce Operator]] operators for processing lists of items
@ -20,15 +20,25 @@ type: text/vnd.tiddlywiki
* New Arabic (Palestine) translation
* Improved Catalan translation
* Improved Chinese translation
* Improved Dutch translation
* Improved French translation
* Improved German translation
! Performance Improvements
* [[Updated|https://github.com/Jermolene/TiddlyWiki5/pull/4659]] templates to use a single VarsWidget instead of several [[SetVariableWidgets|SetVariableWidget]], for improved performance and easier debugging
* [[Updated|https://github.com/Jermolene/TiddlyWiki5/pull/4954]] ListWidget to not initialize parsers for blank `emptyMessage` attributes.
* [[Refactored|https://github.com/Jermolene/TiddlyWiki5/pull/4200]] `story.js` to remove dependency on `wiki.js` for story start up and navigator.
* [[Updated|https://github.com/Jermolene/TiddlyWiki5/pull/4954]] ListWidget to not initialize parsers for blank `emptyMessage` attributes
* [[Refactored|https://github.com/Jermolene/TiddlyWiki5/pull/4200]] `story.js` to remove dependency on `wiki.js` for story start up and navigator
! Usability Improvements
* Several improvements to the import mechanism:
** [[Improved|https://github.com/Jermolene/TiddlyWiki5/commit/527638d5e60114653385ed39dc55c736a67e58d2]] status messages in the import listing
** [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/5067]] colour coding for import items that will overwrite existing tiddlers, and for other warnings
** [[Extended|https://github.com/Jermolene/TiddlyWiki5/pull/4937]] the Import UI to allow renaming tiddlers and to warn about tiddlers that already exist
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/5037]] new ActionConfirm widget
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/5092]] new "Desert Sand" palette
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/5100]] new "Cupertino Dark" palette
* [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/8cf458d3b3f1e38c14a2819529e08dca4a7e297c]] "Solarized Dark" palette
* [[Updated|https://github.com/Jermolene/TiddlyWiki5/pull/4590]] (and [[here|https://github.com/Jermolene/TiddlyWiki5/commit/274a07b4fd2ca2d1b95c8ddf52fe055c44260d9b]]) the Vanilla theme to optionally use palette colours for the [[browser selection outline|https://developer.mozilla.org/en-US/docs/Web/CSS/::selection]]
* [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/1546a4a1895b93a47b79c9d37b94be039604443a]] warning message about using the online plugin library with the client-server configuration
@ -36,34 +46,44 @@ type: text/vnd.tiddlywiki
* [[Changed|https://github.com/Jermolene/TiddlyWiki5/commit/9cd5415dfe54b47819920aa3cf6ac2d5e3a9188e]] favicon for the prerelease edition
* [[Fixed|https://github.com/Jermolene/TiddlyWiki5/commit/484c9e986fc6f323e30460a88f134da3a4e8a89e]] the $:/PaletteManager to show "indirect" colours (ie, colours defined by another `<<colour>>` macro)
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4791]] a 'tabIndex' property to the tiddler editor input area to make it easier to use the tab key to move between edit controls
* [[Extended|https://github.com/Jermolene/TiddlyWiki5/pull/4937]] the Import UI to allow renaming tiddlers and to warn about tiddlers that already exist.
* Added keyboard support:
** [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4909]] keyboard support for cycling through the tabs in $:/AdvancedSearch.
** [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4921]] keyboard support for navigating the field name dropdown in the Edit Template.
** [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4989]] keyboard support or navigating the `type` field input in the Edit Template.
** [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4919]] keyboard support for using the ''insert wikilink'' toolbar dropdown in the Edit Template.
** [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4927]] keyboard shortcut for saving the wiki.
** [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4978]] keyboard shortcut for deleting a field in the Edit Template.
** [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4909]] keyboard support for cycling through the tabs in $:/AdvancedSearch
** [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4921]] keyboard support for navigating the field name dropdown in the Edit Template
** [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4989]] keyboard support or navigating the `type` field input in the Edit Template
** [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4919]] keyboard support for using the ''insert wikilink'' toolbar dropdown in the Edit Template
** [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4927]] keyboard shortcut for saving the wiki
** [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4978]] keyboard shortcut for deleting a field in the Edit Template
* [[Removed|https://github.com/Jermolene/TiddlyWiki5/commit/22e25c05eb5e5cc5b670a362d1eead1d62dedbb9]] normalize.css's styling of search input fields and [[updated|https://github.com/Jermolene/TiddlyWiki5/commit/9003c810393d90ee20db083fda35b6469acc592a]] to a modern fork of normalize.css
* [[Removed|https://github.com/Jermolene/TiddlyWiki5/commit/bb6fee4e1c79a2b1cbf75cd0326ecb8fb1ccb86b]] unneeded editor toolbar buttons when editing SVG tiddlers
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/5089]] global keyboard shortcut for switching layouts
* [[Updated|https://github.com/Jermolene/TiddlyWiki5/pull/5128]] the [[CodeMirror Plugin]] and the [[Hightlight Plugin]] to use palette colours
! Filter Improvements
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/5080]] [[power Operator]] and [[log Operator]]
* [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/4966f6ab625c8ce2c9f0812a726ba928d68ea00b]] new [[slugify Operator]] and [[duplicateslugs Operator]] for generating human readable filenames/URLs
* [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/619c0752bd3c6e71d1fcdb74daa03cfe8257afe4]] new [[sortsub Operator]] for sorting by a user defined subfilter
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4785]] new [[format Operator]] for formatting dates
* [[Extended|https://github.com/Jermolene/TiddlyWiki5/pull/4811]] the [[trim Operator]] to optionally trim a given string instead of whitespace, and trim from front, back, or both sides of input tiddlers
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4991]] new [[draft Operator|is Operator]] to check if a tiddler is a draft of another tiddler.
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4973]] new [[search-replace Operator]] to search and replace in strings.
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4948]] new [[enlist-input Operator]] to parse its input titles as a title lists.
* [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/14a28b77796461c9167898793ab9851e029e0354]] new [[reduce Operator]] to apply a subfilter to each input title in turn, accumulating a single value .
* [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/14a28b77796461c9167898793ab9851e029e0354]] new [[filter Operator]] to apply a subfilter to each input title and return the titles that return a non-empty result from the subfilter.
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4918]] new [[:filter filter run prefix|Filter Expression]] which is analagous to the new [[filter Operator]] but applies to a filter run.
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4959]] new [[:intersection filter run prefix|Filter Expression]] to get the intersection of two filter runs.
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4990]] new [[toggle Operator]] to toggle a title in a list.
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4991]] new [[draft Operator|is Operator]] to check if a tiddler is a draft of another tiddler
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4973]] new [[search-replace Operator]] to search and replace in strings
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4948]] new [[enlist-input Operator]] to parse its input titles as a title lists
* [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/14a28b77796461c9167898793ab9851e029e0354]] new [[reduce Operator]] to apply a subfilter to each input title in turn, accumulating a single value
* [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/14a28b77796461c9167898793ab9851e029e0354]] new [[filter Operator]] to apply a subfilter to each input title and return the titles that return a non-empty result from the subfilter
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4918]] new [[:filter filter run prefix|Filter Expression]] which is analagous to the new [[filter Operator]] but applies to a filter run
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4959]] new [[:intersection filter run prefix|Filter Expression]] to get the intersection of two filter runs
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4990]] new [[toggle Operator]] to toggle a title in a list
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/5021]] new [[cycle Operator]]
! Hackability Improvements
* [[Extended|https://github.com/Jermolene/TiddlyWiki5/pull/5091]] ButtonWidget and DroppableWidget so that changing the class attribute does not trigger a refresh. This makes it easier to use classes to trigger CSS animations
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/5086]] EventCatcherWidget for low level event handling
* [[Extended|https://github.com/Jermolene/TiddlyWiki5/pull/5087]] the RevealWidget to optionally dynamically refresh popup positions when the state tiddler changes
* [[Fixed|https://github.com/Jermolene/TiddlyWiki5/pull/5027]] modals to incorporate a NavigatorWidget so that links work as expected
* [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/1b31c25ea77ee4dce86a9aac4375337423ebd3a6]] new LogWidget and ActionLogWidget to help debugging
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/5014]] support for ''disabled'' attribute to EditWidget, EditTextWidget, CheckboxWidget, RadioWidget and RangeWidget
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/5010]] support for ''disabled'' attribute to ButtonWidget
* [[Extended|https://github.com/Jermolene/TiddlyWiki5/commit/5af76c5ea10db2b59cc20f963a836c6a9faa8b10]] the [[Table-of-Contents Macros]] to support custom link targets
* [[Extended|https://github.com/Jermolene/TiddlyWiki5/commit/ae13a0fee118c50169b7835c950df1dade33788f]] the MacroCallWidget to be able to optionally render the raw text of the macro (previously the output was always wikified)
* [[Adedd|https://github.com/Jermolene/TiddlyWiki5/pull/4777]] new Hyperdrive saver for use with Beaker Browser v1.0
@ -82,26 +102,31 @@ type: text/vnd.tiddlywiki
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4724]] original event to `tm-navigate` event
* [[Extended|https://github.com/Jermolene/TiddlyWiki5/commit/651fb777abd11c88e58b4bdfbced01d6db508852]] the password prompt to enable it to be customised
* [[Extended|https://github.com/Jermolene/TiddlyWiki5/commit/69c12618d963c711edd72a60427bd15ec4fa0e6e]] syncer to enable syncadaptors to customise the login prompt
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4979]] support for switching page templates.
* [[Extended|https://github.com/Jermolene/TiddlyWiki5/commit/a1b486436e9278078c524c6aa11f7f4de6cbc877]] the [[tabs Macro]] to support `actions` and `explicitState` attributes.
* [[Updated|https://github.com/Jermolene/TiddlyWiki5/pull/4906]] (and [[here|https://github.com/Jermolene/TiddlyWiki5/pull/4907]]) filters used for syncing on node.js and saving the single file version to exclude multiple story lists and history lists based on their prefix, as well as multiple tiddlers that might be used for the import process.
* [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/5cc1600072f5aa50c8ff5f5d2e748d81a7067420]] post-render startup actions.
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4979]] support for switching page templates
* [[Extended|https://github.com/Jermolene/TiddlyWiki5/commit/a1b486436e9278078c524c6aa11f7f4de6cbc877]] the [[tabs Macro]] to support `actions` and `explicitState` attributes
* [[Updated|https://github.com/Jermolene/TiddlyWiki5/pull/4906]] (and [[here|https://github.com/Jermolene/TiddlyWiki5/pull/4907]]) filters used for syncing on node.js and saving the single file version to exclude multiple story lists and history lists based on their prefix, as well as multiple tiddlers that might be used for the import process
* [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/5cc1600072f5aa50c8ff5f5d2e748d81a7067420]] post-render startup actions
* [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/f7f55e8eff8b172d8fd04f095781efa2420b1be6]] support for username/password parameters for `tm-login` message
* [[Extended|https://github.com/Jermolene/TiddlyWiki5/pull/4914]] [[tiddlywiki.files Files]] specification with `isEditableFile` attribute allowing files to be saved back to their original location.
* [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/4c6de2271124fc3a4b01e4324a0d5e401500cca2]] support for the content type `image/jpg`.
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4908]] support for an override saver.
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4923]] utility CSS classes to replace use of `&nbsp;` to introduce visual separation.
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4952]] a keyboard shortcut to change the sidebar layout.
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4983]] option to configure the tag used for TableOfContents in the menubar.
* [[Modified|https://github.com/Jermolene/TiddlyWiki5/pull/4971]] the KeyboardWidget to not trap keys if there are no actions to be invoked.
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4975]] buttons to the Edit Template toolbar for the editor-height and the stamp tool for tiddlers of type `application/javascript`,`application/json` and `application/x-tiddler-dictionary`.
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4915]] support for named filter run prefixes.
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4964]] support for multiple operands for filter operators.
* [[Updated|https://github.com/Jermolene/TiddlyWiki5/pull/4985]] all instance of the [[tabs Macro]] in the core to use the explicitState attribute.
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/5000]] support for the `meta` key as a modifier in actions.
* [[Extended|https://github.com/Jermolene/TiddlyWiki5/pull/4914]] [[tiddlywiki.files Files]] specification with `isEditableFile` attribute allowing files to be saved back to their original location
* [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/4c6de2271124fc3a4b01e4324a0d5e401500cca2]] support for the content type `image/jpg`
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4908]] support for an override saver
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4923]] utility CSS classes to replace use of `&nbsp;` to introduce visual separation
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4952]] a keyboard shortcut to change the sidebar layout
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4983]] option to configure the tag used for TableOfContents in the menubar
* [[Modified|https://github.com/Jermolene/TiddlyWiki5/pull/4971]] the KeyboardWidget to not trap keys if there are no actions to be invoked
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4975]] buttons to the Edit Template toolbar for the editor-height and the stamp tool for tiddlers of type `application/javascript`,`application/json` and `application/x-tiddler-dictionary`
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4915]] support for named filter run prefixes
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4964]] support for multiple operands for filter operators
* [[Updated|https://github.com/Jermolene/TiddlyWiki5/pull/4985]] all instance of the [[tabs Macro]] in the core to use the explicitState attribute
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/5000]] support for the `meta` key as a modifier in actions
* [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/c854e518faa2d2661b7b7278634b10607ab0a5f5]] support for $:/info/darkmode to the InfoMechanism, reflecting the browser dark mode vs. light mode setting
! Bug Fixes
* [[Fixed|https://github.com/Jermolene/TiddlyWiki5/pull/5126]] "409 conflict" errors with the ~GitHub saver when saving within 60 seconds of the last save
* [[Fixed|https://github.com/Jermolene/TiddlyWiki5/pull/5088]] incorrect behaviour of default values with [[lookup Operator]]
* [[Restored|https://github.com/Jermolene/TiddlyWiki5/pull/4987]] behaviour of system tiddler syncing with the client server configuration. By default, changes to system tiddlers are not synced from the server to the client, restoring the behaviour from v5.1.21 and earlier. Bidirectional syncing of system tiddlers can be enabled with the configuration tiddler $:/config/SyncSystemTiddlersFromServer
* [[Fixed|https://github.com/Jermolene/TiddlyWiki5/commit/cc3462999b80461fe30b8f4b4f272ccfbbb78b35]] content type of imported `.tid` files that do not have a `type` field
* [[Fixed|https://github.com/Jermolene/TiddlyWiki5/pull/4632]] hover effect for search dropdown items
* [[Fixed|https://github.com/Jermolene/TiddlyWiki5/pull/4584]] restored missing parameter to `saveTiddler()` method of syncadaptors
* [[Fixed|https://github.com/Jermolene/TiddlyWiki5/commit/678e25f510786fbc38f505f8b594f57f39e33a04]] MakeLibraryCommand to skip non-directories
@ -130,12 +155,14 @@ type: text/vnd.tiddlywiki
* [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4751]] a `plugin-priority` field to the TiddlyWeb plugin so that language plugins can override its language strings
* [[Fixed|https://github.com/Jermolene/TiddlyWiki5/pull/4853]] bug whereby joining an empty list would not return an empty list
* [[Fixed|https://github.com/Jermolene/TiddlyWiki5/commit/59f233cd46616646fa8889f65aa9cc7d704d8c9a]] bug exporting tiddlers with double quoted titles
* [[Fixed|https://github.com/Jermolene/TiddlyWiki5/issues/4900]] bug with syncing plugin tiddlers.
* [[Fixed|https://github.com/Jermolene/TiddlyWiki5/commit/4877891980f077c6c31e99cc6a9eb45b5d1230e1]] bug with the position of the tiddler title when there is no icon in use.
* [[Disabled|https://github.com/Jermolene/TiddlyWiki5/commit/3153c588ecddfdc97cc8289720d36b1fb15ef236]] autosave in the upgrade wizard.
* [[Disabled|https://github.com/Jermolene/TiddlyWiki5/pull/4938]] saving of `$:/temp` tiddlers in single file wikis.
* [[Fixed|https://github.com/Jermolene/TiddlyWiki5/pull/4839]] a bug with the `sortan` filter operator when used with date fields.
* [[Fixed|https://github.com/Jermolene/TiddlyWiki5/pull/4947]] a bug for location hashes that contain a `#` character.
* [[Fixed|https://github.com/Jermolene/TiddlyWiki5/issues/4900]] bug with syncing plugin tiddlers
* [[Fixed|https://github.com/Jermolene/TiddlyWiki5/commit/4877891980f077c6c31e99cc6a9eb45b5d1230e1]] bug with the position of the tiddler title when there is no icon in use
* [[Disabled|https://github.com/Jermolene/TiddlyWiki5/commit/3153c588ecddfdc97cc8289720d36b1fb15ef236]] autosave in the upgrade wizard
* [[Disabled|https://github.com/Jermolene/TiddlyWiki5/pull/4938]] saving of `$:/temp` tiddlers in single file wikis
* [[Fixed|https://github.com/Jermolene/TiddlyWiki5/pull/4839]] a bug with the `sortan` filter operator when used with date fields
* [[Fixed|https://github.com/Jermolene/TiddlyWiki5/pull/4947]] a bug for location hashes that contain a `#` character
* [[Fixed|https://github.com/Jermolene/TiddlyWiki5/pull/5055]] default branch to ''main'' for saving to ~GitHub
* [[Fixed|https://github.com/Jermolene/TiddlyWiki5/commit/7327a3fb92fa2ae17d7264c66ab0409d43b18fdc]] shadow tiddlers not refreshing when their plugin is deleted or modified
! Plugin Improvements
@ -153,7 +180,7 @@ type: text/vnd.tiddlywiki
** [[Fixed|https://github.com/Jermolene/TiddlyWiki5/pull/4680]] encoding of Markdown image files
** [[Fixed|https://github.com/Jermolene/TiddlyWiki5/commit/e01b354f7d9e137cb355f7090f5e68661a4ead41]] issue with whitespace and linebreaks
** [[Added|https://github.com/Jermolene/TiddlyWiki5/pull/4862]] ''tc-tiddlylink-external'' class to external links
** [[Fixed|https://github.com/Jermolene/TiddlyWiki5/pull/4771]] to add `rel="noopener noreferrer"` to external links.
** [[Fixed|https://github.com/Jermolene/TiddlyWiki5/pull/4771]] to add `rel="noopener noreferrer"` to external links
* [[Amazon Web Services Plugin]]
** [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/0338f0fee23d176a94de9009492d2e43a916fbfa]] a new ''aws-encodeuricomponent'' filter that also encodes single quotes
* ~BibTeX Plugin
@ -161,9 +188,9 @@ type: text/vnd.tiddlywiki
* Menubar Plugin
** [[Updated|https://github.com/Jermolene/TiddlyWiki5/pull/4974]] so the top margin of the side bar adjusts to the height of the menu
* Dynannotate Plugin
** [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/4394b8e723f78b3d2562a95155aeb91a3d6bbd5f]] examples of usage in the View Template.
** [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/4394b8e723f78b3d2562a95155aeb91a3d6bbd5f]] examples of usage in the View Template
* External Attachments Plugin
** [[Fixed|https://github.com/Jermolene/TiddlyWiki5/issues/4549]] a bug with relative paths in the External Attachments plugin.
** [[Fixed|https://github.com/Jermolene/TiddlyWiki5/issues/4549]] a bug with relative paths in the External Attachments plugin
! Contributors
@ -175,6 +202,7 @@ type: text/vnd.tiddlywiki
* [[@BramChen|https://github.com/BramChen]]
* [[@BurningTreeC|https://github.com/BurningTreeC]]
* [[@danielo515|https://github.com/danielo515]]
* [[@default-kramer|https://github.com/default-kramer]]
* [[@ento|https://github.com/ento]]
* [[@favadi|https://github.com/favadi]]
* [[@fkohrt|https://github.com/fkohrt]]
@ -184,13 +212,15 @@ type: text/vnd.tiddlywiki
* [[@idotobi|https://github.com/idotobi]]
* [[@jdangerx|https://github.com/jdangerx]]
* [[@jjduhamel|https://github.com/jjduhamel]]
* [[@kookma|https://github.com/kookma]]
* [[@Kamal-Habash|https://github.com/Kamal-Habash]]
* [[@Marxsal|https://github.com/Marxsal]]
* [[@mocsa|https://github.com/mocsa]]
* [[@NicolasPeton|https://github.com/NicolasPeton]]
* [[@NicolasPetton|https://github.com/NicolasPetton]]
* [[@passuf|https://github.com/passuf]]
* [[@pmario|https://github.com/pmario]]
* [[@rmunn|https://github.com/rmunn]]
* [[@SmilyOrg|https://github.com/SmilyOrg]]
* [[@saqimtiaz|https://github.com/saqimtiaz]]
* [[@twMat|https://github.com/twMat]]
* [[@default-kramer|https://github.com/default-kramer]]
* [[@xcazin|https://github.com/xcazin]]

View File

@ -184,6 +184,9 @@ function runTests(wiki) {
it("should handle the enlist-input operator", function() {
expect(wiki.filterTiddlers("[[one two three]enlist-input[]]").join(",")).toBe("one,two,three");
expect(wiki.filterTiddlers("[[one two two three]enlist-input[]]").join(",")).toBe("one,two,three");
expect(wiki.filterTiddlers("[[one two two three]enlist-input:dedupe[]]").join(",")).toBe("one,two,three");
expect(wiki.filterTiddlers("[[one two two three]enlist-input:raw[]]").join(",")).toBe("one,two,two,three");
expect(wiki.filterTiddlers("[[one two three]] [[four five six]] +[enlist-input[]]").join(",")).toBe("one,two,three,four,five,six");
expect(wiki.filterTiddlers("[[one two three]] [[four five six]] [[seven eight]] +[enlist-input[]]").join(",")).toBe("one,two,three,four,five,six,seven,eight");
expect(wiki.filterTiddlers("[[]] +[enlist-input[]]").join(",")).toBe("");
@ -207,7 +210,7 @@ function runTests(wiki) {
it("should handle the lookup operator", function() {
expect(wiki.filterTiddlers("Six Seventh 8 +[lookup[Tiddler]]").join(",")).toBe("Missing inaction from TiddlerOne,,Tidd");
expect(wiki.filterTiddlers("Six Seventh 8 +[lookup:8[Tiddler]]").join(",")).toBe("Missing inaction from TiddlerOne,Tidd,Tidd");
expect(wiki.filterTiddlers("Six Seventh 8 +[lookup:8[Tiddler]]").join(",")).toBe("Missing inaction from TiddlerOne,8,Tidd");
});
it("should retrieve shadow tiddlers", function() {
@ -456,7 +459,7 @@ function runTests(wiki) {
it("should handle indirect operands", function() {
expect(wiki.filterTiddlers("[prefix{Tiddler8}] +[sort[title]]").join(",")).toBe("Tiddler Three,TiddlerOne");
expect(wiki.filterTiddlers("[modifier{Tiddler8!!test-field}] +[sort[title]]").join(",")).toBe("TiddlerOne");
var fakeWidget = {getVariable: function() {return "Tiddler Three";}};
var fakeWidget = {wiki: wiki, getVariable: function() {return "Tiddler Three";}};
expect(wiki.filterTiddlers("[modifier{!!modifier}] +[sort[title]]",fakeWidget).join(",")).toBe("$:/TiddlerTwo,a fourth tiddler,one,Tiddler Three");
});
@ -777,6 +780,17 @@ function runTests(wiki) {
expect(wiki.filterTiddlers("[[Hello There]search-replace::regexp<myregexp>,[]]",anchorWidget).join(",")).toBe("Hllo There");
expect(wiki.filterTiddlers("[[Hello There]search-replace:gi[H],[]]",anchorWidget).join(",")).toBe("ello Tere");
});
it("should handle the pad operator", function() {
expect(wiki.filterTiddlers("[[2]pad[]]").join(",")).toBe("2");
expect(wiki.filterTiddlers("[[2]pad[0]]").join(",")).toBe("2");
expect(wiki.filterTiddlers("[[2]pad[1]]").join(",")).toBe("2");
expect(wiki.filterTiddlers("2 20 +[pad[3]]").join(",")).toBe("002,020");
expect(wiki.filterTiddlers("[[2]pad[9]]").join(",")).toBe("000000002");
expect(wiki.filterTiddlers("[[2]pad[9],[a]]").join(",")).toBe("aaaaaaaa2");
expect(wiki.filterTiddlers("[[12]pad[9],[abc]]").join(",")).toBe("abcabca12");
expect(wiki.filterTiddlers("[[12]pad:suffix[9],[abc]]").join(",")).toBe("12abcabca");
});
}
});

View File

@ -25,6 +25,16 @@ describe("Utility tests", function() {
expect(psa(" [[Tidd\u00a0ler8]] two ")).toEqual(["Tidd\u00a0ler8","two"]);
});
it("should handle parsing a date", function() {
var pd = function(v) {
return $tw.utils.parseDate(v).toUTCString();
};
expect(pd("20150428204930183")).toEqual("Tue, 28 Apr 2015 20:49:30 GMT");
expect(pd("-20150428204930183")).toEqual("Sun, 28 Apr -2015 20:49:30 GMT");
expect(pd("00730428204930183")).toEqual("Fri, 28 Apr 0073 20:49:30 GMT");
expect(pd("-00730428204930183")).toEqual("Thu, 28 Apr -0073 20:49:30 GMT");
});
it("should handle base64 encoding emojis", function() {
var booksEmoji = "📚";
expect(booksEmoji).toBe(booksEmoji);
@ -62,6 +72,8 @@ describe("Utility tests", function() {
var fds = $tw.utils.formatDateString,
// nov is month: 10!
d = new Date(2014,10,9,17,41,28,542);
expect(fds(d,"{era:bce||ce}")).toBe("ce");
expect(fds(d,"YYYY")).toBe("2014");
expect(fds(d,"DDD DD MMM YYYY")).toBe("Sunday 9 November 2014");
expect(fds(d,"ddd hh mm ssss")).toBe("Sun 17 41 2828");
expect(fds(d,"MM0DD")).toBe("1109");
@ -92,6 +104,19 @@ describe("Utility tests", function() {
d = new Date(2014,11,29,23,59,59);
expect(fds(d,"WW")).toBe("1");
expect(fds(d,"wYYYY")).toBe("2015");
// Negative years
d = new Date(-2014,10,9,17,41,28,542);
expect(fds(d,"YYYY")).toBe("-2014");
expect(fds(d,"aYYYY")).toBe("2014");
expect(fds(d,"{era:bce||ce}")).toBe("bce");
// Zero years
d = new Date(0,10,9,17,41,28,542);
d.setUTCFullYear(0); // See https://stackoverflow.com/a/5870822
expect(fds(d,"YYYY")).toBe("0000");
expect(fds(d,"aYYYY")).toBe("0000");
expect(fds(d,"{era:bce|z|ce}")).toBe("z");
});
it("should parse text references", function() {

View File

@ -0,0 +1,18 @@
created: 20201117155737569
modified: 20201117155943559
tags: Resources Plugings
title: Favorites by Mohammad
type: text/vnd.tiddlywiki
url: https://kookma.github.io/TW-Favorites/
Favorites plugin is a set of tool for creating favorites (bookmarks) in Tiddlywiki. Each favorite item is a shortcut to a tiddler.
{{!!url}}
A favorite item also called a bookmark is a shortcut, you are creating for quick access to it. You can access that bookmark at any time and view that as many times as you want without having to search and find it again.
The Favorites plugin contains three modes
* flat mode: one favorite list, no folder
* structured mode: use folder, search tool, export and delete tool
* frozen list: read only, simple table of content style

View File

@ -0,0 +1,23 @@
created: 20201117163027900
modified: 20201117163855463
tags: Resources
title: GitHub Saver Tutorial by Mohammad
type: text/vnd.tiddlywiki
url: https://kookma.github.io/TW5-GitHub-Saver/
GitHub Saver is a step by step tutorial shows how to integrate Tiddlywiki 5 and GitHub Pages to create websites hosted on https://github.com/.
{{!!url}}
This instruction is based on Tiddlywiki single html file model, while it can use subfolder for extra materials like images, audios, videos, pdfs,... in separate folders.
!! Other tutorials
;Tiddlywiki, Travis-CI and GitHub Pages
:https://kookma.github.io/Tiddlywiki-Travis-CI/
:This wiki shows how to set up websites hosted on [[GitHub Pages|https://pages.github.com/]] using [[Travis-CI|https://travis-ci.org]] and [[Tiddlywiki 5|https://tiddlywiki.com]] on Node.js.
;Tiddlywiki and GitHub Pages
:https://kookma.github.io/Tiddlywiki-and-GitHub-Pages/
:This instruction is based on local edit, save and push to GitHub. It does NOT use the new GitHub Saver mechanism (requires TW 5.1.20+) which lets edit and save directly from Tiddlywiki!

View File

@ -0,0 +1,15 @@
created: 20201117160603290
modified: 20201117160819308
tags: Resources Plugings
title: Kookma Plugin Library by Mohammad
type: text/vnd.tiddlywiki
url: https://kookma.github.io/TW-PluginLibrary/
This library contains most useful plugins developed under the name [[Kookma|https://github.com/kookma]] for Tiddlywiki 5.
{{!!url}}
It has two parts
The plugin library introduces a very simple mechanism like Tiddlywiki Official Plugin Library to let select among the published plugins and install any number of them you like.

View File

@ -0,0 +1,22 @@
created: 20201117161853918
modified: 20201117162122822
tags: Resources Plugings
title: Refnotes by Mohammad
type: text/vnd.tiddlywiki
url: https://kookma.github.io/Refnotes/
Refnotes plugin is a set of macros and stylesheets for creating abbreviations, footnotes and citations. It also makes tables of footnotes, abbreviations (glossaery) and references (bibliography table).
{{!!url}}
Refnotes contains codes and elements to
;Create and insert
:Abbreviation
:Footnote
:Reference
;Create tables of
:Abbreviations or glossary
:Footnotes and endnote
:References (bibliography) using different output style

View File

@ -0,0 +1,19 @@
created: 20201117164024930
modified: 20201117164308641
tags: Resources
title: RegExp in Tiddlywiki by Mohammad
type: text/vnd.tiddlywiki
url: http://tw-regexp.tiddlyspot.com/
~RegExp in Tiddlywiki contains practical use cases of reular expression in Tiddlywiki.
{{!!url}}
The regular expression is a way to describe complex search patterns using sequences of characters .
~RegExp in Tiddlywiki has four main parts
* Using regular expression to match a pattern in tiddler title
* Using regular expression to match a pattern in tiddler fields excluding tiddler text (body)
* Using regular expression to match a pattern in tiddler body (text field)
* Using regular expression for validation like username, password, etc.

View File

@ -0,0 +1,21 @@
created: 20201117160302426
modified: 20201117160443306
tags: Resources Plugings
title: Searchwikis by Mohammad
type: text/vnd.tiddlywiki
url: https://kookma.github.io/TW-Searchwikis/
Searchwikis plugin uses index (dataTiddler) to search multiple external Tiddlywikis.
{{!!url}}
It has two parts
# An indexer, to build an index of all tiddlers in an external wiki
# A search tool to search indexes and display a link to a tiddler found in an external wiki
Then one master wiki can hosts many index tiddlers and lets to search several external wikis through index tiddlers.
Searchwikis enable to have a central wiki and search all other wikis from one place.

View File

@ -0,0 +1,22 @@
created: 20201117162254751
modified: 20201117162601326
tags: Resources
title: Semantic Colors by Mohammad
type: text/vnd.tiddlywiki
url: https://kookma.github.io/TW-Semantic-Colors/
Semantic colors are set of CSS to apply colorful theme to individual tiddlers for categorization purpose.
{{!!url}}
Tiddlywiki "semantic colors" has two objectives:
# How it is simply possible to apply theme to an individual tiddler
# Use semantic colors for categorization
;Some use cases
:Learning materials (each topic, category can have dedicated semantic color, like learning a foreign language)
:Slideshow (section divider, each part can have a semantic color)
:Books and tutorials ( different semantic colors can be applied to chapters, specific subjects, like example tiddlers)
:Visual tags (instead of looking for tag bar and see to what category this subject (tiddler) belongs, you can identify it by its semantic color)

View File

@ -0,0 +1,32 @@
created: 20201116204317018
modified: 20201116210618803
tags: Resources Plugings
title: Shiraz by Mohammad
type: text/vnd.tiddlywiki
url: https://kookma.github.io/TW-Shiraz/
Shiraz plugin is a very small in size and framework to create stylish contents in Tiddlywiki.
{{!!url}}
Shiraz plugin contains extended markups, macros, styles, and many customization to empty Tiddlywiki and can be used as a ''starter kit''.
Some of Shiraz features are:
* Customized elements like, alerts, cards, panels, badges
* Dynamic tables
* Sortable tables
* Display on demand, slider, and details
* Images, basic image macros, slidein, and overlay images, polaroid and pretty images
* Table customization tools
* Sticky footer
* Multi columns tiddler
* Multi column story river
* List search
* Badge status
* Notebook style
* Test utilities
* Stylish buttons
Adding Shiraz plugin to any Tiddlywiki, convert it to a full production tool. Shiraz uses modified CSS classes from [[Bootstrap|https://getbootstrap.com/]].

View File

@ -0,0 +1,18 @@
created: 20201117162655614
modified: 20201117162926714
tags: Resources Plugings
title: Slider by Mohammad
type: text/vnd.tiddlywiki
url: https://kookma.github.io/slider/
Slider is a plugin to create an ordered set of tiddlers also called Trail.
{{!!url}}
A trail can be used to create a sequence of selected contents like step by step tutorial, guided help, lessons and similar.
The slider plugin user interface contains three sections
* A sidebar tab called Trails to manage trails
* A dashboard for each trail (where trail structure is managed)
* Tiddlers in a trail, also called slides

View File

@ -0,0 +1,22 @@
created: 20180830194141190
modified: 20201116203625120
tags: Resources
title: TW-Scripts by Mohammad
type: text/vnd.tiddlywiki
url: https://kookma.github.io/TW-Scripts/
TW-Scripts is one of the most comprehensive collections of solutions for Tiddlywiki 5.
{{!!url}}
TW-Scripts includes:
* Collected solutions to questions in [[Tiddlywiki Google groups|https://groups.google.com/group/TiddlyWiki]]
* Learn through examples
* Templates, stylesheets
* Wikitext, macros, and snippets
* Tips and tricks
* Search tools 

View File

@ -0,0 +1,25 @@
created: 20201116203717105
modified: 20201116204652385
tags: Resources Plugings
title: Tiddler Commander by Mohammad
type: text/vnd.tiddlywiki
url: https://kookma.github.io/TW-Commander/
Tiddler Commander plugin, in short ''Commander'' is a unique tool for batch operations on tiddlers.
{{!!url}}
Commander has many features including:
* Bulk tiddler creation/deletion
* Selective operation
* Combo search to filter and select tiddlers
* Title operation: add, remove prefixes and suffixes, also remove cahras form begining and end of title (on renaming tiddlers, [[relink|https://flibbles.github.io/tw5-relink/]] can be used to update title in other tiddlers)
* Tag operation: add, remove, replace
* Field operation: add, remove, rename, and set field value
* ~SnR, search and replace in all fields including text, tags, //title//, and common fields
* Inspect, to review and inspect tiddlers in one place, scroll among them and edit all fields (including common fields), tags, text (title is an exception!)
* Log, create logs of all operations
* Search, //save and load// any combination of filter search

View File

@ -0,0 +1,16 @@
created: 20201117160944367
modified: 20201117162735263
tags: Resources Plugings
title: Tiddlyshow by Mohammad
type: text/vnd.tiddlywiki
url: https://kookma.github.io/Tiddlyshow/
Tiddlyshow is a small application of Tiddlywiki for presentation and slideshow. It can also be used as a plugin.
{{!!url}}
Tiddlyshow contains the following features
* Tools for preparing slides
* Shortcut keys for navigation (forward and backward)
* Themes to colorify and customize the slideshow

View File

@ -0,0 +1,14 @@
created: 20201117161434779
modified: 20201117161728094
tags: Resources Plugings
title: Timelines by Mohammad
type: text/vnd.tiddlywiki
url: https://kookma.github.io/TW-Timelines/
Timelines plugin is for creating vertical and horizontal timeline and sequences.
{{!!url}}
The content or description and data of events are stored in individual tiddlers.
Timelines contain two timeline macros and two sequence macros. A sequence macro shows event contents in sequence not necessarily in chronological order. The order can be determined by tag or list field or other methods.

View File

@ -0,0 +1,14 @@
created: 20201116210711381
modified: 20201116212041642
tags: Resources Plugings
title: Todolist by Mohammad
type: text/vnd.tiddlywiki
url: https://kookma.github.io/TW-Todolist/
Todolist is a small pure wikitext plugin, contain all tools to work with todo list.
{{!!url}}
With Todolist, easily organize and prioritize your tasks and projects so youll always know exactly what to work on next.
Todolist creates custom UI and lets you to add new items, set priority, done/undone items, archive, delete. Using Todolist plugin it is possible to create several todo lists in one Tiddlywiki.

View File

@ -0,0 +1,14 @@
created: 20201117155328920
modified: 20201117155604253
tags: Resources Plugings
title: Trashbin by Mohammad
type: text/vnd.tiddlywiki
url: https://kookma.github.io/TW-Trashbin/
The concept behind Trashbin plugin is to have a simple mechanism to move deleted tiddlers to Trashbin and be able to restore them later if required.
{{!!url}}
The trash (also known as the Recycle Bin in Microsoft Windows) is a temporary storage for tiddlers that have been deleted in a Tiddlywiki by the user, but not yet permanently erased.
Typically, a trash bin is presented as a special storage, allowing the user to browse deleted (removed) tiddlers, undelete those that were deleted by mistake, or delete them permanently (either one by one, or by the "Empty Trash" function).

View File

@ -0,0 +1,13 @@
created: 20201117160011169
modified: 20201117160235750
tags: Resources Plugings
title: Utility by Mohammad
type: text/vnd.tiddlywiki
url: https://kookma.github.io/TW-Utility/
The utility plugin objective is to provide set of tools for developers and authors.
{{!!url}}
These tools include simple transclusions, show raw contents of tiddlers, author tools, wikitext macros, show fields in view mode, etc.

View File

@ -1,15 +1,16 @@
created: 20150117190213631
modified: 20150124214537000
modified: 20201201154211507
tags: Concepts
title: Date Fields
type: text/vnd.tiddlywiki
Certain [[fields|TiddlerFields]] of a tiddler are used to store dates and times.
Certain [[fields|TiddlerFields]] of a tiddler are used to store dates and times. TiddlyWiki supports dates from the year -9999 to the year 9999.
The two standard date fields are <<.field created>> and <<.field modified>>.
Values of date fields are 17-character strings:
Values of date fields are 17 or 18-character strings:
* <<.from-version "5.1.23">> an optional minus sign `-` to indicate a negative year
* 4 digits for the year
* 2 digits for the month
* 2 digits for the day

View File

@ -1,5 +1,5 @@
created: 20150917193630604
modified: 20150917193631731
modified: 20201129183045031
tags: Features
title: InfoPanel
type: text/vnd.tiddlywiki
@ -9,7 +9,7 @@ Each tiddler has a panel of additional information. To reveal it, click the <<.i
The info panel has the following tabs:
* ''Tools'' - This offers buttons for various actions you can perform on the tiddler. The checkbox next to each button lets you promote an action to the tiddler's toolbar - this will affect all of the tiddlers in your wiki
* ''References'', ''Tagging'', ''List'' and ''Listed'' - These list various kinds of related tiddlers. See [[Using links to navigate between tiddlers]]
* ''Backlinks'', ''Tagging'', ''List'' and ''Listed'' - These list various kinds of related tiddlers. See [[Using links to navigate between tiddlers]]
* ''Fields'' - This summarises all of the tiddler's [[fields|TiddlerFields]], except for ''text''
* ''Advanced'' - This indicates whether the tiddler is a [[shadow|ShadowTiddlers]]. If it is, this also reveals which plugin it comes from and whether it has been overridden by an ordinary tiddler

View File

@ -1,5 +1,6 @@
created: 20130822080600000
modified: 20180927080631239
list: [[SystemTag: $:/tags/AboveStory]] [[SystemTag: $:/tags/AdvancedSearch]] [[SystemTag: $:/tags/AdvancedSearch/FilterButton]] [[SystemTag: $:/tags/Alert]] [[SystemTag: $:/tags/BelowStory]] [[SystemTag: $:/tags/ControlPanel]] [[SystemTag: $:/tags/ControlPanel/Advanced]] [[SystemTag: $:/tags/ControlPanel/Appearance]] [[SystemTag: $:/tags/ControlPanel/Info]] [[SystemTag: $:/tags/ControlPanel/Saving]] [[SystemTag: $:/tags/ControlPanel/Settings]] [[SystemTag: $:/tags/ControlPanel/Toolbars]] [[SystemTag: $:/tags/EditorToolbar]] [[SystemTag: $:/tags/EditPreview]] [[SystemTag: $:/tags/EditTemplate]] [[SystemTag: $:/tags/EditToolbar]] [[SystemTag: $:/tags/Exporter]] [[SystemTag: $:/tags/Filter]] [[SystemTag: $:/tags/Image]] [[SystemTag: $:/tags/ImportPreview]] [[SystemTag: $:/tags/KeyboardShortcut]] [[SystemTag: $:/tags/Layout]] [[SystemTag: $:/tags/Macro]] [[SystemTag: $:/tags/Macro/View]] [[SystemTag: $:/tags/Manager/ItemMain]] [[SystemTag: $:/tags/Manager/ItemSidebar]] [[SystemTag: $:/tags/MoreSideBar]] [[SystemTag: $:/tags/MoreSideBar/Plugins]] [[SystemTag: $:/tags/PageControls]] [[SystemTag: $:/tags/PageTemplate]] [[SystemTag: $:/tags/Palette]] [[SystemTag: $:/tags/PluginLibrary]] [[SystemTag: $:/tags/RawMarkup]] [[SystemTag: $:/tags/RawMarkupWikified]] [[SystemTag: $:/tags/RawMarkupWikified/BottomBody]] [[SystemTag: $:/tags/RawMarkupWikified/TopBody]] [[SystemTag: $:/tags/RawMarkupWikified/TopHead]] [[SystemTag: $:/tags/RawStaticContent]] [[SystemTag: $:/tags/RemoteAssetInfo]] [[SystemTag: $:/tags/SearchResults]] [[SystemTag: $:/tags/ServerConnection]] [[SystemTag: $:/tags/SideBar]] [[SystemTag: $:/tags/SideBarSegment]] [[SystemTag: $:/tags/StartupAction]] [[SystemTag: $:/tags/StartupAction/Browser]] [[SystemTag: $:/tags/StartupAction/Node]] [[SystemTag: $:/tags/Stylesheet]] [[SystemTag: $:/tags/TagDropdown]] [[SystemTag: $:/tags/TextEditor/Snippet]] [[SystemTag: $:/tags/TiddlerInfo]] [[SystemTag: $:/tags/TiddlerInfo/Advanced]] [[SystemTag: $:/tags/TiddlerInfoSegment]] [[SystemTag: $:/tags/ToolbarButtonStyle]] [[SystemTag: $:/tags/TopLeftBar]] [[SystemTag: $:/tags/TopRightBar]] [[SystemTag: $:/tags/ViewTemplate]] [[SystemTag: $:/tags/ViewToolbar]]
modified: 20201123192434277
tags: Reference Concepts
title: SystemTags
type: text/vnd.tiddlywiki

Some files were not shown because too many files have changed in this diff Show More