mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-27 20:10:03 +00:00
Transclude: replace paramNames/paramValues with more robust JSON payload
More details at https://github.com/Jermolene/TiddlyWiki5/pull/6666#issuecomment-1123719153
This commit is contained in:
parent
a827290332
commit
774459fa73
181
core/modules/filters/json-ops.js
Normal file
181
core/modules/filters/json-ops.js
Normal file
@ -0,0 +1,181 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/json-ops.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operators for JSON operations
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports["jsonget"] = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var data = $tw.utils.parseJSONSafe(title,{});
|
||||
if(data) {
|
||||
var item = getDataItemValueAsStrings(data,operator.operands);
|
||||
if(item !== undefined) {
|
||||
results.push.apply(results,item);
|
||||
}
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
exports["jsonextract"] = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var data = $tw.utils.parseJSONSafe(title,{});
|
||||
if(data) {
|
||||
var item = getDataItem(data,operator.operands);
|
||||
if(item !== undefined) {
|
||||
results.push(JSON.stringify(item));
|
||||
}
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
exports["jsonindexes"] = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var data = $tw.utils.parseJSONSafe(title,{});
|
||||
if(data) {
|
||||
var item = getDataItemKeysAsStrings(data,operator.operands);
|
||||
if(item !== undefined) {
|
||||
results.push.apply(results,item);
|
||||
}
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
exports["jsontype"] = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
var data = $tw.utils.parseJSONSafe(title,{});
|
||||
if(data) {
|
||||
var item = getDataItemType(data,operator.operands);
|
||||
if(item !== undefined) {
|
||||
results.push(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
/*
|
||||
Given a JSON data structure and an array of index strings, return an array of the string representation of the values at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||
*/
|
||||
function getDataItemValueAsStrings(data,indexes) {
|
||||
// Get the item
|
||||
var item = getDataItem(data,indexes);
|
||||
// Return the item as a string
|
||||
return convertDataItemValueToStrings(item);
|
||||
}
|
||||
|
||||
/*
|
||||
Given a JSON data structure and an array of index strings, return an array of the string representation of the keys of the item at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||
*/
|
||||
function getDataItemKeysAsStrings(data,indexes) {
|
||||
// Get the item
|
||||
var item = getDataItem(data,indexes);
|
||||
// Return the item keys as a string
|
||||
return convertDataItemKeysToStrings(item);
|
||||
}
|
||||
|
||||
/*
|
||||
Return an array of the string representation of the values of a data item, or "undefined" if the item is undefined
|
||||
*/
|
||||
function convertDataItemValueToStrings(item) {
|
||||
// Return the item as a string
|
||||
if(item === undefined) {
|
||||
return item;
|
||||
}
|
||||
if(typeof item === "object") {
|
||||
if(item === null) {
|
||||
return ["null"];
|
||||
}
|
||||
var results = [];
|
||||
if($tw.utils.isArray(item)) {
|
||||
$tw.utils.each(item,function(value) {
|
||||
results.push.apply(results,convertDataItemValueToStrings(value));
|
||||
});
|
||||
return results;
|
||||
} else {
|
||||
$tw.utils.each(Object.keys(item).sort(),function(key) {
|
||||
results.push.apply(results,convertDataItemValueToStrings(item[key]));
|
||||
});
|
||||
return results;
|
||||
}
|
||||
}
|
||||
return [item.toString()];
|
||||
}
|
||||
|
||||
/*
|
||||
Return an array of the string representation of the keys of a data item, or "undefined" if the item is undefined
|
||||
*/
|
||||
function convertDataItemKeysToStrings(item) {
|
||||
// Return the item as a string
|
||||
if(item === undefined) {
|
||||
return item;
|
||||
} else if(typeof item === "object") {
|
||||
if(item === null) {
|
||||
return [];
|
||||
}
|
||||
var results = [];
|
||||
if($tw.utils.isArray(item)) {
|
||||
for(var i=0; i<item.length; i++) {
|
||||
results.push(i.toString());
|
||||
}
|
||||
return results;
|
||||
} else {
|
||||
$tw.utils.each(Object.keys(item).sort(),function(key) {
|
||||
results.push(key);
|
||||
});
|
||||
return results;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function getDataItemType(data,indexes) {
|
||||
// Get the item
|
||||
var item = getDataItem(data,indexes);
|
||||
// Return the item type
|
||||
if(item === undefined) {
|
||||
return item;
|
||||
} else if(item === null) {
|
||||
return "null";
|
||||
} else if($tw.utils.isArray(item)) {
|
||||
return "array";
|
||||
} else if(typeof item === "object") {
|
||||
return "object";
|
||||
} else {
|
||||
return typeof item;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Given a JSON data structure and an array of index strings, return the value at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||
*/
|
||||
function getDataItem(data,indexes) {
|
||||
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
||||
return data;
|
||||
}
|
||||
// Get the item
|
||||
var item = data;
|
||||
for(var i=0; i<indexes.length; i++) {
|
||||
if(item !== undefined) {
|
||||
item = item[indexes[i]];
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
})();
|
||||
|
@ -317,30 +317,11 @@ TranscludeWidget.prototype.getTransclusionParameter = function(name,index,defaul
|
||||
Get a hashmap of the special variables to be provided by the parameters widget
|
||||
*/
|
||||
TranscludeWidget.prototype.getTransclusionMetaVariables = function() {
|
||||
return {
|
||||
paramNames: $tw.utils.stringifyList(this.getTransclusionParameterNames()),
|
||||
paramValues: $tw.utils.stringifyList(this.getTransclusionParameterValues()),
|
||||
parseAsInline: this.parseAsInline ? "yes" : "no"
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Get an array of the names of all the provided transclusion parameters
|
||||
*/
|
||||
TranscludeWidget.prototype.getTransclusionParameterNames = function() {
|
||||
return Object.keys(this.stringParametersByName);
|
||||
};
|
||||
|
||||
/*
|
||||
Get an array of the values of all the provided transclusion parameters
|
||||
*/
|
||||
TranscludeWidget.prototype.getTransclusionParameterValues = function() {
|
||||
var self = this,
|
||||
values = [];
|
||||
$tw.utils.each(Object.keys(this.stringParametersByName),function(name) {
|
||||
values.push(self.stringParametersByName[name] || "");
|
||||
});
|
||||
return values;
|
||||
var variables = {
|
||||
"@parseAsInline": this.parseAsInline ? "yes" : "no",
|
||||
"@params": JSON.stringify(this.stringParametersByName)
|
||||
};
|
||||
return variables;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -17,24 +17,24 @@ Block transclusions are shown in red, and inline transclusions are shown in gree
|
||||
<$genesis $type="element" $tag=<<outputTag>> style="display: inline-block;">
|
||||
<div style="background:white;color:black;font-size: 12px;line-height:1.2;text-align:left;font-weight:normal;padding:4px;margin:4px;">
|
||||
<!-- Render the parameters to the transclusion -->
|
||||
<$list filter="[enlist:raw<paramNames>]" counter="counter" emptyMessage="(none)">
|
||||
<$list filter="[<@params>jsonindexes[]]" emptyMessage="(none)">
|
||||
<div>
|
||||
<$text text=<<currentTiddler>>/><$text text=": "/><$text text={{{ [enlist:raw<paramValues>nth<counter>] }}}/>
|
||||
<$text text=<<currentTiddler>>/><$text text=": "/><$text text={{{ [<@params>jsonget<currentTiddler>] }}}/>
|
||||
</div>
|
||||
</$list>
|
||||
</div>
|
||||
</$genesis>
|
||||
<$genesis $type="element" $tag=<<outputTag>> style="background:white;color:black;padding:4px;">
|
||||
<!-- Look for a parameter starting with $ to determine if we are in legacy mode -->
|
||||
<$list filter="[enlist:raw<paramNames>] :filter[<currentTiddler>prefix[$]] +[limit[1]]" variable="ignore" emptyMessage="""
|
||||
<$list filter="[<@params>jsonindexes[]] :filter[<currentTiddler>prefix[$]] +[limit[1]]" variable="ignore" emptyMessage="""
|
||||
<!-- Legacy mode: we render the transclusion without a dollar sign for recursionMarker and mode -->
|
||||
<$genesis $type="transclude" $remappable="no" $names="[enlist:raw<paramNames>]" $values="[enlist:raw<paramValues>]" recursionMarker="no" mode=<<mode>>>
|
||||
<$genesis $type="transclude" $remappable="no" $names="[<@params>jsonindexes[]]" $values="[<@params>jsonindexes[]] :map[<@params>jsonget<currentTiddler>]" recursionMarker="no" mode=<<mode>>>
|
||||
<!-- Reach back up to the grandparent transclusion to get the correct slot value -->
|
||||
<$slot $name="ts-raw" $depth="2"/>
|
||||
</$genesis>
|
||||
""">
|
||||
<!-- Non-legacy mode: we use dollar signs for the recursionMarker and mode -->
|
||||
<$genesis $type="transclude" $remappable="no" $names="[enlist:raw<paramNames>]" $values="[enlist:raw<paramValues>]" $$recursionMarker="no" $$mode=<<mode>>>
|
||||
<$genesis $type="transclude" $remappable="no" $names="[<@params>jsonindexes[]]" $values="[<@params>jsonindexes[]] :map[<@params>jsonget<currentTiddler>]" $$recursionMarker="no" $$mode=<<mode>>>
|
||||
<!-- Reach back up to the grandparent transclusion to get the correct slot value -->
|
||||
<$slot $name="ts-raw" $depth="2"/>
|
||||
</$genesis>
|
||||
|
@ -8,7 +8,7 @@ title: Output
|
||||
\whitespace trim
|
||||
\procedure <$let>
|
||||
\whitespace trim
|
||||
<$setmultiplevariables $names="[enlist:raw<paramNames>]" $values="[enlist:raw<paramValues>addprefix[--]addsuffix[--]]">
|
||||
<$setmultiplevariables $names="[<@params>jsonindexes[]]" $values="[<@params>jsonindexes[]] :map[<@params>jsonget<currentTiddler>addprefix[--]addsuffix[--]]">
|
||||
<$slot $name="ts-body"/>
|
||||
</$setmultiplevariables>
|
||||
\end
|
||||
|
@ -18,8 +18,8 @@ title: TiddlerOne
|
||||
|
||||
\whitespace trim
|
||||
\parameters(zero:'Jaguar',one:'Lizard',two:'Mole')
|
||||
<$list filter="[enlist<paramNames>]" counter="counter">
|
||||
{<$text text={{{ [enlist:raw<paramNames>nth<counter>] }}}/>:<$text text={{{ [enlist:raw<paramValues>nth<counter>] }}}/>}
|
||||
<$list filter="[<@params>jsonindexes[]]">
|
||||
{<$text text=<<currentTiddler>>/>: <$text text={{{ [<@params>jsonget<currentTiddler>] }}}/>}
|
||||
</$list>
|
||||
+
|
||||
title: TiddlerTwo
|
||||
@ -30,4 +30,4 @@ title: TiddlerTwo
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>{0:}{1:}{2:}</p><p></p><p>{0:Ferret}</p><p>{0:Butterfly}{1:Moth}</p><p>{0:Beetle}{1:Scorpion}{2:Snake}</p><p>({zero:Beetle}{one:Scorpion}{two:Snake})</p>
|
||||
<p>{0:}{1:}{2:}</p><p></p><p>{0:Ferret}</p><p>{0:Butterfly}{1:Moth}</p><p>{0:Beetle}{1:Scorpion}{2:Snake}</p><p>({one:Scorpion}{two:Snake}{zero:Beetle})</p>
|
98
editions/test/tiddlers/tests/test-json-filters.js
Normal file
98
editions/test/tiddlers/tests/test-json-filters.js
Normal file
@ -0,0 +1,98 @@
|
||||
/*\
|
||||
title: test-json-filters.js
|
||||
type: application/javascript
|
||||
tags: [[$:/tags/test-spec]]
|
||||
|
||||
Tests the JSON filters.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/* jslint node: true, browser: true */
|
||||
/* eslint-env node, browser, jasmine */
|
||||
/* eslint no-mixed-spaces-and-tabs: ["error", "smart-tabs"]*/
|
||||
/* global $tw, require */
|
||||
"use strict";
|
||||
|
||||
describe("json filter tests", function() {
|
||||
|
||||
var wiki = new $tw.Wiki();
|
||||
var tiddlers = [{
|
||||
title: "First",
|
||||
text: '{"a":"one","b":"","c":1.618,"d": {"e": "four","f": ["five","six",true,false,null]}}',
|
||||
type: "application/json"
|
||||
},{
|
||||
title: "Second",
|
||||
text: '["une","deux","trois"]',
|
||||
type: "application/json"
|
||||
}];
|
||||
wiki.addTiddlers(tiddlers);
|
||||
|
||||
it("should support the getindex operator", function() {
|
||||
expect(wiki.filterTiddlers("[{First}getindex[b]]")).toEqual([]);
|
||||
});
|
||||
|
||||
it("should support the jsonget operator", function() {
|
||||
expect(wiki.filterTiddlers("[{First}jsonget[]]")).toEqual(["one","","1.618","four","five","six","true","false","null"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonget[a]]")).toEqual(["one"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonget[b]]")).toEqual([""]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonget[missing-property]]")).toEqual([]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonget[d]]")).toEqual(["four","five","six","true","false","null"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonget[d],[e]]")).toEqual(["four"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonget[d],[f]]")).toEqual(["five","six","true","false","null"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonget[d],[f],[0]]")).toEqual(["five"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonget[d],[f],[1]]")).toEqual(["six"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonget[d],[f],[2]]")).toEqual(["true"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonget[d],[f],[3]]")).toEqual(["false"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonget[d],[f],[4]]")).toEqual(["null"]);
|
||||
});
|
||||
|
||||
it("should support the jsonextract operator", function() {
|
||||
expect(wiki.filterTiddlers("[{First}jsonextract[]]")).toEqual([`{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}`]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonextract[a]]")).toEqual([`"one"`]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonextract[b]]")).toEqual([`""`]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonextract[d]]")).toEqual([`{"e":"four","f":["five","six",true,false,null]}`]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonextract[missing-property]]")).toEqual([]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonextract[d],[e]]")).toEqual([`"four"`]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonextract[d],[f]]")).toEqual([`["five","six",true,false,null]`]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonextract[d],[f],[0]]")).toEqual([`"five"`]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonextract[d],[f],[1]]")).toEqual([`"six"`]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonextract[d],[f],[2]]")).toEqual([`true`]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonextract[d],[f],[3]]")).toEqual([`false`]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonextract[d],[f],[4]]")).toEqual([`null`]);
|
||||
});
|
||||
|
||||
it("should support the jsonindexes operator", function() {
|
||||
expect(wiki.filterTiddlers("[{Second}jsonindexes[]]")).toEqual(["0","1","2"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonindexes[]]")).toEqual(["a","b","c","d"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonindexes[a]]")).toEqual([]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonindexes[b]]")).toEqual([]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonindexes[d]]")).toEqual(["e","f"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonindexes[d],[e]]")).toEqual([]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonindexes[d],[f]]")).toEqual(["0","1","2","3","4"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonindexes[d],[f],[0]]")).toEqual([]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonindexes[d],[f],[1]]")).toEqual([]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonindexes[d],[f],[2]]")).toEqual([]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonindexes[d],[f],[3]]")).toEqual([]);
|
||||
expect(wiki.filterTiddlers("[{First}jsonindexes[d],[f],[4]]")).toEqual([]);
|
||||
});
|
||||
|
||||
it("should support the jsontype operator", function() {
|
||||
expect(wiki.filterTiddlers("[{First}jsontype[]]")).toEqual(["object"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsontype[a]]")).toEqual(["string"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsontype[b]]")).toEqual(["string"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsontype[c]]")).toEqual(["number"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsontype[d]]")).toEqual(["object"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsontype[d],[e]]")).toEqual(["string"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsontype[d],[f]]")).toEqual(["array"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsontype[d],[f],[0]]")).toEqual(["string"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsontype[d],[f],[1]]")).toEqual(["string"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsontype[d],[f],[2]]")).toEqual(["boolean"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsontype[d],[f],[3]]")).toEqual(["boolean"]);
|
||||
expect(wiki.filterTiddlers("[{First}jsontype[d],[f],[4]]")).toEqual(["null"]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user