mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-05 09:36:18 +00:00
Merge branch 'master' into publishing-framework
This commit is contained in:
commit
160c154ef1
@ -5,52 +5,52 @@ Optimise the SVGs in ./core/images using SVGO from https://github.com/svg/svgo
|
||||
|
||||
Install SVGO with the following command in the root of the repo:
|
||||
|
||||
npm install svgo
|
||||
npm install svgo@2.3.0
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var fs = require("fs"),
|
||||
path = require("path"),
|
||||
SVGO = require("svgo"),
|
||||
svgo = new SVGO({
|
||||
{ optimize } = require("svgo"),
|
||||
config = {
|
||||
plugins: [
|
||||
{cleanupAttrs: true},
|
||||
{removeDoctype: true},
|
||||
{removeXMLProcInst: true},
|
||||
{removeComments: true},
|
||||
{removeMetadata: true},
|
||||
{removeTitle: true},
|
||||
{removeDesc: true},
|
||||
{removeUselessDefs: true},
|
||||
{removeEditorsNSData: true},
|
||||
{removeEmptyAttrs: true},
|
||||
{removeHiddenElems: true},
|
||||
{removeEmptyText: true},
|
||||
{removeEmptyContainers: true},
|
||||
{removeViewBox: false},
|
||||
{cleanupEnableBackground: true},
|
||||
{convertStyleToAttrs: true},
|
||||
{convertColors: true},
|
||||
{convertPathData: true},
|
||||
{convertTransform: true},
|
||||
{removeUnknownsAndDefaults: true},
|
||||
{removeNonInheritableGroupAttrs: true},
|
||||
{removeUselessStrokeAndFill: true},
|
||||
{removeUnusedNS: true},
|
||||
{cleanupIDs: true},
|
||||
{cleanupNumericValues: true},
|
||||
{moveElemsAttrsToGroup: true},
|
||||
{moveGroupAttrsToElems: true},
|
||||
{collapseGroups: true},
|
||||
{removeRasterImages: false},
|
||||
{mergePaths: true},
|
||||
{convertShapeToPath: true},
|
||||
{sortAttrs: true},
|
||||
{removeDimensions: false},
|
||||
{removeAttrs: {attrs: "(stroke|fill)"}}
|
||||
'cleanupAttrs',
|
||||
'removeDoctype',
|
||||
'removeXMLProcInst',
|
||||
'removeComments',
|
||||
'removeMetadata',
|
||||
'removeTitle',
|
||||
'removeDesc',
|
||||
'removeUselessDefs',
|
||||
'removeEditorsNSData',
|
||||
'removeEmptyAttrs',
|
||||
'removeHiddenElems',
|
||||
'removeEmptyText',
|
||||
'removeEmptyContainers',
|
||||
// 'removeViewBox',
|
||||
'cleanupEnableBackground',
|
||||
'convertStyleToAttrs',
|
||||
'convertColors',
|
||||
'convertPathData',
|
||||
'convertTransform',
|
||||
'removeUnknownsAndDefaults',
|
||||
'removeNonInheritableGroupAttrs',
|
||||
'removeUselessStrokeAndFill',
|
||||
'removeUnusedNS',
|
||||
'cleanupIDs',
|
||||
'cleanupNumericValues',
|
||||
'moveElemsAttrsToGroup',
|
||||
'moveGroupAttrsToElems',
|
||||
'collapseGroups',
|
||||
// 'removeRasterImages',
|
||||
'mergePaths',
|
||||
'convertShapeToPath',
|
||||
'sortAttrs',
|
||||
//'removeDimensions',
|
||||
{name: 'removeAttrs', params: { attrs: '(stroke|fill)' } }
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
var basepath = "./core/images/",
|
||||
files = fs.readdirSync(basepath).sort();
|
||||
@ -66,12 +66,14 @@ files.forEach(function(filename) {
|
||||
fakeSVG = body.join("\n");
|
||||
// A hack to make the new-journal-button work
|
||||
fakeSVG = fakeSVG.replace("<<now \"DD\">>","<<now "DD">>");
|
||||
svgo.optimize(fakeSVG, {path: filepath}).then(function(result) {
|
||||
config.path = filepath;
|
||||
var result = optimize(fakeSVG,config);
|
||||
if(result) {
|
||||
var newSVG = header.join("\n") + "\n\n" + result.data.replace("<<now "DD">>","<<now \"DD\">>");
|
||||
fs.writeFileSync(filepath,newSVG);
|
||||
},function(err) {
|
||||
} else {
|
||||
console.log("Error " + err + " with " + filename)
|
||||
process.exit();
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
|
4
core/images/minus-button.tid
Normal file
4
core/images/minus-button.tid
Normal file
@ -0,0 +1,4 @@
|
||||
title: $:/core/images/minus-button
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg width="22pt" height="22pt" class="tc-image-minus-button tc-image-button" viewBox="0 0 128 128"><path d="M64 0c35.346 0 64 28.654 64 64 0 35.346-28.654 64-64 64-35.346 0-64-28.654-64-64C0 28.654 28.654 0 64 0zm.332 16c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48z"/><rect width="80" height="16" x="24" y="56" rx="8"/></svg>
|
4
core/images/plus-button.tid
Normal file
4
core/images/plus-button.tid
Normal file
@ -0,0 +1,4 @@
|
||||
title: $:/core/images/plus-button
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg width="22pt" height="22pt" class="tc-image-plus-button tc-image-button" viewBox="0 0 128 128"><path d="M64-.333c35.346 0 64 28.654 64 64 0 35.346-28.654 64-64 64-35.346 0-64-28.654-64-64 0-35.346 28.654-64 64-64zM64 16c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48z"/><rect width="80" height="16" x="24" y="56" rx="8"/><rect width="16" height="80" x="56" y="24" rx="8"/></svg>
|
@ -125,12 +125,12 @@ Saving/TiddlySpot/BackupDir: Backup Directory
|
||||
Saving/TiddlySpot/ControlPanel: ~TiddlySpot Control Panel
|
||||
Saving/TiddlySpot/Backups: Backups
|
||||
Saving/TiddlySpot/Caption: ~TiddlySpot Saver
|
||||
Saving/TiddlySpot/Description: These settings are only used when saving to http://tiddlyspot.com or a compatible remote server
|
||||
Saving/TiddlySpot/Description: These settings are only used when saving to [[TiddlySpot|http://tiddlyspot.com]], [[TiddlyHost|https://tiddlyhost.com]], or a compatible remote server. See [[here|https://github.com/simonbaird/tiddlyhost/wiki/TiddlySpot-Saver-configuration-for-Tiddlyhost-and-Tiddlyspot]] for information on ~TiddlySpot and ~TiddlyHost saving configuration.
|
||||
Saving/TiddlySpot/Filename: Upload Filename
|
||||
Saving/TiddlySpot/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: The ~TiddlySpot service is currently only available in read-only form. Please see http://tiddlyspot.com/ for the latest details. The ~TiddlySpot saver can still be used to save to compatible servers.
|
||||
Saving/TiddlySpot/ReadOnly: Note that [[TiddlySpot|http://tiddlyspot.com]] no longer allows the creation of new sites. For new sites you can use [[TiddlyHost|https://tiddlyhost.com]], a new hosting service which replaces ~TiddlySpot.
|
||||
Saving/TiddlySpot/ServerURL: Server URL
|
||||
Saving/TiddlySpot/UploadDir: Upload Directory
|
||||
Saving/TiddlySpot/UserName: Wiki Name
|
||||
|
@ -31,6 +31,7 @@ All parameters are optional with safe defaults, and can be specified in any orde
|
||||
* ''tls-key'' - pathname of TLS key file (relative to wiki folder)
|
||||
* ''debug-level'' - optional debug level; set to "debug" to view request details (defaults to "none")
|
||||
* ''gzip'' - set to "yes" to enable gzip compression for some http endpoints (defaults to "no")
|
||||
* ''use-browser-cache'' - set to "yes" to allow the browser to cache responses to save bandwith (defaults to "no")
|
||||
|
||||
For information on opening up your instance to the entire local network, and possible security concerns, see the WebServer tiddler at TiddlyWiki.com.
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
title: $:/language/Import/
|
||||
|
||||
Editor/Import/Heading: Import images and insert into the editor.
|
||||
Imported/Hint: The following tiddlers were imported:
|
||||
Listing/Cancel/Caption: Cancel
|
||||
Listing/Hint: These tiddlers are ready to import:
|
||||
|
@ -24,7 +24,6 @@ Encryption/RepeatPassword: Repeat password
|
||||
Encryption/PasswordNoMatch: Passwords do not match
|
||||
Encryption/SetPassword: Set password
|
||||
Error/Caption: Error
|
||||
Error/EditConflict: File changed on server
|
||||
Error/Filter: Filter error
|
||||
Error/FilterSyntax: Syntax error in filter expression
|
||||
Error/FilterRunPrefix: Filter Error: Unknown prefix for filter run
|
||||
@ -32,6 +31,9 @@ Error/IsFilterOperator: Filter Error: Unknown operand for the 'is' filter operat
|
||||
Error/FormatFilterOperator: Filter Error: Unknown suffix for the 'format' filter operator
|
||||
Error/LoadingPluginLibrary: Error loading plugin library
|
||||
Error/NetworkErrorAlert: `<h2>''Network Error''</h2>It looks like the connection to the server has been lost. This may indicate a problem with your network connection. Please attempt to restore network connectivity before continuing.<br><br>''Any unsaved changes will be automatically synchronised when connectivity is restored''.`
|
||||
Error/PutEditConflict: File changed on server
|
||||
Error/PutForbidden: Permission denied
|
||||
Error/PutUnauthorized: Authentication required
|
||||
Error/RecursiveTransclusion: Recursive transclusion error in transclude widget
|
||||
Error/RetrievingSkinny: Error retrieving skinny tiddler list
|
||||
Error/SavingToTWEdit: Error saving to TWEdit
|
||||
|
@ -87,7 +87,20 @@ function FramedEngine(options) {
|
||||
{name: "input",handlerObject: this,handlerMethod: "handleInputEvent"},
|
||||
{name: "keydown",handlerObject: this.widget,handlerMethod: "handleKeydownEvent"},
|
||||
{name: "focus",handlerObject: this,handlerMethod: "handleFocusEvent"}
|
||||
|
||||
]);
|
||||
// Add drag and drop event listeners if fileDrop is enabled
|
||||
if(this.widget.isFileDropEnabled) {
|
||||
$tw.utils.addEventListeners(this.domNode,[
|
||||
{name: "dragenter",handlerObject: this.widget,handlerMethod: "handleDragEnterEvent"},
|
||||
{name: "dragover",handlerObject: this.widget,handlerMethod: "handleDragOverEvent"},
|
||||
{name: "dragleave",handlerObject: this.widget,handlerMethod: "handleDragLeaveEvent"},
|
||||
{name: "dragend",handlerObject: this.widget,handlerMethod: "handleDragEndEvent"},
|
||||
{name: "drop", handlerObject: this.widget,handlerMethod: "handleDropEvent"},
|
||||
{name: "paste", handlerObject: this.widget,handlerMethod: "handlePasteEvent"},
|
||||
{name: "click",handlerObject: this.widget,handlerMethod: "handleClickEvent"}
|
||||
]);
|
||||
}
|
||||
// Insert the element into the DOM
|
||||
this.iframeDoc.body.appendChild(this.domNode);
|
||||
}
|
||||
|
@ -186,6 +186,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
this.editRefreshTitle = this.getAttribute("refreshTitle");
|
||||
this.editAutoComplete = this.getAttribute("autocomplete");
|
||||
this.isDisabled = this.getAttribute("disabled","no");
|
||||
this.isFileDropEnabled = this.getAttribute("fileDrop","no") === "yes";
|
||||
// Get the default editor element tag and type
|
||||
var tag,type;
|
||||
if(this.editField === "text") {
|
||||
@ -217,7 +218,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 || changedAttributes.autocomplete || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedAttributes.disabled) {
|
||||
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedAttributes.disabled || changedAttributes.fileDrop) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else if (changedTiddlers[this.editRefreshTitle]) {
|
||||
@ -297,19 +298,88 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
Propogate keydown events to our container for the keyboard widgets benefit
|
||||
*/
|
||||
EditTextWidget.prototype.propogateKeydownEvent = function(event) {
|
||||
var newEvent = this.document.createEventObject ? this.document.createEventObject() : this.document.createEvent("Events");
|
||||
if(newEvent.initEvent) {
|
||||
newEvent.initEvent("keydown", true, true);
|
||||
}
|
||||
newEvent.keyCode = event.keyCode;
|
||||
newEvent.which = event.which;
|
||||
newEvent.metaKey = event.metaKey;
|
||||
newEvent.ctrlKey = event.ctrlKey;
|
||||
newEvent.altKey = event.altKey;
|
||||
newEvent.shiftKey = event.shiftKey;
|
||||
var newEvent = this.cloneEvent(event,["keyCode","which","metaKey","ctrlKey","altKey","shiftKey"]);
|
||||
return !this.parentDomNode.dispatchEvent(newEvent);
|
||||
};
|
||||
|
||||
EditTextWidget.prototype.cloneEvent = function(event,propertiesToCopy) {
|
||||
var propertiesToCopy = propertiesToCopy || [],
|
||||
newEvent = this.document.createEventObject ? this.document.createEventObject() : this.document.createEvent("Events");
|
||||
if(newEvent.initEvent) {
|
||||
newEvent.initEvent(event.type, true, true);
|
||||
}
|
||||
$tw.utils.each(propertiesToCopy,function(prop){
|
||||
newEvent[prop] = event[prop];
|
||||
});
|
||||
return newEvent;
|
||||
};
|
||||
|
||||
EditTextWidget.prototype.dispatchDOMEvent = function(newEvent) {
|
||||
var dispatchNode = this.engine.iframeNode || this.engine.parentNode;
|
||||
return dispatchNode.dispatchEvent(newEvent);
|
||||
};
|
||||
|
||||
/*
|
||||
Propogate drag and drop events with File data to our container for the dropzone widgets benefit.
|
||||
If there are no Files, let the browser handle it.
|
||||
*/
|
||||
EditTextWidget.prototype.handleDropEvent = function(event) {
|
||||
if(event.dataTransfer.files.length) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.dispatchDOMEvent(this.cloneEvent(event,["dataTransfer"]));
|
||||
}
|
||||
};
|
||||
|
||||
EditTextWidget.prototype.handlePasteEvent = function(event) {
|
||||
if(event.clipboardData.files.length) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.dispatchDOMEvent(this.cloneEvent(event,["clipboardData"]));
|
||||
}
|
||||
};
|
||||
|
||||
EditTextWidget.prototype.handleDragEnterEvent = function(event) {
|
||||
if($tw.utils.dragEventContainsFiles(event)) {
|
||||
// Ignore excessive events fired by FF when entering and leaving text nodes in a text area.
|
||||
if( event.relatedTarget && (event.relatedTarget.nodeType === 3 || event.target === event.relatedTarget)) {
|
||||
return true;
|
||||
}
|
||||
event.preventDefault();
|
||||
return this.dispatchDOMEvent(this.cloneEvent(event,["dataTransfer"]));
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
EditTextWidget.prototype.handleDragOverEvent = function(event) {
|
||||
if($tw.utils.dragEventContainsFiles(event)) {
|
||||
// Call preventDefault() in browsers that default to not allowing drop events on textarea
|
||||
if($tw.browser.isFirefox || $tw.browser.isIE) {
|
||||
event.preventDefault();
|
||||
}
|
||||
event.dataTransfer.dropEffect = "copy";
|
||||
return this.dispatchDOMEvent(this.cloneEvent(event,["dataTransfer"]));
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
EditTextWidget.prototype.handleDragLeaveEvent = function(event) {
|
||||
// Ignore excessive events fired by FF when entering and leaving text nodes in a text area.
|
||||
if(event.relatedTarget && ((event.relatedTarget.nodeType === 3) || (event.target === event.relatedTarget))) {
|
||||
return true;
|
||||
}
|
||||
event.preventDefault();
|
||||
this.dispatchDOMEvent(this.cloneEvent(event,["dataTransfer"]));
|
||||
};
|
||||
|
||||
EditTextWidget.prototype.handleDragEndEvent = function(event) {
|
||||
this.dispatchDOMEvent(this.cloneEvent(event));
|
||||
};
|
||||
|
||||
EditTextWidget.prototype.handleClickEvent = function(event) {
|
||||
return !this.dispatchDOMEvent(this.cloneEvent(event));
|
||||
};
|
||||
|
||||
return EditTextWidget;
|
||||
|
||||
}
|
||||
|
58
core/modules/filterrunprefixes/sort.js
Normal file
58
core/modules/filterrunprefixes/sort.js
Normal file
@ -0,0 +1,58 @@
|
||||
/*\
|
||||
title: $:/core/modules/filterrunprefixes/sort.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.sort = function(operationSubFunction,options) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length > 0) {
|
||||
var suffixes = options.suffixes,
|
||||
sortType = (suffixes[0] && suffixes[0][0]) ? suffixes[0][0] : "string",
|
||||
invert = suffixes[1] ? (suffixes[1].indexOf("reverse") !== -1) : false,
|
||||
isCaseSensitive = suffixes[1] ? (suffixes[1].indexOf("casesensitive") !== -1) : false,
|
||||
inputTitles = results.toArray(),
|
||||
sortKeys = [],
|
||||
indexes = new Array(inputTitles.length),
|
||||
compareFn;
|
||||
results.each(function(title) {
|
||||
var key = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
|
||||
getVariable: function(name) {
|
||||
switch(name) {
|
||||
case "currentTiddler":
|
||||
return "" + title;
|
||||
default:
|
||||
return widget.getVariable(name);
|
||||
}
|
||||
}
|
||||
});
|
||||
sortKeys.push(key[0] || "");
|
||||
});
|
||||
results.clear();
|
||||
// Prepare an array of indexes to sort
|
||||
for(var t=0; t<inputTitles.length; t++) {
|
||||
indexes[t] = t;
|
||||
}
|
||||
// Sort the indexes
|
||||
compareFn = $tw.utils.makeCompareFunction(sortType,{defaultType: "string", invert:invert, isCaseSensitive:isCaseSensitive});
|
||||
indexes = indexes.sort(function(a,b) {
|
||||
return compareFn(sortKeys[a],sortKeys[b]);
|
||||
});
|
||||
// Add to results in correct order
|
||||
$tw.utils.each(indexes,function(index) {
|
||||
results.push(inputTitles[index]);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
@ -137,7 +137,7 @@ exports.parseFilter = function(filterString) {
|
||||
p = 0, // Current position in the filter string
|
||||
match;
|
||||
var whitespaceRegExp = /(\s+)/mg,
|
||||
operandRegExp = /((?:\+|\-|~|=|\:(\w+))?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
|
||||
operandRegExp = /((?:\+|\-|~|=|\:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
|
||||
while(p < filterString.length) {
|
||||
// Skip any whitespace
|
||||
whitespaceRegExp.lastIndex = p;
|
||||
@ -162,15 +162,27 @@ exports.parseFilter = function(filterString) {
|
||||
if(match[2]) {
|
||||
operation.namedPrefix = match[2];
|
||||
}
|
||||
if(match[3]) {
|
||||
operation.suffixes = [];
|
||||
$tw.utils.each(match[3].split(":"),function(subsuffix) {
|
||||
operation.suffixes.push([]);
|
||||
$tw.utils.each(subsuffix.split(","),function(entry) {
|
||||
entry = $tw.utils.trim(entry);
|
||||
if(entry) {
|
||||
operation.suffixes[operation.suffixes.length -1].push(entry);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
if(match[3]) { // Opening square bracket
|
||||
if(match[4]) { // Opening square bracket
|
||||
p = parseFilterOperation(operation.operators,filterString,p);
|
||||
} else {
|
||||
p = match.index + match[0].length;
|
||||
}
|
||||
if(match[4] || match[5] || match[6]) { // Double quoted string, single quoted string or unquoted title
|
||||
if(match[5] || match[6] || match[7]) { // Double quoted string, single quoted string or unquoted title
|
||||
operation.operators.push(
|
||||
{operator: "title", operands: [{text: match[4] || match[5] || match[6]}]}
|
||||
{operator: "title", operands: [{text: match[5] || match[6] || match[7]}]}
|
||||
);
|
||||
}
|
||||
results.push(operation);
|
||||
@ -280,7 +292,7 @@ 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};
|
||||
var options = {wiki: self, suffixes: operation.suffixes || []};
|
||||
switch(operation.prefix || "") {
|
||||
case "": // No prefix means that the operation is unioned into the result
|
||||
return filterRunPrefixes["or"](operationSubFunction, options);
|
||||
|
@ -20,7 +20,7 @@ exports.filter = function(source,operator,options) {
|
||||
results = [],
|
||||
target = operator.prefix !== "!";
|
||||
source(function(tiddler,title) {
|
||||
var list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]));
|
||||
var list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),options.widget);
|
||||
if((list.length > 0) === target) {
|
||||
results.push(title);
|
||||
}
|
||||
|
@ -125,6 +125,54 @@ exports.minall = makeNumericReducingOperator(
|
||||
Infinity // Initial value
|
||||
);
|
||||
|
||||
exports.median = makeNumericArrayOperator(
|
||||
function(values) {
|
||||
var len = values.length, median;
|
||||
values.sort();
|
||||
if(len % 2) {
|
||||
// Odd, return the middle number
|
||||
median = values[(len - 1) / 2];
|
||||
} else {
|
||||
// Even, return average of two middle numbers
|
||||
median = (values[len / 2 - 1] + values[len / 2]) / 2;
|
||||
}
|
||||
return [median];
|
||||
}
|
||||
);
|
||||
|
||||
exports.average = makeNumericReducingOperator(
|
||||
function(accumulator,value) {return accumulator + value},
|
||||
0, // Initial value
|
||||
function(finalValue,numberOfValues) {
|
||||
return finalValue/numberOfValues;
|
||||
}
|
||||
);
|
||||
|
||||
exports.variance = makeNumericReducingOperator(
|
||||
function(accumulator,value) {return accumulator + value},
|
||||
0,
|
||||
function(finalValue,numberOfValues,originalValues) {
|
||||
return getVarianceFromArray(originalValues,finalValue/numberOfValues);
|
||||
}
|
||||
);
|
||||
|
||||
exports["standard-deviation"] = makeNumericReducingOperator(
|
||||
function(accumulator,value) {return accumulator + value},
|
||||
0,
|
||||
function(finalValue,numberOfValues,originalValues) {
|
||||
var variance = getVarianceFromArray(originalValues,finalValue/numberOfValues);
|
||||
return Math.sqrt(variance);
|
||||
}
|
||||
);
|
||||
|
||||
//Calculate the variance of a population of numbers in an array given its mean
|
||||
function getVarianceFromArray(values,mean) {
|
||||
var deviationTotal = values.reduce(function(accumulator,value) {
|
||||
return accumulator + Math.pow(value - mean, 2);
|
||||
},0);
|
||||
return deviationTotal/values.length;
|
||||
};
|
||||
|
||||
function makeNumericBinaryOperator(fnCalc) {
|
||||
return function(source,operator,options) {
|
||||
var result = [],
|
||||
@ -134,19 +182,37 @@ function makeNumericBinaryOperator(fnCalc) {
|
||||
});
|
||||
return result;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function makeNumericReducingOperator(fnCalc,initialValue) {
|
||||
function makeNumericReducingOperator(fnCalc,initialValue,fnFinal) {
|
||||
initialValue = initialValue || 0;
|
||||
return function(source,operator,options) {
|
||||
var result = [];
|
||||
source(function(tiddler,title) {
|
||||
result.push(title);
|
||||
result.push($tw.utils.parseNumber(title));
|
||||
});
|
||||
return [$tw.utils.stringifyNumber(result.reduce(function(accumulator,currentValue) {
|
||||
return fnCalc(accumulator,$tw.utils.parseNumber(currentValue));
|
||||
},initialValue))];
|
||||
var value = result.reduce(function(accumulator,currentValue) {
|
||||
return fnCalc(accumulator,currentValue);
|
||||
},initialValue);
|
||||
if(fnFinal) {
|
||||
value = fnFinal(value,result.length,result);
|
||||
}
|
||||
return [$tw.utils.stringifyNumber(value)];
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function makeNumericArrayOperator(fnCalc) {
|
||||
return function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push($tw.utils.parseNumber(title));
|
||||
});
|
||||
results = fnCalc(results);
|
||||
$tw.utils.each(results,function(value,index) {
|
||||
results[index] = $tw.utils.stringifyNumber(value);
|
||||
});
|
||||
return results;
|
||||
};
|
||||
};
|
||||
|
||||
})();
|
||||
|
@ -2,6 +2,7 @@
|
||||
title: $:/core/modules/macros/unusedtitle.js
|
||||
type: application/javascript
|
||||
module-type: macro
|
||||
|
||||
Macro to return a new title that is unused in the wiki. It can be given a name as a base.
|
||||
\*/
|
||||
(function(){
|
||||
@ -10,25 +11,25 @@ Macro to return a new title that is unused in the wiki. It can be given a name a
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Information about this macro
|
||||
*/
|
||||
|
||||
exports.name = "unusedtitle";
|
||||
|
||||
exports.params = [
|
||||
{name: "baseName"},
|
||||
{name: "options"}
|
||||
{name: "separator"},
|
||||
{name: "template"}
|
||||
];
|
||||
|
||||
/*
|
||||
Run the macro
|
||||
*/
|
||||
exports.run = function(baseName, options) {
|
||||
exports.run = function(baseName,separator,template) {
|
||||
separator = separator || " ";
|
||||
if(!baseName) {
|
||||
baseName = $tw.language.getString("DefaultNewTiddlerTitle");
|
||||
}
|
||||
return this.wiki.generateNewTitle(baseName, options);
|
||||
// $tw.wiki.generateNewTitle = function(baseTitle,options)
|
||||
// options.prefix must be a string!
|
||||
return this.wiki.generateNewTitle(baseName, {"prefix": separator, "template": template});
|
||||
};
|
||||
|
||||
})();
|
@ -23,10 +23,12 @@ var HtmlParser = function(type,text,options) {
|
||||
type: "element",
|
||||
tag: "iframe",
|
||||
attributes: {
|
||||
src: {type: "string", value: src},
|
||||
sandbox: {type: "string", value: ""}
|
||||
src: {type: "string", value: src}
|
||||
}
|
||||
}];
|
||||
if($tw.wiki.getTiddlerText("$:/config/HtmlParser/DisableSandbox","no") !== "yes") {
|
||||
this.tree[0].attributes.sandbox = {type: "string", value: $tw.wiki.getTiddlerText("$:/config/HtmlParser/SandboxTokens","")};
|
||||
}
|
||||
};
|
||||
|
||||
exports["text/html"] = HtmlParser;
|
||||
|
@ -89,9 +89,12 @@ PutSaver.prototype.save = function(text,method,callback) {
|
||||
if(err) {
|
||||
// response is textual: "XMLHttpRequest error code: 412"
|
||||
var status = Number(err.substring(err.indexOf(':') + 2, err.length))
|
||||
if(status === 412) { // edit conflict
|
||||
var message = $tw.language.getString("Error/EditConflict");
|
||||
callback(message);
|
||||
if(status === 412) { // file changed on server
|
||||
callback($tw.language.getString("Error/PutEditConflict"));
|
||||
} else if(status === 401) { // authentication required
|
||||
callback($tw.language.getString("Error/PutUnauthorized"));
|
||||
} else if(status === 403) { // permission denied
|
||||
callback($tw.language.getString("Error/PutForbidden"));
|
||||
} else {
|
||||
callback(err); // fail
|
||||
}
|
||||
|
@ -17,9 +17,8 @@ exports.method = "GET";
|
||||
exports.path = /^\/favicon.ico$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
response.writeHead(200, {"Content-Type": "image/x-icon"});
|
||||
var buffer = state.wiki.getTiddlerText("$:/favicon.ico","");
|
||||
response.end(buffer,"base64");
|
||||
state.sendResponse(200,{"Content-Type": "image/x-icon"},buffer,"base64");
|
||||
};
|
||||
|
||||
}());
|
||||
|
@ -34,10 +34,7 @@ exports.handler = function(request,response,state) {
|
||||
content = content;
|
||||
type = ($tw.config.fileExtensionInfo[extension] ? $tw.config.fileExtensionInfo[extension].type : "application/octet-stream");
|
||||
}
|
||||
response.writeHead(status,{
|
||||
"Content-Type": type
|
||||
});
|
||||
response.end(content);
|
||||
state.sendResponse(status,{"Content-Type": type},content);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -12,38 +12,16 @@ GET /
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var zlib = require("zlib");
|
||||
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/index.html$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var acceptEncoding = request.headers["accept-encoding"];
|
||||
if(!acceptEncoding) {
|
||||
acceptEncoding = "";
|
||||
}
|
||||
var text = state.wiki.renderTiddler(state.server.get("root-render-type"),state.server.get("root-tiddler")),
|
||||
responseHeaders = {
|
||||
"Content-Type": state.server.get("root-serve-type")
|
||||
};
|
||||
/*
|
||||
If the gzip=yes flag for `listen` is set, check if the user agent permits
|
||||
compression. If so, compress our response. Note that we use the synchronous
|
||||
functions from zlib to stay in the imperative style. The current `Server`
|
||||
doesn't depend on this, and we may just as well use the async versions.
|
||||
*/
|
||||
if(state.server.enableGzip) {
|
||||
if (/\bdeflate\b/.test(acceptEncoding)) {
|
||||
responseHeaders["Content-Encoding"] = "deflate";
|
||||
text = zlib.deflateSync(text);
|
||||
} else if (/\bgzip\b/.test(acceptEncoding)) {
|
||||
responseHeaders["Content-Encoding"] = "gzip";
|
||||
text = zlib.gzipSync(text);
|
||||
}
|
||||
}
|
||||
response.writeHead(200,responseHeaders);
|
||||
response.end(text);
|
||||
state.sendResponse(200,responseHeaders,text);
|
||||
};
|
||||
|
||||
}());
|
||||
|
@ -17,7 +17,6 @@ exports.method = "GET";
|
||||
exports.path = /^\/status$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
response.writeHead(200, {"Content-Type": "application/json"});
|
||||
var text = JSON.stringify({
|
||||
username: state.authenticatedUsername || state.server.get("anon-username") || "",
|
||||
anonymous: !state.authenticatedUsername,
|
||||
@ -28,7 +27,7 @@ exports.handler = function(request,response,state) {
|
||||
},
|
||||
tiddlywiki_version: $tw.version
|
||||
});
|
||||
response.end(text,"utf8");
|
||||
state.sendResponse(200,{"Content-Type": "application/json"},text,"utf8");
|
||||
};
|
||||
|
||||
}());
|
||||
|
@ -32,9 +32,9 @@ exports.handler = function(request,response,state) {
|
||||
renderTemplate = renderTemplate || state.server.get("tiddler-render-template");
|
||||
}
|
||||
var text = state.wiki.renderTiddler(renderType,renderTemplate,{parseAsInline: true, variables: {currentTiddler: title}});
|
||||
|
||||
// Naughty not to set a content-type, but it's the easiest way to ensure the browser will see HTML pages as HTML, and accept plain text tiddlers as CSS or JS
|
||||
response.writeHead(200);
|
||||
response.end(text,"utf8");
|
||||
state.sendResponse(200,{},text,"utf8");
|
||||
} else {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
|
@ -36,8 +36,7 @@ exports.handler = function(request,response,state) {
|
||||
tiddlerFields.revision = state.wiki.getChangeCount(title);
|
||||
tiddlerFields.bag = "default";
|
||||
tiddlerFields.type = tiddlerFields.type || "text/vnd.tiddlywiki";
|
||||
response.writeHead(200, {"Content-Type": "application/json"});
|
||||
response.end(JSON.stringify(tiddlerFields),"utf8");
|
||||
state.sendResponse(200,{"Content-Type": "application/json"},JSON.stringify(tiddlerFields),"utf8");
|
||||
} else {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
|
@ -33,7 +33,6 @@ exports.handler = function(request,response,state) {
|
||||
}
|
||||
var excludeFields = (state.queryParameters.exclude || "text").split(","),
|
||||
titles = state.wiki.filterTiddlers(filter);
|
||||
response.writeHead(200, {"Content-Type": "application/json"});
|
||||
var tiddlers = [];
|
||||
$tw.utils.each(titles,function(title) {
|
||||
var tiddler = state.wiki.getTiddler(title);
|
||||
@ -45,7 +44,7 @@ exports.handler = function(request,response,state) {
|
||||
}
|
||||
});
|
||||
var text = JSON.stringify(tiddlers);
|
||||
response.end(text,"utf8");
|
||||
state.sendResponse(200,{"Content-Type": "application/json"},text,"utf8");
|
||||
};
|
||||
|
||||
}());
|
||||
|
@ -17,7 +17,9 @@ if($tw.node) {
|
||||
fs = require("fs"),
|
||||
url = require("url"),
|
||||
path = require("path"),
|
||||
querystring = require("querystring");
|
||||
querystring = require("querystring"),
|
||||
crypto = require("crypto"),
|
||||
zlib = require("zlib");
|
||||
}
|
||||
|
||||
/*
|
||||
@ -47,6 +49,8 @@ function Server(options) {
|
||||
this.csrfDisable = this.get("csrf-disable") === "yes";
|
||||
// Initialize Gzip compression
|
||||
this.enableGzip = this.get("gzip") === "yes";
|
||||
// Initialize browser-caching
|
||||
this.enableBrowserCache = this.get("use-browser-cache") === "yes";
|
||||
// Initialise authorization
|
||||
var authorizedUserName = (this.get("username") && this.get("password")) ? this.get("username") : "(anon)";
|
||||
this.authorizationPrincipals = {
|
||||
@ -75,6 +79,71 @@ function Server(options) {
|
||||
this.transport = require(this.protocol);
|
||||
}
|
||||
|
||||
/*
|
||||
Send a response to the client. This method checks if the response must be sent
|
||||
or if the client alrady has the data cached. If that's the case only a 304
|
||||
response will be transmitted and the browser will use the cached data.
|
||||
Only requests with status code 200 are considdered for caching.
|
||||
request: request instance passed to the handler
|
||||
response: response instance passed to the handler
|
||||
statusCode: stauts code to send to the browser
|
||||
headers: response headers (they will be augmented with an `Etag` header)
|
||||
data: the data to send (passed to the end method of the response instance)
|
||||
encoding: the encoding of the data to send (passed to the end method of the response instance)
|
||||
*/
|
||||
function sendResponse(request,response,statusCode,headers,data,encoding) {
|
||||
if(this.enableBrowserCache && (statusCode == 200)) {
|
||||
var hash = crypto.createHash('md5');
|
||||
// Put everything into the hash that could change and invalidate the data that
|
||||
// the browser already stored. The headers the data and the encoding.
|
||||
hash.update(data);
|
||||
hash.update(JSON.stringify(headers));
|
||||
if(encoding) {
|
||||
hash.update(encoding);
|
||||
}
|
||||
var contentDigest = hash.digest("hex");
|
||||
// RFC 7232 section 2.3 mandates for the etag to be enclosed in quotes
|
||||
headers["Etag"] = '"' + contentDigest + '"';
|
||||
headers["Cache-Control"] = "max-age=0, must-revalidate";
|
||||
// Check if any of the hashes contained within the if-none-match header
|
||||
// matches the current hash.
|
||||
// If one matches, do not send the data but tell the browser to use the
|
||||
// cached data.
|
||||
// We do not implement "*" as it makes no sense here.
|
||||
var ifNoneMatch = request.headers["if-none-match"];
|
||||
if(ifNoneMatch) {
|
||||
var matchParts = ifNoneMatch.split(",").map(function(etag) {
|
||||
return etag.replace(/^[ "]+|[ "]+$/g, "");
|
||||
});
|
||||
if(matchParts.indexOf(contentDigest) != -1) {
|
||||
response.writeHead(304,headers);
|
||||
response.end();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
If the gzip=yes is set, check if the user agent permits compression. If so,
|
||||
compress our response if the raw data is bigger than 2k. Compressing less
|
||||
data is inefficient. Note that we use the synchronous functions from zlib
|
||||
to stay in the imperative style. The current `Server` doesn't depend on
|
||||
this, and we may just as well use the async versions.
|
||||
*/
|
||||
if(this.enableGzip && (data.length > 2048)) {
|
||||
var acceptEncoding = request.headers["accept-encoding"] || "";
|
||||
if(/\bdeflate\b/.test(acceptEncoding)) {
|
||||
headers["Content-Encoding"] = "deflate";
|
||||
data = zlib.deflateSync(data);
|
||||
} else if(/\bgzip\b/.test(acceptEncoding)) {
|
||||
headers["Content-Encoding"] = "gzip";
|
||||
data = zlib.gzipSync(data);
|
||||
}
|
||||
}
|
||||
|
||||
response.writeHead(statusCode,headers);
|
||||
response.end(data,encoding);
|
||||
}
|
||||
|
||||
Server.prototype.defaultVariables = {
|
||||
port: "8080",
|
||||
host: "127.0.0.1",
|
||||
@ -86,7 +155,8 @@ Server.prototype.defaultVariables = {
|
||||
"system-tiddler-render-type": "text/plain",
|
||||
"system-tiddler-render-template": "$:/core/templates/wikified-tiddler",
|
||||
"debug-level": "none",
|
||||
"gzip": "no"
|
||||
"gzip": "no",
|
||||
"use-browser-cache": "no"
|
||||
};
|
||||
|
||||
Server.prototype.get = function(name) {
|
||||
@ -196,6 +266,7 @@ Server.prototype.requestHandler = function(request,response,options) {
|
||||
state.urlInfo = url.parse(request.url);
|
||||
state.queryParameters = querystring.parse(state.urlInfo.query);
|
||||
state.pathPrefix = options.pathPrefix || this.get("path-prefix") || "";
|
||||
state.sendResponse = sendResponse.bind(self,request,response);
|
||||
// Get the principals authorized to access this resource
|
||||
var authorizationType = this.methodMappings[request.method] || "readers";
|
||||
// Check for the CSRF header if this is a write
|
||||
|
@ -205,4 +205,16 @@ function parseJSONTiddlers(json,fallbackTitle) {
|
||||
return data;
|
||||
};
|
||||
|
||||
exports.dragEventContainsFiles = function(event) {
|
||||
if(event.dataTransfer.types) {
|
||||
for(var i=0; i<event.dataTransfer.types.length; i++) {
|
||||
if(event.dataTransfer.types[i] === "Files") {
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
})();
|
||||
|
@ -294,6 +294,47 @@ exports.slowInSlowOut = function(t) {
|
||||
return (1 - ((Math.cos(t * Math.PI) + 1) / 2));
|
||||
};
|
||||
|
||||
exports.formatTitleString = function(template,options) {
|
||||
var base = options.base || "",
|
||||
separator = options.separator || "",
|
||||
counter = options.counter || "";
|
||||
var result = "",
|
||||
t = template,
|
||||
matches = [
|
||||
[/^\$basename\$/i, function() {
|
||||
return base;
|
||||
}],
|
||||
[/^\$count:(\d+)\$/i, function(match) {
|
||||
return $tw.utils.pad(counter,match[1]);
|
||||
}],
|
||||
[/^\$separator\$/i, function() {
|
||||
return separator;
|
||||
}],
|
||||
[/^\$count\$/i, function() {
|
||||
return counter + "";
|
||||
}]
|
||||
];
|
||||
while(t.length){
|
||||
var matchString = "";
|
||||
$tw.utils.each(matches, function(m) {
|
||||
var match = m[0].exec(t);
|
||||
if(match) {
|
||||
matchString = m[1].call(null,match);
|
||||
t = t.substr(match[0].length);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if(matchString) {
|
||||
result += matchString;
|
||||
} else {
|
||||
result += t.charAt(0);
|
||||
t = t.substr(1);
|
||||
}
|
||||
}
|
||||
result = result.replace(/\\(.)/g,"$1");
|
||||
return result;
|
||||
};
|
||||
|
||||
exports.formatDateString = function(date,template) {
|
||||
var result = "",
|
||||
t = template,
|
||||
@ -876,7 +917,9 @@ exports.stringifyNumber = function(num) {
|
||||
|
||||
exports.makeCompareFunction = function(type,options) {
|
||||
options = options || {};
|
||||
var gt = options.invert ? -1 : +1,
|
||||
// set isCaseSensitive to true if not defined in options
|
||||
var isCaseSensitive = (options.isCaseSensitive === false) ? false : true,
|
||||
gt = options.invert ? -1 : +1,
|
||||
lt = options.invert ? +1 : -1,
|
||||
compare = function(a,b) {
|
||||
if(a > b) {
|
||||
@ -895,7 +938,11 @@ exports.makeCompareFunction = function(type,options) {
|
||||
return compare($tw.utils.parseInt(a),$tw.utils.parseInt(b));
|
||||
},
|
||||
"string": function(a,b) {
|
||||
return compare("" + a,"" +b);
|
||||
if(!isCaseSensitive) {
|
||||
a = a.toLowerCase();
|
||||
b = b.toLowerCase();
|
||||
}
|
||||
return compare("" + a,"" + b);
|
||||
},
|
||||
"date": function(a,b) {
|
||||
var dateA = $tw.utils.parseDate(a),
|
||||
@ -910,6 +957,13 @@ exports.makeCompareFunction = function(type,options) {
|
||||
},
|
||||
"version": function(a,b) {
|
||||
return $tw.utils.compareVersions(a,b);
|
||||
},
|
||||
"alphanumeric": function(a,b) {
|
||||
if(!isCaseSensitive) {
|
||||
a = a.toLowerCase();
|
||||
b = b.toLowerCase();
|
||||
}
|
||||
return options.invert ? b.localeCompare(a,undefined,{numeric: true,sensitivity: "base"}) : a.localeCompare(b,undefined,{numeric: true,sensitivity: "base"});
|
||||
}
|
||||
};
|
||||
return (types[type] || types[options.defaultType] || types.number);
|
||||
|
@ -44,9 +44,7 @@ ActionListopsWidget.prototype.execute = function() {
|
||||
*/
|
||||
ActionListopsWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.$tiddler || changedAttributes.$filter ||
|
||||
changedAttributes.$subfilter || changedAttributes.$field ||
|
||||
changedAttributes.$index || changedAttributes.$tags) {
|
||||
if($tw.utils.count(changedAttributes) > 0) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
@ -60,12 +58,10 @@ ActionListopsWidget.prototype.invokeAction = function(triggeringWidget,
|
||||
//Apply the specified filters to the lists
|
||||
var field = this.listField,
|
||||
index,
|
||||
type = "!!",
|
||||
list = this.listField;
|
||||
if(this.listIndex) {
|
||||
field = undefined;
|
||||
index = this.listIndex;
|
||||
type = "##";
|
||||
list = this.listIndex;
|
||||
}
|
||||
if(this.filter) {
|
||||
@ -74,15 +70,14 @@ ActionListopsWidget.prototype.invokeAction = function(triggeringWidget,
|
||||
.filterTiddlers(this.filter, this)));
|
||||
}
|
||||
if(this.subfilter) {
|
||||
var subfilter = "[list[" + this.target + type + list + "]] " + this.subfilter;
|
||||
this.wiki.setText(this.target, field, index, $tw.utils.stringifyList(
|
||||
this.wiki
|
||||
.filterTiddlers(subfilter, this)));
|
||||
var inputList = this.wiki.getTiddlerList(this.target,field,index),
|
||||
subfilter = $tw.utils.stringifyList(inputList) + " " + this.subfilter;
|
||||
this.wiki.setText(this.target, field, index, $tw.utils.stringifyList(this.wiki.filterTiddlers(subfilter,this)));
|
||||
}
|
||||
if(this.filtertags) {
|
||||
var tiddler = this.wiki.getTiddler(this.target),
|
||||
oldtags = tiddler ? (tiddler.fields.tags || []).slice(0) : [],
|
||||
tagfilter = "[list[" + this.target + "!!tags]] " + this.filtertags,
|
||||
tagfilter = $tw.utils.stringifyList(oldtags) + " " + this.filtertags,
|
||||
newtags = this.wiki.filterTiddlers(tagfilter,this);
|
||||
if($tw.utils.stringifyList(oldtags.sort()) !== $tw.utils.stringifyList(newtags.sort())) {
|
||||
this.wiki.setText(this.target,"tags",undefined,$tw.utils.stringifyList(newtags));
|
||||
|
@ -37,6 +37,7 @@ Compute the internal state of the widget
|
||||
ActionPopupWidget.prototype.execute = function() {
|
||||
this.actionState = this.getAttribute("$state");
|
||||
this.actionCoords = this.getAttribute("$coords");
|
||||
this.floating = this.getAttribute("$floating","no") === "yes";
|
||||
};
|
||||
|
||||
/*
|
||||
@ -68,7 +69,8 @@ ActionPopupWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
height: parseFloat(match[4])
|
||||
},
|
||||
title: this.actionState,
|
||||
wiki: this.wiki
|
||||
wiki: this.wiki,
|
||||
floating: this.floating
|
||||
});
|
||||
} else {
|
||||
$tw.popup.cancel(0);
|
||||
|
@ -12,6 +12,8 @@ Dropzone widget
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var IMPORT_TITLE = "$:/Import";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var DropZoneWidget = function(parseTreeNode,options) {
|
||||
@ -35,6 +37,7 @@ DropZoneWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.execute();
|
||||
// Create element
|
||||
var domNode = this.document.createElement("div");
|
||||
this.domNode = domNode;
|
||||
domNode.className = this.dropzoneClass || "tc-dropzone";
|
||||
// Add event handlers
|
||||
if(this.dropzoneEnable) {
|
||||
@ -45,10 +48,8 @@ DropZoneWidget.prototype.render = function(parent,nextSibling) {
|
||||
{name: "drop", handlerObject: this, handlerMethod: "handleDropEvent"},
|
||||
{name: "paste", handlerObject: this, handlerMethod: "handlePasteEvent"},
|
||||
{name: "dragend", handlerObject: this, handlerMethod: "handleDragEndEvent"}
|
||||
]);
|
||||
]);
|
||||
}
|
||||
domNode.addEventListener("click",function (event) {
|
||||
},false);
|
||||
// Insert element
|
||||
parent.insertBefore(domNode,nextSibling);
|
||||
this.renderChildren(domNode,null);
|
||||
@ -57,12 +58,46 @@ DropZoneWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.currentlyEntered = [];
|
||||
};
|
||||
|
||||
// Handler for transient event listeners added when the dropzone has an active drag in progress
|
||||
DropZoneWidget.prototype.handleEvent = function(event) {
|
||||
if(event.type === "click") {
|
||||
if(this.currentlyEntered.length) {
|
||||
this.resetState();
|
||||
}
|
||||
} else if(event.type === "dragenter") {
|
||||
if(event.target && event.target !== this.domNode && !$tw.utils.domContains(this.domNode,event.target)) {
|
||||
this.resetState();
|
||||
}
|
||||
} else if(event.type === "dragleave") {
|
||||
// Check if drag left the window
|
||||
if(event.relatedTarget === null || (event.relatedTarget && event.relatedTarget.nodeName === "HTML")) {
|
||||
this.resetState();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Reset the state of the dropzone after a drag has ended
|
||||
DropZoneWidget.prototype.resetState = function() {
|
||||
$tw.utils.removeClass(this.domNode,"tc-dragover");
|
||||
this.currentlyEntered = [];
|
||||
this.document.body.removeEventListener("click",this,true);
|
||||
this.document.body.removeEventListener("dragenter",this,true);
|
||||
this.document.body.removeEventListener("dragleave",this,true);
|
||||
this.dragInProgress = false;
|
||||
};
|
||||
|
||||
DropZoneWidget.prototype.enterDrag = function(event) {
|
||||
if(this.currentlyEntered.indexOf(event.target) === -1) {
|
||||
this.currentlyEntered.push(event.target);
|
||||
}
|
||||
// If we're entering for the first time we need to apply highlighting
|
||||
$tw.utils.addClass(this.domNodes[0],"tc-dragover");
|
||||
if(!this.dragInProgress) {
|
||||
this.dragInProgress = true;
|
||||
// If we're entering for the first time we need to apply highlighting
|
||||
$tw.utils.addClass(this.domNodes[0],"tc-dragover");
|
||||
this.document.body.addEventListener("click",this,true);
|
||||
this.document.body.addEventListener("dragenter",this,true);
|
||||
this.document.body.addEventListener("dragleave",this,true);
|
||||
}
|
||||
};
|
||||
|
||||
DropZoneWidget.prototype.leaveDrag = function(event) {
|
||||
@ -72,15 +107,17 @@ DropZoneWidget.prototype.leaveDrag = function(event) {
|
||||
}
|
||||
// Remove highlighting if we're leaving externally
|
||||
if(this.currentlyEntered.length === 0) {
|
||||
$tw.utils.removeClass(this.domNodes[0],"tc-dragover");
|
||||
this.resetState();
|
||||
}
|
||||
};
|
||||
|
||||
DropZoneWidget.prototype.handleDragEnterEvent = function(event) {
|
||||
// Check for this window being the source of the drag
|
||||
if($tw.dragInProgress) {
|
||||
return false;
|
||||
}
|
||||
if(this.filesOnly && !$tw.utils.dragEventContainsFiles(event)) {
|
||||
return false;
|
||||
}
|
||||
this.enterDrag(event);
|
||||
// Tell the browser that we're ready to handle the drop
|
||||
event.preventDefault();
|
||||
@ -99,7 +136,10 @@ DropZoneWidget.prototype.handleDragOverEvent = function(event) {
|
||||
}
|
||||
// Tell the browser that we're still interested in the drop
|
||||
event.preventDefault();
|
||||
event.dataTransfer.dropEffect = "copy"; // Explicitly show this is a copy
|
||||
// Check if this is a synthetic event, IE does not allow accessing dropEffect outside of original event handler
|
||||
if(event.isTrusted) {
|
||||
event.dataTransfer.dropEffect = "copy"; // Explicitly show this is a copy
|
||||
}
|
||||
};
|
||||
|
||||
DropZoneWidget.prototype.handleDragLeaveEvent = function(event) {
|
||||
@ -107,13 +147,41 @@ DropZoneWidget.prototype.handleDragLeaveEvent = function(event) {
|
||||
};
|
||||
|
||||
DropZoneWidget.prototype.handleDragEndEvent = function(event) {
|
||||
$tw.utils.removeClass(this.domNodes[0],"tc-dragover");
|
||||
this.resetState();
|
||||
};
|
||||
|
||||
DropZoneWidget.prototype.filterByContentTypes = function(tiddlerFieldsArray) {
|
||||
var filteredTypes,
|
||||
filtered = [],
|
||||
types = [];
|
||||
$tw.utils.each(tiddlerFieldsArray,function(tiddlerFields) {
|
||||
types.push(tiddlerFields.type || "");
|
||||
});
|
||||
filteredTypes = this.wiki.filterTiddlers(this.contentTypesFilter,this,this.wiki.makeTiddlerIterator(types));
|
||||
$tw.utils.each(tiddlerFieldsArray,function(tiddlerFields) {
|
||||
if(filteredTypes.indexOf(tiddlerFields.type) !== -1) {
|
||||
filtered.push(tiddlerFields);
|
||||
}
|
||||
});
|
||||
return filtered;
|
||||
};
|
||||
|
||||
DropZoneWidget.prototype.readFileCallback = function(tiddlerFieldsArray) {
|
||||
if(this.contentTypesFilter) {
|
||||
tiddlerFieldsArray = this.filterByContentTypes(tiddlerFieldsArray);
|
||||
}
|
||||
if(tiddlerFieldsArray.length) {
|
||||
this.dispatchEvent({type: "tm-import-tiddlers", param: JSON.stringify(tiddlerFieldsArray), autoOpenOnImport: this.autoOpenOnImport, importTitle: this.importTitle});
|
||||
if(this.actions) {
|
||||
this.invokeActionString(this.actions,this,event,{importTitle: this.importTitle});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
DropZoneWidget.prototype.handleDropEvent = function(event) {
|
||||
var self = this,
|
||||
readFileCallback = function(tiddlerFieldsArray) {
|
||||
self.dispatchEvent({type: "tm-import-tiddlers", param: JSON.stringify(tiddlerFieldsArray), autoOpenOnImport: self.autoOpenOnImport, importTitle: self.importTitle});
|
||||
self.readFileCallback(tiddlerFieldsArray);
|
||||
};
|
||||
this.leaveDrag(event);
|
||||
// Check for being over a TEXTAREA or INPUT
|
||||
@ -127,7 +195,7 @@ DropZoneWidget.prototype.handleDropEvent = function(event) {
|
||||
var self = this,
|
||||
dataTransfer = event.dataTransfer;
|
||||
// Remove highlighting
|
||||
$tw.utils.removeClass(this.domNodes[0],"tc-dragover");
|
||||
this.resetState();
|
||||
// Import any files in the drop
|
||||
var numFiles = 0;
|
||||
if(dataTransfer.files) {
|
||||
@ -138,7 +206,23 @@ DropZoneWidget.prototype.handleDropEvent = function(event) {
|
||||
}
|
||||
// Try to import the various data types we understand
|
||||
if(numFiles === 0) {
|
||||
$tw.utils.importDataTransfer(dataTransfer,this.wiki.generateNewTitle("Untitled"),readFileCallback);
|
||||
var fallbackTitle = self.wiki.generateNewTitle("Untitled");
|
||||
//Use the deserializer specified if any
|
||||
if(this.dropzoneDeserializer) {
|
||||
for(var t= 0; t<dataTransfer.items.length; t++) {
|
||||
var item = dataTransfer.items[t];
|
||||
if(item.kind === "string") {
|
||||
item.getAsString(function(str){
|
||||
var tiddlerFields = self.wiki.deserializeTiddlers(null,str,{title: fallbackTitle},{deserializer:self.dropzoneDeserializer});
|
||||
if(tiddlerFields && tiddlerFields.length) {
|
||||
readFileCallback(tiddlerFields);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$tw.utils.importDataTransfer(dataTransfer,fallbackTitle,readFileCallback);
|
||||
}
|
||||
}
|
||||
// Tell the browser that we handled the drop
|
||||
event.preventDefault();
|
||||
@ -149,7 +233,7 @@ DropZoneWidget.prototype.handleDropEvent = function(event) {
|
||||
DropZoneWidget.prototype.handlePasteEvent = function(event) {
|
||||
var self = this,
|
||||
readFileCallback = function(tiddlerFieldsArray) {
|
||||
self.dispatchEvent({type: "tm-import-tiddlers", param: JSON.stringify(tiddlerFieldsArray), autoOpenOnImport: self.autoOpenOnImport, importTitle: self.importTitle});
|
||||
self.readFileCallback(tiddlerFieldsArray);
|
||||
};
|
||||
// Let the browser handle it if we're in a textarea or input box
|
||||
if(["TEXTAREA","INPUT"].indexOf(event.target.tagName) == -1 && !event.target.isContentEditable) {
|
||||
@ -166,17 +250,26 @@ DropZoneWidget.prototype.handlePasteEvent = function(event) {
|
||||
});
|
||||
} else if(item.kind === "string") {
|
||||
// Create tiddlers from string items
|
||||
var type = item.type;
|
||||
var tiddlerFields,
|
||||
type = item.type;
|
||||
item.getAsString(function(str) {
|
||||
var tiddlerFields = {
|
||||
title: self.wiki.generateNewTitle("Untitled"),
|
||||
text: str,
|
||||
type: type
|
||||
};
|
||||
if($tw.log.IMPORT) {
|
||||
console.log("Importing string '" + str + "', type: '" + type + "'");
|
||||
// Use the deserializer specified if any
|
||||
if(self.dropzoneDeserializer) {
|
||||
tiddlerFields = self.wiki.deserializeTiddlers(null,str,{title: self.wiki.generateNewTitle("Untitled")},{deserializer:self.dropzoneDeserializer});
|
||||
if(tiddlerFields && tiddlerFields.length) {
|
||||
readFileCallback(tiddlerFields);
|
||||
}
|
||||
} else {
|
||||
tiddlerFields = {
|
||||
title: self.wiki.generateNewTitle("Untitled"),
|
||||
text: str,
|
||||
type: type
|
||||
};
|
||||
if($tw.log.IMPORT) {
|
||||
console.log("Importing string '" + str + "', type: '" + type + "'");
|
||||
}
|
||||
readFileCallback([tiddlerFields]);
|
||||
}
|
||||
self.dispatchEvent({type: "tm-import-tiddlers", param: JSON.stringify([tiddlerFields]), autoOpenOnImport: self.autoOpenOnImport, importTitle: self.importTitle});
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -194,7 +287,10 @@ DropZoneWidget.prototype.execute = function() {
|
||||
this.dropzoneDeserializer = this.getAttribute("deserializer");
|
||||
this.dropzoneEnable = (this.getAttribute("enable") || "yes") === "yes";
|
||||
this.autoOpenOnImport = this.getAttribute("autoOpenOnImport");
|
||||
this.importTitle = this.getAttribute("importTitle");
|
||||
this.importTitle = this.getAttribute("importTitle",IMPORT_TITLE);
|
||||
this.actions = this.getAttribute("actions");
|
||||
this.contentTypesFilter = this.getAttribute("contentTypesFilter");
|
||||
this.filesOnly = this.getAttribute("filesOnly","no") === "yes";
|
||||
// Make child widgets
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
@ -204,7 +300,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
||||
*/
|
||||
DropZoneWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.enable || changedAttributes.autoOpenOnImport || changedAttributes.importTitle || changedAttributes.deserializer || changedAttributes.class) {
|
||||
if($tw.utils.count(changedAttributes) > 0) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ FieldManglerWidget.prototype.handleRemoveFieldEvent = function(event) {
|
||||
deletion = {};
|
||||
deletion[event.param] = undefined;
|
||||
this.wiki.addTiddler(new $tw.Tiddler(tiddler,deletion));
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
FieldManglerWidget.prototype.handleAddFieldEvent = function(event) {
|
||||
@ -105,7 +105,7 @@ FieldManglerWidget.prototype.handleAddFieldEvent = function(event) {
|
||||
}
|
||||
}
|
||||
this.wiki.addTiddler(new $tw.Tiddler(tiddler,addition));
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
FieldManglerWidget.prototype.handleRemoveTagEvent = function(event) {
|
||||
@ -122,7 +122,7 @@ FieldManglerWidget.prototype.handleRemoveTagEvent = function(event) {
|
||||
this.wiki.addTiddler(new $tw.Tiddler(tiddler,modification));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
FieldManglerWidget.prototype.handleAddTagEvent = function(event) {
|
||||
@ -140,7 +140,7 @@ FieldManglerWidget.prototype.handleAddTagEvent = function(event) {
|
||||
tag.push(event.param.trim());
|
||||
this.wiki.addTiddler(new $tw.Tiddler({title: this.mangleTitle, tags: tag},modification));
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
exports.fieldmangler = FieldManglerWidget;
|
||||
|
@ -61,6 +61,7 @@ ListWidget.prototype.execute = function() {
|
||||
this.template = this.getAttribute("template");
|
||||
this.editTemplate = this.getAttribute("editTemplate");
|
||||
this.variableName = this.getAttribute("variable","currentTiddler");
|
||||
this.counterName = this.getAttribute("counter");
|
||||
this.storyViewName = this.getAttribute("storyview");
|
||||
this.historyTitle = this.getAttribute("history");
|
||||
// Compose the list elements
|
||||
@ -72,7 +73,7 @@ ListWidget.prototype.execute = function() {
|
||||
members = this.getEmptyMessage();
|
||||
} else {
|
||||
$tw.utils.each(this.list,function(title,index) {
|
||||
members.push(self.makeItemTemplate(title));
|
||||
members.push(self.makeItemTemplate(title,index));
|
||||
});
|
||||
}
|
||||
// Construct the child widgets
|
||||
@ -105,7 +106,7 @@ ListWidget.prototype.getEmptyMessage = function() {
|
||||
/*
|
||||
Compose the template for a list item
|
||||
*/
|
||||
ListWidget.prototype.makeItemTemplate = function(title) {
|
||||
ListWidget.prototype.makeItemTemplate = function(title,index) {
|
||||
// Check if the tiddler is a draft
|
||||
var tiddler = this.wiki.getTiddler(title),
|
||||
isDraft = tiddler && tiddler.hasField("draft.of"),
|
||||
@ -128,7 +129,14 @@ ListWidget.prototype.makeItemTemplate = function(title) {
|
||||
}
|
||||
}
|
||||
// Return the list item
|
||||
return {type: "listitem", itemTitle: title, variableName: this.variableName, children: templateTree};
|
||||
var parseTreeNode = {type: "listitem", itemTitle: title, variableName: this.variableName, children: templateTree};
|
||||
if(this.counterName) {
|
||||
parseTreeNode.counter = (index + 1).toString();
|
||||
parseTreeNode.counterName = this.counterName;
|
||||
parseTreeNode.isFirst = index === 0;
|
||||
parseTreeNode.isLast = index === this.list.length - 1;
|
||||
}
|
||||
return parseTreeNode;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -142,7 +150,7 @@ ListWidget.prototype.refresh = function(changedTiddlers) {
|
||||
this.storyview.refreshStart(changedTiddlers,changedAttributes);
|
||||
}
|
||||
// Completely refresh if any of our attributes have changed
|
||||
if(changedAttributes.filter || changedAttributes.template || changedAttributes.editTemplate || changedAttributes.emptyMessage || changedAttributes.storyview || changedAttributes.history) {
|
||||
if(changedAttributes.filter || changedAttributes.variable || changedAttributes.counter || changedAttributes.template || changedAttributes.editTemplate || changedAttributes.emptyMessage || changedAttributes.storyview || changedAttributes.history) {
|
||||
this.refreshSelf();
|
||||
result = true;
|
||||
} else {
|
||||
@ -211,23 +219,41 @@ ListWidget.prototype.handleListChanges = function(changedTiddlers) {
|
||||
this.removeChildDomNodes();
|
||||
this.children = [];
|
||||
}
|
||||
// Cycle through the list, inserting and removing list items as needed
|
||||
var hasRefreshed = false;
|
||||
for(var t=0; t<this.list.length; t++) {
|
||||
var index = this.findListItem(t,this.list[t]);
|
||||
if(index === undefined) {
|
||||
// The list item must be inserted
|
||||
this.insertListItem(t,this.list[t]);
|
||||
hasRefreshed = true;
|
||||
} else {
|
||||
// There are intervening list items that must be removed
|
||||
for(var n=index-1; n>=t; n--) {
|
||||
this.removeListItem(n);
|
||||
// If we are providing an counter variable then we must refresh the items, otherwise we can rearrange them
|
||||
var hasRefreshed = false,t;
|
||||
if(this.counterName) {
|
||||
// Cycle through the list and remove and re-insert the first item that has changed, and all the remaining items
|
||||
for(t=0; t<this.list.length; t++) {
|
||||
if(hasRefreshed || !this.children[t] || this.children[t].parseTreeNode.itemTitle !== this.list[t]) {
|
||||
if(this.children[t]) {
|
||||
this.removeListItem(t);
|
||||
}
|
||||
this.insertListItem(t,this.list[t]);
|
||||
hasRefreshed = true;
|
||||
} else {
|
||||
// Refresh the item we're reusing
|
||||
var refreshed = this.children[t].refresh(changedTiddlers);
|
||||
hasRefreshed = hasRefreshed || refreshed;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Cycle through the list, inserting and removing list items as needed
|
||||
for(t=0; t<this.list.length; t++) {
|
||||
var index = this.findListItem(t,this.list[t]);
|
||||
if(index === undefined) {
|
||||
// The list item must be inserted
|
||||
this.insertListItem(t,this.list[t]);
|
||||
hasRefreshed = true;
|
||||
} else {
|
||||
// There are intervening list items that must be removed
|
||||
for(var n=index-1; n>=t; n--) {
|
||||
this.removeListItem(n);
|
||||
hasRefreshed = true;
|
||||
}
|
||||
// Refresh the item we're reusing
|
||||
var refreshed = this.children[t].refresh(changedTiddlers);
|
||||
hasRefreshed = hasRefreshed || refreshed;
|
||||
}
|
||||
// Refresh the item we're reusing
|
||||
var refreshed = this.children[t].refresh(changedTiddlers);
|
||||
hasRefreshed = hasRefreshed || refreshed;
|
||||
}
|
||||
}
|
||||
// Remove any left over items
|
||||
@ -257,7 +283,7 @@ Insert a new list item at the specified index
|
||||
*/
|
||||
ListWidget.prototype.insertListItem = function(index,title) {
|
||||
// Create, insert and render the new child widgets
|
||||
var widget = this.makeChildWidget(this.makeItemTemplate(title));
|
||||
var widget = this.makeChildWidget(this.makeItemTemplate(title,index));
|
||||
widget.parentDomNode = this.parentDomNode; // Hack to enable findNextSiblingDomNode() to work
|
||||
this.children.splice(index,0,widget);
|
||||
var nextSibling = widget.findNextSiblingDomNode();
|
||||
@ -311,6 +337,11 @@ Compute the internal state of the widget
|
||||
ListItemWidget.prototype.execute = function() {
|
||||
// Set the current list item title
|
||||
this.setVariable(this.parseTreeNode.variableName,this.parseTreeNode.itemTitle);
|
||||
if(this.parseTreeNode.counterName) {
|
||||
this.setVariable(this.parseTreeNode.counterName,this.parseTreeNode.counter);
|
||||
this.setVariable(this.parseTreeNode.counterName + "-first",this.parseTreeNode.isFirst ? "yes" : "no");
|
||||
this.setVariable(this.parseTreeNode.counterName + "-last",this.parseTreeNode.isLast ? "yes" : "no");
|
||||
}
|
||||
// Construct the child widgets
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
@ -170,7 +170,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
||||
SelectWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
// If we're using a different tiddler/field/index then completely refresh ourselves
|
||||
if(changedAttributes.selectTitle || changedAttributes.selectField || changedAttributes.selectIndex || changedAttributes.selectTooltip) {
|
||||
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.tooltip) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
// If the target tiddler value has changed, just update setting and refresh the children
|
||||
|
@ -190,15 +190,25 @@ exports.getChangeCount = function(title) {
|
||||
|
||||
/*
|
||||
Generate an unused title from the specified base
|
||||
options.prefix must be a string
|
||||
*/
|
||||
exports.generateNewTitle = function(baseTitle,options) {
|
||||
options = options || {};
|
||||
var c = 0,
|
||||
title = baseTitle;
|
||||
while(this.tiddlerExists(title) || this.isShadowTiddler(title) || this.findDraft(title)) {
|
||||
title = baseTitle +
|
||||
(options.prefix || " ") +
|
||||
(++c);
|
||||
title = baseTitle,
|
||||
template = options.template,
|
||||
prefix = (typeof(options.prefix) === "string") ? options.prefix : " ";
|
||||
if (template) {
|
||||
// "count" is important to avoid an endless loop in while(...)!!
|
||||
template = (/\$count:?(\d+)?\$/i.test(template)) ? template : template + "$count$";
|
||||
title = $tw.utils.formatTitleString(template,{"base":baseTitle,"separator":prefix,"counter":c});
|
||||
while(this.tiddlerExists(title) || this.isShadowTiddler(title) || this.findDraft(title)) {
|
||||
title = $tw.utils.formatTitleString(template,{"base":baseTitle,"separator":prefix,"counter":(++c)});
|
||||
}
|
||||
} else {
|
||||
while(this.tiddlerExists(title) || this.isShadowTiddler(title) || this.findDraft(title)) {
|
||||
title = baseTitle + prefix + (++c);
|
||||
}
|
||||
}
|
||||
return title;
|
||||
};
|
||||
@ -364,12 +374,12 @@ exports.sortTiddlers = function(titles,sortField,isDescending,isCaseSensitive,is
|
||||
var tiddlerA = self.getTiddler(a),
|
||||
tiddlerB = self.getTiddler(b);
|
||||
if(tiddlerA) {
|
||||
a = tiddlerA.fields[sortField] || "";
|
||||
a = tiddlerA.getFieldString(sortField) || "";
|
||||
} else {
|
||||
a = "";
|
||||
}
|
||||
if(tiddlerB) {
|
||||
b = tiddlerB.fields[sortField] || "";
|
||||
b = tiddlerB.getFieldString(sortField) || "";
|
||||
} else {
|
||||
b = "";
|
||||
}
|
||||
|
@ -30,8 +30,6 @@ http://$(userName)$.tiddlyspot.com/$path$/
|
||||
|
||||
|<<lingo UserName>> |<$edit-text tiddler="$:/UploadName" default="" tag="input"/> |
|
||||
|<<lingo Password>> |<$password name="upload"/> |
|
||||
|<<lingo Backups>> |<<siteLink backup>> |
|
||||
|<<lingo ControlPanel>> |<<siteLink controlpanel>> |
|
||||
|
||||
''<<lingo Advanced/Heading>>''
|
||||
|
||||
|
@ -8,6 +8,7 @@ title: $:/core/ui/EditTemplate/body/editor
|
||||
tabindex={{$:/config/EditTabIndex}}
|
||||
focus={{{ [{$:/config/AutoFocus}match[text]then[true]] ~[[false]] }}}
|
||||
cancelPopups="yes"
|
||||
fileDrop={{{ [{$:/config/DragAndDrop/Enable}match[no]] :else[subfilter{$:/config/Editor/EnableImportFilter}then[yes]else[no]] }}}
|
||||
|
||||
><$set
|
||||
|
||||
@ -30,4 +31,12 @@ title: $:/core/ui/EditTemplate/body/editor
|
||||
tiddler="$:/core/ui/EditTemplate/body/toolbar/button"
|
||||
mode="inline"
|
||||
|
||||
/></$reveal></$list></$set></$edit>
|
||||
/></$reveal></$list><$list
|
||||
|
||||
filter="[all[shadows+tiddlers]tag[$:/tags/EditorTools]!has[draft.of]]"
|
||||
|
||||
><$list
|
||||
filter={{!!condition}}
|
||||
variable="list-condition"
|
||||
><$transclude/>
|
||||
</$list></$list></$set></$edit>
|
||||
|
@ -35,22 +35,23 @@ title: $:/core/ui/EditTemplate/body/toolbar/button
|
||||
filter="[all[current]!has[dropdown]]"
|
||||
variable="no-dropdown"
|
||||
|
||||
><$button
|
||||
><$set name=disabled filter={{!!condition-disabled}}><$button
|
||||
|
||||
class="tc-btn-invisible $(buttonClasses)$"
|
||||
tooltip=<<tooltip-text>>
|
||||
actions={{!!actions}}
|
||||
disabled=<<disabled>>
|
||||
|
||||
><span
|
||||
|
||||
data-tw-keyboard-shortcut={{!!shortcuts}}
|
||||
data-tw-keyboard-shortcut={{{ [<disabled>match[yes]then[]else{!!shortcuts}] }}}
|
||||
|
||||
/><<toolbar-button-icon>><$transclude
|
||||
|
||||
tiddler=<<currentTiddler>>
|
||||
field="text"
|
||||
|
||||
/></$button></$list><$list
|
||||
/></$button></$set></$list><$list
|
||||
|
||||
filter="[all[current]has[dropdown]]"
|
||||
variable="dropdown"
|
||||
@ -60,24 +61,25 @@ title: $:/core/ui/EditTemplate/body/toolbar/button
|
||||
name="dropdown-state"
|
||||
value=<<qualify "$:/state/EditorToolbarDropdown">>
|
||||
|
||||
><$button
|
||||
><$set name=disabled filter={{!!condition-disabled}}><$button
|
||||
|
||||
popup=<<dropdown-state>>
|
||||
class="tc-popup-keep tc-btn-invisible $(buttonClasses)$"
|
||||
selectedClass="tc-selected"
|
||||
tooltip=<<tooltip-text>>
|
||||
actions={{!!actions}}
|
||||
disabled=<<disabled>>
|
||||
|
||||
><span
|
||||
|
||||
data-tw-keyboard-shortcut={{!!shortcuts}}
|
||||
data-tw-keyboard-shortcut={{{ [<disabled>match[yes]then[]else{!!shortcuts}] }}}
|
||||
|
||||
/><<toolbar-button-icon>><$transclude
|
||||
|
||||
tiddler=<<currentTiddler>>
|
||||
field="text"
|
||||
|
||||
/></$button><$reveal
|
||||
/></$button></$set><$reveal
|
||||
|
||||
state=<<dropdown-state>>
|
||||
type="popup"
|
||||
|
@ -5,6 +5,11 @@ tags: $:/tags/EditTemplate
|
||||
\define config-visibility-title()
|
||||
$:/config/EditorToolbarButtons/Visibility/$(currentTiddler)$
|
||||
\end
|
||||
|
||||
\define importFileActions()
|
||||
<$action-popup $state=<<importState>> $coords="(0,0,0,0)" $floating="yes"/>
|
||||
\end
|
||||
|
||||
<$list filter="[all[current]has[_canonical_uri]]">
|
||||
|
||||
<div class="tc-message-box">
|
||||
@ -20,9 +25,8 @@ $:/config/EditorToolbarButtons/Visibility/$(currentTiddler)$
|
||||
</$list>
|
||||
|
||||
<$list filter="[all[current]!has[_canonical_uri]]">
|
||||
|
||||
<$reveal state="$:/state/showeditpreview" type="match" text="yes">
|
||||
|
||||
<$vars importTitle=<<qualify $:/ImportImage>> importState=<<qualify $:/state/ImportImage>> >
|
||||
<$dropzone importTitle=<<importTitle>> autoOpenOnImport="no" contentTypesFilter={{$:/config/Editor/ImportContentTypesFilter}} class="tc-dropzone-editor" enable={{{ [{$:/config/DragAndDrop/Enable}match[no]] :else[subfilter{$:/config/Editor/EnableImportFilter}then[yes]else[no]] }}} filesOnly="yes" actions=<<importFileActions>> ><$reveal state="$:/state/showeditpreview" type="match" text="yes">
|
||||
<div class="tc-tiddler-preview">
|
||||
|
||||
<$transclude tiddler="$:/core/ui/EditTemplate/body/editor" mode="inline"/>
|
||||
@ -38,7 +42,6 @@ $:/config/EditorToolbarButtons/Visibility/$(currentTiddler)$
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</$reveal>
|
||||
|
||||
<$reveal state="$:/state/showeditpreview" type="nomatch" text="yes">
|
||||
@ -46,5 +49,6 @@ $:/config/EditorToolbarButtons/Visibility/$(currentTiddler)$
|
||||
<$transclude tiddler="$:/core/ui/EditTemplate/body/editor" mode="inline"/>
|
||||
|
||||
</$reveal>
|
||||
|
||||
</$list>
|
||||
</$dropzone>
|
||||
</$vars>
|
||||
</$list>
|
@ -23,7 +23,7 @@ tags: $:/tags/EditTemplate
|
||||
|
||||
<div class="tc-message-box">
|
||||
|
||||
{{$:/core/images/warning}} {{$:/language/EditTemplate/Title/Exists/Prompt}}
|
||||
{{$:/core/images/warning}} {{$:/language/EditTemplate/Title/Exists/Prompt}}: <$link to={{!!draft.title}} />
|
||||
|
||||
</div>
|
||||
|
||||
|
41
core/ui/EditorToolbar/file-import.tid
Normal file
41
core/ui/EditorToolbar/file-import.tid
Normal file
@ -0,0 +1,41 @@
|
||||
title: $:/core/ui/EditorToolbar/file-import
|
||||
tags: $:/tags/EditorTools
|
||||
condition: [<targetTiddler>!has[type]] [<targetTiddler>type[text/vnd.tiddlywiki]]
|
||||
|
||||
\define lingo-base() $:/language/Import/
|
||||
|
||||
\define closePopupActions()
|
||||
<$action-deletetiddler $filter="[title<importState>] [title<importTitle>]"/>
|
||||
\end
|
||||
|
||||
\define replacement-text-image() [img[$title$]]
|
||||
|
||||
\define replacement-text-file() [[$title$]]
|
||||
|
||||
\define postImportActions()
|
||||
<$list filter="[<importTitle>links[]] :reduce[get[type]prefix[image]then<replacement-text-image>else<replacement-text-file>search-replace[$title$],<currentTiddler>addprefix<accumulator>]" variable="imageTitle">
|
||||
<$action-sendmessage
|
||||
$message="tm-edit-text-operation"
|
||||
$param="replace-selection"
|
||||
text=<<imageTitle>>
|
||||
/>
|
||||
</$list>
|
||||
<<closePopupActions>>
|
||||
\end
|
||||
|
||||
\define buttons()
|
||||
<$button class="tc-btn-invisible" actions=<<closePopupActions>> ><<lingo Listing/Cancel/Caption>></$button>
|
||||
<$button class="tc-btn-invisible" message="tm-perform-import" param=<<importTitle>> actions=<<postImportActions>> ><<lingo Listing/Import/Caption>></$button>
|
||||
\end
|
||||
|
||||
<$reveal type="popup" state=<<importState>> tag="div" class="tc-editor-importpopup">
|
||||
<div class="tc-editor-import">
|
||||
<$list filter="[<importTitle>field:plugin-type[import]]">
|
||||
<h2><<lingo Editor/Import/Heading>></h2>
|
||||
<$tiddler tiddler=<<importTitle>>>
|
||||
{{||$:/core/ui/ImportListing}}
|
||||
<<buttons>>
|
||||
</$tiddler>
|
||||
</$list>
|
||||
</div>
|
||||
</$reveal>
|
4
core/wiki/config/EditorEnableImportFilter.tid
Normal file
4
core/wiki/config/EditorEnableImportFilter.tid
Normal file
@ -0,0 +1,4 @@
|
||||
title: $:/config/Editor/EnableImportFilter
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
[all[current]type[text/vnd.tiddlywiki]] [all[current]!has[type]]
|
4
core/wiki/config/EditorImportContentTypesFilter.tid
Normal file
4
core/wiki/config/EditorImportContentTypesFilter.tid
Normal file
@ -0,0 +1,4 @@
|
||||
title: $:/config/Editor/ImportContentTypesFilter
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
[prefix[image/]]
|
@ -25,12 +25,31 @@ type: text/vnd.tiddlywiki
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/5370">> page title so that the separating em-dash is only used if the site subtitle is present
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/5397">> broken aria-label in $:/PaletteManager
|
||||
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/5451">> macro calls to use the same parser as that used for widget attributes
|
||||
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/commit/89546b3357b0696a7047e6915bd6cd137b589de6">> a hidden setting to control sandboxing of tiddlers of type `text/html`
|
||||
* <<.link-badge-updated "https://github.com/Jermolene/TiddlyWiki5/commit/caec6bc3fea9155eb2b0aae64d577c565dd7b088">> SVG optimiser script
|
||||
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/commit/c325380231a8c592a6e51d4498c1e6c3a241b539">> plus/minus SVG icons: <<.icon $:/core/images/plus-button>> and <<.icon $:/core/images/minus-button>>
|
||||
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/5294">> support for [[dynamic toolbar buttons|How to create dynamic editor toolbar buttons]]
|
||||
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/5612">> [[average Operator]], [[median Operator]], [[variance Operator]] and [[standard-deviation Operator]] for calculating the arithmetic mean of a list of numbers
|
||||
* <<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/commit/cf56a17f28f1e44dcb62c5e161be4ac29e27c3f2">> unusedtitle macro to use the prefix parameter
|
||||
|
||||
|
||||
! Hackability Improvements
|
||||
|
||||
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/commit/9eda02868f21e9dd1733ffe26352bd7ac96285b4">> new MessageCatcherWidget
|
||||
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/commit/d25e540dd2f0decf61c52fdc665a28a5dfeda93f">> support for `image/vnd.microsoft.icon` content type
|
||||
|
||||
! Widget Improvements
|
||||
* <<.link-badge-modified "https://github.com/Jermolene/TiddlyWiki5/commit/b9647b2c48152dac069a1099a0822b32375a66cf">> [[FieldManglerWidget]] to ensure it doesn't propogate events that it traps
|
||||
* <<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/pull/5597">> [[DropzoneWidget]] to optionally invoke actions after the `tm-import-tiddlers` message has been sent, and to specify an optional `contentTypesFilter` which determines which content types are accepted by the dropzone.
|
||||
* <<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/pull/5611">> [[ListWidget]] with `index` attribute and here (and [[here| https://github.com/Jermolene/TiddlyWiki5/commit/4a99e0cc7d4a6b9e7071c0b2a9a0f63c3c7d2492]])
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/5635">> [[SelectWidget]] refreshing
|
||||
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/5252">> support for suffixes to filter run prefixes
|
||||
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/5653">> :sort filter run prefix
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/5644">> [[ActionListopsWidget]] bug by avoiding stitching together filter expressions for the original list values
|
||||
* <<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/commit/07caa16e8714afe9a64eb202375e4a2f95da1508">> [[DropzoneWidget]] to also use the specified deserializer for strings either dropped or pasted on to the dropzone
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/commit/44df6fe52f79bee88357afb4fc3d6f4800aa6dde">> issue with widget not being available to filter operator
|
||||
* <<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/commit/3f986861538a3cc5c3c6da578b45d0d9138a6b2b">> [[ActionPopupWidget]] to create floating popups that must be manually cleared
|
||||
|
||||
! Client-server Improvements
|
||||
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/commit/e96a54c7531a2d9e07745e27d2015d8d7d09588f">> crash running in client server configuration when 'etag' header is missing
|
||||
@ -40,6 +59,9 @@ type: text/vnd.tiddlywiki
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/5329">> issue with tiddler titles that already end in the required extension
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/5465">> several consistency issues with the filesystem plugin
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/5483">> issue with encoding of $:/config/OriginalTiddlerPaths outside the wiki folder
|
||||
* <<.link-badge-updated "https://github.com/Jermolene/TiddlyWiki5/pull/5628">> the TiddlySpot Saver settings form
|
||||
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/5638">> 401 and 403 error messages for PUT saver
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/commit/d8ac00a10856b1b64311b8e0496344d5b0c1b987">> fixed crash if browser doesn't support Server Sent Events
|
||||
|
||||
! Plugin Improvements
|
||||
|
||||
@ -62,6 +84,7 @@ type: text/vnd.tiddlywiki
|
||||
!! [[BibTeX Plugin]]
|
||||
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/5581">> BibTeX Plugin to report errors more sensibly
|
||||
* <<.link-badge-modified "https://github.com/Jermolene/TiddlyWiki5/commit/953fb9f237ad78e409c03d4b29b9854d8abf6cdf">> BibTex Plugin to force fieldnames to be lowercase
|
||||
|
||||
! Developer Experience Improvements
|
||||
|
||||
@ -71,6 +94,11 @@ type: text/vnd.tiddlywiki
|
||||
* <<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/commit/9f9ce6595b08032a602981f82940ca113cff8211">> wikitext parser with a subclassing mechanism
|
||||
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/commit/ef76349c37662e9706acfffc2c2edb51a920183d">> added support for ''utils-browser'' modules
|
||||
|
||||
! Translation improvements
|
||||
|
||||
* <<.link-badge-improved>> Chinese translations
|
||||
|
||||
|
||||
! Other Bug Fixes
|
||||
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/5376">> issue with [[lookup Operator]] returning "undefined" under some circumstances
|
||||
@ -90,6 +118,7 @@ type: text/vnd.tiddlywiki
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/commit/d6ea369f5ef9d3092a360a4286a99902df37782b">> EditTextWidget to use default text for missing fields
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/5552">> css-escape-polyfill to work under Node.js
|
||||
|
||||
|
||||
[[@Jermolene|https://github.com/Jermolene]] would like to thank the contributors to this release who have generously given their time to help improve TiddlyWiki:
|
||||
|
||||
* <<contributor Arlen22
|
||||
|
@ -750,6 +750,7 @@ function runTests(wiki) {
|
||||
rootWidget.setVariable("sort1","[length[]]");
|
||||
rootWidget.setVariable("sort2","[get[text]else[]length[]]");
|
||||
rootWidget.setVariable("sort3","[{!!value}divide{!!cost}]");
|
||||
rootWidget.setVariable("sort4","[{!!title}]");
|
||||
expect(wiki.filterTiddlers("[sortsub:number<sort1>]",anchorWidget).join(",")).toBe("one,hasList,TiddlerOne,has filter,$:/TiddlerTwo,Tiddler Three,$:/ShadowPlugin,a fourth tiddler,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[!sortsub:number<sort1>]",anchorWidget).join(",")).toBe("filter regexp test,a fourth tiddler,$:/ShadowPlugin,$:/TiddlerTwo,Tiddler Three,TiddlerOne,has filter,hasList,one");
|
||||
expect(wiki.filterTiddlers("[sortsub:string<sort1>]",anchorWidget).join(",")).toBe("TiddlerOne,has filter,$:/TiddlerTwo,Tiddler Three,$:/ShadowPlugin,a fourth tiddler,filter regexp test,one,hasList");
|
||||
@ -759,6 +760,7 @@ function runTests(wiki) {
|
||||
expect(wiki.filterTiddlers("[sortsub:string<sort2>]",anchorWidget).join(",")).toBe("one,TiddlerOne,hasList,has filter,$:/ShadowPlugin,a fourth tiddler,Tiddler Three,$:/TiddlerTwo,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[!sortsub:string<sort2>]",anchorWidget).join(",")).toBe("filter regexp test,$:/TiddlerTwo,Tiddler Three,a fourth tiddler,$:/ShadowPlugin,has filter,hasList,TiddlerOne,one");
|
||||
expect(wiki.filterTiddlers("[[TiddlerOne]] [[$:/TiddlerTwo]] [[Tiddler Three]] [[a fourth tiddler]] +[!sortsub:number<sort3>]",anchorWidget).join(",")).toBe("$:/TiddlerTwo,Tiddler Three,TiddlerOne,a fourth tiddler");
|
||||
expect(wiki.filterTiddlers("a1 a10 a2 a3 b10 b3 b1 c9 c11 c1 +[sortsub:alphanumeric<sort4>]",anchorWidget).join(",")).toBe("a1,a2,a3,a10,b1,b3,b10,c1,c9,c11");
|
||||
});
|
||||
|
||||
it("should handle the toggle operator", function() {
|
||||
|
@ -18,6 +18,199 @@ describe("general filter prefix tests", function() {
|
||||
var results = wiki.filterTiddlers("[tag[A]] :nonexistent[tag[B]]");
|
||||
expect(results).toEqual(["Filter Error: Unknown prefix for filter run"]);
|
||||
});
|
||||
|
||||
// Test filter run prefix parsing
|
||||
it("should parse filter run prefix suffixes", function() {
|
||||
|
||||
// two runs, one with a named prefix but no suffix
|
||||
expect($tw.wiki.parseFilter("[[Sparkling water]tags[]] :intersection[[Red wine]tags[]]")).toEqual(
|
||||
[
|
||||
{
|
||||
"prefix": "",
|
||||
"operators": [
|
||||
{
|
||||
"operator": "title",
|
||||
"operands": [
|
||||
{
|
||||
"text": "Sparkling water"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"operator": "tags",
|
||||
"operands": [
|
||||
{
|
||||
"text": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"prefix": ":intersection",
|
||||
"operators": [
|
||||
{
|
||||
"operator": "title",
|
||||
"operands": [
|
||||
{
|
||||
"text": "Red wine"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"operator": "tags",
|
||||
"operands": [
|
||||
{
|
||||
"text": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"namedPrefix": "intersection"
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
// named prefix with no suffix
|
||||
expect($tw.wiki.parseFilter(":reduce[multiply<accumulator>]")).toEqual(
|
||||
[
|
||||
{
|
||||
"prefix": ":reduce",
|
||||
"operators": [
|
||||
{
|
||||
"operator": "multiply",
|
||||
"operands": [
|
||||
{
|
||||
"variable": true,
|
||||
"text": "accumulator"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"namedPrefix": "reduce"
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
//named prefix with one simple suffix
|
||||
expect($tw.wiki.parseFilter(":reduce:1[multiply<accumulator>]")).toEqual(
|
||||
[
|
||||
{
|
||||
"prefix": ":reduce:1",
|
||||
"operators": [
|
||||
{
|
||||
"operator": "multiply",
|
||||
"operands": [
|
||||
{
|
||||
"variable": true,
|
||||
"text": "accumulator"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"namedPrefix": "reduce",
|
||||
"suffixes": [
|
||||
[
|
||||
"1"
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
//named prefix with two simple suffixes
|
||||
expect($tw.wiki.parseFilter(":reduce:1:hello[multiply<accumulator>]")).toEqual(
|
||||
[
|
||||
{
|
||||
"prefix": ":reduce:1:hello",
|
||||
"operators": [
|
||||
{
|
||||
"operator": "multiply",
|
||||
"operands": [
|
||||
{
|
||||
"variable": true,
|
||||
"text": "accumulator"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"namedPrefix": "reduce",
|
||||
"suffixes": [
|
||||
[
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"hello",
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
//named prefix with two rich (comma separated) suffixes
|
||||
expect($tw.wiki.parseFilter(":reduce:1,one:hello,there[multiply<accumulator>]")).toEqual(
|
||||
[
|
||||
{
|
||||
"prefix": ":reduce:1,one:hello,there",
|
||||
"operators": [
|
||||
{
|
||||
"operator": "multiply",
|
||||
"operands": [
|
||||
{
|
||||
"variable": true,
|
||||
"text": "accumulator"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"namedPrefix": "reduce",
|
||||
"suffixes": [
|
||||
[
|
||||
"1",
|
||||
"one"
|
||||
],
|
||||
[
|
||||
"hello",
|
||||
"there"
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
// suffixes with spaces
|
||||
expect($tw.wiki.parseFilter(":reduce: 1, one:hello, there [multiply<accumulator>]")).toEqual(
|
||||
[
|
||||
{
|
||||
"prefix": ":reduce: 1, one:hello, there ",
|
||||
"operators": [
|
||||
{
|
||||
"operator": "multiply",
|
||||
"operands": [
|
||||
{
|
||||
"variable": true,
|
||||
"text": "accumulator"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"namedPrefix": "reduce",
|
||||
"suffixes": [
|
||||
[
|
||||
"1",
|
||||
"one"
|
||||
],
|
||||
[
|
||||
"hello",
|
||||
"there"
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("'reduce' and 'intersection' filter prefix tests", function() {
|
||||
@ -60,7 +253,7 @@ describe("'reduce' and 'intersection' filter prefix tests", function() {
|
||||
wiki.addTiddler({
|
||||
title: "Red wine",
|
||||
tags: ["drinks", "wine", "textexample"],
|
||||
text: "This is some more text"
|
||||
text: "This is some more text!"
|
||||
});
|
||||
wiki.addTiddler({
|
||||
title: "Cheesecake",
|
||||
@ -72,6 +265,26 @@ describe("'reduce' and 'intersection' filter prefix tests", function() {
|
||||
tags: ["cakes", "food", "textexample"],
|
||||
text: "This is even more text"
|
||||
});
|
||||
wiki.addTiddler({
|
||||
title: "Persian love cake",
|
||||
tags: ["cakes"],
|
||||
text: "An amazing cake worth the effort to make"
|
||||
});
|
||||
wiki.addTiddler({
|
||||
title: "cheesecake",
|
||||
tags: ["cakes"],
|
||||
text: "Everyone likes cheescake"
|
||||
});
|
||||
wiki.addTiddler({
|
||||
title: "chocolate cake",
|
||||
tags: ["cakes"],
|
||||
text: "lower case chocolate cake"
|
||||
});
|
||||
wiki.addTiddler({
|
||||
title: "Pound cake",
|
||||
tags: ["cakes","with tea"],
|
||||
text: "Does anyone eat pound cake?"
|
||||
});
|
||||
|
||||
it("should handle the :reduce filter prefix", function() {
|
||||
expect(wiki.filterTiddlers("[tag[shopping]] :reduce[get[quantity]add<accumulator>]").join(",")).toBe("22");
|
||||
@ -80,6 +293,10 @@ describe("'reduce' and 'intersection' filter prefix tests", function() {
|
||||
// Empty input should become empty output
|
||||
expect(wiki.filterTiddlers("[tag[non-existent]] :reduce[get[price]multiply{!!quantity}add<accumulator>]").length).toBe(0);
|
||||
expect(wiki.filterTiddlers("[tag[non-existent]] :reduce[get[price]multiply{!!quantity}add<accumulator>] :else[[0]]").join(",")).toBe("0");
|
||||
|
||||
expect(wiki.filterTiddlers("[tag[non-existent]] :reduce:11,22[get[price]multiply{!!quantity}add<accumulator>] :else[[0]]").join(",")).toBe("0");
|
||||
|
||||
expect(wiki.filterTiddlers("[tag[non-existent]] :reduce:11[get[price]multiply{!!quantity}add<accumulator>] :else[[0]]").join(",")).toBe("0");
|
||||
});
|
||||
|
||||
it("should handle the reduce operator", function() {
|
||||
@ -101,6 +318,28 @@ describe("'reduce' and 'intersection' filter prefix tests", function() {
|
||||
expect(wiki.filterTiddlers("[tag[non-existent]reduce<add-price>else[0]]",anchorWidget).join(",")).toBe("0");
|
||||
});
|
||||
|
||||
it("should handle the average operator", function() {
|
||||
expect(wiki.filterTiddlers("[tag[shopping]get[price]average[]]").join(",")).toBe("2.3575");
|
||||
expect(parseFloat(wiki.filterTiddlers("[tag[food]get[price]average[]]").join(","))).toBeCloseTo(3.155);
|
||||
});
|
||||
|
||||
it("should handle the median operator", function() {
|
||||
expect(parseFloat(wiki.filterTiddlers("[tag[shopping]get[price]median[]]").join(","))).toBeCloseTo(1.99);
|
||||
expect(parseFloat(wiki.filterTiddlers("[tag[food]get[price]median[]]").join(","))).toBeCloseTo(3.155);
|
||||
});
|
||||
|
||||
it("should handle the variance operator", function() {
|
||||
expect(parseFloat(wiki.filterTiddlers("[tag[shopping]get[price]variance[]]").join(","))).toBeCloseTo(2.92);
|
||||
expect(parseFloat(wiki.filterTiddlers("[tag[food]get[price]variance[]]").join(","))).toBeCloseTo(3.367);
|
||||
expect(wiki.filterTiddlers(" +[variance[]]").toString()).toBe("NaN");
|
||||
});
|
||||
|
||||
it("should handle the standard-deviation operator", function() {
|
||||
expect(parseFloat(wiki.filterTiddlers("[tag[shopping]get[price]standard-deviation[]]").join(","))).toBeCloseTo(1.71);
|
||||
expect(parseFloat(wiki.filterTiddlers("[tag[food]get[price]standard-deviation[]]").join(","))).toBeCloseTo(1.835);
|
||||
expect(wiki.filterTiddlers(" +[standard-deviation[]]").toString()).toBe("NaN");
|
||||
});
|
||||
|
||||
it("should handle the :intersection prefix", function() {
|
||||
expect(wiki.filterTiddlers("[[Sparkling water]tags[]] :intersection[[Red wine]tags[]]").join(",")).toBe("drinks,textexample");
|
||||
expect(wiki.filterTiddlers("[[Brownies]tags[]] :intersection[[Chocolate Cake]tags[]]").join(",")).toBe("food");
|
||||
@ -116,11 +355,25 @@ describe("'reduce' and 'intersection' filter prefix tests", function() {
|
||||
rootWidget.makeChildWidgets();
|
||||
var anchorWidget = rootWidget.children[0];
|
||||
rootWidget.setVariable("larger-than-18","[get[text]length[]compare:integer:gteq[18]]");
|
||||
rootWidget.setVariable("nr","18");
|
||||
rootWidget.setVariable("larger-than-18-with-var","[get[text]length[]compare:integer:gteq<nr>]");
|
||||
expect(wiki.filterTiddlers("[tag[textexample]] :filter[get[text]length[]compare:integer:gteq[18]]",anchorWidget).join(",")).toBe("Red wine,Cheesecake,Chocolate Cake");
|
||||
expect(wiki.filterTiddlers("[tag[textexample]]",anchorWidget).join(",")).toBe("Sparkling water,Red wine,Cheesecake,Chocolate Cake");
|
||||
expect(wiki.filterTiddlers("[tag[textexample]filter<larger-than-18>]",anchorWidget).join(",")).toBe("Red wine,Cheesecake,Chocolate Cake");
|
||||
})
|
||||
expect(wiki.filterTiddlers("[tag[textexample]filter<larger-than-18-with-var>]",anchorWidget).join(",")).toBe("Red wine,Cheesecake,Chocolate Cake");
|
||||
});
|
||||
|
||||
it("should handle the :sort prefix", function() {
|
||||
expect(wiki.filterTiddlers("a1 a10 a2 a3 b10 b3 b1 c9 c11 c1 :sort:alphanumeric[{!!title}]").join(",")).toBe("a1,a2,a3,a10,b1,b3,b10,c1,c9,c11");
|
||||
expect(wiki.filterTiddlers("a1 a10 a2 a3 b10 b3 b1 c9 c11 c1 :sort:alphanumeric:reverse[{!!title}]").join(",")).toBe("c11,c9,c1,b10,b3,b1,a10,a3,a2,a1");
|
||||
expect(wiki.filterTiddlers("[tag[shopping]] :sort:number:[get[price]]").join(",")).toBe("Milk,Chick Peas,Rice Pudding,Brownies");
|
||||
expect(wiki.filterTiddlers("[tag[textexample]] :sort:number:[get[text]length[]]").join(",")).toBe("Sparkling water,Chocolate Cake,Red wine,Cheesecake");
|
||||
expect(wiki.filterTiddlers("[tag[textexample]] :sort:number:reverse[get[text]length[]]").join(",")).toBe("Cheesecake,Red wine,Chocolate Cake,Sparkling water");
|
||||
expect(wiki.filterTiddlers("[tag[notatag]] :sort:number[get[price]]").join(",")).toBe("");
|
||||
expect(wiki.filterTiddlers("[tag[cakes]] :sort:string[{!!title}]").join(",")).toBe("Cheesecake,cheesecake,Chocolate Cake,chocolate cake,Persian love cake,Pound cake");
|
||||
expect(wiki.filterTiddlers("[tag[cakes]] :sort:string:casesensitive[{!!title}]").join(",")).toBe("Cheesecake,Chocolate Cake,Persian love cake,Pound cake,cheesecake,chocolate cake");
|
||||
expect(wiki.filterTiddlers("[tag[cakes]] :sort:string:casesensitive,reverse[{!!title}]").join(",")).toBe("chocolate cake,cheesecake,Pound cake,Persian love cake,Chocolate Cake,Cheesecake");
|
||||
});
|
||||
});
|
||||
|
||||
})();
|
@ -350,6 +350,123 @@ describe("Widget module", function() {
|
||||
expect(wrapper.children[0].children[4].sequenceNumber).toBe(5);
|
||||
});
|
||||
|
||||
|
||||
it("should deal with the list widget using a counter variable", function() {
|
||||
var wiki = new $tw.Wiki();
|
||||
// Add some tiddlers
|
||||
wiki.addTiddlers([
|
||||
{title: "TiddlerOne", text: "Jolly Old World"},
|
||||
{title: "TiddlerTwo", text: "Worldly Old Jelly"},
|
||||
{title: "TiddlerThree", text: "Golly Gosh"},
|
||||
{title: "TiddlerFour", text: "Lemon Squash"}
|
||||
]);
|
||||
// Construct the widget node
|
||||
var text = "<$list counter='index'><$view field='text'/><$text text=<<index>>/><$text text=<<index-first>>/><$text text=<<index-last>>/></$list>";
|
||||
var widgetNode = createWidgetNode(parseText(text,wiki),wiki);
|
||||
// Render the widget node to the DOM
|
||||
var wrapper = renderWidgetNode(widgetNode);
|
||||
// Test the rendering
|
||||
expect(wrapper.innerHTML).toBe("<p>Lemon Squash1yesnoJolly Old World2nonoGolly Gosh3nonoWorldly Old Jelly4noyes</p>");
|
||||
// Test the sequence numbers in the DOM
|
||||
expect(wrapper.sequenceNumber).toBe(0);
|
||||
expect(wrapper.children[0].sequenceNumber).toBe(1);
|
||||
expect(wrapper.children[0].children[0].sequenceNumber).toBe(2);
|
||||
expect(wrapper.children[0].children[1].sequenceNumber).toBe(3);
|
||||
expect(wrapper.children[0].children[2].sequenceNumber).toBe(4);
|
||||
expect(wrapper.children[0].children[3].sequenceNumber).toBe(5);
|
||||
expect(wrapper.children[0].children[4].sequenceNumber).toBe(6);
|
||||
expect(wrapper.children[0].children[5].sequenceNumber).toBe(7);
|
||||
expect(wrapper.children[0].children[6].sequenceNumber).toBe(8);
|
||||
expect(wrapper.children[0].children[7].sequenceNumber).toBe(9);
|
||||
expect(wrapper.children[0].children[8].sequenceNumber).toBe(10);
|
||||
expect(wrapper.children[0].children[9].sequenceNumber).toBe(11);
|
||||
expect(wrapper.children[0].children[10].sequenceNumber).toBe(12);
|
||||
expect(wrapper.children[0].children[11].sequenceNumber).toBe(13);
|
||||
expect(wrapper.children[0].children[12].sequenceNumber).toBe(14);
|
||||
expect(wrapper.children[0].children[13].sequenceNumber).toBe(15);
|
||||
expect(wrapper.children[0].children[14].sequenceNumber).toBe(16);
|
||||
expect(wrapper.children[0].children[15].sequenceNumber).toBe(17);
|
||||
// Add another tiddler
|
||||
wiki.addTiddler({title: "TiddlerFive", text: "Jalapeno Peppers"});
|
||||
// Refresh
|
||||
refreshWidgetNode(widgetNode,wrapper,["TiddlerFive"]);
|
||||
// Test the refreshing
|
||||
expect(wrapper.innerHTML).toBe("<p>Jalapeno Peppers1yesnoLemon Squash2nonoJolly Old World3nonoGolly Gosh4nonoWorldly Old Jelly5noyes</p>");
|
||||
// Test the sequence numbers in the DOM
|
||||
expect(wrapper.sequenceNumber).toBe(0);
|
||||
expect(wrapper.children[0].sequenceNumber).toBe(1);
|
||||
expect(wrapper.children[0].children[0].sequenceNumber).toBe(18);
|
||||
expect(wrapper.children[0].children[1].sequenceNumber).toBe(19);
|
||||
expect(wrapper.children[0].children[2].sequenceNumber).toBe(20);
|
||||
expect(wrapper.children[0].children[3].sequenceNumber).toBe(21);
|
||||
expect(wrapper.children[0].children[4].sequenceNumber).toBe(22);
|
||||
expect(wrapper.children[0].children[5].sequenceNumber).toBe(23);
|
||||
expect(wrapper.children[0].children[6].sequenceNumber).toBe(24);
|
||||
expect(wrapper.children[0].children[7].sequenceNumber).toBe(25);
|
||||
expect(wrapper.children[0].children[8].sequenceNumber).toBe(26);
|
||||
expect(wrapper.children[0].children[9].sequenceNumber).toBe(27);
|
||||
expect(wrapper.children[0].children[10].sequenceNumber).toBe(28);
|
||||
expect(wrapper.children[0].children[11].sequenceNumber).toBe(29);
|
||||
expect(wrapper.children[0].children[12].sequenceNumber).toBe(30);
|
||||
expect(wrapper.children[0].children[13].sequenceNumber).toBe(31);
|
||||
expect(wrapper.children[0].children[14].sequenceNumber).toBe(32);
|
||||
expect(wrapper.children[0].children[15].sequenceNumber).toBe(33);
|
||||
expect(wrapper.children[0].children[16].sequenceNumber).toBe(34);
|
||||
expect(wrapper.children[0].children[17].sequenceNumber).toBe(35);
|
||||
expect(wrapper.children[0].children[18].sequenceNumber).toBe(36);
|
||||
expect(wrapper.children[0].children[19].sequenceNumber).toBe(37);
|
||||
// Remove a tiddler
|
||||
wiki.deleteTiddler("TiddlerThree");
|
||||
// Refresh
|
||||
refreshWidgetNode(widgetNode,wrapper,["TiddlerThree"]);
|
||||
// Test the refreshing
|
||||
expect(wrapper.innerHTML).toBe("<p>Jalapeno Peppers1yesnoLemon Squash2nonoJolly Old World3nonoWorldly Old Jelly4noyes</p>");
|
||||
// Test the sequence numbers in the DOM
|
||||
expect(wrapper.sequenceNumber).toBe(0);
|
||||
expect(wrapper.children[0].sequenceNumber).toBe(1);
|
||||
expect(wrapper.children[0].children[0].sequenceNumber).toBe(18);
|
||||
expect(wrapper.children[0].children[1].sequenceNumber).toBe(19);
|
||||
expect(wrapper.children[0].children[2].sequenceNumber).toBe(20);
|
||||
expect(wrapper.children[0].children[3].sequenceNumber).toBe(21);
|
||||
expect(wrapper.children[0].children[4].sequenceNumber).toBe(22);
|
||||
expect(wrapper.children[0].children[5].sequenceNumber).toBe(23);
|
||||
expect(wrapper.children[0].children[6].sequenceNumber).toBe(24);
|
||||
expect(wrapper.children[0].children[7].sequenceNumber).toBe(25);
|
||||
expect(wrapper.children[0].children[8].sequenceNumber).toBe(26);
|
||||
expect(wrapper.children[0].children[9].sequenceNumber).toBe(27);
|
||||
expect(wrapper.children[0].children[10].sequenceNumber).toBe(28);
|
||||
expect(wrapper.children[0].children[11].sequenceNumber).toBe(29);
|
||||
expect(wrapper.children[0].children[12].sequenceNumber).toBe(38);
|
||||
expect(wrapper.children[0].children[13].sequenceNumber).toBe(39);
|
||||
expect(wrapper.children[0].children[14].sequenceNumber).toBe(40);
|
||||
expect(wrapper.children[0].children[15].sequenceNumber).toBe(41);
|
||||
// Add it back a tiddler
|
||||
wiki.addTiddler({title: "TiddlerThree", text: "Something"});
|
||||
// Refresh
|
||||
refreshWidgetNode(widgetNode,wrapper,["TiddlerThree"]);
|
||||
// Test the refreshing
|
||||
expect(wrapper.innerHTML).toBe("<p>Jalapeno Peppers1yesnoLemon Squash2nonoJolly Old World3nonoSomething4nonoWorldly Old Jelly5noyes</p>");
|
||||
// Test the sequence numbers in the DOM
|
||||
expect(wrapper.sequenceNumber).toBe(0);
|
||||
expect(wrapper.children[0].sequenceNumber).toBe(1);
|
||||
expect(wrapper.children[0].children[0].sequenceNumber).toBe(18);
|
||||
expect(wrapper.children[0].children[1].sequenceNumber).toBe(19);
|
||||
expect(wrapper.children[0].children[2].sequenceNumber).toBe(20);
|
||||
expect(wrapper.children[0].children[3].sequenceNumber).toBe(21);
|
||||
expect(wrapper.children[0].children[4].sequenceNumber).toBe(22);
|
||||
expect(wrapper.children[0].children[5].sequenceNumber).toBe(23);
|
||||
expect(wrapper.children[0].children[6].sequenceNumber).toBe(24);
|
||||
expect(wrapper.children[0].children[7].sequenceNumber).toBe(25);
|
||||
expect(wrapper.children[0].children[8].sequenceNumber).toBe(26);
|
||||
expect(wrapper.children[0].children[9].sequenceNumber).toBe(27);
|
||||
expect(wrapper.children[0].children[10].sequenceNumber).toBe(28);
|
||||
expect(wrapper.children[0].children[11].sequenceNumber).toBe(29);
|
||||
expect(wrapper.children[0].children[12].sequenceNumber).toBe(42);
|
||||
expect(wrapper.children[0].children[13].sequenceNumber).toBe(43);
|
||||
expect(wrapper.children[0].children[14].sequenceNumber).toBe(44);
|
||||
expect(wrapper.children[0].children[15].sequenceNumber).toBe(45);
|
||||
});
|
||||
|
||||
it("should deal with the list widget followed by other widgets", function() {
|
||||
var wiki = new $tw.Wiki();
|
||||
// Add some tiddlers
|
||||
|
@ -6,7 +6,7 @@ type: text/vnd.tiddlywiki
|
||||
|
||||
//These are personal reflections on the history and development of TiddlyWiki from JeremyRuston.//
|
||||
|
||||
//There is also a [[podcast|https://changelog.com/196/]] discussing TiddlyWiki's backstory.//
|
||||
//There is also a [[podcast from 2016|https://changelog.com/podcast/196]] discussing TiddlyWiki's backstory as well as a [[recording from 2021|https://twit.tv/shows/floss-weekly/episodes/620]].//
|
||||
|
||||
! Origins of TiddlyWiki
|
||||
|
||||
|
@ -1,14 +0,0 @@
|
||||
created: 20140315085406905
|
||||
modified: 20210106151027120
|
||||
tags: Tutorials
|
||||
title: "Hosting TiddlyWiki5 on GoogleDrive" by Tony Ching
|
||||
type: text/vnd.tiddlywiki
|
||||
url: https://googledrive.com/host/0B51gSXixfJ2Qb0I4R2M4MWJVMlU
|
||||
|
||||
Tony Ching's quick guide for sharing TiddlyWiki with Google Drive.
|
||||
|
||||
{{!!url}}
|
||||
|
||||
<<<
|
||||
Anyway your self-contained a non-linear personal web notebook can be hosted on Google Drive, a free cloud service from Google.com. Because TiddlyWiki5 now supports the Stanford Javascript Crypto Library (SJCL), you can encrypt your content from prying eyes (excluding the NSA of course)
|
||||
<<<
|
@ -1,5 +1,5 @@
|
||||
created: 20140502213500000
|
||||
modified: 20160622111355787
|
||||
modified: 20210406131243532
|
||||
tags: Features Concepts
|
||||
title: PermaLinks
|
||||
type: text/vnd.tiddlywiki
|
||||
@ -32,7 +32,7 @@ If the target tiddler isn't present in the story list then it is automatically i
|
||||
|
||||
It is also possible to specify a story filter without specifying a target tiddler for navigation:
|
||||
|
||||
<a href="https://tiddlywiki.com/#:[tags[task]]" rel="noopener noreferrer">~https://tiddlywiki.com/#:[tags[task]]</a>
|
||||
<a href="https://tiddlywiki.com/#:[tag[task]]" rel="noopener noreferrer">~https://tiddlywiki.com/#:[tag[task]]</a>
|
||||
|
||||
! About URL encoding
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
created: 20130822080600000
|
||||
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
|
||||
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/EditorTools]] [[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: 20210519160636964
|
||||
tags: Reference Concepts
|
||||
title: SystemTags
|
||||
type: text/vnd.tiddlywiki
|
||||
|
@ -1,5 +1,5 @@
|
||||
created: 20190206140446821
|
||||
modified: 20190611155838557
|
||||
modified: 20210417090408263
|
||||
tags: Filters
|
||||
title: Mathematics Operators
|
||||
type: text/vnd.tiddlywiki
|
||||
@ -26,6 +26,7 @@ The mathematics operators take three different forms:
|
||||
* ''Reducing operators'' apply an operation to all of the numbers in the input list, returning a single result (e.g. sum, product)
|
||||
** <<.inline-operator-example "=1 =2 =3 =4 +[sum[]]">>
|
||||
** <<.inline-operator-example "=1 =2 =3 =4 +[product[]]">>
|
||||
** <<.inline-operator-example "=1 =2 =3 =4 +[average[]]">>
|
||||
|
||||
Operators can be combined:
|
||||
|
||||
|
13
editions/tw5.com/tiddlers/filters/average.tid
Normal file
13
editions/tw5.com/tiddlers/filters/average.tid
Normal file
@ -0,0 +1,13 @@
|
||||
caption: average
|
||||
created: 20210417090137714
|
||||
modified: 20210426131553482
|
||||
op-input: a [[selection of titles|Title Selection]]
|
||||
op-output: the arithmetic mean of the input as numbers
|
||||
op-purpose: treating each input title as a number, compute their arithmetic mean
|
||||
tags: [[Reducing Mathematics Operators]] [[Filter Operators]] [[Mathematics Operators]]
|
||||
title: average Operator
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.from-version "5.1.24">> See [[Mathematics Operators]] for an overview.
|
||||
|
||||
<<.operator-examples "average">>
|
@ -0,0 +1,10 @@
|
||||
created: 20210426130837644
|
||||
modified: 20210426131553546
|
||||
tags: [[Operator Examples]] [[average Operator]]
|
||||
title: average Operator (Examples)
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.operator-example 1 "=1 =3 =4 =5 +[average[]]">>
|
||||
|
||||
Note that if there is no input the operator returns `NaN`
|
||||
<<.operator-example 2 "[tag[NotATiddler]get[price]] +[average[]]">>
|
@ -0,0 +1,10 @@
|
||||
created: 20210426131042769
|
||||
modified: 20210426131553560
|
||||
tags: [[Operator Examples]] [[median Operator]]
|
||||
title: median Operator (Examples)
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.operator-example 1 "=1 =3 =4 =5 +[median[]]">>
|
||||
|
||||
Note that if there is no input the operator returns `NaN`
|
||||
<<.operator-example 2 "[title[NotATiddler]get[price]] +[median[]]">>
|
@ -0,0 +1,10 @@
|
||||
created: 20210426130306824
|
||||
modified: 20210426131553553
|
||||
tags: [[Operator Examples]] [[standard-deviation Operator]]
|
||||
title: standard-deviation Operator (Examples)
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.operator-example 1 "=1 =3 =4 =5 +[standard-deviation[]]">>
|
||||
|
||||
Note that if there is no input the operator returns `NaN`
|
||||
<<.operator-example 2 "[title[NotATiddler]get[price]] +[standard-deviation[]]">>
|
@ -0,0 +1,10 @@
|
||||
created: 20210426130620777
|
||||
modified: 20210426131553522
|
||||
tags: [[Operator Examples]] [[variance Operator]]
|
||||
title: variance Operator (Examples)
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.operator-example 1 "1 3 4 5 +[variance[]]">>
|
||||
|
||||
Note that if there is no input the operator returns `NaN`
|
||||
<<.operator-example 2 "[title[NotATiddler]is[tiddler]get[price]] +[variance[]]">>
|
13
editions/tw5.com/tiddlers/filters/median.tid
Normal file
13
editions/tw5.com/tiddlers/filters/median.tid
Normal file
@ -0,0 +1,13 @@
|
||||
caption: median
|
||||
created: 20210417090137714
|
||||
modified: 20210426131553507
|
||||
op-input: a [[selection of titles|Title Selection]]
|
||||
op-output: the median of the input numbers
|
||||
op-purpose: treating each input title as a number, compute their median value
|
||||
tags: [[Filter Operators]] [[Mathematics Operators]]
|
||||
title: median Operator
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.from-version "5.1.24">> See [[Mathematics Operators]] for an overview.
|
||||
|
||||
<<.operator-examples "median">>
|
@ -1,17 +1,17 @@
|
||||
caption: sortsub
|
||||
created: 20200424160155182
|
||||
modified: 20200424160155182
|
||||
modified: 20210428152533501
|
||||
op-input: a [[selection of titles|Title Selection]]
|
||||
op-neg-output: the input, sorted into reverse order by the result of evaluating subfilter <<.param S>>
|
||||
op-output: the input, sorted into ascending order by the result of evaluating subfilter <<.param S>>
|
||||
op-parameter: a subfilter to be evaluated
|
||||
op-parameter-name: S
|
||||
op-purpose: sort the input by the result of evaluating a subfilter for each item
|
||||
op-suffix: the type used for the comparison (string, number, integer, date, version), defaulting to string
|
||||
op-suffix-name: T
|
||||
tags: [[Filter Operators]] [[Field Operators]] [[Order Operators]] [[Negatable Operators]]
|
||||
title: sortsub Operator
|
||||
type: text/vnd.tiddlywiki
|
||||
caption: sortsub
|
||||
op-purpose: sort the input by the result of evaluating a subfilter for each item
|
||||
op-input: a [[selection of titles|Title Selection]]
|
||||
op-parameter: a subfilter to be evaluated
|
||||
op-parameter-name: S
|
||||
op-suffix: the type used for the comparison (string, number, integer, date, version), defaulting to string
|
||||
op-suffix-name: T
|
||||
op-output: the input, sorted into ascending order by the result of evaluating subfilter <<.param S>>
|
||||
op-neg-output: the input, sorted into reverse order by the result of evaluating subfilter <<.param S>>
|
||||
|
||||
Each item in the list of input titles is passed to the subfilter in turn. The subfilter transforms the input titles into the form needed for sorting. For example, the subfilter `[length[]]` transforms each input title in the number representing its length, and thus sorts the input titles according to their length.
|
||||
|
||||
@ -24,6 +24,7 @@ The suffix <<.place T>> determines how the items are compared and can be:
|
||||
* "integer" - invalid integers are interpreted as zero
|
||||
* "date" - invalid dates are interpreted as 1st January 1970
|
||||
* "version" - invalid versions are interpreted as "v0.0.0"
|
||||
* "alphanumeric" - treat items as alphanumerics <<.from-version "5.1.24">>
|
||||
|
||||
Note that subfilters should return the same number of items that they are passed. Any missing entries will be treated as zero or the empty string. In particular, when retrieving the value of a field with the [[get Operator]] it is helpful to guard against a missing field value using the [[else Operator]]. For example `[get[myfield]else[default-value]...`.
|
||||
|
||||
|
@ -0,0 +1,15 @@
|
||||
caption: standard-deviation
|
||||
created: 20210426130150358
|
||||
modified: 20210426131553530
|
||||
op-input: a [[selection of titles|Title Selection]]
|
||||
op-output: the standard-deviation of the input as numbers
|
||||
op-purpose: treating each input title as a number, compute their standard-deviation
|
||||
tags: [[Reducing Mathematics Operators]] [[Filter Operators]] [[Mathematics Operators]]
|
||||
title: standard-deviation Operator
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.from-version "5.1.24">> See [[Mathematics Operators]] for an overview.
|
||||
|
||||
<<.tip """ The `standard-deviation` operator treats the input as a complete population and not a sample""">>
|
||||
|
||||
<<.operator-examples "standard-deviation">>
|
@ -1,5 +1,5 @@
|
||||
created: 20150124182421000
|
||||
modified: 20201214053032397
|
||||
modified: 20210428084144231
|
||||
tags: [[Filter Syntax]]
|
||||
title: Filter Expression
|
||||
type: text/vnd.tiddlywiki
|
||||
@ -26,6 +26,8 @@ If a run has:
|
||||
* named prefix `:intersection` replaces all filter output so far with titles that are present in the output of this run, as well as the output from previous runs. Forms the input for the next run. <<.from-version "5.1.23">>
|
||||
* named prefix `:reduce` replaces all filter output so far with a single item by repeatedly applying a formula to each input title. A typical use is to add up the values in a given field of each input title. <<.from-version "5.1.23">>
|
||||
** [[Examples|Filter Run Prefix (Examples)]]
|
||||
* named prefix `:sort` sorts all filter output so far by applying this run to each input title and sorting according to that output. <<.from-version "5.1.24">>
|
||||
** See [[Sort Filter Run Prefix]].
|
||||
|
||||
<<.tip "Compare named filter run prefix `:filter` with [[filter Operator]] which applies a subfilter to every input title, removing the titles that return an empty result from the subfilter">>
|
||||
|
||||
@ -47,7 +49,7 @@ The input of a run is normally a list of all the non-[[shadow|ShadowTiddlers]] t
|
||||
|
||||
|Prefix|Input|h
|
||||
|`-`, `~`, `=`, `:intersection` or none| <$link to="all Operator">`[all[]]`</$link> tiddler titles, unless otherwise determined by the first [[filter operator|Filter Operators]]|
|
||||
|`+`, `:filter`, `:reduce`|the filter output of all previous runs so far|
|
||||
|`+`, `:filter`, `:reduce`,`:sort`|the filter output of all previous runs so far|
|
||||
|
||||
Precisely because of varying inputs, be aware that both prefixes `-` and `+` do not behave inverse to one another!
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
created: 20201117073343969
|
||||
modified: 20201208185546667
|
||||
tags: [[Filter Syntax]]
|
||||
modified: 20210428084013109
|
||||
tags: [[Filter Syntax]] [[Filter Run Prefix Examples]]
|
||||
title: Filter Run Prefix (Examples)
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
@ -44,3 +44,7 @@ Specifying a default value when input is empty:
|
||||
`[tag[non-existent]] :reduce[get[price]multiply{!!quantity}add<accumulator>] :else[[0]]`
|
||||
|
||||
<$macrocall $name=".tip" _="""Unlike the [[reduce Operator]], the `:reduce` prefix cannot specify an initial value for the accumulator, so its initial value will always be empty (which is treated as 0 by mathematical operators). So `=1 =2 =3 :reduce[multiply<accumulator>]` will produce 0, not 6. If you need to specify an initial accumulator value, use the [[reduce Operator]]."""/>
|
||||
|
||||
!! `:sort` examples
|
||||
|
||||
See [[Sort Filter Run Prefix (Examples)]]
|
@ -0,0 +1,33 @@
|
||||
created: 20210428074912172
|
||||
modified: 20210428085746041
|
||||
tags: [[Filter Syntax]] [[Sort Filter Run Prefix]] [[Filter Run Prefix Examples]]
|
||||
title: Sort Filter Run Prefix (Examples)
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
Sort by title length:
|
||||
|
||||
<<.operator-example 1 "[all[tiddlers]] :sort:number[length[]] +[limit[10]]">>
|
||||
|
||||
Sort by title length reversed:
|
||||
|
||||
<<.operator-example 2 "[all[tiddlers]] :sort:number:reverse[length[]] +[limit[10]]">>
|
||||
|
||||
Sort by text length:
|
||||
|
||||
<<.operator-example 3 "[all[tiddlers]] :sort:number[get[text]length[]] +[limit[10]]">>
|
||||
|
||||
Sort by newest of modified dates:
|
||||
|
||||
<<.operator-example 4 "[tag[Field Operators]] :sort:date[get[modified]else[19700101]] +[limit[10]]">>
|
||||
|
||||
Sort by title:
|
||||
<<.operator-example 5 "[tag[Field Operators]] :sort:string:casesensitive[get[caption]] +[limit[10]]">>
|
||||
|
||||
Sort by title in reverse order:
|
||||
<<.operator-example 6 "[tag[Field Operators]] :sort:string:casesensitive,reverse[get[caption]] +[limit[10]]">>
|
||||
|
||||
Sort as text with case sensitivity:
|
||||
<<.operator-example 7 "Apple Banana Orange Grapefruit guava DragonFruit Kiwi apple orange :sort:string:casesensitive[{!!title}]">>
|
||||
|
||||
Sort as text ignoring case:
|
||||
<<.operator-example 8 "Apple Banana Orange Grapefruit guava DragonFruit Kiwi apple orange :sort:string:caseinsensitive[{!!title}]">>
|
@ -0,0 +1,32 @@
|
||||
created: 20210428083929749
|
||||
modified: 20210428140713422
|
||||
tags: [[Filter Syntax]] [[Filter Run Prefix]]
|
||||
title: Sort Filter Run Prefix
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.from-version "5.1.24">>
|
||||
|
||||
|''purpose'' |sort the input titles by the result of evaluating this filter run for each item |
|
||||
|''input'' |all titles from previous filter runs |
|
||||
|''suffix'' |the `:sort` filter run prefix uses a rich suffix, see below for details |
|
||||
|''output''|the sorted result of previous filter runs |
|
||||
|
||||
Each input title from previous runs is passed to this run in turn. The filter run transforms the input titles into the form needed for sorting. For example, the filter run `[length[]]` transforms each input title in to the number representing its length, and thus sorts the input titles according to their length.
|
||||
|
||||
Note that within the filter run, the "currentTiddler" variable is set to the title of the tiddler being processed. This permits filter runs like `:sort:number[{!!value}divide{!!cost}]` to be used for computation.
|
||||
|
||||
The `:sort` filter run prefix uses an extended syntax that allows for multiple suffixes, some of which are required:
|
||||
|
||||
```
|
||||
:sort:<type>:<flaglist>[...filter run...]
|
||||
|
||||
```
|
||||
|
||||
* ''type'': Required. Determines how the items are compared and can be any of: ''string'', ''alphanumeric'', ''number'', ''integer'', ''version'' or ''date''.
|
||||
* ''flaglist'': comma separated list of the following flags:
|
||||
** ''casesensitive'' or ''caseinsensitive'' (required for types `string` and `alphanumeric`).
|
||||
** ''reverse'' to invert the order of the filter run (optional).
|
||||
|
||||
Note that filter runs used with the `:sort` prefix should return the same number of items that they are passed. Any missing entries will be treated as zero or the empty string. In particular, when retrieving the value of a field with the [[get Operator]] it is helpful to guard against a missing field value using the [[else Operator]]. For example `[get[myfield]else[default-value]...`.
|
||||
|
||||
[[Examples|Sort Filter Run Prefix (Examples)]]
|
15
editions/tw5.com/tiddlers/filters/variance Operator.tid
Normal file
15
editions/tw5.com/tiddlers/filters/variance Operator.tid
Normal file
@ -0,0 +1,15 @@
|
||||
caption: variance
|
||||
created: 20210426130029500
|
||||
modified: 20210426131553539
|
||||
op-input: a [[selection of titles|Title Selection]]
|
||||
op-output: the variance of the input as numbers
|
||||
op-purpose: treating each input title as a number, compute their variance
|
||||
tags: [[Reducing Mathematics Operators]] [[Filter Operators]] [[Mathematics Operators]]
|
||||
title: variance Operator
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.from-version "5.1.24">> See [[Mathematics Operators]] for an overview.
|
||||
|
||||
<<.tip """ The `standard-deviation` operator treats the input as a complete population and not a sample""">>
|
||||
|
||||
<<.operator-examples "variance">>
|
@ -0,0 +1,13 @@
|
||||
created: 20210411100148461
|
||||
modified: 20210411100148461
|
||||
tags: [[Hidden Settings]]
|
||||
title: Hidden Setting: HTML Parser Sandbox
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.from-version "5.1.24">> By default, tiddlers with the type `text/html` are displayed in an iframe with the [[sandbox attribute|https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-sandbox]] set to the empty string. This causes all security restrictions to be applied, disabling many features such as JavaScript, downloads and external file references. This is the safest setting.
|
||||
|
||||
To globally disable the sandbox, set the tiddler $:/config/HtmlParser/DisableSandbox to `yes`. This will mean that the code in the iframe has full access to TiddlyWiki's internals, which means that a malicious HTML page could exfiltrate data from a private wiki.
|
||||
|
||||
To keep the sandbox but control which restrictions are applied, ensure that $:/config/HtmlParser/DisableSandbox is not set to `yes`, and then set $:/config/HtmlParser/SandboxTokens to the desired list of tokens [[from the MDN documentation|https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-sandbox]].
|
||||
|
||||
Note that these are global settings. To control the sandboxing on an individual tiddler basis will require a custom `<iframe>` to be used.
|
@ -1,10 +1,10 @@
|
||||
created: 20200315143638556
|
||||
modified: 20200315143638556
|
||||
modified: 20210519155433742
|
||||
tags: [[Hidden Settings]]
|
||||
title: Hidden Setting: Disable Drag and Drop
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<.from-version "5.1.22">> To disable all the drag and drop operations that are built into the core, set the following tiddler to "no":
|
||||
<<.from-version "5.1.22">> To disable all the drag and drop operations that are built into the core, set the following tiddler to "no":
|
||||
|
||||
$:/config/DragAndDrop/Enable
|
||||
|
||||
|
@ -0,0 +1,12 @@
|
||||
created: 20210519155447339
|
||||
modified: 20210519160010708
|
||||
tags: [[Hidden Settings]]
|
||||
title: Hidden Setting: Enable File Import in Editor
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.from-version "5.1.24">>
|
||||
|
||||
$:/config/Editor/EnableImportFilter
|
||||
|
||||
This filter determines whether dragging and dropping files in the editor works for a given tiddler or not. A non-empty result enables drag and drop in the editor for that tiddler.
|
||||
This filter is used in such a manner that it respects the global drag and drop setting.
|
@ -0,0 +1,11 @@
|
||||
created: 20210519155910219
|
||||
modified: 20210519160221219
|
||||
tags: [[Hidden Settings]]
|
||||
title: Hidden Settings: Import Content Types for Editor
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.from-version "5.1.24">>
|
||||
|
||||
$:/config/Editor/ImportContentTypesFilter
|
||||
|
||||
This filter determines which `contentTypes` can be imported by dragging and dropping into the editor. It used by a DropzoneWidget wrapped around the editor, for the `contentTypesFilter` attribute.
|
@ -0,0 +1,126 @@
|
||||
created: 20201216182347597
|
||||
modified: 20201217193318816
|
||||
tags:
|
||||
title: How to create dynamic editor toolbar buttons
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
\define disabledFilterExample()`[[$(tempBoldDisabled)$]get[state-disabled]else[no]]`
|
||||
|
||||
\define remove-shortcuts()
|
||||
<$action-deletetiddler $tiddler=<<shortcutInfo>>/>
|
||||
<$action-deletetiddler $tiddler=<<shortcutConfigMac>>/>
|
||||
<$action-deletetiddler $tiddler=<<shortcutConfigNotMac>>/>
|
||||
<$action-deletetiddler $tiddler=<<tempBold>>/>
|
||||
<$action-deletetiddler $tiddler=<<tempBoldDisabled>>/>
|
||||
\end
|
||||
|
||||
\define create-shortcut-tiddlers()
|
||||
<$action-createtiddler $basetitle=<<shortcutInfo>>
|
||||
$template="$:/config/ShortcutInfo/bold"
|
||||
$overwrite="yes"
|
||||
/>
|
||||
<$action-navigate $to=<<shortcutInfo>>/>
|
||||
|
||||
<$action-createtiddler $basetitle=<<shortcutConfigMac>>
|
||||
$template="$:/config/shortcuts-mac/bold"
|
||||
$overwrite="yes"
|
||||
text="meta-shift-X"
|
||||
/>
|
||||
<$action-navigate $to=<<shortcutConfigMac>>/>
|
||||
|
||||
<$action-createtiddler $basetitle=<<shortcutConfigNotMac>>
|
||||
$template="$:/config/shortcuts-not-mac/bold"
|
||||
$overwrite="yes"
|
||||
text="ctrl-shift-X"
|
||||
/>
|
||||
<$action-navigate $to=<<shortcutConfigNotMac>>/>
|
||||
|
||||
\end
|
||||
|
||||
\define clone-bold()
|
||||
<$action-createtiddler $basetitle=<<tempBold>>
|
||||
$template="$:/core/ui/EditorToolbar/bold"
|
||||
$overwrite="yes"
|
||||
icon="$:/core/images/spiral"
|
||||
shortcuts="((temp-bold))"
|
||||
condition-disabled="[[$(tempBoldDisabled)$]get[state-disabled]else[no]]"
|
||||
/>
|
||||
<$action-sendmessage $message="tm-edit-tiddler" $param=<<tempBold>>/>
|
||||
\end
|
||||
|
||||
\define clone-button-bold()
|
||||
<$button actions=<<clone-bold>> >Create a Temporary Bold Button</$button>
|
||||
\end
|
||||
|
||||
\define toggle-bold()
|
||||
<$action-listops $tiddler=<<tempBoldDisabled>> $field="state-disabled" $subfilter="+[toggle[yes],[no]]" />
|
||||
\end
|
||||
|
||||
<!-- $vars is needed don't remove it! -->
|
||||
<$vars tempBold="$:/temp/bold" tempBoldDisabled="$:/temp/bold/disabled" shortcutInfo="$:/config/ShortcutInfo/temp-bold" shortcutConfigMac="$:/config/shortcuts-mac/temp-bold" shortcutConfigNotMac="$:/config/shortcuts-not-mac/temp-bold">
|
||||
|
||||
!! Create a New Toolbar Button
|
||||
|
||||
The easiest way to create new editor toolbar button is to clone and open one.
|
||||
|
||||
><<clone-button-bold>>
|
||||
|
||||
This tiddler contains all the necessary elements that are important for toolbar buttons.
|
||||
|
||||
<<<
|
||||
|
||||
; text
|
||||
: We don't discuss the text field details in this howto
|
||||
|
||||
; caption
|
||||
: The caption field is used to display the shortcut name in the $:/ControlPanel : Keyboard Shortcuts tab
|
||||
|
||||
; condition
|
||||
: A filter, that defines the button visibility state
|
||||
|
||||
; condition-disabled <<.from-version "5.1.23">>
|
||||
: A ''filter'', that allows us to define the "disabled" attribute for buttons. eg: <<disabledFilterExample>>
|
||||
: This condition ''must'' return "no", if the "state tiddler" or "state field" doesn't exist! So there has to be a `else[no]` element in the filter.
|
||||
|
||||
; description
|
||||
: Is used as the button tooltip
|
||||
|
||||
; icon
|
||||
: Assigns the button icon. We use `$:/core/images/spiral` {{$:/core/images/spiral}} here.
|
||||
|
||||
; shortcuts
|
||||
: This is the [[Keyboard Shortcut Descriptor]] eg: `((temp-bold))`
|
||||
|
||||
<<<
|
||||
|
||||
!! Disabled State
|
||||
|
||||
You can use any "state tiddler" to define the button disabled state. It's important, that the ''condition-disabled'' field is a ''filter''. For our example we use the `state-disabled` field from tiddler: <<tempBoldDisabled>>
|
||||
|
||||
The easiest way to test filters is with the $:/AdvancedSearch : Filter tab
|
||||
|
||||
> The temporary "bold button" is disabled: ''"{{{ [<tempBoldDisabled>get[state-disabled]else[no]] }}}"'' ... You can see the button in the editor toolbar if you edit any tiddler!
|
||||
|
||||
> <$button actions=<<toggle-bold>>>Toggle Temporary Bold Button Visisbility</$button>
|
||||
|
||||
!! Create Keyboard Shortcuts for New Button
|
||||
|
||||
For our ~HowTo we use the ''Keyboard Shortcut Descriptor'': `((temp-bold))`
|
||||
|
||||
To create a valid shortcut configuration we need 2 tiddlers:
|
||||
|
||||
>[[$:/config/ShortcutInfo/|$:/config/ShortcutInfo/temp-bold]]''temp-bold'' .. and
|
||||
>[[$:/config/shortcuts/|$:/config/shortcuts/temp-bold]]''temp-bold''
|
||||
|
||||
> <$button actions=<<create-shortcut-tiddlers>>>Create Shortcut Tiddlers</$button>
|
||||
|
||||
!!
|
||||
|
||||
!! Clean up the Configuration Tiddlers
|
||||
|
||||
If you don't need the config tiddlers anymore you can
|
||||
|
||||
><$button actions=<<remove-shortcuts>>>Remove the Shortcut Configuration</$button>
|
||||
|
||||
|
||||
</$vars><!-- needed don't remove! -->
|
@ -1,5 +1,6 @@
|
||||
|
||||
caption: unusedtitle
|
||||
created: 20210104143546885
|
||||
modified: 20210427184035684
|
||||
tags: Macros [[Core Macros]]
|
||||
title: unusedtitle Macro
|
||||
type: text/vnd.tiddlywiki
|
||||
@ -10,7 +11,30 @@ It uses the same method as the create new tiddler button, a number is appended t
|
||||
|
||||
!! Parameters
|
||||
|
||||
;baseName
|
||||
: A string specifying the desired base name, defaulting to `New Tiddler`
|
||||
; baseName
|
||||
: A string specifying the desired base name, defaulting to `New Tiddler`. <br>The default setting can be adjusted in the $:/ControlPanel '': Info : Basics - tab.''
|
||||
|
||||
<<.macro-examples "unusedtitle">>
|
||||
; separator
|
||||
: <<.from-version "5.1.24">> An ''optional'' string specifying the separator between baseName and the unique number. eg: `separator:"-"`. Defaults to a space: `" "`. If you need an empty separator use the ''template''!
|
||||
|
||||
; template
|
||||
: <<.from-version "5.1.24">> A ''optional'' template string can be used to allow you maximum flexibility. If the template string is used, there will always be a counter value.
|
||||
|
||||
!! Template String
|
||||
|
||||
; `$basename$`
|
||||
: This variable will be replaced by the content of the ''baseName'' parameter
|
||||
|
||||
; `$separator$`
|
||||
: This variable will be replaced by the ''separator'' parameter
|
||||
|
||||
;`$count$`
|
||||
: This variable will be createad automatically and is a counter starting with 0
|
||||
|
||||
;`$count:4$`
|
||||
: This variable will be createad automatically and starts at 0000
|
||||
: `:4` represents the number of digits
|
||||
|
||||
!! Examples
|
||||
|
||||
<<list-links "[prefix[unusedtitle Macro (E]!sort[]]">>
|
||||
|
@ -0,0 +1,51 @@
|
||||
created: 20210227212730299
|
||||
modified: 20210427184057456
|
||||
tags:
|
||||
title: unusedtitle Macro (Examples 1)
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
\define testCreate()
|
||||
<$action-createtiddler $basetitle=<<unusedtitle template:"$count:2$-new">>/>
|
||||
\end
|
||||
|
||||
\define testCreate1()
|
||||
<$action-createtiddler $basetitle=<<unusedtitle baseName:"new" separator:"-" template:"$count:2$$separator$$basename$">>/>
|
||||
\end
|
||||
|
||||
\define testNew()
|
||||
<$action-sendmessage $message="tm-new-tiddler" title=<<unusedtitle baseName:"new" template:"$count:2$-$basename$">> />
|
||||
\end
|
||||
|
||||
```
|
||||
<<unusedtitle template:"$count:2$-new">>
|
||||
```
|
||||
|
||||
<$button actions=<<testCreate>> >
|
||||
<$action-setfield $tiddler="$:/state/tab/sidebar--595412856" text="$:/core/ui/SideBar/Recent"/>
|
||||
Create Tiddler
|
||||
</$button>
|
||||
|
||||
```
|
||||
<<unusedtitle baseName:"new" template:"$count:2$-$basename$">>
|
||||
```
|
||||
|
||||
<$button actions=<<testNew>>>
|
||||
<$action-setfield $tiddler="$:/state/tab/sidebar--595412856" text="$:/core/ui/SideBar/Recent"/>
|
||||
New Tiddler
|
||||
</$button>
|
||||
|
||||
```
|
||||
<<unusedtitle baseName:"new" separator:"-" template:"$count:2$$separator$$basename$">>
|
||||
```
|
||||
|
||||
<$button actions=<<testCreate1>>>
|
||||
<$action-setfield $tiddler="$:/state/tab/sidebar--595412856" text="$:/core/ui/SideBar/Recent"/>
|
||||
Create Tiddler
|
||||
</$button>
|
||||
|
||||
---
|
||||
|
||||
<details>
|
||||
<summary>Show the code</summary>
|
||||
<pre><code><$view><pre><code>
|
||||
</details>
|
@ -1,7 +1,16 @@
|
||||
created: 20210104143940715
|
||||
modified: 20210228141241657
|
||||
tags: [[unusedtitle Macro]] [[Macro Examples]]
|
||||
title: unusedtitle Macro (Examples)
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<$macrocall $name=".example" n="1" eg="""<<unusedtitle>>"""/>
|
||||
<$macrocall $name=".example" n="2" eg="""<<unusedtitle AnotherBase>>"""/>
|
||||
<$macrocall $name=".example" n="3" eg="""<<unusedtitle TiddlyWiki>>"""/>
|
||||
''The following example works best if there is an open tiddler in draft mode, or there is a tiddler named "New Tiddler".'' So you can see the automatic numbering.
|
||||
<$macrocall $name=".example" n="2" eg="""<<unusedtitle separator:"-">>"""/>
|
||||
<$macrocall $name=".example" n="3" eg="""<<unusedtitle baseName:"anotherBase">>"""/>
|
||||
<$macrocall $name=".example" n="4" eg="""<<unusedtitle baseName:"About" separator:"-">>"""/>
|
||||
<$macrocall $name=".example" n="5" eg="""<<unusedtitle template:"$count:2$-test">>"""/>
|
||||
|
||||
---
|
||||
|
||||
Working buttons can be found at: [[unusedtitle Macro (Examples 1)]]. You'll have to examine the code to see, what's going on.
|
@ -1,5 +1,5 @@
|
||||
created: 20181002112106875
|
||||
modified: 20181002124355314
|
||||
modified: 20210418100750769
|
||||
tags: [[WebServer API]]
|
||||
title: WebServer API: Delete Tiddler
|
||||
type: text/vnd.tiddlywiki
|
||||
@ -14,6 +14,10 @@ Parameters:
|
||||
|
||||
* ''title'' - URI encoded title of the tiddler to delete
|
||||
|
||||
Headers:
|
||||
|
||||
* ''x-requested-with'' - must be set to `TiddlyWiki` in order for the request to succeed, unless [[WebServer Parameter: csrf-disable]] is set to `yes`
|
||||
|
||||
Response:
|
||||
|
||||
* 204 No Content
|
@ -1,5 +1,5 @@
|
||||
created: 20181002131341062
|
||||
modified: 20181002131556452
|
||||
modified: 20210418100750769
|
||||
tags: [[WebServer API]]
|
||||
title: WebServer API: Put Tiddler
|
||||
type: text/vnd.tiddlywiki
|
||||
@ -16,6 +16,10 @@ Parameters:
|
||||
|
||||
* ''title'' - URI encoded title of the tiddler to save
|
||||
|
||||
Headers:
|
||||
|
||||
* ''x-requested-with'' - must be set to `TiddlyWiki` in order for the request to succeed, unless [[WebServer Parameter: csrf-disable]] is set to `yes`
|
||||
|
||||
Response:
|
||||
|
||||
* 204 No Content
|
||||
|
@ -1,6 +1,6 @@
|
||||
caption: action-popup
|
||||
created: 20200303114556528
|
||||
modified: 20200421221304177
|
||||
modified: 20210501203451387
|
||||
tags: Widgets ActionWidgets
|
||||
title: ActionPopupWidget
|
||||
type: text/vnd.tiddlywiki
|
||||
@ -16,9 +16,12 @@ The ''action-popup'' widget is invisible. Any content within it is ignored.
|
||||
|!Attribute |!Description |
|
||||
|$state |The title of the state tiddler for the popup |
|
||||
|$coords |Optional coordinates for the handle to which popup is positioned (in the format `(x,y,w,h)`) |
|
||||
|$floating |<<.from-version "5.1.24">> Optional. Defaults to `no`. Set to `yes` to create a popup that must be closed explicitly. |
|
||||
|
||||
<<.from-version "5.1.23">> If the ''$coords'' attribute is missing or empty then all popups are cancelled.
|
||||
|
||||
<<.tip "Delete the state tiddler for a floating popup to close it.">>
|
||||
|
||||
! Examples
|
||||
|
||||
Here is an example of button that triggers the "more" button in the sidebar "Tools" tab. You may need to scroll to see the popup
|
||||
|
@ -1,6 +1,6 @@
|
||||
caption: dropzone
|
||||
created: 20131024141900000
|
||||
modified: 20200403103224328
|
||||
modified: 20210519154948743
|
||||
tags: Widgets
|
||||
title: DropzoneWidget
|
||||
type: text/vnd.tiddlywiki
|
||||
@ -16,9 +16,14 @@ It sends a [[WidgetMessage: tm-import-tiddlers]] carrying a JSON representation
|
||||
|!Attribute |!Description |
|
||||
|deserializer |<<.from-version "5.1.15">> Optional name of deserializer to be used (by default the deserializer is derived from the file extension) |
|
||||
|enable |<<.from-version "5.1.22">> Optional value "no" to disable the dropzone functionality (defaults to "yes") |
|
||||
|class |<<.from-version "5.1.22">> Optional CSS class to be assigned to the dropzone (defaults to "tc-drag-over") |
|
||||
|class |<<.from-version "5.1.22">> Optional CSS class to be assigned to the DOM node created by the dropzone (defaults to "tc-dropzone") |
|
||||
|autoOpenOnImport |<<.from-version "5.1.23">> Optional value "no" or "yes" that can override tv-auto-open-on-import |
|
||||
|importTitle|<<.from-version "5.1.23">> optional tiddler title to use for import process instead of ~$:/Import |
|
||||
|importTitle|<<.from-version "5.1.23">> Optional tiddler title to use for import process instead of ~$:/Import |
|
||||
|actions|<<.from-version "5.1.24">> Optional actions string to be invoked after the `tm-import-tiddlers` message has been sent. The variable `importTitle` provides the title of the tiddler used for the import process. |
|
||||
|contentTypesFilter |<<.from-version "5.1.24">> Optional filter that specifies the [[content types|ContentType]] accepted by the dropzone. |
|
||||
|filesOnly|<<.from-version "5.1.24">> Optional. When set to "yes", the dropzone only accepts files and not string data. Defaults to "no" |
|
||||
|
||||
<<.tip """Use the `prefix` filter operator to easily accept multiple related content types. For example this filter will accept all image content types: `[prefix[image/]]`""">>
|
||||
|
||||
The list of available deserializers can be inspected by executing `Object.keys($tw.Wiki.tiddlerDeserializerModules).sort().join("\n")` in the browser JavaScript console.
|
||||
|
||||
@ -26,7 +31,7 @@ The dropzone widget displays any contained content within the dropzone.
|
||||
|
||||
! Display
|
||||
|
||||
The dropzone widget creates an HTML `<div class="tc-dropzone">` to contain its content. During a drag operation the class `tc-dragover` is added. CSS is used to provide user feedback.
|
||||
The dropzone widget creates an HTML `<div class="tc-dropzone">` to contain its content. During a drag operation the class `tc-dragover` is added. CSS is used to provide user feedback. For custom styling of this state where a drag is in progress, specify a custom class name with the `class` attribute and use CSS with the selector `.myclass.tc-dragover`.
|
||||
|
||||
! Data types supported
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
caption: edit-text
|
||||
created: 20131024141900000
|
||||
modified: 20201130184701532
|
||||
modified: 20210519154352055
|
||||
tags: Widgets
|
||||
title: EditTextWidget
|
||||
type: text/vnd.tiddlywiki
|
||||
@ -36,6 +36,7 @@ The content of the `<$edit-text>` widget is ignored.
|
||||
|inputActions |<<.from-version 5.1.23>> Optional actions that are triggered every time an input event occurs within the input field or textarea |
|
||||
|refreshTitle |<<.from-version 5.1.23>> An optional tiddler title that makes the input field update whenever the specified tiddler changes |
|
||||
|disabled|<<.from-version "5.1.23">> Optional, disables the text input if set to "yes". Defaults to "no"|
|
||||
|fileDrop|<<.from-version "5.1.24">> Optional. When set to "yes" allows dropping or pasting images into the editor to import them. Defaults to "no"|
|
||||
|
||||
! Notes
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
caption: list
|
||||
created: 20131024141900000
|
||||
modified: 20190608162410684
|
||||
modified: 20210416175333981
|
||||
tags: Widgets Lists
|
||||
title: ListWidget
|
||||
type: text/vnd.tiddlywiki
|
||||
@ -82,10 +82,43 @@ The action of the list widget depends on the results of the filter combined with
|
||||
|template |The title of a template tiddler for transcluding each tiddler in the list. When no template is specified, the body of the ListWidget serves as the item template. With no body, a simple link to the tiddler is returned. |
|
||||
|editTemplate |An alternative template to use for [[DraftTiddlers|DraftMechanism]] in edit mode |
|
||||
|variable |The name for a [[variable|Variables]] in which the title of each listed tiddler is stored. Defaults to ''currentTiddler'' |
|
||||
|counter |<<.from-version "5.1.24">> Optional name for a [[variable|Variables]] in which the 1-based numeric index of each listed tiddler is stored (see below) |
|
||||
|emptyMessage |Message to be displayed when the list is empty |
|
||||
|storyview |Optional name of module responsible for animating/processing the list |
|
||||
|history |The title of the tiddler containing the navigation history |
|
||||
|
||||
!! `counter` attribute
|
||||
|
||||
The optional `counter` attribute specifies the name of a variable to hold the 1-based numeric index of the current item in the list.
|
||||
|
||||
Two additional variables are also set to indicate the first and last items in the list:
|
||||
|
||||
* `<counter-variable-name>-first` is set to `yes` for the first entry in the list, `no` for the others
|
||||
* `<counter-variable-name>-last` is set to `yes` for the last entry in the list, `no` for the others
|
||||
|
||||
For example:
|
||||
|
||||
|
||||
```
|
||||
<$list filter="[tag[About]sort[title]]" counter="counter">
|
||||
<div>
|
||||
<<counter>>: ''<$text text=<<currentTiddler>>/>'' (is first: <<counter-first>>, is last: <<counter-last>>)
|
||||
</div>
|
||||
</$list>
|
||||
```
|
||||
|
||||
Displays as:
|
||||
|
||||
<<<
|
||||
<$list filter="[tag[About]sort[title]]" counter="counter">
|
||||
<div>
|
||||
<<counter>>: ''<$text text=<<currentTiddler>>/>'' (is first: <<counter-first>>, is last: <<counter-last>>)
|
||||
</div>
|
||||
</$list>
|
||||
<<<
|
||||
|
||||
Note that using the `counter` attribute degrades the performance of the list widget because it prevents the optimisation of refreshes by moving list items around instead of rerendering them.
|
||||
|
||||
!! Edit mode
|
||||
|
||||
The `<$list>` widget can optionally render draft tiddlers through a different template to handle editing, see DraftMechanism.
|
||||
|
@ -25,7 +25,7 @@ The message catcher widget
|
||||
|!Variables |!Description |
|
||||
|`event-*` |All string-based properties of the `event` object, with the names prefixed with `event-` |
|
||||
|`event-paramObject-*` |All string-based properties of the `event.paramObject` object, with the names prefixed with `event-paramObject-` |
|
||||
|`modifier` |For messages that originated with browser events, the modifier keys that were pressed when the event was fired. The possible modifiers are ''norma'' (no modifiers), ''ctrl'', ''ctrl-alt'', ''ctrl-shift'', ''alt'', ''alt-shift'', ''shift'' and ''ctrl-alt-shift'' |
|
||||
|`modifier` |For messages that originated with browser events, the modifier keys that were pressed when the event was fired. The possible modifiers are ''normal'' (no modifiers), ''ctrl'', ''ctrl-alt'', ''ctrl-shift'', ''alt'', ''alt-shift'', ''shift'' and ''ctrl-alt-shift'' |
|
||||
|
||||
! Example
|
||||
|
||||
@ -39,4 +39,4 @@ The message catcher widget
|
||||
Click on [[this link]] to fire an action. See the browser JavaScript console for the output
|
||||
|
||||
</$messagecatcher>
|
||||
"""/>
|
||||
"""/>
|
||||
|
@ -1,6 +1,6 @@
|
||||
caption: Images
|
||||
created: 20131205160221762
|
||||
modified: 20160617100358365
|
||||
modified: 20210519160846733
|
||||
tags: WikiText [[Working with TiddlyWiki]]
|
||||
title: Images in WikiText
|
||||
type: text/vnd.tiddlywiki
|
||||
@ -64,3 +64,5 @@ Renders as:
|
||||
|
||||
Use the <<.button import>> button (under the <<.sidebar-tab Tools>> tab in the sidebar), or drag and drop.
|
||||
See [[ImportingTiddlers]] for details.
|
||||
|
||||
<<.from-version "5.1.24">> You can also import images by dropping or pasting images into the tiddler editor.
|
||||
|
@ -24,7 +24,6 @@ Encryption/RepeatPassword: كرر/ي كلمة السر
|
||||
Encryption/SetPassword: ضبط كلمة السر
|
||||
Encryption/Username: اسم المستخدم
|
||||
Error/Caption: خطأ
|
||||
Error/EditConflict: تم تغيير الملف على الخادم
|
||||
Error/Filter: خطأ في التصفية
|
||||
Error/FilterSyntax: خطأ في بناء الجملة في تعبير عامل التصفية
|
||||
Error/IsFilterOperator: خطأ في التصفية: معامل غير معروف لعامل التصفية 'is'
|
||||
@ -32,6 +31,7 @@ Error/IsFilterOperator: خطأ في التصفية: معامل غير معروف
|
||||
Error/LoadingPluginLibrary: خطأ في تحميل مكتبة المكونات الإضافية
|
||||
|
||||
Error/NetworkErrorAlert: `<h2>''خطأ في الشبكة''</h2> يبدو أن الاتصال بالخادم قد انقطع. قد يشير هذا إلى وجود مشكلة في اتصال الشبكة. يرجى محاولة استعادة اتصال الشبكة قبل المتابعة. <br> <br> '' ستتم مزامنة أي تغييرات غير محفوظة تلقائيًا عند استعادة الاتصال ''.
|
||||
Error/PutEditConflict: تم تغيير الملف على الخادم
|
||||
Error/WhileSaving: حدث خطأ أثناء الحفظ
|
||||
|
||||
InternalJavaScriptError/Hint: حسنا، هذا أمر محرج. من المستحسن إعادة تشغيل تدلي ويكي عن طريق إنعاش المتصفح الخاص بك
|
||||
|
@ -22,12 +22,12 @@ Encryption/RepeatPassword: Repetiu la contrasenya
|
||||
Encryption/SetPassword: Indiqueu la contrasenya
|
||||
Encryption/Username: Usuari
|
||||
Error/Caption: S'ha produït un error
|
||||
Error/EditConflict: El fitxer ha canviat al servidor
|
||||
Error/Filter: S'ha produït un error del filtre
|
||||
Error/FilterSyntax: S'ha produït un error de sintaxi en l'expressió del filtre
|
||||
Error/IsFilterOperator: S'ha produït un error del filtre: operant desconegut per a l’operador de filtre "is"
|
||||
Error/LoadingPluginLibrary: S'ha produït un error en carregar la biblioteca del connector
|
||||
Error/NetworkErrorAlert: `<h2>''Error de la xarxa''</h2>Sembla que s'ha perdut la connexió amb el servidor. Això pot indicar un problema amb la vostra connexió de la xarxa. Intenteu restaurar la connectivitat de xarxa abans de continuar.<br><br>' Qualsevol canvi no guardat es sincronitzarà automàticament quan es restableixi la connectivitat''.'
|
||||
Error/PutEditConflict: El fitxer ha canviat al servidor
|
||||
Error/RecursiveTransclusion: S'ha produït un error de transclusió recursiva en el widget de transclusió
|
||||
Error/RetrievingSkinny: S'ha produït un error en recuperar la llista de tiddler parcials
|
||||
Error/SavingToTWEdit: S'ha produït un error en desar a TWEdit
|
||||
|
@ -31,5 +31,6 @@ Mögliche Parameter:
|
||||
* ''tls-key'' - Pfad zur "TLS key" Datei (relativ zum Wiki Verzeichnis)
|
||||
* ''debug-level'' - "debug" bewikt eine detailierte Anzeige der HTTP Anfrage-Parameter. (Standard: "none")
|
||||
* ''gzip'' - Wenn auf "yes" gesetzt, dann wird gzip Kompression aktiviert. (Standard: "no")
|
||||
* ''use-browser-cache'' - Ist dieser Parameter auf "yes" gesetzt kann der Browser Inhalte zwischenspeichern um Übertragungsbandbreite zu sparen. (Standard: "no")
|
||||
|
||||
Für weitere Sicherheitshinweise und Informationen für die Verwendung in lokalen Netzwerken siehe: WebServer auf TiddlyWiki.com
|
||||
|
@ -24,7 +24,6 @@ Encryption/RepeatPassword: Passwort wiederholen
|
||||
Encryption/PasswordNoMatch: Passwörter stimmen nicht überein
|
||||
Encryption/SetPassword: Passwort setzen
|
||||
Error/Caption: Fehler
|
||||
Error/EditConflict: Datei auf Server verändert
|
||||
Error/Filter: Filter Fehler
|
||||
Error/FilterSyntax: Syntax Fehler im Filter-Ausdruck
|
||||
Error/FilterRunPrefix: Filter Fehler: Unbekanntes Prefix für Filter lauf
|
||||
@ -32,6 +31,7 @@ Error/IsFilterOperator: Filter Fehler: Unbekannter Operand für den 'is' Filter
|
||||
Error/FormatFilterOperator: Filter Fehler: Unbekannter Operand für den 'format' Filter Operator
|
||||
Error/LoadingPluginLibrary: Fehler beim Laden der "plugin library"
|
||||
Error/NetworkErrorAlert: `<h2>''Netzwerk Fehler''</h2>Es scheint, die Verbindung zum Server ist ausgefallen. Das weist auf Probleme mit der Netzwerkverbindung hin. Bitte versuchen Sie die Verbingung wider herzustellen, bevor Sie weitermachen.<br><br>''Nicht gespeicherte Änderungen werden automatich synchronisiert, sobald die Verbindung wider hergestellt ist.
|
||||
Error/PutEditConflict: Datei auf Server verändert
|
||||
Error/RecursiveTransclusion: Recursive Transclusion: Fehler im "transclude widget"
|
||||
Error/RetrievingSkinny: Fehler beim Empfangen einer "skinny" Tiddler Liste
|
||||
Error/SavingToTWEdit: Fehler beim Speichern mit "TWEdit"
|
||||
|
@ -22,11 +22,11 @@ Encryption/RepeatPassword: Επαναλάβατε το συνθηματικό
|
||||
Encryption/SetPassword: Ορίστε το συνθηματικό
|
||||
Encryption/Username: Όνομα χρήστη
|
||||
Error/Caption: Σφάλμα
|
||||
Error/EditConflict: Το αρχείο στον εξυπηρετητή είναι διαφορετικό
|
||||
Error/Filter: Σφάλμα φίλτρου
|
||||
Error/FilterSyntax: Συντακτικό σφάλμα στην έκφραση του φίλτρου
|
||||
Error/IsFilterOperator: Σφάλμα φίλτρου: Άγνωστος τελεστέος για τον τελεστή φίλτρου 'is'
|
||||
Error/LoadingPluginLibrary: Σφάλμα κατά την φόρτωση της βιβλιοθήκης του πρόσθετου
|
||||
Error/PutEditConflict: Το αρχείο στον εξυπηρετητή είναι διαφορετικό
|
||||
Error/RecursiveTransclusion: Σφάλμα αναδρομής σε transclusion στο transclude widget
|
||||
Error/RetrievingSkinny: Σφάλμα κατά την ανάκληση της skinny tiddler λίστας
|
||||
Error/SavingToTWEdit: Σφάλμα κατά την αποθήκευση στο TWEdit
|
||||
|
@ -22,11 +22,11 @@ Encryption/RepeatPassword: تکرار رمز
|
||||
Encryption/SetPassword: تعیین رمز
|
||||
Encryption/Username: نام کاربری
|
||||
Error/Caption: خطا
|
||||
Error/EditConflict: فایل در سرور عوض شد
|
||||
Error/Filter: خطای فیلتر
|
||||
Error/FilterSyntax: در نحوهی بیان فیلتر خطای نحوی وجود داشت
|
||||
Error/IsFilterOperator: خطای فیلتر: عملکرد ناشناختهای برای عملگر 'is' مشخص شده
|
||||
Error/LoadingPluginLibrary: خطا در بارگزاری کتابخانه افزونه
|
||||
Error/PutEditConflict: فایل در سرور عوض شد
|
||||
Error/RecursiveTransclusion: Recursive transclusion error in transclude widget
|
||||
Error/RetrievingSkinny: طا در دریافت لیستهای تیدلر لاغر
|
||||
Error/SavingToTWEdit: خطا در ذخیره در TWEdit
|
||||
|
@ -23,7 +23,6 @@ Encryption/RepeatPassword: Répéter le mot de passe
|
||||
Encryption/PasswordNoMatch: Les mots de passe ne correspondent pas
|
||||
Encryption/SetPassword: Définir ce mot de passe
|
||||
Error/Caption: Erreur
|
||||
Error/EditConflict: Le fichier a changé sur le serveur
|
||||
Error/Filter: Erreur de filtre
|
||||
Error/FilterSyntax: Erreur de syntaxe dans l'expression du filtre
|
||||
Error/FilterRunPrefix: Erreur de filtre : Préfixe de run inconnu pour le filtre
|
||||
@ -31,6 +30,7 @@ Error/IsFilterOperator: Erreur de filtre : Opérande inconnu pour l'opérateur d
|
||||
Error/FormatFilterOperator: Erreur de filtre : Suffixe inconnu pour l'opérateur de filtre 'format'
|
||||
Error/LoadingPluginLibrary: Erreur lors du chargement de la bibliothèque de plugins
|
||||
Error/NetworkErrorAlert: `<h2>''Erreur Réseau''</h2>Il semble que la connexion au serveur soit perdue. Cela peut indiquer un problème avec votre connexion réseau. Essayez de rétablir la connectivité du réseau avant de continuer.<br><br>''Toute modification non enregistrée sera automatiquement synchronisée lorsque la connectivité sera rétablie''.`
|
||||
Error/PutEditConflict: Le fichier a changé sur le serveur
|
||||
Error/RecursiveTransclusion: Erreur dans le widget //transclude// : transclusion récursive
|
||||
Error/RetrievingSkinny: Erreur pendant la récupération de la liste des tiddlers partiels
|
||||
Error/SavingToTWEdit: Erreur lors de l'enregistrement vers TWEdit
|
||||
|
@ -23,7 +23,6 @@ Encryption/RepeatPassword: Herhaal wachtwoord
|
||||
Encryption/SetPassword: Vul wachtwoord in
|
||||
Encryption/Username: Gebruikersnaam
|
||||
Error/Caption: Fout
|
||||
Error/EditConflict: Bestand gewijzigd op server
|
||||
Error/Filter: Filterfout
|
||||
Error/FilterRunPrefix: Filterfout: Onbekend voorvoegsel voor filter 'run'
|
||||
Error/FilterSyntax: Syntaxfout in filter expressie
|
||||
@ -31,6 +30,7 @@ Error/FormatFilterOperator: Filterfout: Onbekend achtervoegsel voor de 'format'
|
||||
Error/IsFilterOperator: Filterfout: Onbekende operand voor het 'is' filter
|
||||
Error/LoadingPluginLibrary: Fout bij laden van de pluginbibliotheek
|
||||
Error/NetworkErrorAlert: `<h2>''Network fout''</h2>De verbinding met de server lijkt verbroken. Mogelijk een probleem met de netwerkverbinding. Herstel de netwerkverbinding voordat verder wordt gegaan.<br><br>''Niet opgeslagen veranderingen worden gesynchroniseerd als de verbinding hersteld is''.`
|
||||
Error/PutEditConflict: Bestand gewijzigd op server
|
||||
Error/RecursiveTransclusion: Recursieve transclusiefout in 'transclude' widget
|
||||
Error/RetrievingSkinny: Fout bij ophalen van de 'skinny' tiddlerlijst
|
||||
Error/SavingToTWEdit: Fout bij opslaan naar TWEdit
|
||||
|
@ -23,11 +23,11 @@ Encryption/RepeatPassword: Repetir palavra passe
|
||||
Encryption/SetPassword: Definir palavra passe
|
||||
Encryption/Username: Nome de utilizador
|
||||
Error/Caption: Erro
|
||||
Error/EditConflict: File changed on server
|
||||
Error/Filter: Erro de filtro
|
||||
Error/FilterSyntax: Erro de sintaxe na expressão do filtro
|
||||
Error/IsFilterOperator: Erro de Filtro: Operando desconhecido para o operador de filtro 'is'
|
||||
Error/LoadingPluginLibrary: Erro ao carregar a biblioteca de extensões
|
||||
Error/PutEditConflict: File changed on server
|
||||
Error/RecursiveTransclusion: Erro de transclusão recursiva na widget de transclusão
|
||||
Error/RetrievingSkinny: Erro ao obter a lista simples de tiddlers
|
||||
Error/SavingToTWEdit: Erro ao gravar em TWEdit
|
||||
|
@ -22,11 +22,11 @@ Encryption/RepeatPassword: Ponovite geslo
|
||||
Encryption/SetPassword: Nastavite geslo
|
||||
Encryption/Username: Uporabniško ime
|
||||
Error/Caption: Napaka
|
||||
Error/EditConflict: Datoteka je spremenjena na strežniku
|
||||
Error/Filter: Filter napaka
|
||||
Error/FilterSyntax: Sintaktična napaka v izrazu filtra
|
||||
Error/IsFilterOperator: Filter napaka: neznan operand za 'is' operator filtra
|
||||
Error/LoadingPluginLibrary: Napaka pri nalaganju knjižnice vtičnikov
|
||||
Error/PutEditConflict: Datoteka je spremenjena na strežniku
|
||||
Error/RecursiveTransclusion: Rekurzivna napaka transkluzije v "transclude widget"
|
||||
Error/RetrievingSkinny: Napaka pri pridobivanju "skinny" seznama tiddlerjev
|
||||
Error/SavingToTWEdit: Napaka pri shranjevanju v TWEdit
|
||||
|
@ -124,12 +124,12 @@ Saving/TiddlySpot/BackupDir: 备份文件夹
|
||||
Saving/TiddlySpot/Backups: 备份
|
||||
Saving/TiddlySpot/Caption: ~TiddlySpot 保存模块
|
||||
Saving/TiddlySpot/ControlPanel: ~TiddlySpot 控制台
|
||||
Saving/TiddlySpot/Description: 这些设置只适用于保存到 http://tiddlyspot.com 或兼容的远程服务器时。
|
||||
Saving/TiddlySpot/Description: 这些设置只适用于保存到 [[TiddlySpot|http://tiddlyspot.com]]、[[TiddlyHost|https://tiddlyhost.com]],或兼容的远程服务器。有关 ~TiddlySpot 和 ~TiddlyHost 的保存设置信息,请参阅[[此处|https://github.com/simonbaird/tiddlyhost/wiki/TiddlySpot-Saver-configuration-for-Tiddlyhost-and-Tiddlyspot]]。
|
||||
Saving/TiddlySpot/Filename: 上传文件名
|
||||
Saving/TiddlySpot/Heading: ~TiddlySpot
|
||||
Saving/TiddlySpot/Hint: //默认之服务器网址 `http://<wikiname>.tiddlyspot.com/store.cgi`,可改为定制之服务器网址,例如 `http://example.com/store.php`。//
|
||||
Saving/TiddlySpot/Password: 密码
|
||||
Saving/TiddlySpot/ReadOnly: ~TiddlySpot 服务目前仅以唯读形式提供。相关最新详细信息,请参阅 http://tiddlyspot.com/ 。~TiddlySpot 保存模块仍可用于保存到兼容的服务器。
|
||||
Saving/TiddlySpot/ReadOnly: 请注意,[[TiddlySpot|http://tiddlyspot.com]] 不再允许创建新网站。对于新网站,您可以使用 [[TiddlyHost|https://tiddlyhost.com]],一个新的取代 ~TiddlySpot 的讬管服务 。
|
||||
Saving/TiddlySpot/ServerURL: 服务器网址
|
||||
Saving/TiddlySpot/UploadDir: 上传文件夹
|
||||
Saving/TiddlySpot/UserName: 用户
|
||||
|
@ -30,5 +30,6 @@ listen 命令使用[[命名的命令参数|NamedCommandParameters]]:
|
||||
* ''tls-key'' - TLS 密钥文件的路径名(相对于维基文件夹)
|
||||
* ''debug-level'' - 可选的调试级别;设置为 "debug" 来查看请求的详细信息;(默认为 "none")
|
||||
* ''gzip'' - 设为 "yes" 以启用某些 http 端点的 gzip 压缩 (默认为 "no")
|
||||
* ''use-browser-cache'' - 设置为 "yes" 允许浏览器缓存响应,以节省带宽(默认为 "no")
|
||||
|
||||
有关向整个本地网络开启实例的信息,以及可能的安全问题,请参阅 TiddlyWiki.com 的 WebServer 条目。
|
||||
|
@ -24,7 +24,6 @@ Encryption/RepeatPassword: 重复输入密码
|
||||
Encryption/PasswordNoMatch: 密码不匹配
|
||||
Encryption/SetPassword: 设定密码
|
||||
Error/Caption: 错误
|
||||
Error/EditConflict: 服务器上的文件已更改
|
||||
Error/Filter: 筛选器错误
|
||||
Error/FilterRunPrefix: 筛选器错误:筛选器 run 的未知首码
|
||||
Error/FilterSyntax: 筛选器运算式中的语法错误
|
||||
@ -32,6 +31,9 @@ Error/FormatFilterOperator: 筛选器错误:`format` 筛选器运算符的未
|
||||
Error/IsFilterOperator: 筛选器错误︰'is' 筛选器运算符的未知操作数
|
||||
Error/LoadingPluginLibrary: 加载插件程式库时,发生错误
|
||||
Error/NetworkErrorAlert: `<h2>''网络错误''</h2>与服务器的连缐似乎已中断。这可能表示您的网络连缐有问题。请尝试恢复网路连缐才能继续。<br><br>''恢复连缐时,所有未保存的更改,将自动同步''。`
|
||||
Error/PutEditConflict: 服务器上的文件已更改
|
||||
Error/PutForbidden: 没有权限
|
||||
Error/PutUnauthorized: 需要身分验证
|
||||
Error/RecursiveTransclusion: 于 transclude 小部件中的递回嵌入错误
|
||||
Error/RetrievingSkinny: 简要条目清单撷取错误
|
||||
Error/SavingToTWEdit: 保存到 TWEdit 时,发生错误
|
||||
|
@ -124,12 +124,12 @@ Saving/TiddlySpot/BackupDir: 備份資料夾
|
||||
Saving/TiddlySpot/Backups: 備份
|
||||
Saving/TiddlySpot/Caption: ~TiddlySpot 儲存模組
|
||||
Saving/TiddlySpot/ControlPanel: ~TiddlySpot 控制台
|
||||
Saving/TiddlySpot/Description: 這些設定只適用於儲存到 http://tiddlyspot.com 或相容的遠端伺服器時。
|
||||
Saving/TiddlySpot/Description: 這些設定只適用於儲存到 [[TiddlySpot|http://tiddlyspot.com]]、[[TiddlyHost|https://tiddlyhost.com]],或相容的遠端伺服器。有關 ~TiddlySpot 和 ~TiddlyHost 的儲存設定資訊,請參閱[[此處|https://github.com/simonbaird/tiddlyhost/wiki/TiddlySpot-Saver-configuration-for-Tiddlyhost-and-Tiddlyspot]]。
|
||||
Saving/TiddlySpot/Filename: 上傳檔名
|
||||
Saving/TiddlySpot/Heading: ~TiddlySpot
|
||||
Saving/TiddlySpot/Hint: //預設之伺服器網址 `http://<wikiname>.tiddlyspot.com/store.cgi`,可改為自訂之伺服器網址,例如 `http://example.com/store.php`。//
|
||||
Saving/TiddlySpot/Password: 密碼
|
||||
Saving/TiddlySpot/ReadOnly: ~TiddlySpot 服務目前僅以唯讀形式提供。相關最新詳細資訊,請參閱 http://tiddlyspot.com/ 。~TiddlySpot 儲存模組仍可用於儲存到相容的伺服器。
|
||||
Saving/TiddlySpot/ReadOnly: 請注意,[[TiddlySpot|http://tiddlyspot.com]] 不再允許建立新網站。對於新網站,您可以使用 [[TiddlyHost|https://tiddlyhost.com]],一個新的取代 ~TiddlySpot 的託管服務 。
|
||||
Saving/TiddlySpot/ServerURL: 伺服器網址
|
||||
Saving/TiddlySpot/UploadDir: 上傳資料夾
|
||||
Saving/TiddlySpot/UserName: 帳號
|
||||
|
@ -30,5 +30,6 @@ listen 命令使用[[命名的命令參數|NamedCommandParameters]]:
|
||||
* ''tls-key'' - TLS 密鑰檔案的路徑名(相對於維基資料夾)
|
||||
* ''debug-level'' - 可選的偵錯層級;設定為 "debug" 來檢視請求的詳細資訊;(預設為 "none")
|
||||
* ''gzip'' - 設為 "yes" 以啟用某些 http 端點的 gzip 壓縮 (預設為 "no")
|
||||
* ''use-browser-cache'' - 設定為 "yes" ,允許瀏覽器快取回應,以節省頻寬(預設值為 "no")
|
||||
|
||||
有關向整個本地網路開啟實例的資訊,以及可能的安全問題,請參閱 TiddlyWiki.com 的 WebServer 條目。
|
||||
|
@ -24,7 +24,6 @@ Encryption/RepeatPassword: 重複輸入密碼
|
||||
Encryption/PasswordNoMatch: 密碼不匹配
|
||||
Encryption/SetPassword: 設定密碼
|
||||
Error/Caption: 錯誤
|
||||
Error/EditConflict: 伺服器上的檔案已更改
|
||||
Error/Filter: 篩選器錯誤
|
||||
Error/FilterRunPrefix: 篩選器錯誤:篩選器 run 的未知首碼
|
||||
Error/FilterSyntax: 篩選器運算式中的語法錯誤
|
||||
@ -32,6 +31,9 @@ Error/FormatFilterOperator: 篩選器錯誤:`format` 篩選器運算子的未
|
||||
Error/IsFilterOperator: 篩選器錯誤︰'is' 篩選器運算子的未知運算元
|
||||
Error/LoadingPluginLibrary: 載入插件程式庫時,發生錯誤
|
||||
Error/NetworkErrorAlert: `<h2>''網路錯誤''</h2>與伺服器的連線似乎已中斷。這可能表示您的網路連線有問題。請嘗試恢復網路連線才能繼續。<br><br>''恢復連線時,所有未儲存的變更,將自動同步''。`
|
||||
Error/PutEditConflict: 伺服器上的檔案已更改
|
||||
Error/PutForbidden: 沒有權限
|
||||
Error/PutUnauthorized: 需要身份驗證
|
||||
Error/RecursiveTransclusion: 於 transclude 小工具中的遞迴嵌入錯誤
|
||||
Error/RetrievingSkinny: 簡要條目清單擷取錯誤
|
||||
Error/SavingToTWEdit: 儲存到 TWEdit 時,發生錯誤
|
||||
|
@ -39,7 +39,7 @@ exports["application/x-bibtex"] = function(text,fields) {
|
||||
"bibtex-entry-type": entry.entryType
|
||||
};
|
||||
$tw.utils.each(entry.entryTags,function(value,name) {
|
||||
fields["bibtex-" + name] = value;
|
||||
fields["bibtex-" + name.toLowerCase()] = value;
|
||||
});
|
||||
results.push(fields);
|
||||
});
|
||||
|
@ -124,8 +124,11 @@ function CodeMirrorEngine(options) {
|
||||
self.widget.invokeActionString(self.widget.editInputActions);
|
||||
}
|
||||
});
|
||||
|
||||
this.cm.on("drop",function(cm,event) {
|
||||
event.stopPropagation(); // Otherwise TW's dropzone widget sees the drop event
|
||||
if(!self.widget.isFileDropEnabled) {
|
||||
event.stopPropagation(); // Otherwise TW's dropzone widget sees the drop event
|
||||
}
|
||||
return false;
|
||||
});
|
||||
this.cm.on("keydown",function(cm,event) {
|
||||
@ -136,6 +139,32 @@ function CodeMirrorEngine(options) {
|
||||
$tw.popup.cancel(0);
|
||||
}
|
||||
});
|
||||
// Add drag and drop event listeners if fileDrop is enabled
|
||||
if(this.widget.isFileDropEnabled) {
|
||||
// If the drag event contains Files, prevent the default CodeMirror handling
|
||||
this.cm.on("dragenter",function(cm,event) {
|
||||
if($tw.utils.dragEventContainsFiles(event)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
this.cm.on("dragleave",function(cm,event) {
|
||||
event.preventDefault();
|
||||
});
|
||||
this.cm.on("dragover",function(cm,event) {
|
||||
if($tw.utils.dragEventContainsFiles(event)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
this.cm.on("drop",function(cm,event) {
|
||||
if($tw.utils.dragEventContainsFiles(event)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
this.cm.on("paste",function(cm,event) {
|
||||
self.widget.handlePasteEvent.call(self.widget,event);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -40,14 +40,17 @@ function debounce(callback) {
|
||||
}
|
||||
|
||||
function setupEvents(host) {
|
||||
var events = new EventSource(host + "events/plugins/tiddlywiki/tiddlyweb");
|
||||
var debouncedSync = debounce($tw.syncer.syncFromServer.bind($tw.syncer));
|
||||
events.addEventListener("change",debouncedSync);
|
||||
events.onerror = function() {
|
||||
events.close();
|
||||
setTimeout(function() {
|
||||
setupEvents(host);
|
||||
},$tw.syncer.errorRetryInterval);
|
||||
};
|
||||
if(window.EventSource) {
|
||||
var events = new EventSource(host + "events/plugins/tiddlywiki/tiddlyweb");
|
||||
var debouncedSync = debounce($tw.syncer.syncFromServer.bind($tw.syncer));
|
||||
events.addEventListener("change",debouncedSync);
|
||||
events.onerror = function() {
|
||||
events.close();
|
||||
setTimeout(function() {
|
||||
setupEvents(host);
|
||||
},$tw.syncer.errorRetryInterval);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
||||
|
@ -8,17 +8,17 @@ Placeholder for a more thorough refinement of Snow White
|
||||
*/
|
||||
|
||||
@font-face {
|
||||
font-family: "Arvo";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local("Arvo"), url(<<datauri "$:/themes/tiddlywiki/starlight/arvo.woff">>) format("woff");
|
||||
font-family: "Arvo";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local("Arvo"), url(<<datauri "$:/themes/tiddlywiki/starlight/arvo.woff">>) format("woff");
|
||||
}
|
||||
|
||||
html body, .tc-sidebar-scrollable-backdrop {
|
||||
font-family: "Arvo", "Times";
|
||||
background: url(<<datauri "$:/themes/tiddlywiki/starlight/ltbg.jpg">>);
|
||||
background: url(<<datauri "$:/themes/tiddlywiki/starlight/ltbg.jpg">>);
|
||||
}
|
||||
|
||||
.tc-page-controls svg {
|
||||
<<filter "drop-shadow(1px 1px 2px rgba(255,255,255,0.9))">>
|
||||
<<filter "drop-shadow(1px 1px 2px rgba(255,255,255,0.9))">>
|
||||
}
|
||||
|
@ -82,17 +82,17 @@ tags: [[$:/tags/Stylesheet]]
|
||||
}
|
||||
|
||||
html body.tc-body .tc-tiddler-frame .tc-tiddler-info {
|
||||
margin: 0 -13px 0 -13px;
|
||||
margin: 0 -13px 0 -13px;
|
||||
}
|
||||
|
||||
html body.tc-body .tc-tiddler-frame .tc-fold-banner {
|
||||
width: 13px;
|
||||
margin-left: -15px;
|
||||
width: 13px;
|
||||
margin-left: -15px;
|
||||
}
|
||||
|
||||
html body.tc-body .tc-tiddler-frame .tc-unfold-banner {
|
||||
margin-left: -13px;
|
||||
margin-top: -4px;
|
||||
margin-left: -13px;
|
||||
margin-top: -4px;
|
||||
}
|
||||
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user