mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-09-16 06:41:21 +00:00
Split "transclude" widget into a separate "tiddler" and "transclude" widget
Belatedly realised that the design would be clearer without these two separate concepts being conflated into a single widget. As a result of this change, any other widget or template that generates transclude widgets has needed adjustment.
This commit is contained in:
@@ -61,7 +61,7 @@ GridWidget.prototype.generateTable = function() {
|
||||
type: "element",
|
||||
tag: "$transclude",
|
||||
attributes: {
|
||||
target: {type: "string", value: this.getTableCellTitle(col,row)}
|
||||
title: {type: "string", value: this.getTableCellTitle(col,row)}
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
||||
@@ -41,7 +41,7 @@ InfoWidget.types.currentfielddescription = function(options) {
|
||||
tag: "$transclude",
|
||||
isBlock: false,
|
||||
attributes: {
|
||||
target: {type: "string", value: descriptionTitle}
|
||||
title: {type: "string", value: descriptionTitle}
|
||||
}
|
||||
}];
|
||||
};
|
||||
@@ -71,7 +71,7 @@ InfoWidget.types.modules = function(options) {
|
||||
tag: "$transclude",
|
||||
isBlock: false,
|
||||
attributes: {
|
||||
target: {type: "string", value: MODULE_TYPE_DESCRIPTION_PREFIX + moduleType}
|
||||
title: {type: "string", value: MODULE_TYPE_DESCRIPTION_PREFIX + moduleType}
|
||||
}
|
||||
});
|
||||
// List each module
|
||||
|
||||
@@ -197,23 +197,37 @@ ListWidget.prototype.createListElementTransclusion = function(title) {
|
||||
}];
|
||||
}
|
||||
}
|
||||
// Create the transclude widget
|
||||
var widget = {
|
||||
type: "element",
|
||||
tag: "$transclude",
|
||||
isBlock: this.renderer.parseTreeNode.isBlock,
|
||||
attributes: {},
|
||||
children: templateTree
|
||||
};
|
||||
// Set the target if needed
|
||||
if(!this.renderer.hasAttribute("hackTemplate")) {
|
||||
widget.attributes.target = {type: "string", value: title};
|
||||
widget.attributes.template = {type: "string", value: template};
|
||||
// Create the element widgets
|
||||
if(this.renderer.hasAttribute("hackTemplate")) {
|
||||
return {
|
||||
type: "element",
|
||||
tag: "$transclude",
|
||||
isBlock: this.renderer.parseTreeNode.isBlock,
|
||||
attributes: {
|
||||
title: {type: "string", value: title}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
widget.attributes.template = {type: "string", value: title};
|
||||
widget.children = undefined;
|
||||
if(!templateTree) {
|
||||
templateTree = [{
|
||||
type: "element",
|
||||
tag: "$transclude",
|
||||
attributes: {
|
||||
title: {type: "string", value: template}
|
||||
},
|
||||
children: templateTree
|
||||
}];
|
||||
}
|
||||
return {
|
||||
type: "element",
|
||||
tag: "$tiddler",
|
||||
isBlock: this.renderer.parseTreeNode.isBlock,
|
||||
attributes: {
|
||||
title: {type: "string", value: title}
|
||||
},
|
||||
children: templateTree
|
||||
};
|
||||
}
|
||||
return widget;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -245,10 +259,13 @@ ListWidget.prototype.findListElementByTitle = function(startIndex,title) {
|
||||
var testNode = this.macro ? function(node) {
|
||||
// We're looking for a macro list element
|
||||
return node.widget.children[0].parseTreeNode.params[0].value === title;
|
||||
} : function(node) {
|
||||
// We're looking for a transclusion list element
|
||||
return node.widget.children[0].attributes.target === title;
|
||||
};
|
||||
} : (this.renderer.hasAttribute("hackTemplate") ? function(node) {
|
||||
// We're looking for a transclusion list element
|
||||
return node.widget.children[0].attributes.title === title;
|
||||
} : function(node) {
|
||||
// We're looking for a transclusion list element
|
||||
return node.widget.children[0].attributes.title === title;
|
||||
});
|
||||
// Search for the list element
|
||||
while(startIndex < this.children.length) {
|
||||
if(testNode(this.children[startIndex])) {
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/tiddler.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
The tiddler widget sets the current tiddler to a specified title.
|
||||
|
||||
Attributes:
|
||||
title: the title of the current tiddler
|
||||
class: CSS classes
|
||||
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var TiddlerWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate child nodes
|
||||
this.generate();
|
||||
};
|
||||
|
||||
TiddlerWidget.prototype.generate = function() {
|
||||
var self = this;
|
||||
this.tiddlerTitle = this.renderer.getAttribute("title","");
|
||||
// Set up the attributes for the wrapper element
|
||||
var classes = ["tw-tiddler"];
|
||||
if(this.renderer.hasAttribute("class")) {
|
||||
$tw.utils.pushTop(classes,this.renderer.getAttribute("class").split(" "));
|
||||
}
|
||||
if(!this.renderer.renderTree.wiki.tiddlerExists(this.tiddlerTitle) && !this.renderer.renderTree.wiki.isShadowTiddler(this.tiddlerTitle)) {
|
||||
$tw.utils.pushTop(classes,"tw-tiddler-missing");
|
||||
}
|
||||
// Save the context for this renderer node
|
||||
this.renderer.context = {
|
||||
tiddlerTitle: this.tiddlerTitle
|
||||
};
|
||||
// Initialise events
|
||||
this.events = [];
|
||||
// Trap and update tag modification events
|
||||
this.events.push({name: "tw-remove-tag", handlerFunction: function(event) {
|
||||
event.currentTag = self.tiddlerTitle;
|
||||
return true;
|
||||
}});
|
||||
// Set the element
|
||||
this.tag = this.renderer.parseTreeNode.isBlock ? "div" : "span";
|
||||
this.attributes = {};
|
||||
if(classes.length > 0) {
|
||||
this.attributes["class"] = classes.join(" ");
|
||||
}
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,this.renderer.parseTreeNode.children);
|
||||
};
|
||||
|
||||
TiddlerWidget.prototype.refreshInDom = function(changedAttributes,changedTiddlers) {
|
||||
// Set the class for missing tiddlers
|
||||
if(this.tiddlerTitle && changedTiddlers[this.tiddlerTitle]) {
|
||||
$tw.utils.toggleClass(this.renderer.domNode,"tw-tiddler-missing",!this.renderer.renderTree.wiki.tiddlerExists(this.tiddlerTitle));
|
||||
}
|
||||
// Check if any of our attributes have changed, or if a tiddler we're interested in has changed
|
||||
if(changedAttributes.title) {
|
||||
// Regenerate and rerender the widget and replace the existing DOM node
|
||||
this.generate();
|
||||
var oldDomNode = this.renderer.domNode,
|
||||
newDomNode = this.renderer.renderInDom();
|
||||
oldDomNode.parentNode.replaceChild(newDomNode,oldDomNode);
|
||||
} else {
|
||||
// We don't need to refresh ourselves, so just refresh any child nodes
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.refreshInDom) {
|
||||
node.refreshInDom(changedTiddlers);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.tiddler = TiddlerWidget;
|
||||
|
||||
})();
|
||||
@@ -6,38 +6,7 @@ module-type: widget
|
||||
The transclude widget includes another tiddler into the tiddler being rendered.
|
||||
|
||||
Attributes:
|
||||
target: the title of the tiddler to transclude
|
||||
template: the title of the tiddler to use as a template for the transcluded tiddler
|
||||
|
||||
The simplest case is to just supply a target tiddler:
|
||||
|
||||
{{{
|
||||
<$transclude target="Foo"/>
|
||||
}}}
|
||||
|
||||
This will render the tiddler Foo within the current tiddler. If the tiddler Foo includes
|
||||
the view widget (or other widget that reference the fields of the current tiddler), then the
|
||||
fields of the tiddler Foo will be accessed.
|
||||
|
||||
If you want to transclude the tiddler as a template, so that the fields referenced by the view
|
||||
widget are those of the tiddler doing the transcluding, then you can instead specify the tiddler
|
||||
as a template:
|
||||
|
||||
{{{
|
||||
<$transclude template="Foo"/>
|
||||
}}}
|
||||
|
||||
The effect is the same as the previous example: the text of the tiddler Foo is rendered. The
|
||||
difference is that the view widget will access the fields of the tiddler doing the transcluding.
|
||||
|
||||
The `target` and `template` attributes may be combined:
|
||||
|
||||
{{{
|
||||
<$transclude template="Bar" target="Foo"/>
|
||||
}}}
|
||||
|
||||
Here, the text of the tiddler `Bar` will be transcluded, with the widgets within it accessing the fields
|
||||
of the tiddler `Foo`.
|
||||
title: the title of the tiddler to transclude
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
@@ -55,65 +24,49 @@ var TranscludeWidget = function(renderer) {
|
||||
|
||||
TranscludeWidget.prototype.generate = function() {
|
||||
var self = this,
|
||||
tr, templateParseTree, templateTiddler;
|
||||
templateParseTree;
|
||||
// Get the render target details
|
||||
this.targetTitle = this.renderer.getAttribute("target",this.renderer.tiddlerTitle);
|
||||
this.targetField = this.renderer.getAttribute("field");
|
||||
this.targetIndex = this.renderer.getAttribute("index");
|
||||
// Get the render tree for the template
|
||||
this.templateTitle = undefined;
|
||||
if(this.renderer.parseTreeNode.children && this.renderer.parseTreeNode.children.length > 0) {
|
||||
// Use the child nodes as the template if we've got them
|
||||
templateParseTree = this.renderer.parseTreeNode.children;
|
||||
this.transcludeTitle = this.renderer.getAttribute("title",this.renderer.tiddlerTitle);
|
||||
this.transcludeField = this.renderer.getAttribute("field");
|
||||
this.transcludeIndex = this.renderer.getAttribute("index");
|
||||
// Check for recursion
|
||||
if(this.renderer.renderTree.checkContextRecursion(this.renderer.parentRenderer,{
|
||||
transcludeTitle: this.transcludeTitle,
|
||||
transcludeField: this.transcludeField,
|
||||
transcludeIndex: this.transcludeIndex
|
||||
})) {
|
||||
templateParseTree = [{type: "text", text: "Tiddler recursion error in transclude widget"}];
|
||||
} else {
|
||||
this.templateTitle = this.renderer.getAttribute("template",this.targetTitle);
|
||||
// Check for recursion
|
||||
if(this.renderer.renderTree.checkContextRecursion(this.renderer.parentRenderer,{
|
||||
tiddlerTitle: this.targetTitle,
|
||||
templateTitle: this.templateTitle
|
||||
})) {
|
||||
templateParseTree = [{type: "text", text: "Tiddler recursion error in transclude widget"}];
|
||||
var parser;
|
||||
if(this.transcludeField === "text" || (!this.transcludeField && !this.transcludeIndex)) {
|
||||
parser = this.renderer.renderTree.wiki.parseTiddler(this.transcludeTitle,{parseAsInline: !this.renderer.parseTreeNode.isBlock});
|
||||
} else {
|
||||
var parser;
|
||||
if(this.targetField === "text" || (!this.targetField && !this.targetIndex)) {
|
||||
parser = this.renderer.renderTree.wiki.parseTiddler(this.templateTitle,{parseAsInline: !this.renderer.parseTreeNode.isBlock});
|
||||
} else {
|
||||
var tiddler,text;
|
||||
if(this.targetField) {
|
||||
tiddler = this.renderer.renderTree.wiki.getTiddler(this.targetTitle);
|
||||
text = tiddler ? tiddler.fields[this.targetField] : "";
|
||||
if(text === undefined) {
|
||||
text = "";
|
||||
}
|
||||
parser = this.renderer.renderTree.wiki.parseText("text/vnd.tiddlywiki",text,{parseAsInline: !this.renderer.parseTreeNode.isBlock});
|
||||
} else if(this.targetIndex) {
|
||||
text = this.renderer.renderTree.wiki.extractTiddlerDataItem(this.targetTitle,this.targetIndex,"");
|
||||
parser = this.renderer.renderTree.wiki.parseText("text/vnd.tiddlywiki",text,{parseAsInline: !this.renderer.parseTreeNode.isBlock});
|
||||
var tiddler,text;
|
||||
if(this.transcludeField) {
|
||||
tiddler = this.renderer.renderTree.wiki.getTiddler(this.transcludeTitle);
|
||||
text = tiddler ? tiddler.fields[this.transcludeField] : "";
|
||||
if(text === undefined) {
|
||||
text = "";
|
||||
}
|
||||
parser = this.renderer.renderTree.wiki.parseText("text/vnd.tiddlywiki",text,{parseAsInline: !this.renderer.parseTreeNode.isBlock});
|
||||
} else if(this.transcludeIndex) {
|
||||
text = this.renderer.renderTree.wiki.extractTiddlerDataItem(this.transcludeTitle,this.transcludeIndex,"");
|
||||
parser = this.renderer.renderTree.wiki.parseText("text/vnd.tiddlywiki",text,{parseAsInline: !this.renderer.parseTreeNode.isBlock});
|
||||
}
|
||||
templateParseTree = parser ? parser.tree : [];
|
||||
}
|
||||
templateParseTree = parser ? parser.tree : [];
|
||||
}
|
||||
// Set up the attributes for the wrapper element
|
||||
var classes = ["tw-transclude"];
|
||||
if(this.renderer.hasAttribute("class")) {
|
||||
$tw.utils.pushTop(classes,this.renderer.getAttribute("class").split(" "));
|
||||
}
|
||||
if(!this.renderer.renderTree.wiki.tiddlerExists(this.targetTitle) && !this.renderer.renderTree.wiki.isShadowTiddler(this.targetTitle)) {
|
||||
$tw.utils.pushTop(classes,"tw-tiddler-missing");
|
||||
}
|
||||
// Save the context for this renderer node
|
||||
this.renderer.context = {
|
||||
tiddlerTitle: this.targetTitle,
|
||||
templateTitle: this.templateTitle
|
||||
transcludeTitle: this.transcludeTitle,
|
||||
transcludeField: this.transcludeField,
|
||||
transcludeIndex: this.transcludeIndex
|
||||
};
|
||||
// Initialise events
|
||||
this.events = [];
|
||||
// Trap and update tag modification events
|
||||
this.events.push({name: "tw-remove-tag", handlerFunction: function(event) {
|
||||
event.currentTag = self.targetTitle;
|
||||
return true;
|
||||
}});
|
||||
// Set the element
|
||||
this.tag = this.renderer.parseTreeNode.isBlock ? "div" : "span";
|
||||
this.attributes = {};
|
||||
@@ -130,12 +83,8 @@ TranscludeWidget.prototype.generate = function() {
|
||||
};
|
||||
|
||||
TranscludeWidget.prototype.refreshInDom = function(changedAttributes,changedTiddlers) {
|
||||
// Set the class for missing tiddlers
|
||||
if(this.targetTitle && changedTiddlers[this.targetTitle]) {
|
||||
$tw.utils.toggleClass(this.renderer.domNode,"tw-tiddler-missing",!this.renderer.renderTree.wiki.tiddlerExists(this.targetTitle));
|
||||
}
|
||||
// Check if any of our attributes have changed, or if a tiddler we're interested in has changed
|
||||
if(changedAttributes.target || changedAttributes.template || (this.templateTitle && changedTiddlers[this.templateTitle])) {
|
||||
if(changedAttributes.transcludeField || changedAttributes.transcludeIndex || (this.transcludeTitle && changedTiddlers[this.transcludeTitle])) {
|
||||
// Regenerate and rerender the widget and replace the existing DOM node
|
||||
this.generate();
|
||||
var oldDomNode = this.renderer.domNode,
|
||||
|
||||
Reference in New Issue
Block a user