Compare commits
40 Commits
button-wid
...
fail-ci-in
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fe17993dc | ||
|
|
4b56cb4298 | ||
|
|
902c7f55ba | ||
|
|
801e8e312c | ||
|
|
23a576b8bd | ||
|
|
6a52081d6b | ||
|
|
246751be1b | ||
|
|
4ebaba8e89 | ||
|
|
efaa8dd1e8 | ||
|
|
326ae61929 | ||
|
|
c185e373c5 | ||
|
|
2ffbfd84a5 | ||
|
|
faef02df7a | ||
|
|
c93d56667e | ||
|
|
3855a9f013 | ||
|
|
4d548580e6 | ||
|
|
9773dff1e3 | ||
|
|
c6604c0c56 | ||
|
|
e521ee2133 | ||
|
|
a7bd134c35 | ||
|
|
d3f5695601 | ||
|
|
efa4f34131 | ||
|
|
fffbedd6b9 | ||
|
|
ff1437e439 | ||
|
|
32966c9e91 | ||
|
|
96b0543351 | ||
|
|
b7562f0c7b | ||
|
|
4c9c85aec5 | ||
|
|
7726982d71 | ||
|
|
774058912d | ||
|
|
106e1c68df | ||
|
|
12f42ad62f | ||
|
|
66a8e2dbf2 | ||
|
|
327ecf8f66 | ||
|
|
35e45f3b90 | ||
|
|
93bc9e4309 | ||
|
|
23b75bbc5d | ||
|
|
68da654eb3 | ||
|
|
3fb71e2553 | ||
|
|
9ee1ef7e23 |
10
.github/workflows/ci.yml
vendored
@@ -5,7 +5,7 @@ on:
|
||||
- master
|
||||
- tiddlywiki-com
|
||||
env:
|
||||
NODE_VERSION: "12"
|
||||
NODE_VERSION: "18"
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -14,7 +14,13 @@ jobs:
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: "${{ env.NODE_VERSION }}"
|
||||
- run: "./bin/test.sh"
|
||||
- run: "./bin/ci-test.sh"
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
retention-days: 30
|
||||
build-prerelease:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/master'
|
||||
|
||||
4
.gitignore
vendored
@@ -5,4 +5,6 @@
|
||||
tmp/
|
||||
output/
|
||||
node_modules/
|
||||
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/playwright/.cache/
|
||||
|
||||
16
bin/ci-test.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
# test TiddlyWiki5 for tiddlywiki.com
|
||||
|
||||
npm install playwright @playwright/test
|
||||
npx playwright install chromium firefox --with-deps
|
||||
|
||||
node ./tiddlywiki.js \
|
||||
./editions/test \
|
||||
--verbose \
|
||||
--version \
|
||||
--rendertiddler $:/core/save/all test.html text/plain \
|
||||
--test \
|
||||
|| exit 1
|
||||
|
||||
npx playwright test
|
||||
@@ -18,16 +18,20 @@ Export our filter functions
|
||||
|
||||
exports.decodebase64 = function(source,operator,options) {
|
||||
var results = [];
|
||||
var binary = operator.suffixes && operator.suffixes.indexOf("binary") !== -1;
|
||||
var urlsafe = operator.suffixes && operator.suffixes.indexOf("urlsafe") !== -1;
|
||||
source(function(tiddler,title) {
|
||||
results.push($tw.utils.base64Decode(title));
|
||||
results.push($tw.utils.base64Decode(title,binary,urlsafe));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.encodebase64 = function(source,operator,options) {
|
||||
var results = [];
|
||||
var binary = operator.suffixes && operator.suffixes.indexOf("binary") !== -1;
|
||||
var urlsafe = operator.suffixes && operator.suffixes.indexOf("urlsafe") !== -1;
|
||||
source(function(tiddler,title) {
|
||||
results.push($tw.utils.base64Encode(title));
|
||||
results.push($tw.utils.base64Encode(title,binary,urlsafe));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -68,6 +68,54 @@ exports["jsontype"] = function(source,operator,options) {
|
||||
return results;
|
||||
};
|
||||
|
||||
exports["jsonset"] = function(source,operator,options) {
|
||||
var suffixes = operator.suffixes || [],
|
||||
type = suffixes[0] && suffixes[0][0],
|
||||
indexes = operator.operands.slice(0,-1),
|
||||
value = operator.operands[operator.operands.length - 1],
|
||||
results = [];
|
||||
if(operator.operands.length === 1 && operator.operands[0] === "") {
|
||||
value = undefined; // Prevents the value from being assigned
|
||||
}
|
||||
switch(type) {
|
||||
case "string":
|
||||
// Use value unchanged
|
||||
break;
|
||||
case "boolean":
|
||||
value = (value === "true" ? true : (value === "false" ? false : undefined));
|
||||
break;
|
||||
case "number":
|
||||
value = $tw.utils.parseNumber(value);
|
||||
break;
|
||||
case "array":
|
||||
indexes = operator.operands;
|
||||
value = [];
|
||||
break;
|
||||
case "object":
|
||||
indexes = operator.operands;
|
||||
value = {};
|
||||
break;
|
||||
case "null":
|
||||
indexes = operator.operands;
|
||||
value = null;
|
||||
break;
|
||||
case "json":
|
||||
value = $tw.utils.parseJSONSafe(value,function() {return undefined;});
|
||||
break;
|
||||
default:
|
||||
// Use value unchanged
|
||||
break;
|
||||
}
|
||||
source(function(tiddler,title) {
|
||||
var data = $tw.utils.parseJSONSafe(title,title);
|
||||
if(data) {
|
||||
data = setDataItem(data,indexes,value);
|
||||
results.push(JSON.stringify(data));
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
/*
|
||||
Given a JSON data structure and an array of index strings, return an array of the string representation of the values at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||
*/
|
||||
@@ -186,5 +234,34 @@ function getDataItem(data,indexes) {
|
||||
return item;
|
||||
}
|
||||
|
||||
/*
|
||||
Given a JSON data structure, an array of index strings and a value, return the data structure with the value added at the end of the index chain. If any of the index strings are invalid then the JSON data structure is returned unmodified. If the root item is targetted then a different data object will be returned
|
||||
*/
|
||||
function setDataItem(data,indexes,value) {
|
||||
// Ignore attempts to assign undefined
|
||||
if(value === undefined) {
|
||||
return data;
|
||||
}
|
||||
// Check for the root item
|
||||
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
||||
return value;
|
||||
}
|
||||
// Traverse the JSON data structure using the index chain
|
||||
var current = data;
|
||||
for(var i = 0; i < indexes.length - 1; i++) {
|
||||
var index = indexes[i];
|
||||
if($tw.utils.hop(current,index)) {
|
||||
current = current[index];
|
||||
} else {
|
||||
// Return the original JSON data structure if any of the index strings are invalid
|
||||
return data;
|
||||
}
|
||||
}
|
||||
// Add the value to the end of the index chain
|
||||
var lastIndex = indexes[indexes.length - 1];
|
||||
current[lastIndex] = value;
|
||||
return data;
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
@@ -58,6 +58,7 @@ Last entry/entries in list
|
||||
exports.last = function(source,operator,options) {
|
||||
var count = $tw.utils.getInt(operator.operand,1),
|
||||
results = [];
|
||||
if(count === 0) return results;
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
|
||||
@@ -52,7 +52,7 @@ exports.tag = function(source,operator,options) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
return $tw.browser ? results.reverse() : results;
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
120
core/modules/parsers/wikiparser/rules/conditional.js
Normal file
@@ -0,0 +1,120 @@
|
||||
/*\
|
||||
title: $:/core/modules/parsers/wikiparser/rules/conditional.js
|
||||
type: application/javascript
|
||||
module-type: wikirule
|
||||
|
||||
Conditional shortcut syntax
|
||||
|
||||
```
|
||||
This is a <% if [{something}] %>Elephant<% elseif [{else}] %>Pelican<% else %>Crocodile<% endif %>
|
||||
```
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.name = "conditional";
|
||||
exports.types = {inline: true, block: true};
|
||||
|
||||
exports.init = function(parser) {
|
||||
this.parser = parser;
|
||||
// Regexp to match
|
||||
this.matchRegExp = /\<\%\s*if\s+/mg;
|
||||
this.terminateIfRegExp = /\%\>/mg;
|
||||
};
|
||||
|
||||
exports.findNextMatch = function(startPos) {
|
||||
// Look for the next <% if shortcut
|
||||
this.matchRegExp.lastIndex = startPos;
|
||||
this.match = this.matchRegExp.exec(this.parser.source);
|
||||
// If not found then return no match
|
||||
if(!this.match) {
|
||||
return undefined;
|
||||
}
|
||||
// Check for the next %>
|
||||
this.terminateIfRegExp.lastIndex = this.match.index;
|
||||
this.terminateIfMatch = this.terminateIfRegExp.exec(this.parser.source);
|
||||
// If not found then return no match
|
||||
if(!this.terminateIfMatch) {
|
||||
return undefined;
|
||||
}
|
||||
// Return the position at which the construction was found
|
||||
return this.match.index;
|
||||
};
|
||||
|
||||
/*
|
||||
Parse the most recent match
|
||||
*/
|
||||
exports.parse = function() {
|
||||
// Get the filter condition
|
||||
var filterCondition = this.parser.source.substring(this.match.index + this.match[0].length,this.terminateIfMatch.index);
|
||||
// Advance the parser position to past the %>
|
||||
this.parser.pos = this.terminateIfMatch.index + this.terminateIfMatch[0].length;
|
||||
// Parse the if clause
|
||||
return this.parseIfClause(filterCondition);
|
||||
};
|
||||
|
||||
exports.parseIfClause = function(filterCondition) {
|
||||
// Create the list widget
|
||||
var listWidget = {
|
||||
type: "list",
|
||||
tag: "$list",
|
||||
isBlock: this.is.block,
|
||||
children: [
|
||||
{
|
||||
type: "list-template",
|
||||
tag: "$list-template"
|
||||
},
|
||||
{
|
||||
type: "list-empty",
|
||||
tag: "$list-empty"
|
||||
}
|
||||
]
|
||||
};
|
||||
$tw.utils.addAttributeToParseTreeNode(listWidget,"filter",filterCondition);
|
||||
$tw.utils.addAttributeToParseTreeNode(listWidget,"variable","condition");
|
||||
$tw.utils.addAttributeToParseTreeNode(listWidget,"limit","1");
|
||||
// Check for an immediately following double linebreak
|
||||
var hasLineBreak = !!$tw.utils.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/g);
|
||||
// Parse the body looking for else or endif
|
||||
var reEndString = "\\<\\%\\s*(endif)\\s*\\%\\>|\\<\\%\\s*(else)\\s*\\%\\>|\\<\\%\\s*(elseif)\\s+([\\s\\S]+?)\\%\\>",
|
||||
ex;
|
||||
if(hasLineBreak) {
|
||||
ex = this.parser.parseBlocksTerminatedExtended(reEndString);
|
||||
} else {
|
||||
var reEnd = new RegExp(reEndString,"mg");
|
||||
ex = this.parser.parseInlineRunTerminatedExtended(reEnd,{eatTerminator: true});
|
||||
}
|
||||
// Put the body into the list template
|
||||
listWidget.children[0].children = ex.tree;
|
||||
// Check for an else or elseif
|
||||
if(ex.match) {
|
||||
if(ex.match[1] === "endif") {
|
||||
// Nothing to do if we just found an endif
|
||||
} else if(ex.match[2] === "else") {
|
||||
// Check for an immediately following double linebreak
|
||||
hasLineBreak = !!$tw.utils.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/g);
|
||||
// If we found an else then we need to parse the body looking for the endif
|
||||
var reEndString = "\\<\\%\\s*(endif)\\s*\\%\\>",
|
||||
ex;
|
||||
if(hasLineBreak) {
|
||||
ex = this.parser.parseBlocksTerminatedExtended(reEndString);
|
||||
} else {
|
||||
var reEnd = new RegExp(reEndString,"mg");
|
||||
ex = this.parser.parseInlineRunTerminatedExtended(reEnd,{eatTerminator: true});
|
||||
}
|
||||
// Put the parsed content inside the list empty template
|
||||
listWidget.children[1].children = ex.tree;
|
||||
} else if(ex.match[3] === "elseif") {
|
||||
// Parse the elseif clause by reusing this parser, passing the new filter condition
|
||||
listWidget.children[1].children = this.parseIfClause(ex.match[4]);
|
||||
}
|
||||
}
|
||||
// Return the parse tree node
|
||||
return [listWidget];
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -81,6 +81,9 @@ exports.parse = function() {
|
||||
}
|
||||
return [tiddlerNode];
|
||||
} else {
|
||||
// No template or text reference is provided, so we'll use a blank target. Otherwise we'll generate
|
||||
// a transclude widget that transcludes the current tiddler, often leading to recursion errors
|
||||
transcludeNode.attributes["$tiddler"] = {name: "$tiddler", type: "string", value: ""};
|
||||
return [transcludeNode];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,9 @@ exports.parse = function() {
|
||||
}
|
||||
return [tiddlerNode];
|
||||
} else {
|
||||
// No template or text reference is provided, so we'll use a blank target. Otherwise we'll generate
|
||||
// a transclude widget that transcludes the current tiddler, often leading to recursion errors
|
||||
transcludeNode.attributes["$tiddler"] = {name: "$tiddler", type: "string", value: ""};
|
||||
return [transcludeNode];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,7 +223,7 @@ Parse a block from the current position
|
||||
terminatorRegExpString: optional regular expression string that identifies the end of plain paragraphs. Must not include capturing parenthesis
|
||||
*/
|
||||
WikiParser.prototype.parseBlock = function(terminatorRegExpString) {
|
||||
var terminatorRegExp = terminatorRegExpString ? new RegExp("(" + terminatorRegExpString + "|\\r?\\n\\r?\\n)","mg") : /(\r?\n\r?\n)/mg;
|
||||
var terminatorRegExp = terminatorRegExpString ? new RegExp(terminatorRegExpString + "|\\r?\\n\\r?\\n","mg") : /(\r?\n\r?\n)/mg;
|
||||
this.skipWhitespace();
|
||||
if(this.pos >= this.sourceLength) {
|
||||
return [];
|
||||
@@ -264,11 +264,21 @@ WikiParser.prototype.parseBlocksUnterminated = function() {
|
||||
};
|
||||
|
||||
/*
|
||||
Parse blocks of text until a terminating regexp is encountered
|
||||
Parse blocks of text until a terminating regexp is encountered. Wrapper for parseBlocksTerminatedExtended that just returns the parse tree
|
||||
*/
|
||||
WikiParser.prototype.parseBlocksTerminated = function(terminatorRegExpString) {
|
||||
var terminatorRegExp = new RegExp("(" + terminatorRegExpString + ")","mg"),
|
||||
tree = [];
|
||||
var ex = this.parseBlocksTerminatedExtended(terminatorRegExpString);
|
||||
return ex.tree;
|
||||
};
|
||||
|
||||
/*
|
||||
Parse blocks of text until a terminating regexp is encountered
|
||||
*/
|
||||
WikiParser.prototype.parseBlocksTerminatedExtended = function(terminatorRegExpString) {
|
||||
var terminatorRegExp = new RegExp(terminatorRegExpString,"mg"),
|
||||
result = {
|
||||
tree: []
|
||||
};
|
||||
// Skip any whitespace
|
||||
this.skipWhitespace();
|
||||
// Check if we've got the end marker
|
||||
@@ -277,7 +287,7 @@ WikiParser.prototype.parseBlocksTerminated = function(terminatorRegExpString) {
|
||||
// Parse the text into blocks
|
||||
while(this.pos < this.sourceLength && !(match && match.index === this.pos)) {
|
||||
var blocks = this.parseBlock(terminatorRegExpString);
|
||||
tree.push.apply(tree,blocks);
|
||||
result.tree.push.apply(result.tree,blocks);
|
||||
// Skip any whitespace
|
||||
this.skipWhitespace();
|
||||
// Check if we've got the end marker
|
||||
@@ -286,8 +296,9 @@ WikiParser.prototype.parseBlocksTerminated = function(terminatorRegExpString) {
|
||||
}
|
||||
if(match && match.index === this.pos) {
|
||||
this.pos = match.index + match[0].length;
|
||||
result.match = match;
|
||||
}
|
||||
return tree;
|
||||
return result;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -330,6 +341,11 @@ WikiParser.prototype.parseInlineRunUnterminated = function(options) {
|
||||
};
|
||||
|
||||
WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,options) {
|
||||
var ex = this.parseInlineRunTerminatedExtended(terminatorRegExp,options);
|
||||
return ex.tree;
|
||||
};
|
||||
|
||||
WikiParser.prototype.parseInlineRunTerminatedExtended = function(terminatorRegExp,options) {
|
||||
options = options || {};
|
||||
var tree = [];
|
||||
// Find the next occurrence of the terminator
|
||||
@@ -349,7 +365,10 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
|
||||
if(options.eatTerminator) {
|
||||
this.pos += terminatorMatch[0].length;
|
||||
}
|
||||
return tree;
|
||||
return {
|
||||
match: terminatorMatch,
|
||||
tree: tree
|
||||
};
|
||||
}
|
||||
}
|
||||
// Process any inline rule, along with the text preceding it
|
||||
@@ -373,7 +392,9 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
|
||||
this.pushTextWidget(tree,this.source.substr(this.pos),this.pos,this.sourceLength);
|
||||
}
|
||||
this.pos = this.sourceLength;
|
||||
return tree;
|
||||
return {
|
||||
tree: tree
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -31,7 +31,7 @@ GitHubSaver.prototype.save = function(text,method,callback) {
|
||||
headers = {
|
||||
"Accept": "application/vnd.github.v3+json",
|
||||
"Content-Type": "application/json;charset=UTF-8",
|
||||
"Authorization": "Basic " + window.btoa(username + ":" + password),
|
||||
"Authorization": "Basic " + $tw.utils.base64Encode(username + ":" + password),
|
||||
"If-None-Match": ""
|
||||
};
|
||||
// Bail if we don't have everything we need
|
||||
|
||||
@@ -40,7 +40,7 @@ exports.startup = function() {
|
||||
variables = $tw.utils.extend({},paramObject,{currentTiddler: title, "tv-window-id": windowID});
|
||||
// Open the window
|
||||
var srcWindow,
|
||||
srcDocument;
|
||||
srcDocument;
|
||||
// In case that popup blockers deny opening a new window
|
||||
try {
|
||||
srcWindow = window.open("","external-" + windowID,"scrollbars,width=" + width + ",height=" + height + (top ? ",top=" + top : "" ) + (left ? ",left=" + left : "" )),
|
||||
@@ -52,6 +52,7 @@ exports.startup = function() {
|
||||
$tw.windows[windowID] = srcWindow;
|
||||
// Check for reopening the same window
|
||||
if(srcWindow.haveInitialisedWindow) {
|
||||
srcWindow.focus();
|
||||
return;
|
||||
}
|
||||
// Initialise the document
|
||||
|
||||
@@ -187,7 +187,7 @@ HttpClientRequest.prototype.send = function(callback) {
|
||||
for (var i=0; i<len; i++) {
|
||||
binary += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
resultVariables.data = window.btoa(binary);
|
||||
resultVariables.data = $tw.utils.base64Encode(binary,true);
|
||||
}
|
||||
self.wiki.addTiddler(new $tw.Tiddler(self.wiki.getTiddler(requestTrackerTitle),{
|
||||
status: completionCode,
|
||||
|
||||
@@ -104,11 +104,7 @@ TW_Element.prototype.setAttribute = function(name,value) {
|
||||
if(this.isRaw) {
|
||||
throw "Cannot setAttribute on a raw TW_Element";
|
||||
}
|
||||
if(name === "style") {
|
||||
this.style = value;
|
||||
} else {
|
||||
this.attributes[name] = value + "";
|
||||
}
|
||||
this.attributes[name] = value + "";
|
||||
};
|
||||
|
||||
TW_Element.prototype.setAttributeNS = function(namespace,name,value) {
|
||||
|
||||
@@ -819,18 +819,41 @@ exports.hashString = function(str) {
|
||||
},0);
|
||||
};
|
||||
|
||||
/*
|
||||
Base64 utility functions that work in either browser or Node.js
|
||||
*/
|
||||
if(typeof window !== 'undefined') {
|
||||
exports.btoa = function(binstr) { return window.btoa(binstr); }
|
||||
exports.atob = function(b64) { return window.atob(b64); }
|
||||
} else {
|
||||
exports.btoa = function(binstr) {
|
||||
return Buffer.from(binstr, 'binary').toString('base64');
|
||||
}
|
||||
exports.atob = function(b64) {
|
||||
return Buffer.from(b64, 'base64').toString('binary');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Decode a base64 string
|
||||
*/
|
||||
exports.base64Decode = function(string64) {
|
||||
return base64utf8.base64.decode.call(base64utf8,string64);
|
||||
exports.base64Decode = function(string64,binary,urlsafe) {
|
||||
var encoded = urlsafe ? string64.replace(/_/g,'/').replace(/-/g,'+') : string64;
|
||||
if(binary) return exports.atob(encoded)
|
||||
else return base64utf8.base64.decode.call(base64utf8,encoded);
|
||||
};
|
||||
|
||||
/*
|
||||
Encode a string to base64
|
||||
*/
|
||||
exports.base64Encode = function(string64) {
|
||||
return base64utf8.base64.encode.call(base64utf8,string64);
|
||||
exports.base64Encode = function(string64,binary,urlsafe) {
|
||||
var encoded;
|
||||
if(binary) encoded = exports.btoa(string64);
|
||||
else encoded = base64utf8.base64.encode.call(base64utf8,string64);
|
||||
if(urlsafe) {
|
||||
encoded = encoded.replace(/\+/g,'-').replace(/\//g,'_');
|
||||
}
|
||||
return encoded;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -70,11 +70,6 @@ BrowseWidget.prototype.render = function(parent,nextSibling) {
|
||||
}
|
||||
return false;
|
||||
},false);
|
||||
// Assign data- attributes
|
||||
this.assignAttributes(domNode,{
|
||||
sourcePrefix: "data-",
|
||||
destPrefix: "data-"
|
||||
});
|
||||
// Insert element
|
||||
parent.insertBefore(domNode,nextSibling);
|
||||
this.renderChildren(domNode,null);
|
||||
@@ -100,11 +95,6 @@ BrowseWidget.prototype.execute = function() {
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
BrowseWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if($tw.utils.count(changedAttributes) > 0) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
@@ -59,11 +59,6 @@ ButtonWidget.prototype.render = function(parent,nextSibling) {
|
||||
$tw.utils.pushTop(classes,"tc-popup-handle");
|
||||
}
|
||||
domNode.className = classes.join(" ");
|
||||
// Assign data- attributes
|
||||
this.assignAttributes(domNode,{
|
||||
sourcePrefix: "data-",
|
||||
destPrefix: "data-"
|
||||
});
|
||||
// Assign other attributes
|
||||
if(this.style) {
|
||||
domNode.setAttribute("style",this.style);
|
||||
@@ -255,7 +250,7 @@ ButtonWidget.prototype.updateDomNodeClasses = function() {
|
||||
//Add new classes from updated class attribute.
|
||||
$tw.utils.pushTop(domNodeClasses,newClasses);
|
||||
this.domNode.className = domNodeClasses.join(" ");
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
@@ -265,15 +260,8 @@ ButtonWidget.prototype.refresh = function(changedTiddlers) {
|
||||
if(changedAttributes.actions || changedAttributes.to || changedAttributes.message || changedAttributes.param || changedAttributes.set || changedAttributes.setTo || changedAttributes.popup || changedAttributes.hover || changedAttributes.selectedClass || changedAttributes.style || changedAttributes.dragFilter || changedAttributes.dragTiddler || (this.set && changedTiddlers[this.set]) || (this.popup && changedTiddlers[this.popup]) || (this.popupTitle && changedTiddlers[this.popupTitle]) || changedAttributes.popupAbsCoords || changedAttributes.setTitle || changedAttributes.setField || changedAttributes.setIndex || changedAttributes.popupTitle || changedAttributes.disabled || changedAttributes["default"]) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
if(changedAttributes["class"]) {
|
||||
this.updateDomNodeClasses();
|
||||
}
|
||||
this.assignAttributes(this.domNodes[0],{
|
||||
changedAttributes: changedAttributes,
|
||||
sourcePrefix: "data-",
|
||||
destPrefix: "data-"
|
||||
});
|
||||
} else if(changedAttributes["class"]) {
|
||||
this.updateDomNodeClasses();
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
};
|
||||
|
||||
@@ -53,11 +53,6 @@ CheckboxWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.labelDomNode.appendChild(this.inputDomNode);
|
||||
this.spanDomNode = this.document.createElement("span");
|
||||
this.labelDomNode.appendChild(this.spanDomNode);
|
||||
// Assign data- attributes
|
||||
this.assignAttributes(this.inputDomNode,{
|
||||
sourcePrefix: "data-",
|
||||
destPrefix: "data-"
|
||||
});
|
||||
// Add a click event handler
|
||||
$tw.utils.addEventListeners(this.inputDomNode,[
|
||||
{name: "change", handlerObject: this, handlerMethod: "handleChangeEvent"}
|
||||
@@ -330,11 +325,6 @@ CheckboxWidget.prototype.refresh = function(changedTiddlers) {
|
||||
$tw.utils.removeClass(this.labelDomNode,"tc-checkbox-checked");
|
||||
}
|
||||
}
|
||||
this.assignAttributes(this.inputDomNode,{
|
||||
changedAttributes: changedAttributes,
|
||||
sourcePrefix: "data-",
|
||||
destPrefix: "data-"
|
||||
});
|
||||
return this.refreshChildren(changedTiddlers) || refreshed;
|
||||
}
|
||||
};
|
||||
@@ -342,4 +332,3 @@ CheckboxWidget.prototype.refresh = function(changedTiddlers) {
|
||||
exports.checkbox = CheckboxWidget;
|
||||
|
||||
})();
|
||||
|
||||
@@ -52,11 +52,6 @@ DraggableWidget.prototype.render = function(parent,nextSibling) {
|
||||
classes.push("tc-draggable");
|
||||
}
|
||||
domNode.setAttribute("class",classes.join(" "));
|
||||
// Assign data- attributes and style. attributes
|
||||
this.assignAttributes(domNode,{
|
||||
sourcePrefix: "data-",
|
||||
destPrefix: "data-"
|
||||
});
|
||||
// Insert the node into the DOM and render any children
|
||||
parent.insertBefore(domNode,nextSibling);
|
||||
this.renderChildren(domNode,null);
|
||||
@@ -113,19 +108,13 @@ DraggableWidget.prototype.updateDomNodeClasses = function() {
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
DraggableWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.tag || changedAttributes.selector || changedAttributes.dragimagetype || changedAttributes.enable || changedAttributes.startactions || changedAttributes.endactions) {
|
||||
var changedAttributes = this.computeAttributes(),
|
||||
changedAttributesCount = $tw.utils.count(changedAttributes);
|
||||
if(changedAttributesCount === 1 && changedAttributes["class"]) {
|
||||
this.updateDomNodeClasses();
|
||||
} else if(changedAttributesCount > 0) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
if(changedAttributes["class"]) {
|
||||
this.assignDomNodeClasses();
|
||||
}
|
||||
this.assignAttributes(this.domNodes[0],{
|
||||
changedAttributes: changedAttributes,
|
||||
sourcePrefix: "data-",
|
||||
destPrefix: "data-"
|
||||
});
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
};
|
||||
|
||||
@@ -42,11 +42,6 @@ DroppableWidget.prototype.render = function(parent,nextSibling) {
|
||||
domNode = this.document.createElement(tag);
|
||||
this.domNode = domNode;
|
||||
this.assignDomNodeClasses();
|
||||
// Assign data- attributes and style. attributes
|
||||
this.assignAttributes(domNode,{
|
||||
sourcePrefix: "data-",
|
||||
destPrefix: "data-"
|
||||
});
|
||||
// Add event handlers
|
||||
if(this.droppableEnable) {
|
||||
$tw.utils.addEventListeners(domNode,[
|
||||
@@ -171,15 +166,8 @@ DroppableWidget.prototype.refresh = function(changedTiddlers) {
|
||||
if(changedAttributes.tag || changedAttributes.enable || changedAttributes.disabledClass || changedAttributes.actions || changedAttributes.effect) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
if(changedAttributes["class"]) {
|
||||
this.assignDomNodeClasses();
|
||||
}
|
||||
this.assignAttributes(this.domNodes[0],{
|
||||
changedAttributes: changedAttributes,
|
||||
sourcePrefix: "data-",
|
||||
destPrefix: "data-"
|
||||
});
|
||||
} else if(changedAttributes["class"]) {
|
||||
this.assignDomNodeClasses();
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
};
|
||||
|
||||
@@ -58,24 +58,25 @@ ImageWidget.prototype.render = function(parent,nextSibling) {
|
||||
if(this.wiki.isImageTiddler(this.imageSource)) {
|
||||
var type = tiddler.fields.type,
|
||||
text = tiddler.fields.text,
|
||||
_canonical_uri = tiddler.fields._canonical_uri;
|
||||
_canonical_uri = tiddler.fields._canonical_uri,
|
||||
typeInfo = $tw.config.contentTypeInfo[type] || {},
|
||||
deserializerType = typeInfo.deserializerType || type;
|
||||
// If the tiddler has body text then it doesn't need to be lazily loaded
|
||||
if(text) {
|
||||
// Render the appropriate element for the image type
|
||||
switch(type) {
|
||||
case "application/pdf":
|
||||
// Render the appropriate element for the image type by looking up the encoding in the content type info
|
||||
var encoding = typeInfo.encoding || "utf8";
|
||||
if (encoding === "base64") {
|
||||
// .pdf .png .jpg etc.
|
||||
src = "data:" + deserializerType + ";base64," + text;
|
||||
if (deserializerType === "application/pdf") {
|
||||
tag = "embed";
|
||||
src = "data:application/pdf;base64," + text;
|
||||
break;
|
||||
case "image/svg+xml":
|
||||
src = "data:image/svg+xml," + encodeURIComponent(text);
|
||||
break;
|
||||
default:
|
||||
src = "data:" + type + ";base64," + text;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// .svg .tid .xml etc.
|
||||
src = "data:" + deserializerType + "," + encodeURIComponent(text);
|
||||
}
|
||||
} else if(_canonical_uri) {
|
||||
switch(type) {
|
||||
switch(deserializerType) {
|
||||
case "application/pdf":
|
||||
tag = "embed";
|
||||
src = _canonical_uri;
|
||||
|
||||
@@ -43,11 +43,6 @@ LinkWidget.prototype.render = function(parent,nextSibling) {
|
||||
} else {
|
||||
// Just insert the link text
|
||||
var domNode = this.document.createElement("span");
|
||||
// Assign data- attributes
|
||||
this.assignAttributes(domNode,{
|
||||
sourcePrefix: "data-",
|
||||
destPrefix: "data-"
|
||||
});
|
||||
parent.insertBefore(domNode,nextSibling);
|
||||
this.renderChildren(domNode,null);
|
||||
this.domNodes.push(domNode);
|
||||
@@ -143,11 +138,6 @@ LinkWidget.prototype.renderLink = function(parent,nextSibling) {
|
||||
widget: this
|
||||
});
|
||||
}
|
||||
// Assign data- attributes
|
||||
this.assignAttributes(domNode,{
|
||||
sourcePrefix: "data-",
|
||||
destPrefix: "data-"
|
||||
});
|
||||
// Insert the link into the DOM and render any children
|
||||
parent.insertBefore(domNode,nextSibling);
|
||||
this.renderChildren(domNode,null);
|
||||
@@ -217,7 +207,8 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
||||
*/
|
||||
LinkWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if($tw.utils.count(changedAttributes) > 0) {
|
||||
if(changedAttributes.to || changedTiddlers[this.to] || changedAttributes["aria-label"] || changedAttributes.tooltip ||
|
||||
changedAttributes["class"] || changedAttributes.tabindex || changedAttributes.draggable || changedAttributes.tag) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
@@ -227,4 +218,3 @@ LinkWidget.prototype.refresh = function(changedTiddlers) {
|
||||
exports.link = LinkWidget;
|
||||
|
||||
})();
|
||||
|
||||
@@ -60,6 +60,7 @@ ListWidget.prototype.render = function(parent,nextSibling) {
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
ListWidget.prototype.execute = function() {
|
||||
var self = this;
|
||||
// Get our attributes
|
||||
this.template = this.getAttribute("template");
|
||||
this.editTemplate = this.getAttribute("editTemplate");
|
||||
@@ -67,6 +68,8 @@ ListWidget.prototype.execute = function() {
|
||||
this.counterName = this.getAttribute("counter");
|
||||
this.storyViewName = this.getAttribute("storyview");
|
||||
this.historyTitle = this.getAttribute("history");
|
||||
// Look for <$list-template> and <$list-empty> widgets as immediate child widgets
|
||||
this.findExplicitTemplates();
|
||||
// Compose the list elements
|
||||
this.list = this.getTiddlerList();
|
||||
var members = [],
|
||||
@@ -85,18 +88,48 @@ ListWidget.prototype.execute = function() {
|
||||
this.history = [];
|
||||
};
|
||||
|
||||
ListWidget.prototype.findExplicitTemplates = function() {
|
||||
var self = this;
|
||||
this.explicitListTemplate = null;
|
||||
this.explicitEmptyTemplate = null;
|
||||
var searchChildren = function(childNodes) {
|
||||
$tw.utils.each(childNodes,function(node) {
|
||||
if(node.type === "list-template") {
|
||||
self.explicitListTemplate = node.children;
|
||||
} else if(node.type === "list-empty") {
|
||||
self.explicitEmptyTemplate = node.children;
|
||||
} else if(node.type === "element" && node.tag === "p") {
|
||||
searchChildren(node.children);
|
||||
}
|
||||
});
|
||||
};
|
||||
searchChildren(this.parseTreeNode.children);
|
||||
}
|
||||
|
||||
ListWidget.prototype.getTiddlerList = function() {
|
||||
var limit = $tw.utils.getInt(this.getAttribute("limit",""),undefined);
|
||||
var defaultFilter = "[!is[system]sort[title]]";
|
||||
return this.wiki.filterTiddlers(this.getAttribute("filter",defaultFilter),this);
|
||||
var results = this.wiki.filterTiddlers(this.getAttribute("filter",defaultFilter),this);
|
||||
if(limit !== undefined) {
|
||||
if(limit >= 0) {
|
||||
results = results.slice(0,limit);
|
||||
} else {
|
||||
results = results.slice(limit);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
ListWidget.prototype.getEmptyMessage = function() {
|
||||
var parser,
|
||||
emptyMessage = this.getAttribute("emptyMessage","");
|
||||
// this.wiki.parseText() calls
|
||||
// new Parser(..), which should only be done, if needed, because it's heavy!
|
||||
if (emptyMessage === "") {
|
||||
return [];
|
||||
emptyMessage = this.getAttribute("emptyMessage");
|
||||
// If emptyMessage attribute is not present or empty then look for an explicit empty template
|
||||
if(!emptyMessage) {
|
||||
if(this.explicitEmptyTemplate) {
|
||||
return this.explicitEmptyTemplate;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
parser = this.wiki.parseText("text/vnd.tiddlywiki",emptyMessage,{parseAsInline: true});
|
||||
if(parser) {
|
||||
@@ -122,12 +155,19 @@ ListWidget.prototype.makeItemTemplate = function(title,index) {
|
||||
if(template) {
|
||||
templateTree = [{type: "transclude", attributes: {tiddler: {type: "string", value: template}}}];
|
||||
} else {
|
||||
// Check for child nodes of the list widget
|
||||
if(this.parseTreeNode.children && this.parseTreeNode.children.length > 0) {
|
||||
templateTree = this.parseTreeNode.children;
|
||||
} else {
|
||||
// Check for a <$list-item> widget
|
||||
if(this.explicitListTemplate) {
|
||||
templateTree = this.explicitListTemplate;
|
||||
} else if (!this.explicitEmptyTemplate) {
|
||||
templateTree = this.parseTreeNode.children;
|
||||
}
|
||||
}
|
||||
if(!templateTree) {
|
||||
// Default template is a link to the title
|
||||
templateTree = [{type: "element", tag: this.parseTreeNode.isBlock ? "div" : "span", children: [{type: "link", attributes: {to: {type: "string", value: title}}, children: [
|
||||
{type: "text", text: title}
|
||||
{type: "text", text: title}
|
||||
]}]}];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,10 +40,6 @@ RadioWidget.prototype.render = function(parent,nextSibling) {
|
||||
);
|
||||
this.inputDomNode = this.document.createElement("input");
|
||||
this.inputDomNode.setAttribute("type","radio");
|
||||
this.assignAttributes(this.inputDomNode,{
|
||||
sourcePrefix: "data-",
|
||||
destPrefix: "data-"
|
||||
});
|
||||
if(isChecked) {
|
||||
this.inputDomNode.checked = true;
|
||||
}
|
||||
|
||||
@@ -50,10 +50,6 @@ RangeWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.inputDomNode.setAttribute("disabled",true);
|
||||
}
|
||||
this.inputDomNode.value = this.getValue();
|
||||
this.assignAttributes(this.inputDomNode,{
|
||||
sourcePrefix: "data-",
|
||||
destPrefix: "data-"
|
||||
});
|
||||
// Add a click event handler
|
||||
$tw.utils.addEventListeners(this.inputDomNode,[
|
||||
{name:"mousedown", handlerObject:this, handlerMethod:"handleMouseDownEvent"},
|
||||
|
||||
@@ -40,31 +40,7 @@ SelectWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
//Create element
|
||||
var domNode = this.document.createElement("select");
|
||||
if(this.selectClass) {
|
||||
domNode.classname = this.selectClass;
|
||||
}
|
||||
// Assign data- attributes
|
||||
this.assignAttributes(domNode,{
|
||||
sourcePrefix: "data-",
|
||||
destPrefix: "data-"
|
||||
});
|
||||
if(this.selectMultiple) {
|
||||
domNode.setAttribute("multiple","multiple");
|
||||
}
|
||||
if(this.selectSize) {
|
||||
domNode.setAttribute("size",this.selectSize);
|
||||
}
|
||||
if(this.selectTabindex) {
|
||||
domNode.setAttribute("tabindex",this.selectTabindex);
|
||||
}
|
||||
if(this.selectTooltip) {
|
||||
domNode.setAttribute("title",this.selectTooltip);
|
||||
}
|
||||
this.renderChildren(domNode,nextSibling);
|
||||
this.parentDomNode.insertBefore(domNode,nextSibling);
|
||||
this.domNodes.push(domNode);
|
||||
this.renderChildren(parent,nextSibling);
|
||||
this.setSelectValue();
|
||||
if(this.selectFocus == "yes") {
|
||||
this.getSelectDomNode().focus();
|
||||
@@ -137,7 +113,7 @@ SelectWidget.prototype.setSelectValue = function() {
|
||||
Get the DOM node of the select element
|
||||
*/
|
||||
SelectWidget.prototype.getSelectDomNode = function() {
|
||||
return this.domNodes[0];
|
||||
return this.children[0].domNodes[0];
|
||||
};
|
||||
|
||||
// Return an array of the selected opion values
|
||||
@@ -173,7 +149,27 @@ SelectWidget.prototype.execute = function() {
|
||||
this.selectTooltip = this.getAttribute("tooltip");
|
||||
this.selectFocus = this.getAttribute("focus");
|
||||
// Make the child widgets
|
||||
this.makeChildWidgets();
|
||||
var selectNode = {
|
||||
type: "element",
|
||||
tag: "select",
|
||||
children: this.parseTreeNode.children
|
||||
};
|
||||
if(this.selectClass) {
|
||||
$tw.utils.addAttributeToParseTreeNode(selectNode,"class",this.selectClass);
|
||||
}
|
||||
if(this.selectMultiple) {
|
||||
$tw.utils.addAttributeToParseTreeNode(selectNode,"multiple","multiple");
|
||||
}
|
||||
if(this.selectSize) {
|
||||
$tw.utils.addAttributeToParseTreeNode(selectNode,"size",this.selectSize);
|
||||
}
|
||||
if(this.selectTabindex) {
|
||||
$tw.utils.addAttributeToParseTreeNode(selectNode,"tabindex",this.selectTabindex);
|
||||
}
|
||||
if(this.selectTooltip) {
|
||||
$tw.utils.addAttributeToParseTreeNode(selectNode,"title",this.selectTooltip);
|
||||
}
|
||||
this.makeChildWidgets([selectNode]);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -182,21 +178,17 @@ 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.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.tooltip || changedAttributes.tabindex) {
|
||||
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
|
||||
} else {
|
||||
if(changedAttributes.class) {
|
||||
this.selectClass = this.getAttribute("class");
|
||||
this.getSelectDomNode().setAttribute("class",this.selectClass);
|
||||
}
|
||||
this.assignAttributes(this.getSelectDomNode(),{
|
||||
changedAttributes: changedAttributes,
|
||||
sourcePrefix: "data-",
|
||||
destPrefix: "data-"
|
||||
});
|
||||
|
||||
var childrenRefreshed = this.refreshChildren(changedTiddlers);
|
||||
// If the target tiddler value has changed, just update setting and refresh the children
|
||||
if(changedTiddlers[this.selectTitle] || childrenRefreshed) {
|
||||
this.setSelectValue();
|
||||
}
|
||||
|
||||
@@ -109,6 +109,7 @@ TranscludeWidget.prototype.collectAttributes = function() {
|
||||
this.recursionMarker = this.getAttribute("recursionMarker","yes");
|
||||
} else {
|
||||
this.transcludeVariable = this.getAttribute("$variable");
|
||||
this.transcludeVariableIsFunction = false;
|
||||
this.transcludeType = this.getAttribute("$type");
|
||||
this.transcludeOutput = this.getAttribute("$output","text/html");
|
||||
this.transcludeTitle = this.getAttribute("$tiddler",this.getVariable("currentTiddler"));
|
||||
@@ -184,7 +185,9 @@ TranscludeWidget.prototype.getTransclusionTarget = function() {
|
||||
if(this.transcludeVariable) {
|
||||
// Transcluding a variable
|
||||
var variableInfo = this.getVariableInfo(this.transcludeVariable,{params: this.getOrderedTransclusionParameters()});
|
||||
this.transcludeVariableIsFunction = variableInfo.srcVariable && variableInfo.srcVariable.isFunctionDefinition;
|
||||
text = variableInfo.text;
|
||||
this.transcludeFunctionResult = text;
|
||||
return {
|
||||
text: variableInfo.text,
|
||||
type: this.transcludeType
|
||||
@@ -219,21 +222,24 @@ TranscludeWidget.prototype.parseTransclusionTarget = function(parseAsInline) {
|
||||
// Transcluding a variable
|
||||
var variableInfo = this.getVariableInfo(this.transcludeVariable,{params: this.getOrderedTransclusionParameters()}),
|
||||
srcVariable = variableInfo && variableInfo.srcVariable;
|
||||
if(srcVariable && srcVariable.isFunctionDefinition) {
|
||||
this.transcludeVariableIsFunction = true;
|
||||
this.transcludeFunctionResult = (variableInfo.resultList ? variableInfo.resultList[0] : variableInfo.text) || "";
|
||||
}
|
||||
if(variableInfo.text) {
|
||||
if(srcVariable && srcVariable.isFunctionDefinition) {
|
||||
var result = (variableInfo.resultList ? variableInfo.resultList[0] : variableInfo.text) || "";
|
||||
parser = {
|
||||
tree: [{
|
||||
type: "text",
|
||||
text: result
|
||||
text: this.transcludeFunctionResult
|
||||
}],
|
||||
source: result,
|
||||
source: this.transcludeFunctionResult,
|
||||
type: "text/vnd.tiddlywiki"
|
||||
};
|
||||
if(parseAsInline) {
|
||||
parser.tree[0] = {
|
||||
type: "text",
|
||||
text: result
|
||||
text: this.transcludeFunctionResult
|
||||
};
|
||||
} else {
|
||||
parser.tree[0] = {
|
||||
@@ -241,7 +247,7 @@ TranscludeWidget.prototype.parseTransclusionTarget = function(parseAsInline) {
|
||||
tag: "p",
|
||||
children: [{
|
||||
type: "text",
|
||||
text: result
|
||||
text: this.transcludeFunctionResult
|
||||
}]
|
||||
}
|
||||
}
|
||||
@@ -430,12 +436,19 @@ TranscludeWidget.prototype.parserNeedsRefresh = function() {
|
||||
return (this.sourceText === undefined || parserInfo.sourceText !== this.sourceText || parserInfo.parserType !== this.parserType)
|
||||
};
|
||||
|
||||
TranscludeWidget.prototype.functionNeedsRefresh = function() {
|
||||
var oldResult = this.transcludeFunctionResult;
|
||||
var variableInfo = this.getVariableInfo(this.transcludeVariable,{params: this.getOrderedTransclusionParameters()});
|
||||
var newResult = (variableInfo.resultList ? variableInfo.resultList[0] : variableInfo.text) || "";
|
||||
return oldResult !== newResult;
|
||||
}
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
TranscludeWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(($tw.utils.count(changedAttributes) > 0) || (!this.transcludeVariable && changedTiddlers[this.transcludeTitle] && this.parserNeedsRefresh())) {
|
||||
if(($tw.utils.count(changedAttributes) > 0) || (this.transcludeVariableIsFunction && this.functionNeedsRefresh()) || (!this.transcludeVariable && changedTiddlers[this.transcludeTitle] && this.parserNeedsRefresh())) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
|
||||
@@ -413,34 +413,16 @@ Widget.prototype.getAttribute = function(name,defaultText) {
|
||||
};
|
||||
|
||||
/*
|
||||
Assign the common attributes of the widget to a domNode
|
||||
Assign the computed attributes of the widget to a domNode
|
||||
options include:
|
||||
sourcePrefix: prefix of attributes that are to be directly assigned (defaults to the empty string meaning all attributes)
|
||||
destPrefix: prefix to be applied to attribute names that are to be directly assigned (defaults to the emtpy string which means no prefix is added)
|
||||
changedAttributes: hashmap by attribute name of attributes to process (if missing, process all attributes)
|
||||
excludeEventAttributes: ignores attributes whose name would begin with "on"
|
||||
excludeEventAttributes: ignores attributes whose name begins with "on"
|
||||
*/
|
||||
Widget.prototype.assignAttributes = function(domNode,options) {
|
||||
options = options || {};
|
||||
var self = this,
|
||||
changedAttributes = options.changedAttributes || this.attributes,
|
||||
sourcePrefix = options.sourcePrefix || "",
|
||||
destPrefix = options.destPrefix || "",
|
||||
EVENT_ATTRIBUTE_PREFIX = "on";
|
||||
var self = this;
|
||||
var assignAttribute = function(name,value) {
|
||||
// Process any style attributes before considering sourcePrefix and destPrefix
|
||||
if(name.substr(0,6) === "style." && name.length > 6) {
|
||||
domNode.style[$tw.utils.unHyphenateCss(name.substr(6))] = value;
|
||||
return;
|
||||
}
|
||||
// Check if the sourcePrefix is a match
|
||||
if(name.substr(0,sourcePrefix.length) === sourcePrefix) {
|
||||
name = destPrefix + name.substr(sourcePrefix.length);
|
||||
} else {
|
||||
value = undefined;
|
||||
}
|
||||
// Check for excluded attribute names
|
||||
if(options.excludeEventAttributes && name.substr(0,2).toLowerCase() === EVENT_ATTRIBUTE_PREFIX) {
|
||||
if(options.excludeEventAttributes && name.substr(0,2) === "on") {
|
||||
value = undefined;
|
||||
}
|
||||
if(value !== undefined) {
|
||||
@@ -450,24 +432,26 @@ Widget.prototype.assignAttributes = function(domNode,options) {
|
||||
namespace = "http://www.w3.org/1999/xlink";
|
||||
name = name.substr(6);
|
||||
}
|
||||
// Setting certain attributes can cause a DOM error (eg xmlns on the svg element)
|
||||
try {
|
||||
domNode.setAttributeNS(namespace,name,value);
|
||||
} catch(e) {
|
||||
// Handle styles
|
||||
if(name.substr(0,6) === "style." && name.length > 6) {
|
||||
domNode.style[$tw.utils.unHyphenateCss(name.substr(6))] = value;
|
||||
} else {
|
||||
// Setting certain attributes can cause a DOM error (eg xmlns on the svg element)
|
||||
try {
|
||||
domNode.setAttributeNS(namespace,name,value);
|
||||
} catch(e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
// If the parse tree node has the orderedAttributes property then use that order
|
||||
}
|
||||
// Not all parse tree nodes have the orderedAttributes property
|
||||
if(this.parseTreeNode.orderedAttributes) {
|
||||
$tw.utils.each(this.parseTreeNode.orderedAttributes,function(attribute,index) {
|
||||
if(attribute.name in changedAttributes) {
|
||||
assignAttribute(attribute.name,self.getAttribute(attribute.name));
|
||||
}
|
||||
});
|
||||
// Otherwise update each changed attribute irrespective of order
|
||||
assignAttribute(attribute.name,self.attributes[attribute.name]);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(changedAttributes,function(value,name) {
|
||||
assignAttribute(name,self.getAttribute(name));
|
||||
$tw.utils.each(Object.keys(self.attributes).sort(),function(name) {
|
||||
assignAttribute(name,self.attributes[name]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -26,10 +26,10 @@ caption: {{$:/language/ControlPanel/Basics/Caption}}
|
||||
|<$link to="$:/SiteSubtitle"><<lingo Subtitle/Prompt>></$link> |<$edit-text tiddler="$:/SiteSubtitle" default="" tag="input"/> |
|
||||
|<$link to="$:/status/UserName"><<lingo Username/Prompt>></$link> |<$edit-text tiddler="$:/status/UserName" default="" tag="input"/> |
|
||||
|<$link to="$:/config/AnimationDuration"><<lingo AnimDuration/Prompt>></$link> |<$edit-text tiddler="$:/config/AnimationDuration" default="" tag="input"/> |
|
||||
|<$link to="$:/DefaultTiddlers"><<lingo DefaultTiddlers/Prompt>></$link> |<<lingo DefaultTiddlers/TopHint>><br> <$edit class="tc-edit-texteditor" tiddler="$:/DefaultTiddlers"/><br>//<<lingo DefaultTiddlers/BottomHint>>// |
|
||||
|<$link to="$:/DefaultTiddlers"><<lingo DefaultTiddlers/Prompt>></$link> |<<lingo DefaultTiddlers/TopHint>><br> <$edit class="tc-edit-texteditor" tiddler="$:/DefaultTiddlers" autoHeight="yes"/><br>//<<lingo DefaultTiddlers/BottomHint>>// |
|
||||
|<$link to="$:/language/DefaultNewTiddlerTitle"><<lingo NewTiddler/Title/Prompt>></$link> |<$edit-text tiddler="$:/language/DefaultNewTiddlerTitle" default="" tag="input"/> |
|
||||
|<$link to="$:/config/NewJournal/Title"><<lingo NewJournal/Title/Prompt>></$link> |<$edit-text tiddler="$:/config/NewJournal/Title" default="" tag="input"/> |
|
||||
|<$link to="$:/config/NewJournal/Text"><<lingo NewJournal/Text/Prompt>></$link> |<$edit tiddler="$:/config/NewJournal/Text" class="tc-edit-texteditor" default=""/> |
|
||||
|<$link to="$:/config/NewJournal/Text"><<lingo NewJournal/Text/Prompt>></$link> |<$edit tiddler="$:/config/NewJournal/Text" class="tc-edit-texteditor" default="" autoHeight="yes"/> |
|
||||
|<$link to="$:/config/NewTiddler/Tags"><<lingo NewTiddler/Tags/Prompt>></$link> |<$vars currentTiddler="$:/config/NewTiddler/Tags" tagField="text">{{||$:/core/ui/EditTemplate/tags}}<$list filter="[<currentTiddler>tags[]] +[limit[1]]" variable="ignore"><$button tooltip={{$:/language/ControlPanel/Basics/RemoveTags/Hint}}><<lingo RemoveTags>><$action-listops $tiddler=<<currentTiddler>> $field="text" $subfilter={{{ [<currentTiddler>get[tags]] }}}/><$action-setfield $tiddler=<<currentTiddler>> tags=""/></$button></$list></$vars> |
|
||||
|<$link to="$:/config/NewJournal/Tags"><<lingo NewJournal/Tags/Prompt>></$link> |<$vars currentTiddler="$:/config/NewJournal/Tags" tagField="text">{{||$:/core/ui/EditTemplate/tags}}<$list filter="[<currentTiddler>tags[]] +[limit[1]]" variable="ignore"><$button tooltip={{$:/language/ControlPanel/Basics/RemoveTags/Hint}}><<lingo RemoveTags>><$action-listops $tiddler=<<currentTiddler>> $field="text" $subfilter={{{ [<currentTiddler>get[tags]] }}}/><$action-setfield $tiddler=<<currentTiddler>> tags=""/></$button></$list></$vars> |
|
||||
|<$link to="$:/config/AutoFocus"><<lingo AutoFocus/Prompt>></$link> |{{$:/snippets/minifocusswitcher}} |
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
title: $:/core/ui/EditTemplate/body/default
|
||||
|
||||
\function edit-preview-state()
|
||||
[{$:/config/ShowEditPreview/PerTiddler}!match[yes]then[$:/state/showeditpreview]] :else[<qualify "$:/state/showeditpreview">] +[get[text]] :else[[no]]
|
||||
\end
|
||||
|
||||
\define config-visibility-title()
|
||||
$:/config/EditorToolbarButtons/Visibility/$(currentTiddler)$
|
||||
\end
|
||||
@@ -10,15 +14,16 @@ $:/config/EditorToolbarButtons/Visibility/$(currentTiddler)$
|
||||
|
||||
\whitespace trim
|
||||
<$let
|
||||
edit-preview-state={{{ [{$:/config/ShowEditPreview/PerTiddler}!match[yes]then[$:/state/showeditpreview]] :else[<qualify "$:/state/showeditpreview">] }}}
|
||||
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 stateTitle=<<edit-preview-state>> type="match" text="yes" tag="div">
|
||||
<div class="tc-tiddler-preview">
|
||||
<div>
|
||||
<div class={{{ [function[edit-preview-state]match[yes]then[tc-tiddler-preview]else[tc-tiddler-preview-hidden]] [[tc-tiddler-editor]] +[join[ ]] }}}>
|
||||
|
||||
<$transclude tiddler="$:/core/ui/EditTemplate/body/editor" mode="inline"/>
|
||||
|
||||
<$list filter="[function[edit-preview-state]match[yes]]" variable="ignore">
|
||||
|
||||
<div class="tc-tiddler-preview-preview" data-tiddler-title={{!!draft.title}} data-tags={{!!tags}}>
|
||||
|
||||
<$transclude tiddler={{$:/state/editpreviewtype}} mode="inline">
|
||||
@@ -29,13 +34,12 @@ $:/config/EditorToolbarButtons/Visibility/$(currentTiddler)$
|
||||
|
||||
</div>
|
||||
|
||||
</$list>
|
||||
|
||||
</div>
|
||||
</$reveal>
|
||||
|
||||
<$reveal stateTitle=<<edit-preview-state>> type="nomatch" text="yes" tag="div">
|
||||
</div>
|
||||
|
||||
<$transclude tiddler="$:/core/ui/EditTemplate/body/editor" mode="inline"/>
|
||||
|
||||
</$reveal>
|
||||
</$dropzone>
|
||||
|
||||
</$let>
|
||||
|
||||
@@ -89,7 +89,7 @@ $value={{{ [subfilter<get-field-value-tiddler-filter>get[text]] }}}/>
|
||||
</td>
|
||||
<td class="tc-edit-field-remove">
|
||||
<$button class="tc-btn-invisible" tooltip={{$:/language/EditTemplate/Field/Remove/Hint}} aria-label={{$:/language/EditTemplate/Field/Remove/Caption}}>
|
||||
<$action-deletefield $field=<<currentField>>/><$set name="currentTiddlerCSSescaped" value={{{ [<currentTiddler>escapecss[]] }}}><$action-sendmessage $message="tm-focus-selector" $param=<<current-tiddler-new-field-selector>>/></$set>
|
||||
<$action-deletefield $field=<<currentField>>/>
|
||||
{{$:/core/images/delete-button}}
|
||||
</$button>
|
||||
</td>
|
||||
|
||||
@@ -9,11 +9,17 @@ button-classes: tc-text-editor-toolbar-item-start-group
|
||||
shortcuts: ((preview))
|
||||
|
||||
\whitespace trim
|
||||
<$let
|
||||
edit-preview-state={{{ [{$:/config/ShowEditPreview/PerTiddler}!match[yes]then[$:/state/showeditpreview]] :else[<qualify "$:/state/showeditpreview">] }}}
|
||||
>
|
||||
<$reveal state=<<edit-preview-state>> type="match" text="yes" tag="span">
|
||||
{{$:/core/images/preview-open}}
|
||||
<$action-setfield $tiddler=<<edit-preview-state>> $value="no"/>
|
||||
<$action-sendmessage $message="tm-edit-text-operation" $param="focus-editor"/>
|
||||
</$reveal>
|
||||
<$reveal state=<<edit-preview-state>> type="nomatch" text="yes" tag="span">
|
||||
{{$:/core/images/preview-closed}}
|
||||
<$action-setfield $tiddler=<<edit-preview-state>> $value="yes"/>
|
||||
<$action-sendmessage $message="tm-edit-text-operation" $param="focus-editor"/>
|
||||
</$reveal>
|
||||
</$let>
|
||||
|
||||
@@ -4,15 +4,7 @@ code-body: yes
|
||||
|
||||
\define tabs-button()
|
||||
\whitespace trim
|
||||
<$button
|
||||
set=<<tabsState>>
|
||||
setTo=<<currentTab>>
|
||||
default=<<__default__>>
|
||||
selectedClass="tc-tab-selected"
|
||||
tooltip={{!!tooltip}}
|
||||
role="switch"
|
||||
data-tab-title=<<currentTab>>
|
||||
>
|
||||
<$button set=<<tabsState>> setTo=<<currentTab>> default=<<__default__>> selectedClass="tc-tab-selected" tooltip={{!!tooltip}} role="switch">
|
||||
<$tiddler tiddler=<<save-currentTiddler>>>
|
||||
<$set name="tv-wikilinks" value="no">
|
||||
<$transclude tiddler=<<__buttonTemplate__>> mode="inline">
|
||||
|
||||
@@ -118,7 +118,7 @@ tags: $:/tags/Macro
|
||||
<$set name="toc-item-class" filter=<<__itemClassFilter__>> emptyValue="toc-item-selected" value="toc-item" >
|
||||
<li class=<<toc-item-class>>>
|
||||
<$link to={{{ [<currentTiddler>get[target]else<currentTiddler>] }}}>
|
||||
<$list filter="[all[current]tagging[]$sort$limit[1]]" variable="ignore" emptyMessage="<$button class='tc-btn-invisible'>{{$:/core/images/blank}}</$button>">
|
||||
<$list filter="[all[current]tagging[]$sort$limit[1]] -[subfilter<__exclude__>]" variable="ignore" emptyMessage="<$button class='tc-btn-invisible'>{{$:/core/images/blank}}</$button>">
|
||||
<$reveal type="nomatch" stateTitle=<<toc-state>> text="open">
|
||||
<$button setTitle=<<toc-state>> setTo="open" class="tc-btn-invisible tc-popup-keep">
|
||||
<$transclude tiddler=<<toc-closed-icon>> />
|
||||
@@ -145,7 +145,7 @@ tags: $:/tags/Macro
|
||||
<$qualify name="toc-state" title={{{ [[$:/state/toc]addsuffix<__path__>addsuffix[-]addsuffix<currentTiddler>] }}}>
|
||||
<$set name="toc-item-class" filter=<<__itemClassFilter__>> emptyValue="toc-item-selected" value="toc-item">
|
||||
<li class=<<toc-item-class>>>
|
||||
<$list filter="[all[current]tagging[]$sort$limit[1]]" variable="ignore" emptyMessage="""<$button class="tc-btn-invisible">{{$:/core/images/blank}}</$button><span class="toc-item-muted"><<toc-caption>></span>""">
|
||||
<$list filter="[all[current]tagging[]$sort$limit[1]] -[subfilter<__exclude__>]" variable="ignore" emptyMessage="""<$button class="tc-btn-invisible">{{$:/core/images/blank}}</$button><span class="toc-item-muted"><<toc-caption>></span>""">
|
||||
<$reveal type="nomatch" stateTitle=<<toc-state>> text="open">
|
||||
<$button setTitle=<<toc-state>> setTo="open" class="tc-btn-invisible tc-popup-keep">
|
||||
<$transclude tiddler=<<toc-closed-icon>> />
|
||||
|
||||
|
Before Width: | Height: | Size: 6.4 KiB |
BIN
editions/de-AT-server/tiddlers/system/favicon.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
@@ -1,2 +1,2 @@
|
||||
title: $:/favicon.ico
|
||||
type: image/x-icon
|
||||
type: image/png
|
||||
|
Before Width: | Height: | Size: 6.4 KiB |
BIN
editions/dev/tiddlers/images/favicon.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
@@ -1,2 +1,2 @@
|
||||
title: $:/favicon.ico
|
||||
type: image/x-icon
|
||||
type: image/png
|
||||
|
Before Width: | Height: | Size: 6.4 KiB |
BIN
editions/es-ES-server/tiddlers/system/favicon.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
@@ -1,2 +1,2 @@
|
||||
title: $:/favicon.ico
|
||||
type: image/x-icon
|
||||
type: image/png
|
||||
|
Before Width: | Height: | Size: 6.4 KiB |
BIN
editions/es-ES/tiddlers/images/favicon.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
@@ -1,2 +1,2 @@
|
||||
title: $:/favicon.ico
|
||||
type: image/x-icon
|
||||
type: image/png
|
||||
|
Before Width: | Height: | Size: 6.4 KiB |
BIN
editions/es-ES/tiddlers/images/green_favicon.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
@@ -1,2 +1,2 @@
|
||||
title: $:/green_favicon.ico
|
||||
type: image/x-icon
|
||||
type: image/png
|
||||
|
Before Width: | Height: | Size: 6.4 KiB |
@@ -1,2 +0,0 @@
|
||||
title: $:/favicon.ico
|
||||
type: image/x-icon
|
||||
BIN
editions/fr-FR-server/tiddlers/system/favicon.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
2
editions/fr-FR-server/tiddlers/system/favicon.png.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
title: $:/favicon.ico
|
||||
type: image/png
|
||||
|
Before Width: | Height: | Size: 6.4 KiB |
@@ -1,2 +0,0 @@
|
||||
title: $:/favicon.ico
|
||||
type: image/x-icon
|
||||
BIN
editions/fr-FR/tiddlers/images/favicon.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
2
editions/fr-FR/tiddlers/images/favicon.png.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
title: $:/favicon.ico
|
||||
type: image/png
|
||||
|
Before Width: | Height: | Size: 6.4 KiB |
BIN
editions/fr-FR/tiddlers/images/green_favicon.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
@@ -1,2 +1,2 @@
|
||||
title: $:/green_favicon.ico
|
||||
type: image/x-icon
|
||||
type: image/png
|
||||
|
Before Width: | Height: | Size: 6.4 KiB |
@@ -1,2 +0,0 @@
|
||||
title: $:/favicon.ico
|
||||
type: image/x-icon
|
||||
BIN
editions/ja-JP/tiddlers/images/favicon.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
2
editions/ja-JP/tiddlers/images/favicon.png.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
title: $:/favicon.ico
|
||||
type: image/png
|
||||
|
Before Width: | Height: | Size: 6.4 KiB |
BIN
editions/ja-JP/tiddlers/images/green_favicon.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
@@ -1,2 +1,2 @@
|
||||
title: $:/green_favicon.ico
|
||||
type: image/x-icon
|
||||
type: image/png
|
||||
|
Before Width: | Height: | Size: 6.4 KiB |
@@ -1,2 +0,0 @@
|
||||
title: $:/favicon.ico
|
||||
type: image/x-icon
|
||||
BIN
editions/ko-KR-server/tiddlers/system/favicon.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
2
editions/ko-KR-server/tiddlers/system/favicon.png.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
title: $:/favicon.ico
|
||||
type: image/png
|
||||
|
Before Width: | Height: | Size: 6.4 KiB |
@@ -1,2 +0,0 @@
|
||||
title: $:/favicon.ico
|
||||
type: image/x-icon
|
||||
BIN
editions/ko-KR/tiddlers/images/favicon.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
2
editions/ko-KR/tiddlers/images/favicon.png.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
title: $:/favicon.ico
|
||||
type: image/png
|
||||
|
Before Width: | Height: | Size: 6.4 KiB |
BIN
editions/ko-KR/tiddlers/images/green_favicon.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
@@ -1,2 +1,2 @@
|
||||
title: $:/green_favicon.ico
|
||||
type: image/x-icon
|
||||
type: image/png
|
||||
@@ -1,37 +1,105 @@
|
||||
caption: 5.3.2
|
||||
created: 20230820114855583
|
||||
modified: 20230820114855583
|
||||
created: 20231016122502955
|
||||
modified: 20231016122502955
|
||||
tags: ReleaseNotes
|
||||
title: Release 5.3.2
|
||||
type: text/vnd.tiddlywiki
|
||||
description: Under development
|
||||
|
||||
//[[See GitHub for detailed change history of this release|https://github.com/Jermolene/TiddlyWiki5/compare/v5.3.1...master]]//
|
||||
|
||||
! Major Improvements
|
||||
|
||||
!! Conditional Shortcut Syntax
|
||||
|
||||
<<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7710">> a new [[shortcut syntax|Conditional Shortcut Syntax]] for concisely expressing if-then-else logic. For example:
|
||||
|
||||
```
|
||||
<% if [<animal>match[Elephant]] %>
|
||||
It is an elephant
|
||||
<% elseif [<animal>match[Giraffe]] %>
|
||||
It is a giraffe
|
||||
<% else %>
|
||||
It is completely unknown
|
||||
<% endif %>
|
||||
```
|
||||
|
||||
!! Explicit Templates for the ListWidget
|
||||
|
||||
<<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7784">> support for `<$list-template>` and `<$list-empty>` as immediate children of the <<.wid "ListWidget">> widget to specify the list item template and/or the empty template. For example:
|
||||
|
||||
```
|
||||
<$list filter=<<filter>>>
|
||||
<$list-template>
|
||||
<$text text=<<currentTiddler>>/>
|
||||
</$list-template>
|
||||
<$list-empty>
|
||||
None!
|
||||
</$list-empty>
|
||||
</$list>
|
||||
```
|
||||
|
||||
Note that the <<.attr "emptyMessage">> and <<.attr "template">> attributes take precedence if they are present.
|
||||
|
||||
!! jsonset operator
|
||||
|
||||
<<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7742">> [[jsonset Operator]] for setting values within JSON objects
|
||||
|
||||
!! QR Code Reader
|
||||
|
||||
<<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/pull/7746">> QR Code plugin to be able to read QR codes and a number of other bar code formats
|
||||
|
||||
! Translation improvement
|
||||
|
||||
Improvements to the following translations:
|
||||
|
||||
*
|
||||
* Chinese
|
||||
* Polish
|
||||
* Spanish
|
||||
|
||||
! Plugin Improvements
|
||||
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/commit/1be8f0a9336952d4745d2bd4f2327e353580a272">> Comments Plugin to use predefined palette colours
|
||||
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7785">> Evernote Importer Plugin to support images and other attachments
|
||||
|
||||
! Widget Improvements
|
||||
|
||||
*
|
||||
|
||||
! Usability Improvements
|
||||
|
||||
* <<.link-badge-updated "https://github.com/Jermolene/TiddlyWiki5/pull/7747">> editor preview button to automatically focus the editor
|
||||
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7764">> file type names in the export menu
|
||||
|
||||
! Hackability Improvements
|
||||
|
||||
*
|
||||
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7737">> an automatic build of the external core TiddlyWiki at https://tiddlywiki.com/empty-external-core.html
|
||||
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7690">> the default page layout to better support CSS grid and flexbox layouts
|
||||
|
||||
! Bug Fixes
|
||||
|
||||
*
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/7665">> `{{}}` generating a recursion error
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7758">> ordering of Vanilla stylesheets
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/commit/fa9bfa07a095548eb2f8339b0b1b816d2e6794ef">> missing closing tag in tag-pill-inner macro
|
||||
* <<.link-badge-removed "https://github.com/Jermolene/TiddlyWiki5/issues/7732">> invalid "type" attribute from textarea elements generated by the EditTextWidget
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7749">> editor "type" dropdown state tiddlers
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7712">> handling of "counter-last" variable when appending items with the ListWidget
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/6088">> upgrade download link in Firefox
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7698">> refreshing of transcluded functions
|
||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7789">> resizing of height of textareas in control panel
|
||||
|
||||
! Node.js Improvements
|
||||
|
||||
*
|
||||
|
||||
! Performance Improvements
|
||||
|
||||
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7702">> performance of predefined patterns with [[all Operator]]
|
||||
* <<.link-badge-updated "https://github.com/Jermolene/TiddlyWiki5/issues/7671">> favicon format to PNG
|
||||
|
||||
! Developer Improvements
|
||||
|
||||
*
|
||||
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7751">> global hook handling to support removing hooks
|
||||
|
||||
! Acknowledgements
|
||||
|
||||
@@ -39,22 +107,16 @@ Improvements to the following translations:
|
||||
|
||||
<<.contributors """
|
||||
AnthonyMuscio
|
||||
btheado
|
||||
catter-fly
|
||||
cmo-pomerium
|
||||
CrossEye
|
||||
flibbles
|
||||
hffqyd
|
||||
lilscribby
|
||||
BramChen
|
||||
BuckarooBanzay
|
||||
BurningTreeC
|
||||
EvidentlyCube
|
||||
joebordes
|
||||
kookma
|
||||
linonetwo
|
||||
Marxsal
|
||||
mateuszwilczek
|
||||
pille1842
|
||||
pmario
|
||||
rmunn
|
||||
saqimtiaz
|
||||
stevesunypoly
|
||||
TiddlyTweeter
|
||||
twMat
|
||||
yaisog
|
||||
simonbaird
|
||||
T1mL3arn
|
||||
""">>
|
||||
|
||||
|
Before Width: | Height: | Size: 118 KiB |
@@ -1,2 +0,0 @@
|
||||
title: $:/favicon.ico
|
||||
type: image/x-icon
|
||||
BIN
editions/prerelease/tiddlers/system/favicon.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
2
editions/prerelease/tiddlers/system/favicon.png.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
title: $:/favicon.ico
|
||||
type: image/png
|
||||
25
editions/test/playwright.spec.js
Normal file
@@ -0,0 +1,25 @@
|
||||
const { test, expect } = require('@playwright/test');
|
||||
const {resolve} = require('path');
|
||||
|
||||
const indexPath = resolve(__dirname, 'output', 'test.html');
|
||||
const crossPlatformIndexPath = indexPath.replace(/^\/+/, '');
|
||||
|
||||
|
||||
test('get started link', async ({ page }) => {
|
||||
// The tests can take a while to run
|
||||
const timeout = 1000 * 30;
|
||||
test.setTimeout(timeout);
|
||||
|
||||
// Load the generated test TW html
|
||||
await page.goto(`file:///${crossPlatformIndexPath}`);
|
||||
|
||||
// Sanity check
|
||||
await expect(page.locator('.tc-site-title'), "Expected correct page title to verify the test page was loaded").toHaveText('TiddlyWiki5');
|
||||
|
||||
// Wait for jasmine results bar to appear
|
||||
await expect(page.locator('.jasmine-overall-result'), "Expected jasmine test results bar to be present").toBeVisible({timeout});
|
||||
|
||||
// Assert the tests have passed
|
||||
await expect(page.locator('.jasmine-overall-result.jasmine-failed'), "Expected jasmine tests to not have failed").not.toBeVisible();
|
||||
await expect(page.locator('.jasmine-overall-result.jasmine-passed'), "Expected jasmine tests to have passed").toBeVisible();
|
||||
});
|
||||
26
editions/test/tiddlers/tests/data/conditionals/Basic.tid
Normal file
@@ -0,0 +1,26 @@
|
||||
title: Conditionals/Basic
|
||||
description: Basic conditional shortcut syntax
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Text
|
||||
|
||||
This is a <% if [<something>match[one]] %>Elephant<% endif %>, I think.
|
||||
+
|
||||
title: Output
|
||||
|
||||
<$let something="one">
|
||||
{{Text}}
|
||||
</$let>
|
||||
|
||||
<$let something="two">
|
||||
{{Text}}
|
||||
</$let>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>
|
||||
This is a Elephant, I think.
|
||||
</p><p>
|
||||
This is a , I think.
|
||||
</p>
|
||||
37
editions/test/tiddlers/tests/data/conditionals/BlockMode.tid
Normal file
@@ -0,0 +1,37 @@
|
||||
title: Conditionals/BlockMode
|
||||
description: Basic conditional shortcut syntax in block mode
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\procedure test(animal)
|
||||
<% if [<animal>match[Elephant]] %>
|
||||
|
||||
! It is an elephant
|
||||
|
||||
<% else %>
|
||||
|
||||
<% if [<animal>match[Giraffe]] %>
|
||||
|
||||
! It is a giraffe
|
||||
|
||||
<% else %>
|
||||
|
||||
! It is completely unknown
|
||||
|
||||
<% endif %>
|
||||
|
||||
<% endif %>
|
||||
|
||||
\end
|
||||
|
||||
<<test "Giraffe">>
|
||||
|
||||
<<test "Elephant">>
|
||||
|
||||
<<test "Antelope">>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<h1 class="">It is a giraffe</h1><h1 class="">It is an elephant</h1><h1 class="">It is completely unknown</h1>
|
||||
26
editions/test/tiddlers/tests/data/conditionals/Else.tid
Normal file
@@ -0,0 +1,26 @@
|
||||
title: Conditionals/Else
|
||||
description: Else conditional shortcut syntax
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Text
|
||||
|
||||
This is a <% if [<something>match[one]] %>Elephant<% else %>Crocodile<% endif %>, I think.
|
||||
+
|
||||
title: Output
|
||||
|
||||
<$let something="one">
|
||||
{{Text}}
|
||||
</$let>
|
||||
|
||||
<$let something="two">
|
||||
{{Text}}
|
||||
</$let>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>
|
||||
This is a Elephant, I think.
|
||||
</p><p>
|
||||
This is a Crocodile, I think.
|
||||
</p>
|
||||
32
editions/test/tiddlers/tests/data/conditionals/Elseif.tid
Normal file
@@ -0,0 +1,32 @@
|
||||
title: Conditionals/Elseif
|
||||
description: Elseif conditional shortcut syntax
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Text
|
||||
|
||||
This is a <% if [<something>match[one]] %>Elephant<% elseif [<something>match[two]] %>Antelope<% else %>Crocodile<% endif %>, I think.
|
||||
+
|
||||
title: Output
|
||||
|
||||
<$let something="one">
|
||||
{{Text}}
|
||||
</$let>
|
||||
|
||||
<$let something="two">
|
||||
{{Text}}
|
||||
</$let>
|
||||
|
||||
<$let something="three">
|
||||
{{Text}}
|
||||
</$let>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>
|
||||
This is a Elephant, I think.
|
||||
</p><p>
|
||||
This is a Antelope, I think.
|
||||
</p><p>
|
||||
This is a Crocodile, I think.
|
||||
</p>
|
||||
@@ -0,0 +1,26 @@
|
||||
title: Conditionals/MissingEndif
|
||||
description: Conditional shortcut syntax with missing endif
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Text
|
||||
|
||||
This is a <% if [<something>match[one]] %>Elephant
|
||||
+
|
||||
title: Output
|
||||
|
||||
<$let something="one">
|
||||
{{Text}}
|
||||
</$let>
|
||||
|
||||
<$let something="two">
|
||||
{{Text}}
|
||||
</$let>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>
|
||||
This is a Elephant
|
||||
</p><p>
|
||||
This is a
|
||||
</p>
|
||||
@@ -0,0 +1,12 @@
|
||||
title: Conditionals/MultipleResults
|
||||
description: Check that multiple results from the filter are ignored
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
This is a <% if 1 2 3 4 5 6 %>Elephant<% endif %>, I think.
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>This is a Elephant, I think.</p>
|
||||
38
editions/test/tiddlers/tests/data/conditionals/Nested.tid
Normal file
@@ -0,0 +1,38 @@
|
||||
title: Conditionals/Nested
|
||||
description: Nested conditional shortcut syntax
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\procedure test(animal)
|
||||
<% if [<animal>match[Elephant]] %>
|
||||
It is an elephant
|
||||
<% else %>
|
||||
<% if [<animal>match[Giraffe]] %>
|
||||
It is a giraffe
|
||||
<% else %>
|
||||
It is completely unknown
|
||||
<% endif %>
|
||||
<% endif %>
|
||||
\end
|
||||
|
||||
<<test "Giraffe">>
|
||||
|
||||
<<test "Elephant">>
|
||||
|
||||
<<test "Antelope">>
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
|
||||
|
||||
It is a giraffe
|
||||
|
||||
|
||||
It is an elephant
|
||||
|
||||
|
||||
It is completely unknown
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
title: Conditionals/NestedElseif
|
||||
description: Nested elseif conditional shortcut syntax
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Text
|
||||
|
||||
\whitespace trim
|
||||
This is a 
|
||||
<% if [<something>match[one]] %>
|
||||
<% if [<another>match[one]] %>
|
||||
Indian
|
||||
<% elseif [<another>match[two]] %>
|
||||
African
|
||||
<% else %>
|
||||
Unknown
|
||||
<% endif %>
|
||||
 Elephant
|
||||
<% elseif [<something>match[two]] %>
|
||||
Antelope
|
||||
<% else %>
|
||||
Crocodile
|
||||
<% endif %>
|
||||
, I think.
|
||||
+
|
||||
title: Output
|
||||
|
||||
<$let something="one" another="one">
|
||||
{{Text}}
|
||||
</$let>
|
||||
|
||||
<$let something="one" another="two">
|
||||
{{Text}}
|
||||
</$let>
|
||||
|
||||
<$let something="one" another="three">
|
||||
{{Text}}
|
||||
</$let>
|
||||
|
||||
<$let something="two">
|
||||
{{Text}}
|
||||
</$let>
|
||||
|
||||
<$let something="three">
|
||||
{{Text}}
|
||||
</$let>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>
|
||||
This is a Indian Elephant, I think.
|
||||
</p><p>
|
||||
This is a African Elephant, I think.
|
||||
</p><p>
|
||||
This is a Unknown Elephant, I think.
|
||||
</p><p>
|
||||
This is a Antelope, I think.
|
||||
</p><p>
|
||||
This is a Crocodile, I think.
|
||||
</p>
|
||||
@@ -0,0 +1,29 @@
|
||||
title: ListWidget/WithExplicitTemplates
|
||||
description: List widget with explicit templates
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
+
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
|
||||
\procedure test(filter)
|
||||
<$list filter=<<filter>>>
|
||||
<$list-template>
|
||||
<$text text=<<currentTiddler>>/>
|
||||
</$list-template>
|
||||
<$list-empty>
|
||||
None!
|
||||
</$list-empty>
|
||||
</$list>
|
||||
\end
|
||||
|
||||
<<test "1 2 3">>
|
||||
|
||||
<<test "">>
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>123</p><p>None!</p>
|
||||
@@ -0,0 +1,32 @@
|
||||
title: ListWidget/WithExplicitTemplatesInBlockMode
|
||||
description: List widget with explicit templates in block mode
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
+
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
|
||||
\procedure test(filter)
|
||||
<$list filter=<<filter>>>
|
||||
|
||||
<$list-template>
|
||||
<$text text=<<currentTiddler>>/>
|
||||
</$list-template>
|
||||
|
||||
<$list-empty>
|
||||
None!
|
||||
</$list-empty>
|
||||
|
||||
</$list>
|
||||
\end
|
||||
|
||||
<<test "1 2 3">>
|
||||
|
||||
<<test "">>
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
123None!
|
||||
@@ -0,0 +1,33 @@
|
||||
title: ListWidget/WithExplicitTemplatesOverriddenByAttributes
|
||||
description: List widget with explicit templates
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
+
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
|
||||
\procedure test(filter)
|
||||
<$list filter=<<filter>> emptyMessage="Zero" template="Template">
|
||||
<$list-template>
|
||||
<$text text=<<currentTiddler>>/>
|
||||
</$list-template>
|
||||
<$list-empty>
|
||||
None!
|
||||
</$list-empty>
|
||||
</$list>
|
||||
\end
|
||||
|
||||
<<test "1 2 3">>
|
||||
|
||||
<<test "">>
|
||||
|
||||
+
|
||||
title: Template
|
||||
|
||||
<$text text=<<currentTiddler>>/><$text text=<<currentTiddler>>/>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>112233</p><p>Zero</p>
|
||||
25
editions/test/tiddlers/tests/data/list-widget/WithLimit.tid
Normal file
@@ -0,0 +1,25 @@
|
||||
title: ListWidget/WithLimit
|
||||
description: List widget with limit
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
+
|
||||
title: Output
|
||||
|
||||
Zero: <$list filter="1 2 3 4" limit="0" template="Template"/>
|
||||
|
||||
One: <$list filter="1 2 3 4" limit="1" template="Template"/>
|
||||
|
||||
Two: <$list filter="1 2 3 4" limit="2" template="Template"/>
|
||||
|
||||
Minus Two: <$list filter="1 2 3 4" limit="-2" template="Template"/>
|
||||
|
||||
+
|
||||
title: Template
|
||||
|
||||
<$text text=<<currentTiddler>>/>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>Zero: </p><p>One: 1</p><p>Two: 12</p><p>Minus Two: 34
|
||||
</p>
|
||||
@@ -0,0 +1,26 @@
|
||||
title: ListWidget/WithMissingTemplate
|
||||
description: List widget with explicit templates
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
+
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
|
||||
\procedure test(filter)
|
||||
<$list filter=<<filter>>>
|
||||
<$list-empty>
|
||||
None!
|
||||
</$list-empty>
|
||||
</$list>
|
||||
\end
|
||||
|
||||
<<test "1 2 3">>
|
||||
|
||||
<<test "">>
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p><span><a class="tc-tiddlylink tc-tiddlylink-missing" href="#1">1</a></span><span><a class="tc-tiddlylink tc-tiddlylink-missing" href="#2">2</a></span><span><a class="tc-tiddlylink tc-tiddlylink-missing" href="#3">3</a></span></p><p>None!</p>
|
||||
@@ -0,0 +1,27 @@
|
||||
title: Transclude/Variable/Refreshing
|
||||
description: Transcluding and refreshing a function
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\function list-join(filter, sep:", ") [subfilter<filter>join<sep>]
|
||||
|
||||
<$tiddler tiddler="TestData">
|
||||
|
||||
<<list-join "[enlist{!!items}]">>
|
||||
|
||||
</$tiddler>
|
||||
|
||||
+
|
||||
title: TestData
|
||||
|
||||
|
||||
+
|
||||
title: Actions
|
||||
|
||||
<$action-setfield $tiddler="TestData" items={{{ [range[10]join[ ]] }}}/>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>1, 2, 3, 4, 5, 6, 7, 8, 9, 10</p>
|
||||
@@ -0,0 +1,15 @@
|
||||
title: Transclude/Variable/Static
|
||||
description: Transcluding a function
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
items: 1 2 3 4 5 6 7 8 9 10
|
||||
|
||||
\function list-join(filter, sep:", ") [subfilter<filter>join<sep>]
|
||||
|
||||
<<list-join "[enlist{!!items}]">>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>1, 2, 3, 4, 5, 6, 7, 8, 9, 10</p>
|
||||