mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-12-24 00:50:28 +00:00
The big purge of the old widget mechanism
Getting rid of the old widget mechanism files finally gives us a payoff for all the refactoring. Still a bit of tidying up to do, and we need to re-introduce the animation mechanisms.
This commit is contained in:
parent
5610efff01
commit
20f03de712
6
2bld.sh
6
2bld.sh
@ -11,7 +11,7 @@ mkdir -p tmp/tw2
|
||||
node ./tiddlywiki.js \
|
||||
editions/tw5.com \
|
||||
--verbose \
|
||||
--rendertiddler TiddlyWiki2ReadMe editions/tw2/readme.md text/html \
|
||||
--new_rendertiddler TiddlyWiki2ReadMe editions/tw2/readme.md text/html \
|
||||
|| exit 1
|
||||
|
||||
# cook the TiddlyWiki 2.x.x index file
|
||||
@ -20,7 +20,7 @@ node ./tiddlywiki.js \
|
||||
editions/tw2 \
|
||||
--verbose \
|
||||
--load editions/tw2/source/tiddlywiki.com/index.html.recipe \
|
||||
--rendertiddler $:/core/templates/tiddlywiki2.template.html ./tmp/tw2/index.html text/plain \
|
||||
--new_rendertiddler $:/core/templates/tiddlywiki2.template.html ./tmp/tw2/index.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
opendiff tmp/tw2/index.html editions/tw2/target/index.2.6.5.html
|
||||
diff -q tmp/tw2/index.html editions/tw2/target/prebuilt.html
|
||||
|
20
bld.sh
20
bld.sh
@ -35,12 +35,12 @@ rm $TW5_BUILD_OUTPUT/static/*
|
||||
node ./tiddlywiki.js \
|
||||
./editions/tw5.com \
|
||||
--verbose \
|
||||
--rendertiddler ReadMe ./readme.md text/html \
|
||||
--rendertiddler ContributingTemplate ./contributing.md text/html \
|
||||
--rendertiddler $:/core/templates/tiddlywiki5.template.html $TW5_BUILD_OUTPUT/index.html text/plain \
|
||||
--rendertiddler $:/core/templates/static.template.html $TW5_BUILD_OUTPUT/static.html text/plain \
|
||||
--rendertiddler $:/core/templates/static.template.css $TW5_BUILD_OUTPUT/static/static.css text/plain \
|
||||
--rendertiddlers [!is[system]] $:/core/templates/static.tiddler.html $TW5_BUILD_OUTPUT/static text/plain \
|
||||
--new_rendertiddler ReadMe ./readme.md text/html \
|
||||
--new_rendertiddler ContributingTemplate ./contributing.md text/html \
|
||||
--new_rendertiddler $:/core/templates/tiddlywiki5.template.html $TW5_BUILD_OUTPUT/index.html text/plain \
|
||||
--new_rendertiddler $:/core/templates/static.template.html $TW5_BUILD_OUTPUT/static.html text/plain \
|
||||
--new_rendertiddler $:/core/templates/static.template.css $TW5_BUILD_OUTPUT/static/static.css text/plain \
|
||||
--new_rendertiddlers [!is[system]] $:/core/templates/static.tiddler.html $TW5_BUILD_OUTPUT/static text/plain \
|
||||
|| exit 1
|
||||
|
||||
# Second, encrypted.html: a version of the main file encrypted with the password "password"
|
||||
@ -49,7 +49,7 @@ node ./tiddlywiki.js \
|
||||
./editions/tw5.com \
|
||||
--verbose \
|
||||
--password password \
|
||||
--rendertiddler $:/core/templates/tiddlywiki5.template.html $TW5_BUILD_OUTPUT/encrypted.html text/plain \
|
||||
--new_rendertiddler $:/core/templates/tiddlywiki5.template.html $TW5_BUILD_OUTPUT/encrypted.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# Third, empty.html: empty wiki for reuse
|
||||
@ -57,7 +57,7 @@ node ./tiddlywiki.js \
|
||||
node ./tiddlywiki.js \
|
||||
./editions/empty \
|
||||
--verbose \
|
||||
--rendertiddler $:/core/templates/tiddlywiki5.template.html $TW5_BUILD_OUTPUT/empty.html text/plain \
|
||||
--new_rendertiddler $:/core/templates/tiddlywiki5.template.html $TW5_BUILD_OUTPUT/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# Fourth, tahoelafs.html: empty wiki with plugin for Tahoe-LAFS
|
||||
@ -65,7 +65,7 @@ node ./tiddlywiki.js \
|
||||
node ./tiddlywiki.js \
|
||||
./editions/tahoelafs \
|
||||
--verbose \
|
||||
--rendertiddler $:/core/templates/tiddlywiki5.template.html $TW5_BUILD_OUTPUT/tahoelafs.html text/plain \
|
||||
--new_rendertiddler $:/core/templates/tiddlywiki5.template.html $TW5_BUILD_OUTPUT/tahoelafs.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# Fifth, d3demo.html: wiki to demo d3 plugin
|
||||
@ -73,7 +73,7 @@ node ./tiddlywiki.js \
|
||||
node ./tiddlywiki.js \
|
||||
./editions/d3demo \
|
||||
--verbose \
|
||||
--rendertiddler $:/core/templates/tiddlywiki5.template.html $TW5_BUILD_OUTPUT/d3demo.html text/plain \
|
||||
--new_rendertiddler $:/core/templates/tiddlywiki5.template.html $TW5_BUILD_OUTPUT/d3demo.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# Sixth, run the test edition to run the node.js tests and to generate test.html for tests in the browser
|
||||
|
@ -1,44 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/commands/rendertiddler.js
|
||||
type: application/javascript
|
||||
module-type: command
|
||||
|
||||
Command to render a tiddler and save it to a file
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.info = {
|
||||
name: "rendertiddler",
|
||||
synchronous: false
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
if(this.params.length < 2) {
|
||||
return "Missing filename";
|
||||
}
|
||||
var self = this,
|
||||
fs = require("fs"),
|
||||
path = require("path"),
|
||||
title = this.params[0],
|
||||
filename = this.params[1],
|
||||
type = this.params[2] || "text/html";
|
||||
fs.writeFile(filename,this.commander.wiki.renderTiddler(type,title),"utf8",function(err) {
|
||||
self.callback(err);
|
||||
});
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
})();
|
@ -1,54 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/commands/rendertiddlers.js
|
||||
type: application/javascript
|
||||
module-type: command
|
||||
|
||||
Command to render several tiddlers to a folder of files
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.info = {
|
||||
name: "rendertiddlers",
|
||||
synchronous: true
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
if(this.params.length < 2) {
|
||||
return "Missing filename";
|
||||
}
|
||||
var self = this,
|
||||
fs = require("fs"),
|
||||
path = require("path"),
|
||||
wiki = this.commander.wiki,
|
||||
filter = this.params[0],
|
||||
template = this.params[1],
|
||||
pathname = this.params[2],
|
||||
type = this.params[3] || "text/html",
|
||||
extension = this.params[4] || ".html",
|
||||
parser = wiki.parseTiddler(template),
|
||||
tiddlers = wiki.filterTiddlers(filter);
|
||||
$tw.utils.each(tiddlers,function(title) {
|
||||
var renderTree = new $tw.WikiRenderTree(parser,{wiki: wiki, context: {tiddlerTitle: title}, document: $tw.document});
|
||||
renderTree.execute();
|
||||
var container = $tw.document.createElement("div");
|
||||
renderTree.renderInDom(container);
|
||||
var text = type === "text/html" ? container.innerHTML : container.textContent;
|
||||
fs.writeFileSync(path.resolve(pathname,encodeURIComponent(title) + extension),text,"utf8");
|
||||
});
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
})();
|
@ -1,212 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/rendertree/renderers/element.js
|
||||
type: application/javascript
|
||||
module-type: wikirenderer
|
||||
|
||||
Element renderer
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Element widget. A degenerate widget that renders ordinary HTML elements
|
||||
*/
|
||||
var ElementWidget = function(renderer) {
|
||||
this.renderer = renderer;
|
||||
this.tag = this.renderer.parseTreeNode.tag;
|
||||
this.attributes = this.renderer.attributes;
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,this.renderer.parseTreeNode.children);
|
||||
this.events = this.renderer.parseTreeNode.events;
|
||||
};
|
||||
|
||||
ElementWidget.prototype.refreshInDom = function(changedAttributes,changedTiddlers) {
|
||||
// Check if any of our attribute dependencies have changed
|
||||
if($tw.utils.count(changedAttributes) > 0) {
|
||||
// Update our attributes
|
||||
this.renderer.assignAttributes();
|
||||
}
|
||||
// Refresh any child nodes
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.refreshInDom) {
|
||||
node.refreshInDom(changedTiddlers);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Element renderer
|
||||
*/
|
||||
var ElementRenderer = function(renderTree,parentRenderer,parseTreeNode) {
|
||||
// Store state information
|
||||
this.renderTree = renderTree;
|
||||
this.parentRenderer = parentRenderer;
|
||||
this.parseTreeNode = parseTreeNode;
|
||||
// Initialise widget classes
|
||||
if(!this.widgetClasses) {
|
||||
ElementRenderer.prototype.widgetClasses = $tw.modules.applyMethods("widget");
|
||||
}
|
||||
// Select the namespace for the tag
|
||||
var tagNameSpaces = {
|
||||
svg: "http://www.w3.org/2000/svg",
|
||||
math: "http://www.w3.org/1998/Math/MathML"
|
||||
};
|
||||
this.namespace = tagNameSpaces[this.parseTreeNode.tag];
|
||||
if(this.namespace) {
|
||||
this.context = this.context || {};
|
||||
this.context.namespace = this.namespace;
|
||||
} else {
|
||||
this.namespace = this.renderTree.getContextVariable(this.parentRenderer,"namespace","http://www.w3.org/1999/xhtml");
|
||||
}
|
||||
// Get the context tiddler title
|
||||
this.tiddlerTitle = this.renderTree.getContextVariable(this.parentRenderer,"tiddlerTitle");
|
||||
// Compute our dependencies
|
||||
this.dependencies = {};
|
||||
var self = this;
|
||||
$tw.utils.each(this.parseTreeNode.attributes,function(attribute,name) {
|
||||
if(attribute.type === "indirect") {
|
||||
var tr = $tw.utils.parseTextReference(attribute.textReference);
|
||||
self.dependencies[tr.title ? tr.title : self.tiddlerTitle] = true;
|
||||
}
|
||||
});
|
||||
// Compute our attributes
|
||||
this.attributes = {};
|
||||
this.computeAttributes();
|
||||
// Create the parasite widget object if required
|
||||
if(this.parseTreeNode.tag.charAt(0) === "$") {
|
||||
// Choose the class
|
||||
var WidgetClass = this.widgetClasses[this.parseTreeNode.tag.substr(1)];
|
||||
// Instantiate the widget
|
||||
if(WidgetClass) {
|
||||
this.widget = new WidgetClass(this);
|
||||
} else {
|
||||
WidgetClass = this.widgetClasses.error;
|
||||
if(WidgetClass) {
|
||||
this.widget = new WidgetClass(this,"Unknown widget '<" + this.parseTreeNode.tag + ">'");
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we haven't got a widget, use the generic HTML element widget
|
||||
if(!this.widget) {
|
||||
this.widget = new ElementWidget(this);
|
||||
}
|
||||
};
|
||||
|
||||
ElementRenderer.prototype.computeAttributes = function() {
|
||||
var changedAttributes = {},
|
||||
self = this,
|
||||
value;
|
||||
$tw.utils.each(this.parseTreeNode.attributes,function(attribute,name) {
|
||||
if(attribute.type === "indirect") {
|
||||
value = self.renderTree.wiki.getTextReference(attribute.textReference,"",self.tiddlerTitle);
|
||||
} else if(attribute.type === "macro") {
|
||||
// Get the macro definition
|
||||
var macro = self.renderTree.findMacroDefinition(self.parentRenderer,attribute.value.name);
|
||||
if(!macro) {
|
||||
value = "";
|
||||
} else {
|
||||
// Substitute the macro parameters
|
||||
value = self.renderTree.substituteParameters(macro,attribute.value);
|
||||
// Parse the text and render it as text
|
||||
value = self.renderTree.wiki.renderText("text/plain","text/vnd.tiddlywiki",value,self.context);
|
||||
}
|
||||
} else { // String attribute
|
||||
value = attribute.value;
|
||||
}
|
||||
// Check whether the attribute has changed
|
||||
if(self.attributes[name] !== value) {
|
||||
self.attributes[name] = value;
|
||||
changedAttributes[name] = true;
|
||||
}
|
||||
});
|
||||
return changedAttributes;
|
||||
};
|
||||
|
||||
ElementRenderer.prototype.hasAttribute = function(name) {
|
||||
return $tw.utils.hop(this.attributes,name);
|
||||
};
|
||||
|
||||
ElementRenderer.prototype.getAttribute = function(name,defaultValue) {
|
||||
if($tw.utils.hop(this.attributes,name)) {
|
||||
return this.attributes[name];
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
};
|
||||
|
||||
ElementRenderer.prototype.renderInDom = function() {
|
||||
// Check if our widget is providing an element
|
||||
if(this.widget.tag) {
|
||||
// Create the element
|
||||
this.domNode = this.renderTree.document.createElementNS(this.namespace,this.widget.tag);
|
||||
// Assign any specified event handlers
|
||||
$tw.utils.addEventListeners(this.domNode,this.widget.events);
|
||||
// Assign the attributes
|
||||
this.assignAttributes();
|
||||
// Render any child nodes
|
||||
var self = this;
|
||||
$tw.utils.each(this.widget.children,function(node) {
|
||||
if(node.renderInDom) {
|
||||
self.domNode.appendChild(node.renderInDom());
|
||||
}
|
||||
});
|
||||
// Call postRenderInDom if the widget provides it and we're in the browser
|
||||
if($tw.browser && this.widget.postRenderInDom) {
|
||||
this.widget.postRenderInDom();
|
||||
}
|
||||
// Return the dom node
|
||||
return this.domNode;
|
||||
} else {
|
||||
// If we're not generating an element, just render our first child
|
||||
return this.widget.children[0].renderInDom();
|
||||
}
|
||||
};
|
||||
|
||||
ElementRenderer.prototype.assignAttributes = function() {
|
||||
var self = this;
|
||||
$tw.utils.each(this.widget.attributes,function(v,a) {
|
||||
if(v !== undefined) {
|
||||
if($tw.utils.isArray(v)) { // Ahem, could there be arrays other than className?
|
||||
self.domNode.className = v.join(" ");
|
||||
} else if (typeof v === "object") { // ...or objects other than style?
|
||||
for(var p in v) {
|
||||
self.domNode.style[$tw.utils.unHyphenateCss(p)] = v[p];
|
||||
}
|
||||
} else {
|
||||
// Setting certain attributes can cause a DOM error (eg xmlns on the svg element)
|
||||
try {
|
||||
self.domNode.setAttributeNS(null,a,v);
|
||||
} catch(e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ElementRenderer.prototype.refreshInDom = function(changedTiddlers) {
|
||||
// Update our attributes if required
|
||||
var changedAttributes = {};
|
||||
if($tw.utils.checkDependencies(this.dependencies,changedTiddlers)) {
|
||||
changedAttributes = this.computeAttributes();
|
||||
}
|
||||
// Check if the widget has a refreshInDom method
|
||||
if(this.widget.refreshInDom) {
|
||||
// Let the widget refresh itself
|
||||
this.widget.refreshInDom(changedAttributes,changedTiddlers);
|
||||
} else {
|
||||
// If not, assign the attributes and refresh any child nodes
|
||||
this.assignAttributes();
|
||||
$tw.utils.each(this.widget.children,function(node) {
|
||||
if(node.refreshInDom) {
|
||||
node.refreshInDom(changedTiddlers);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.element = ElementRenderer
|
||||
|
||||
})();
|
@ -1,31 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/rendertree/renderers/entity.js
|
||||
type: application/javascript
|
||||
module-type: wikirenderer
|
||||
|
||||
Entity renderer
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Entity renderer
|
||||
*/
|
||||
var EntityRenderer = function(renderTree,parentRenderer,parseTreeNode) {
|
||||
// Store state information
|
||||
this.renderTree = renderTree;
|
||||
this.parentRenderer = parentRenderer;
|
||||
this.parseTreeNode = parseTreeNode;
|
||||
};
|
||||
|
||||
EntityRenderer.prototype.renderInDom = function() {
|
||||
return this.renderTree.document.createTextNode($tw.utils.entityDecode(this.parseTreeNode.entity));
|
||||
};
|
||||
|
||||
exports.entity = EntityRenderer
|
||||
|
||||
})();
|
@ -1,65 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/rendertree/renderers/macrocall.js
|
||||
type: application/javascript
|
||||
module-type: wikirenderer
|
||||
|
||||
Macro call renderer
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Macro call renderer
|
||||
*/
|
||||
var MacroCallRenderer = function(renderTree,parentRenderer,parseTreeNode) {
|
||||
// Store state information
|
||||
this.renderTree = renderTree;
|
||||
this.parentRenderer = parentRenderer;
|
||||
this.parseTreeNode = parseTreeNode;
|
||||
// Find the macro definition
|
||||
var macro = this.renderTree.findMacroDefinition(this.parentRenderer,this.parseTreeNode.name);
|
||||
// Insert an error message if we couldn't find the macro
|
||||
var childTree;
|
||||
if(!macro) {
|
||||
childTree = [{type: "text", text: "<<Undefined macro: " + this.parseTreeNode.name + ">>"}];
|
||||
} else {
|
||||
// Substitute the macro parameters
|
||||
var text = this.renderTree.substituteParameters(macro,this.parseTreeNode);
|
||||
// Parse the text
|
||||
childTree = this.renderTree.wiki.parseText("text/vnd.tiddlywiki",text,{parseAsInline: !this.parseTreeNode.isBlock}).tree;
|
||||
}
|
||||
// Create the renderers for the child nodes
|
||||
this.children = this.renderTree.createRenderers(this,childTree);
|
||||
};
|
||||
|
||||
MacroCallRenderer.prototype.renderInDom = function() {
|
||||
// Create the element
|
||||
this.domNode = this.renderTree.document.createElement(this.parseTreeNode.isBlock ? "div" : "span");
|
||||
this.domNode.setAttribute("data-macro-name",this.parseTreeNode.name);
|
||||
// Render any child nodes
|
||||
var self = this;
|
||||
$tw.utils.each(this.children,function(node,index) {
|
||||
if(node.renderInDom) {
|
||||
self.domNode.appendChild(node.renderInDom());
|
||||
}
|
||||
});
|
||||
// Return the dom node
|
||||
return this.domNode;
|
||||
};
|
||||
|
||||
MacroCallRenderer.prototype.refreshInDom = function(changedTiddlers) {
|
||||
// Refresh any child nodes
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.refreshInDom) {
|
||||
node.refreshInDom(changedTiddlers);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.macrocall = MacroCallRenderer
|
||||
|
||||
})();
|
@ -1,30 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/rendertree/renderers/macrodef.js
|
||||
type: application/javascript
|
||||
module-type: wikirenderer
|
||||
|
||||
Macro definition renderer
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Macro definition renderer
|
||||
*/
|
||||
var MacroDefRenderer = function(renderTree,parentRenderer,parseTreeNode) {
|
||||
// Store state information
|
||||
this.renderTree = renderTree;
|
||||
this.parentRenderer = parentRenderer;
|
||||
this.parseTreeNode = parseTreeNode;
|
||||
// Save the macro definition into the context of the rendertree
|
||||
this.renderTree.context.macroDefinitions = this.renderTree.context.macroDefinitions || {};
|
||||
this.renderTree.context.macroDefinitions[this.parseTreeNode.name] = this.parseTreeNode;
|
||||
};
|
||||
|
||||
exports.macrodef = MacroDefRenderer
|
||||
|
||||
})();
|
@ -1,33 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/rendertree/renderers/raw.js
|
||||
type: application/javascript
|
||||
module-type: wikirenderer
|
||||
|
||||
Raw HTML renderer
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Raw HTML renderer
|
||||
*/
|
||||
var RawRenderer = function(renderTree,parentRenderer,parseTreeNode) {
|
||||
// Store state information
|
||||
this.renderTree = renderTree;
|
||||
this.parentRenderer = parentRenderer;
|
||||
this.parseTreeNode = parseTreeNode;
|
||||
};
|
||||
|
||||
RawRenderer.prototype.renderInDom = function() {
|
||||
var domNode = this.renderTree.document.createElement("div");
|
||||
domNode.innerHTML = this.parseTreeNode.html;
|
||||
return domNode;
|
||||
};
|
||||
|
||||
exports.raw = RawRenderer
|
||||
|
||||
})();
|
@ -1,31 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/rendertree/renderers/text.js
|
||||
type: application/javascript
|
||||
module-type: wikirenderer
|
||||
|
||||
Text renderer
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Text renderer
|
||||
*/
|
||||
var TextRenderer = function(renderTree,parentRenderer,parseTreeNode) {
|
||||
// Store state information
|
||||
this.renderTree = renderTree;
|
||||
this.parentRenderer = parentRenderer;
|
||||
this.parseTreeNode = parseTreeNode;
|
||||
};
|
||||
|
||||
TextRenderer.prototype.renderInDom = function() {
|
||||
return this.renderTree.document.createTextNode(this.parseTreeNode.text);
|
||||
};
|
||||
|
||||
exports.text = TextRenderer
|
||||
|
||||
})();
|
@ -1,198 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/rendertree/wikirendertree.js
|
||||
type: application/javascript
|
||||
module-type: global
|
||||
|
||||
Wiki text render tree
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Create a render tree object for a parse tree
|
||||
parser: reference to the parse tree to be rendered
|
||||
options: see below
|
||||
Options include:
|
||||
wiki: mandatory reference to wiki associated with this render tree
|
||||
context: optional hashmap of context variables (see below)
|
||||
parentRenderer: optional reference to a parent renderer node for the context chain
|
||||
document: optional document object to use instead of global document
|
||||
Context variables include:
|
||||
tiddlerTitle: title of the tiddler providing the context
|
||||
templateTitle: title of the tiddler providing the current template
|
||||
macroDefinitions: hashmap of macro definitions
|
||||
*/
|
||||
var WikiRenderTree = function(parser,options) {
|
||||
this.parser = parser;
|
||||
this.wiki = options.wiki;
|
||||
this.context = options.context || {};
|
||||
this.parentRenderer = options.parentRenderer;
|
||||
this.document = options.document;
|
||||
// Hashmap of the renderer classes
|
||||
if(!this.rendererClasses) {
|
||||
WikiRenderTree.prototype.rendererClasses = $tw.modules.applyMethods("wikirenderer");
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Generate the full render tree for this parse tree
|
||||
*/
|
||||
WikiRenderTree.prototype.execute = function() {
|
||||
this.rendererTree = this.createRenderers(this,this.parser.tree);
|
||||
};
|
||||
|
||||
/*
|
||||
Create an array of renderers for an array of parse tree nodes
|
||||
*/
|
||||
WikiRenderTree.prototype.createRenderers = function(parentRenderer,parseTreeNodes) {
|
||||
var rendererNodes = [];
|
||||
if(parseTreeNodes) {
|
||||
for(var t=0; t<parseTreeNodes.length; t++) {
|
||||
rendererNodes.push(this.createRenderer(parentRenderer,parseTreeNodes[t]));
|
||||
}
|
||||
}
|
||||
return rendererNodes;
|
||||
};
|
||||
|
||||
/*
|
||||
Create a renderer node for a parse tree node
|
||||
*/
|
||||
WikiRenderTree.prototype.createRenderer = function(parentRenderer,parseTreeNode) {
|
||||
var RenderNodeClass = this.rendererClasses[parseTreeNode.type];
|
||||
return new RenderNodeClass(this,parentRenderer,parseTreeNode);
|
||||
};
|
||||
|
||||
/*
|
||||
Render to the DOM
|
||||
*/
|
||||
WikiRenderTree.prototype.renderInDom = function(container) {
|
||||
this.container = container;
|
||||
$tw.utils.each(this.rendererTree,function(node) {
|
||||
if(node.renderInDom) {
|
||||
container.appendChild(node.renderInDom());
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Update the DOM rendering in the light of a set of changes
|
||||
*/
|
||||
WikiRenderTree.prototype.refreshInDom = function(changes) {
|
||||
$tw.utils.each(this.rendererTree,function(node) {
|
||||
if(node.refreshInDom) {
|
||||
node.refreshInDom(changes);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Find the value of a given context variable for a particular renderer node
|
||||
*/
|
||||
WikiRenderTree.prototype.getContextVariable = function(renderer,name,defaultValue) {
|
||||
while(renderer) {
|
||||
if($tw.utils.hop(renderer.context,name)) {
|
||||
return renderer.context[name];
|
||||
}
|
||||
renderer = renderer.parentRenderer;
|
||||
};
|
||||
return defaultValue;
|
||||
};
|
||||
|
||||
/*
|
||||
Check for render context recursion from a particular renderer node by returning true if the members of a proposed new render context are already present in the render context chain
|
||||
*/
|
||||
WikiRenderTree.prototype.checkContextRecursion = function(renderer,newContext) {
|
||||
while(renderer) {
|
||||
var context = renderer.context;
|
||||
if(context) {
|
||||
var match = true;
|
||||
for(var member in newContext) {
|
||||
if($tw.utils.hop(context,member)) {
|
||||
if(newContext[member] !== context[member]) {
|
||||
match = false;
|
||||
}
|
||||
} else {
|
||||
match = false;
|
||||
}
|
||||
}
|
||||
if(match) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
renderer = renderer.parentRenderer;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
WikiRenderTree.prototype.getContextScopeId = function(renderer) {
|
||||
var guidBits = [],
|
||||
scopeComponents = ["tiddlerTitle","templateTitle"],
|
||||
processContext = function(field,name) {
|
||||
if(scopeComponents.indexOf(name) !== -1) {
|
||||
guidBits.push(name + ":" + field + ";");
|
||||
}
|
||||
};
|
||||
while(renderer) {
|
||||
if(renderer.context) {
|
||||
$tw.utils.each(renderer.context,processContext);
|
||||
guidBits.push("-");
|
||||
}
|
||||
renderer = renderer.parentRenderer;
|
||||
}
|
||||
return guidBits.join("");
|
||||
};
|
||||
|
||||
/*
|
||||
Find a named macro definition
|
||||
*/
|
||||
WikiRenderTree.prototype.findMacroDefinition = function(renderer,name) {
|
||||
while(renderer) {
|
||||
if(renderer.context && renderer.context.macroDefinitions && renderer.context.macroDefinitions[name]) {
|
||||
return renderer.context.macroDefinitions[name];
|
||||
}
|
||||
renderer = renderer.parentRenderer;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
/*
|
||||
Expand the parameters of a macro
|
||||
*/
|
||||
WikiRenderTree.prototype.substituteParameters = function(macroDefinition,macroCallParseTreeNode) {
|
||||
var text = macroDefinition.text,
|
||||
nextAnonParameter = 0; // Next candidate anonymous parameter in macro call
|
||||
// Step through each of the parameters in the macro definition
|
||||
for(var p=0; p<macroDefinition.params.length; p++) {
|
||||
// Check if we've got a macro call parameter with the same name
|
||||
var paramInfo = macroDefinition.params[p],
|
||||
paramValue = undefined;
|
||||
for(var m=0; m<macroCallParseTreeNode.params.length; m++) {
|
||||
if(macroCallParseTreeNode.params[m].name === paramInfo.name) {
|
||||
paramValue = macroCallParseTreeNode.params[m].value;
|
||||
}
|
||||
}
|
||||
// If not, use the next available anonymous macro call parameter
|
||||
if(!paramValue && nextAnonParameter < macroCallParseTreeNode.params.length) {
|
||||
while(macroCallParseTreeNode.params[nextAnonParameter].name && nextAnonParameter < macroCallParseTreeNode.params.length-1) {
|
||||
nextAnonParameter++;
|
||||
}
|
||||
if(!macroCallParseTreeNode.params[nextAnonParameter].name) {
|
||||
paramValue = macroCallParseTreeNode.params[nextAnonParameter].value;
|
||||
nextAnonParameter++;
|
||||
}
|
||||
}
|
||||
// If we've still not got a value, use the default, if any
|
||||
paramValue = paramValue || paramInfo["default"] || "";
|
||||
// Replace any instances of this parameter
|
||||
text = text.replace(new RegExp("\\$" + $tw.utils.escapeRegExp(paramInfo.name) + "\\$","mg"),paramValue);
|
||||
}
|
||||
return text;
|
||||
};
|
||||
|
||||
exports.WikiRenderTree = WikiRenderTree;
|
||||
|
||||
})();
|
@ -1,150 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/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.generate();
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.generate = 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");
|
||||
this.selectedClass = this.renderer.getAttribute("selectedClass");
|
||||
// Compose the button
|
||||
var classes = ["tw-button"];
|
||||
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"});
|
||||
}
|
||||
if(this.set && this.setTo && this.selectedClass) {
|
||||
if(this.isSelected()) {
|
||||
classes.push(this.selectedClass);
|
||||
}
|
||||
}
|
||||
// Set the return element
|
||||
this.tag = "button";
|
||||
this.attributes ={"class": classes.join(" ")};
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,this.renderer.parseTreeNode.children);
|
||||
this.events = events;
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.dispatchMessage = function(event) {
|
||||
$tw.utils.dispatchCustomEvent(event.target,this.message,{
|
||||
param: this.param,
|
||||
tiddlerTitle: this.renderer.tiddlerTitle
|
||||
});
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.triggerPopup = function(event) {
|
||||
var title = this.popup;
|
||||
if(this.qualifyTiddlerTitles) {
|
||||
title = title + "-" + this.renderer.renderTree.getContextScopeId(this.renderer.parentRenderer);
|
||||
}
|
||||
$tw.popup.triggerPopup({
|
||||
domNode: this.renderer.domNode,
|
||||
title: title,
|
||||
wiki: this.renderer.renderTree.wiki
|
||||
});
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.isSelected = function() {
|
||||
var title = this.set;
|
||||
if(this.qualifyTiddlerTitles) {
|
||||
title = title + "-" + this.renderer.renderTree.getContextScopeId(this.renderer.parentRenderer);
|
||||
}
|
||||
var tiddler = this.renderer.renderTree.wiki.getTiddler(title);
|
||||
return tiddler ? tiddler.fields.text === this.setTo : false;
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.setTiddler = function() {
|
||||
var title = this.set;
|
||||
if(this.qualifyTiddlerTitles) {
|
||||
title = title + "-" + this.renderer.renderTree.getContextScopeId(this.renderer.parentRenderer);
|
||||
}
|
||||
var tiddler = this.renderer.renderTree.wiki.getTiddler(title);
|
||||
this.renderer.renderTree.wiki.addTiddler(new $tw.Tiddler(tiddler,{title: title, text: this.setTo}));
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.handleClickEvent = function(event) {
|
||||
var handled = false;
|
||||
if(this.message) {
|
||||
this.dispatchMessage(event);
|
||||
handled = true;
|
||||
}
|
||||
if(this.popup) {
|
||||
this.triggerPopup(event);
|
||||
handled = true;
|
||||
}
|
||||
if(this.set) {
|
||||
this.setTiddler();
|
||||
handled = true;
|
||||
}
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
return handled;
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.handleMouseOverOrOutEvent = function(event) {
|
||||
if(this.popup) {
|
||||
this.triggerPopup(event);
|
||||
}
|
||||
event.preventDefault();
|
||||
return false;
|
||||
};
|
||||
|
||||
ButtonWidget.prototype.refreshInDom = function(changedAttributes,changedTiddlers) {
|
||||
var setTitle = this.set,
|
||||
popupTitle = this.popup;
|
||||
if(this.qualifyTiddlerTitles) {
|
||||
var scopeId = this.renderer.renderTree.getContextScopeId(this.renderer.parentRenderer);
|
||||
if(setTitle) {
|
||||
setTitle = setTitle + "-" + scopeId;
|
||||
}
|
||||
if(popupTitle) {
|
||||
popupTitle = popupTitle + "-" + scopeId;
|
||||
}
|
||||
}
|
||||
// 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"] || (setTitle && changedTiddlers[setTitle]) || (popupTitle && changedTiddlers[popupTitle])) {
|
||||
// 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.button = ButtonWidget;
|
||||
|
||||
})();
|
@ -1,111 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/checkbox.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Implements the checkbox widget.
|
||||
|
||||
```
|
||||
<$checkbox tag="done"/>
|
||||
|
||||
<$checkbox tiddler="HelloThere" tag="red"/>
|
||||
|
||||
<$checkbox tag="done">
|
||||
<$view field="title" format="link"/>
|
||||
</$checkbox>
|
||||
```
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var CheckboxWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate child nodes
|
||||
this.generate();
|
||||
};
|
||||
|
||||
CheckboxWidget.prototype.generate = function() {
|
||||
// Get the parameters from the attributes
|
||||
this.tiddlerTitle = this.renderer.getAttribute("tiddler",this.renderer.tiddlerTitle);
|
||||
this.tagName = this.renderer.getAttribute("tag");
|
||||
this["class"] = this.renderer.getAttribute("class");
|
||||
// Compute classes
|
||||
var classes = ["tw-checkbox"];
|
||||
if(this["class"]) {
|
||||
$tw.utils.pushTop(classes,this["class"]);
|
||||
}
|
||||
// Create the checkbox and span elements
|
||||
var nodeCheckbox = {
|
||||
type: "element",
|
||||
tag: "input",
|
||||
attributes: {
|
||||
type: {type: "string", value: "checkbox"}
|
||||
}
|
||||
},
|
||||
nodeSpan = {
|
||||
type: "element",
|
||||
tag: "span",
|
||||
children: this.renderer.parseTreeNode.children
|
||||
};
|
||||
// Set the state of the checkbox
|
||||
if(this.getValue()) {
|
||||
$tw.utils.addAttributeToParseTreeNode(nodeCheckbox,"checked","true");
|
||||
}
|
||||
// Set the return element
|
||||
this.tag = "label";
|
||||
this.attributes ={"class": classes.join(" ")};
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,[nodeCheckbox,nodeSpan]);
|
||||
this.events = [{name: "change", handlerObject: this, handlerMethod: "handleChangeEvent"}];
|
||||
};
|
||||
|
||||
CheckboxWidget.prototype.getValue = function() {
|
||||
var tiddler = this.renderer.renderTree.wiki.getTiddler(this.tiddlerTitle);
|
||||
return tiddler ? tiddler.hasTag(this.tagName) : false;
|
||||
};
|
||||
|
||||
CheckboxWidget.prototype.handleChangeEvent = function(event) {
|
||||
var checked = this.children[0].domNode.checked,
|
||||
tiddler = this.renderer.renderTree.wiki.getTiddler(this.tiddlerTitle);
|
||||
if(tiddler && tiddler.hasTag(this.tagName) !== checked) {
|
||||
var newTags = tiddler.fields.tags.slice(0),
|
||||
pos = newTags.indexOf(this.tagName);
|
||||
if(pos !== -1) {
|
||||
newTags.splice(pos,1);
|
||||
}
|
||||
if(checked) {
|
||||
newTags.push(this.tagName);
|
||||
}
|
||||
this.renderer.renderTree.wiki.addTiddler(new $tw.Tiddler(tiddler,{tags: newTags}));
|
||||
}
|
||||
};
|
||||
|
||||
CheckboxWidget.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.tag || changedAttributes["class"]) {
|
||||
// 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 {
|
||||
// Update the checkbox if necessary
|
||||
if(changedTiddlers[this.tiddlerTitle]) {
|
||||
this.children[0].domNode.checked = this.getValue();
|
||||
}
|
||||
// Refresh children
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.refreshInDom) {
|
||||
node.refreshInDom(changedTiddlers);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.checkbox = CheckboxWidget;
|
||||
|
||||
})();
|
@ -1,59 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/count.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Implements the count widget that displays the number of tiddlers that match a filter
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var CountWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Execute the filter to get the initial count
|
||||
this.executeFilter();
|
||||
// Generate child nodes
|
||||
this.generate();
|
||||
};
|
||||
|
||||
CountWidget.prototype.executeFilter = function() {
|
||||
// Get attributes
|
||||
this.filter = this.renderer.getAttribute("filter");
|
||||
// Execute the filter
|
||||
if(this.filter) {
|
||||
this.currentCount = this.renderer.renderTree.wiki.filterTiddlers(this.filter,this.renderer.tiddlerTitle).length;
|
||||
} else {
|
||||
this.currentCount = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
CountWidget.prototype.generate = function() {
|
||||
// Set the element
|
||||
this.tag = "span";
|
||||
this.attributes = {};
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,[
|
||||
{type: "text", text: this.currentCount !== undefined ? this.currentCount.toString() : ""}
|
||||
]);
|
||||
};
|
||||
|
||||
CountWidget.prototype.refreshInDom = function(changedAttributes,changedTiddlers) {
|
||||
// Re-execute the filter to get the count
|
||||
var oldCount = this.currentCount;
|
||||
this.executeFilter();
|
||||
if(this.currentCount !== oldCount) {
|
||||
// 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);
|
||||
}
|
||||
};
|
||||
|
||||
exports.count = CountWidget;
|
||||
|
||||
})();
|
@ -1,53 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/datauri.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
The datauri widget displays the contents of a tiddler as a data URI.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var DataUriWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate child nodes
|
||||
this.generate();
|
||||
};
|
||||
|
||||
DataUriWidget.prototype.generate = function() {
|
||||
// Get parameters from our attributes
|
||||
this.tiddlerTitle = this.renderer.getAttribute("tiddler",this.renderer.tiddlerTitle);
|
||||
// Compose the data URI
|
||||
var tiddler = this.renderer.renderTree.wiki.getTiddler(this.tiddlerTitle),
|
||||
uri = "";
|
||||
if(tiddler) {
|
||||
var type = tiddler.fields.type || "text/vnd.tiddlywiki",
|
||||
typeInfo = $tw.config.contentTypeInfo[type],
|
||||
isBase64 = typeInfo && typeInfo.encoding === "base64",
|
||||
parts = ["data:"];
|
||||
parts.push(type);
|
||||
parts.push(isBase64 ? ";base64" : "");
|
||||
parts.push(",");
|
||||
parts.push(isBase64 ? tiddler.fields.text : encodeURIComponent(tiddler.fields.text));
|
||||
uri = parts.join("");
|
||||
}
|
||||
// Set the element
|
||||
this.tag = "pre";
|
||||
this.attributes = {
|
||||
"class": "tw-data-uri"
|
||||
};
|
||||
// Create the renderers for the wrapper and the children
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,[{
|
||||
type: "text",
|
||||
text: uri
|
||||
}]);
|
||||
};
|
||||
|
||||
exports.datauri = DataUriWidget;
|
||||
|
||||
})();
|
@ -1,87 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/edit/edit.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
The edit widget uses editor plugins to edit tiddlers of different types.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var EditWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Initialise the editors if they've not been done already
|
||||
if(!this.editors) {
|
||||
EditWidget.prototype.editors = {};
|
||||
$tw.modules.applyMethods("editor",this.editors);
|
||||
}
|
||||
// Generate child nodes
|
||||
this.generate();
|
||||
};
|
||||
|
||||
EditWidget.prototype.generate = function() {
|
||||
// Get parameters from our attributes
|
||||
this.tiddlerTitle = this.renderer.getAttribute("tiddler",this.renderer.tiddlerTitle);
|
||||
this.fieldName = this.renderer.getAttribute("field");
|
||||
this.indexName = this.renderer.getAttribute("index");
|
||||
if(!this.fieldName && !this.indexName) {
|
||||
this.fieldName = "text";
|
||||
}
|
||||
// Choose the editor to use
|
||||
// TODO: Tiddler field modules should be able to specify a field type from which the editor is derived
|
||||
this.editorName = this.chooseEditor();
|
||||
var Editor = this.editors[this.editorName];
|
||||
// Instantiate the editor
|
||||
this.editor = new Editor(this,this.tiddlerTitle,this.fieldName,this.indexName);
|
||||
// Ask the editor to create the widget element
|
||||
this.editor.render();
|
||||
};
|
||||
|
||||
/*
|
||||
Return the name of the editor that should handle this tiddler field
|
||||
*/
|
||||
EditWidget.prototype.chooseEditor = function() {
|
||||
var tiddler = this.renderer.renderTree.wiki.getTiddler(this.tiddlerTitle);
|
||||
if(this.fieldName === "text" && tiddler && tiddler.fields.type && this.editors[tiddler.fields.type]) {
|
||||
return tiddler.fields.type;
|
||||
}
|
||||
return "text/vnd.tiddlywiki";
|
||||
};
|
||||
|
||||
EditWidget.prototype.postRenderInDom = function() {
|
||||
if(this.editor && this.editor.postRenderInDom) {
|
||||
this.editor.postRenderInDom();
|
||||
}
|
||||
};
|
||||
|
||||
EditWidget.prototype.refreshInDom = function(changedAttributes,changedTiddlers) {
|
||||
// We'll completely regenerate ourselves if any of our attributes have changed
|
||||
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.format || this.chooseEditor() !== this.editorName) {
|
||||
// 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 if(this.tiddlerTitle && changedTiddlers[this.tiddlerTitle]) {
|
||||
// Refresh the editor if our tiddler has changed
|
||||
if(this.editor && this.editor.refreshInDom) {
|
||||
this.editor.refreshInDom(changedTiddlers);
|
||||
}
|
||||
} else {
|
||||
// Otherwise, just refresh any child nodes
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.refreshInDom) {
|
||||
node.refreshInDom(changedTiddlers);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.edit = EditWidget;
|
||||
|
||||
})();
|
@ -1,318 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/edit/editors/bitmapeditor.js
|
||||
type: application/javascript
|
||||
module-type: editor
|
||||
|
||||
A bitmap editor
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
// Default images sizes
|
||||
var DEFAULT_IMAGE_WIDTH = 300,
|
||||
DEFAULT_IMAGE_HEIGHT = 185;
|
||||
|
||||
// The elements of the editor UI
|
||||
var DOM_CANVAS = 0,
|
||||
DOM_WIDTH = 1,
|
||||
DOM_HEIGHT = 2;
|
||||
|
||||
var BitmapEditor = function(editWidget,tiddlerTitle,fieldName,indexName) {
|
||||
this.editWidget = editWidget;
|
||||
this.tiddlerTitle = tiddlerTitle;
|
||||
this.fieldName = fieldName;
|
||||
};
|
||||
|
||||
BitmapEditor.prototype.render = function() {
|
||||
// Set the element details
|
||||
this.editWidget.tag = "div";
|
||||
this.editWidget.attributes = {
|
||||
"class": "tw-edit-bitmapeditor-wrapper"
|
||||
};
|
||||
var children = [{
|
||||
type: "element",
|
||||
tag: "canvas",
|
||||
attributes: {
|
||||
"class": {type: "string", value: "tw-edit-bitmapeditor"}
|
||||
},
|
||||
events: [{
|
||||
name: "touchstart",
|
||||
handlerObject: this,
|
||||
handlerMethod: "handleTouchStartEvent"
|
||||
},{
|
||||
name: "touchmove",
|
||||
handlerObject: this,
|
||||
handlerMethod: "handleTouchMoveEvent"
|
||||
},{
|
||||
name: "touchend",
|
||||
handlerObject: this,
|
||||
handlerMethod: "handleTouchEndEvent"
|
||||
},{
|
||||
name: "mousedown",
|
||||
handlerObject: this,
|
||||
handlerMethod: "handleMouseDownEvent"
|
||||
},{
|
||||
name: "mousemove",
|
||||
handlerObject: this,
|
||||
handlerMethod: "handleMouseMoveEvent"
|
||||
},{
|
||||
name: "mouseup",
|
||||
handlerObject: this,
|
||||
handlerMethod: "handleMouseUpEvent"
|
||||
}]
|
||||
},{
|
||||
type: "element",
|
||||
tag: "input",
|
||||
attributes: {
|
||||
"class": {type: "string", value: "tw-edit-bitmapeditor-width"},
|
||||
"type": {type: "string", value: "number"},
|
||||
"value": {type: "string", value: ""}
|
||||
},
|
||||
events: [{
|
||||
name: "change",
|
||||
handlerObject: this,
|
||||
handlerMethod: "handleWidthChangeEvent"
|
||||
}]
|
||||
},{
|
||||
type: "element",
|
||||
tag: "input",
|
||||
attributes: {
|
||||
"class": {type: "string", value: "tw-edit-bitmapeditor-height"},
|
||||
"type": {type: "string", value: "number"},
|
||||
"value": {type: "string", value: ""}
|
||||
},
|
||||
events: [{
|
||||
name: "change",
|
||||
handlerObject: this,
|
||||
handlerMethod: "handleHeightChangeEvent"
|
||||
}]
|
||||
}];
|
||||
this.editWidget.children = this.editWidget.renderer.renderTree.createRenderers(this.editWidget.renderer,children);
|
||||
};
|
||||
|
||||
BitmapEditor.prototype.postRenderInDom = function() {
|
||||
var tiddler = this.editWidget.renderer.renderTree.wiki.getTiddler(this.tiddlerTitle),
|
||||
canvas = this.getDomNode(DOM_CANVAS),
|
||||
currImage = new Image();
|
||||
// Set up event handlers for loading the image
|
||||
var self = this;
|
||||
currImage.onload = function() {
|
||||
// Copy the image to the on-screen canvas
|
||||
self.initCanvas(canvas,currImage.width,currImage.height,currImage);
|
||||
// And also copy the current bitmap to the off-screen canvas
|
||||
self.currCanvas = self.editWidget.renderer.renderTree.document.createElement("canvas");
|
||||
self.initCanvas(self.currCanvas,currImage.width,currImage.height,currImage);
|
||||
// Set the width and height input boxes
|
||||
self.updateSize();
|
||||
};
|
||||
currImage.onerror = function() {
|
||||
// Set the on-screen canvas size and clear it
|
||||
self.initCanvas(canvas,DEFAULT_IMAGE_WIDTH,DEFAULT_IMAGE_HEIGHT);
|
||||
// Set the off-screen canvas size and clear it
|
||||
self.currCanvas = self.editWidget.renderer.renderTree.document.createElement("canvas");
|
||||
self.initCanvas(self.currCanvas,DEFAULT_IMAGE_WIDTH,DEFAULT_IMAGE_HEIGHT);
|
||||
// Set the width and height input boxes
|
||||
self.updateSize();
|
||||
}
|
||||
// Get the current bitmap into an image object
|
||||
currImage.src = "data:" + tiddler.fields.type + ";base64," + tiddler.fields.text;
|
||||
};
|
||||
|
||||
BitmapEditor.prototype.initCanvas = function(canvas,width,height,image) {
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
var ctx = canvas.getContext("2d");
|
||||
if(image) {
|
||||
ctx.drawImage(image,0,0);
|
||||
} else {
|
||||
ctx.fillStyle = "#fff";
|
||||
ctx.fillRect(0,0,canvas.width,canvas.height);
|
||||
}
|
||||
}
|
||||
|
||||
BitmapEditor.prototype.getDomNode = function(index) {
|
||||
return this.editWidget.renderer.domNode.childNodes[index];
|
||||
};
|
||||
|
||||
/*
|
||||
** Update the input boxes with the actual size of the canvas
|
||||
*/
|
||||
BitmapEditor.prototype.updateSize = function() {
|
||||
this.getDomNode(DOM_WIDTH).value = this.currCanvas.width;
|
||||
this.getDomNode(DOM_HEIGHT).value = this.currCanvas.height;
|
||||
};
|
||||
|
||||
/*
|
||||
** Change the size of the canvas, preserving the current image
|
||||
*/
|
||||
BitmapEditor.prototype.changeCanvasSize = function(newWidth,newHeight) {
|
||||
// Create and size a new canvas
|
||||
var newCanvas = this.editWidget.renderer.renderTree.document.createElement("canvas");
|
||||
this.initCanvas(newCanvas,newWidth,newHeight);
|
||||
// Copy the old image
|
||||
var ctx = newCanvas.getContext("2d");
|
||||
ctx.drawImage(this.currCanvas,0,0);
|
||||
// Set the new canvas as the current one
|
||||
this.currCanvas = newCanvas;
|
||||
// Set the size of the onscreen canvas
|
||||
var canvas = this.getDomNode(DOM_CANVAS);
|
||||
canvas.width = newWidth;
|
||||
canvas.height = newHeight;
|
||||
// Paint the onscreen canvas with the offscreen canvas
|
||||
ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(this.currCanvas,0,0);
|
||||
};
|
||||
|
||||
BitmapEditor.prototype.handleWidthChangeEvent = function(event) {
|
||||
// Get the new width
|
||||
var newWidth = parseInt(this.getDomNode(DOM_WIDTH).value,10);
|
||||
// Update if necessary
|
||||
if(newWidth > 0 && newWidth !== this.currCanvas.width) {
|
||||
this.changeCanvasSize(newWidth,this.currCanvas.height);
|
||||
}
|
||||
// Update the input controls
|
||||
this.updateSize();
|
||||
};
|
||||
|
||||
BitmapEditor.prototype.handleHeightChangeEvent = function(event) {
|
||||
// Get the new width
|
||||
var newHeight = parseInt(this.getDomNode(DOM_HEIGHT).value,10);
|
||||
// Update if necessary
|
||||
if(newHeight > 0 && newHeight !== this.currCanvas.height) {
|
||||
this.changeCanvasSize(this.currCanvas.width,newHeight);
|
||||
}
|
||||
// Update the input controls
|
||||
this.updateSize();
|
||||
};
|
||||
|
||||
BitmapEditor.prototype.handleTouchStartEvent = function(event) {
|
||||
this.brushDown = true;
|
||||
this.strokeStart(event.touches[0].clientX,event.touches[0].clientY);
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
};
|
||||
|
||||
BitmapEditor.prototype.handleTouchMoveEvent = function(event) {
|
||||
if(this.brushDown) {
|
||||
this.strokeMove(event.touches[0].clientX,event.touches[0].clientY);
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
};
|
||||
|
||||
BitmapEditor.prototype.handleTouchEndEvent = function(event) {
|
||||
if(this.brushDown) {
|
||||
this.brushDown = false;
|
||||
this.strokeEnd();
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
};
|
||||
|
||||
BitmapEditor.prototype.handleMouseDownEvent = function(event) {
|
||||
this.strokeStart(event.clientX,event.clientY);
|
||||
this.brushDown = true;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
};
|
||||
|
||||
BitmapEditor.prototype.handleMouseMoveEvent = function(event) {
|
||||
if(this.brushDown) {
|
||||
this.strokeMove(event.clientX,event.clientY);
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
BitmapEditor.prototype.handleMouseUpEvent = function(event) {
|
||||
if(this.brushDown) {
|
||||
this.brushDown = false;
|
||||
this.strokeEnd();
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
BitmapEditor.prototype.adjustCoordinates = function(x,y) {
|
||||
var canvas = this.getDomNode(DOM_CANVAS),
|
||||
canvasRect = canvas.getBoundingClientRect(),
|
||||
scale = canvas.width/canvasRect.width;
|
||||
return {x: (x - canvasRect.left) * scale, y: (y - canvasRect.top) * scale};
|
||||
};
|
||||
|
||||
BitmapEditor.prototype.strokeStart = function(x,y) {
|
||||
// Start off a new stroke
|
||||
this.stroke = [this.adjustCoordinates(x,y)];
|
||||
};
|
||||
|
||||
BitmapEditor.prototype.strokeMove = function(x,y) {
|
||||
var canvas = this.getDomNode(DOM_CANVAS),
|
||||
ctx = canvas.getContext("2d"),
|
||||
t;
|
||||
// Add the new position to the end of the stroke
|
||||
this.stroke.push(this.adjustCoordinates(x,y));
|
||||
// Redraw the previous image
|
||||
ctx.drawImage(this.currCanvas,0,0);
|
||||
// Render the stroke
|
||||
ctx.strokeStyle = "#ff0";
|
||||
ctx.lineWidth = 3;
|
||||
ctx.lineCap = "round";
|
||||
ctx.lineJoin = "round";
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(this.stroke[0].x,this.stroke[0].y);
|
||||
for(t=1; t<this.stroke.length-1; t++) {
|
||||
var s1 = this.stroke[t],
|
||||
s2 = this.stroke[t-1],
|
||||
tx = (s1.x + s2.x)/2,
|
||||
ty = (s1.y + s2.y)/2;
|
||||
ctx.quadraticCurveTo(s2.x,s2.y,tx,ty);
|
||||
}
|
||||
ctx.stroke();
|
||||
};
|
||||
|
||||
BitmapEditor.prototype.strokeEnd = function() {
|
||||
// Copy the bitmap to the off-screen canvas
|
||||
var canvas = this.getDomNode(DOM_CANVAS),
|
||||
ctx = this.currCanvas.getContext("2d");
|
||||
ctx.drawImage(canvas,0,0);
|
||||
// Save the image into the tiddler
|
||||
this.saveChanges();
|
||||
};
|
||||
|
||||
BitmapEditor.prototype.saveChanges = function() {
|
||||
var tiddler = this.editWidget.renderer.renderTree.wiki.getTiddler(this.tiddlerTitle);
|
||||
if(tiddler) {
|
||||
// data URIs look like "data:<type>;base64,<text>"
|
||||
var dataURL = this.getDomNode(DOM_CANVAS).toDataURL(tiddler.fields.type,1.0),
|
||||
posColon = dataURL.indexOf(":"),
|
||||
posSemiColon = dataURL.indexOf(";"),
|
||||
posComma = dataURL.indexOf(","),
|
||||
type = dataURL.substring(posColon+1,posSemiColon),
|
||||
text = dataURL.substring(posComma+1);
|
||||
var update = {type: type, text: text};
|
||||
this.editWidget.renderer.renderTree.wiki.addTiddler(new $tw.Tiddler(tiddler,update));
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Note that the bitmap editor intentionally doesn't have a refreshInDom method to avoid the situation where a bitmap being editted is modified externally
|
||||
*/
|
||||
|
||||
exports["image/jpg"] = BitmapEditor;
|
||||
exports["image/jpeg"] = BitmapEditor;
|
||||
exports["image/png"] = BitmapEditor;
|
||||
exports["image/gif"] = BitmapEditor;
|
||||
|
||||
})();
|
@ -1,219 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/edit/editors/texteditor.js
|
||||
type: application/javascript
|
||||
module-type: editor
|
||||
|
||||
A plain text editor
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var MIN_TEXT_AREA_HEIGHT = 100;
|
||||
|
||||
var TextEditor = function(editWidget,tiddlerTitle,fieldName,indexName) {
|
||||
this.editWidget = editWidget;
|
||||
this.tiddlerTitle = tiddlerTitle;
|
||||
this.fieldName = fieldName;
|
||||
this.indexName = indexName;
|
||||
};
|
||||
|
||||
/*
|
||||
Get the tiddler being edited and current value
|
||||
*/
|
||||
TextEditor.prototype.getEditInfo = function() {
|
||||
var tiddler = this.editWidget.renderer.renderTree.wiki.getTiddler(this.tiddlerTitle),
|
||||
value;
|
||||
if(this.fieldName) {
|
||||
// Get the current tiddler and the field name
|
||||
if(tiddler) {
|
||||
// If we've got a tiddler, the value to display is the field string value
|
||||
value = tiddler.getFieldString(this.fieldName);
|
||||
} else {
|
||||
// Otherwise, we need to construct a default value for the editor
|
||||
switch(this.fieldName) {
|
||||
case "text":
|
||||
value = "Type the text for the tiddler '" + this.tiddlerTitle + "'";
|
||||
break;
|
||||
case "title":
|
||||
value = this.tiddlerTitle;
|
||||
break;
|
||||
default:
|
||||
value = "";
|
||||
break;
|
||||
}
|
||||
value = this.editWidget.renderer.getAttribute("default",value);
|
||||
}
|
||||
} else {
|
||||
value = this.editWidget.renderer.renderTree.wiki.extractTiddlerDataItem(this.tiddlerTitle,this.indexName,this.editWidget.renderer.getAttribute("default"));
|
||||
}
|
||||
return {tiddler: tiddler, value: value};
|
||||
};
|
||||
|
||||
TextEditor.prototype.render = function() {
|
||||
// Get the initial value of the editor
|
||||
var editInfo = this.getEditInfo();
|
||||
// Create the editor nodes
|
||||
var node = {
|
||||
type: "element",
|
||||
attributes: {}
|
||||
};
|
||||
// Get the edit type associated with this field
|
||||
var type = "input";
|
||||
if(this.fieldName === "text") {
|
||||
type = "textarea";
|
||||
} else {
|
||||
var fieldModule = $tw.Tiddler.fieldModules[this.fieldName];
|
||||
if(fieldModule && fieldModule.editType) {
|
||||
type = fieldModule.editType;
|
||||
}
|
||||
}
|
||||
var type = this.editWidget.renderer.getAttribute("type",type);
|
||||
switch(type) {
|
||||
case "textarea":
|
||||
node.tag = "textarea";
|
||||
node.children = [{
|
||||
type: "text",
|
||||
text: editInfo.value
|
||||
}];
|
||||
break;
|
||||
case "color":
|
||||
node.tag = "input";
|
||||
node.attributes.type = {type: "string", value: "color"};
|
||||
node.attributes.value = {type: "string", value: editInfo.value};
|
||||
break;
|
||||
case "search":
|
||||
node.tag = "input";
|
||||
node.attributes.type = {type: "string", value: "search"};
|
||||
node.attributes.value = {type: "string", value: editInfo.value};
|
||||
break;
|
||||
default: // "input"
|
||||
node.tag = "input";
|
||||
node.attributes.type = {type: "string", value: "text"};
|
||||
node.attributes.value = {type: "string", value: editInfo.value};
|
||||
break;
|
||||
}
|
||||
node.events = [
|
||||
{name: "focus", handlerObject: this, handlerMethod: "handleFocusEvent"},
|
||||
{name: "blur", handlerObject: this, handlerMethod: "handleBlurEvent"},
|
||||
{name: "input", handlerObject: this, handlerMethod: "handleInputEvent"}
|
||||
];
|
||||
// Add a placeholder if specified
|
||||
if(this.editWidget.renderer.hasAttribute("placeholder")) {
|
||||
node.attributes.placeholder = {type: "string", value: this.editWidget.renderer.getAttribute("placeholder")};
|
||||
}
|
||||
// Set the element details
|
||||
this.editWidget.tag = this.editWidget.renderer.parseTreeNode.isBlock ? "div" : "span";
|
||||
this.editWidget.attributes = {
|
||||
"class": "tw-edit-texteditor"
|
||||
};
|
||||
if(this.editWidget.renderer.hasAttribute("class")) {
|
||||
this.editWidget.attributes["class"] += " " + this.editWidget.renderer.getAttribute("class");
|
||||
}
|
||||
if(this.editWidget.renderer.hasAttribute("style")) {
|
||||
this.editWidget.attributes.style = this.editWidget.attributes.style || "";
|
||||
this.editWidget.attributes.style += this.editWidget.renderer.getAttribute("style");
|
||||
}
|
||||
this.editWidget.children = this.editWidget.renderer.renderTree.createRenderers(this.editWidget.renderer,[node]);
|
||||
};
|
||||
|
||||
TextEditor.prototype.setFocus = function() {
|
||||
if(this.editWidget.renderer.hasAttribute("focusSet")) {
|
||||
var title = this.editWidget.renderer.getAttribute("focusSet");
|
||||
if(this.editWidget.renderer.getAttribute("qualifyTiddlerTitles") === "yes") {
|
||||
title = title + "-" + this.editWidget.renderer.renderTree.getContextScopeId(this.editWidget.renderer.parentRenderer);
|
||||
}
|
||||
$tw.popup.triggerPopup({
|
||||
domNode: this.editWidget.renderer.domNode,
|
||||
title: title,
|
||||
wiki: this.editWidget.renderer.renderTree.wiki,
|
||||
force: true
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
TextEditor.prototype.handleFocusEvent = function(event) {
|
||||
// this.saveChanges();
|
||||
// this.fixHeight();
|
||||
this.setFocus();
|
||||
return true;
|
||||
};
|
||||
|
||||
TextEditor.prototype.handleBlurEvent = function(event) {
|
||||
// this.saveChanges();
|
||||
return true;
|
||||
};
|
||||
|
||||
TextEditor.prototype.handleInputEvent = function(event) {
|
||||
this.saveChanges();
|
||||
this.fixHeight();
|
||||
return true;
|
||||
};
|
||||
|
||||
TextEditor.prototype.saveChanges = function() {
|
||||
var text = this.editWidget.children[0].domNode.value
|
||||
if(this.fieldName) {
|
||||
var tiddler = this.editWidget.renderer.renderTree.wiki.getTiddler(this.tiddlerTitle);
|
||||
if(!tiddler) {
|
||||
tiddler = new $tw.Tiddler({title: this.tiddlerTitle});
|
||||
}
|
||||
var oldValue = tiddler.getFieldString(this.fieldName);
|
||||
if(text !== oldValue) {
|
||||
var update = {};
|
||||
update[this.fieldName] = text;
|
||||
this.editWidget.renderer.renderTree.wiki.addTiddler(new $tw.Tiddler(tiddler,update));
|
||||
}
|
||||
} else {
|
||||
var data = this.editWidget.renderer.renderTree.wiki.getTiddlerData(this.tiddlerTitle,{});
|
||||
if(data[this.indexName] !== text) {
|
||||
data[this.indexName] = text;
|
||||
this.editWidget.renderer.renderTree.wiki.setTiddlerData(this.tiddlerTitle,data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TextEditor.prototype.fixHeight = function() {
|
||||
var self = this;
|
||||
if(this.editWidget.children[0].domNode && this.editWidget.children[0].domNode.type === "textarea") {
|
||||
$tw.utils.nextTick(function() {
|
||||
// Resize the textarea to fit its content
|
||||
var textarea = self.editWidget.children[0].domNode,
|
||||
scrollPosition = $tw.utils.getScrollPosition(),
|
||||
scrollTop = scrollPosition.y;
|
||||
// Set its height to auto so that it snaps to the correct height
|
||||
textarea.style.height = "auto";
|
||||
// Calculate the revised height
|
||||
var newHeight = Math.max(textarea.scrollHeight + textarea.offsetHeight - textarea.clientHeight,MIN_TEXT_AREA_HEIGHT);
|
||||
// Only try to change the height if it has changed
|
||||
if(newHeight !== textarea.offsetHeight) {
|
||||
textarea.style.height = newHeight + "px";
|
||||
// Make sure that the dimensions of the textarea are recalculated
|
||||
$tw.utils.forceLayout(textarea);
|
||||
// Check that the scroll position is still visible before trying to scroll back to it
|
||||
scrollTop = Math.min(scrollTop,self.editWidget.renderer.renderTree.document.body.scrollHeight - window.innerHeight);
|
||||
window.scrollTo(scrollPosition.x,scrollTop);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
TextEditor.prototype.postRenderInDom = function() {
|
||||
this.fixHeight();
|
||||
};
|
||||
|
||||
TextEditor.prototype.refreshInDom = function() {
|
||||
if(this.editWidget.renderer.renderTree.document.activeElement !== this.editWidget.children[0].domNode) {
|
||||
var editInfo = this.getEditInfo();
|
||||
this.editWidget.children[0].domNode.value = editInfo.value;
|
||||
}
|
||||
// Fix the height if needed
|
||||
this.fixHeight();
|
||||
};
|
||||
|
||||
exports["text/vnd.tiddlywiki"] = TextEditor;
|
||||
exports["text/plain"] = TextEditor;
|
||||
|
||||
})();
|
@ -1,51 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/encrypt.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Implements the encrypt widget.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var EncryptWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate child nodes
|
||||
this.generate();
|
||||
};
|
||||
|
||||
EncryptWidget.prototype.generate = function() {
|
||||
// Get the parameters from the attributes
|
||||
this.filter = this.renderer.getAttribute("filter");
|
||||
// Check whether we've got an encryption password
|
||||
var isEncrypted = $tw.crypto.hasPassword();
|
||||
// Encrypt the filtered tiddlers
|
||||
var tiddlers = this.renderer.renderTree.wiki.filterTiddlers(this.filter),
|
||||
json = {},
|
||||
self = this;
|
||||
$tw.utils.each(tiddlers,function(title) {
|
||||
var tiddler = self.renderer.renderTree.wiki.getTiddler(title),
|
||||
jsonTiddler = {};
|
||||
for(var f in tiddler.fields) {
|
||||
jsonTiddler[f] = tiddler.getFieldString(f);
|
||||
}
|
||||
json[title] = jsonTiddler;
|
||||
});
|
||||
var encryptedText = $tw.utils.htmlEncode($tw.crypto.encrypt(JSON.stringify(json)));
|
||||
// Set the return element
|
||||
this.tag = "pre";
|
||||
this.attributes ={"class": "tw-encrypt"};
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,[{
|
||||
type: "text",
|
||||
text: encryptedText
|
||||
}]);
|
||||
};
|
||||
|
||||
exports.encrypt = EncryptWidget;
|
||||
|
||||
})();
|
@ -1,37 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/error.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
The error widget displays an error message.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var ErrorWidget = function(renderer,errorMessage) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
this.errorMessage = errorMessage;
|
||||
// Generate child nodes
|
||||
this.generate();
|
||||
};
|
||||
|
||||
ErrorWidget.prototype.generate = function() {
|
||||
// Set the element details
|
||||
this.tag = "span";
|
||||
this.attributes = {
|
||||
"class": "tw-error-widget"
|
||||
};
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,[{
|
||||
type: "text",
|
||||
text: this.errorMessage
|
||||
}]);
|
||||
};
|
||||
|
||||
exports.error = ErrorWidget;
|
||||
|
||||
})();
|
@ -1,87 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/fieldmangler.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
The fieldmangler widget modifies the fields of the current tiddler in response to messages.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var FieldManglerWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate child nodes
|
||||
this.generate();
|
||||
};
|
||||
|
||||
FieldManglerWidget.prototype.generate = function() {
|
||||
var self = this;
|
||||
// Get parameters from our attributes
|
||||
this.tiddlerTitle = this.renderer.getAttribute("tiddler",this.renderer.tiddlerTitle);
|
||||
// Set the element
|
||||
this.tag = "div";
|
||||
this.attributes = {
|
||||
"class": "tw-fieldmangler"
|
||||
};
|
||||
// Set event handlers
|
||||
this.events = [
|
||||
{name: "tw-remove-field", handlerObject: this, handlerMethod: "handleRemoveFieldEvent"},
|
||||
{name: "tw-add-field", handlerObject: this, handlerMethod: "handleAddFieldEvent"},
|
||||
{name: "tw-remove-tag", handlerObject: this, handlerMethod: "handleRemoveTagEvent"},
|
||||
{name: "tw-add-tag", handlerObject: this, handlerMethod: "handleAddTagEvent"}
|
||||
];
|
||||
// Render the children
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,this.renderer.parseTreeNode.children);
|
||||
};
|
||||
|
||||
FieldManglerWidget.prototype.handleRemoveFieldEvent = function(event) {
|
||||
var tiddler = this.renderer.renderTree.wiki.getTiddler(this.tiddlerTitle),
|
||||
deletion = {};
|
||||
deletion[event.param] = undefined;
|
||||
this.renderer.renderTree.wiki.addTiddler(new $tw.Tiddler(tiddler,deletion));
|
||||
return true;
|
||||
};
|
||||
|
||||
FieldManglerWidget.prototype.handleAddFieldEvent = function(event) {
|
||||
var tiddler = this.renderer.renderTree.wiki.getTiddler(this.tiddlerTitle);
|
||||
if(tiddler && typeof event.param === "string" && event.param !== "" && !$tw.utils.hop(tiddler.fields,event.param)) {
|
||||
var addition = {};
|
||||
addition[event.param] = "";
|
||||
this.renderer.renderTree.wiki.addTiddler(new $tw.Tiddler(tiddler,addition));
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
FieldManglerWidget.prototype.handleRemoveTagEvent = function(event) {
|
||||
var tiddler = this.renderer.renderTree.wiki.getTiddler(this.tiddlerTitle);
|
||||
if(tiddler && tiddler.fields.tags) {
|
||||
var p = tiddler.fields.tags.indexOf(event.param);
|
||||
if(p !== -1) {
|
||||
var modification = {};
|
||||
modification.tags = (tiddler.fields.tags || []).slice(0);
|
||||
modification.tags.splice(p,1);
|
||||
this.renderer.renderTree.wiki.addTiddler(new $tw.Tiddler(tiddler,modification));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
FieldManglerWidget.prototype.handleAddTagEvent = function(event) {
|
||||
var tiddler = this.renderer.renderTree.wiki.getTiddler(this.tiddlerTitle);
|
||||
if(tiddler && typeof event.param === "string" && event.param !== "") {
|
||||
var modification = {};
|
||||
modification.tags = (tiddler.fields.tags || []).slice(0);
|
||||
$tw.utils.pushTop(modification.tags,event.param);
|
||||
this.renderer.renderTree.wiki.addTiddler(new $tw.Tiddler(tiddler,modification));
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
exports.fieldmangler = FieldManglerWidget;
|
||||
|
||||
})();
|
@ -1,94 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/fields.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
The fields widget displays the fields of a tiddler through a text substitution template.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var FieldsWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate child nodes
|
||||
this.generate();
|
||||
};
|
||||
|
||||
FieldsWidget.prototype.generate = function() {
|
||||
// Get parameters from our attributes
|
||||
this.tiddlerTitle = this.renderer.getAttribute("tiddler",this.renderer.tiddlerTitle);
|
||||
this.template = this.renderer.getAttribute("template");
|
||||
this.exclude = this.renderer.getAttribute("exclude");
|
||||
this.stripTitlePrefix = this.renderer.getAttribute("stripTitlePrefix","no") === "yes";
|
||||
// Get the tiddler we're displaying
|
||||
var tiddler = this.renderer.renderTree.wiki.getTiddler(this.tiddlerTitle);
|
||||
// Get the exclusion list
|
||||
var exclude;
|
||||
if(this.exclude) {
|
||||
exclude = this.exclude.split(" ");
|
||||
} else {
|
||||
exclude = ["text"];
|
||||
}
|
||||
// Compose the template
|
||||
var text = [];
|
||||
if(this.template && tiddler) {
|
||||
var fields = [];
|
||||
for(var fieldName in tiddler.fields) {
|
||||
if(exclude.indexOf(fieldName) === -1) {
|
||||
fields.push(fieldName);
|
||||
}
|
||||
}
|
||||
fields.sort();
|
||||
for(var f=0; f<fields.length; f++) {
|
||||
fieldName = fields[f];
|
||||
if(exclude.indexOf(fieldName) === -1) {
|
||||
var row = this.template,
|
||||
value = tiddler.getFieldString(fieldName);
|
||||
if(this.stripTitlePrefix && fieldName === "title") {
|
||||
var reStrip = /^\{[^\}]+\}(.+)/mg,
|
||||
reMatch = reStrip.exec(value);
|
||||
if(reMatch) {
|
||||
value = reMatch[1];
|
||||
}
|
||||
}
|
||||
row = row.replace("$name$",fieldName);
|
||||
row = row.replace("$value$",value);
|
||||
row = row.replace("$encoded_value$",$tw.utils.htmlEncode(value));
|
||||
text.push(row)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set the element
|
||||
this.tag = "pre";
|
||||
this.attributes = {
|
||||
"class": "tw-fields"
|
||||
};
|
||||
// Set up the attributes for the wrapper element
|
||||
var classes = [];
|
||||
if(this.renderer.hasAttribute("class")) {
|
||||
$tw.utils.pushTop(classes,this.renderer.getAttribute("class").split(" "));
|
||||
}
|
||||
if(classes.length > 0) {
|
||||
this.attributes["class"] = classes.join(" ");
|
||||
}
|
||||
if(this.renderer.hasAttribute("style")) {
|
||||
this.attributes.style = this.renderer.getAttribute("style");
|
||||
}
|
||||
if(this.renderer.hasAttribute("tooltip")) {
|
||||
this.attributes.title = this.renderer.getAttribute("tooltip");
|
||||
}
|
||||
// Create the renderers for the wrapper and the children
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,[{
|
||||
type: "text",
|
||||
text: text.join("")
|
||||
}]);
|
||||
};
|
||||
|
||||
exports.fields = FieldsWidget;
|
||||
|
||||
})();
|
@ -1,109 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/grid.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
The grid widget.
|
||||
|
||||
This example renders a table made up of tiddlers titled `MySheet_A_1`, `MySheet_A_2`, `MySheet_A_3`, ... , `MySheet_B_1`, `MySheet_B_2`, `MySheet_B_3` etc.
|
||||
|
||||
```
|
||||
<$grid prefix="MySheet" rows=20 cols=20/>
|
||||
```
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var GridWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate widget elements
|
||||
this.generate();
|
||||
};
|
||||
|
||||
GridWidget.prototype.generate = function() {
|
||||
// Get our attributes
|
||||
this.prefix = this.renderer.getAttribute("prefix","Grid");
|
||||
this.rows = parseInt(this.renderer.getAttribute("rows","10"),10);
|
||||
this.cols = parseInt(this.renderer.getAttribute("cols","10"),10);
|
||||
this["class"] = this.renderer.getAttribute("class");
|
||||
// Set up the classes
|
||||
var classes = ["tw-grid-frame"];
|
||||
if(this["class"]) {
|
||||
$tw.utils.pushTop(classes,this["class"]);
|
||||
}
|
||||
// Create the grid table element
|
||||
this.tag = "div";
|
||||
this.attributes = {
|
||||
"class": classes.join(" ")
|
||||
};
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,this.generateTable());
|
||||
};
|
||||
|
||||
GridWidget.prototype.generateTable = function() {
|
||||
var rows = [];
|
||||
for(var row=0; row<this.rows; row++) {
|
||||
var tr = {
|
||||
type: "element",
|
||||
tag: "tr",
|
||||
children: []
|
||||
};
|
||||
rows.push(tr);
|
||||
for(var col=0; col<this.cols; col++) {
|
||||
var td = {
|
||||
type: "element",
|
||||
tag: "td",
|
||||
children: [{
|
||||
type: "element",
|
||||
tag: "$transclude",
|
||||
attributes: {
|
||||
title: {type: "string", value: this.getTableCellTitle(col,row)}
|
||||
}
|
||||
}]
|
||||
};
|
||||
tr.children.push(td);
|
||||
}
|
||||
}
|
||||
return [{
|
||||
type: "element",
|
||||
tag: "table",
|
||||
children: [{
|
||||
type: "element",
|
||||
tag: "tbody",
|
||||
children: rows
|
||||
}]
|
||||
}];
|
||||
};
|
||||
|
||||
GridWidget.prototype.getTableCellTitle = function(col,row) {
|
||||
var c = String.fromCharCode(col % 26 + "A".charCodeAt(0));
|
||||
col = Math.floor(col/26);
|
||||
while(col>0) {
|
||||
c = String.fromCharCode(col % 26 + "A".charCodeAt(0) - 1) + c;
|
||||
col = Math.floor(col/26);
|
||||
}
|
||||
return this.prefix + "_" + c + "_" + (row + 1);
|
||||
};
|
||||
|
||||
GridWidget.prototype.postRenderInDom = function() {
|
||||
};
|
||||
|
||||
GridWidget.prototype.refreshInDom = function(changedAttributes,changedTiddlers) {
|
||||
// Reexecute the widget if any of our attributes have changed
|
||||
if(true) {
|
||||
// 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 {
|
||||
}
|
||||
};
|
||||
|
||||
exports.grid = GridWidget;
|
||||
|
||||
})();
|
@ -1,256 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/import.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Implements the import widget.
|
||||
|
||||
```
|
||||
<$import>
|
||||
Import using the "browse..." button or drag files onto this text
|
||||
</$import>
|
||||
```
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var ImportWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate child nodes
|
||||
this.generate();
|
||||
};
|
||||
|
||||
ImportWidget.prototype.generate = function() {
|
||||
// Get the parameters from the attributes
|
||||
this.browse = this.renderer.getAttribute("browse","yes");
|
||||
this["class"] = this.renderer.getAttribute("class");
|
||||
// Compute classes
|
||||
var classes = ["tw-import"];
|
||||
if(this["class"]) {
|
||||
$tw.utils.pushTop(classes,this["class"]);
|
||||
}
|
||||
// Create the file input and container elements
|
||||
var fileInput = {
|
||||
type: "element",
|
||||
tag: "input",
|
||||
attributes: {
|
||||
type: {type: "string", value: "file"},
|
||||
style: {type: "string", value: this.browse === "no" ? "display: none;" : "display: block;"}
|
||||
},
|
||||
events: [{name: "change", handlerObject: this, handlerMethod: "handleChangeEvent"}]
|
||||
},
|
||||
container = {
|
||||
type: "element",
|
||||
tag: "div",
|
||||
children: this.renderer.parseTreeNode.children,
|
||||
events: [
|
||||
{name: "dragenter", handlerObject: this, handlerMethod: "handleDragEnterEvent"},
|
||||
{name: "dragover", handlerObject: this, handlerMethod: "handleDragOverEvent"},
|
||||
{name: "dragleave", handlerObject: this, handlerMethod: "handleDragLeaveEvent"},
|
||||
{name: "drop", handlerObject: this, handlerMethod: "handleDropEvent"},
|
||||
{name: "paste", handlerObject: this, handlerMethod: "handlePasteEvent"}]
|
||||
};
|
||||
// Set the return element
|
||||
this.tag = "div";
|
||||
this.attributes = {
|
||||
"class": classes.join(" ")
|
||||
};
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,[fileInput,container]);
|
||||
};
|
||||
|
||||
ImportWidget.prototype.handleChangeEvent = function(event) {
|
||||
event.stopPropagation();
|
||||
this.importFiles(event.target.files);
|
||||
};
|
||||
|
||||
ImportWidget.prototype.handleDragEnterEvent = function(event) {
|
||||
// We count enter/leave events
|
||||
this.dragEnterCount = (this.dragEnterCount || 0) + 1;
|
||||
// If we're entering for the first time we need to apply highlighting
|
||||
if(this.dragEnterCount === 1) {
|
||||
$tw.utils.addClass(this.renderer.domNode,"tw-dragover");
|
||||
}
|
||||
// Tell the browser that we're ready to handle the drop
|
||||
event.preventDefault();
|
||||
// Tell the browser not to ripple the drag up to any parent drop handlers
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
ImportWidget.prototype.handleDragOverEvent = function(event) {
|
||||
// Tell the browser that we're still interested in the drop
|
||||
event.preventDefault();
|
||||
event.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy
|
||||
};
|
||||
|
||||
ImportWidget.prototype.handleDragLeaveEvent = function(event) {
|
||||
// Reduce the enter count
|
||||
this.dragEnterCount = (this.dragEnterCount || 0) - 1;
|
||||
// Remove highlighting if we're leaving externally
|
||||
if(this.dragEnterCount <= 0) {
|
||||
$tw.utils.removeClass(this.renderer.domNode,"tw-dragover");
|
||||
}
|
||||
};
|
||||
|
||||
ImportWidget.prototype.handleDropEvent = function(event) {
|
||||
var dataTransfer = event.dataTransfer;
|
||||
// Reset the enter count
|
||||
this.dragEnterCount = 0;
|
||||
// Remove highlighting
|
||||
$tw.utils.removeClass(this.renderer.domNode,"tw-dragover");
|
||||
// Try to import the various data types we understand
|
||||
this.importData(dataTransfer);
|
||||
// Import any files in the drop
|
||||
this.importFiles(dataTransfer.files);
|
||||
// Tell the browser that we handled the drop
|
||||
event.preventDefault();
|
||||
// Stop the drop ripple up to any parent handlers
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
ImportWidget.prototype.handlePasteEvent = function(event) {
|
||||
// Let the browser handle it if we're in a textarea or input box
|
||||
if(["TEXTAREA","INPUT"].indexOf(event.target.tagName) == -1) {
|
||||
var self = this,
|
||||
items = event.clipboardData.items;
|
||||
// Enumerate the clipboard items
|
||||
for(var t = 0; t<items.length; t++) {
|
||||
var item = items[t];
|
||||
if(item.kind === "file") {
|
||||
// Import any files
|
||||
var file = item.getAsFile();
|
||||
this.importFiles([file]);
|
||||
} else if(item.kind === "string") {
|
||||
// Create tiddlers from string items
|
||||
item.getAsString(function(str) {
|
||||
var fields = {
|
||||
title: self.generateTitle("Untitled"),
|
||||
text: str
|
||||
};
|
||||
self.storeTiddler(fields);
|
||||
self.openTiddler(fields.title);
|
||||
});
|
||||
}
|
||||
}
|
||||
// Tell the browser that we've handled the paste
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
ImportWidget.prototype.openTiddler = function(title) {
|
||||
$tw.utils.dispatchCustomEvent(this.renderer.domNode,"tw-navigate",{
|
||||
navigateTo: title,
|
||||
navigateFromNode: this.renderer.domNode,
|
||||
navigateFromClientRect: this.renderer.domNode.getBoundingClientRect()
|
||||
});
|
||||
};
|
||||
|
||||
ImportWidget.prototype.importData = function(dataTransfer) {
|
||||
for(var t=0; t<this.importDataTypes.length; t++) {
|
||||
var dataType = this.importDataTypes[t];
|
||||
var data = dataTransfer.getData(dataType.type);
|
||||
if(data !== "") {
|
||||
var fields = dataType.handler(data);
|
||||
if(!fields.title) {
|
||||
fields.title = this.generateTitle("Untitled");
|
||||
}
|
||||
this.storeTiddler(fields);
|
||||
this.openTiddler(fields.title);
|
||||
return;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
ImportWidget.prototype.importDataTypes = [
|
||||
{type: "text/vnd.tiddler", handler: function(data) {
|
||||
return JSON.parse(data);
|
||||
}},
|
||||
{type: "text/plain", handler: function(data) {
|
||||
return {
|
||||
text: data
|
||||
};
|
||||
}},
|
||||
{type: "text/uri-list", handler: function(data) {
|
||||
return {
|
||||
text: data
|
||||
};
|
||||
}}
|
||||
];
|
||||
|
||||
ImportWidget.prototype.importFiles = function(files) {
|
||||
var self = this,
|
||||
importFile = function(file) {
|
||||
// Get the type, falling back to the filename extension
|
||||
var type = file.type;
|
||||
if(type === "" || !type) {
|
||||
var dotPos = file.name.lastIndexOf(".");
|
||||
if(dotPos !== -1) {
|
||||
var fileExtensionInfo = $tw.config.fileExtensionInfo[file.name.substr(dotPos)];
|
||||
if(fileExtensionInfo) {
|
||||
type = fileExtensionInfo.type;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Figure out if we're reading a binary file
|
||||
var contentTypeInfo = $tw.config.contentTypeInfo[type],
|
||||
isBinary = contentTypeInfo ? contentTypeInfo.encoding === "base64" : false;
|
||||
// Create the FileReader
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(event) {
|
||||
// Deserialise the file contents
|
||||
var fields = {
|
||||
title: file.name || "Untitled",
|
||||
type: type};
|
||||
// Are we binary?
|
||||
if(isBinary) {
|
||||
var commaPos = event.target.result.indexOf(",");
|
||||
if(commaPos !== -1) {
|
||||
fields.text = event.target.result.substr(commaPos+1);
|
||||
self.storeTiddler(fields);
|
||||
self.openTiddler(fields.title);
|
||||
}
|
||||
} else {
|
||||
var tiddlers = self.renderer.renderTree.wiki.deserializeTiddlers(type,event.target.result,fields);
|
||||
if(!tiddlers) {
|
||||
console.log("No tiddlers found in file ",file.name);
|
||||
} else {
|
||||
$tw.utils.each(tiddlers,function(tiddlerFields) {
|
||||
tiddlerFields.title = self.generateTitle(tiddlerFields.title);
|
||||
self.storeTiddler(tiddlerFields);
|
||||
self.openTiddler(tiddlerFields.title);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
if(isBinary) {
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
reader.readAsText(file);
|
||||
}
|
||||
};
|
||||
for(var f=0; f<files.length; f++) {
|
||||
importFile(files[f]);
|
||||
};
|
||||
};
|
||||
|
||||
ImportWidget.prototype.storeTiddler = function(fields) {
|
||||
this.renderer.renderTree.wiki.addTiddler(new $tw.Tiddler(fields,this.renderer.renderTree.wiki.getModificationFields()));
|
||||
};
|
||||
|
||||
ImportWidget.prototype.generateTitle = function(baseTitle) {
|
||||
var c = 0;
|
||||
do {
|
||||
var title = baseTitle + (c ? " " + (c + 1) : "");
|
||||
c++;
|
||||
} while(this.renderer.renderTree.wiki.tiddlerExists(title));
|
||||
return title;
|
||||
};
|
||||
|
||||
exports.import = ImportWidget;
|
||||
|
||||
})();
|
@ -1,115 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/info.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Implements the info widget that displays various information about a specified tiddler.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var InfoWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate child nodes
|
||||
this.generate();
|
||||
};
|
||||
|
||||
InfoWidget.types = {};
|
||||
|
||||
InfoWidget.types.changecount = function(options) {
|
||||
var text = options.wiki.getChangeCount(options.widget.renderer.tiddlerTitle);
|
||||
return [{type: "text", text: text}];
|
||||
};
|
||||
|
||||
InfoWidget.types.currentfield = function(options) {
|
||||
var fieldName = options.widget.renderer.renderTree.getContextVariable(options.widget.renderer,"field","text");
|
||||
return [{type: "text", text: fieldName}];
|
||||
};
|
||||
|
||||
var FIELD_DESCRIPTION_PREFIX = "$:/docs/fields/";
|
||||
|
||||
InfoWidget.types.currentfielddescription = function(options) {
|
||||
var fieldName = options.widget.renderer.renderTree.getContextVariable(options.widget.renderer,"field","text"),
|
||||
descriptionTitle = FIELD_DESCRIPTION_PREFIX + fieldName;
|
||||
return [{
|
||||
type: "element",
|
||||
tag: "$transclude",
|
||||
isBlock: false,
|
||||
attributes: {
|
||||
title: {type: "string", value: descriptionTitle}
|
||||
}
|
||||
}];
|
||||
};
|
||||
|
||||
var MODULE_TYPE_DESCRIPTION_PREFIX = "$:/docs/moduletypes/";
|
||||
|
||||
/*
|
||||
Return a list of all the currently loaded modules grouped by type
|
||||
*/
|
||||
InfoWidget.types.modules = function(options) {
|
||||
var output = [],
|
||||
types = [];
|
||||
// Collect and sort the module types
|
||||
$tw.utils.each($tw.modules.types,function(moduleInfo,type) {
|
||||
types.push(type);
|
||||
});
|
||||
types.sort();
|
||||
// Output the module types
|
||||
$tw.utils.each(types,function(moduleType) {
|
||||
// Heading
|
||||
output.push({type: "element", tag: "h2", children: [
|
||||
{type: "text", text: moduleType}
|
||||
]})
|
||||
// Description
|
||||
output.push({
|
||||
type: "element",
|
||||
tag: "$transclude",
|
||||
isBlock: false,
|
||||
attributes: {
|
||||
title: {type: "string", value: MODULE_TYPE_DESCRIPTION_PREFIX + moduleType}
|
||||
}
|
||||
});
|
||||
// List each module
|
||||
var list = {type: "element", tag: "ul", children: []},
|
||||
modules = [];
|
||||
$tw.utils.each($tw.modules.types[moduleType],function(moduleInfo,moduleName) {
|
||||
var listItem = {type: "element", tag: "li", children: [
|
||||
{type: "element", tag: "$link", attributes: {
|
||||
to: {type: "string", value: moduleName}
|
||||
}, children: [
|
||||
{type: "text", text: moduleName}
|
||||
]}
|
||||
]}
|
||||
list.children.push(listItem);
|
||||
});
|
||||
output.push(list);
|
||||
});
|
||||
return output;
|
||||
};
|
||||
|
||||
InfoWidget.prototype.generate = function() {
|
||||
// Get attributes
|
||||
this.type = this.renderer.getAttribute("type","changecount").toLowerCase();
|
||||
// Get the appropriate value for the current tiddler
|
||||
var value = [],
|
||||
fn = InfoWidget.types[this.type];
|
||||
if(fn) {
|
||||
value = fn({
|
||||
wiki: this.renderer.renderTree.wiki,
|
||||
widget: this
|
||||
});
|
||||
}
|
||||
// Set the element
|
||||
this.tag = "span";
|
||||
this.attributes = {};
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,value);
|
||||
};
|
||||
|
||||
exports.info = InfoWidget;
|
||||
|
||||
})();
|
@ -1,203 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/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.generate();
|
||||
};
|
||||
|
||||
LinkWidget.prototype.generate = function() {
|
||||
// Get the parameters from the attributes
|
||||
this.to = this.renderer.getAttribute("to",this.renderer.tiddlerTitle);
|
||||
this.hover = this.renderer.getAttribute("hover");
|
||||
this.qualifyHoverTitles = this.renderer.getAttribute("qualifyHoverTitles");
|
||||
// Qualify the hover tiddler title if needed
|
||||
if(this.qualifyHoverTitles) {
|
||||
this.hover = this.hover + "-" + this.renderer.renderTree.getContextScopeId(this.renderer.parentRenderer);
|
||||
}
|
||||
// Determine the default link characteristics
|
||||
this.isExternal = isLinkExternal(this.to);
|
||||
if(!this.isExternal) {
|
||||
this.isMissing = !this.renderer.renderTree.wiki.tiddlerExists(this.to);
|
||||
this.isShadow = this.renderer.renderTree.wiki.isShadowTiddler(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.isShadow) {
|
||||
$tw.utils.pushTop(classes,"tw-tiddlylink-shadow");
|
||||
}
|
||||
if(this.isMissing && !this.isShadow) {
|
||||
$tw.utils.pushTop(classes,"tw-tiddlylink-missing");
|
||||
} else {
|
||||
if(!this.isMissing) {
|
||||
$tw.utils.pushTop(classes,"tw-tiddlylink-resolves");
|
||||
}
|
||||
}
|
||||
}
|
||||
var events = [
|
||||
{name: "click", handlerObject: this, handlerMethod: "handleClickEvent"},
|
||||
{name: "dragstart", handlerObject: this, handlerMethod: "handleDragStartEvent"},
|
||||
{name: "dragend", handlerObject: this, handlerMethod: "handleDragEndEvent"}
|
||||
];
|
||||
if(this.hover) {
|
||||
events.push({name: "mouseover", handlerObject: this, handlerMethod: "handleMouseOverOrOutEvent"});
|
||||
events.push({name: "mouseout", handlerObject: this, handlerMethod: "handleMouseOverOrOutEvent"});
|
||||
}
|
||||
// Get the value of the tw-wikilinks configuration macro
|
||||
var wikiLinksMacro = this.renderer.renderTree.findMacroDefinition(this.renderer.parentRenderer,"tw-wikilinks"),
|
||||
useWikiLinks = wikiLinksMacro ? !(wikiLinksMacro.text.trim() === "no") : true;
|
||||
// Set up the element
|
||||
if(useWikiLinks) {
|
||||
this.tag = "a";
|
||||
this.attributes = {
|
||||
"class": classes.join(" ")
|
||||
};
|
||||
if(this.isExternal) {
|
||||
this.attributes.href = this.to;
|
||||
} else {
|
||||
var wikiLinkTemplateMacro = this.renderer.renderTree.findMacroDefinition(this.renderer.parentRenderer,"tw-wikilink-template"),
|
||||
wikiLinkTemplate = wikiLinkTemplateMacro ? wikiLinkTemplateMacro.text.trim() : "#$uri_encoded$";
|
||||
this.wikiLinkText = wikiLinkTemplate.replace("$uri_encoded$",encodeURIComponent(this.to));
|
||||
this.wikiLinkText = this.wikiLinkText.replace("$uri_doubleencoded$",encodeURIComponent(encodeURIComponent(this.to)));
|
||||
this.attributes.href = this.wikiLinkText;
|
||||
}
|
||||
this.events = events;
|
||||
} else {
|
||||
this.tag = "span";
|
||||
}
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,this.renderer.parseTreeNode.children);
|
||||
};
|
||||
|
||||
LinkWidget.prototype.handleClickEvent = function(event) {
|
||||
if(isLinkExternal(this.to)) {
|
||||
event.target.setAttribute("target","_blank");
|
||||
return true;
|
||||
} else {
|
||||
var bounds = this.renderer.domNode.getBoundingClientRect();
|
||||
$tw.utils.dispatchCustomEvent(event.target,"tw-navigate",{
|
||||
navigateTo: this.to,
|
||||
navigateFromNode: this,
|
||||
navigateFromClientRect: {
|
||||
top: bounds.top,
|
||||
left: bounds.left,
|
||||
width: bounds.width,
|
||||
right: bounds.right,
|
||||
bottom: bounds.bottom,
|
||||
height: bounds.height
|
||||
}
|
||||
});
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
LinkWidget.prototype.handleMouseOverOrOutEvent = function(event) {
|
||||
if(this.hover) {
|
||||
$tw.popup.triggerPopup({
|
||||
title: this.hover,
|
||||
domNode: this.renderer.domNode,
|
||||
wiki: this.renderer.renderTree.wiki
|
||||
});
|
||||
}
|
||||
event.preventDefault();
|
||||
return false;
|
||||
};
|
||||
|
||||
LinkWidget.prototype.handleDragStartEvent = function(event) {
|
||||
if(this.to) {
|
||||
// Set the dragging class on the element being dragged
|
||||
$tw.utils.addClass(event.target,"tw-tiddlylink-dragging");
|
||||
// Create the drag image elements
|
||||
this.dragImage = this.renderer.renderTree.document.createElement("div");
|
||||
this.dragImage.className = "tw-tiddler-dragger";
|
||||
var inner = this.renderer.renderTree.document.createElement("div");
|
||||
inner.className = "tw-tiddler-dragger-inner";
|
||||
inner.appendChild(this.renderer.renderTree.document.createTextNode(this.to));
|
||||
this.dragImage.appendChild(inner);
|
||||
this.renderer.renderTree.document.body.appendChild(this.dragImage);
|
||||
// Astoundingly, we need to cover the dragger up: http://www.kryogenix.org/code/browser/custom-drag-image.html
|
||||
var bounds = this.dragImage.firstChild.getBoundingClientRect(),
|
||||
cover = this.renderer.renderTree.document.createElement("div");
|
||||
cover.className = "tw-tiddler-dragger-cover";
|
||||
cover.style.left = (bounds.left - 8) + "px";
|
||||
cover.style.top = (bounds.top - 8) + "px";
|
||||
cover.style.width = (bounds.width + 16) + "px";
|
||||
cover.style.height = (bounds.height + 16) + "px";
|
||||
this.dragImage.appendChild(cover);
|
||||
// Set the data transfer properties
|
||||
var dataTransfer = event.dataTransfer;
|
||||
dataTransfer.effectAllowed = "copy";
|
||||
dataTransfer.setDragImage(this.dragImage.firstChild,-16,-16);
|
||||
dataTransfer.clearData();
|
||||
dataTransfer.setData("text/vnd.tiddler",this.renderer.renderTree.wiki.getTiddlerAsJson(this.to));
|
||||
dataTransfer.setData("text/plain",this.renderer.renderTree.wiki.getTiddlerText(this.to,""));
|
||||
event.stopPropagation();
|
||||
} else {
|
||||
event.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
LinkWidget.prototype.handleDragEndEvent = function(event) {
|
||||
// Remove the dragging class on the element being dragged
|
||||
$tw.utils.removeClass(event.target,"tw-tiddlylink-dragging");
|
||||
// Delete the drag image element
|
||||
if(this.dragImage) {
|
||||
this.dragImage.parentNode.removeChild(this.dragImage);
|
||||
}
|
||||
};
|
||||
|
||||
LinkWidget.prototype.postRenderInDom = function() {
|
||||
// Add the draggable attribute to links (we don't include it in the static HTML representation)
|
||||
if(this.renderer.domNode.tagName === "A") {
|
||||
this.renderer.domNode.setAttribute("draggable",true);
|
||||
}
|
||||
};
|
||||
|
||||
LinkWidget.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.to || changedAttributes.hover || (this.to && changedTiddlers[this.to]) || (this.hover && changedTiddlers[this.hover])) {
|
||||
// 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.link = LinkWidget;
|
||||
|
||||
})();
|
@ -1,71 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/linkcatcher.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Implements the linkcatcher widget. It intercepts navigation events from its children, preventing normal navigation, and instead stores the name of the target tiddler in the text reference specified in the `to` attribute.
|
||||
|
||||
Using the linkcatcher widget allows the linking mechanism to be used for tasks like selecting the current theme tiddler from a list.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var LinkCatcherWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate child nodes
|
||||
this.generate();
|
||||
};
|
||||
|
||||
LinkCatcherWidget.prototype.generate = function() {
|
||||
// Get our attributes
|
||||
this.to = this.renderer.getAttribute("to");
|
||||
this.message = this.renderer.getAttribute("message");
|
||||
this.set = this.renderer.getAttribute("set");
|
||||
this.setTo = this.renderer.getAttribute("setTo");
|
||||
// Set the element
|
||||
this.tag = "div";
|
||||
this.attributes = {
|
||||
"class": "tw-linkcatcher"
|
||||
};
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,this.renderer.parseTreeNode.children);
|
||||
this.events = [
|
||||
{name: "tw-navigate", handlerObject: this, handlerMethod: "handleNavigateEvent"}
|
||||
];
|
||||
};
|
||||
|
||||
LinkCatcherWidget.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);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Navigate to a specified tiddler
|
||||
LinkCatcherWidget.prototype.handleNavigateEvent = function(event) {
|
||||
if(this.to) {
|
||||
this.renderer.renderTree.wiki.setTextReference(this.to,event.navigateTo,this.renderer.tiddlerTitle);
|
||||
}
|
||||
if(this.message) {
|
||||
$tw.utils.dispatchCustomEvent(this.renderer.domNode,this.message,{
|
||||
param: event.navigateTo,
|
||||
tiddlerTitle: this.renderer.tiddlerTitle
|
||||
});
|
||||
}
|
||||
if(this.set) {
|
||||
var tiddler = this.renderer.renderTree.wiki.getTiddler(this.set);
|
||||
this.renderer.renderTree.wiki.addTiddler(new $tw.Tiddler(tiddler,{title: this.set, text: this.setTo}));
|
||||
}
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
};
|
||||
|
||||
exports.linkcatcher = LinkCatcherWidget;
|
||||
|
||||
})();
|
@ -1,408 +0,0 @@
|
||||
/*\
|
||||
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";
|
||||
|
||||
var ListWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Initialise the listviews if they've not been done already
|
||||
if(!this.listViews) {
|
||||
ListWidget.prototype.listViews = {};
|
||||
$tw.modules.applyMethods("listview",this.listViews);
|
||||
}
|
||||
// Generate widget elements
|
||||
this.generate();
|
||||
};
|
||||
|
||||
var typeInfoByType = {
|
||||
plain: {
|
||||
frame: {
|
||||
block: "div", inline: "span"
|
||||
},
|
||||
member: {
|
||||
block: "div", inline: "span"
|
||||
}
|
||||
},
|
||||
ul: {
|
||||
frame: {
|
||||
block: "ul", inline: "ul"
|
||||
},
|
||||
member: {
|
||||
block: "li", inline: "li"
|
||||
}
|
||||
},
|
||||
ol: {
|
||||
frame: {
|
||||
block: "ol", inline: "ol"
|
||||
},
|
||||
member: {
|
||||
block: "li", inline: "li"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ListWidget.prototype.generate = function() {
|
||||
// Get our attributes
|
||||
this.macro = this.renderer.getAttribute("macro");
|
||||
this.type = this.renderer.getAttribute("type","plain");
|
||||
this.itemClass = this.renderer.getAttribute("itemClass");
|
||||
this.template = this.renderer.getAttribute("template");
|
||||
this.editTemplate = this.renderer.getAttribute("editTemplate");
|
||||
this.emptyMessage = this.renderer.getAttribute("emptyMessage");
|
||||
this["class"] = this.renderer.getAttribute("class");
|
||||
// Get our type information
|
||||
this.typeInfo = typeInfoByType[this.type] || typeInfoByType.plain;
|
||||
// Set up the classes
|
||||
var classes = ["tw-list-frame"];
|
||||
if(this["class"]) {
|
||||
$tw.utils.pushTop(classes,this["class"]);
|
||||
}
|
||||
// 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
|
||||
this.tag = this.renderer.parseTreeNode.isBlock ? this.typeInfo.frame.block : this.typeInfo.frame.inline;
|
||||
this.attributes = {
|
||||
"class": classes.join(" ")
|
||||
};
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,listMembers);
|
||||
};
|
||||
|
||||
ListWidget.prototype.getTiddlerList = function() {
|
||||
var filter;
|
||||
if(this.renderer.hasAttribute("filter")) {
|
||||
filter = this.renderer.getAttribute("filter");
|
||||
}
|
||||
if(!filter) {
|
||||
filter = "[!is[system]]";
|
||||
}
|
||||
this.list = this.renderer.renderTree.wiki.filterTiddlers(filter,this.renderer.tiddlerTitle);
|
||||
};
|
||||
|
||||
/*
|
||||
Create and execute the nodes representing the empty message
|
||||
*/
|
||||
ListWidget.prototype.getEmptyMessage = function() {
|
||||
return {
|
||||
type: "element",
|
||||
tag: "span",
|
||||
children: this.renderer.renderTree.wiki.parseText("text/vnd.tiddlywiki",this.emptyMessage,{parseAsInline: true}).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: this.renderer.parseTreeNode.isBlock ? this.typeInfo.member.block : this.typeInfo.member.inline,
|
||||
attributes: {
|
||||
"class": {type: "string", value: classes.join(" ")}
|
||||
},
|
||||
children: [this.createListElementParseTree(title)],
|
||||
events: [
|
||||
{name: "tw-navigate", handlerFunction: handleEvent},
|
||||
{name: "tw-edit-tiddler", handlerFunction: handleEvent},
|
||||
{name: "tw-save-tiddler", handlerFunction: handleEvent},
|
||||
{name: "tw-close-tiddler", handlerFunction: handleEvent},
|
||||
{name: "tw-new-tiddler", handlerFunction: handleEvent}
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
Create the parse tree nodes needed to represent a given list element
|
||||
*/
|
||||
ListWidget.prototype.createListElementParseTree = function(title) {
|
||||
if(this.macro) {
|
||||
return this.createListElementMacro(title);
|
||||
} else {
|
||||
return this.createListElementTransclusion(title);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Create a macro call to represent a list element
|
||||
*/
|
||||
ListWidget.prototype.createListElementMacro = function(title) {
|
||||
// Create the macrocall rendertree node
|
||||
return {
|
||||
type: "macrocall",
|
||||
name: this.macro,
|
||||
params: [
|
||||
{name: "title", value: title}
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
Create a transclusion to represent a list element
|
||||
*/
|
||||
ListWidget.prototype.createListElementTransclusion = 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: "element",
|
||||
tag: "$view",
|
||||
attributes: {
|
||||
field: {type: "string", value: "title"},
|
||||
format: {type: "string", value: "link"}
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
// 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 {
|
||||
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
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
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[index];
|
||||
// Invoke the listview to animate the removal
|
||||
if(this.listview && this.listview.remove) {
|
||||
if(!this.listview.remove(index)) {
|
||||
// Only delete the DOM element if the listview.remove() returned false
|
||||
listElement.domNode.parentNode.removeChild(listElement.domNode);
|
||||
}
|
||||
} else {
|
||||
// Always remove the DOM node if we didn't invoke the listview
|
||||
listElement.domNode.parentNode.removeChild(listElement.domNode);
|
||||
}
|
||||
// Then delete the actual renderer node
|
||||
this.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) {
|
||||
var testNode = this.macro ? function(node) {
|
||||
// We're looking for a macro list element
|
||||
return node.widget.children[0].parseTreeNode.params[0].value === 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])) {
|
||||
return startIndex;
|
||||
}
|
||||
startIndex++;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
ListWidget.prototype.postRenderInDom = function() {
|
||||
this.listview = this.chooseListView();
|
||||
this.history = [];
|
||||
};
|
||||
|
||||
/*
|
||||
Select the appropriate list viewer
|
||||
*/
|
||||
ListWidget.prototype.chooseListView = function() {
|
||||
// Instantiate the list view
|
||||
var listviewName = this.renderer.getAttribute("listview");
|
||||
var ListView = this.listViews[listviewName];
|
||||
return ListView ? new ListView(this) : null;
|
||||
};
|
||||
|
||||
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 || changedAttributes.history || changedAttributes.listview) {
|
||||
// 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 {
|
||||
// Handle any changes to the list, and refresh any nodes we're reusing
|
||||
this.handleListChanges(changedTiddlers);
|
||||
// Update the history list
|
||||
var history = this.renderer.getAttribute("history");
|
||||
if(history && changedTiddlers[history]) {
|
||||
this.handleHistoryChanges();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ListWidget.prototype.handleListChanges = function(changedTiddlers) {
|
||||
var t,
|
||||
prevListLength = this.list.length,
|
||||
self = this;
|
||||
// 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
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,[this.getEmptyMessage()]);
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.renderInDom) {
|
||||
self.renderer.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
|
||||
this.children.splice(t,0,this.renderer.renderTree.createRenderer(this.renderer,this.createListElement(this.list[t])));
|
||||
var before = this.renderer.domNode.childNodes[t],
|
||||
newNode = this.children[t].renderInDom();
|
||||
if(before) {
|
||||
this.renderer.domNode.insertBefore(newNode,before);
|
||||
} else {
|
||||
this.renderer.domNode.appendChild(newNode);
|
||||
}
|
||||
// Ask the listview to animate the insertion
|
||||
if(this.listview && this.listview.insert) {
|
||||
this.listview.insert(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
|
||||
this.children[t].refreshInDom(changedTiddlers);
|
||||
}
|
||||
}
|
||||
// Remove any left over elements
|
||||
for(t=this.children.length-1; t>=this.list.length; t--) {
|
||||
this.removeListElement(t);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Handle any changes to the history list
|
||||
*/
|
||||
ListWidget.prototype.handleHistoryChanges = function() {
|
||||
// Get the history data
|
||||
var historyAtt = this.renderer.getAttribute("history"),
|
||||
newHistory = this.renderer.renderTree.wiki.getTiddlerData(historyAtt,[]);
|
||||
// Ignore any entries of the history that match the previous history
|
||||
var entry = 0;
|
||||
while(entry < newHistory.length && entry < this.history.length && newHistory[entry].title === this.history[entry].title) {
|
||||
entry++;
|
||||
}
|
||||
// Navigate forwards to each of the new tiddlers
|
||||
while(entry < newHistory.length) {
|
||||
if(this.listview && this.listview.navigateTo) {
|
||||
this.listview.navigateTo(newHistory[entry]);
|
||||
}
|
||||
entry++;
|
||||
}
|
||||
// Update the history
|
||||
this.history = newHistory;
|
||||
};
|
||||
|
||||
exports.list = ListWidget;
|
||||
|
||||
})();
|
@ -1,100 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/list/listviews/classic.js
|
||||
type: application/javascript
|
||||
module-type: listview
|
||||
|
||||
Views the list as a linear sequence
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var ClassicListView = function(listWidget) {
|
||||
this.listWidget = listWidget;
|
||||
}
|
||||
|
||||
ClassicListView.prototype.navigateTo = function(historyInfo) {
|
||||
var listElementIndex = this.listWidget.findListElementByTitle(0,historyInfo.title);
|
||||
if(listElementIndex === undefined) {
|
||||
return;
|
||||
}
|
||||
var listElementNode = this.listWidget.children[listElementIndex],
|
||||
targetElement = listElementNode.domNode;
|
||||
// Scroll the node into view
|
||||
var scrollEvent = this.listWidget.renderer.renderTree.document.createEvent("Event");
|
||||
scrollEvent.initEvent("tw-scroll",true,true);
|
||||
targetElement.dispatchEvent(scrollEvent);
|
||||
};
|
||||
|
||||
ClassicListView.prototype.insert = function(index) {
|
||||
var listElementNode = this.listWidget.children[index],
|
||||
targetElement = listElementNode.domNode,
|
||||
duration = $tw.utils.getAnimationDuration();
|
||||
// Get the current height of the tiddler
|
||||
var currMarginBottom = parseInt(window.getComputedStyle(targetElement).marginBottom,10),
|
||||
currMarginTop = parseInt(window.getComputedStyle(targetElement).marginTop,10),
|
||||
currHeight = targetElement.offsetHeight + currMarginTop;
|
||||
// Reset the margin once the transition is over
|
||||
setTimeout(function() {
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: "none"},
|
||||
{marginBottom: ""}
|
||||
]);
|
||||
},duration);
|
||||
// Set up the initial position of the element
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: "none"},
|
||||
{marginBottom: (-currHeight) + "px"},
|
||||
{opacity: "0.0"}
|
||||
]);
|
||||
$tw.utils.forceLayout(targetElement);
|
||||
// Transition to the final position
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: "opacity " + duration + "ms ease-in-out, " +
|
||||
"margin-bottom " + duration + "ms ease-in-out"},
|
||||
{marginBottom: currMarginBottom + "px"},
|
||||
{opacity: "1.0"}
|
||||
]);
|
||||
};
|
||||
|
||||
ClassicListView.prototype.remove = function(index) {
|
||||
var listElementNode = this.listWidget.children[index],
|
||||
targetElement = listElementNode.domNode,
|
||||
duration = $tw.utils.getAnimationDuration();
|
||||
// Get the current height of the tiddler
|
||||
var currWidth = targetElement.offsetWidth,
|
||||
currMarginBottom = parseInt(window.getComputedStyle(targetElement).marginBottom,10),
|
||||
currMarginTop = parseInt(window.getComputedStyle(targetElement).marginTop,10),
|
||||
currHeight = targetElement.offsetHeight + currMarginTop;
|
||||
// Remove the element at the end of the transition
|
||||
setTimeout(function() {
|
||||
if(targetElement.parentNode) {
|
||||
targetElement.parentNode.removeChild(targetElement);
|
||||
}
|
||||
},duration);
|
||||
// Animate the closure
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: "none"},
|
||||
{transform: "translateX(0px)"},
|
||||
{marginBottom: currMarginBottom + "px"},
|
||||
{opacity: "1.0"}
|
||||
]);
|
||||
$tw.utils.forceLayout(targetElement);
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms ease-in-out, " +
|
||||
"opacity " + duration + "ms ease-in-out, " +
|
||||
"margin-bottom " + duration + "ms ease-in-out"},
|
||||
{transform: "translateX(-" + currWidth + "px)"},
|
||||
{marginBottom: (-currHeight) + "px"},
|
||||
{opacity: "0.0"}
|
||||
]);
|
||||
// Returning true causes the DOM node not to be deleted
|
||||
return true;
|
||||
};
|
||||
|
||||
exports.classic = ClassicListView;
|
||||
|
||||
})();
|
@ -1,75 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/list/listviews/pop.js
|
||||
type: application/javascript
|
||||
module-type: listview
|
||||
|
||||
Animates list insertions and removals
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var PopListView = function(listWidget) {
|
||||
this.listWidget = listWidget;
|
||||
}
|
||||
|
||||
PopListView.prototype.insert = function(index) {
|
||||
var listElementNode = this.listWidget.children[index],
|
||||
targetElement = listElementNode.domNode,
|
||||
duration = $tw.utils.getAnimationDuration();
|
||||
// Reset once the transition is over
|
||||
setTimeout(function() {
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: "none"},
|
||||
{transform: "none"}
|
||||
]);
|
||||
},duration);
|
||||
// Set up the initial position of the element
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: "none"},
|
||||
{transform: "scale(2)"},
|
||||
{opacity: "0.0"}
|
||||
]);
|
||||
$tw.utils.forceLayout(targetElement);
|
||||
// Transition to the final position
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms ease-in-out, " +
|
||||
"opacity " + duration + "ms ease-in-out"},
|
||||
{transform: "scale(1)"},
|
||||
{opacity: "1.0"}
|
||||
]);
|
||||
};
|
||||
|
||||
PopListView.prototype.remove = function(index) {
|
||||
var listElementNode = this.listWidget.children[index],
|
||||
targetElement = listElementNode.domNode,
|
||||
duration = $tw.utils.getAnimationDuration();
|
||||
// Remove the element at the end of the transition
|
||||
setTimeout(function() {
|
||||
if(targetElement.parentNode) {
|
||||
targetElement.parentNode.removeChild(targetElement);
|
||||
}
|
||||
},duration);
|
||||
// Animate the closure
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: "none"},
|
||||
{transform: "scale(1)"},
|
||||
{opacity: "1.0"}
|
||||
]);
|
||||
$tw.utils.forceLayout(targetElement);
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms ease-in-out, " +
|
||||
"opacity " + duration + "ms ease-in-out"},
|
||||
{transform: "scale(0.1)"},
|
||||
{opacity: "0.0"}
|
||||
]);
|
||||
// Returning true causes the DOM node not to be deleted
|
||||
return true;
|
||||
};
|
||||
|
||||
exports.pop = PopListView;
|
||||
|
||||
})();
|
@ -1,31 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/list/listviews/scroller.js
|
||||
type: application/javascript
|
||||
module-type: listview
|
||||
|
||||
A list view that scrolls to newly inserted elements
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var ScrollerListView = function(listWidget) {
|
||||
this.listWidget = listWidget;
|
||||
}
|
||||
|
||||
ScrollerListView.prototype.navigateTo = function(historyInfo) {
|
||||
var listElementIndex = this.listWidget.findListElementByTitle(0,historyInfo.title),
|
||||
listElementNode = this.listWidget.children[listElementIndex],
|
||||
targetElement = listElementNode.domNode;
|
||||
// Scroll the node into view
|
||||
var scrollEvent = this.listWidget.renderer.renderTree.document.createEvent("Event");
|
||||
scrollEvent.initEvent("tw-scroll",true,true);
|
||||
targetElement.dispatchEvent(scrollEvent);
|
||||
};
|
||||
|
||||
exports.scroller = ScrollerListView;
|
||||
|
||||
})();
|
@ -1,207 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/list/listviews/zoomin.js
|
||||
type: application/javascript
|
||||
module-type: listview
|
||||
|
||||
Zooms between individual tiddlers
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var ZoominListView = function(listWidget) {
|
||||
this.listWidget = listWidget;
|
||||
this.storyNode = this.listWidget.renderer.domNode;
|
||||
// Set the current tiddler
|
||||
this.currentTiddler = this.listWidget.children[0].domNode;
|
||||
// Make all the tiddlers position absolute, and hide all but the first one
|
||||
this.storyNode.style.position = "relative";
|
||||
for(var t=0; t<this.storyNode.children.length; t++) {
|
||||
if(t) {
|
||||
this.storyNode.children[t].style.display = "none";
|
||||
}
|
||||
this.storyNode.children[t].style.position = "absolute";
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Find the first descendent node that is a <$view field="title"> widget
|
||||
*/
|
||||
function findTitleNode(node) {
|
||||
var t,r;
|
||||
// Return true if this node is a view widget with the field attribute set to "title"
|
||||
if(node instanceof $tw.WikiRenderTree.prototype.rendererClasses.element) {
|
||||
if(node.widget instanceof $tw.WikiRenderTree.prototype.rendererClasses.element.prototype.widgetClasses.view && node.attributes.field === "title") {
|
||||
return node;
|
||||
}
|
||||
if(node.widget.children) {
|
||||
for(t=0; t<node.widget.children.length; t++) {
|
||||
var r = findTitleNode(node.widget.children[t]);
|
||||
if(r) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(node.children) {
|
||||
for(t=0; t<node.children.length; t++) {
|
||||
var r = findTitleNode(node.children[t]);
|
||||
if(r) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
ZoominListView.prototype.insert = function(index) {
|
||||
var listElementNode = this.listWidget.children[index],
|
||||
targetElement = listElementNode.domNode;
|
||||
// Make the newly inserted node position absolute and hidden
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{display: "none"},
|
||||
{position: "absolute"}
|
||||
]);
|
||||
};
|
||||
|
||||
/*
|
||||
Visualise navigating back to the previous tiddler
|
||||
storyElement: story element being closed
|
||||
*/
|
||||
ZoominListView.prototype.remove = function(index) {
|
||||
var listElementNode = this.listWidget.children[index],
|
||||
targetElement = listElementNode.domNode,
|
||||
duration = $tw.utils.getAnimationDuration();
|
||||
// Set up the tiddler that is being closed
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{position: "absolute"},
|
||||
{display: "block"},
|
||||
{transformOrigin: "50% 50%"},
|
||||
{transform: "translateX(0px) translateY(0px) scale(1)"},
|
||||
{transition: "none"},
|
||||
{zIndex: "0"}
|
||||
]);
|
||||
// We'll move back to the previous or next element in the story
|
||||
var toElement = this.storyNode.children[index - 1];
|
||||
if(!toElement) {
|
||||
toElement = this.storyNode.children[index + 1];
|
||||
}
|
||||
// Set up the tiddler we're moving back in
|
||||
if(toElement) {
|
||||
$tw.utils.setStyle(toElement,[
|
||||
{position: "absolute"},
|
||||
{display: "block"},
|
||||
{transformOrigin: "50% 50%"},
|
||||
{transform: "translateX(0px) translateY(0px) scale(10)"},
|
||||
{transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms ease-in, opacity " + duration + "ms ease-in"},
|
||||
{opacity: "0"},
|
||||
{zIndex: "500"}
|
||||
]);
|
||||
this.currentTiddler = toElement;
|
||||
}
|
||||
// Animate them both
|
||||
// Force layout
|
||||
$tw.utils.forceLayout(this.storyNode);
|
||||
// First, the tiddler we're closing
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transformOrigin: "50% 50%"},
|
||||
{transform: "translateX(0px) translateY(0px) scale(0.1)"},
|
||||
{transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms ease-in, opacity " + duration + "ms ease-in"},
|
||||
{opacity: "0"},
|
||||
{zIndex: "0"}
|
||||
]);
|
||||
setTimeout(function() {
|
||||
// Delete the DOM node when the transition is over
|
||||
if(targetElement.parentNode) {
|
||||
targetElement.parentNode.removeChild(targetElement);
|
||||
}
|
||||
},duration);
|
||||
// Now the tiddler we're going back to
|
||||
if(toElement) {
|
||||
$tw.utils.setStyle(toElement,[
|
||||
{transform: "translateX(0px) translateY(0px) scale(1)"},
|
||||
{opacity: "1"}
|
||||
]);
|
||||
}
|
||||
return true; // Indicate that we'll delete the DOM node
|
||||
};
|
||||
|
||||
ZoominListView.prototype.navigateTo = function(historyInfo) {
|
||||
var listElementIndex = this.listWidget.findListElementByTitle(0,historyInfo.title),
|
||||
duration = $tw.utils.getAnimationDuration();
|
||||
if(listElementIndex === undefined) {
|
||||
return;
|
||||
}
|
||||
var listElementNode = this.listWidget.children[listElementIndex],
|
||||
targetElement = listElementNode.domNode;
|
||||
// Make the new tiddler be position absolute and visible so that we can measure it
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{position: "absolute"},
|
||||
{display: "block"},
|
||||
{transformOrigin: "0 0"},
|
||||
{transform: "translateX(0px) translateY(0px) scale(1)"},
|
||||
{transition: "none"},
|
||||
{opacity: "0.0"}
|
||||
]);
|
||||
// Get the position of the source node, or use the centre of the window as the source position
|
||||
var sourceBounds = historyInfo.fromPageRect || {
|
||||
left: window.innerWidth/2 - 2,
|
||||
top: window.innerHeight/2 - 2,
|
||||
width: window.innerWidth/8,
|
||||
height: window.innerHeight/8
|
||||
};
|
||||
// Try to find the title node in the target tiddler
|
||||
var titleNode = findTitleNode(listElementNode) || listElementNode,
|
||||
zoomBounds = titleNode.domNode.getBoundingClientRect();
|
||||
// Compute the transform for the target tiddler to make the title lie over the source rectange
|
||||
var targetBounds = targetElement.getBoundingClientRect(),
|
||||
scale = sourceBounds.width / zoomBounds.width,
|
||||
x = sourceBounds.left - targetBounds.left - (zoomBounds.left - targetBounds.left) * scale,
|
||||
y = sourceBounds.top - targetBounds.top - (zoomBounds.top - targetBounds.top) * scale;
|
||||
// Transform the target tiddler to its starting position
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transform: "translateX(" + x + "px) translateY(" + y + "px) scale(" + scale + ")"}
|
||||
]);
|
||||
// Force layout
|
||||
$tw.utils.forceLayout(targetElement);
|
||||
// Apply the ending transitions with a timeout to ensure that the previously applied transformations are applied first
|
||||
var self = this,
|
||||
prevCurrentTiddler = this.currentTiddler;
|
||||
this.currentTiddler = targetElement;
|
||||
// Transform the target tiddler to its natural size
|
||||
$tw.utils.setStyle(targetElement,[
|
||||
{transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms ease-in, opacity " + duration + "ms ease-in"},
|
||||
{opacity: "1.0"},
|
||||
{transform: "translateX(0px) translateY(0px) scale(1)"},
|
||||
{zIndex: "500"},
|
||||
]);
|
||||
// Transform the previous tiddler out of the way and then hide it
|
||||
if(prevCurrentTiddler && prevCurrentTiddler !== targetElement) {
|
||||
var scale = zoomBounds.width / sourceBounds.width;
|
||||
x = zoomBounds.left - targetBounds.left - (sourceBounds.left - targetBounds.left) * scale;
|
||||
y = zoomBounds.top - targetBounds.top - (sourceBounds.top - targetBounds.top) * scale;
|
||||
$tw.utils.setStyle(prevCurrentTiddler,[
|
||||
{transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms ease-in, opacity " + duration + "ms ease-in"},
|
||||
{opacity: "0.0"},
|
||||
{transformOrigin: "0 0"},
|
||||
{transform: "translateX(" + x + "px) translateY(" + y + "px) scale(" + scale + ")"},
|
||||
{zIndex: "0"}
|
||||
]);
|
||||
// Hide the tiddler when the transition has finished
|
||||
setTimeout(function() {
|
||||
if(self.currentTiddler !== prevCurrentTiddler) {
|
||||
prevCurrentTiddler.style.display = "none";
|
||||
}
|
||||
},duration);
|
||||
}
|
||||
// Scroll the target into view
|
||||
// $tw.pageScroller.scrollIntoView(targetElement);
|
||||
};
|
||||
|
||||
exports.zoomin = ZoominListView;
|
||||
|
||||
})();
|
@ -1,301 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/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.generate();
|
||||
};
|
||||
|
||||
NavigatorWidget.prototype.generate = function() {
|
||||
// Get our parameters
|
||||
this.storyTitle = this.renderer.getAttribute("story");
|
||||
this.historyTitle = this.renderer.getAttribute("history");
|
||||
// Set the element
|
||||
this.tag = "div";
|
||||
this.attributes = {
|
||||
"class": "tw-navigator"
|
||||
};
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,this.renderer.parseTreeNode.children);
|
||||
this.events = [
|
||||
{name: "tw-navigate", handlerObject: this, handlerMethod: "handleNavigateEvent"},
|
||||
{name: "tw-edit-tiddler", handlerObject: this, handlerMethod: "handleEditTiddlerEvent"},
|
||||
{name: "tw-delete-tiddler", handlerObject: this, handlerMethod: "handleDeleteTiddlerEvent"},
|
||||
{name: "tw-save-tiddler", handlerObject: this, handlerMethod: "handleSaveTiddlerEvent"},
|
||||
{name: "tw-cancel-tiddler", handlerObject: this, handlerMethod: "handleCancelTiddlerEvent"},
|
||||
{name: "tw-close-tiddler", handlerObject: this, handlerMethod: "handleCloseTiddlerEvent"},
|
||||
{name: "tw-close-all-tiddlers", handlerObject: this, handlerMethod: "handleCloseAllTiddlersEvent"},
|
||||
{name: "tw-new-tiddler", 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() {
|
||||
this.storyList = this.renderer.renderTree.wiki.getTiddlerList(this.storyTitle);
|
||||
};
|
||||
|
||||
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,{list: this.storyList}));
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
// Close all tiddlers
|
||||
NavigatorWidget.prototype.handleCloseAllTiddlersEvent = function(event) {
|
||||
this.storyList = [];
|
||||
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 = this.generateDraftTitle(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.renderer.renderTree.wiki.getModificationFields()
|
||||
));
|
||||
}
|
||||
}
|
||||
this.saveStoryList();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
};
|
||||
|
||||
// Delete a tiddler
|
||||
NavigatorWidget.prototype.handleDeleteTiddlerEvent = function(event) {
|
||||
// Get the tiddler title we're deleting
|
||||
var tiddler = this.renderer.renderTree.wiki.getTiddler(event.tiddlerTitle);
|
||||
// Check if the tiddler we're deleting is in draft mode
|
||||
if(tiddler.hasField("draft.title")) {
|
||||
// Delete the original tiddler
|
||||
this.renderer.renderTree.wiki.deleteTiddler(tiddler.fields["draft.of"]);
|
||||
}
|
||||
// Delete this tiddler
|
||||
this.renderer.renderTree.wiki.deleteTiddler(event.tiddlerTitle);
|
||||
// Remove the closed tiddler from the story
|
||||
this.getStoryList();
|
||||
// Look for tiddler 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;
|
||||
};
|
||||
|
||||
/*
|
||||
Generate a title for the draft of a given tiddler
|
||||
*/
|
||||
NavigatorWidget.prototype.generateDraftTitle = function(title) {
|
||||
var c = 0;
|
||||
do {
|
||||
var draftTitle = "Draft " + (c ? (c + 1) + " " : "") + "of '" + title + "'";
|
||||
c++;
|
||||
} while(this.renderer.renderTree.wiki.tiddlerExists(draftTitle));
|
||||
return draftTitle;
|
||||
};
|
||||
|
||||
// Take a tiddler out of edit mode, saving the changes
|
||||
NavigatorWidget.prototype.handleSaveTiddlerEvent = function(event) {
|
||||
this.getStoryList();
|
||||
var storyTiddlerModified = false; // We have to special case saving the story tiddler itself
|
||||
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) {
|
||||
var draftTitle = tiddler.fields["draft.title"],
|
||||
draftOf = tiddler.fields["draft.of"];
|
||||
if(draftTitle) {
|
||||
var isRename = draftOf !== draftTitle,
|
||||
isConfirmed = true;
|
||||
if(isRename && this.renderer.renderTree.wiki.tiddlerExists(draftTitle)) {
|
||||
isConfirmed = confirm("Do you wish to overwrite the tiddler '" + draftTitle + "'?");
|
||||
}
|
||||
if(isConfirmed) {
|
||||
// Save the draft tiddler as the real tiddler
|
||||
this.renderer.renderTree.wiki.addTiddler(new $tw.Tiddler(this.renderer.renderTree.wiki.getCreationFields(),tiddler,{
|
||||
title: draftTitle,
|
||||
"draft.title": undefined,
|
||||
"draft.of": undefined
|
||||
},this.renderer.renderTree.wiki.getModificationFields()));
|
||||
// Remove the draft tiddler
|
||||
this.renderer.renderTree.wiki.deleteTiddler(event.tiddlerTitle);
|
||||
// Remove the original tiddler if we're renaming it
|
||||
if(isRename) {
|
||||
this.renderer.renderTree.wiki.deleteTiddler(draftOf);
|
||||
}
|
||||
// Make the story record point to the newly saved tiddler
|
||||
this.storyList[t] = draftTitle;
|
||||
// Check if we're modifying the story tiddler itself
|
||||
if(draftTitle === this.storyTitle) {
|
||||
storyTiddlerModified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!storyTiddlerModified) {
|
||||
this.saveStoryList();
|
||||
}
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
};
|
||||
|
||||
// Take a tiddler out of edit mode without saving the changes
|
||||
NavigatorWidget.prototype.handleCancelTiddlerEvent = 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.hasField("draft.title")) {
|
||||
// Remove the draft tiddler
|
||||
this.renderer.renderTree.wiki.deleteTiddler(event.tiddlerTitle);
|
||||
// Make the story record point to the original 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(this.renderer.renderTree.wiki.getCreationFields(),{
|
||||
title: title,
|
||||
text: "Newly created tiddler"
|
||||
},this.renderer.renderTree.wiki.getModificationFields());
|
||||
this.renderer.renderTree.wiki.addTiddler(tiddler);
|
||||
// Create the draft tiddler
|
||||
var draftTitle = this.generateDraftTitle(title),
|
||||
draftTiddler = new $tw.Tiddler({
|
||||
text: "Type the text for the new tiddler",
|
||||
title: draftTitle,
|
||||
"draft.title": title,
|
||||
"draft.of": title
|
||||
},this.renderer.renderTree.wiki.getModificationFields());
|
||||
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,history);
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
};
|
||||
|
||||
exports.navigator = NavigatorWidget;
|
||||
|
||||
})();
|
@ -1,45 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/password.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Implements the password widget.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var PasswordWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate child nodes
|
||||
this.generate();
|
||||
};
|
||||
|
||||
PasswordWidget.prototype.generate = function() {
|
||||
// Get the parameters from the attributes
|
||||
this.name = this.renderer.getAttribute("name");
|
||||
// Get the current password
|
||||
var password = $tw.browser ? $tw.utils.getPassword(this.name) : "";
|
||||
// Generate our element
|
||||
this.tag = "input";
|
||||
this.attributes = {
|
||||
type: "password",
|
||||
value: password
|
||||
};
|
||||
this.events = [
|
||||
{name: "keyup", handlerObject: this},
|
||||
{name: "input", handlerObject: this}];
|
||||
};
|
||||
|
||||
PasswordWidget.prototype.handleEvent = function(event) {
|
||||
var password = this.renderer.domNode.value;
|
||||
return $tw.utils.savePassword(this.name,password);
|
||||
};
|
||||
|
||||
exports.password = PasswordWidget;
|
||||
|
||||
})();
|
@ -1,216 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/reveal.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Implements the reveal widget.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var RevealWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate child nodes
|
||||
this.generate();
|
||||
};
|
||||
|
||||
RevealWidget.prototype.generate = function() {
|
||||
// Get the parameters from the attributes
|
||||
this.state = this.renderer.getAttribute("state");
|
||||
this.type = this.renderer.getAttribute("type");
|
||||
this.text = this.renderer.getAttribute("text");
|
||||
this.position = this.renderer.getAttribute("position");
|
||||
this["default"] = this.renderer.getAttribute("default","");
|
||||
this.qualifyTiddlerTitles = this.renderer.getAttribute("qualifyTiddlerTitles");
|
||||
this["class"] = this.renderer.getAttribute("class");
|
||||
this.animate = this.renderer.getAttribute("animate","no");
|
||||
// Compute the title of the state tiddler and read it
|
||||
this.stateTitle = this.state;
|
||||
if(this.qualifyTiddlerTitles) {
|
||||
this.stateTitle = this.stateTitle + "-" + this.renderer.renderTree.getContextScopeId(this.renderer.parentRenderer);
|
||||
}
|
||||
this.readState();
|
||||
// Set up the element attributes
|
||||
var classes = ["tw-reveal"],
|
||||
styles = [];
|
||||
if(this["class"]) {
|
||||
$tw.utils.pushTop(classes,this["class"]);
|
||||
}
|
||||
if(this.isOpen) {
|
||||
$tw.utils.pushTop(classes,"tw-reveal-open");
|
||||
}
|
||||
switch(this.type) {
|
||||
case "popup":
|
||||
styles.push("position:absolute;");
|
||||
classes.push("tw-popup");
|
||||
break;
|
||||
}
|
||||
styles.push("display:" + (this.isOpen ? (this.renderer.parseTreeNode.isBlock ? "block" : "inline") : "none") + ";");
|
||||
// Set the element
|
||||
this.tag = "div";
|
||||
this.attributes = {
|
||||
"class": classes.join(" "),
|
||||
style: styles.join("")
|
||||
};
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,this.isOpen ? this.renderer.parseTreeNode.children : []);
|
||||
this.events = [{name: "click", handlerObject: this, handlerMethod: "handleClickEvent"}];
|
||||
};
|
||||
|
||||
/*
|
||||
Read the state tiddler
|
||||
*/
|
||||
RevealWidget.prototype.readState = function() {
|
||||
// Read the information from the state tiddler
|
||||
if(this.stateTitle) {
|
||||
var state = this.renderer.renderTree.wiki.getTextReference(this.stateTitle,this["default"],this.renderer.tiddlerTitle);
|
||||
switch(this.type) {
|
||||
case "popup":
|
||||
this.readPopupState(state);
|
||||
break;
|
||||
case "match":
|
||||
this.readMatchState(state);
|
||||
break;
|
||||
case "nomatch":
|
||||
this.readMatchState(state);
|
||||
this.isOpen = !this.isOpen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
RevealWidget.prototype.readMatchState = function(state) {
|
||||
this.isOpen = state === this.text;
|
||||
};
|
||||
|
||||
RevealWidget.prototype.readPopupState = function(state) {
|
||||
var popupLocationRegExp = /^\((-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+)\)$/,
|
||||
match = popupLocationRegExp.exec(state);
|
||||
// Check if the state matches the location regexp
|
||||
if(match) {
|
||||
// If so, we're open
|
||||
this.isOpen = true;
|
||||
// Get the location
|
||||
this.popup = {
|
||||
left: parseFloat(match[1]),
|
||||
top: parseFloat(match[2]),
|
||||
width: parseFloat(match[3]),
|
||||
height: parseFloat(match[4])
|
||||
};
|
||||
} else {
|
||||
// If not, we're closed
|
||||
this.isOpen = false;
|
||||
}
|
||||
};
|
||||
|
||||
RevealWidget.prototype.handleClickEvent = function(event) {
|
||||
if(event.type === "click" && this.type === "popup") {
|
||||
// Cancel the popup if we get a click on it
|
||||
if(this.stateTitle) {
|
||||
this.renderer.renderTree.wiki.deleteTextReference(this.stateTitle);
|
||||
}
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
RevealWidget.prototype.refreshInDom = function(changedAttributes,changedTiddlers) {
|
||||
var self = this;
|
||||
// Check if any of our attributes have changed, or if a tiddler we're interested in has changed
|
||||
if(changedAttributes.state || changedAttributes.type || changedAttributes.text || changedAttributes.position || changedAttributes["default"] || changedAttributes.qualifyTiddlerTitles || changedAttributes["class"]) {
|
||||
// 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 {
|
||||
var needChildrenRefresh = true; // Avoid refreshing the children nodes if we don't need to
|
||||
// Get the open state
|
||||
var previousState = this.isOpen
|
||||
this.readState();
|
||||
// Construct the child nodes if required
|
||||
if(this.isOpen && this.children.length === 0) {
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,this.renderer.parseTreeNode.children);
|
||||
var parentNode = this.renderer.domNode;
|
||||
$tw.utils.each(this.children,function(child) {
|
||||
parentNode.appendChild(child.renderInDom());
|
||||
});
|
||||
needChildrenRefresh = false;
|
||||
}
|
||||
// Refresh any child nodes
|
||||
if(needChildrenRefresh) {
|
||||
$tw.utils.each(this.children,function(node) {
|
||||
if(node.refreshInDom) {
|
||||
node.refreshInDom(changedTiddlers);
|
||||
}
|
||||
});
|
||||
}
|
||||
// Animate the opening or closing
|
||||
if(this.isOpen !== previousState) {
|
||||
if(this.animate !== "no") {
|
||||
if(this.isOpen) {
|
||||
this.renderer.domNode.style.display = this.renderer.parseTreeNode.isBlock ? "block" : "inline";
|
||||
$tw.anim.perform("open",this.renderer.domNode);
|
||||
} else {
|
||||
$tw.anim.perform("close",this.renderer.domNode,{callback: function() {
|
||||
self.renderer.domNode.style.display = "none";
|
||||
}});
|
||||
}
|
||||
} else {
|
||||
this.renderer.domNode.style.display = this.isOpen ? (this.renderer.parseTreeNode.isBlock ? "block" : "inline") : "none";
|
||||
}
|
||||
}
|
||||
// Add or remove the tw-reveal-open class
|
||||
$tw.utils.toggleClass(this.renderer.domNode,"tw-reveal-open",this.isOpen);
|
||||
}
|
||||
// Position the content if required
|
||||
if(this.isOpen) {
|
||||
this.postRenderInDom();
|
||||
}
|
||||
};
|
||||
|
||||
RevealWidget.prototype.postRenderInDom = function() {
|
||||
switch(this.type) {
|
||||
case "popup":
|
||||
if(this.isOpen) {
|
||||
this.renderer.domNode.style.position = "absolute";
|
||||
this.renderer.domNode.style.zIndex = "1000";
|
||||
switch(this.position) {
|
||||
case "left":
|
||||
this.renderer.domNode.style.left = (this.popup.left - this.renderer.domNode.offsetWidth) + "px";
|
||||
this.renderer.domNode.style.top = this.popup.top + "px";
|
||||
break;
|
||||
case "above":
|
||||
this.renderer.domNode.style.left = this.popup.left + "px";
|
||||
this.renderer.domNode.style.top = (this.popup.top - this.renderer.domNode.offsetHeight) + "px";
|
||||
break;
|
||||
case "aboveright":
|
||||
this.renderer.domNode.style.left = (this.popup.left + this.popup.width) + "px";
|
||||
this.renderer.domNode.style.top = (this.popup.top + this.popup.height - this.renderer.domNode.offsetHeight) + "px";
|
||||
break;
|
||||
case "right":
|
||||
this.renderer.domNode.style.left = (this.popup.left + this.popup.width) + "px";
|
||||
this.renderer.domNode.style.top = this.popup.top + "px";
|
||||
break;
|
||||
case "belowleft":
|
||||
this.renderer.domNode.style.left = (this.popup.left + this.popup.width - this.renderer.domNode.offsetWidth) + "px";
|
||||
this.renderer.domNode.style.top = (this.popup.top + this.popup.height) + "px";
|
||||
break;
|
||||
default: // Below
|
||||
this.renderer.domNode.style.left = this.popup.left + "px";
|
||||
this.renderer.domNode.style.top = (this.popup.top + this.popup.height) + "px";
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
exports.reveal = RevealWidget;
|
||||
|
||||
})();
|
@ -1,58 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/setstyle.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Implements the setstyle widget.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var SetStyleWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate child nodes
|
||||
this.generate();
|
||||
};
|
||||
|
||||
SetStyleWidget.prototype.generate = function() {
|
||||
// Get the parameters from the attributes
|
||||
this.name = this.renderer.getAttribute("name");
|
||||
this.value = this.renderer.getAttribute("value");
|
||||
this["class"] = this.renderer.getAttribute("class");
|
||||
// Set up the element
|
||||
this.tag = this.renderer.parseTreeNode.isBlock ? "div" : "span";
|
||||
this.attributes = {
|
||||
style: this.name + ":" + this.value
|
||||
};
|
||||
if(this["class"]) {
|
||||
this.attributes["class"] = this["class"];
|
||||
}
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,this.renderer.parseTreeNode.children);
|
||||
};
|
||||
|
||||
SetStyleWidget.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.name || changedAttributes.value || changedAttributes["class"]) {
|
||||
// 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.setstyle = SetStyleWidget;
|
||||
|
||||
})();
|
@ -1,82 +0,0 @@
|
||||
/*\
|
||||
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;
|
||||
|
||||
})();
|
@ -1,105 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/transclude.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
The transclude widget includes another tiddler into the tiddler being rendered.
|
||||
|
||||
Attributes:
|
||||
title: the title of the tiddler to transclude
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var TranscludeWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate child nodes
|
||||
this.generate();
|
||||
};
|
||||
|
||||
TranscludeWidget.prototype.generate = function() {
|
||||
var self = this,
|
||||
templateParseTree;
|
||||
// Get the render target details
|
||||
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 {
|
||||
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 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 : [];
|
||||
}
|
||||
// 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(" "));
|
||||
}
|
||||
// Save the context for this renderer node
|
||||
this.renderer.context = {
|
||||
transcludeTitle: this.transcludeTitle,
|
||||
transcludeField: this.transcludeField,
|
||||
transcludeIndex: this.transcludeIndex
|
||||
};
|
||||
// Set the element
|
||||
this.tag = this.renderer.parseTreeNode.isBlock ? "div" : "span";
|
||||
this.attributes = {};
|
||||
if(classes.length > 0) {
|
||||
this.attributes["class"] = classes.join(" ");
|
||||
}
|
||||
if(this.renderer.hasAttribute("style")) {
|
||||
this.attributes.style = this.renderer.getAttribute("style");
|
||||
}
|
||||
if(this.renderer.hasAttribute("tooltip")) {
|
||||
this.attributes.title = this.renderer.getAttribute("tooltip");
|
||||
}
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,templateParseTree);
|
||||
};
|
||||
|
||||
TranscludeWidget.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.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,
|
||||
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.transclude = TranscludeWidget;
|
||||
|
||||
})();
|
@ -1,34 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/version.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Implements the version widget.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var VersionWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate child nodes
|
||||
this.generate();
|
||||
};
|
||||
|
||||
VersionWidget.prototype.generate = function() {
|
||||
// Set the element
|
||||
this.tag = "span";
|
||||
this.attributes = {};
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,[{
|
||||
type: "text",
|
||||
text: $tw.version
|
||||
}]);
|
||||
};
|
||||
|
||||
exports.version = VersionWidget;
|
||||
|
||||
})();
|
@ -1,70 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/video.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Implements the video widget.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var VideoWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Generate child nodes
|
||||
this.generate();
|
||||
};
|
||||
|
||||
VideoWidget.prototype.generate = function() {
|
||||
// Get attributes
|
||||
this.src = this.renderer.getAttribute("src");
|
||||
this.type = this.renderer.getAttribute("type","vimeo");
|
||||
this.width = parseInt(this.renderer.getAttribute("width","640"),10);
|
||||
this.height = parseInt(this.renderer.getAttribute("height","360"),10);
|
||||
// Return the appropriate element
|
||||
switch(this.type) {
|
||||
case "vimeo":
|
||||
this.tag = "iframe";
|
||||
this.attributes = {
|
||||
src: "http://player.vimeo.com/video/" + this.src + "?autoplay=0",
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
frameborder: 0
|
||||
};
|
||||
break;
|
||||
case "youtube":
|
||||
this.tag = "iframe";
|
||||
this.attributes = {
|
||||
src: "http://www.youtube.com/embed/" + this.src,
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
frameborder: 0
|
||||
};
|
||||
break;
|
||||
case "archiveorg":
|
||||
this.tag = "iframe";
|
||||
this.attributes = {
|
||||
src: "http://www.archive.org/embed/" + this.src,
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
frameborder: 0
|
||||
};
|
||||
break;
|
||||
default:
|
||||
this.tag = "div";
|
||||
this.attributes = {};
|
||||
this.children = this.renderer.renderTree.createRenderers(this.renderer,[{
|
||||
type: "text",
|
||||
text: "Unknown video type"
|
||||
}]);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
exports.video = VideoWidget;
|
||||
|
||||
})();
|
@ -1,120 +0,0 @@
|
||||
/*\
|
||||
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;
|
||||
}
|
||||
// Set the element details
|
||||
this.viewWidget.tag = "span";
|
||||
this.viewWidget.attributes = {};
|
||||
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer.renderContext,[{
|
||||
type: "text",
|
||||
text: value
|
||||
}]);
|
||||
};
|
||||
|
||||
var ViewWidget = function(renderer) {
|
||||
// Save state
|
||||
this.renderer = renderer;
|
||||
// Initialise the field viewers if they've not been done already
|
||||
if(!this.fieldViewers) {
|
||||
ViewWidget.prototype.fieldViewers = {text: TextViewer}; // Start with the built-in text viewer
|
||||
$tw.modules.applyMethods("fieldviewer",this.fieldViewers);
|
||||
}
|
||||
// Generate child nodes
|
||||
this.generate();
|
||||
};
|
||||
|
||||
ViewWidget.prototype.generate = function() {
|
||||
// Get parameters from our attributes
|
||||
this.tiddlerTitle = this.renderer.getAttribute("tiddler",this.renderer.tiddlerTitle);
|
||||
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 = this.fieldViewers.text;
|
||||
if($tw.utils.hop(this.fieldViewers,this.format)) {
|
||||
Viewer = this.fieldViewers[this.format];
|
||||
}
|
||||
this.viewer = new Viewer(this,tiddler,this.fieldName,value);
|
||||
// Ask the viewer to create the widget element
|
||||
this.viewer.render();
|
||||
};
|
||||
|
||||
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])) {
|
||||
// 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
ViewWidget.prototype.postRenderInDom = function() {
|
||||
if(this.viewer && this.viewer.postRenderInDom) {
|
||||
this.viewer.postRenderInDom();
|
||||
}
|
||||
};
|
||||
|
||||
exports.view = ViewWidget;
|
||||
|
||||
})();
|
@ -1,41 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/view/viewers/date.js
|
||||
type: application/javascript
|
||||
module-type: fieldviewer
|
||||
|
||||
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);
|
||||
}
|
||||
// Set the element details
|
||||
this.viewWidget.tag = "span";
|
||||
this.viewWidget.attributes = {
|
||||
"class": "tw-view-date"
|
||||
};
|
||||
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer,[{
|
||||
type: "text",
|
||||
text: value
|
||||
}]);
|
||||
};
|
||||
|
||||
exports.date = DateViewer;
|
||||
|
||||
})();
|
@ -1,44 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/view/viewers/htmlencoded.js
|
||||
type: application/javascript
|
||||
module-type: fieldviewer
|
||||
|
||||
A viewer for viewing tiddler fields as HTML encoded text
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var HtmlEncodedViewer = function(viewWidget,tiddler,field,value) {
|
||||
this.viewWidget = viewWidget;
|
||||
this.tiddler = tiddler;
|
||||
this.field = field;
|
||||
this.value = value;
|
||||
};
|
||||
|
||||
HtmlEncodedViewer.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;
|
||||
}
|
||||
// Set the element details
|
||||
this.viewWidget.tag = "span";
|
||||
this.viewWidget.attributes = {
|
||||
"class": "tw-view-htmlencoded"
|
||||
};
|
||||
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer,[{
|
||||
type: "text",
|
||||
text: $tw.utils.htmlEncode(value)
|
||||
}]);
|
||||
};
|
||||
|
||||
exports.htmlencoded = HtmlEncodedViewer;
|
||||
|
||||
})();
|
@ -1,44 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/view/viewers/htmlwikified.js
|
||||
type: application/javascript
|
||||
module-type: fieldviewer
|
||||
|
||||
A viewer for viewing tiddler fields as a textual HTML representation of the wikified text
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var HtmlWikifiedViewer = function(viewWidget,tiddler,field,value) {
|
||||
this.viewWidget = viewWidget;
|
||||
this.tiddler = tiddler;
|
||||
this.field = field;
|
||||
this.value = value;
|
||||
};
|
||||
|
||||
HtmlWikifiedViewer.prototype.render = function() {
|
||||
// Parse the field text
|
||||
var wiki = this.viewWidget.renderer.renderTree.wiki,
|
||||
parser = wiki.parseText("text/vnd.tiddlywiki",this.value),
|
||||
renderTree = new $tw.WikiRenderTree(parser,{wiki: wiki, parentRenderer: this.viewWidget.renderer, document: this.viewWidget.renderer.renderTree.document});
|
||||
renderTree.execute();
|
||||
var container = this.viewWidget.renderer.renderTree.document.createElement("div");
|
||||
renderTree.renderInDom(container)
|
||||
var text = container.innerHTML;
|
||||
// Set the element details
|
||||
this.viewWidget.tag = "pre";
|
||||
this.viewWidget.attributes = {
|
||||
"class": "tw-view-htmlwikified"
|
||||
};
|
||||
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer,[{
|
||||
type: "text",
|
||||
text: text
|
||||
}]);
|
||||
};
|
||||
|
||||
exports.htmlwikified = HtmlWikifiedViewer;
|
||||
|
||||
})();
|
@ -1,44 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/view/viewers/jsencoded.js
|
||||
type: application/javascript
|
||||
module-type: fieldviewer
|
||||
|
||||
A viewer for viewing tiddler fields as JavaScript stringified text
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var JsEncodedViewer = function(viewWidget,tiddler,field,value) {
|
||||
this.viewWidget = viewWidget;
|
||||
this.tiddler = tiddler;
|
||||
this.field = field;
|
||||
this.value = value;
|
||||
};
|
||||
|
||||
JsEncodedViewer.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;
|
||||
}
|
||||
// Set the element details
|
||||
this.viewWidget.tag = "pre";
|
||||
this.viewWidget.attributes = {
|
||||
"class": "tw-view-jsencoded"
|
||||
};
|
||||
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer,[{
|
||||
type: "text",
|
||||
text: $tw.utils.stringify(value)
|
||||
}]);
|
||||
};
|
||||
|
||||
exports.jsencoded = JsEncodedViewer;
|
||||
|
||||
})();
|
@ -1,44 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/view/viewers/link.js
|
||||
type: application/javascript
|
||||
module-type: fieldviewer
|
||||
|
||||
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 text = this.value === undefined ? "" : this.value;
|
||||
// Indicate that we're not generating an element
|
||||
this.viewWidget.tag = this.viewWidget.renderer.parseTreeNode.isBlock ? "div" : "span";
|
||||
this.viewWidget.attributes = {
|
||||
"class": "tw-view-link"
|
||||
};
|
||||
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer,[{
|
||||
type: "element",
|
||||
tag: "$link",
|
||||
attributes: {
|
||||
to: {type: "string", value: text}
|
||||
},
|
||||
children: [{
|
||||
type: "text",
|
||||
text: text
|
||||
}]
|
||||
}]);
|
||||
};
|
||||
|
||||
exports.link = LinkViewer;
|
||||
|
||||
})();
|
@ -1,77 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/view/viewers/relativedate.js
|
||||
type: application/javascript
|
||||
module-type: fieldviewer
|
||||
|
||||
A viewer for viewing tiddler fields as a relative date
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var RelativeDateViewer = function(viewWidget,tiddler,field,value) {
|
||||
this.viewWidget = viewWidget;
|
||||
this.tiddler = tiddler;
|
||||
this.field = field;
|
||||
this.value = value;
|
||||
};
|
||||
|
||||
RelativeDateViewer.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);
|
||||
}
|
||||
// Set the element details
|
||||
this.viewWidget.tag = "span";
|
||||
this.viewWidget.attributes = {
|
||||
"class": "tw-view-date"
|
||||
};
|
||||
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer,[{
|
||||
type: "text",
|
||||
text: value
|
||||
}]);
|
||||
};
|
||||
|
||||
/*
|
||||
Trigger the timer when the relative date is put into the DOM
|
||||
*/
|
||||
RelativeDateViewer.prototype.postRenderInDom = function() {
|
||||
this.update();
|
||||
};
|
||||
|
||||
/*
|
||||
Trigger the timer for the next update of the relative date
|
||||
*/
|
||||
RelativeDateViewer.prototype.setTimer = function() {
|
||||
var self = this;
|
||||
if(this.relativeDate.updatePeriod < 24 * 60 * 60 * 1000) {
|
||||
window.setTimeout(function() {
|
||||
// Only call the update function if the dom node is still in the document
|
||||
if($tw.utils.domContains(self.viewWidget.renderer.renderTree.document,self.viewWidget.renderer.domNode)) {
|
||||
self.update.call(self);
|
||||
}
|
||||
},this.relativeDate.updatePeriod);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Update the relative date display, and trigger the timer for the next update
|
||||
*/
|
||||
RelativeDateViewer.prototype.update = function() {
|
||||
this.relativeDate = $tw.utils.getRelativeDate((new Date()) - this.value);
|
||||
if(this.relativeDate.delta > 0) {
|
||||
while(this.viewWidget.renderer.domNode.hasChildNodes()) {
|
||||
this.viewWidget.renderer.domNode.removeChild(this.viewWidget.renderer.domNode.firstChild);
|
||||
}
|
||||
this.viewWidget.renderer.domNode.appendChild(this.viewWidget.renderer.renderTree.document.createTextNode(this.relativeDate.description));
|
||||
this.setTimer();
|
||||
}
|
||||
};
|
||||
|
||||
exports.relativedate = RelativeDateViewer;
|
||||
|
||||
})();
|
@ -1,44 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/view/viewers/urlencoded.js
|
||||
type: application/javascript
|
||||
module-type: fieldviewer
|
||||
|
||||
A viewer for viewing tiddler fields as url encoded text
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var UrlEncodedViewer = function(viewWidget,tiddler,field,value) {
|
||||
this.viewWidget = viewWidget;
|
||||
this.tiddler = tiddler;
|
||||
this.field = field;
|
||||
this.value = value;
|
||||
};
|
||||
|
||||
UrlEncodedViewer.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;
|
||||
}
|
||||
// Set the element details
|
||||
this.viewWidget.tag = "span";
|
||||
this.viewWidget.attributes = {
|
||||
"class": "tw-view-urlencoded"
|
||||
};
|
||||
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer,[{
|
||||
type: "text",
|
||||
text: encodeURIComponent(value)
|
||||
}]);
|
||||
};
|
||||
|
||||
exports.urlencoded = UrlEncodedViewer;
|
||||
|
||||
})();
|
@ -1,43 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/view/viewers/wikified.js
|
||||
type: application/javascript
|
||||
module-type: fieldviewer
|
||||
|
||||
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() {
|
||||
// Set the element details
|
||||
this.viewWidget.tag = this.viewWidget.renderer.parseTreeNode.isBlock ? "div" : "span";
|
||||
this.viewWidget.attributes = {};
|
||||
var node = {
|
||||
type: "element",
|
||||
tag: "$transclude",
|
||||
attributes: {
|
||||
"class": "tw-view-wikified",
|
||||
field: {type: "string", value: this.field}
|
||||
},
|
||||
isBlock: this.viewWidget.renderer.parseTreeNode.isBlock
|
||||
};
|
||||
if(this.tiddler && this.tiddler.fields.title) {
|
||||
node.attributes.target = {type: "string", value: this.tiddler.fields.title}
|
||||
}
|
||||
this.viewWidget.children = this.viewWidget.renderer.renderTree.createRenderers(this.viewWidget.renderer,[node]);
|
||||
};
|
||||
|
||||
exports.wikified = WikifiedViewer;
|
||||
|
||||
})();
|
@ -329,13 +329,13 @@ exports.getTiddlerLinks = function(title) {
|
||||
// We'll cache the links so they only get computed if the tiddler changes
|
||||
return this.getCacheForTiddler(title,"links",function() {
|
||||
// Parse the tiddler
|
||||
var parser = self.parseTiddler(title);
|
||||
var parser = self.new_parseTiddler(title);
|
||||
// Count up the links
|
||||
var links = [],
|
||||
checkParseTree = function(parseTree) {
|
||||
for(var t=0; t<parseTree.length; t++) {
|
||||
var parseTreeNode = parseTree[t];
|
||||
if(parseTreeNode.type === "element" && parseTreeNode.tag === "$link" && parseTreeNode.attributes.to && parseTreeNode.attributes.to.type === "string") {
|
||||
if(parseTreeNode.type === "link" && parseTreeNode.attributes.to && parseTreeNode.attributes.to.type === "string") {
|
||||
var value = parseTreeNode.attributes.to.value;
|
||||
if(links.indexOf(value) === -1) {
|
||||
links.push(value);
|
||||
@ -606,7 +606,7 @@ Parse a block of text of a specified MIME type
|
||||
Options include:
|
||||
parseAsInline: if true, the text of the tiddler will be parsed as an inline run
|
||||
*/
|
||||
exports.parseText = function(type,text,options) {
|
||||
exports.old_parseText = function(type,text,options) {
|
||||
options = options || {};
|
||||
// Select a parser
|
||||
var Parser = $tw.Wiki.parsers[type];
|
||||
@ -629,13 +629,13 @@ exports.parseText = function(type,text,options) {
|
||||
/*
|
||||
Parse a tiddler according to its MIME type
|
||||
*/
|
||||
exports.parseTiddler = function(title,options) {
|
||||
exports.old_parseTiddler = function(title,options) {
|
||||
options = options || {};
|
||||
var cacheType = options.parseAsInline ? "newInlineParseTree" : "newBlockParseTree",
|
||||
tiddler = this.getTiddler(title),
|
||||
self = this;
|
||||
return tiddler ? this.getCacheForTiddler(title,cacheType,function() {
|
||||
return self.parseText(tiddler.fields.type,tiddler.fields.text,options);
|
||||
return self.old_parseText(tiddler.fields.type,tiddler.fields.text,options);
|
||||
}) : null;
|
||||
};
|
||||
|
||||
@ -643,6 +643,7 @@ exports.parseTiddler = function(title,options) {
|
||||
var tweakParseTreeNode = function(node) {
|
||||
if(node.type === "element" && node.tag.charAt(0) === "$") {
|
||||
node.type = node.tag.substr(1);
|
||||
delete node.tag;
|
||||
}
|
||||
tweakParseTreeNodes(node.children);
|
||||
};
|
||||
@ -672,7 +673,7 @@ var tweakParser = function(parser) {
|
||||
};
|
||||
|
||||
exports.new_parseText = function(type,text,options) {
|
||||
var parser = this.parseText(type,text,options);
|
||||
var parser = this.old_parseText(type,text,options);
|
||||
if(parser) {
|
||||
tweakParser(parser)
|
||||
};
|
||||
@ -680,7 +681,7 @@ exports.new_parseText = function(type,text,options) {
|
||||
};
|
||||
|
||||
exports.new_parseTiddler = function(title,options) {
|
||||
var parser = this.parseTiddler(title,options);
|
||||
var parser = this.old_parseTiddler(title,options);
|
||||
if(parser) {
|
||||
tweakParser(parser)
|
||||
};
|
||||
@ -706,21 +707,6 @@ exports.new_parseTextReference = function(title,field,index,options) {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Parse text in a specified format and render it into another format
|
||||
outputType: content type for the output
|
||||
textType: content type of the input text
|
||||
text: input text
|
||||
*/
|
||||
exports.renderText = function(outputType,textType,text,context) {
|
||||
var parser = this.parseText(textType,text),
|
||||
renderTree = new $tw.WikiRenderTree(parser,{wiki: this, context: context, document: $tw.document});
|
||||
renderTree.execute();
|
||||
var container = $tw.document.createElement("div");
|
||||
renderTree.renderInDom(container)
|
||||
return outputType === "text/html" ? container.innerHTML : container.textContent;
|
||||
};
|
||||
|
||||
/*
|
||||
Parse text in a specified format and render it into another format
|
||||
outputType: content type for the output
|
||||
@ -740,27 +726,13 @@ exports.new_renderText = function(outputType,textType,text,parentWidget) {
|
||||
return outputType === "text/html" ? container.innerHTML : container.textContent;
|
||||
};
|
||||
|
||||
/*
|
||||
Parse text from a tiddler and render it into another format
|
||||
outputType: content type for the output
|
||||
title: title of the tiddler to be rendered
|
||||
*/
|
||||
exports.renderTiddler = function(outputType,title,context) {
|
||||
var parser = this.parseTiddler(title),
|
||||
renderTree = new $tw.WikiRenderTree(parser,{wiki: this, context: context, document: $tw.document});
|
||||
renderTree.execute();
|
||||
var container = $tw.document.createElement("div");
|
||||
renderTree.renderInDom(container)
|
||||
return outputType === "text/html" ? container.innerHTML : container.textContent;
|
||||
};
|
||||
|
||||
/*
|
||||
Parse text from a tiddler and render it into another format
|
||||
outputType: content type for the output
|
||||
title: title of the tiddler to be rendered
|
||||
*/
|
||||
exports.new_renderTiddler = function(outputType,title,parentWidget) {
|
||||
var parser = $tw.wiki.new_parseTiddler(title),
|
||||
var parser = this.new_parseTiddler(title),
|
||||
parseTreeNode = parser ? {type: "widget", children: parser.tree} : undefined,
|
||||
widgetNode = new widget.widget(parseTreeNode,{
|
||||
wiki: this,
|
||||
@ -821,7 +793,7 @@ exports.saveWiki = function(options) {
|
||||
options = options || {};
|
||||
var template = options.template || "$:/core/templates/tiddlywiki5.template.html",
|
||||
downloadType = options.downloadType || "text/plain";
|
||||
var text = this.renderTiddler(downloadType,template);
|
||||
var text = this.new_renderTiddler(downloadType,template);
|
||||
this.callSaver("save",text,function(err) {
|
||||
$tw.notifier.display("$:/messages/Saved");
|
||||
});
|
||||
|
@ -1,47 +0,0 @@
|
||||
/*\
|
||||
title: test-wikitext.js
|
||||
type: application/javascript
|
||||
tags: [[$:/tags/test-spec]]
|
||||
|
||||
Tests the wikitext rendering pipeline end-to-end. We also need tests that individually test parsers, rendertreenodes etc., but this gets us started.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
describe("WikiText tests", function() {
|
||||
|
||||
// Create a wiki
|
||||
var wiki = new $tw.Wiki();
|
||||
// Add a couple of tiddlers
|
||||
wiki.addTiddler({title: "TiddlerOne", text: "The quick brown fox"});
|
||||
wiki.addTiddler({title: "TiddlerTwo", text: "The rain in Spain\nfalls mainly on the plain"});
|
||||
wiki.addTiddler({title: "TiddlerThree", text: "The speed of sound\n\nThe light of speed"});
|
||||
|
||||
it("should render tiddlers with no special markup render as-is", function() {
|
||||
expect(wiki.renderTiddler("text/plain","TiddlerOne")).toBe("The quick brown fox");
|
||||
});
|
||||
it("should preserve single new lines", function() {
|
||||
expect(wiki.renderTiddler("text/plain","TiddlerTwo")).toBe("The rain in Spain\nfalls mainly on the plain");
|
||||
});
|
||||
it("should use double new lines to create paragraphs", function() {
|
||||
// The paragraphs are lost in the conversion to plain text
|
||||
expect(wiki.renderTiddler("text/plain","TiddlerThree")).toBe("The speed of soundThe light of speed");
|
||||
});
|
||||
|
||||
it("should render plain text tiddlers as a paragraph", function() {
|
||||
expect(wiki.renderTiddler("text/html","TiddlerOne")).toBe("<p>\nThe quick brown fox</p>");
|
||||
});
|
||||
it("should preserve single new lines", function() {
|
||||
expect(wiki.renderTiddler("text/html","TiddlerTwo")).toBe("<p>\nThe rain in Spain\nfalls mainly on the plain</p>");
|
||||
});
|
||||
it("should use double new lines to create paragraphs", function() {
|
||||
expect(wiki.renderTiddler("text/html","TiddlerThree")).toBe("<p>\nThe speed of sound</p><p>\nThe light of speed</p>");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
})();
|
@ -19,7 +19,7 @@ describe("WikiText parser tests", function() {
|
||||
|
||||
// Define a parsing shortcut
|
||||
var parse = function(text) {
|
||||
return wiki.parseText("text/vnd.tiddlywiki",text).tree;
|
||||
return wiki.new_parseText("text/vnd.tiddlywiki",text).tree;
|
||||
};
|
||||
|
||||
it("should parse tags", function() {
|
||||
@ -70,7 +70,7 @@ describe("WikiText parser tests", function() {
|
||||
);
|
||||
expect(parse("<$reveal state='$:/temp/search' type='nomatch' text=''>")).toEqual(
|
||||
|
||||
[ { type : 'element', tag : 'p', children : [ { type : 'element', start : 0, attributes : { state : { start : 8, name : 'state', type : 'string', value : '$:/temp/search', end : 31 }, type : { start : 31, name : 'type', type : 'string', value : 'nomatch', end : 46 }, text : { start : 46, name : 'text', type : 'string', value : '', end : 54 } }, tag : '$reveal', end : 55, children : [ ], isBlock : false } ] } ]
|
||||
[ { type : 'element', tag : 'p', children : [ { type : 'reveal', start : 0, attributes : { state : { start : 8, name : 'state', type : 'string', value : '$:/temp/search', end : 31 }, type : { start : 31, name : 'type', type : 'string', value : 'nomatch', end : 46 }, text : { start : 46, name : 'text', type : 'string', value : '', end : 54 } }, end : 55, isBlock : false, children : [ ] } ] } ]
|
||||
|
||||
);
|
||||
expect(parse("<div attribute={{TiddlerTitle!!field}}>some text</div>")).toEqual(
|
||||
@ -93,7 +93,7 @@ describe("WikiText parser tests", function() {
|
||||
it("should parse macro definitions", function() {
|
||||
expect(parse("\\define myMacro()\nnothing\n\\end\n")).toEqual(
|
||||
|
||||
[ { type : 'macrodef', name : 'myMacro', params : [ ], text : 'nothing' } ]
|
||||
[ { type : 'setvariable', name : 'myMacro', params : [ ], text : 'nothing', attributes : { name : { type : 'string', value : 'myMacro' }, value : { type : 'string', value : 'nothing' } }, children : [ ] } ]
|
||||
|
||||
);
|
||||
|
||||
|
@ -23,30 +23,29 @@ describe("WikiText tests", function() {
|
||||
wiki.addTiddler({title: "TiddlerFour", text: "\\define my-macro(adjective:'groovy')\nThis is my ''amazingly'' $adjective$ macro!\n\\end\n\n<$link to=<<my-macro>>>This is a link</$link>"});
|
||||
|
||||
it("should render tiddlers with no special markup as-is", function() {
|
||||
expect(wiki.renderTiddler("text/plain","TiddlerOne")).toBe("The quick brown fox");
|
||||
expect(wiki.new_renderTiddler("text/plain","TiddlerOne")).toBe("The quick brown fox");
|
||||
});
|
||||
it("should preserve single new lines", function() {
|
||||
expect(wiki.renderTiddler("text/plain","TiddlerTwo")).toBe("The rain in Spain\nfalls mainly on the plain");
|
||||
expect(wiki.new_renderTiddler("text/plain","TiddlerTwo")).toBe("The rain in Spain\nfalls mainly on the plain");
|
||||
});
|
||||
it("should use double new lines to create paragraphs", function() {
|
||||
// The paragraphs are lost in the conversion to plain text
|
||||
expect(wiki.renderTiddler("text/plain","TiddlerThree")).toBe("The speed of soundThe light of speed");
|
||||
expect(wiki.new_renderTiddler("text/plain","TiddlerThree")).toBe("The speed of soundThe light of speed");
|
||||
});
|
||||
|
||||
it("should render plain text tiddlers as a paragraph", function() {
|
||||
expect(wiki.renderTiddler("text/html","TiddlerOne")).toBe("<p>\nThe quick brown fox</p>");
|
||||
expect(wiki.new_renderTiddler("text/html","TiddlerOne")).toBe("<p>\nThe quick brown fox</p>");
|
||||
});
|
||||
it("should preserve single new lines", function() {
|
||||
expect(wiki.renderTiddler("text/html","TiddlerTwo")).toBe("<p>\nThe rain in Spain\nfalls mainly on the plain</p>");
|
||||
expect(wiki.new_renderTiddler("text/html","TiddlerTwo")).toBe("<p>\nThe rain in Spain\nfalls mainly on the plain</p>");
|
||||
});
|
||||
it("should use double new lines to create paragraphs", function() {
|
||||
expect(wiki.renderTiddler("text/html","TiddlerThree")).toBe("<p>\nThe speed of sound</p><p>\nThe light of speed</p>");
|
||||
expect(wiki.new_renderTiddler("text/html","TiddlerThree")).toBe("<p>\nThe speed of sound</p><p>\nThe light of speed</p>");
|
||||
});
|
||||
it("should support attributes specified as macro invocations", function() {
|
||||
expect(wiki.renderTiddler("text/html","TiddlerFour")).toBe("<p>\n<a class='tw-tiddlylink tw-tiddlylink-internal tw-tiddlylink-missing' href='#This%20is%20my%20amazingly%20groovy%20macro!'>\nThis is a link</a></p>");
|
||||
expect(wiki.new_renderTiddler("text/html","TiddlerFour")).toBe("<p>\n<a class=' tw-tiddlylink tw-tiddlylink-missing' href='#This%20is%20my%20amazingly%20groovy%20macro!'>\nThis is a link</a></p>");
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
})();
|
||||
|
@ -1,9 +1,7 @@
|
||||
<h1 class=''>
|
||||
Building classic <span>
|
||||
TiddlyWiki</span> with <span>
|
||||
TiddlyWiki5</span></h1><div class='tw-tiddler'>
|
||||
<div class='tw-transclude'>
|
||||
<p>
|
||||
TiddlyWiki5</span></h1><p>
|
||||
<span>
|
||||
TiddlyWiki5</span> can be used to build older 2.x.x versions of <span>
|
||||
TiddlyWiki</span> from their constituent components. Doing so involves these additional features over and above those used for building <span>
|
||||
@ -34,4 +32,4 @@ node ../../tiddlywiki.js \
|
||||
--verbose \
|
||||
--load <path_to_recipe_file> \
|
||||
--rendertiddler $:/core/templates/tiddlywiki2.template.html <path_to_write_index_file> text/plain \
|
||||
|| exit 1</pre></div></div>
|
||||
|| exit 1</pre>
|
4
ginsu.sh
4
ginsu.sh
@ -9,6 +9,6 @@ node ./tiddlywiki.js \
|
||||
./editions/empty \
|
||||
--verbose \
|
||||
--load $1 \
|
||||
--rendertiddler $:/core/templates/split-recipe tmp/ginsu/split.recipe text/plain \
|
||||
--rendertiddlers [!is[system]] $:/core/templates/tid-tiddler tmp/ginsu text/plain .tid \
|
||||
--new_rendertiddler $:/core/templates/split-recipe tmp/ginsu/split.recipe text/plain \
|
||||
--new_rendertiddlers [!is[system]] $:/core/templates/tid-tiddler tmp/ginsu text/plain .tid \
|
||||
|| exit 1
|
||||
|
2
test.sh
2
test.sh
@ -20,6 +20,6 @@ echo "Using TW5_BUILD_OUTPUT as [$TW5_BUILD_OUTPUT]"
|
||||
node ./tiddlywiki.js \
|
||||
./editions/test \
|
||||
--verbose \
|
||||
--rendertiddler $:/core/templates/tiddlywiki5.template.html $TW5_BUILD_OUTPUT/test.html text/plain \
|
||||
--new_rendertiddler $:/core/templates/tiddlywiki5.template.html $TW5_BUILD_OUTPUT/test.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
|
2
wbld.sh
2
wbld.sh
@ -15,7 +15,7 @@ mkdir -p tmp
|
||||
node ./tiddlywiki.js \
|
||||
editions/tw5tiddlyweb \
|
||||
--verbose \
|
||||
--rendertiddler $:/core/templates/tiddlywiki5.template.html tmp/tiddlyweb.html text/plain \
|
||||
--new_rendertiddler $:/core/templates/tiddlywiki5.template.html tmp/tiddlyweb.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# Prepend the type information that TiddlyWeb needs to turn the .html file into a .tid file
|
||||
|
Loading…
Reference in New Issue
Block a user