mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-09-29 07:20:47 +00:00
Merge branch 'master' into geospatial-plugin
This commit is contained in:
commit
44736b6217
@ -18,16 +18,20 @@ Export our filter functions
|
|||||||
|
|
||||||
exports.decodebase64 = function(source,operator,options) {
|
exports.decodebase64 = function(source,operator,options) {
|
||||||
var results = [];
|
var results = [];
|
||||||
|
var binary = operator.suffixes && operator.suffixes.indexOf("binary") !== -1;
|
||||||
|
var urlsafe = operator.suffixes && operator.suffixes.indexOf("urlsafe") !== -1;
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
results.push($tw.utils.base64Decode(title));
|
results.push($tw.utils.base64Decode(title,binary,urlsafe));
|
||||||
});
|
});
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.encodebase64 = function(source,operator,options) {
|
exports.encodebase64 = function(source,operator,options) {
|
||||||
var results = [];
|
var results = [];
|
||||||
|
var binary = operator.suffixes && operator.suffixes.indexOf("binary") !== -1;
|
||||||
|
var urlsafe = operator.suffixes && operator.suffixes.indexOf("urlsafe") !== -1;
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
results.push($tw.utils.base64Encode(title));
|
results.push($tw.utils.base64Encode(title,binary,urlsafe));
|
||||||
});
|
});
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
@ -58,6 +58,7 @@ Last entry/entries in list
|
|||||||
exports.last = function(source,operator,options) {
|
exports.last = function(source,operator,options) {
|
||||||
var count = $tw.utils.getInt(operator.operand,1),
|
var count = $tw.utils.getInt(operator.operand,1),
|
||||||
results = [];
|
results = [];
|
||||||
|
if(count === 0) return results;
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
results.push(title);
|
results.push(title);
|
||||||
});
|
});
|
||||||
|
120
core/modules/parsers/wikiparser/rules/conditional.js
Normal file
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];
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
@ -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
|
terminatorRegExpString: optional regular expression string that identifies the end of plain paragraphs. Must not include capturing parenthesis
|
||||||
*/
|
*/
|
||||||
WikiParser.prototype.parseBlock = function(terminatorRegExpString) {
|
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();
|
this.skipWhitespace();
|
||||||
if(this.pos >= this.sourceLength) {
|
if(this.pos >= this.sourceLength) {
|
||||||
return [];
|
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) {
|
WikiParser.prototype.parseBlocksTerminated = function(terminatorRegExpString) {
|
||||||
var terminatorRegExp = new RegExp("(" + terminatorRegExpString + ")","mg"),
|
var ex = this.parseBlocksTerminatedExtended(terminatorRegExpString);
|
||||||
tree = [];
|
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
|
// Skip any whitespace
|
||||||
this.skipWhitespace();
|
this.skipWhitespace();
|
||||||
// Check if we've got the end marker
|
// Check if we've got the end marker
|
||||||
@ -277,7 +287,7 @@ WikiParser.prototype.parseBlocksTerminated = function(terminatorRegExpString) {
|
|||||||
// Parse the text into blocks
|
// Parse the text into blocks
|
||||||
while(this.pos < this.sourceLength && !(match && match.index === this.pos)) {
|
while(this.pos < this.sourceLength && !(match && match.index === this.pos)) {
|
||||||
var blocks = this.parseBlock(terminatorRegExpString);
|
var blocks = this.parseBlock(terminatorRegExpString);
|
||||||
tree.push.apply(tree,blocks);
|
result.tree.push.apply(result.tree,blocks);
|
||||||
// Skip any whitespace
|
// Skip any whitespace
|
||||||
this.skipWhitespace();
|
this.skipWhitespace();
|
||||||
// Check if we've got the end marker
|
// Check if we've got the end marker
|
||||||
@ -286,8 +296,9 @@ WikiParser.prototype.parseBlocksTerminated = function(terminatorRegExpString) {
|
|||||||
}
|
}
|
||||||
if(match && match.index === this.pos) {
|
if(match && match.index === this.pos) {
|
||||||
this.pos = match.index + match[0].length;
|
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) {
|
WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,options) {
|
||||||
|
var ex = this.parseInlineRunTerminatedExtended(terminatorRegExp,options);
|
||||||
|
return ex.tree;
|
||||||
|
};
|
||||||
|
|
||||||
|
WikiParser.prototype.parseInlineRunTerminatedExtended = function(terminatorRegExp,options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
var tree = [];
|
var tree = [];
|
||||||
// Find the next occurrence of the terminator
|
// Find the next occurrence of the terminator
|
||||||
@ -349,7 +365,10 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
|
|||||||
if(options.eatTerminator) {
|
if(options.eatTerminator) {
|
||||||
this.pos += terminatorMatch[0].length;
|
this.pos += terminatorMatch[0].length;
|
||||||
}
|
}
|
||||||
return tree;
|
return {
|
||||||
|
match: terminatorMatch,
|
||||||
|
tree: tree
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Process any inline rule, along with the text preceding it
|
// 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.pushTextWidget(tree,this.source.substr(this.pos),this.pos,this.sourceLength);
|
||||||
}
|
}
|
||||||
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 = {
|
headers = {
|
||||||
"Accept": "application/vnd.github.v3+json",
|
"Accept": "application/vnd.github.v3+json",
|
||||||
"Content-Type": "application/json;charset=UTF-8",
|
"Content-Type": "application/json;charset=UTF-8",
|
||||||
"Authorization": "Basic " + window.btoa(username + ":" + password),
|
"Authorization": "Basic " + $tw.utils.base64Encode(username + ":" + password),
|
||||||
"If-None-Match": ""
|
"If-None-Match": ""
|
||||||
};
|
};
|
||||||
// Bail if we don't have everything we need
|
// 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});
|
variables = $tw.utils.extend({},paramObject,{currentTiddler: title, "tv-window-id": windowID});
|
||||||
// Open the window
|
// Open the window
|
||||||
var srcWindow,
|
var srcWindow,
|
||||||
srcDocument;
|
srcDocument;
|
||||||
// In case that popup blockers deny opening a new window
|
// In case that popup blockers deny opening a new window
|
||||||
try {
|
try {
|
||||||
srcWindow = window.open("","external-" + windowID,"scrollbars,width=" + width + ",height=" + height + (top ? ",top=" + top : "" ) + (left ? ",left=" + left : "" )),
|
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;
|
$tw.windows[windowID] = srcWindow;
|
||||||
// Check for reopening the same window
|
// Check for reopening the same window
|
||||||
if(srcWindow.haveInitialisedWindow) {
|
if(srcWindow.haveInitialisedWindow) {
|
||||||
|
srcWindow.focus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Initialise the document
|
// Initialise the document
|
||||||
|
@ -187,7 +187,7 @@ HttpClientRequest.prototype.send = function(callback) {
|
|||||||
for (var i=0; i<len; i++) {
|
for (var i=0; i<len; i++) {
|
||||||
binary += String.fromCharCode(bytes[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),{
|
self.wiki.addTiddler(new $tw.Tiddler(self.wiki.getTiddler(requestTrackerTitle),{
|
||||||
status: completionCode,
|
status: completionCode,
|
||||||
|
@ -819,18 +819,41 @@ exports.hashString = function(str) {
|
|||||||
},0);
|
},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
|
Decode a base64 string
|
||||||
*/
|
*/
|
||||||
exports.base64Decode = function(string64) {
|
exports.base64Decode = function(string64,binary,urlsafe) {
|
||||||
return base64utf8.base64.decode.call(base64utf8,string64);
|
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
|
Encode a string to base64
|
||||||
*/
|
*/
|
||||||
exports.base64Encode = function(string64) {
|
exports.base64Encode = function(string64,binary,urlsafe) {
|
||||||
return base64utf8.base64.encode.call(base64utf8,string64);
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -58,24 +58,25 @@ ImageWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
if(this.wiki.isImageTiddler(this.imageSource)) {
|
if(this.wiki.isImageTiddler(this.imageSource)) {
|
||||||
var type = tiddler.fields.type,
|
var type = tiddler.fields.type,
|
||||||
text = tiddler.fields.text,
|
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 the tiddler has body text then it doesn't need to be lazily loaded
|
||||||
if(text) {
|
if(text) {
|
||||||
// Render the appropriate element for the image type
|
// Render the appropriate element for the image type by looking up the encoding in the content type info
|
||||||
switch(type) {
|
var encoding = typeInfo.encoding || "utf8";
|
||||||
case "application/pdf":
|
if (encoding === "base64") {
|
||||||
|
// .pdf .png .jpg etc.
|
||||||
|
src = "data:" + deserializerType + ";base64," + text;
|
||||||
|
if (deserializerType === "application/pdf") {
|
||||||
tag = "embed";
|
tag = "embed";
|
||||||
src = "data:application/pdf;base64," + text;
|
}
|
||||||
break;
|
} else {
|
||||||
case "image/svg+xml":
|
// .svg .tid .xml etc.
|
||||||
src = "data:image/svg+xml," + encodeURIComponent(text);
|
src = "data:" + deserializerType + "," + encodeURIComponent(text);
|
||||||
break;
|
|
||||||
default:
|
|
||||||
src = "data:" + type + ";base64," + text;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} else if(_canonical_uri) {
|
} else if(_canonical_uri) {
|
||||||
switch(type) {
|
switch(deserializerType) {
|
||||||
case "application/pdf":
|
case "application/pdf":
|
||||||
tag = "embed";
|
tag = "embed";
|
||||||
src = _canonical_uri;
|
src = _canonical_uri;
|
||||||
|
@ -60,6 +60,7 @@ ListWidget.prototype.render = function(parent,nextSibling) {
|
|||||||
Compute the internal state of the widget
|
Compute the internal state of the widget
|
||||||
*/
|
*/
|
||||||
ListWidget.prototype.execute = function() {
|
ListWidget.prototype.execute = function() {
|
||||||
|
var self = this;
|
||||||
// Get our attributes
|
// Get our attributes
|
||||||
this.template = this.getAttribute("template");
|
this.template = this.getAttribute("template");
|
||||||
this.editTemplate = this.getAttribute("editTemplate");
|
this.editTemplate = this.getAttribute("editTemplate");
|
||||||
@ -67,6 +68,8 @@ ListWidget.prototype.execute = function() {
|
|||||||
this.counterName = this.getAttribute("counter");
|
this.counterName = this.getAttribute("counter");
|
||||||
this.storyViewName = this.getAttribute("storyview");
|
this.storyViewName = this.getAttribute("storyview");
|
||||||
this.historyTitle = this.getAttribute("history");
|
this.historyTitle = this.getAttribute("history");
|
||||||
|
// Look for <$list-template> and <$list-empty> widgets as immediate child widgets
|
||||||
|
this.findExplicitTemplates();
|
||||||
// Compose the list elements
|
// Compose the list elements
|
||||||
this.list = this.getTiddlerList();
|
this.list = this.getTiddlerList();
|
||||||
var members = [],
|
var members = [],
|
||||||
@ -85,18 +88,48 @@ ListWidget.prototype.execute = function() {
|
|||||||
this.history = [];
|
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() {
|
ListWidget.prototype.getTiddlerList = function() {
|
||||||
|
var limit = $tw.utils.getInt(this.getAttribute("limit",""),undefined);
|
||||||
var defaultFilter = "[!is[system]sort[title]]";
|
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() {
|
ListWidget.prototype.getEmptyMessage = function() {
|
||||||
var parser,
|
var parser,
|
||||||
emptyMessage = this.getAttribute("emptyMessage","");
|
emptyMessage = this.getAttribute("emptyMessage");
|
||||||
// this.wiki.parseText() calls
|
// If emptyMessage attribute is not present or empty then look for an explicit empty template
|
||||||
// new Parser(..), which should only be done, if needed, because it's heavy!
|
if(!emptyMessage) {
|
||||||
if (emptyMessage === "") {
|
if(this.explicitEmptyTemplate) {
|
||||||
return [];
|
return this.explicitEmptyTemplate;
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
parser = this.wiki.parseText("text/vnd.tiddlywiki",emptyMessage,{parseAsInline: true});
|
parser = this.wiki.parseText("text/vnd.tiddlywiki",emptyMessage,{parseAsInline: true});
|
||||||
if(parser) {
|
if(parser) {
|
||||||
@ -122,12 +155,19 @@ ListWidget.prototype.makeItemTemplate = function(title,index) {
|
|||||||
if(template) {
|
if(template) {
|
||||||
templateTree = [{type: "transclude", attributes: {tiddler: {type: "string", value: template}}}];
|
templateTree = [{type: "transclude", attributes: {tiddler: {type: "string", value: template}}}];
|
||||||
} else {
|
} else {
|
||||||
|
// Check for child nodes of the list widget
|
||||||
if(this.parseTreeNode.children && this.parseTreeNode.children.length > 0) {
|
if(this.parseTreeNode.children && this.parseTreeNode.children.length > 0) {
|
||||||
templateTree = this.parseTreeNode.children;
|
// Check for a <$list-item> widget
|
||||||
} else {
|
if(this.explicitListTemplate) {
|
||||||
|
templateTree = this.explicitListTemplate;
|
||||||
|
} else if (!this.explicitEmptyTemplate) {
|
||||||
|
templateTree = this.parseTreeNode.children;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!templateTree) {
|
||||||
// Default template is a link to the title
|
// 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: [
|
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}
|
||||||
]}]}];
|
]}]}];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,6 +109,7 @@ TranscludeWidget.prototype.collectAttributes = function() {
|
|||||||
this.recursionMarker = this.getAttribute("recursionMarker","yes");
|
this.recursionMarker = this.getAttribute("recursionMarker","yes");
|
||||||
} else {
|
} else {
|
||||||
this.transcludeVariable = this.getAttribute("$variable");
|
this.transcludeVariable = this.getAttribute("$variable");
|
||||||
|
this.transcludeVariableIsFunction = false;
|
||||||
this.transcludeType = this.getAttribute("$type");
|
this.transcludeType = this.getAttribute("$type");
|
||||||
this.transcludeOutput = this.getAttribute("$output","text/html");
|
this.transcludeOutput = this.getAttribute("$output","text/html");
|
||||||
this.transcludeTitle = this.getAttribute("$tiddler",this.getVariable("currentTiddler"));
|
this.transcludeTitle = this.getAttribute("$tiddler",this.getVariable("currentTiddler"));
|
||||||
@ -184,7 +185,9 @@ TranscludeWidget.prototype.getTransclusionTarget = function() {
|
|||||||
if(this.transcludeVariable) {
|
if(this.transcludeVariable) {
|
||||||
// Transcluding a variable
|
// Transcluding a variable
|
||||||
var variableInfo = this.getVariableInfo(this.transcludeVariable,{params: this.getOrderedTransclusionParameters()});
|
var variableInfo = this.getVariableInfo(this.transcludeVariable,{params: this.getOrderedTransclusionParameters()});
|
||||||
|
this.transcludeVariableIsFunction = variableInfo.srcVariable && variableInfo.srcVariable.isFunctionDefinition;
|
||||||
text = variableInfo.text;
|
text = variableInfo.text;
|
||||||
|
this.transcludeFunctionResult = text;
|
||||||
return {
|
return {
|
||||||
text: variableInfo.text,
|
text: variableInfo.text,
|
||||||
type: this.transcludeType
|
type: this.transcludeType
|
||||||
@ -219,21 +222,24 @@ TranscludeWidget.prototype.parseTransclusionTarget = function(parseAsInline) {
|
|||||||
// Transcluding a variable
|
// Transcluding a variable
|
||||||
var variableInfo = this.getVariableInfo(this.transcludeVariable,{params: this.getOrderedTransclusionParameters()}),
|
var variableInfo = this.getVariableInfo(this.transcludeVariable,{params: this.getOrderedTransclusionParameters()}),
|
||||||
srcVariable = variableInfo && variableInfo.srcVariable;
|
srcVariable = variableInfo && variableInfo.srcVariable;
|
||||||
|
if(srcVariable && srcVariable.isFunctionDefinition) {
|
||||||
|
this.transcludeVariableIsFunction = true;
|
||||||
|
this.transcludeFunctionResult = (variableInfo.resultList ? variableInfo.resultList[0] : variableInfo.text) || "";
|
||||||
|
}
|
||||||
if(variableInfo.text) {
|
if(variableInfo.text) {
|
||||||
if(srcVariable && srcVariable.isFunctionDefinition) {
|
if(srcVariable && srcVariable.isFunctionDefinition) {
|
||||||
var result = (variableInfo.resultList ? variableInfo.resultList[0] : variableInfo.text) || "";
|
|
||||||
parser = {
|
parser = {
|
||||||
tree: [{
|
tree: [{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: result
|
text: this.transcludeFunctionResult
|
||||||
}],
|
}],
|
||||||
source: result,
|
source: this.transcludeFunctionResult,
|
||||||
type: "text/vnd.tiddlywiki"
|
type: "text/vnd.tiddlywiki"
|
||||||
};
|
};
|
||||||
if(parseAsInline) {
|
if(parseAsInline) {
|
||||||
parser.tree[0] = {
|
parser.tree[0] = {
|
||||||
type: "text",
|
type: "text",
|
||||||
text: result
|
text: this.transcludeFunctionResult
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
parser.tree[0] = {
|
parser.tree[0] = {
|
||||||
@ -241,7 +247,7 @@ TranscludeWidget.prototype.parseTransclusionTarget = function(parseAsInline) {
|
|||||||
tag: "p",
|
tag: "p",
|
||||||
children: [{
|
children: [{
|
||||||
type: "text",
|
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)
|
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
|
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||||
*/
|
*/
|
||||||
TranscludeWidget.prototype.refresh = function(changedTiddlers) {
|
TranscludeWidget.prototype.refresh = function(changedTiddlers) {
|
||||||
var changedAttributes = this.computeAttributes();
|
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();
|
this.refreshSelf();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -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="$:/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="$:/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="$:/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="$:/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/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/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/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}} |
|
|<$link to="$:/config/AutoFocus"><<lingo AutoFocus/Prompt>></$link> |{{$:/snippets/minifocusswitcher}} |
|
||||||
|
@ -18,7 +18,7 @@ $:/config/EditorToolbarButtons/Visibility/$(currentTiddler)$
|
|||||||
importState=<<qualify $:/state/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>> >
|
<$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>> >
|
||||||
<div>
|
<div>
|
||||||
<div class={{{ [function[edit-preview-state]match[yes]then[tc-tiddler-preview]] +[join[ ]] }}}>
|
<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"/>
|
<$transclude tiddler="$:/core/ui/EditTemplate/body/editor" mode="inline"/>
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ $value={{{ [subfilter<get-field-value-tiddler-filter>get[text]] }}}/>
|
|||||||
</td>
|
</td>
|
||||||
<td class="tc-edit-field-remove">
|
<td class="tc-edit-field-remove">
|
||||||
<$button class="tc-btn-invisible" tooltip={{$:/language/EditTemplate/Field/Remove/Hint}} aria-label={{$:/language/EditTemplate/Field/Remove/Caption}}>
|
<$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}}
|
{{$:/core/images/delete-button}}
|
||||||
</$button>
|
</$button>
|
||||||
</td>
|
</td>
|
||||||
|
@ -118,7 +118,7 @@ tags: $:/tags/Macro
|
|||||||
<$set name="toc-item-class" filter=<<__itemClassFilter__>> emptyValue="toc-item-selected" value="toc-item" >
|
<$set name="toc-item-class" filter=<<__itemClassFilter__>> emptyValue="toc-item-selected" value="toc-item" >
|
||||||
<li class=<<toc-item-class>>>
|
<li class=<<toc-item-class>>>
|
||||||
<$link to={{{ [<currentTiddler>get[target]else<currentTiddler>] }}}>
|
<$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">
|
<$reveal type="nomatch" stateTitle=<<toc-state>> text="open">
|
||||||
<$button setTitle=<<toc-state>> setTo="open" class="tc-btn-invisible tc-popup-keep">
|
<$button setTitle=<<toc-state>> setTo="open" class="tc-btn-invisible tc-popup-keep">
|
||||||
<$transclude tiddler=<<toc-closed-icon>> />
|
<$transclude tiddler=<<toc-closed-icon>> />
|
||||||
@ -145,7 +145,7 @@ tags: $:/tags/Macro
|
|||||||
<$qualify name="toc-state" title={{{ [[$:/state/toc]addsuffix<__path__>addsuffix[-]addsuffix<currentTiddler>] }}}>
|
<$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">
|
<$set name="toc-item-class" filter=<<__itemClassFilter__>> emptyValue="toc-item-selected" value="toc-item">
|
||||||
<li class=<<toc-item-class>>>
|
<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">
|
<$reveal type="nomatch" stateTitle=<<toc-state>> text="open">
|
||||||
<$button setTitle=<<toc-state>> setTo="open" class="tc-btn-invisible tc-popup-keep">
|
<$button setTitle=<<toc-state>> setTo="open" class="tc-btn-invisible tc-popup-keep">
|
||||||
<$transclude tiddler=<<toc-closed-icon>> />
|
<$transclude tiddler=<<toc-closed-icon>> />
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
caption: 5.3.2
|
caption: 5.3.2
|
||||||
created: 20230820114855583
|
created: 20231016122502955
|
||||||
modified: 20230820114855583
|
modified: 20231016122502955
|
||||||
tags: ReleaseNotes
|
tags: ReleaseNotes
|
||||||
title: Release 5.3.2
|
title: Release 5.3.2
|
||||||
type: text/vnd.tiddlywiki
|
type: text/vnd.tiddlywiki
|
||||||
@ -8,6 +8,47 @@ description: Under development
|
|||||||
|
|
||||||
//[[See GitHub for detailed change history of this release|https://github.com/Jermolene/TiddlyWiki5/compare/v5.3.1...master]]//
|
//[[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
|
! Translation improvement
|
||||||
|
|
||||||
Improvements to the following translations:
|
Improvements to the following translations:
|
||||||
@ -18,7 +59,8 @@ Improvements to the following translations:
|
|||||||
|
|
||||||
! Plugin Improvements
|
! Plugin Improvements
|
||||||
|
|
||||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/commit/1be8f0a9336952d4745d2bd4f2327e353580a272">> comments plugin to use predefined palette colours
|
* <<.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
|
! Widget Improvements
|
||||||
|
|
||||||
@ -43,6 +85,8 @@ Improvements to the following translations:
|
|||||||
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7749">> editor "type" dropdown state tiddlers
|
* <<.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/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/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
|
! Node.js Improvements
|
||||||
|
|
||||||
|
26
editions/test/tiddlers/tests/data/conditionals/Basic.tid
Normal file
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
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
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
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
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
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>
|
@ -365,6 +365,7 @@ Tests the filtering mechanism.
|
|||||||
expect(wiki.filterTiddlers("[sort[title]first[8]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,a fourth tiddler,filter regexp test,has filter,hasList,one,Tiddler Three");
|
expect(wiki.filterTiddlers("[sort[title]first[8]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,a fourth tiddler,filter regexp test,has filter,hasList,one,Tiddler Three");
|
||||||
expect(wiki.filterTiddlers("[sort[title]first[x]]").join(",")).toBe("$:/ShadowPlugin");
|
expect(wiki.filterTiddlers("[sort[title]first[x]]").join(",")).toBe("$:/ShadowPlugin");
|
||||||
expect(wiki.filterTiddlers("[sort[title]last[]]").join(",")).toBe("TiddlerOne");
|
expect(wiki.filterTiddlers("[sort[title]last[]]").join(",")).toBe("TiddlerOne");
|
||||||
|
expect(wiki.filterTiddlers("[sort[title]last[0]]").join(",")).toBe("");
|
||||||
expect(wiki.filterTiddlers("[sort[title]last[2]]").join(",")).toBe("Tiddler Three,TiddlerOne");
|
expect(wiki.filterTiddlers("[sort[title]last[2]]").join(",")).toBe("Tiddler Three,TiddlerOne");
|
||||||
expect(wiki.filterTiddlers("[sort[title]last[8]]").join(",")).toBe("$:/TiddlerTwo,a fourth tiddler,filter regexp test,has filter,hasList,one,Tiddler Three,TiddlerOne");
|
expect(wiki.filterTiddlers("[sort[title]last[8]]").join(",")).toBe("$:/TiddlerTwo,a fourth tiddler,filter regexp test,has filter,hasList,one,Tiddler Three,TiddlerOne");
|
||||||
expect(wiki.filterTiddlers("[sort[title]last[x]]").join(",")).toBe("TiddlerOne");
|
expect(wiki.filterTiddlers("[sort[title]last[x]]").join(",")).toBe("TiddlerOne");
|
||||||
|
@ -48,6 +48,29 @@ describe("Utility tests", function() {
|
|||||||
expect($tw.utils.base64Decode($tw.utils.base64Encode(booksEmoji))).toBe(booksEmoji, "should round-trip correctly");
|
expect($tw.utils.base64Decode($tw.utils.base64Encode(booksEmoji))).toBe(booksEmoji, "should round-trip correctly");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should handle base64 encoding emojis in URL-safe variant", function() {
|
||||||
|
var booksEmoji = "📚";
|
||||||
|
expect($tw.utils.base64Encode(booksEmoji, false, true)).toBe("8J-Tmg==", "if surrogate pairs are correctly treated as a single code unit then base64 should be 8J+Tmg==");
|
||||||
|
expect($tw.utils.base64Decode("8J-Tmg==", false, true)).toBe(booksEmoji);
|
||||||
|
expect($tw.utils.base64Decode($tw.utils.base64Encode(booksEmoji, false, true), false, true)).toBe(booksEmoji, "should round-trip correctly");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle base64 encoding binary data", function() {
|
||||||
|
var binaryData = "\xff\xfe\xfe\xff";
|
||||||
|
var encoded = $tw.utils.base64Encode(binaryData,true);
|
||||||
|
expect(encoded).toBe("//7+/w==");
|
||||||
|
var decoded = $tw.utils.base64Decode(encoded,true);
|
||||||
|
expect(decoded).toBe(binaryData, "Binary data did not round-trip correctly");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle base64 encoding binary data in URL-safe variant", function() {
|
||||||
|
var binaryData = "\xff\xfe\xfe\xff";
|
||||||
|
var encoded = $tw.utils.base64Encode(binaryData,true,true);
|
||||||
|
expect(encoded).toBe("__7-_w==");
|
||||||
|
var decoded = $tw.utils.base64Decode(encoded,true,true);
|
||||||
|
expect(decoded).toBe(binaryData, "Binary data did not round-trip correctly");
|
||||||
|
});
|
||||||
|
|
||||||
it("should handle stringifying a string array", function() {
|
it("should handle stringifying a string array", function() {
|
||||||
var str = $tw.utils.stringifyList;
|
var str = $tw.utils.stringifyList;
|
||||||
expect(str([])).toEqual("");
|
expect(str([])).toEqual("");
|
||||||
|
20
editions/tw5.com/tiddlers/community/Chinese Community.tid
Normal file
20
editions/tw5.com/tiddlers/community/Chinese Community.tid
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
title: 中文社区 - Chinese Community
|
||||||
|
tags: Community
|
||||||
|
|
||||||
|
# A Chinese community tutorial program that people can edit together:
|
||||||
|
#* Main site: [ext[https://tw-cn.netlify.app/]]
|
||||||
|
#* Accelerated access: [ext[https://tw-cn.cpolar.top/]]
|
||||||
|
#* Alternate: [ext[https://tiddly-wiki-chinese-tutorial.vercel.app]]
|
||||||
|
# Tiddlywiki Chinese Chat Forum: [ext[https://talk.tidgi.fun/topic/6]]
|
||||||
|
# Chinese translation of Tiddlywiki official website [ext[https://bramchen.github.io/tw5-docs/zh-Hans/]]
|
||||||
|
# The best Chinese introductory tutorial for newbies [ext[https://keatonlao.github.io/tiddlywiki-xp/]]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 大家可以一起编辑的中文社区教程项目:
|
||||||
|
#* 主站:[ext[https://tw-cn.netlify.app/]]
|
||||||
|
#* 加速访问:[ext[https://tw-cn.cpolar.top/]]
|
||||||
|
#* 备用:[ext[https://tiddly-wiki-chinese-tutorial.vercel.app]]
|
||||||
|
# 太微中文交流论坛:[ext[https://talk.tidgi.fun/topic/6]]
|
||||||
|
# 太微官网汉化版:[ext[https://bramchen.github.io/tw5-docs/zh-Hans/]]
|
||||||
|
# 最适合新手的中文入门教程:[ext[https://keatonlao.github.io/tiddlywiki-xp/]]
|
@ -1,16 +0,0 @@
|
|||||||
created: 20220417010615742
|
|
||||||
modified: 20220417011547812
|
|
||||||
tags: [[Community Plugins]] [[Community Editions]] Resources
|
|
||||||
title: TiddlyMemo by oflg
|
|
||||||
type: text/vnd.tiddlywiki
|
|
||||||
url: https://tiddlymemo.org/
|
|
||||||
|
|
||||||
Lifelong knowledge, deep in the Sea of Mind.
|
|
||||||
|
|
||||||
{{!!url}}
|
|
||||||
|
|
||||||
~TiddlyMemo uses advanced [[Incremental Learning|https://help.supermemo.org/wiki/Incremental_learning]] concepts to make it your powerful second brain for acquiring lifelong knowledge.
|
|
||||||
|
|
||||||
* [[Read Articles|https://tiddlymemo.org/#Read%20Articles]] like ~SuperMemo
|
|
||||||
* [[Learn languages|https://tiddlymemo.org/#Learn%20languages]] like ~LingQ
|
|
||||||
* [[Memory Notes|https://tiddlymemo.org/#Memory%20Notes]] like Anki
|
|
@ -0,0 +1,16 @@
|
|||||||
|
created: 20220417010615742
|
||||||
|
modified: 20231005060241771
|
||||||
|
tags: [[Community Editions]]
|
||||||
|
title: Tidme by oflg
|
||||||
|
type: text/vnd.tiddlywiki
|
||||||
|
url: https://github.com/oflg/Tidme
|
||||||
|
|
||||||
|
Lifelong knowledge, deep in Mind.
|
||||||
|
|
||||||
|
{{!!url}}
|
||||||
|
|
||||||
|
Tidme uses advanced [[Incremental Learning|https://help.supermemo.org/wiki/Incremental_learning]] concepts to make it your powerful second brain for acquiring lifelong knowledge.
|
||||||
|
|
||||||
|
* Read Articles like SuperMemo
|
||||||
|
* Learn languages like LingQ
|
||||||
|
* Memory Notes like Anki
|
@ -0,0 +1,10 @@
|
|||||||
|
created: 20220417010615742
|
||||||
|
modified: 20231005060241771
|
||||||
|
tags: [[Community Plugins]]
|
||||||
|
title: Free Spaced Repetition Scheduler for TiddlyWiki by oflg
|
||||||
|
type: text/vnd.tiddlywiki
|
||||||
|
url: https://github.com/open-spaced-repetition/fsrs4tw
|
||||||
|
|
||||||
|
TiddlyWiki-based memory programme using advanced FSRS algorithm
|
||||||
|
|
||||||
|
{{!!url}}
|
@ -1,6 +1,7 @@
|
|||||||
caption: decodebase64
|
caption: decodebase64
|
||||||
op-input: a [[selection of titles|Title Selection]]
|
op-input: a [[selection of titles|Title Selection]]
|
||||||
op-output: the input with base 64 decoding applied
|
op-output: the input with base 64 decoding applied
|
||||||
|
op-suffix: optional: `binary` to produce binary output, `urlsafe` for URL-safe input
|
||||||
op-parameter:
|
op-parameter:
|
||||||
op-parameter-name:
|
op-parameter-name:
|
||||||
op-purpose: apply base 64 decoding to a string
|
op-purpose: apply base 64 decoding to a string
|
||||||
@ -11,6 +12,10 @@ from-version: 5.2.6
|
|||||||
|
|
||||||
See Mozilla Developer Network for details of [[base 64 encoding|https://developer.mozilla.org/en-US/docs/Glossary/Base64]]. TiddlyWiki uses [[library code from @nijikokun|https://gist.github.com/Nijikokun/5192472]] to handle the conversion.
|
See Mozilla Developer Network for details of [[base 64 encoding|https://developer.mozilla.org/en-US/docs/Glossary/Base64]]. TiddlyWiki uses [[library code from @nijikokun|https://gist.github.com/Nijikokun/5192472]] to handle the conversion.
|
||||||
|
|
||||||
The input strings must be base64 encoded. The output strings are binary data.
|
The input strings must be base64 encoded. The output strings are the text (or binary data) decoded from base64 format.
|
||||||
|
|
||||||
|
The optional `binary` suffix, if present, changes how the input is processed. The input is normally assumed to be [[UTF-8|https://developer.mozilla.org/en-US/docs/Glossary/UTF-8]] text encoded in base64 form (such as what the <<.op "encodebase64">> operator produces), so only certain byte sequences in the input are valid. If the input is binary data encoded in base64 format (such as an image, audio file, video file, etc.), then use the optional `binary` suffix, which will allow all byte sequences. Note that the output will then be binary, ''not'' text, and should probably not be passed into further filter operators.
|
||||||
|
|
||||||
|
The optional `urlsafe` suffix, if present, causes the decoder to assume that the base64 input uses `-` and `_` instead of `+` and `/` for the 62nd and 63rd characters of the base64 "alphabet", which is usually referred to as "URL-safe base64" or "bae64url".
|
||||||
|
|
||||||
<<.operator-examples "decodebase64">>
|
<<.operator-examples "decodebase64">>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
caption: encodebase64
|
caption: encodebase64
|
||||||
op-input: a [[selection of titles|Title Selection]]
|
op-input: a [[selection of titles|Title Selection]]
|
||||||
op-output: the input with base 64 encoding applied
|
op-output: the input with base 64 encoding applied
|
||||||
|
op-suffix: optional: `binary` to treat input as binary data, `urlsafe` for URL-safe output
|
||||||
op-parameter:
|
op-parameter:
|
||||||
op-parameter-name:
|
op-parameter-name:
|
||||||
op-purpose: apply base 64 encoding to a string
|
op-purpose: apply base 64 encoding to a string
|
||||||
@ -11,6 +12,10 @@ from-version: 5.2.6
|
|||||||
|
|
||||||
See Mozilla Developer Network for details of [[base 64 encoding|https://developer.mozilla.org/en-US/docs/Glossary/Base64]]. TiddlyWiki uses [[library code from @nijikokun|https://gist.github.com/Nijikokun/5192472]] to handle the conversion.
|
See Mozilla Developer Network for details of [[base 64 encoding|https://developer.mozilla.org/en-US/docs/Glossary/Base64]]. TiddlyWiki uses [[library code from @nijikokun|https://gist.github.com/Nijikokun/5192472]] to handle the conversion.
|
||||||
|
|
||||||
The input strings are interpreted as binary data. The output strings are base64 encoded.
|
The input strings are interpreted as [[UTF-8 encoded|https://developer.mozilla.org/en-US/docs/Glossary/UTF-8]] text (or binary data instead if the `binary` suffix is present). The output strings are base64 encoded.
|
||||||
|
|
||||||
|
The optional `binary` suffix, if present, causes the input string to be interpreted as binary data instead of text. Normally, an extra UTF-8 encoding step will be added before the base64 output is produced, so that emojis and other Unicode characters will be encoded correctly. If the input is binary data, such as an image, audio file, video, etc., then the UTF-8 encoding step would produce incorrect results, so using the `binary` suffix causes the UTF-8 encoding step to be skipped.
|
||||||
|
|
||||||
|
The optional `urlsafe` suffix, if present, will use the alternate "URL-safe" base64 encoding, where `-` and `_` are used instead of `+` and `/` respectively, allowing the result to be used in URL query parameters or filenames.
|
||||||
|
|
||||||
<<.operator-examples "encodebase64">>
|
<<.operator-examples "encodebase64">>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
created: 20230405101444090
|
created: 20230915121010948
|
||||||
modified: 20230405101444090
|
modified: 20230915121010948
|
||||||
tags: [[Filter Operators]] [[JSON Operators]]
|
tags: [[Filter Operators]] [[JSON Operators]]
|
||||||
title: jsonset Operator
|
title: jsonset Operator
|
||||||
caption: jsonset
|
caption: jsonset
|
||||||
@ -8,7 +8,7 @@ op-input: a selection of JSON strings
|
|||||||
op-parameter: one or more indexes of the property to retrieve and sometimes a value to assign
|
op-parameter: one or more indexes of the property to retrieve and sometimes a value to assign
|
||||||
op-output: the JSON strings with the specified property assigned
|
op-output: the JSON strings with the specified property assigned
|
||||||
|
|
||||||
<<.from-version "5.3.0">> See [[JSON in TiddlyWiki]] for background.
|
<<.from-version "5.3.2">> See [[JSON in TiddlyWiki]] for background.
|
||||||
|
|
||||||
The <<.op jsonset>> operator is used to set a property value in JSON strings. See also the following related operators:
|
The <<.op jsonset>> operator is used to set a property value in JSON strings. See also the following related operators:
|
||||||
|
|
||||||
|
@ -34,6 +34,11 @@ TiddlyWiki lets you choose where to keep your data, guaranteeing that in the dec
|
|||||||
<$macrocall $name="flex-card" bordercolor={{!!color}} textcolor={{!!text-color}} backgroundcolor={{!!background-color}} captionField="caption" descriptionField="text"/>
|
<$macrocall $name="flex-card" bordercolor={{!!color}} textcolor={{!!text-color}} backgroundcolor={{!!background-color}} captionField="caption" descriptionField="text"/>
|
||||||
</$list>
|
</$list>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="tc-cards tc-small">
|
||||||
|
<$link to="中文社区 - Chinese Community" class="tc-btn-big-green tc-card">
|
||||||
|
中文社区 - Chinese Community
|
||||||
|
</$link>
|
||||||
|
</div>
|
||||||
|
|
||||||
!! ''Find Out More''
|
!! ''Find Out More''
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
caption: tm-open-window
|
caption: tm-open-window
|
||||||
created: 20160424181447704
|
created: 20160424181447704
|
||||||
modified: 20220301162140993
|
modified: 20230831201518773
|
||||||
tags: Messages
|
tags: Messages
|
||||||
title: WidgetMessage: tm-open-window
|
title: WidgetMessage: tm-open-window
|
||||||
type: text/vnd.tiddlywiki
|
type: text/vnd.tiddlywiki
|
||||||
@ -20,10 +20,17 @@ The `tm-open-window` [[message|Messages]] opens a tiddler in a new //browser// w
|
|||||||
|
|
||||||
The `tm-open-window` message is best generated with the ActionSendMessageWidget, which in turn is triggered by a widget such as the ButtonWidget. The message is handled by the core itself.
|
The `tm-open-window` message is best generated with the ActionSendMessageWidget, which in turn is triggered by a widget such as the ButtonWidget. The message is handled by the core itself.
|
||||||
|
|
||||||
<<.tip """When used with the ActionSendMessageWidget, <<.param 'param'>> becomes <<.param '$param'>> """>>
|
<<.tip """When used with the ActionSendMessageWidget, <<.param 'param'>> becomes <<.param '$param'>>.<br>
|
||||||
<<.tip """Parameters <<.param template>>, <<.param windowTitle>>, <<.param width>>, <<.param height>>, <<.param left>> and <<.param top>> require the ActionSendMessageWidget.""">>
|
Parameters <<.param template>>, <<.param windowTitle>>, <<.param width>>, <<.param height>>, <<.param left>> and <<.param top>> require the ActionSendMessageWidget. """>>
|
||||||
<<.tip """<<.from-version 5.2.2>> To close a window opened with tm-open-window use [[WidgetMessage: tm-close-window]]""">>
|
|
||||||
<<.tip """<<.from-version 5.2.2>> To open a tiddler in more than one new window, use a unique value for <<.param windowID>>""">>
|
<<.tip """<<.from-version 5.2.2>>
|
||||||
|
To close a window opened with tm-open-window use [[WidgetMessage: tm-close-window]]<br>
|
||||||
|
To open a tiddler in more than one new window, use a unique value for <<.param windowID>>
|
||||||
|
""">>
|
||||||
|
|
||||||
|
<<.tip """<<.from-version 5.3.2>>
|
||||||
|
If the new window is hidden by other windows, clicking the "open" button again will bring it to the foreground and set focus to the new window. This behaviour should be consistent for all browsers now
|
||||||
|
""">>
|
||||||
|
|
||||||
<$macrocall $name='wikitext-example-without-html'
|
<$macrocall $name='wikitext-example-without-html'
|
||||||
src="""
|
src="""
|
||||||
|
@ -147,6 +147,10 @@ type: text/vnd.tiddlywiki
|
|||||||
gap: 1em;
|
gap: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tc-cards.tc-small {
|
||||||
|
font-size: 0.7em;
|
||||||
|
}
|
||||||
|
|
||||||
.tc-cards.tc-action-card {
|
.tc-cards.tc-action-card {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background: none;
|
background: none;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
caption: list
|
caption: list
|
||||||
created: 20131024141900000
|
created: 20131024141900000
|
||||||
modified: 20230725203601441
|
modified: 20230831182949930
|
||||||
tags: Widgets Lists
|
tags: Widgets Lists
|
||||||
title: ListWidget
|
title: ListWidget
|
||||||
type: text/vnd.tiddlywiki
|
type: text/vnd.tiddlywiki
|
||||||
@ -70,6 +70,8 @@ See GroupedLists for how to generate nested and grouped lists using the ListWidg
|
|||||||
|
|
||||||
The content of the `<$list>` widget is an optional template to use for rendering each tiddler in the list.
|
The content of the `<$list>` widget is an optional template to use for rendering each tiddler in the list.
|
||||||
|
|
||||||
|
<<.from-version "5.3.2">> If the widgets `<$list-template>` or `<$list-empty>` are found as immediate children of the <<.wid "ListWidget">> widget then the content of those widgets are used as the list item template and/or the empty template. Note that the <<.attr "emptyMessage">> and <<.attr "template">> attributes take precedence if they are present.
|
||||||
|
|
||||||
The action of the list widget depends on the results of the filter combined with several options for specifying the template:
|
The action of the list widget depends on the results of the filter combined with several options for specifying the template:
|
||||||
|
|
||||||
* If the filter evaluates to an empty list, the text of the ''emptyMessage'' attribute is rendered, and all other templates are ignored
|
* If the filter evaluates to an empty list, the text of the ''emptyMessage'' attribute is rendered, and all other templates are ignored
|
||||||
@ -79,6 +81,7 @@ The action of the list widget depends on the results of the filter combined with
|
|||||||
|
|
||||||
|!Attribute |!Description |
|
|!Attribute |!Description |
|
||||||
|filter |The [[tiddler filter|Filters]] to display |
|
|filter |The [[tiddler filter|Filters]] to display |
|
||||||
|
|limit |<<.from-version "5.3.2">> Optional numeric limit for the number of results that are returned. Negative values will return the results from the end of the list |
|
||||||
|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. |
|
|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 |
|
|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'' |
|
|variable |The name for a [[variable|Variables]] in which the title of each listed tiddler is stored. Defaults to ''currentTiddler'' |
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
created: 20230901122740573
|
||||||
|
modified: 20230901123102263
|
||||||
|
tags: WikiText
|
||||||
|
title: Conditional Shortcut Syntax
|
||||||
|
type: text/vnd.tiddlywiki
|
||||||
|
|
||||||
|
<<.from-version "5.3.2">> The conditional shortcut syntax provides a convenient way to express if-then-else logic within WikiText. It evaluates a filter and considers the condition to be true if there is at least one result (regardless of the value of that result).
|
||||||
|
|
||||||
|
A simple example:
|
||||||
|
|
||||||
|
<$macrocall $name='wikitext-example-without-html'
|
||||||
|
src='<% if [{$:/$:/info/url/protocol}match[file:]] %>
|
||||||
|
Loaded from a file URI
|
||||||
|
<% else %>
|
||||||
|
Not loaded from a file URI
|
||||||
|
<% endif %>
|
||||||
|
'/>
|
||||||
|
|
||||||
|
One or more `<% elseif %>` clauses may be included before the `<% else %>` clause:
|
||||||
|
|
||||||
|
<$macrocall $name='wikitext-example-without-html'
|
||||||
|
src='<% if [{$:/$:/info/url/protocol}match[file:]] %>
|
||||||
|
Loaded from a file URI
|
||||||
|
<% elseif [{$:/$:/info/url/protocol}match[https:]] %>
|
||||||
|
Loaded from an HTTPS URI
|
||||||
|
<% elseif [{$:/$:/info/url/protocol}match[http:]] %>
|
||||||
|
Loaded from an HTTP URI
|
||||||
|
<% else %>
|
||||||
|
Loaded from an unknown protocol
|
||||||
|
<% endif %>
|
||||||
|
'/>
|
||||||
|
|
||||||
|
The conditional shortcut syntax can be nested:
|
||||||
|
|
||||||
|
<$macrocall $name='wikitext-example-without-html'
|
||||||
|
src='\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">>
|
||||||
|
'/>
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
* Clauses are parsed in inline mode by default. Force block mode parsing by following the opening `<% if %>`, `<% elseif %>` or `<% else %>` with two line breaks
|
||||||
|
* Within an "if" or "elseif" clause, the variable `condition` contains the value of the first result of evaluating the filter condition
|
||||||
|
* Widgets and HTML elements must be within a single conditional clause; it is not possible to start an element in one conditional clause and end it in another
|
||||||
|
* The conditional shortcut syntax cannot contain pragmas such as procedure definitions
|
||||||
|
|
@ -6,7 +6,8 @@
|
|||||||
"tiddlywiki/railroad",
|
"tiddlywiki/railroad",
|
||||||
"tiddlywiki/evernote",
|
"tiddlywiki/evernote",
|
||||||
"tiddlywiki/internals",
|
"tiddlywiki/internals",
|
||||||
"tiddlywiki/menubar"
|
"tiddlywiki/menubar",
|
||||||
|
"tiddlywiki/qrcode"
|
||||||
],
|
],
|
||||||
"themes": [
|
"themes": [
|
||||||
"tiddlywiki/vanilla",
|
"tiddlywiki/vanilla",
|
||||||
|
@ -3,5 +3,5 @@ title: $:/language/Exporters/
|
|||||||
StaticRiver: Statyczny HTML
|
StaticRiver: Statyczny HTML
|
||||||
JsonFile: Plik JSON
|
JsonFile: Plik JSON
|
||||||
CsvFile: Plik CSV
|
CsvFile: Plik CSV
|
||||||
TidFile: Plik ".tid"
|
TidFile: Plik tekstowy TID
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@ Wspierane argumenty:
|
|||||||
** `yes` rozdzieli wtyczki na osobne pliki tiddlerów i zapisze je do podfolderu z wtyczkami
|
** `yes` rozdzieli wtyczki na osobne pliki tiddlerów i zapisze je do podfolderu z wtyczkami
|
||||||
** `no` każda wtyczka będzie zapisana jako jeden zbiorczy plik w formacie JSON w folderze z tiddlerami
|
** `no` każda wtyczka będzie zapisana jako jeden zbiorczy plik w formacie JSON w folderze z tiddlerami
|
||||||
|
|
||||||
|
Obie wartości dla `explodePlugins` stworzą taką samą wiki. Różnica będzie jedynie w sposobie rozlokowania wtyczek.
|
||||||
|
|
||||||
Typowe zastosowanie to konwersja pliku TiddlyWiki w formie pliku HTML do formatu folderu:
|
Typowe zastosowanie to konwersja pliku TiddlyWiki w formie pliku HTML do formatu folderu:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -551,3 +551,5 @@ Eric Haberstroh, @pille1842, 2023/07/23
|
|||||||
BuckarooBanzay, @BuckarooBanzay, 2023/09/01
|
BuckarooBanzay, @BuckarooBanzay, 2023/09/01
|
||||||
|
|
||||||
Timur, @T1mL3arn, 2023/10/04
|
Timur, @T1mL3arn, 2023/10/04
|
||||||
|
|
||||||
|
Wang Ke, @Gk0Wk, 2023/10/17
|
||||||
|
@ -32,6 +32,9 @@
|
|||||||
"node": ">=0.8.2"
|
"node": ">=0.8.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"dev": "node ./tiddlywiki.js ./editions/tw5.com-server --listen",
|
||||||
|
"test": "node ./tiddlywiki.js ./editions/test --verbose --version --build index",
|
||||||
|
"lint:fix": "eslint . --fix",
|
||||||
"lint": "eslint ."
|
"lint": "eslint ."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,11 @@ name: tiddlywiki
|
|||||||
rendering-intent: auto;
|
rendering-intent: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tc-tiddler-frame .tc-tiddler-editor .tc-edit-texteditor,
|
||||||
|
.tc-tiddler-frame .tc-tiddler-editor .tc-tiddler-preview-preview {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.cm-s-tiddlywiki.CodeMirror, .cm-s-tiddlywiki .CodeMirror-gutters { background-color: <<colour tiddler-editor-background>>; color: <<colour foreground>>; }
|
.cm-s-tiddlywiki.CodeMirror, .cm-s-tiddlywiki .CodeMirror-gutters { background-color: <<colour tiddler-editor-background>>; color: <<colour foreground>>; }
|
||||||
.cm-s-tiddlywiki .CodeMirror-gutters {background: <<colour tiddler-editor-background>>; border-right: 1px solid <<colour tiddler-editor-border>>;}
|
.cm-s-tiddlywiki .CodeMirror-gutters {background: <<colour tiddler-editor-background>>; border-right: 1px solid <<colour tiddler-editor-border>>;}
|
||||||
.cm-s-tiddlywiki .CodeMirror-linenumber {color: <<colour foreground>>;}
|
.cm-s-tiddlywiki .CodeMirror-linenumber {color: <<colour foreground>>;}
|
||||||
|
@ -23,6 +23,7 @@ The `<$dynannotate>` widget uses the selection tracker to support a popup that d
|
|||||||
|filter |Filter identifying the annotation tiddlers applying to this content (see below) |
|
|filter |Filter identifying the annotation tiddlers applying to this content (see below) |
|
||||||
|actions |Action string to be executed when an annotation is clicked. The variable `annotationTiddler` contains the title of the tiddler corresponding to the annotation that was clicked, and the variable `modifierKey` contains "ctrl", "shift", "ctrl-shift", "normal" according to which modifier keys were pressed |
|
|actions |Action string to be executed when an annotation is clicked. The variable `annotationTiddler` contains the title of the tiddler corresponding to the annotation that was clicked, and the variable `modifierKey` contains "ctrl", "shift", "ctrl-shift", "normal" according to which modifier keys were pressed |
|
||||||
|popup |Popup state tiddler to be used to trigger a popup when an annotation is clicked |
|
|popup |Popup state tiddler to be used to trigger a popup when an annotation is clicked |
|
||||||
|
|floating |Setting to `yes` makes the popup need to be closed explicitly. |
|
||||||
|search |Search text to be highlighted within the widget |
|
|search |Search text to be highlighted within the widget |
|
||||||
|searchDisplay |"overlay" or "snippet" (see below) |
|
|searchDisplay |"overlay" or "snippet" (see below) |
|
||||||
|searchMode |"literal" (default), "regexp", "whitespace", "words" or "some" (see below) |
|
|searchMode |"literal" (default), "regexp", "whitespace", "words" or "some" (see below) |
|
||||||
|
@ -205,7 +205,8 @@ DynannotateWidget.prototype.applyAnnotations = function() {
|
|||||||
if(self.hasAttribute("popup")) {
|
if(self.hasAttribute("popup")) {
|
||||||
$tw.popup.triggerPopup({
|
$tw.popup.triggerPopup({
|
||||||
domNode: domOverlay,
|
domNode: domOverlay,
|
||||||
title: self.getAttribute("popup"),
|
title: self.getAttribute("popup"),
|
||||||
|
floating: self.getAttribute("floating"),
|
||||||
wiki: self.wiki
|
wiki: self.wiki
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ For details see: https://blog.evernote.com/tech/2013/08/08/evernote-export-forma
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// DOMParser = require("$:/plugins/tiddlywiki/xmldom/dom-parser").DOMParser;
|
// DOMParser = require("$:/plugins/tiddlywiki/xmldom/dom-parser").DOMParser;
|
||||||
|
var illegalFilenameCharacters = /[\[\]<>;\:\"\/\\\|\?\*\^\?\$\(\)\s~]/g;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Parse an ENEX file into tiddlers
|
Parse an ENEX file into tiddlers
|
||||||
@ -23,10 +24,13 @@ exports["application/enex+xml"] = function(text,fields) {
|
|||||||
// Collect output tiddlers in an array
|
// Collect output tiddlers in an array
|
||||||
var results = [];
|
var results = [];
|
||||||
// Parse the XML document
|
// Parse the XML document
|
||||||
var parser = new DOMParser(),
|
var doc = new DOMParser().parseFromString(text,"application/xml");
|
||||||
doc = parser.parseFromString(text,"application/xml");
|
|
||||||
// Output a report tiddler with information about the import
|
// Output a report tiddler with information about the import
|
||||||
var enex = doc.querySelector("en-export");
|
var enex = doc.querySelector("en-export");
|
||||||
|
if(!enex) {
|
||||||
|
// Firefox's DOMParser have problem in some cases.
|
||||||
|
throw new Error('Failed to parse ENEX file, no "en-export" node found, try use Chrome/Edge to export again.');
|
||||||
|
}
|
||||||
results.push({
|
results.push({
|
||||||
title: "Evernote Import Report",
|
title: "Evernote Import Report",
|
||||||
text: "Evernote file imported on " + enex.getAttribute("export-date") + " from " + enex.getAttribute("application") + " (" + enex.getAttribute("version") + ")"
|
text: "Evernote file imported on " + enex.getAttribute("export-date") + " from " + enex.getAttribute("application") + " (" + enex.getAttribute("version") + ")"
|
||||||
@ -34,47 +38,102 @@ exports["application/enex+xml"] = function(text,fields) {
|
|||||||
// Get all the "note" nodes
|
// Get all the "note" nodes
|
||||||
var noteNodes = doc.querySelectorAll("note");
|
var noteNodes = doc.querySelectorAll("note");
|
||||||
$tw.utils.each(noteNodes,function(noteNode) {
|
$tw.utils.each(noteNodes,function(noteNode) {
|
||||||
var result = {
|
var noteTitle = getTextContent(noteNode,"title");
|
||||||
title: getTextContent(noteNode,"title"),
|
// get real note content node
|
||||||
type: "text/html",
|
var contentNode = noteNode.querySelector("content")
|
||||||
|
var contentText = (contentNode.textContent || "").replace(/ /g, ' ').trim();
|
||||||
|
if(contentText) {
|
||||||
|
// The final content will be HTML instead of xml. And we will save it as wikitext, to make wiki syntax work, and remaining HTML will also work.
|
||||||
|
try {
|
||||||
|
// may error if content is not valid XML
|
||||||
|
contentNode = new DOMParser().parseFromString(contentText,"application/xml").querySelector("en-note") || contentNode;
|
||||||
|
} catch(e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// process main content and metadata, and save as wikitext tiddler.
|
||||||
|
var noteResult = {
|
||||||
|
title: noteTitle.replace(illegalFilenameCharacters,"_"),
|
||||||
tags: [],
|
tags: [],
|
||||||
text: getTextContent(noteNode,"content"),
|
modified: convertDate(getTextContent(noteNode,"updated") || getTextContent(noteNode,"created")),
|
||||||
modified: convertDate(getTextContent(noteNode,"created")),
|
modifier: getTextContent(noteNode,"author"),
|
||||||
created: convertDate(getTextContent(noteNode,"created"))
|
created: convertDate(getTextContent(noteNode,"created")),
|
||||||
|
creator: getTextContent(noteNode,"author")
|
||||||
};
|
};
|
||||||
|
// process resources (images, PDFs, etc.)
|
||||||
|
$tw.utils.each(noteNode.querySelectorAll("resource"),function(resourceNode) {
|
||||||
|
// hash generated by applying https://github.com/vzhd1701/evernote-backup/pull/54
|
||||||
|
var hash = resourceNode.querySelector("data").getAttribute("hash");
|
||||||
|
var text = getTextContent(resourceNode,"data");
|
||||||
|
var mimeType = getTextContent(resourceNode,"mime");
|
||||||
|
var contentTypeInfo = $tw.config.contentTypeInfo[mimeType] || {extension:""};
|
||||||
|
var title = getTextContent(resourceNode,"resource-attributes>file-name")
|
||||||
|
// a few resources don't have title, use hash as fallback
|
||||||
|
title = title || (hash + contentTypeInfo.extension);
|
||||||
|
// replace all system reserved characters in title
|
||||||
|
title = title.replace(illegalFilenameCharacters,"_");
|
||||||
|
// prefix image title with note title, to avoid name conflicts which is quite common in web-clipped content
|
||||||
|
title = noteResult.title + "/" + title;
|
||||||
|
results.push({
|
||||||
|
title: title,
|
||||||
|
type: mimeType,
|
||||||
|
width: getTextContent(resourceNode,"width"),
|
||||||
|
height: getTextContent(resourceNode,"height"),
|
||||||
|
text: text,
|
||||||
|
// give image same modified and modifier as the note, so they can be grouped together in the "Recent"
|
||||||
|
modified: noteResult.modified,
|
||||||
|
modifier: noteResult.modifier,
|
||||||
|
created: noteResult.created,
|
||||||
|
creator: noteResult.creator
|
||||||
|
});
|
||||||
|
if(hash) {
|
||||||
|
fixAttachmentReference(contentNode, hash, mimeType, title);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// export mixed content of wikitext and HTML
|
||||||
|
noteResult.text = contentNode.innerHTML;
|
||||||
|
// remove all ` xmlns="http://www.w3.org/1999/xhtml"` attributes to save some space
|
||||||
|
noteResult.text = noteResult.text.replace(/ xmlns="http:\/\/www.w3.org\/1999\/xhtml"/g, "");
|
||||||
$tw.utils.each(noteNode.querySelectorAll("tag"),function(tagNode) {
|
$tw.utils.each(noteNode.querySelectorAll("tag"),function(tagNode) {
|
||||||
result.tags.push(tagNode.textContent);
|
noteResult.tags.push(tagNode.textContent);
|
||||||
});
|
});
|
||||||
// If there's an update date, set modifiy date accordingly
|
// If there's an update date, set modifiy date accordingly
|
||||||
var update = getTextContent(noteNode,"updated");
|
var update = getTextContent(noteNode,"updated");
|
||||||
if(update) {
|
if(update) {
|
||||||
result.modified = convertDate(update);
|
noteResult.modified = convertDate(update);
|
||||||
}
|
}
|
||||||
$tw.utils.each(noteNode.querySelectorAll("note-attributes>*"),function(attrNode) {
|
$tw.utils.each(noteNode.querySelectorAll("note-attributes>*"),function(attrNode) {
|
||||||
result[attrNode.tagName] = attrNode.textContent;
|
noteResult[attrNode.tagName] = attrNode.textContent;
|
||||||
});
|
|
||||||
results.push(result);
|
|
||||||
$tw.utils.each(noteNode.querySelectorAll("resource"),function(resourceNode) {
|
|
||||||
results.push({
|
|
||||||
title: getTextContent(resourceNode,"resource-attributes>file-name"),
|
|
||||||
type: getTextContent(resourceNode,"mime"),
|
|
||||||
width: getTextContent(resourceNode,"width"),
|
|
||||||
height: getTextContent(resourceNode,"height"),
|
|
||||||
text: getTextContent(resourceNode,"data")
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
results.push(noteResult);
|
||||||
});
|
});
|
||||||
// Return the output tiddlers
|
// Return the output tiddlers
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|
||||||
function getTextContent(node,selector) {
|
function getTextContent(node,selector) {
|
||||||
return (node.querySelector(selector) || {}).textContent;
|
return (node.querySelector(selector) || {}).textContent || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertDate(isoDate) {
|
function convertDate(isoDate) {
|
||||||
return (isoDate || "").replace("T","").replace("Z","") + "000"
|
return (isoDate || "").replace("T","").replace("Z","") + "000"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fixAttachmentReference(contentNode, md5Hash, mimeType, name) {
|
||||||
|
if(!contentNode) return;
|
||||||
|
var mediaNode = contentNode.querySelector('en-media[hash="' + md5Hash + '"]');
|
||||||
|
if(!name) {
|
||||||
|
throw new Error("name is empty for resource hash" + md5Hash);
|
||||||
|
}
|
||||||
|
if(!mediaNode) return;
|
||||||
|
if(mimeType.indexOf("image/") === 0) {
|
||||||
|
// find en-media node, replace with image syntax
|
||||||
|
mediaNode.parentNode.replaceChild($tw.utils.domMaker("p", {text: "[img["+ name + "]]"}), mediaNode);
|
||||||
|
} else {
|
||||||
|
// For other than image attachments, we make a link to the tiddler
|
||||||
|
mediaNode.parentNode.replaceChild($tw.utils.domMaker("p", {text: "[["+ name + "]]"}), mediaNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -5,6 +5,7 @@ This plugin contains tool to assist migration of content from Evernote ENEX file
|
|||||||
!! Instructions
|
!! Instructions
|
||||||
|
|
||||||
# Download or save your ENEX file from Evernote
|
# Download or save your ENEX file from Evernote
|
||||||
|
## Use [ext[evernote-backup|https://github.com/vzhd1701/evernote-backup]] to export ENEX file with resource hash, so images can be linked in the note
|
||||||
# Rename the file to have an `.enex` extension
|
# Rename the file to have an `.enex` extension
|
||||||
# Drag the file into the TiddlyWiki browser window
|
# Drag the file into the TiddlyWiki browser window
|
||||||
## Alternatively, click the "Import" button in the "Tools" sidebar tab
|
## Alternatively, click the "Import" button in the "Tools" sidebar tab
|
||||||
|
File diff suppressed because one or more lines are too long
90
plugins/tiddlywiki/qrcode/barcodereader.js
Normal file
90
plugins/tiddlywiki/qrcode/barcodereader.js
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/plugins/tiddlywiki/qrcode/barcodereader.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: widget
|
||||||
|
|
||||||
|
barcodereader widget for reading barcodes
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||||
|
|
||||||
|
var nextID = 0;
|
||||||
|
|
||||||
|
var BarCodeReaderWidget = function(parseTreeNode,options) {
|
||||||
|
this.initialise(parseTreeNode,options);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Inherit from the base widget class
|
||||||
|
*/
|
||||||
|
BarCodeReaderWidget.prototype = new Widget();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Render this widget into the DOM
|
||||||
|
*/
|
||||||
|
BarCodeReaderWidget.prototype.render = function(parent,nextSibling) {
|
||||||
|
var self = this;
|
||||||
|
this.parentDomNode = parent;
|
||||||
|
this.computeAttributes();
|
||||||
|
// Make the child widgets
|
||||||
|
this.makeChildWidgets();
|
||||||
|
// Generate an ID for this element
|
||||||
|
var id = "capture-widget-internal-" + nextID;
|
||||||
|
nextID += 1;
|
||||||
|
// Create the DOM node and render children
|
||||||
|
var domNode = this.document.createElement("div");
|
||||||
|
domNode.className = "tc-readcode-widget";
|
||||||
|
domNode.setAttribute("width","300px");
|
||||||
|
domNode.setAttribute("height","300px");
|
||||||
|
domNode.id = id;
|
||||||
|
parent.insertBefore(domNode,nextSibling);
|
||||||
|
this.renderChildren(domNode,null);
|
||||||
|
this.domNodes.push(domNode);
|
||||||
|
// Setup the qrcode library
|
||||||
|
if($tw.browser) {
|
||||||
|
var __Html5QrcodeLibrary__ = require("$:/plugins/tiddlywiki/qrcode/html5-qrcode/html5-qrcode.js").__Html5QrcodeLibrary__;
|
||||||
|
function onScanSuccess(decodedText, decodedResult) {
|
||||||
|
self.invokeActionString(self.getAttribute("actionsSuccess",""),self,{},{
|
||||||
|
format: decodedResult.result.format.formatName,
|
||||||
|
text: decodedText
|
||||||
|
});
|
||||||
|
console.log("Scan result",decodedResult,decodedText);
|
||||||
|
}
|
||||||
|
function onScanFailure(errorMessage) {
|
||||||
|
self.invokeActionString(self.getAttribute("actionsFailure",""),self,{},{
|
||||||
|
error: errorMessage
|
||||||
|
});
|
||||||
|
console.log("Scan error",errorMessage);
|
||||||
|
}
|
||||||
|
var html5QrcodeScanner = new __Html5QrcodeLibrary__.Html5QrcodeScanner(
|
||||||
|
id,
|
||||||
|
{
|
||||||
|
fps: 10,
|
||||||
|
qrbox: 250
|
||||||
|
}
|
||||||
|
);
|
||||||
|
html5QrcodeScanner.render(onScanSuccess,onScanFailure);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||||
|
*/
|
||||||
|
BarCodeReaderWidget.prototype.refresh = function(changedTiddlers) {
|
||||||
|
var changedAttributes = this.computeAttributes(),
|
||||||
|
hasChangedAttributes = $tw.utils.count(changedAttributes) > 0;
|
||||||
|
if(hasChangedAttributes) {
|
||||||
|
return this.refreshSelf();
|
||||||
|
}
|
||||||
|
return this.refreshChildren(changedTiddlers) || hasChangedAttributes;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.barcodereader = BarCodeReaderWidget;
|
||||||
|
|
||||||
|
})();
|
@ -1,3 +0,0 @@
|
|||||||
title: $:/plugins/tiddlywiki/qrcode/examples
|
|
||||||
|
|
||||||
<<tabs "[all[shadows+tiddlers]tag[$:/tags/MakeQR]!has[draft.of]]" "$:/plugins/tiddlywiki/qrcode/MakeGenericQR">>
|
|
@ -1,13 +0,0 @@
|
|||||||
title: $:/plugins/tiddlywiki/qrcode/readme
|
|
||||||
|
|
||||||
The QR code plugin provides a macro that enables any text to be rendered as a [[QR code|https://en.wikipedia.org/wiki/QR_code]]. QR codes are a type of 2-dimensional bar code that encodes arbitrary data: text, numbers, links. QR code readers are available or built-in for smartphones, making them a convenient means to transfer information between devices
|
|
||||||
|
|
||||||
The QR code plugin adds the following features to TiddlyWiki:
|
|
||||||
|
|
||||||
* A new [[makeqr Macro]] that renders specified text as a QR code image that can be displayed or printed
|
|
||||||
* A new toolbar button that can display several QR code renderings of the content of a tiddler:
|
|
||||||
** Raw content
|
|
||||||
** Rendered, formatted content
|
|
||||||
** URL of tiddler
|
|
||||||
|
|
||||||
The QR code plugin is based on the library [[qrcode.js by Zeno Zeng|https://github.com/zenozeng/node-yaqrcode]].
|
|
3
plugins/tiddlywiki/qrcode/docs.tid
Normal file
3
plugins/tiddlywiki/qrcode/docs.tid
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
title: $:/plugins/tiddlywiki/qrcode/docs
|
||||||
|
|
||||||
|
<<tabs "[all[shadows+tiddlers]tag[$:/tags/QRCodeDocs]!has[draft.of]]" "$:/plugins/tiddlywiki/qrcode/docs/barcodereader">>
|
44
plugins/tiddlywiki/qrcode/docs/barcodereader.tid
Normal file
44
plugins/tiddlywiki/qrcode/docs/barcodereader.tid
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
title: $:/plugins/tiddlywiki/qrcode/docs/barcodereader
|
||||||
|
tags: $:/tags/QRCodeDocs
|
||||||
|
caption: barcodereader Widget
|
||||||
|
|
||||||
|
The `<$barcodereader>` widget allows barcodes to be read from the device camera or from an image file. In the case of the camera, a live preview feed is shown to allow the barcode to be framed.
|
||||||
|
|
||||||
|
Note that for security reasons browsers restrict the operation of the camera to only work with web pages that have been loaded via HTTPS, or via localhost. Safari and Firefox allow usage from a file URI, but Chrome crashes when attempting to use the barcode reader from a file URI.
|
||||||
|
|
||||||
|
The `<$barcodereader>` widget has the following attributes:
|
||||||
|
|
||||||
|
|!Name |!Description |
|
||||||
|
|actionsSuccess |Action string to be executed when a code is successfully decoded |
|
||||||
|
|actionsFailure |Action string to be executed in the event of an error |
|
||||||
|
|
||||||
|
The following variables are passed to the ''actionsSuccess'' handler:
|
||||||
|
|
||||||
|
|!Name |!Description |
|
||||||
|
|format |Barcode format (see below) |
|
||||||
|
|text |Decoded text |
|
||||||
|
|
||||||
|
The following barcode formats are supported:
|
||||||
|
|
||||||
|
* 0: "QR_CODE"
|
||||||
|
* 1: "AZTEC"
|
||||||
|
* 2: "CODABAR"
|
||||||
|
* 3: "CODE_39"
|
||||||
|
* 4: "CODE_93"
|
||||||
|
* 5: "CODE_128"
|
||||||
|
* 6: "DATA_MATRIX"
|
||||||
|
* 7: "MAXICODE"
|
||||||
|
* 8: "ITF"
|
||||||
|
* 9: "EAN_13"
|
||||||
|
* 10: "EAN_8"
|
||||||
|
* 11: "PDF_417"
|
||||||
|
* 12: "RSS_14"
|
||||||
|
* 13: "RSS_EXPANDED"
|
||||||
|
* 14: "UPC_A"
|
||||||
|
* 15: "UPC_E"
|
||||||
|
* 16: "UPC_EAN_EXTENSION"
|
||||||
|
|
||||||
|
The following variables are passed to the ''actionsFailure'' handler:
|
||||||
|
|
||||||
|
|!Name |!Description |
|
||||||
|
|error |Error message |
|
@ -1,8 +1,8 @@
|
|||||||
title: $:/plugins/tiddlywiki/qrcode/usage
|
title: $:/plugins/tiddlywiki/qrcode/docs/qrcode
|
||||||
|
tags: $:/tags/QRCodeDocs
|
||||||
|
caption: makeqr Macro
|
||||||
|
|
||||||
! `makeqr` Macro
|
The ''makeqr'' [[macro|Macros]] converts text data into an image of the corresponding QR code. The image is returned as [[base64-encoded data URI|https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs]].
|
||||||
|
|
||||||
The <<.def makeqr>> [[macro|Macros]] converts text data into an image of the corresponding QR code. The image is returned as [[base64-encoded data URI|https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs]].
|
|
||||||
|
|
||||||
!! Parameters
|
!! Parameters
|
||||||
|
|
3
plugins/tiddlywiki/qrcode/examples.tid
Normal file
3
plugins/tiddlywiki/qrcode/examples.tid
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
title: $:/plugins/tiddlywiki/qrcode/examples
|
||||||
|
|
||||||
|
<<tabs "[all[shadows+tiddlers]tag[$:/tags/QRCodeExample]!has[draft.of]]" "$:/plugins/tiddlywiki/qrcode/examples/read">>
|
@ -1,4 +1,4 @@
|
|||||||
title: $:/plugins/tiddlywiki/qrcode/MakeContactQR
|
title: $:/plugins/tiddlywiki/qrcode/make/MakeContactQR
|
||||||
tags: $:/tags/MakeQR
|
tags: $:/tags/MakeQR
|
||||||
caption: Contact
|
caption: Contact
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
title: $:/plugins/tiddlywiki/qrcode/MakeGenericQR
|
title: $:/plugins/tiddlywiki/qrcode/make/MakeGenericQR
|
||||||
tags: $:/tags/MakeQR
|
tags: $:/tags/MakeQR
|
||||||
caption: Generic
|
caption: Generic
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
title: $:/plugins/tiddlywiki/qrcode/MakeWifiQR
|
title: $:/plugins/tiddlywiki/qrcode/make/MakeWifiQR
|
||||||
tags: $:/tags/MakeQR
|
tags: $:/tags/MakeQR
|
||||||
caption: Wifi
|
caption: Wifi
|
||||||
|
|
5
plugins/tiddlywiki/qrcode/examples/make/make.tid
Normal file
5
plugins/tiddlywiki/qrcode/examples/make/make.tid
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
title: $:/plugins/tiddlywiki/qrcode/examples/make
|
||||||
|
tags: $:/tags/QRCodeExample
|
||||||
|
caption: Making Barcodes
|
||||||
|
|
||||||
|
<<tabs "[all[shadows+tiddlers]tag[$:/tags/MakeQR]!has[draft.of]]" "$:/plugins/tiddlywiki/qrcode/make/MakeGenericQR">>
|
17
plugins/tiddlywiki/qrcode/examples/read/BarCodeReader.tid
Normal file
17
plugins/tiddlywiki/qrcode/examples/read/BarCodeReader.tid
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
title: $:/plugins/tiddlywiki/qrcode/examples/read/BarCodeReader
|
||||||
|
tags: $:/tags/ReadQR
|
||||||
|
caption: Barcode Reader
|
||||||
|
|
||||||
|
\procedure success()
|
||||||
|
<$action-setfield $tiddler="$:/state/BarCodeReaderDemoStatus" text=<<text>> result=<<format>> success="yes"/>
|
||||||
|
\end
|
||||||
|
|
||||||
|
\procedure failure()
|
||||||
|
<$action-setfield $tiddler="$:/state/BarCodeReaderDemoStatus" text=<<error>> success="no"/>
|
||||||
|
\end
|
||||||
|
|
||||||
|
Scanning status: {{$:/state/BarCodeReaderDemoStatus}}
|
||||||
|
|
||||||
|
{{$:/state/BarCodeReaderDemoStatus||$:/core/ui/TiddlerFields}}
|
||||||
|
|
||||||
|
<$barcodereader actionsSuccess=<<success>> actionsFail=<<failure>>/>
|
5
plugins/tiddlywiki/qrcode/examples/read/read.tid
Normal file
5
plugins/tiddlywiki/qrcode/examples/read/read.tid
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
title: $:/plugins/tiddlywiki/qrcode/examples/read
|
||||||
|
tags: $:/tags/QRCodeExample
|
||||||
|
caption: Reading Barcodes
|
||||||
|
|
||||||
|
<<tabs "[all[shadows+tiddlers]tag[$:/tags/ReadQR]!has[draft.of]]" "$:/plugins/tiddlywiki/qrcode/examples/read/BarCodeReader">>
|
201
plugins/tiddlywiki/qrcode/files/html5-qrcode/LICENSE
Normal file
201
plugins/tiddlywiki/qrcode/files/html5-qrcode/LICENSE
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [2020] [MINHAZ <minhazav@gmail.com>]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
398
plugins/tiddlywiki/qrcode/files/html5-qrcode/README.md
Normal file
398
plugins/tiddlywiki/qrcode/files/html5-qrcode/README.md
Normal file
@ -0,0 +1,398 @@
|
|||||||
|
# Html5-QRCode
|
||||||
|
|
||||||
|
## Lightweight & cross platform QR Code and Bar code scanning library for the web
|
||||||
|
|
||||||
|
Use this lightweight library to easily / quickly integrate QR code, bar code, and other common code scanning capabilities to your web application.
|
||||||
|
|
||||||
|
## Key highlights
|
||||||
|
- 🔲 Support scanning [different types of bar codes and QR codes](#supported-code-formats).
|
||||||
|
|
||||||
|
- 🖥 Supports [different platforms](#supported-platforms) be it Android, IOS, MacOs, Windows or Linux
|
||||||
|
|
||||||
|
- 🌐 Supports [different browsers](#supported-platforms) like Chrome, Firefox, Safari, Edge, Opera ...
|
||||||
|
|
||||||
|
- 📷 Supports scanning with camera as well as local files
|
||||||
|
|
||||||
|
- ➡️ Comes with an [end to end library with UI](#easy-mode---with-end-to-end-scanner-user-interface) as well as a [low level library to build your own UI with](#pro-mode---if-you-want-to-implement-your-own-user-interface).
|
||||||
|
|
||||||
|
- 🔦 Supports customisations like [flash/torch support](#showtorchbuttonifsupported---boolean--undefined), zooming etc.
|
||||||
|
|
||||||
|
|
||||||
|
Supports two kinds of APIs
|
||||||
|
|
||||||
|
- `Html5QrcodeScanner` — End-to-end scanner with UI, integrate with less than ten lines of code.
|
||||||
|
|
||||||
|
- `Html5Qrcode` — Powerful set of APIs you can use to build your UI without worrying about camera setup, handling permissions, reading codes, etc.
|
||||||
|
|
||||||
|
> Support for scanning local files on the device is a new addition and helpful for the web browser which does not support inline web-camera access in smartphones. **Note:** This doesn't upload files to any server — everything is done locally.
|
||||||
|
|
||||||
|
[![CircleCI](https://dl.circleci.com/status-badge/img/gh/mebjas/html5-qrcode/tree/master.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/mebjas/html5-qrcode/tree/master) [![GitHub issues](https://img.shields.io/github/issues/mebjas/html5-qrcode)](https://github.com/mebjas/html5-qrcode/issues) [![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/mebjas/html5-qrcode)](https://github.com/mebjas/html5-qrcode/releases) ![GitHub](https://img.shields.io/github/license/mebjas/html5-qrcode) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/51e4f0ef8b0b42e1b93ce29875dd23a0)](https://www.codacy.com/gh/mebjas/html5-qrcode/dashboard?utm_source=github.com&utm_medium=referral&utm_content=mebjas/html5-qrcode&utm_campaign=Badge_Grade) [![Gitter](https://badges.gitter.im/html5-qrcode/community.svg)](https://gitter.im/html5-qrcode/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||||
|
|
||||||
|
![GitHub all releases](https://img.shields.io/github/downloads/mebjas/html5-qrcode/total?label=Github%20downloads&style=for-the-badge) [![npm](https://img.shields.io/npm/dw/html5-qrcode?label=npm%20downloads&style=for-the-badge)](https://www.npmjs.com/package/html5-qrcode) [![](https://img.shields.io/badge/Medium-12100E?style=for-the-badge&logo=medium&logoColor=white)](https://bit.ly/3CZiASv)
|
||||||
|
|
||||||
|
| <img src="https://scanapp.org/assets/github_assets/pixel6pro-optimised.gif" width="180px" /> | <img src="https://scanapp.org/assets/github_assets/pixel4_barcode_480.gif" width="180px" />|
|
||||||
|
| -- | -- |
|
||||||
|
| _Demo at [scanapp.org](https://scanapp.org)_ | _Demo at [qrcode.minhazav.dev](https://qrcode.minhazav.dev) - **Scanning different types of codes**_ |
|
||||||
|
|
||||||
|
## We need your help!
|
||||||
|
|
||||||
|
![image](https://user-images.githubusercontent.com/3007365/222830114-e5bcca15-bf8a-434e-9f48-339e82a0a4ef.png)
|
||||||
|
Help incentivise feature development, bug fixing by supporting the sponsorhip goals of this project. See [list of sponsered feature requests here](https://github.com/mebjas/html5-qrcode/wiki/Feature-request-sponsorship-goals#feature-requests).
|
||||||
|
|
||||||
|
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/L3L84G0C8)
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
The documentation for this project has been moved to [scanapp.org/html5-qrcode-docs](https://scanapp.org/html5-qrcode-docs/).
|
||||||
|
|
||||||
|
- [Getting started](https://scanapp.org/html5-qrcode-docs/docs/intro)
|
||||||
|
- [Supported frameworks](https://scanapp.org/html5-qrcode-docs/docs/supported_frameworks)
|
||||||
|
- [Supported 1D and 2D Code formats](https://scanapp.org/html5-qrcode-docs/docs/supported_code_formats)
|
||||||
|
- [Detailed API documentation](https://scanapp.org/html5-qrcode-docs/docs/apis)
|
||||||
|
|
||||||
|
## Supported platforms
|
||||||
|
|
||||||
|
We are working continuously on adding support for more and more platforms. If you find a platform or a browser where the library is not working, please feel free to file an issue. Check the [demo link](https://blog.minhazav.dev/research/html5-qrcode.html) to test it out.
|
||||||
|
|
||||||
|
**Legends**
|
||||||
|
- ![](https://scanapp.org/assets/github_assets/done.png) Means full support — inline webcam and file based
|
||||||
|
- ![](https://scanapp.org/assets/github_assets/partial.png) Means partial support — only file based, webcam in progress
|
||||||
|
|
||||||
|
### PC / Mac
|
||||||
|
|
||||||
|
| <img src="https://scanapp.org/assets/github_assets/browsers/firefox_48x48.png" alt="Firefox" width="24px" height="24px" /><br/>Firefox | <img src="https://scanapp.org/assets/github_assets/browsers/chrome_48x48.png" alt="Chrome" width="24px" height="24px" /><br/>Chrome | <img src="https://scanapp.org/assets/github_assets/browsers/safari_48x48.png" alt="Safari" width="24px" height="24px" /><br/>Safari | <img src="https://scanapp.org/assets/github_assets/browsers/opera_48x48.png" alt="Opera" width="24px" height="24px" /><br/>Opera | <img src="https://scanapp.org/assets/github_assets/browsers/edge_48x48.png" alt="Edge" width="24px" height="24px" /><br/> Edge
|
||||||
|
| --------- | --------- | --------- | --------- | ------- |
|
||||||
|
|![](https://scanapp.org/assets/github_assets/done.png)| ![](https://scanapp.org/assets/github_assets/done.png)| ![](https://scanapp.org/assets/github_assets/done.png)| ![](https://scanapp.org/assets/github_assets/done.png) | ![](https://scanapp.org/assets/github_assets/done.png)
|
||||||
|
|
||||||
|
### Android
|
||||||
|
|
||||||
|
| <img src="https://scanapp.org/assets/github_assets/browsers/chrome_48x48.png" alt="Chrome" width="24px" height="24px" /><br/>Chrome | <img src="https://scanapp.org/assets/github_assets/browsers/firefox_48x48.png" alt="Firefox" width="24px" height="24px" /><br/>Firefox | <img src="https://scanapp.org/assets/github_assets/browsers/edge_48x48.png" alt="Edge" width="24px" height="24px" /><br/> Edge | <img src="https://scanapp.org/assets/github_assets/browsers/opera_48x48.png" alt="Opera" width="24px" height="24px" /><br/>Opera | <img src="https://scanapp.org/assets/github_assets/browsers/opera-mini_48x48.png" alt="Opera-Mini" width="24px" height="24px" /><br/> Opera Mini | <img src="https://scanapp.org/assets/github_assets/browsers/uc_48x48.png" alt="UC" width="24px" height="24px" /> <br/> UC
|
||||||
|
| --------- | --------- | --------- | --------- | --------- | --------- |
|
||||||
|
|![](https://scanapp.org/assets/github_assets/done.png)| ![](https://scanapp.org/assets/github_assets/done.png)| ![](https://scanapp.org/assets/github_assets/done.png)| ![](https://scanapp.org/assets/github_assets/done.png)| ![](https://scanapp.org/assets/github_assets/partial.png) | ![](https://scanapp.org/assets/github_assets/partial.png)
|
||||||
|
|
||||||
|
### IOS
|
||||||
|
|
||||||
|
| <img src="https://scanapp.org/assets/github_assets/browsers/safari_48x48.png" alt="Safari" width="24px" height="24px" /><br/>Safari | <img src="https://scanapp.org/assets/github_assets/browsers/chrome_48x48.png" alt="Chrome" width="24px" height="24px" /><br/>Chrome | <img src="https://scanapp.org/assets/github_assets/browsers/firefox_48x48.png" alt="Firefox" width="24px" height="24px" /><br/>Firefox | <img src="https://scanapp.org/assets/github_assets/browsers/edge_48x48.png" alt="Edge" width="24px" height="24px" /><br/> Edge
|
||||||
|
| --------- | --------- | --------- | --------- |
|
||||||
|
|![](https://scanapp.org/assets/github_assets/done.png)| ![](https://scanapp.org/assets/github_assets/done.png)* | ![](https://scanapp.org/assets/github_assets/done.png)* | ![](https://scanapp.org/assets/github_assets/partial.png)
|
||||||
|
|
||||||
|
|
||||||
|
> \* Supported for IOS versions >= 15.1
|
||||||
|
>
|
||||||
|
> Before version 15.1, Webkit for IOS is used by Chrome, Firefox, and other browsers in IOS and they do not have webcam permissions yet. There is an ongoing issue on fixing the support for iOS - [issue/14](https://github.com/mebjas/html5-qrcode/issues/14)
|
||||||
|
|
||||||
|
### Framework support
|
||||||
|
The library can be easily used with several other frameworks, I have been adding examples for a few of them and would continue to add more.
|
||||||
|
|
||||||
|
|<img src="https://scanapp.org/assets/github_assets/html5.png" width="30px" />| <img src="https://scanapp.org/assets/github_assets/vuejs.png" width="30px" />|<img src="https://scanapp.org/assets/github_assets/electron.png" width="30px" /> | <img src="https://scanapp.org/assets/github_assets/react.svg" width="30px" /> | <img src="https://seeklogo.com/images/L/lit-logo-6B43868CDC-seeklogo.com.png" width="30px" />
|
||||||
|
| -------- | -------- | -------- | -------- | -------- |
|
||||||
|
| [Html5](./examples/html5) | [VueJs](./examples/vuejs) | [ElectronJs](./examples/electron) | [React](https://github.com/scanapp-org/html5-qrcode-react) | [Lit](./examples/lit)
|
||||||
|
|
||||||
|
### Supported Code formats
|
||||||
|
Code scanning is dependent on [Zxing-js](https://github.com/zxing-js/library) library. We will be working on top of it to add support for more types of code scanning. If you feel a certain type of code would be helpful to have, please file a feature request.
|
||||||
|
|
||||||
|
| Code | Example |
|
||||||
|
| ---- | ----- |
|
||||||
|
| QR Code | <img src="https://scanapp.org/assets/github_assets/qr-code.png" width="200px" /> |
|
||||||
|
| AZTEC | <img src="https://scanapp.org/assets/github_assets/aztec.png" /> |
|
||||||
|
| CODE_39| <img src="https://scanapp.org/assets/github_assets/code_39.gif" /> |
|
||||||
|
| CODE_93| <img src="https://scanapp.org/assets/github_assets/code_93.gif" />|
|
||||||
|
| CODE_128| <img src="https://scanapp.org/assets/github_assets/code_128.gif" />|
|
||||||
|
| ITF| <img src="https://scanapp.org/assets/github_assets/itf.png" />|
|
||||||
|
| EAN_13|<img src="https://scanapp.org/assets/github_assets/ean13.jpeg" /> |
|
||||||
|
| EAN_8| <img src="https://scanapp.org/assets/github_assets/ean8.jpeg" />|
|
||||||
|
| PDF_417| <img src="https://scanapp.org/assets/github_assets/pdf417.png" />|
|
||||||
|
| UPC_A| <img src="https://scanapp.org/assets/github_assets/upca.jpeg" />|
|
||||||
|
| UPC_E| <img src="https://scanapp.org/assets/github_assets/upce.jpeg" />|
|
||||||
|
| DATA_MATRIX|<img src="https://scanapp.org/assets/github_assets/datamatrix.png" /> |
|
||||||
|
| MAXICODE*| <img src="https://scanapp.org/assets/github_assets/maxicode.gif" /> |
|
||||||
|
| RSS_14*| <img src="https://scanapp.org/assets/github_assets/rss14.gif" />|
|
||||||
|
| RSS_EXPANDED*|<img src="https://scanapp.org/assets/github_assets/rssexpanded.gif" /> |
|
||||||
|
|
||||||
|
> *Formats are not supported by our experimental integration with native
|
||||||
|
> BarcodeDetector API integration ([Read more](/experimental.md)).
|
||||||
|
|
||||||
|
## Description - [View Demo](https://blog.minhazav.dev/research/html5-qrcode.html)
|
||||||
|
|
||||||
|
> See an end to end scanner experience at [scanapp.org](https://scanapp.org).
|
||||||
|
|
||||||
|
This is a cross-platform JavaScript library to integrate QR code, bar codes & a few other types of code scanning capabilities to your applications running on HTML5 compatible browser.
|
||||||
|
|
||||||
|
Supports:
|
||||||
|
- Querying camera on the device (with user permissions)
|
||||||
|
- Rendering live camera feed, with easy to use user interface for scanning
|
||||||
|
- Supports scanning a different kind of QR codes, bar codes and other formats
|
||||||
|
- Supports selecting image files from the device for scanning codes
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
|
||||||
|
Find detailed guidelines on how to use this library on [scanapp.org/html5-qrcode-docs](https://scanapp.org/html5-qrcode-docs/docs/intro).
|
||||||
|
|
||||||
|
## Demo
|
||||||
|
<img src="https://scanapp.org/assets/github_assets/qr-code.png" width="200px"><br />
|
||||||
|
_Scan this image or visit [blog.minhazav.dev/research/html5-qrcode.html](https://blog.minhazav.dev/research/html5-qrcode.html)_
|
||||||
|
|
||||||
|
### For more information
|
||||||
|
Check these articles on how to use this library:
|
||||||
|
<!-- TODO(mebjas) Mirgate this link to blog.minhazav.dev -->
|
||||||
|
- [QR and barcode scanner using HTML and JavaScript](https://minhazav.medium.com/qr-and-barcode-scanner-using-html-and-javascript-2cdc937f793d)
|
||||||
|
- [HTML5 QR Code scanning — launched v1.0.1 without jQuery dependency and refactored Promise based APIs](https://blog.minhazav.dev/HTML5-QR-Code-scanning-launched-v1.0.1/).
|
||||||
|
- [HTML5 QR Code scanning with JavaScript — Support for scanning the local file and using default camera added (v1.0.5)](https://blog.minhazav.dev/HTML5-QR-Code-scanning-support-for-local-file-and-default-camera/)
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
![screenshot](https://scanapp.org/assets/github_assets/screen.gif)<br />
|
||||||
|
_Figure: Screenshot from Google Chrome running on MacBook Pro_
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
Find the full API documentation at [scanapp.org/html5-qrcode-docs/docs/apis](https://scanapp.org/html5-qrcode-docs/docs/apis).
|
||||||
|
|
||||||
|
### Extra optional `configuration` in `start()` method
|
||||||
|
Configuration object that can be used to configure both the scanning behavior and the user interface (UI). Most of the fields have default properties that will be used unless a different value is provided. If you do not want to override anything, you can just pass in an empty object `{}`.
|
||||||
|
|
||||||
|
#### `fps` — Integer, Example = 10
|
||||||
|
A.K.A frame per second, the default value for this is 2, but it can be increased to get faster scanning. Increasing too high value could affect performance. Value `>1000` will simply fail.
|
||||||
|
|
||||||
|
#### `qrbox` — `QrDimensions` or `QrDimensionFunction` (Optional), Example = `{ width: 250, height: 250 }`
|
||||||
|
Use this property to limit the region of the viewfinder you want to use for scanning. The rest of the viewfinder would be shaded. For example, by passing config `{ qrbox : { width: 250, height: 250 } }`, the screen will look like:
|
||||||
|
|
||||||
|
<img src="https://scanapp.org/assets/github_assets/screen.gif" />
|
||||||
|
|
||||||
|
This can be used to set a rectangular scanning area with config like:
|
||||||
|
|
||||||
|
```js
|
||||||
|
let config = { qrbox : { width: 400, height: 150 } }
|
||||||
|
```
|
||||||
|
|
||||||
|
This config also accepts a function of type
|
||||||
|
```ts
|
||||||
|
/**
|
||||||
|
* A function that takes in the width and height of the video stream
|
||||||
|
* and returns QrDimensions.
|
||||||
|
*
|
||||||
|
* Viewfinder refers to the video showing camera stream.
|
||||||
|
*/
|
||||||
|
type QrDimensionFunction =
|
||||||
|
(viewfinderWidth: number, viewfinderHeight: number) => QrDimensions;
|
||||||
|
```
|
||||||
|
|
||||||
|
This allows you to set dynamic QR box dimensions based on the video dimensions. See this blog article for example: [Setting dynamic QR box size in Html5-qrcode - ScanApp blog](https://scanapp.org/blog/2022/01/09/setting-dynamic-qr-box-size-in-html5-qrcode.html)
|
||||||
|
|
||||||
|
> This might be desirable for bar code scanning.
|
||||||
|
|
||||||
|
If this value is not set, no shaded QR box will be rendered and the scanner will scan the entire area of video stream.
|
||||||
|
|
||||||
|
#### `aspectRatio` — Float, Example 1.777778 for 16:9 aspect ratio
|
||||||
|
Use this property to render the video feed in a certain aspect ratio. Passing a nonstandard aspect ratio like `100000:1` could lead to the video feed not even showing up. Ideal values can be:
|
||||||
|
| Value | Aspect Ratio | Use Case |
|
||||||
|
| ----- | ------------ | -------- |
|
||||||
|
|1.333334 | 4:3 | Standard camera aspect ratio |
|
||||||
|
|1.777778 | 16:9 | Full screen, cinematic |
|
||||||
|
|1.0 | 1:1 | Square view |
|
||||||
|
|
||||||
|
If you do not pass any value, the whole viewfinder would be used for scanning.
|
||||||
|
**Note**: this value has to be smaller than the width and height of the `QR code HTML element`.
|
||||||
|
|
||||||
|
#### `disableFlip` — Boolean (Optional), default = false
|
||||||
|
By default, the scanner can scan for horizontally flipped QR Codes. This also enables scanning QR code using the front camera on mobile devices which are sometimes mirrored. This is `false` by default and I recommend changing this only if:
|
||||||
|
- You are sure that the camera feed cannot be mirrored (Horizontally flipped)
|
||||||
|
- You are facing performance issues with this enabled.
|
||||||
|
|
||||||
|
Here's an example of a normal and mirrored QR Code
|
||||||
|
| Normal QR Code | Mirrored QR Code |
|
||||||
|
| ----- | ---- |
|
||||||
|
| <img src="https://scanapp.org/assets/github_assets/qr-code.png" width="200px" /> | <img src="https://scanapp.org/assets/github_assets/qr-code-flipped.png" width="200px" /><br /> |
|
||||||
|
|
||||||
|
#### `rememberLastUsedCamera` — Boolean (Optional), default = true
|
||||||
|
If `true` the last camera used by the user and weather or not permission was granted would be remembered in the local storage. If the user has previously granted permissions — the request permission option in the UI will be skipped and the last selected camera would be launched automatically for scanning.
|
||||||
|
|
||||||
|
If `true` the library shall remember if the camera permissions were previously
|
||||||
|
granted and what camera was last used. If the permissions is already granted for
|
||||||
|
"camera", QR code scanning will automatically * start for previously used camera.
|
||||||
|
|
||||||
|
#### `supportedScanTypes` - `Array<Html5QrcodeScanType> | []`
|
||||||
|
> This is only supported for `Html5QrcodeScanner`.
|
||||||
|
|
||||||
|
Default = `[Html5QrcodeScanType.SCAN_TYPE_CAMERA, Html5QrcodeScanType.SCAN_TYPE_FILE]`
|
||||||
|
|
||||||
|
This field can be used to:
|
||||||
|
- Limit support to either of `Camera` or `File` based scan.
|
||||||
|
- Change default scan type.
|
||||||
|
|
||||||
|
How to use:
|
||||||
|
|
||||||
|
```js
|
||||||
|
function onScanSuccess(decodedText, decodedResult) {
|
||||||
|
// handle the scanned code as you like, for example:
|
||||||
|
console.log(`Code matched = ${decodedText}`, decodedResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
let config = {
|
||||||
|
fps: 10,
|
||||||
|
qrbox: {width: 100, height: 100},
|
||||||
|
rememberLastUsedCamera: true,
|
||||||
|
// Only support camera scan type.
|
||||||
|
supportedScanTypes: [Html5QrcodeScanType.SCAN_TYPE_CAMERA]
|
||||||
|
};
|
||||||
|
|
||||||
|
let html5QrcodeScanner = new Html5QrcodeScanner(
|
||||||
|
"reader", config, /* verbose= */ false);
|
||||||
|
html5QrcodeScanner.render(onScanSuccess);
|
||||||
|
```
|
||||||
|
|
||||||
|
For file based scan only choose:
|
||||||
|
```js
|
||||||
|
supportedScanTypes: [Html5QrcodeScanType.SCAN_TYPE_FILE]
|
||||||
|
```
|
||||||
|
|
||||||
|
For supporting both as it is today, you can ignore this field or set as:
|
||||||
|
```js
|
||||||
|
supportedScanTypes: [
|
||||||
|
Html5QrcodeScanType.SCAN_TYPE_CAMERA,
|
||||||
|
Html5QrcodeScanType.SCAN_TYPE_FILE]
|
||||||
|
```
|
||||||
|
|
||||||
|
To set the file based scan as defult change the order:
|
||||||
|
```js
|
||||||
|
supportedScanTypes: [
|
||||||
|
Html5QrcodeScanType.SCAN_TYPE_FILE,
|
||||||
|
Html5QrcodeScanType.SCAN_TYPE_CAMERA]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `showTorchButtonIfSupported` - `boolean | undefined`
|
||||||
|
> This is only supported for `Html5QrcodeScanner`.
|
||||||
|
|
||||||
|
If `true` the rendered UI will have button to turn flash on or off based on device + browser support. The value is `false` by default.
|
||||||
|
|
||||||
|
### Scanning only specific formats
|
||||||
|
By default, both camera stream and image files are scanned against all the
|
||||||
|
supported code formats. Both `Html5QrcodeScanner` and `Html5Qrcode` classes can
|
||||||
|
be configured to only support a subset of supported formats. Supported formats
|
||||||
|
are defined in
|
||||||
|
[enum Html5QrcodeSupportedFormats](https://github.com/mebjas/html5-qrcode/blob/master/src/core.ts#L14).
|
||||||
|
|
||||||
|
```ts
|
||||||
|
enum Html5QrcodeSupportedFormats {
|
||||||
|
QR_CODE = 0,
|
||||||
|
AZTEC,
|
||||||
|
CODABAR,
|
||||||
|
CODE_39,
|
||||||
|
CODE_93,
|
||||||
|
CODE_128,
|
||||||
|
DATA_MATRIX,
|
||||||
|
MAXICODE,
|
||||||
|
ITF,
|
||||||
|
EAN_13,
|
||||||
|
EAN_8,
|
||||||
|
PDF_417,
|
||||||
|
RSS_14,
|
||||||
|
RSS_EXPANDED,
|
||||||
|
UPC_A,
|
||||||
|
UPC_E,
|
||||||
|
UPC_EAN_EXTENSION,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
I recommend using this only if you need to explicitly omit support for certain
|
||||||
|
formats or want to reduce the number of scans done per second for performance
|
||||||
|
reasons.
|
||||||
|
|
||||||
|
#### Scanning only QR code with `Html5Qrcode`
|
||||||
|
```js
|
||||||
|
const html5QrCode = new Html5Qrcode(
|
||||||
|
"reader", { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] });
|
||||||
|
const qrCodeSuccessCallback = (decodedText, decodedResult) => {
|
||||||
|
/* handle success */
|
||||||
|
};
|
||||||
|
const config = { fps: 10, qrbox: { width: 250, height: 250 } };
|
||||||
|
|
||||||
|
// If you want to prefer front camera
|
||||||
|
html5QrCode.start({ facingMode: "user" }, config, qrCodeSuccessCallback);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Scanning only QR code and UPC codes with `Html5QrcodeScanner`
|
||||||
|
```js
|
||||||
|
function onScanSuccess(decodedText, decodedResult) {
|
||||||
|
// Handle the scanned code as you like, for example:
|
||||||
|
console.log(`Code matched = ${decodedText}`, decodedResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatsToSupport = [
|
||||||
|
Html5QrcodeSupportedFormats.QR_CODE,
|
||||||
|
Html5QrcodeSupportedFormats.UPC_A,
|
||||||
|
Html5QrcodeSupportedFormats.UPC_E,
|
||||||
|
Html5QrcodeSupportedFormats.UPC_EAN_EXTENSION,
|
||||||
|
];
|
||||||
|
const html5QrcodeScanner = new Html5QrcodeScanner(
|
||||||
|
"reader",
|
||||||
|
{
|
||||||
|
fps: 10,
|
||||||
|
qrbox: { width: 250, height: 250 },
|
||||||
|
formatsToSupport: formatsToSupport
|
||||||
|
},
|
||||||
|
/* verbose= */ false);
|
||||||
|
html5QrcodeScanner.render(onScanSuccess);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Experimental features
|
||||||
|
The library now supports some experimental features which are supported in the
|
||||||
|
library but not recommended for production usage either due to limited testing
|
||||||
|
done or limited compatibility for underlying APIs used. Read more about it [here](/experimental.md).
|
||||||
|
Some experimental features include:
|
||||||
|
- [Support for BarcodeDetector JavaScript API](/experimental.md)
|
||||||
|
|
||||||
|
## How to modify and build
|
||||||
|
1. Code changes should only be made to [/src](./src) only.
|
||||||
|
|
||||||
|
2. Run `npm install` to install all dependencies.
|
||||||
|
|
||||||
|
3. Run `npm run-script build` to build JavaScript output. The output JavaScript distribution is built to [/dist/html5-qrcode.min.js](./dist/html5-qrcode.min.js). If you are developing on Windows OS, run `npm run-script build-windows`.
|
||||||
|
|
||||||
|
4. Testing
|
||||||
|
- Run `npm test`
|
||||||
|
- Run the tests before sending a pull request, all tests should run.
|
||||||
|
- Please add tests for new behaviors sent in PR.
|
||||||
|
|
||||||
|
5. Send a pull request
|
||||||
|
- Include code changes only to `./src`. **Do not change `./dist` manually.**
|
||||||
|
- In the pull request add a comment like
|
||||||
|
```text
|
||||||
|
@all-contributors please add @mebjas for this new feature or tests
|
||||||
|
```
|
||||||
|
- For calling out your contributions, the bot will update the contributions file.
|
||||||
|
- Code will be built & published by the author in batches.
|
||||||
|
|
||||||
|
## How to contribute
|
||||||
|
You can contribute to the project in several ways:
|
||||||
|
|
||||||
|
- File issue ticket for any observed bug or compatibility issue with the project.
|
||||||
|
- File feature request for missing features.
|
||||||
|
- Take open bugs or feature request and work on it and send a Pull Request.
|
||||||
|
- Write unit tests for existing codebase (which is not covered by tests today). **Help wanted on this** - [read more](./tests).
|
||||||
|
|
||||||
|
## Support 💖
|
||||||
|
|
||||||
|
This project would not be possible without all of our fantastic contributors and [sponsors](https://github.com/sponsors/mebjas). If you'd like to support the maintenance and upkeep of this project you can [donate via GitHub Sponsors](https://github.com/sponsors/mebjas).
|
||||||
|
|
||||||
|
**Sponsor the project for priortising feature requests / bugs relevant to you**. (Depends on scope of ask and bandwidth of the contributors).
|
||||||
|
|
||||||
|
<!-- sponsors -->
|
||||||
|
<a href="https://github.com/webauthor"><img src="https://github.com/webauthor.png" width="40px" alt="webauthor@" /></a>
|
||||||
|
<a href="https://github.com/ben-gy"><img src="https://github.com/ben-gy.png" width="40px" alt="ben-gy" /></a>
|
||||||
|
<a href="https://github.com/bujjivadu"><img src="https://github.com/bujjivadu.png" width="40px" alt="bujjivadu" /></a>
|
||||||
|
<!-- sponsors -->
|
||||||
|
|
||||||
|
Help incentivise feature development, bug fixing by supporting the sponsorhip goals of this project. See [list of sponsered feature requests here](https://github.com/mebjas/html5-qrcode/wiki/Feature-request-sponsorship-goals#feature-requests).
|
||||||
|
|
||||||
|
Also, huge thanks to following organizations for non monitery sponsorships
|
||||||
|
|
||||||
|
<!-- sponsors -->
|
||||||
|
<div>
|
||||||
|
<a href="https://scanapp.org"><img src="https://scanapp.org/assets/svg/scanapp.svg" height="60px" alt="" /></a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="https://www.browserstack.com"><img src="https://www.browserstack.com/images/layout/browserstack-logo-600x315.png" height="100px" alt="" /></a>
|
||||||
|
</div>
|
||||||
|
<!-- sponsors -->
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
The decoder used for the QR code reading is from `Zxing-js` https://github.com/zxing-js/library<br />
|
1
plugins/tiddlywiki/qrcode/files/html5-qrcode/html5-qrcode.min.js
vendored
Normal file
1
plugins/tiddlywiki/qrcode/files/html5-qrcode/html5-qrcode.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -1,18 +1,34 @@
|
|||||||
{
|
{
|
||||||
"tiddlers": [
|
"tiddlers": [
|
||||||
{
|
{
|
||||||
"file": "qrcode.js",
|
"file": "qrcode/qrcode.js",
|
||||||
"fields": {
|
"fields": {
|
||||||
"type": "application/javascript",
|
"type": "application/javascript",
|
||||||
"title": "$:/plugins/tiddlywiki/qrcode/qrcode.js",
|
"title": "$:/plugins/tiddlywiki/qrcode/qrcode/qrcode.js",
|
||||||
"module-type": "library"
|
"module-type": "library"
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
"file": "LICENSE",
|
"file": "qrcode/LICENSE",
|
||||||
"fields": {
|
"fields": {
|
||||||
"type": "text/plain",
|
"type": "text/plain",
|
||||||
"title": "$:/plugins/tiddlywiki/qrcode/license"
|
"title": "$:/plugins/tiddlywiki/qrcode/qrcode/license"
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
"file": "html5-qrcode/html5-qrcode.min.js",
|
||||||
|
"fields": {
|
||||||
|
"type": "application/javascript",
|
||||||
|
"title": "$:/plugins/tiddlywiki/qrcode/html5-qrcode/html5-qrcode.js",
|
||||||
|
"module-type": "library"
|
||||||
|
},
|
||||||
|
"prefix": "window.__Html5QrcodeLibrary__ = {};",
|
||||||
|
"suffix": "\n;exports.__Html5QrcodeLibrary__ = __Html5QrcodeLibrary__;window.__Html5QrcodeLibrary__ = __Html5QrcodeLibrary__;"
|
||||||
|
},{
|
||||||
|
"file": "html5-qrcode/LICENSE",
|
||||||
|
"fields": {
|
||||||
|
"type": "text/plain",
|
||||||
|
"title": "$:/plugins/tiddlywiki/qrcode/html5-qrcode/license"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ Macro to convert a string into a QR Code
|
|||||||
Information about this macro
|
Information about this macro
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var qrcode = require("$:/plugins/tiddlywiki/qrcode/qrcode.js");
|
var qrcode = require("$:/plugins/tiddlywiki/qrcode/qrcode/qrcode.js");
|
||||||
|
|
||||||
var QRCODE_GENERATION_ERROR_PREFIX = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300"><text x="0" y="30" fill="red" font-family="Helvetica, sans-serif" font-size="18">',
|
var QRCODE_GENERATION_ERROR_PREFIX = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300"><text x="0" y="30" fill="red" font-family="Helvetica, sans-serif" font-size="18">',
|
||||||
QRCODE_GENERATION_ERROR_SUFFIX = '</text></svg>';
|
QRCODE_GENERATION_ERROR_SUFFIX = '</text></svg>';
|
||||||
|
@ -3,5 +3,5 @@
|
|||||||
"name": "QR Code",
|
"name": "QR Code",
|
||||||
"description": "QR Code generator",
|
"description": "QR Code generator",
|
||||||
"author": "Zeno Zeng",
|
"author": "Zeno Zeng",
|
||||||
"list": "readme usage examples license"
|
"list": "readme docs examples license"
|
||||||
}
|
}
|
||||||
|
15
plugins/tiddlywiki/qrcode/readme.tid
Normal file
15
plugins/tiddlywiki/qrcode/readme.tid
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
title: $:/plugins/tiddlywiki/qrcode/readme
|
||||||
|
|
||||||
|
The QR Code Plugin contains several features for working with QR codes and other types of barcode.
|
||||||
|
|
||||||
|
* The ''makeqr'' macro enables any text to be rendered as a [[QR code|https://en.wikipedia.org/wiki/QR_code]]. QR codes are a type of 2-dimensional bar code that encodes arbitrary data: text, numbers, links. QR code readers are available or built-in for smartphones, making them a convenient means to transfer information between devices
|
||||||
|
* The `<$barcodereader>` widget that enables barcodes to be decoded from the device camera or direct from an image file
|
||||||
|
* A new toolbar button that can display several QR code renderings of the content of a tiddler:
|
||||||
|
** Raw content
|
||||||
|
** Rendered, formatted content
|
||||||
|
** URL of tiddler
|
||||||
|
|
||||||
|
This plugin uses the following open source libraries:
|
||||||
|
|
||||||
|
* [[qrcode.js by Zeno Zeng|https://github.com/zenozeng/node-yaqrcode]]
|
||||||
|
* [[Html5-QRCode by Minhaz|https://github.com/mebjas/html5-qrcode]]
|
@ -1365,6 +1365,11 @@ html body.tc-body.tc-single-tiddler-window {
|
|||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tc-tiddler-frame .tc-tiddler-editor.tc-tiddler-preview .tc-editor-toolbar,
|
||||||
|
.tc-tiddler-frame .tc-tiddler-editor.tc-tiddler-preview-hidden .tc-editor-toolbar {
|
||||||
|
grid-area: toolbar;
|
||||||
|
}
|
||||||
|
|
||||||
.tc-editor-toolbar button {
|
.tc-editor-toolbar button {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
background-color: <<colour tiddler-controls-foreground>>;
|
background-color: <<colour tiddler-controls-foreground>>;
|
||||||
@ -1576,9 +1581,30 @@ html body.tc-body.tc-single-tiddler-window {
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tc-tiddler-preview-preview {
|
.tc-tiddler-editor {
|
||||||
float: right;
|
display: grid;
|
||||||
width: 49%;
|
}
|
||||||
|
|
||||||
|
.tc-tiddler-frame .tc-tiddler-editor.tc-tiddler-preview {
|
||||||
|
grid-template-areas:
|
||||||
|
"toolbar toolbar"
|
||||||
|
"editor preview";
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
grid-template-rows: auto 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tc-tiddler-frame .tc-tiddler-editor.tc-tiddler-preview-hidden {
|
||||||
|
grid-template-areas:
|
||||||
|
"toolbar"
|
||||||
|
"editor";
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: auto 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tc-tiddler-frame .tc-tiddler-editor.tc-tiddler-preview .tc-tiddler-preview-preview {
|
||||||
|
grid-area: preview;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
word-break: normal;
|
||||||
border: 1px solid <<colour tiddler-editor-border>>;
|
border: 1px solid <<colour tiddler-editor-border>>;
|
||||||
margin: 4px 0 3px 3px;
|
margin: 4px 0 3px 3px;
|
||||||
padding: 3px 3px 3px 3px;
|
padding: 3px 3px 3px 3px;
|
||||||
@ -1593,12 +1619,15 @@ html body.tc-body.tc-single-tiddler-window {
|
|||||||
|
|
||||||
""">>
|
""">>
|
||||||
|
|
||||||
.tc-tiddler-frame .tc-tiddler-preview .tc-edit-texteditor {
|
.tc-tiddler-frame .tc-tiddler-editor.tc-tiddler-preview .tc-edit-texteditor,
|
||||||
width: 49%;
|
.tc-tiddler-frame .tc-tiddler-editor.tc-tiddler-preview-hidden .tc-edit-texteditor {
|
||||||
|
grid-area: editor;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tc-tiddler-frame .tc-tiddler-preview canvas.tc-edit-bitmapeditor {
|
.tc-tiddler-frame .tc-tiddler-editor.tc-tiddler-preview canvas.tc-edit-bitmapeditor,
|
||||||
max-width: 49%;
|
.tc-tiddler-frame .tc-tiddler-editor.tc-tiddler-preview-hidden canvas.tc-edit-bitmapeditor {
|
||||||
|
grid-area: editor;
|
||||||
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tc-edit-fields {
|
.tc-edit-fields {
|
||||||
|
Loading…
Reference in New Issue
Block a user