mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-09-23 09:48:43 +00:00
Introduce refactored wiki parser and renderer
This is a half-way through a big refactoring of the parsing and rendering infrastructure. The main change is to separate the parse and render trees, which makes the code a lot cleaner. The new parser isn't yet functional enough to replace the existing parser so for the moment you have to manually invoke it with `$tw.testNewParser()` in your browser console. I really ought to use branches for this kind of thing...
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
/*\
|
||||
title: $:/core/modules/widget/button.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Implements the button widget.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var ButtonWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate child nodes
|
||||
this.generateChildNodes();
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.generateChildNodes = function() {
|
||||
// Get the parameters from the attributes
|
||||
this.message = this.renderer.getAttribute("message");
|
||||
this.param = this.renderer.getAttribute("param");
|
||||
this.set = this.renderer.getAttribute("set");
|
||||
this.setTo = this.renderer.getAttribute("setTo");
|
||||
this.popup = this.renderer.getAttribute("popup");
|
||||
this.hover = this.renderer.getAttribute("hover");
|
||||
this.qualifyTiddlerTitles = this.renderer.getAttribute("qualifyTiddlerTitles");
|
||||
this["class"] = this.renderer.getAttribute("class");
|
||||
// Compose the button
|
||||
var classes = ["tw-tiddlybutton"];
|
||||
if(this.classes) {
|
||||
$tw.utils.pushTop(classes,this.classes);
|
||||
}
|
||||
if(this["class"]) {
|
||||
$tw.utils.pushTop(classes,this["class"]);
|
||||
}
|
||||
var events = [{name: "click", handlerObject: this, handlerMethod: "handleClickEvent"}];
|
||||
if(this.hover === "yes") {
|
||||
events.push({name: "mouseover", handlerObject: this, handlerMethod: "handleMouseOverOrOutEvent"});
|
||||
events.push({name: "mouseout", handlerObject: this, handlerMethod: "handleMouseOverOrOutEvent"});
|
||||
}
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer.renderContext,[{
|
||||
type: "element",
|
||||
tag: "button",
|
||||
attributes: {
|
||||
"class": {type: "string", value: classes.join(" ")}
|
||||
},
|
||||
children: this.renderer.parseTreeNode.children,
|
||||
events: events
|
||||
}]);
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.render = function(type) {
|
||||
var output = [];
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.render) {
|
||||
output.push(node.render(type));
|
||||
}
|
||||
});
|
||||
return output.join("");
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.renderInDom = function(parentElement) {
|
||||
this.parentElement = parentElement;
|
||||
// Render any child nodes
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.renderInDom) {
|
||||
parentElement.appendChild(node.renderInDom());
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.dispatchMessage = function(event) {
|
||||
$tw.utils.dispatchCustomEvent(event.target,this.message,{
|
||||
param: this.param,
|
||||
tiddlerTitle: this.renderer.getContextTiddlerTitle()
|
||||
});
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.triggerPopup = function(event) {
|
||||
$tw.popup.triggerPopup({
|
||||
textRef: this.popup,
|
||||
domNode: this.renderer.domNode,
|
||||
qualifyTiddlerTitles: this.qualifyTiddlerTitles,
|
||||
renderContext: this.renderer.renderContext,
|
||||
wiki: this.renderer.renderTree.wiki
|
||||
});
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.setTiddler = function() {
|
||||
var tiddler = this.renderer.renderTree.wiki.getTiddler(this.set);
|
||||
this.renderer.renderTree.wiki.addTiddler(new $tw.Tiddler(tiddler,{title: this.set, text: this.setTo}));
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.handleClickEvent = function(event) {
|
||||
if(this.message) {
|
||||
this.dispatchMessage(event);
|
||||
}
|
||||
if(this.popup) {
|
||||
this.triggerPopup(event);
|
||||
}
|
||||
if(this.set && this.setTo) {
|
||||
this.setTiddler();
|
||||
}
|
||||
event.preventDefault();
|
||||
return false;
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.handleMouseOverOrOutEvent = function(event) {
|
||||
if(this.popup) {
|
||||
this.triggerPopup(event);
|
||||
}
|
||||
event.preventDefault();
|
||||
return false;
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.refreshInDom = function(changedAttributes,changedTiddlers) {
|
||||
// Check if any of our attributes have changed, or if a tiddler we're interested in has changed
|
||||
if(changedAttributes.message || changedAttributes.param || changedAttributes.set || changedAttributes.setTo || changedAttributes.popup || changedAttributes.hover || changedAttributes.qualifyTiddlerTitles || changedAttributes["class"] || (this.set && changedTiddlers[this.set]) || (this.popup && changedTiddlers[this.popup])) {
|
||||
// Remove old child nodes
|
||||
$tw.utils.removeChildren(this.parentElement);
|
||||
// Regenerate and render children
|
||||
this.generateChildNodes();
|
||||
var self = this;
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.renderInDom) {
|
||||
self.parentElement.appendChild(node.renderInDom());
|
||||
}
|
||||
});
|
||||
} 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.button = ButtonWidget;
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,147 @@
|
||||
/*\
|
||||
title: $:/core/modules/widget/link.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Implements the link widget.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var isLinkExternal = function(to) {
|
||||
var externalRegExp = /(?:file|http|https|mailto|ftp|irc|news|data):[^\s'"]+(?:\/|\b)/i;
|
||||
return externalRegExp.test(to);
|
||||
};
|
||||
|
||||
var LinkWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate child nodes
|
||||
this.generateChildNodes();
|
||||
};
|
||||
|
||||
LinkWidget.prototype.generateChildNodes = function() {
|
||||
// Get the parameters from the attributes
|
||||
this.to = this.renderer.getAttribute("to");
|
||||
this.hover = this.renderer.getAttribute("hover");
|
||||
this.qualifyHoverTitle = this.renderer.getAttribute("qualifyHoverTitle");
|
||||
// Determine the default link characteristics
|
||||
this.isExternal = isLinkExternal(this.to);
|
||||
if(!this.isExternal) {
|
||||
this.isMissing = !this.renderer.renderTree.wiki.tiddlerExists(this.to);
|
||||
}
|
||||
// Compose the link
|
||||
var classes = ["tw-tiddlylink"]
|
||||
if(this.isExternal) {
|
||||
$tw.utils.pushTop(classes,"tw-tiddlylink-external");
|
||||
} else {
|
||||
$tw.utils.pushTop(classes,"tw-tiddlylink-internal");
|
||||
if(this.isMissing) {
|
||||
$tw.utils.pushTop(classes,"tw-tiddlylink-missing");
|
||||
} else {
|
||||
$tw.utils.pushTop(classes,"tw-tiddlylink-resolves");
|
||||
}
|
||||
}
|
||||
if(this.classes) {
|
||||
$tw.utils.pushTop(classes,this.classes);
|
||||
}
|
||||
var events = [{name: "click", handlerObject: this, handlerMethod: "handleClickEvent"}];
|
||||
if(this.hover) {
|
||||
events.push({name: "mouseover", handlerObject: this, handlerMethod: "handleMouseOverOrOutEvent"});
|
||||
events.push({name: "mouseout", handlerObject: this, handlerMethod: "handleMouseOverOrOutEvent"});
|
||||
}
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer.renderContext,[{
|
||||
type: "element",
|
||||
tag: "a",
|
||||
attributes: {
|
||||
href: {type: "string", value: this.isExternal ? this.to : encodeURIComponent(this.to)},
|
||||
"class": {type: "string", value: classes.join(" ")}
|
||||
},
|
||||
children: this.renderer.parseTreeNode.children,
|
||||
events: events
|
||||
}]);
|
||||
};
|
||||
|
||||
LinkWidget.prototype.render = function(type) {
|
||||
var output = [];
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.render) {
|
||||
output.push(node.render(type));
|
||||
}
|
||||
});
|
||||
return output.join("");
|
||||
};
|
||||
|
||||
LinkWidget.prototype.renderInDom = function(parentElement) {
|
||||
this.parentElement = parentElement;
|
||||
// Render any child nodes
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.renderInDom) {
|
||||
parentElement.appendChild(node.renderInDom());
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
LinkWidget.prototype.handleClickEvent = function(event) {
|
||||
if(isLinkExternal(this.to)) {
|
||||
event.target.setAttribute("target","_blank");
|
||||
return true;
|
||||
} else {
|
||||
$tw.utils.dispatchCustomEvent(event.target,"tw-navigate",{
|
||||
navigateTo: this.to,
|
||||
navigateFromNode: this,
|
||||
navigateFromClientRect: this.children[0].domNode.getBoundingClientRect()
|
||||
});
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
LinkWidget.prototype.handleMouseOverOrOutEvent = function(event) {
|
||||
if(this.hover) {
|
||||
$tw.popup.triggerPopup({
|
||||
textRef: this.hover,
|
||||
domNode: this.children[0].domNode,
|
||||
qualifyTiddlerTitles: this.qualifyHoverTitle,
|
||||
contextTiddlerTitle: this.renderer.getContextTiddlerTitle(),
|
||||
wiki: this.renderer.renderTree.wiki
|
||||
});
|
||||
}
|
||||
event.preventDefault();
|
||||
return false;
|
||||
};
|
||||
|
||||
LinkWidget.prototype.refreshInDom = function(changedAttributes,changedTiddlers) {
|
||||
// Set the class for missing tiddlers
|
||||
if(this.targetTitle) {
|
||||
$tw.utils.toggleClass(this.children[0].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.to || changedAttributes.hover || (this.to && changedTiddlers[this.to]) || (this.hover && changedTiddlers[this.hover])) {
|
||||
// Remove old child nodes
|
||||
$tw.utils.removeChildren(this.parentElement);
|
||||
// Regenerate and render children
|
||||
this.generateChildNodes();
|
||||
var self = this;
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.renderInDom) {
|
||||
self.parentElement.appendChild(node.renderInDom());
|
||||
}
|
||||
});
|
||||
} 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.link = LinkWidget;
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,295 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/list/list.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
The list widget
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
These types are shorthands for particular filters
|
||||
*/
|
||||
var typeMappings = {
|
||||
all: "[!is[shadow]sort[title]]",
|
||||
recent: "[!is[shadow]sort[modified]]",
|
||||
missing: "[is[missing]sort[title]]",
|
||||
orphans: "[is[orphan]sort[title]]",
|
||||
shadowed: "[is[shadow]sort[title]]"
|
||||
};
|
||||
|
||||
var ListWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate child nodes
|
||||
this.generateChildNodes();
|
||||
};
|
||||
|
||||
ListWidget.prototype.generateChildNodes = function() {
|
||||
// We'll manage our own dependencies
|
||||
this.renderer.dependencies = undefined;
|
||||
// Get our attributes
|
||||
this.itemClass = this.renderer.getAttribute("itemClass");
|
||||
this.template = this.renderer.getAttribute("template");
|
||||
this.editTemplate = this.renderer.getAttribute("editTemplate");
|
||||
this.emptyMessage = this.renderer.getAttribute("emptyMessage");
|
||||
// Get the list of tiddlers object
|
||||
this.getTiddlerList();
|
||||
// Create the list
|
||||
var listMembers = [];
|
||||
if(this.list.length === 0) {
|
||||
// Check for an empty list
|
||||
listMembers = [this.getEmptyMessage()];
|
||||
} else {
|
||||
// Create the list
|
||||
for(var t=0; t<this.list.length; t++) {
|
||||
listMembers.push(this.createListElement(this.list[t]));
|
||||
}
|
||||
}
|
||||
// Create the list frame element
|
||||
var classes = ["tw-list-frame"];
|
||||
if(this.classes) {
|
||||
$tw.utils.pushTop(classes,this.classes);
|
||||
}
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer.renderContext,[{
|
||||
type: "element",
|
||||
tag: "div",
|
||||
attributes: {
|
||||
"class": {type: "string", value: classes.join(" ")}
|
||||
},
|
||||
children: listMembers
|
||||
}]);
|
||||
};
|
||||
|
||||
ListWidget.prototype.getTiddlerList = function() {
|
||||
var filter;
|
||||
if(this.renderer.hasAttribute("type")) {
|
||||
filter = typeMappings[this.renderer.getAttribute("type")];
|
||||
} else if(this.renderer.hasAttribute("filter")) {
|
||||
filter = this.renderer.getAttribute("filter");
|
||||
}
|
||||
if(!filter) {
|
||||
filter = "[!is[shadow]]";
|
||||
}
|
||||
this.list = this.renderer.renderTree.wiki.filterTiddlers(filter,this.renderer.getContextTiddlerTitle());
|
||||
};
|
||||
|
||||
/*
|
||||
Create and execute the nodes representing the empty message
|
||||
*/
|
||||
ListWidget.prototype.getEmptyMessage = function() {
|
||||
return {
|
||||
type: "element",
|
||||
tag: "span",
|
||||
children: this.renderer.renderTree.wiki.new_parseText("text/vnd.tiddlywiki",this.emptyMessage).tree
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
Create a list element representing a given tiddler
|
||||
*/
|
||||
ListWidget.prototype.createListElement = function(title) {
|
||||
// Define an event handler that adds navigation information to the event
|
||||
var handleEvent = function(event) {
|
||||
event.navigateFromTitle = title;
|
||||
return true;
|
||||
},
|
||||
classes = ["tw-list-element"];
|
||||
// Add any specified classes
|
||||
if(this.itemClass) {
|
||||
$tw.utils.pushTop(classes,this.itemClass);
|
||||
}
|
||||
// Return the list element
|
||||
return {
|
||||
type: "element",
|
||||
tag: "div",
|
||||
attributes: {
|
||||
"class": {type: "string", value: classes.join(" ")}
|
||||
},
|
||||
children: [this.createListElementMacro(title)],
|
||||
events: [
|
||||
{name: "tw-navigate", handlerFunction: handleEvent},
|
||||
{name: "tw-EditTiddler", handlerFunction: handleEvent},
|
||||
{name: "tw-SaveTiddler", handlerFunction: handleEvent},
|
||||
{name: "tw-CloseTiddler", handlerFunction: handleEvent},
|
||||
{name: "tw-NewTiddler", handlerFunction: handleEvent}
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
Create the tiddler macro needed to represent a given tiddler
|
||||
*/
|
||||
ListWidget.prototype.createListElementMacro = function(title) {
|
||||
// Check if the tiddler is a draft
|
||||
var tiddler = this.renderer.renderTree.wiki.getTiddler(title),
|
||||
isDraft = tiddler ? tiddler.hasField("draft.of") : false;
|
||||
// Figure out the template to use
|
||||
var template = this.template,
|
||||
templateTree = undefined;
|
||||
if(isDraft && this.editTemplate) {
|
||||
template = this.editTemplate;
|
||||
}
|
||||
// Check for not having a template
|
||||
if(!template) {
|
||||
if(this.renderer.parseTreeNode.children && this.renderer.parseTreeNode.children.length > 0) {
|
||||
// Use our content as the template
|
||||
templateTree = this.renderer.parseTreeNode.children;
|
||||
} else {
|
||||
// Use default content
|
||||
templateTree = [{
|
||||
type: "widget",
|
||||
tag: "view",
|
||||
attributes: {
|
||||
field: {type: "string", value: "title"},
|
||||
format: {type: "string", value: "link"}
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
// Create the tiddler macro
|
||||
return {
|
||||
type: "widget",
|
||||
tag: "transclude",
|
||||
attributes: {
|
||||
target: {type: "string", value: title},
|
||||
template: {type: "string", value: template}
|
||||
},
|
||||
children: templateTree
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
Remove a list element from the list, along with the attendant DOM nodes
|
||||
*/
|
||||
ListWidget.prototype.removeListElement = function(index) {
|
||||
// Get the list element
|
||||
var listElement = this.children[0].children[index];
|
||||
// Remove the DOM node
|
||||
listElement.domNode.parentNode.removeChild(listElement.domNode);
|
||||
// Then delete the actual renderer node
|
||||
this.children[0].children.splice(index,1);
|
||||
};
|
||||
|
||||
/*
|
||||
Return the index of the list element that corresponds to a particular title
|
||||
startIndex: index to start search (use zero to search from the top)
|
||||
title: tiddler title to seach for
|
||||
*/
|
||||
ListWidget.prototype.findListElementByTitle = function(startIndex,title) {
|
||||
while(startIndex < this.children[0].children.length) {
|
||||
if(this.children[0].children[startIndex].children[0].attributes.target === title) {
|
||||
return startIndex;
|
||||
}
|
||||
startIndex++;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
ListWidget.prototype.render = function(type) {
|
||||
var output = [];
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.render) {
|
||||
output.push(node.render(type));
|
||||
}
|
||||
});
|
||||
return output.join("");
|
||||
};
|
||||
|
||||
ListWidget.prototype.renderInDom = function(parentElement) {
|
||||
this.parentElement = parentElement;
|
||||
// Render any child nodes
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.renderInDom) {
|
||||
parentElement.appendChild(node.renderInDom());
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ListWidget.prototype.refreshInDom = function(changedAttributes,changedTiddlers) {
|
||||
// Reexecute the widget if any of our attributes have changed
|
||||
if(changedAttributes.itemClass || changedAttributes.template || changedAttributes.editTemplate || changedAttributes.emptyMessage || changedAttributes.type || changedAttributes.filter || changedAttributes.template) {
|
||||
// Remove old child nodes
|
||||
$tw.utils.removeChildren(this.parentElement);
|
||||
// Regenerate and render children
|
||||
this.generateChildNodes();
|
||||
var self = this;
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.renderInDom) {
|
||||
self.parentElement.appendChild(node.renderInDom());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Handle any changes to the list, and refresh any nodes we're reusing
|
||||
this.handleListChanges(changedTiddlers);
|
||||
}
|
||||
};
|
||||
|
||||
ListWidget.prototype.handleListChanges = function(changedTiddlers) {
|
||||
var t,
|
||||
prevListLength = this.list.length,
|
||||
frame = this.children[0];
|
||||
// Get the list of tiddlers, having saved the previous length
|
||||
this.getTiddlerList();
|
||||
// Check if the list is empty
|
||||
if(this.list.length === 0) {
|
||||
// Check if it was empty before
|
||||
if(prevListLength === 0) {
|
||||
// If so, just refresh the empty message
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.refreshInDom) {
|
||||
node.refreshInDom(changedTiddlers);
|
||||
}
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
// If the list wasn't empty before, empty it
|
||||
for(t=prevListLength-1; t>=0; t--) {
|
||||
this.removeListElement(t);
|
||||
}
|
||||
// Insert the empty message
|
||||
frame.children = this.renderer.renderTree.createRenderers(this.renderer.renderContext,[this.getEmptyMessage()]);
|
||||
$tw.utils.each(frame.children,function(node) {
|
||||
if(node.renderInDom) {
|
||||
frame.domNode.appendChild(node.renderInDom());
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// If it is not empty now, but was empty previously, then remove the empty message
|
||||
if(prevListLength === 0) {
|
||||
this.removeListElement(0);
|
||||
}
|
||||
}
|
||||
// Step through the list and adjust our child list elements appropriately
|
||||
for(t=0; t<this.list.length; t++) {
|
||||
// Check to see if the list element is already there
|
||||
var index = this.findListElementByTitle(t,this.list[t]);
|
||||
if(index === undefined) {
|
||||
// The list element isn't there, so we need to insert it
|
||||
frame.children.splice(t,0,this.renderer.renderTree.createRenderer(this.renderer.renderContext,this.createListElement(this.list[t])));
|
||||
frame.domNode.insertBefore(frame.children[t].renderInDom(),frame.domNode.childNodes[t]);
|
||||
} else {
|
||||
// Delete any list elements preceding the one we want
|
||||
for(var n=index-1; n>=t; n--) {
|
||||
this.removeListElement(n);
|
||||
}
|
||||
// Refresh the node we're reusing
|
||||
frame.children[t].refreshInDom(changedTiddlers);
|
||||
}
|
||||
}
|
||||
// Remove any left over elements
|
||||
for(t=frame.children.length-1; t>=this.list.length; t--) {
|
||||
this.removeListElement(t);
|
||||
}
|
||||
};
|
||||
|
||||
exports.list = ListWidget;
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,241 @@
|
||||
/*\
|
||||
title: $:/core/modules/widget/navigator.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Implements the navigator widget.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var NavigatorWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate child nodes
|
||||
this.generateChildNodes();
|
||||
};
|
||||
|
||||
NavigatorWidget.prototype.generateChildNodes = function() {
|
||||
// We'll manage our own dependencies
|
||||
this.renderer.dependencies = undefined;
|
||||
// Get our parameters
|
||||
this.storyTitle = this.renderer.getAttribute("story");
|
||||
this.historyTitle = this.renderer.getAttribute("history");
|
||||
// Render our children
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer.renderContext,this.renderer.parseTreeNode.children);
|
||||
};
|
||||
|
||||
NavigatorWidget.prototype.render = function(type) {
|
||||
var output = [];
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.render) {
|
||||
output.push(node.render(type));
|
||||
}
|
||||
});
|
||||
return output.join("");
|
||||
};
|
||||
|
||||
NavigatorWidget.prototype.renderInDom = function(parentElement) {
|
||||
this.parentElement = parentElement;
|
||||
// Render any child nodes
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.renderInDom) {
|
||||
parentElement.appendChild(node.renderInDom());
|
||||
}
|
||||
});
|
||||
// Attach our event handlers
|
||||
$tw.utils.addEventListeners(this.renderer.domNode,[
|
||||
{name: "tw-navigate", handlerObject: this, handlerMethod: "handleNavigateEvent"},
|
||||
{name: "tw-EditTiddler", handlerObject: this, handlerMethod: "handleEditTiddlerEvent"},
|
||||
{name: "tw-SaveTiddler", handlerObject: this, handlerMethod: "handleSaveTiddlerEvent"},
|
||||
{name: "tw-close", handlerObject: this, handlerMethod: "handleCloseTiddlerEvent"},
|
||||
{name: "tw-NewTiddler", handlerObject: this, handlerMethod: "handleNewTiddlerEvent"}
|
||||
]);
|
||||
};
|
||||
|
||||
NavigatorWidget.prototype.refreshInDom = function(changedAttributes,changedTiddlers) {
|
||||
// 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);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
NavigatorWidget.prototype.getStoryList = function() {
|
||||
var text = this.renderer.renderTree.wiki.getTextReference(this.storyTitle,"");
|
||||
if(text && text.length > 0) {
|
||||
this.storyList = text.split("\n");
|
||||
} else {
|
||||
this.storyList = [];
|
||||
}
|
||||
};
|
||||
|
||||
NavigatorWidget.prototype.saveStoryList = function() {
|
||||
var storyTiddler = this.renderer.renderTree.wiki.getTiddler(this.storyTitle);
|
||||
this.renderer.renderTree.wiki.addTiddler(new $tw.Tiddler({
|
||||
title: this.storyTitle
|
||||
},storyTiddler,{text: this.storyList.join("\n")}));
|
||||
};
|
||||
|
||||
NavigatorWidget.prototype.findTitleInStory = function(title,defaultIndex) {
|
||||
for(var t=0; t<this.storyList.length; t++) {
|
||||
if(this.storyList[t] === title) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return defaultIndex;
|
||||
};
|
||||
|
||||
// Navigate to a specified tiddler
|
||||
NavigatorWidget.prototype.handleNavigateEvent = function(event) {
|
||||
if(this.storyTitle) {
|
||||
// Update the story tiddler if specified
|
||||
this.getStoryList();
|
||||
// See if the tiddler is already there
|
||||
var slot = this.findTitleInStory(event.navigateTo,-1);
|
||||
// If not we need to add it
|
||||
if(slot === -1) {
|
||||
// First we try to find the position of the story element we navigated from
|
||||
slot = this.findTitleInStory(event.navigateFromTitle,-1) + 1;
|
||||
// Add the tiddler
|
||||
this.storyList.splice(slot,0,event.navigateTo);
|
||||
// Save the story
|
||||
this.saveStoryList();
|
||||
}
|
||||
}
|
||||
// Add a new record to the top of the history stack
|
||||
if(this.historyTitle) {
|
||||
var historyList = this.renderer.renderTree.wiki.getTiddlerData(this.historyTitle,[]);
|
||||
historyList.push({title: event.navigateTo, fromPageRect: event.navigateFromClientRect});
|
||||
this.renderer.renderTree.wiki.setTiddlerData(this.historyTitle,historyList);
|
||||
}
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
};
|
||||
|
||||
// Close a specified tiddler
|
||||
NavigatorWidget.prototype.handleCloseTiddlerEvent = function(event) {
|
||||
this.getStoryList();
|
||||
// Look for tiddlers with this title to close
|
||||
var slot = this.findTitleInStory(event.tiddlerTitle,-1);
|
||||
if(slot !== -1) {
|
||||
this.storyList.splice(slot,1);
|
||||
this.saveStoryList();
|
||||
}
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
};
|
||||
|
||||
// Place a tiddler in edit mode
|
||||
NavigatorWidget.prototype.handleEditTiddlerEvent = function(event) {
|
||||
this.getStoryList();
|
||||
// Replace the specified tiddler with a draft in edit mode
|
||||
for(var t=0; t<this.storyList.length; t++) {
|
||||
if(this.storyList[t] === event.tiddlerTitle) {
|
||||
// Compute the title for the draft
|
||||
var draftTitle = "Draft " + (new Date()) + " of " + event.tiddlerTitle;
|
||||
this.storyList[t] = draftTitle;
|
||||
// Get the current value of the tiddler we're editing
|
||||
var tiddler = this.renderer.renderTree.wiki.getTiddler(event.tiddlerTitle);
|
||||
// Save the initial value of the draft tiddler
|
||||
this.renderer.renderTree.wiki.addTiddler(new $tw.Tiddler(
|
||||
{
|
||||
text: "Type the text for the tiddler '" + event.tiddlerTitle + "'"
|
||||
},
|
||||
tiddler,
|
||||
{
|
||||
title: draftTitle,
|
||||
"draft.title": event.tiddlerTitle,
|
||||
"draft.of": event.tiddlerTitle
|
||||
}));
|
||||
}
|
||||
}
|
||||
this.saveStoryList();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
};
|
||||
|
||||
// Take a tiddler out of edit mode, saving the changes
|
||||
NavigatorWidget.prototype.handleSaveTiddlerEvent = function(event) {
|
||||
this.getStoryList();
|
||||
var storyTiddlerModified = false;
|
||||
for(var t=0; t<this.storyList.length; t++) {
|
||||
if(this.storyList[t] === event.tiddlerTitle) {
|
||||
var tiddler = this.renderer.renderTree.wiki.getTiddler(event.tiddlerTitle);
|
||||
if(tiddler && $tw.utils.hop(tiddler.fields,"draft.title")) {
|
||||
// Save the draft tiddler as the real tiddler
|
||||
this.renderer.renderTree.wiki.addTiddler(new $tw.Tiddler(tiddler,{
|
||||
title: tiddler.fields["draft.title"],
|
||||
modified: new Date(),
|
||||
"draft.title": undefined,
|
||||
"draft.of": undefined
|
||||
}));
|
||||
// Remove the draft tiddler
|
||||
this.renderer.renderTree.wiki.deleteTiddler(event.tiddlerTitle);
|
||||
// Remove the original tiddler if we're renaming it
|
||||
if(tiddler.fields["draft.of"] !== tiddler.fields["draft.title"]) {
|
||||
this.renderer.renderTree.wiki.deleteTiddler(tiddler.fields["draft.of"]);
|
||||
}
|
||||
// Make the story record point to the newly saved tiddler
|
||||
this.storyList[t] = tiddler.fields["draft.title"];
|
||||
// Check if we're modifying the story tiddler itself
|
||||
if(tiddler.fields["draft.title"] === this.storyTitle) {
|
||||
storyTiddlerModified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!storyTiddlerModified) {
|
||||
this.saveStoryList();
|
||||
}
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
};
|
||||
|
||||
// Create a new draft tiddler
|
||||
NavigatorWidget.prototype.handleNewTiddlerEvent = function(event) {
|
||||
// Get the story details
|
||||
this.getStoryList();
|
||||
// Create the new tiddler
|
||||
var title;
|
||||
for(var t=0; true; t++) {
|
||||
title = "New Tiddler" + (t ? " " + t : "");
|
||||
if(!this.renderer.renderTree.wiki.tiddlerExists(title)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
var tiddler = new $tw.Tiddler({
|
||||
title: title,
|
||||
text: "Newly created tiddler"
|
||||
});
|
||||
this.renderer.renderTree.wiki.addTiddler(tiddler);
|
||||
// Create the draft tiddler
|
||||
var draftTitle = "New Tiddler at " + (new Date()),
|
||||
draftTiddler = new $tw.Tiddler({
|
||||
text: "Type the text for the new tiddler",
|
||||
title: draftTitle,
|
||||
"draft.title": title,
|
||||
"draft.of": title
|
||||
});
|
||||
this.renderer.renderTree.wiki.addTiddler(draftTiddler);
|
||||
// Update the story to insert the new draft at the top
|
||||
var slot = this.findTitleInStory(event.navigateFromTitle,-1) + 1;
|
||||
this.storyList.splice(slot,0,draftTitle);
|
||||
// Save the updated story
|
||||
this.saveStoryList();
|
||||
// Add a new record to the top of the history stack
|
||||
var history = this.renderer.renderTree.wiki.getTiddlerData(this.historyTitle,[]);
|
||||
history.push({title: draftTitle});
|
||||
this.renderer.renderTree.wiki.setTiddlerData(this.historyTitle,historyList);
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
};
|
||||
|
||||
exports.navigator = NavigatorWidget;
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,150 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/transclude.js
|
||||
type: application/javascript
|
||||
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`.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var TranscludeWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate child nodes
|
||||
this.generateChildNodes();
|
||||
};
|
||||
|
||||
TranscludeWidget.prototype.generateChildNodes = function() {
|
||||
var tr, templateParseTree, templateTiddler;
|
||||
// We'll manage our own dependencies
|
||||
this.renderer.dependencies = undefined;
|
||||
// Get the render target details
|
||||
this.targetTitle = this.renderer.getAttribute("target",this.renderer.getContextTiddlerTitle());
|
||||
// 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;
|
||||
} else {
|
||||
this.templateTitle = this.renderer.getAttribute("template",this.targetTitle);
|
||||
// Check for recursion
|
||||
if(this.renderer.checkContextRecursion({
|
||||
tiddlerTitle: this.targetTitle,
|
||||
templateTitle: this.templateTitle
|
||||
})) {
|
||||
templateParseTree = [{type: "text", text: "Tiddler recursion error in transclude widget"}];
|
||||
} else {
|
||||
var parser = this.renderer.renderTree.wiki.new_parseTiddler(this.templateTitle);
|
||||
templateParseTree = parser ? parser.tree : [];
|
||||
}
|
||||
}
|
||||
// Set up the attributes for the wrapper element
|
||||
var classes = [];
|
||||
if(!this.renderer.renderTree.wiki.tiddlerExists(this.targetTitle)) {
|
||||
$tw.utils.pushTop(classes,"tw-tiddler-missing");
|
||||
}
|
||||
// Create the renderers for the wrapper and the children
|
||||
var newRenderContext = {
|
||||
tiddlerTitle: this.targetTitle,
|
||||
templateTitle: this.templateTitle,
|
||||
parentContext: this.renderer.renderContext
|
||||
};
|
||||
this.children = this.renderer.renderTree.createRenderers(newRenderContext,[{
|
||||
type: "element",
|
||||
tag: this.renderer.parseTreeNode.isBlock ? "div" : "span",
|
||||
attributes: {
|
||||
"class": {type: "string", value: classes.join(" ")}
|
||||
},
|
||||
children: templateParseTree
|
||||
}]);
|
||||
};
|
||||
|
||||
TranscludeWidget.prototype.render = function(type) {
|
||||
var output = [];
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.render) {
|
||||
output.push(node.render(type));
|
||||
}
|
||||
});
|
||||
return output.join("");
|
||||
};
|
||||
|
||||
TranscludeWidget.prototype.renderInDom = function(parentElement) {
|
||||
this.parentElement = parentElement;
|
||||
// Render any child nodes
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.renderInDom) {
|
||||
parentElement.appendChild(node.renderInDom());
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
TranscludeWidget.prototype.refreshInDom = function(changedAttributes,changedTiddlers) {
|
||||
// Set the class for missing tiddlers
|
||||
if(this.targetTitle) {
|
||||
$tw.utils.toggleClass(this.children[0].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.targetTitle && changedTiddlers[this.targetTitle]) || (this.templateTitle && changedTiddlers[this.templateTitle])) {
|
||||
// Remove old child nodes
|
||||
$tw.utils.removeChildren(this.parentElement);
|
||||
// Regenerate and render children
|
||||
this.generateChildNodes();
|
||||
var self = this;
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.renderInDom) {
|
||||
self.parentElement.appendChild(node.renderInDom());
|
||||
}
|
||||
});
|
||||
} 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.transclude = TranscludeWidget;
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,141 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/view.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
The view widget displays a tiddler field.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Define the "text" viewer here so that it is always available
|
||||
*/
|
||||
var TextViewer = function(viewWidget,tiddler,field,value) {
|
||||
this.viewWidget = viewWidget;
|
||||
this.tiddler = tiddler;
|
||||
this.field = field;
|
||||
this.value = value;
|
||||
};
|
||||
|
||||
TextViewer.prototype.render = function() {
|
||||
// Get the value as a string
|
||||
if(this.field !== "text" && this.tiddler) {
|
||||
this.value = this.tiddler.getFieldString(this.field);
|
||||
}
|
||||
var value = "";
|
||||
if(this.value !== undefined && this.value !== null) {
|
||||
value = this.value;
|
||||
}
|
||||
return this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer.renderContext,[{
|
||||
type: "text",
|
||||
text: value
|
||||
}]);
|
||||
};
|
||||
|
||||
// We'll cache the available field viewers here
|
||||
var fieldViewers = undefined;
|
||||
|
||||
var ViewWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Initialise the field viewers if they've not been done already
|
||||
if(!fieldViewers) {
|
||||
fieldViewers = {text: TextViewer}; // Start with the built-in text viewer
|
||||
$tw.modules.applyMethods("newfieldviewer",fieldViewers);
|
||||
}
|
||||
// Generate child nodes
|
||||
this.generateChildNodes();
|
||||
};
|
||||
|
||||
ViewWidget.prototype.generateChildNodes = function() {
|
||||
// We'll manage our own dependencies
|
||||
this.renderer.dependencies = undefined;
|
||||
// Get parameters from our attributes
|
||||
this.tiddlerTitle = this.renderer.getAttribute("tiddler",this.renderer.getContextTiddlerTitle());
|
||||
this.fieldName = this.renderer.getAttribute("field","text");
|
||||
this.format = this.renderer.getAttribute("format","text");
|
||||
// Get the value to display
|
||||
var tiddler = this.renderer.renderTree.wiki.getTiddler(this.tiddlerTitle),
|
||||
value;
|
||||
if(tiddler) {
|
||||
if(this.fieldName === "text") {
|
||||
// Calling getTiddlerText() triggers lazy loading of skinny tiddlers
|
||||
value = this.renderer.renderTree.wiki.getTiddlerText(this.tiddlerTitle);
|
||||
} else {
|
||||
value = tiddler.fields[this.fieldName];
|
||||
}
|
||||
} else { // Use a special value if the tiddler is missing
|
||||
switch(this.fieldName) {
|
||||
case "title":
|
||||
value = this.tiddlerTitle;
|
||||
break;
|
||||
case "modified":
|
||||
case "created":
|
||||
value = new Date();
|
||||
break;
|
||||
default:
|
||||
value = "";
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Choose the viewer to use
|
||||
var Viewer = fieldViewers.text;
|
||||
if($tw.utils.hop(fieldViewers,this.format)) {
|
||||
Viewer = fieldViewers[this.format];
|
||||
}
|
||||
this.viewer = new Viewer(this,tiddler,this.fieldName,value);
|
||||
// Ask the viewer to create the children
|
||||
this.children = this.viewer.render();
|
||||
};
|
||||
|
||||
ViewWidget.prototype.render = function(type) {
|
||||
var output = [];
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.render) {
|
||||
output.push(node.render(type));
|
||||
}
|
||||
});
|
||||
return output.join("");
|
||||
};
|
||||
|
||||
ViewWidget.prototype.renderInDom = function(parentElement) {
|
||||
this.parentElement = parentElement;
|
||||
// Render any child nodes
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.renderInDom) {
|
||||
parentElement.appendChild(node.renderInDom());
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ViewWidget.prototype.refreshInDom = function(changedAttributes,changedTiddlers) {
|
||||
// Check if any of our attributes have changed, or if a tiddler we're interested in has changed
|
||||
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.format || (this.tiddlerTitle && changedTiddlers[this.tiddlerTitle])) {
|
||||
// Remove old child nodes
|
||||
$tw.utils.removeChildren(this.parentElement);
|
||||
// Regenerate and render children
|
||||
this.generateChildNodes();
|
||||
var self = this;
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.renderInDom) {
|
||||
self.parentElement.appendChild(node.renderInDom());
|
||||
}
|
||||
});
|
||||
} 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.view = ViewWidget;
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,36 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/view/viewers/date.js
|
||||
type: application/javascript
|
||||
module-type: newfieldviewer
|
||||
|
||||
A viewer for viewing tiddler fields as a date
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var DateViewer = function(viewWidget,tiddler,field,value) {
|
||||
this.viewWidget = viewWidget;
|
||||
this.tiddler = tiddler;
|
||||
this.field = field;
|
||||
this.value = value;
|
||||
};
|
||||
|
||||
DateViewer.prototype.render = function() {
|
||||
var template = this.viewWidget.renderer.getAttribute("template","DD MMM YYYY"),
|
||||
value = "";
|
||||
if(this.value !== undefined) {
|
||||
value = $tw.utils.formatDateString(this.value,template);
|
||||
}
|
||||
return this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer.renderContext,[{
|
||||
type: "text",
|
||||
text: value
|
||||
}]);
|
||||
};
|
||||
|
||||
exports.date = DateViewer;
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,44 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/view/viewers/link.js
|
||||
type: application/javascript
|
||||
module-type: newfieldviewer
|
||||
|
||||
A viewer for viewing tiddler fields as a link
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var LinkViewer = function(viewWidget,tiddler,field,value) {
|
||||
this.viewWidget = viewWidget;
|
||||
this.tiddler = tiddler;
|
||||
this.field = field;
|
||||
this.value = value;
|
||||
};
|
||||
|
||||
LinkViewer.prototype.render = function() {
|
||||
var parseTree = [];
|
||||
if(this.value === undefined) {
|
||||
parseTree.push({type: "text", text: ""});
|
||||
} else {
|
||||
parseTree.push({
|
||||
type: "widget",
|
||||
tag: "link",
|
||||
attributes: {
|
||||
to: {type: "string", value: this.value}
|
||||
},
|
||||
children: [{
|
||||
type: "text",
|
||||
text: this.value
|
||||
}]
|
||||
})
|
||||
}
|
||||
return this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer.renderContext,parseTree);
|
||||
};
|
||||
|
||||
exports.link = LinkViewer;
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,41 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/view/viewers/wikified.js
|
||||
type: application/javascript
|
||||
module-type: newfieldviewer
|
||||
|
||||
A viewer for viewing tiddler fields as wikified text
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var WikifiedViewer = function(viewWidget,tiddler,field,value) {
|
||||
this.viewWidget = viewWidget;
|
||||
this.tiddler = tiddler;
|
||||
this.field = field;
|
||||
this.value = value;
|
||||
};
|
||||
|
||||
WikifiedViewer.prototype.render = function() {
|
||||
var parseTree;
|
||||
// If we're viewing the text field of a tiddler then we'll transclude it
|
||||
if(this.tiddler && this.field === "text") {
|
||||
parseTree = [{
|
||||
type: "widget",
|
||||
tag: "transclude",
|
||||
attributes: {
|
||||
target: {type: "string", value: this.tiddler.fields.title}
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
parseTree = this.viewWidget.renderer.renderTree.wiki.new_parseText("text/vnd.tiddlywiki",this.value).tree;
|
||||
}
|
||||
return this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer.renderContext,parseTree);
|
||||
};
|
||||
|
||||
exports.wikified = WikifiedViewer;
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user