mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-12-02 14:29:55 +00:00
Fix: transcludes and backtranscludes operators to always include self-referential transclusion (#8257)
* fix: ignore self-referential transclusion * feat: support old <$transclude tiddler param * fix: restore old behavior: include itself like backlinks[] * refactor: use LinkedList in transcludes[] and backtranscludes[] * fix: only fallback to title when {{!!xxx}}, not when input is empty * refactor: move transcludes ast extractor to a file * refactor: move links ast extractor to a file * Revert "refactor: move links ast extractor to a file" This reverts commit5600a00cd8
. * Revert "refactor: move transcludes ast extractor to a file" This reverts commit61d5484f09
. * lint: use pushTop and remove space
This commit is contained in:
parent
8eb08820ac
commit
741aef55e4
@ -16,11 +16,11 @@ Filter operator for returning all the backtranscludes from a tiddler
|
|||||||
Export our filter function
|
Export our filter function
|
||||||
*/
|
*/
|
||||||
exports.backtranscludes = function(source,operator,options) {
|
exports.backtranscludes = function(source,operator,options) {
|
||||||
var results = [];
|
var results = new $tw.utils.LinkedList();
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
$tw.utils.pushTop(results,options.wiki.getTiddlerBacktranscludes(title));
|
results.pushTop(options.wiki.getTiddlerBacktranscludes(title));
|
||||||
});
|
});
|
||||||
return results;
|
return results.makeTiddlerIterator(options.wiki);
|
||||||
};
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -20,7 +20,7 @@ exports.transcludes = function(source,operator,options) {
|
|||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
results.pushTop(options.wiki.getTiddlerTranscludes(title));
|
results.pushTop(options.wiki.getTiddlerTranscludes(title));
|
||||||
});
|
});
|
||||||
return results.toArray();
|
return results.makeTiddlerIterator(options.wiki);
|
||||||
};
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -75,7 +75,7 @@ BackSubIndexer.prototype._getTarget = function(tiddler) {
|
|||||||
}
|
}
|
||||||
var parser = this.wiki.parseText(tiddler.fields.type, tiddler.fields.text, {});
|
var parser = this.wiki.parseText(tiddler.fields.type, tiddler.fields.text, {});
|
||||||
if(parser) {
|
if(parser) {
|
||||||
return this.wiki[this.extractor](parser.tree);
|
return this.wiki[this.extractor](parser.tree, tiddler.fields.title);
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
@ -551,28 +551,41 @@ exports.getTiddlerBacklinks = function(targetTitle) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Return an array of tiddler titles that are directly transcluded within the given parse tree
|
Return an array of tiddler titles that are directly transcluded within the given parse tree. `title` is the tiddler being parsed, we will ignore its self-referential transclusions, only return
|
||||||
*/
|
*/
|
||||||
exports.extractTranscludes = function(parseTreeRoot) {
|
exports.extractTranscludes = function(parseTreeRoot, title) {
|
||||||
// Count up the transcludes
|
// Count up the transcludes
|
||||||
var transcludes = [],
|
var transcludes = [],
|
||||||
checkParseTree = function(parseTree, parentNode) {
|
checkParseTree = function(parseTree, parentNode) {
|
||||||
for(var t=0; t<parseTree.length; t++) {
|
for(var t=0; t<parseTree.length; t++) {
|
||||||
var parseTreeNode = parseTree[t];
|
var parseTreeNode = parseTree[t];
|
||||||
if(parseTreeNode.type === "transclude" && parseTreeNode.attributes.$tiddler && parseTreeNode.attributes.$tiddler.type === "string") {
|
if(parseTreeNode.type === "transclude") {
|
||||||
|
if(parseTreeNode.attributes.$tiddler && parseTreeNode.attributes.$tiddler.type === "string") {
|
||||||
var value;
|
var value;
|
||||||
// if it is Transclusion with Templates like `{{Index||$:/core/ui/TagTemplate}}`, the `$tiddler` will point to the template. We need to find the actual target tiddler from parent node
|
// if it is Transclusion with Templates like `{{Index||$:/core/ui/TagTemplate}}`, the `$tiddler` will point to the template. We need to find the actual target tiddler from parent node
|
||||||
if(parentNode && parentNode.type === "tiddler" && parentNode.attributes.tiddler && parentNode.attributes.tiddler.type === "string") {
|
if(parentNode && parentNode.type === "tiddler" && parentNode.attributes.tiddler && parentNode.attributes.tiddler.type === "string") {
|
||||||
value = parentNode.attributes.tiddler.value;
|
// Empty value (like `{{!!field}}`) means self-referential transclusion.
|
||||||
|
value = parentNode.attributes.tiddler.value || title;
|
||||||
} else {
|
} else {
|
||||||
value = parseTreeNode.attributes.$tiddler.value;
|
value = parseTreeNode.attributes.$tiddler.value;
|
||||||
}
|
}
|
||||||
if(transcludes.indexOf(value) === -1 && value !== undefined) {
|
} else if(parseTreeNode.attributes.tiddler && parseTreeNode.attributes.tiddler.type === "string") {
|
||||||
transcludes.push(value);
|
// Old transclude widget usage
|
||||||
|
value = parseTreeNode.attributes.tiddler.value;
|
||||||
|
} else if(parseTreeNode.attributes.$field && parseTreeNode.attributes.$field.type === "string") {
|
||||||
|
// Empty value (like `<$transclude $field='created'/>`) means self-referential transclusion.
|
||||||
|
value = title;
|
||||||
|
} else if(parseTreeNode.attributes.field && parseTreeNode.attributes.field.type === "string") {
|
||||||
|
// Old usage with Empty value (like `<$transclude field='created'/>`)
|
||||||
|
value = title;
|
||||||
|
}
|
||||||
|
// Deduplicate the result.
|
||||||
|
if(value && transcludes.indexOf(value) === -1) {
|
||||||
|
$tw.utils.pushTop(transcludes,value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(parseTreeNode.children) {
|
if(parseTreeNode.children) {
|
||||||
checkParseTree(parseTreeNode.children, parseTreeNode);
|
checkParseTree(parseTreeNode.children,parseTreeNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -591,7 +604,8 @@ exports.getTiddlerTranscludes = function(title) {
|
|||||||
// Parse the tiddler
|
// Parse the tiddler
|
||||||
var parser = self.parseTiddler(title);
|
var parser = self.parseTiddler(title);
|
||||||
if(parser) {
|
if(parser) {
|
||||||
return self.extractTranscludes(parser.tree);
|
// this will ignore self-referential transclusions from `title`
|
||||||
|
return self.extractTranscludes(parser.tree,title);
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
|
@ -22,6 +22,9 @@ describe('Backtranscludes and transclude filter tests', function() {
|
|||||||
it('should have no backtranscludes', function() {
|
it('should have no backtranscludes', function() {
|
||||||
expect(wiki.filterTiddlers('TestIncoming +[backtranscludes[]]').join(',')).toBe('');
|
expect(wiki.filterTiddlers('TestIncoming +[backtranscludes[]]').join(',')).toBe('');
|
||||||
});
|
});
|
||||||
|
it('should have no transcludes', function() {
|
||||||
|
expect(wiki.filterTiddlers('TestIncoming +[transcludes[]]').join(',')).toBe('');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('A tiddler added to the wiki with a transclude to it', function() {
|
describe('A tiddler added to the wiki with a transclude to it', function() {
|
||||||
@ -38,6 +41,9 @@ describe('Backtranscludes and transclude filter tests', function() {
|
|||||||
it('should have a backtransclude', function() {
|
it('should have a backtransclude', function() {
|
||||||
expect(wiki.filterTiddlers('TestIncoming +[backtranscludes[]]').join(',')).toBe('TestOutgoing');
|
expect(wiki.filterTiddlers('TestIncoming +[backtranscludes[]]').join(',')).toBe('TestOutgoing');
|
||||||
});
|
});
|
||||||
|
it('should have a transclude', function() {
|
||||||
|
expect(wiki.filterTiddlers('TestOutgoing +[transcludes[]]').join(',')).toBe('TestIncoming');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('A tiddler transclude with template will still use the tiddler as result.', function() {
|
describe('A tiddler transclude with template will still use the tiddler as result.', function() {
|
||||||
@ -182,35 +188,52 @@ describe('Backtranscludes and transclude filter tests', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('ignore self transclusion', function() {
|
describe('include implicit self transclusion', function() {
|
||||||
var wiki = new $tw.Wiki();
|
var wiki = new $tw.Wiki();
|
||||||
|
|
||||||
wiki.addTiddler({
|
wiki.addTiddler({
|
||||||
title: 'TestOutgoing',
|
title: 'TestOutgoing',
|
||||||
text: "{{!!created}}\n\nA transclude to {{!!title}}"});
|
text: "{{!!created}}\n\nAn implicit self-referential transclude to <$transclude $field='created'/> and <$transclude field='created'/>"});
|
||||||
|
|
||||||
it('should have no transclude', function() {
|
it('should have no transclude', function() {
|
||||||
expect(wiki.filterTiddlers('TestOutgoing +[transcludes[]]').join(',')).toBe('');
|
expect(wiki.filterTiddlers('TestOutgoing +[transcludes[]]').join(',')).toBe('TestOutgoing');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have no back transcludes', function() {
|
it('should have no back transcludes', function() {
|
||||||
expect(wiki.filterTiddlers('TestOutgoing +[backtranscludes[]]').join(',')).toBe('');
|
expect(wiki.filterTiddlers('TestOutgoing +[backtranscludes[]]').join(',')).toBe('TestOutgoing');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('recognize soft transclusion defined by widget', function() {
|
describe('include explicit self transclusion', function() {
|
||||||
var wiki = new $tw.Wiki();
|
var wiki = new $tw.Wiki();
|
||||||
|
|
||||||
wiki.addTiddler({
|
wiki.addTiddler({
|
||||||
title: 'TestOutgoing',
|
title: 'TestOutgoing',
|
||||||
text: "<$tiddler tiddler='TestIncoming'><$transclude $tiddler /></$tiddler>"});
|
text: "{{TestOutgoing!!created}}\n\n<$transclude $tiddler='TestOutgoing' $field='created'/> and <$transclude tiddler='TestOutgoing' field='created'/>"});
|
||||||
|
|
||||||
|
it('should have no transclude', function() {
|
||||||
|
expect(wiki.filterTiddlers('TestOutgoing +[transcludes[]]').join(',')).toBe('TestOutgoing');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have no back transcludes', function() {
|
||||||
|
expect(wiki.filterTiddlers('TestOutgoing +[backtranscludes[]]').join(',')).toBe('TestOutgoing');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('recognize transclusion defined by widget', function() {
|
||||||
|
var wiki = new $tw.Wiki();
|
||||||
|
|
||||||
|
wiki.addTiddler({
|
||||||
|
title: 'TestOutgoing',
|
||||||
|
text: "<$tiddler tiddler='TestIncoming'><$transclude $tiddler /></$tiddler>\n\n<$transclude tiddler='TiddlyWiki Pre-release'/>"});
|
||||||
|
|
||||||
it('should have a transclude', function() {
|
it('should have a transclude', function() {
|
||||||
expect(wiki.filterTiddlers('TestOutgoing +[transcludes[]]').join(',')).toBe('TestIncoming');
|
expect(wiki.filterTiddlers('TestOutgoing +[transcludes[]]').join(',')).toBe('TestIncoming,TiddlyWiki Pre-release');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have a back transclude', function() {
|
it('should have a back transclude', function() {
|
||||||
expect(wiki.filterTiddlers('TestIncoming +[backtranscludes[]]').join(',')).toBe('TestOutgoing');
|
expect(wiki.filterTiddlers('TestIncoming +[backtranscludes[]]').join(',')).toBe('TestOutgoing');
|
||||||
|
expect(wiki.filterTiddlers('[[TiddlyWiki Pre-release]] +[backtranscludes[]]').join(',')).toBe('TestOutgoing');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user