Remove the old parser code

Thus introducing a few functional regressions, but it's going to be
easier to fix things up without the old code knocking around and
getting in the way.
This commit is contained in:
Jeremy Ruston
2012-12-28 22:08:32 +00:00
parent d6e531e87c
commit b006cf163f
167 changed files with 138 additions and 120412 deletions
-100
View File
@@ -1,100 +0,0 @@
/*\
title: $:/core/modules/macros/button.js
type: application/javascript
module-type: macro
Button macro
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "button",
params: {
message: {byName: "default", type: "text"},
param: {byName: true, type: "text"},
set: {byName: true, type: "tiddler"},
setTo: {byName: true, type: "text"},
popup: {byName: true, type: "tiddler"},
hover: {byName: true, type: "text"},
qualifyTiddlerTitles: {byName: true, type: "text"},
"class": {byName: true, type: "text"}
}
};
exports.dispatchMessage = function(event) {
var buttonEvent = document.createEvent("Event");
buttonEvent.initEvent("tw-" + this.params.message,true,true);
buttonEvent.param = this.params.param;
buttonEvent.tiddlerTitle = this.tiddlerTitle;
event.target.dispatchEvent(buttonEvent);
};
exports.triggerPopup = function(event) {
$tw.popup.triggerPopup({
textRef: this.params.popup,
domNode: this.child.domNode,
qualifyTiddlerTitles: this.params.qualifyTiddlerTitles,
contextTiddlerTitle: this.tiddlerTitle,
contextParents: this.parents,
wiki: this.wiki
});
};
exports.setTiddler = function() {
var set = this.params.set,
setTo = this.params.setTo,
tiddler = this.wiki.getTiddler(set);
this.wiki.addTiddler(new $tw.Tiddler(tiddler,{title: set, text: setTo}));
};
exports.handleEvent = function(event) {
if(event.type === "click") {
if(this.hasParameter("message")) {
this.dispatchMessage(event);
}
if(this.hasParameter("popup")) {
this.triggerPopup(event);
}
if(this.hasParameter("set") && this.hasParameter("setTo")) {
this.setTiddler();
}
event.preventDefault();
return false;
}
if(event.type === "mouseover" || event.type === "mouseout") {
if(this.hasParameter("popup")) {
this.triggerPopup(event);
}
event.preventDefault();
return false;
}
return true;
};
exports.executeMacro = function() {
var attributes = {"class": []};
if(this.hasParameter("class")) {
$tw.utils.pushTop(attributes["class"],this.params["class"].split(" "));
}
if(this.classes) {
$tw.utils.pushTop(attributes["class"],this.classes);
}
for(var t=0; t<this.content.length; t++) {
this.content[t].execute(this.parents,this.tiddlerTitle);
}
var events = ["click"];
if(this.hasParameter("hover") && this.params.hover === "yes") {
events.push("mouseover","mouseout");
}
return $tw.Tree.Element("button",attributes,this.content,{
events: events,
eventHandler: this
});
};
})();
-106
View File
@@ -1,106 +0,0 @@
/*\
title: $:/core/modules/macros/checkbox.js
type: application/javascript
module-type: macro
Checkbox macro
{{{
<<checkbox tag:done>>
<<checkbox tiddler:HelloThere tag:red>>
<<checkbox tag:done><
<<view title>>
>>
}}}
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "checkbox",
params: {
tiddler: {byName: true, type: "tiddler"},
tag: {byPos: 0, type: "text"},
"class": {byName: true, type: "text"}
}
};
exports.getValue = function() {
var tiddler = this.wiki.getTiddler(this.targetTitle);
return tiddler ? tiddler.hasTag(this.params.tag) : false;
};
exports.executeMacro = function() {
// Get the title of the target tiddler
if(this.hasParameter("tiddler")) {
this.targetTitle = this.params.tiddler;
} else {
this.targetTitle = this.tiddlerTitle;
}
// Checkbox attributes
var checkboxAttributes = {
type: "checkbox"
};
if(this.getValue()) {
checkboxAttributes.checked = "true";
}
// Label attributes
var labelAttributes = {
"class": []
};
if(this.hasParameter("class")) {
$tw.utils.pushTop(labelAttributes["class"],this.params["class"].split(" "));
}
if(this.classes) {
$tw.utils.pushTop(labelAttributes["class"],this.classes);
}
// Execute content
for(var t=0; t<this.content.length; t++) {
this.content[t].execute(this.parents,this.tiddlerTitle);
}
// Create elements
return $tw.Tree.Element("label",labelAttributes,[
$tw.Tree.Element("input",checkboxAttributes,[],{
events: ["change"],
eventHandler: this
}),
$tw.Tree.Element("span",{},this.content)
],{});
return ;
};
exports.handleEvent = function(event) {
if(event.type === "change") {
var checked = this.child.children[0].domNode.checked,
tiddler = this.wiki.getTiddler(this.targetTitle);
if(tiddler && tiddler.hasTag(this.params.tag) !== checked) {
var newTags = tiddler.fields.tags.slice(0),
pos = newTags.indexOf(this.params.tag);
if(pos !== -1) {
newTags.splice(pos,1);
}
if(checked) {
newTags.push(this.params.tag);
}
this.wiki.addTiddler(new $tw.Tiddler(tiddler,{tags: newTags}));
}
}
};
exports.refreshInDom = function(changes) {
// Only change the checkbox if the tiddler has changed
if(this.dependencies.hasChanged(changes,this.targetTitle)) {
this.child.children[0].domNode.checked = this.getValue();
}
// Refresh any children
this.child.refreshInDom(changes);
};
})();
-40
View File
@@ -1,40 +0,0 @@
/*\
title: $:/core/modules/macros/color.js
type: application/javascript
module-type: macro
Color macro.
Applies the specified colour to its content. By default, the colour value is obtained from the `color` field of the current tiddler
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "color",
params: {
"default": {byName: "default", type: "text"}
}
};
exports.executeMacro = function() {
var tiddler = this.wiki.getTiddler(this.tiddlerTitle),
attributes = {
style: {
"background-color": (tiddler && tiddler.fields.color) || this.params["default"]
}
};
if(this.classes) {
attributes["class"] = this.classes.slice(0);
}
for(var t=0; t<this.content.length; t++) {
this.content[t].execute(this.parents,this.tiddlerTitle);
}
return $tw.Tree.Element("span",attributes,this.content);
};
})();
-25
View File
@@ -1,25 +0,0 @@
/*\
title: $:/core/modules/macros/comment.js
type: application/javascript
module-type: macro
Comment macro, a no-op
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "!",
params: {}
};
exports.executeMacro = function() {
return null;
};
})();
-27
View File
@@ -1,27 +0,0 @@
/*\
title: $:/core/modules/macros/echo.js
type: application/javascript
module-type: macro
Echo macro
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "echo",
params: {
text: {byPos: 0, type: "text"}
}
};
exports.executeMacro = function() {
return $tw.Tree.Text(this.params.text);
};
})();
-84
View File
@@ -1,84 +0,0 @@
/*\
title: $:/core/modules/macros/edit/edit.js
type: application/javascript
module-type: macro
Edit macro for editting fields and tiddlers
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "edit",
params: {
tiddler: {byName: true, type: "tiddler"},
field: {byPos: 0, type: "text"},
type: {byName: true, type: "text"},
"default": {byName: true, type: "text"},
requireFocus: {byName: true, type: "text"}
}
};
exports.evaluateDependencies = function() {
var dependencies = new $tw.Dependencies();
if(!this.srcParams.tiddler) {
dependencies.dependentOnContextTiddler = true;
}
for(var m in this.info.params) {
var paramInfo = this.info.params[m];
if(m in this.srcParams && paramInfo.type === "tiddler") {
if(typeof this.srcParams[m] === "function") {
dependencies.dependentAll = true;
} else {
dependencies.addDependency(this.srcParams[m],!paramInfo.skinny);
}
}
}
return dependencies;
};
exports.executeMacro = function() {
// Get the tiddler being editted
this.editField = this.hasParameter("field") ? this.params.field : "text";
this.editTiddler = this.hasParameter("tiddler") ? this.params.tiddler : this.tiddlerTitle;
var tiddler = this.wiki.getTiddler(this.editTiddler),
Editor;
// Figure out which editor to use
// TODO: Tiddler field modules should be able to specify a field type from which the editor is derived
if(this.editField === "text" && tiddler && tiddler.fields.type) {
Editor = this.wiki.macros.edit.editors[tiddler.fields.type];
}
if(!Editor) {
Editor = this.wiki.macros.edit.editors["text/vnd.tiddlywiki"];
}
this.editor = new Editor(this);
// Call the editor to generate the child nodes
var child = this.editor.getChild();
child.execute(this.parents,this.tiddlerTitle);
return child;
};
exports.postRenderInDom = function() {
if(this.editor.postRenderInDom) {
this.editor.postRenderInDom();
}
};
exports.refreshInDom = function(changes) {
var t;
// Only refresh if a dependency is triggered
if(this.dependencies.hasChanged(changes,this.tiddlerTitle)) {
if(this.editor.refreshInDom) {
this.editor.refreshInDom();
}
} else {
// Refresh any children
this.child.refreshInDom(changes);
}
};
})();
@@ -1,164 +0,0 @@
/*\
title: $:/core/modules/macros/edit/editors/bitmapeditor.js
type: application/javascript
module-type: editor
An editor module for editting bitmaps
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
function BitmapEditor(macroNode) {
this.macroNode = macroNode;
}
BitmapEditor.prototype.getChild = function() {
return $tw.Tree.Element("canvas",{
"class": ["tw-edit-field"]
},[],{
events: ["touchstart","touchmove","touchend","mousedown","mousemove","mouseup"],
eventHandler: this
});
};
BitmapEditor.prototype.postRenderInDom = function() {
var tiddler = this.macroNode.wiki.getTiddler(this.macroNode.editTiddler),
canvas = this.macroNode.child.domNode,
currImage = new Image();
///////////////////// // Set the macro node itself to be position: relative
///////////////////// this.macroNode.domNode.style.position = "relative";
// Get the current bitmap into an image object
currImage.src = "data:" + tiddler.fields.type + ";base64," + tiddler.fields.text;
// Copy it to the on-screen canvas
canvas.width = currImage.width;
canvas.height = currImage.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(currImage,0,0);
// And also copy the current bitmap to the off-screen canvas
this.currCanvas = document.createElement("canvas");
this.currCanvas.width = currImage.width;
this.currCanvas.height = currImage.height;
ctx = this.currCanvas.getContext("2d");
ctx.drawImage(currImage,0,0);
};
BitmapEditor.prototype.handleEvent = function(event) {
switch(event.type) {
case "touchstart":
this.brushDown = true;
this.strokeStart(event.touches[0].clientX,event.touches[0].clientY);
event.preventDefault();
event.stopPropagation();
return false;
case "touchmove":
if(this.brushDown) {
this.strokeMove(event.touches[0].clientX,event.touches[0].clientY);
}
event.preventDefault();
event.stopPropagation();
return false;
case "touchend":
if(this.brushDown) {
this.brushDown = false;
this.strokeEnd();
}
event.preventDefault();
event.stopPropagation();
return false;
case "mousedown":
this.strokeStart(event.clientX,event.clientY);
this.brushDown = true;
event.preventDefault();
event.stopPropagation();
return false;
case "mousemove":
if(this.brushDown) {
this.strokeMove(event.clientX,event.clientY);
event.preventDefault();
event.stopPropagation();
return false;
}
return true;
case "mouseup":
if(this.brushDown) {
this.brushDown = false;
this.strokeEnd();
event.preventDefault();
event.stopPropagation();
return false;
}
return true;
}
return true;
};
BitmapEditor.prototype.adjustCoordinates = function(x,y) {
var canvas = this.macroNode.child.domNode,
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.macroNode.child.domNode,
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.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.macroNode.child.domNode,
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.macroNode.wiki.getTiddler(this.macroNode.editTiddler);
if(tiddler) {
// data URIs look like "data:<type>;base64,<text>"
var dataURL = this.macroNode.child.domNode.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.macroNode.wiki.addTiddler(new $tw.Tiddler(tiddler,update));
}
};
exports["image/jpg"] = BitmapEditor;
exports["image/jpeg"] = BitmapEditor;
exports["image/png"] = BitmapEditor;
exports["image/gif"] = BitmapEditor;
})();
@@ -1,151 +0,0 @@
/*\
title: $:/core/modules/macros/edit/editors/texteditor.js
type: application/javascript
module-type: editor
An editor module for editting text
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var MIN_TEXT_AREA_HEIGHT = 100;
function TextEditor(macroNode) {
this.macroNode = macroNode;
}
/*
Get the tiddler being editted, field name and current value
*/
TextEditor.prototype.getEditText = function() {
// Get the current tiddler and the field name
var tiddler = this.macroNode.wiki.getTiddler(this.macroNode.editTiddler),
value;
// If we've got a tiddler, the value to display is the field string value
if(tiddler) {
value = tiddler.getFieldString(this.macroNode.editField);
} else {
// Otherwise, we need to construct a default value for the editor
if(this.macroNode.hasParameter("default")) {
value = this.macroNode.params["default"];
} else {
switch(this.macroNode.editField) {
case "text":
value = "Type the text for the tiddler '" + this.macroNode.editTiddler + "'";
break;
case "title":
value = this.macroNode.editTiddler;
break;
default:
value = "";
break;
}
}
}
return {tiddler: tiddler, field: this.macroNode.editField, value: value};
};
TextEditor.prototype.getChild = function() {
var edit = this.getEditText();
var attributes = {
"class": ["tw-edit-field"]
},
tagName,
content = [];
if(this.macroNode.classes) {
$tw.utils.pushTop(attributes["class"],this.macroNode.classes);
}
// Figure out what element to use for this editor
var type = this.macroNode.params.type;
if(type === undefined) {
type = edit.field === "text" ? "textarea" : "input";
}
switch(type) {
case "textarea":
tagName = "textarea";
content.push($tw.Tree.Text(edit.value));
break;
case "search":
tagName = "input";
attributes.type = "search";
attributes.value = edit.value;
break;
default: // "input"
tagName = "input";
attributes.type = "text";
attributes.value = edit.value;
break;
}
// Wrap the editor control in a div
return $tw.Tree.Element(this.macroNode.isBlock ? "div" : "span",{},[$tw.Tree.Element(tagName,attributes,content,{
events: ["focus","blur","keyup"],
eventHandler: this
})]);
};
TextEditor.prototype.handleEvent = function(event) {
// Get the value of the field if it might have changed
if("keyup focus blur".split(" ").indexOf(event.type) !== -1) {
this.saveChanges();
}
// Fix the height of the textarea if required
if("keyup focus".split(" ").indexOf(event.type) !== -1) {
var self = this;
window.setTimeout(function() {
self.fixHeight();
},5);
}
return true;
};
TextEditor.prototype.saveChanges = function() {
var text = this.macroNode.child.children[0].domNode.value,
tiddler = this.macroNode.wiki.getTiddler(this.macroNode.editTiddler);
// if(this.macroNode.params.requireFocus === "yes" && document.activeElement !== this.macroNode.child.children[0].domNode) {
// text = this.macroNode.params["default"] || "";
// }
if(!tiddler) {
tiddler = new $tw.Tiddler({title: this.macroNode.editTiddler});
}
if(text !== tiddler.fields[this.macroNode.editField]) {
var update = {};
update[this.macroNode.editField] = text;
this.macroNode.wiki.addTiddler(new $tw.Tiddler(tiddler,update));
}
};
TextEditor.prototype.fixHeight = function() {
if(this.macroNode.child && this.macroNode.child.children[0] && this.macroNode.child.children[0].type === "textarea") {
var wrapper = this.macroNode.child.domNode,
textarea = this.macroNode.child.children[0].domNode;
// Set the text area height to 1px temporarily, which allows us to read the true scrollHeight
var prevWrapperHeight = wrapper.style.height;
wrapper.style.height = textarea.style.height + "px";
textarea.style.overflow = "hidden";
textarea.style.height = "1px";
textarea.style.height = Math.max(textarea.scrollHeight,MIN_TEXT_AREA_HEIGHT) + "px";
wrapper.style.height = prevWrapperHeight;
}
};
TextEditor.prototype.postRenderInDom = function() {
this.fixHeight();
};
TextEditor.prototype.refreshInDom = function() {
if(document.activeElement !== this.macroNode.child.children[0].domNode) {
var edit = this.getEditText();
this.macroNode.child.children[0].domNode.value = edit.value;
}
// Fix the height if needed
this.fixHeight();
};
exports["text/vnd.tiddlywiki"] = TextEditor;
exports["text/plain"] = TextEditor;
})();
-66
View File
@@ -1,66 +0,0 @@
/*\
title: $:/core/modules/macros/fields.js
type: application/javascript
module-type: macro
Fields macro
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "fields",
dependentOnContextTiddler: true,
params: {
}
};
exports.executeMacro = function() {
// Create the table
var attributes = {
"class": ["tw-fields-table"]
};
if(this.classes) {
$tw.utils.pushTop(attributes["class"],this.classes);
}
var rows = [
$tw.Tree.Element("tr",{},[
$tw.Tree.Element("th",{},[$tw.Tree.Text("Field")]),
$tw.Tree.Element("th",{},[$tw.Tree.Text("Value")])
])
];
// Get the value to display
var tiddler = this.wiki.getTiddler(this.tiddlerTitle);
if(tiddler) {
var fields = [];
for(var f in tiddler.fields) {
fields.push(f);
}
fields.sort();
for(f=0; f<fields.length; f++) {
var value;
if(fields[f] === "text") {
value = $tw.Tree.Element("em",{},[
$tw.Tree.Text("(length: " + tiddler.fields.text.length + ")")
]);
} else {
value = $tw.Tree.Text(tiddler.getFieldString(fields[f]));
}
rows.push($tw.Tree.Element("tr",{},[
$tw.Tree.Element("td",{},[$tw.Tree.Text(fields[f])]),
$tw.Tree.Element("td",{},[value])
]));
}
}
var child = $tw.Tree.Element("table",attributes,[
$tw.Tree.Element("tbody",{},rows)
]);
child.execute(this.parents,this.tiddlerTitle);
return child;
};
})();
-55
View File
@@ -1,55 +0,0 @@
/*\
title: $:/core/modules/macros/image.js
type: application/javascript
module-type: macro
Image macro for displaying images
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "image",
params: {
src: {byName: "default", type: "tiddler"},
text: {byName: true, type: "text"},
alignment: {byName: true, type: "text"},
width: {byName: true, type: "text"},
height: {byName: true, type: "text"}
}
};
exports.executeMacro = function() {
if(this.wiki.tiddlerExists(this.params.src)) {
var imageTree = this.wiki.parseTiddler(this.params.src).tree,
cloneImage = imageTree[0].clone();
if(this.hasParameter("width")) {
cloneImage.attributes.width = this.params.width;
}
if(this.hasParameter("height")) {
cloneImage.attributes.height = this.params.height;
}
if(this.params.text) {
return $tw.Tree.Element("div",{
alt: this.params.text,
title: this.params.text
},[cloneImage]);
} else {
return cloneImage;
}
} else {
return $tw.Tree.Element("img",{
src: this.params.src,
alt: this.params.text,
width: this.params.width,
height: this.params.height,
title: this.params.text
});
}
};
})();
-117
View File
@@ -1,117 +0,0 @@
/*\
title: $:/core/modules/macros/link.js
type: application/javascript
module-type: macro
Implements the link macro.
\*/
(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);
};
exports.info = {
name: "link",
params: {
to: {byName: "default", type: "tiddler", skinny: true},
throughField: {byname: true, type: "text"},
space: {byName: true, type: "text"},
qualifyHoverTitle: {byName: true, type: "text"},
hover: {byName: true, type: "tiddler"}
}
};
exports.handleEvent = function (event) {
if(event.type === "click") {
if(isLinkExternal(this.linkInfo.to)) {
event.target.setAttribute("target","_blank");
return true;
} else {
var navEvent = document.createEvent("Event");
navEvent.initEvent("tw-navigate",true,true);
navEvent.navigateTo = this.linkInfo.to;
navEvent.navigateFromNode = this;
navEvent.navigateFromClientRect = this.child.domNode.getBoundingClientRect();
event.target.dispatchEvent(navEvent);
event.preventDefault();
return false;
}
}
if(event.type === "mouseover" || event.type === "mouseout") {
if(this.hasParameter("hover")) {
$tw.popup.triggerPopup({
textRef: this.params.hover,
domNode: this.child.domNode,
qualifyTiddlerTitles: this.params.qualifyHoverTitle,
contextTiddlerTitle: this.tiddlerTitle,
contextParents: this.parents,
wiki: this.wiki
});
}
event.preventDefault();
return false;
}
};
exports.executeMacro = function() {
// Assemble the information about the link
this.linkInfo = {
space: this.params.space
};
if(this.hasParameter("to")) {
this.linkInfo.to = this.params.to;
} else if(this.hasParameter("throughField") && this.tiddlerTitle) {
var currTiddler = this.wiki.getTiddler(this.tiddlerTitle);
if(currTiddler && this.params.throughField in currTiddler.fields) {
this.linkInfo.to = currTiddler.fields[this.params.throughField];
}
}
// Generate the default link characteristics
this.linkInfo.isExternal = isLinkExternal(this.linkInfo.to);
if(!this.linkInfo.isExternal) {
this.linkInfo.isMissing = !this.wiki.tiddlerExists(this.linkInfo.to);
}
this.linkInfo.attributes = {
href: this.linkInfo.to
};
if(!this.linkInfo.isExternal) {
this.linkInfo.attributes.href = encodeURIComponent(this.linkInfo.to);
}
// Generate the default classes for the link
this.linkInfo.attributes["class"] = ["tw-tiddlylink"];
if(this.linkInfo.isExternal) {
this.linkInfo.attributes["class"].push("tw-tiddlylink-external");
} else {
this.linkInfo.attributes["class"].push("tw-tiddlylink-internal");
if(this.linkInfo.isMissing) {
this.linkInfo.attributes["class"].push("tw-tiddlylink-missing");
} else {
this.linkInfo.attributes["class"].push("tw-tiddlylink-resolves");
}
}
if(this.classes) {
$tw.utils.pushTop(this.linkInfo.attributes["class"],this.classes);
}
// Create the link
var events = ["click"];
if(this.hasParameter("hover")) {
events.push("mouseover","mouseout");
}
var child;
if(this.linkInfo.suppressLink) {
child = $tw.Tree.Element("span",{},this.content);
} else {
child = $tw.Tree.Element("a",this.linkInfo.attributes,this.content,{events: events, eventHandler: this});
}
child.execute(this.parents,this.tiddlerTitle);
return child;
};
})();
-317
View File
@@ -1,317 +0,0 @@
/*\
title: $:/core/modules/macros/list.js
type: application/javascript
module-type: macro
List macro
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "list",
dependentAll: true, // Tiddlers containing <<list>> macro are dependent on every tiddler
params: {
type: {byPos: 0, type: "text"},
filter: {byName: true, type: "filter"},
history: {byName: true, type: "tiddler"},
template: {byName: true, type: "tiddler"},
editTemplate: {byName: true, type: "tiddler"},
emptyMessage: {byName: true, type: "text"},
listviewTiddler: {byName: true, type: "tiddler"},
listview: {byName: true, type: "text"},
itemClass: {byName: true, type: "text"},
map: {byName: true, type: "tiddler"},
block: {ByName: true, type: "text"} // HACK: To be removed...
}
};
/*
These types are shorthands for particular filters
*/
var typeMappings = {
all: "[!is[shadow]sort[title]]",
recent: "[!is[shadow]sort[modified]]",
missing: "[is[missing]sort[title]]",
orphans: "[is[orphan]sort[title]]",
shadowed: "[is[shadow]sort[title]]"
};
exports.executeMacro = function() {
this.useBlock = this.isBlock;
if(this.hasParameter("block")) {
this.useBlock = this.params.block === "yes";
}
// Get the list of tiddlers object
this.getTiddlerList();
// Create the list frame element
var attributes = {"class": ["tw-list-frame"]};
if(this.classes) {
$tw.utils.pushTop(attributes["class"],this.classes);
}
this.listFrame = $tw.Tree.Element(this.useBlock ? "div" : "span",attributes,[]);
// Create the list
if(this.list.length === 0) {
// Check for an empty list
this.listFrame.children = [this.getEmptyMessage()];
} else {
// Create the list
for(var t=0; t<this.list.length; t++) {
this.listFrame.children.push(this.createListElement(this.list[t]));
}
}
return this.listFrame;
};
exports.postRenderInDom = function() {
this.listview = this.chooseListView();
this.history = [];
};
/*
Select the appropriate list viewer
*/
exports.chooseListView = function() {
// Instantiate the list view
var listviewName;
if(this.hasParameter("listviewTiddler")) {
listviewName = this.wiki.getTextReference(this.params.listviewTiddler);
}
if(!listviewName && this.hasParameter("listview")) {
listviewName = this.params.listview;
}
var ListView = this.wiki.macros.list.listviews[listviewName];
return ListView ? new ListView(this) : null;
};
exports.getTiddlerList = function() {
var filter;
if(this.hasParameter("type")) {
filter = typeMappings[this.params.type];
} else if(this.hasParameter("filter")) {
filter = this.params.filter;
}
if(!filter) {
filter = "[!is[shadow]]";
}
this.list = this.wiki.filterTiddlers(filter,this.tiddlerTitle);
};
/*
Create and execute the nodes representing the empty message
*/
exports.getEmptyMessage = function() {
var nodes = this.wiki.parseText("text/vnd.tiddlywiki",this.params.emptyMessage).tree;
for(var c=0; c<nodes.length; c++) {
nodes[c].execute(this.parents,this.tiddlerTitle);
}
return $tw.Tree.Element("span",{},nodes);
};
/*
Create a list element representing a given tiddler
*/
exports.createListElement = function(title) {
var node = this.createListElementMacro(title),
attributes = {"class": ["tw-list-element"]},
eventHandler = {handleEvent: function(event) {
// Add context information to the event
event.navigateFromTitle = title;
return true;
}};
node.execute(this.parents,this.tiddlerTitle);
// Add any specified classes
if(this.hasParameter("itemClass")) {
attributes["class"].push(this.params.itemClass);
}
var listElement = $tw.Tree.Element(this.useBlock ? "div" : "span",attributes,[node],{
events: ["tw-navigate","tw-EditTiddler","tw-SaveTiddler","tw-CloseTiddler","tw-NewTiddler"],
eventHandler: eventHandler
});
// Save our data inside the list element node
listElement.listElementInfo = {title: title};
return listElement;
};
/*
Create the tiddler macro needed to represent a given tiddler
*/
exports.createListElementMacro = function(title) {
// Check if the tiddler is a draft
var tiddler = this.wiki.getTiddler(title),
isDraft = tiddler ? tiddler.hasField("draft.of") : false;
// Figure out the template to use
var template = this.params.template,
templateTree = undefined;
if(isDraft && this.hasParameter("editTemplate")) {
template = this.params.editTemplate;
}
// Check for not having a template
if(!template) {
if(this.content.length > 0) {
// Use our content as the template
templateTree = [];
for(var t=0; t<this.content.length; t++) {
templateTree.push(this.content[t].clone());
}
} else {
// Use default content
var defaultTemplate = "<<view title link>>";
templateTree = this.wiki.parseText("text/vnd.tiddlywiki",defaultTemplate).tree;
}
}
// Create the tiddler macro
return $tw.Tree.Macro("tiddler",{
srcParams: {
target: title,
template: template
},
wiki: this.wiki,
content: templateTree
});
};
/*
Remove a list element from the list, along with the attendant DOM nodes
*/
exports.removeListElement = function(index) {
// Get the list element
var listElement = this.listFrame.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.listFrame.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
*/
exports.findListElementByTitle = function(startIndex,title) {
while(startIndex < this.listFrame.children.length) {
var listElementInfo = this.listFrame.children[startIndex].listElementInfo;
if(listElementInfo && listElementInfo.title === title) {
return startIndex;
}
startIndex++;
}
return undefined;
};
/*
Selectively update the list in response to changes in tiddlers
*/
exports.refreshInDom = function(changes) {
// If any of our parameters have changed we'll have to completely re-execute the macro
var paramNames = ["template","editTemplate"];
for(var t=0; t<paramNames.length; t++) {
if(this.hasParameter(paramNames[t]) && $tw.utils.hop(changes,this.params[paramNames[t]])) {
this.reexecuteInDom();
return;
}
}
// Reflect any changes in the list
this.handleListChanges(changes);
// Process any history list changes
if(this.hasParameter("history") && $tw.utils.hop(changes,this.params.history)) {
this.handleHistoryChanges();
}
};
/*
Handle changes to the content of the list
*/
exports.handleListChanges = function(changes) {
// Get the list of tiddlers, saving the previous length
var t,
prevListLength = this.list.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
this.listFrame.refreshInDom(changes);
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.listFrame.children = [this.getEmptyMessage()];
this.listFrame.children[0].renderInDom(this.listFrame.domNode,this.listFrame.domNode.childNodes[0]);
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.listFrame.children.splice(t,0,this.createListElement(this.list[t]));
this.listFrame.children[t].renderInDom(this.listFrame.domNode,this.listFrame.domNode.childNodes[t]);
if(this.listview && this.listview.insert) {
this.listview.insert(t);
}
} else {
// Delete any list elements preceding the one we want
if(index > t) {
for(var n=index-1; n>=t; n--) {
this.removeListElement(n);
}
}
// Refresh the node we're reusing
this.listFrame.children[t].refreshInDom(changes);
}
}
// Remove any left over elements
if(this.listFrame.children.length > this.list.length) {
for(t=this.listFrame.children.length-1; t>=this.list.length; t--) {
this.removeListElement(t);
}
}
};
/*
Handle any changes to the history list
*/
exports.handleHistoryChanges = function() {
// Get the history data
var newHistory = this.wiki.getTiddlerData(this.params.history,[]);
// 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;
};
})();
@@ -1,135 +0,0 @@
/*\
title: $:/core/modules/macros/list/listviews/cecily.js
type: application/javascript
module-type: listview
Views the list through a 2D map
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
function CecilyListView(listMacro) {
// The list macro we're attached to
this.listMacro = listMacro;
// Prepare the list frame
var listFrame = this.listMacro.listFrame,
listFrameDomNode = listFrame.domNode;
// Position the initial list entries on the map
this.loadMap();
for(var t=0; t<listFrame.children.length; t++) {
if(listFrame.children[t].listElementInfo) {
var domNode = listFrame.children[t].domNode,
title = listFrame.children[t].listElementInfo.title;
domNode.style.position = "absolute";
this.positionTiddler(title,domNode);
}
}
}
CecilyListView.prototype.getMapTiddlerTitle = function() {
return this.listMacro.params.map || "$:/TiddlerMap";
};
CecilyListView.prototype.loadMap = function() {
this.map = this.listMacro.wiki.getTiddlerData(this.getMapTiddlerTitle(),{
positions: {},
newTiddlerPosition: {x: 0, y: 0}
});
};
CecilyListView.prototype.saveMap = function() {
this.listMacro.wiki.setTiddlerData(this.getMapTiddlerTitle(),this.map);
};
// Get the position of a particular tiddler
CecilyListView.prototype.lookupTiddlerInMap = function(title,domNode) {
// First try looking it up in the map
if(this.map.positions[title]) {
return this.map.positions[title];
}
// If the tiddler wasn't in the map we'll have to compute it
var newPosition;
switch(this.map.positionNew) {
default: // "right"
newPosition = {
x: this.map.newTiddlerPosition.x,
y: this.map.newTiddlerPosition.y,
w: 100,
h: 100
};
this.map.newTiddlerPosition.x += newPosition.w * 1.2;
break;
}
// A default position
newPosition = newPosition || {x: 0,y: 0,w: 100,h: 100};
// Save the position back to the map
this.map.positions[title] = newPosition;
this.saveMap();
return newPosition;
};
CecilyListView.prototype.positionTiddler = function(title,domNode) {
var pos = this.lookupTiddlerInMap(title,domNode),
scale = pos.w/domNode.offsetWidth;
domNode.setAttribute("data-tw-zoom",JSON.stringify(pos));
$tw.utils.setStyle(domNode,[
{transformOrigin: "0% 0%"},
{transform: "translateX(" + pos.x + "px) translateY(" + pos.y + "px) scale(" + scale + ")"}
]);
};
CecilyListView.prototype.navigateTo = function(historyInfo) {
var listElementIndex = this.listMacro.findListElementByTitle(0,historyInfo.title),
listElementNode = this.listMacro.listFrame.children[listElementIndex],
targetElement = listElementNode.domNode;
// Scroll the node into view
var scrollEvent = document.createEvent("Event");
scrollEvent.initEvent("tw-scroll",true,true);
targetElement.dispatchEvent(scrollEvent);
};
CecilyListView.prototype.insert = function(index) {
var listElementNode = this.listMacro.listFrame.children[index],
targetElement = listElementNode.domNode;
targetElement.style.position = "absolute";
$tw.utils.setStyle(targetElement,[
{transition: ""},
{opacity: "0.0"}
]);
this.positionTiddler(listElementNode.listElementInfo.title,targetElement);
$tw.utils.forceLayout(targetElement);
$tw.utils.setStyle(targetElement,[
{transition: "opacity " + $tw.config.preferences.animationDurationMs + " ease-out"},
{opacity: "1.0"}
]);
};
CecilyListView.prototype.remove = function(index) {
var listElementNode = this.listMacro.listFrame.children[index],
targetElement = listElementNode.domNode;
// Attach an event handler for the end of the transition
targetElement.addEventListener($tw.utils.convertEventName("transitionEnd"),function(event) {
if(targetElement.parentNode) {
targetElement.parentNode.removeChild(targetElement);
}
},false);
// Animate the closure
$tw.utils.setStyle(targetElement,[
{transition: "opacity " + $tw.config.preferences.animationDurationMs + " ease-out"},
{opacity: "1.0"}
]);
$tw.utils.forceLayout(targetElement);
$tw.utils.setStyle(targetElement,[
{opacity: "0.0"}
]);
// Returning true causes the DOM node not to be deleted
return true;
};
exports.cecily = CecilyListView;
})();
@@ -1,95 +0,0 @@
/*\
title: $:/core/modules/macros/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";
function ClassicListView(listMacro) {
this.listMacro = listMacro;
var listFrame = this.listMacro.listFrame,
listFrameDomNode = listFrame.domNode;
}
ClassicListView.prototype.navigateTo = function(historyInfo) {
var listElementIndex = this.listMacro.findListElementByTitle(0,historyInfo.title),
listElementNode = this.listMacro.listFrame.children[listElementIndex],
targetElement = listElementNode.domNode;
// Scroll the node into view
var scrollEvent = document.createEvent("Event");
scrollEvent.initEvent("tw-scroll",true,true);
targetElement.dispatchEvent(scrollEvent);
};
ClassicListView.prototype.insert = function(index) {
var listElementNode = this.listMacro.listFrame.children[index],
targetElement = listElementNode.domNode;
// Get the current height of the tiddler
var currHeight = targetElement.offsetHeight + parseInt(window.getComputedStyle(targetElement).marginTop,10);
// Reset the margin once the transition is over
targetElement.addEventListener($tw.utils.convertEventName("transitionEnd"),function(event) {
$tw.utils.setStyle(targetElement,[
{transition: "none"},
{transform: "none"},
{marginBottom: "auto"}
]);
},false);
// 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 " + $tw.config.preferences.animationDurationMs + " ease-in-out, " +
"margin-bottom " + $tw.config.preferences.animationDurationMs + " ease-in-out"},
{transform: "rotateX(0deg)"},
{marginBottom: "0px"},
{opacity: "1.0"}
]);
};
ClassicListView.prototype.remove = function(index) {
var listElementNode = this.listMacro.listFrame.children[index],
targetElement = listElementNode.domNode;
// Get the current height of the tiddler
var currWidth = targetElement.offsetWidth,
currHeight = targetElement.offsetHeight + parseInt(window.getComputedStyle(targetElement).marginTop,10);
// Attach an event handler for the end of the transition
targetElement.addEventListener($tw.utils.convertEventName("transitionEnd"),function(event) {
if(targetElement.parentNode) {
targetElement.parentNode.removeChild(targetElement);
}
},false);
// Animate the closure
$tw.utils.setStyle(targetElement,[
{transition: "none"},
{transform: "translateX(0px)"},
{marginBottom: "0px"},
{opacity: "1.0"}
]);
$tw.utils.forceLayout(targetElement);
$tw.utils.setStyle(targetElement,[
{transition: $tw.utils.roundTripPropertyName("transform") + " " + $tw.config.preferences.animationDurationMs + " ease-in-out, " +
"opacity " + $tw.config.preferences.animationDurationMs + " ease-in-out, " +
"margin-bottom " + $tw.config.preferences.animationDurationMs + " 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,96 +0,0 @@
/*\
title: $:/core/modules/macros/list/listviews/sideways.js
type: application/javascript
module-type: listview
Views the list as a sideways linear sequence
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
function SidewaysListView(listMacro) {
this.listMacro = listMacro;
// Prepare the list frame
var listFrame = this.listMacro.listFrame,
listFrameDomNode = listFrame.domNode;
// Prepare any list elements
for(var t=0; t<this.listMacro.list.length; t++) {
var index = this.listMacro.findListElementByTitle(0,this.listMacro.list[t]);
if(index !== undefined) {
var listElement = listFrame.children[index];
$tw.utils.setStyle(listElement.domNode,[
{verticalAlign: "top"},
{display: "inline-block"}
]);
}
}
}
SidewaysListView.prototype.navigateTo = function(historyInfo) {
var listElementIndex = this.listMacro.findListElementByTitle(0,historyInfo.title),
listElementNode = this.listMacro.listFrame.children[listElementIndex],
targetElement = listElementNode.domNode;
// Scroll the node into view
var scrollEvent = document.createEvent("Event");
scrollEvent.initEvent("tw-scroll",true,true);
targetElement.dispatchEvent(scrollEvent);
};
SidewaysListView.prototype.insert = function(index) {
var listElementNode = this.listMacro.listFrame.children[index],
targetElement = listElementNode.domNode;
// Set up the initial position of the element
$tw.utils.setStyle(targetElement,[
{verticalAlign: "top"},
{display: "inline-block"},
{transition: "none"},
{opacity: "0.0"}
]);
var currWidth = targetElement.offsetWidth + parseInt(window.getComputedStyle(targetElement).marginLeft,10);
$tw.utils.setStyle(targetElement,[
{marginRight: (-currWidth) + "px"}
]);
$tw.utils.forceLayout(targetElement);
// Transition to the final position
$tw.utils.setStyle(targetElement,[
{transition: "opacity " + $tw.config.preferences.animationDurationMs + " ease-out, " +
"margin-right " + $tw.config.preferences.animationDurationMs + " ease-in-out"},
{opacity: "1.0"},
{marginRight: ""}
]);
};
SidewaysListView.prototype.remove = function(index) {
var listElementNode = this.listMacro.listFrame.children[index],
targetElement = listElementNode.domNode,
currWidth = targetElement.offsetWidth + parseInt(window.getComputedStyle(targetElement).marginLeft,10);
// Attach an event handler for the end of the transition
targetElement.addEventListener($tw.utils.convertEventName("transitionEnd"),function(event) {
if(targetElement.parentNode) {
targetElement.parentNode.removeChild(targetElement);
}
},false);
// Animate the closure
$tw.utils.setStyle(targetElement,[
{transition: ""},
{opacity: "1.0"},
{marginRight: "0px"}
]);
$tw.utils.forceLayout(targetElement);
$tw.utils.setStyle(targetElement,[
{transition: "opacity " + $tw.config.preferences.animationDurationMs + " ease-out, " +
"margin-right " + $tw.config.preferences.animationDurationMs + " ease-in-out"},
{opacity: "0.0"},
{marginRight: (-currWidth) + "px"}
]);
// Returning true causes the DOM node not to be deleted
return true;
};
exports.sideways = SidewaysListView;
})();
-223
View File
@@ -1,223 +0,0 @@
/*\
title: $:/core/modules/macros/navigator.js
type: application/javascript
module-type: macro
Traps navigation events to update a story tiddler and history tiddler. Can also optionally capture navigation target in a specified text reference.
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "navigator",
params: {
story: {byName: "default", type: "text"}, // Actually a tiddler, but we don't want it to be a dependency
history: {byName: "default", type: "text"}, // Actually a tiddler, but we don't want it to be a dependency
set: {byName: true, type: "tiddler"}
}
};
exports.getList = function(title) {
var text = this.wiki.getTextReference(title,"");
if(text && text.length > 0) {
return text.split("\n");
} else {
return [];
}
};
exports.saveList = function(title,list) {
var storyTiddler = this.wiki.getTiddler(title);
this.wiki.addTiddler(new $tw.Tiddler({
title: title
},storyTiddler,{text: list.join("\n")}));
};
exports.findTitleInStory = function(title,defaultIndex) {
for(var t=0; t<this.story.length; t++) {
if(this.story[t] === title) {
return t;
}
}
return defaultIndex;
};
exports.handleEvent = function(event) {
if(this.eventMap[event.type]) {
this.eventMap[event.type].call(this,event);
}
};
exports.eventMap = {};
// Navigate to a specified tiddler
exports.eventMap["tw-navigate"] = function(event) {
if(this.hasParameter("story")) {
// Update the story tiddler if specified
this.story = this.getList(this.storyTitle);
// 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.story.splice(slot,0,event.navigateTo);
// Save the story
this.saveList(this.storyTitle,this.story);
}
}
// Set the tiddler if specified
if(this.hasParameter("set")) {
this.wiki.setTextReference(this.params.set,event.navigateTo);
}
// Add a new record to the top of the history stack
if(this.hasParameter("history")) {
this.history = this.wiki.getTiddlerData(this.historyTitle,[]);
this.history.push({title: event.navigateTo, fromPageRect: event.navigateFromClientRect});
this.wiki.setTiddlerData(this.historyTitle,this.history);
}
event.stopPropagation();
return false;
};
// Close a specified tiddler
exports.eventMap["tw-close"] = function(event) {
this.story = this.getList(this.storyTitle);
// Look for tiddlers with this title to close
var slot = this.findTitleInStory(event.tiddlerTitle,-1);
if(slot !== -1) {
this.story.splice(slot,1);
this.saveList(this.storyTitle,this.story);
}
event.stopPropagation();
return false;
};
// Place a tiddler in edit mode
exports.eventMap["tw-EditTiddler"] = function(event) {
this.story = this.getList(this.storyTitle);
// Replace the specified tiddler with a draft in edit mode
for(var t=0; t<this.story.length; t++) {
if(this.story[t] === event.tiddlerTitle) {
// Compute the title for the draft
var draftTitle = "Draft " + (new Date()) + " of " + event.tiddlerTitle;
this.story[t] = draftTitle;
// Get the current value of the tiddler we're editing
var tiddler = this.wiki.getTiddler(event.tiddlerTitle);
// Save the initial value of the draft tiddler
this.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.saveList(this.storyTitle,this.story);
event.stopPropagation();
return false;
};
// Take a tiddler out of edit mode, saving the changes
exports.eventMap["tw-SaveTiddler"] = function(event) {
this.story = this.getList(this.storyTitle);
var storyTiddlerModified = false;
for(var t=0; t<this.story.length; t++) {
if(this.story[t] === event.tiddlerTitle) {
var tiddler = this.wiki.getTiddler(event.tiddlerTitle);
if(tiddler && $tw.utils.hop(tiddler.fields,"draft.title")) {
// Save the draft tiddler as the real tiddler
this.wiki.addTiddler(new $tw.Tiddler(tiddler,{
title: tiddler.fields["draft.title"],
modified: new Date(),
"draft.title": undefined,
"draft.of": undefined
}));
// Remove the draft tiddler
this.wiki.deleteTiddler(event.tiddlerTitle);
// Remove the original tiddler if we're renaming it
if(tiddler.fields["draft.of"] !== tiddler.fields["draft.title"]) {
this.wiki.deleteTiddler(tiddler.fields["draft.of"]);
}
// Make the story record point to the newly saved tiddler
this.story[t] = tiddler.fields["draft.title"];
// Check if we're modifying the story tiddler itself
if(tiddler.fields["draft.title"] === this.params.story) {
storyTiddlerModified = true;
}
}
}
}
if(!storyTiddlerModified) {
this.saveList(this.storyTitle,this.story);
}
event.stopPropagation();
return false;
};
// Create a new draft tiddler
exports.eventMap["tw-NewTiddler"] = function(event) {
// Get the story details
this.story = this.getList(this.storyTitle);
// Create the new tiddler
var title;
for(var t=0; true; t++) {
title = "New Tiddler" + (t ? " " + t : "");
if(!this.wiki.tiddlerExists(title)) {
break;
}
}
var tiddler = new $tw.Tiddler({
title: title,
text: "Newly created tiddler"
});
this.wiki.addTiddler(tiddler);
// Create the draft tiddler
var draftTitle = "New Tiddler at " + (new Date()),
draftTiddler = new $tw.Tiddler({
text: "Type the text for the new tiddler",
title: draftTitle,
"draft.title": title,
"draft.of": title
});
this.wiki.addTiddler(draftTiddler);
// Update the story to insert the new draft at the top
var slot = this.findTitleInStory(event.navigateFromTitle,-1) + 1;
this.story.splice(slot,0,draftTitle);
// Save the updated story
this.saveList(this.storyTitle,this.story);
// Add a new record to the top of the history stack
this.history = this.wiki.getTiddlerData(this.historyTitle,[]);
this.history.push({title: draftTitle});
this.wiki.setTiddlerData(this.historyTitle,this.history);
event.stopPropagation();
return false;
};
exports.executeMacro = function() {
// Compute the titles of the story and history list tiddlers
this.storyTitle = this.params.story || "$:/StoryList";
this.historyTitle = this.params.history || "$:/HistoryList";
var attributes = {};
if(this.classes) {
attributes["class"] = this.classes.slice(0);
}
for(var t=0; t<this.content.length; t++) {
this.content[t].execute(this.parents,this.tiddlerTitle);
}
return $tw.Tree.Element("div",attributes,this.content,{
events: ["tw-navigate","tw-EditTiddler","tw-SaveTiddler","tw-close","tw-NavigateBack","tw-NewTiddler"],
eventHandler: this
});
};
})();
-42
View File
@@ -1,42 +0,0 @@
/*\
title: $:/core/modules/macros/password.js
type: application/javascript
module-type: macro
Allows a password to be set
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "password",
params: {
name: {byName: "default", type: "text"}
}
};
exports.executeMacro = function() {
var password = $tw.browser ? $tw.utils.getPassword(this.params.name) : "";
var attributes = {
type: "password",
value: password
};
if(this.classes) {
attributes["class"] = this.classes.slice(0);
}
return $tw.Tree.Element("input",attributes,[],{
events: ["keyup","input"],
eventHandler: this
});
};
exports.handleEvent = function(event) {
var password = this.child.domNode.value;
return $tw.utils.savePassword(this.params.name,password);
};
})();
-195
View File
@@ -1,195 +0,0 @@
/*\
title: $:/core/modules/macros/reveal.js
type: application/javascript
module-type: macro
The reveal macro shows or hides content according to the value of the text in a specified tiddler.
The parameters are:
* ''state'' - text reference where the hide/reveal state is stored
* ''type'' - type of the hide/reveal state:
** //popup// - a popup - the state tiddler should contain the page coordinates of the button that triggered the popup
** //match// - reveals if the state tiddler matches the match text
** //nomatch// - reveals if the state tiddler does not match the match text
* ''position'' - popup position: //left//, //above//, //aboveright//, //right//, //below// or //belowleft//
* ''text'' - match text
* ''qualifyTiddlerTitles'' - if present, causes the title of the state tiddler to be qualified with the current tiddler stack
* ''default'' - default hide/reveal state: `open` if visible, otherwise hidden
* ''class'' - CSS class(es) to be assigned to the revealed element
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "reveal",
params: {
state: {byPos: 0, type: "tiddler"},
type: {byName: true, type: "text"},
text: {byName: true, type: "text"},
position: {byName: true, type: "text"},
qualifyTiddlerTitles: {byName: true, type: "text"},
"default": {byName: true, type: "text"},
"class": {byName: true, type: "text"}
}
};
exports.readState = function() {
// Start with the default value for being open or closed
if(this.hasParameter("default")) {
this.isOpen = this.params["default"] === "open";
}
// Read the information from the state tiddler
if(this.stateTextRef) {
var state = this.wiki.getTextReference(this.stateTextRef,"",this.tiddlerTitle);
switch(this.params.type) {
case "popup":
this.readPopupState(state);
break;
case "match":
this.readMatchState(state);
break;
case "nomatch":
this.readMatchState(state);
this.isOpen = !this.isOpen;
break;
}
}
};
exports.readMatchState = function(state) {
this.isOpen = state === this.params.text;
};
exports.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;
}
};
exports.handleEvent = function(event) {
if(event.type === "click" && this.params.type === "popup") {
// Cancel the popup if we get a click on it
if(this.stateTextRef) {
this.wiki.deleteTextReference(this.stateTextRef);
}
event.preventDefault();
return false;
}
return true;
};
exports.executeMacro = function() {
this.stateTextRef = this.params.state;
if(this.hasParameter("qualifyTiddlerTitles")) {
this.stateTextRef = this.stateTextRef + "(" + this.parents.join(",") + "," + this.tiddlerTitle + ")";
}
this.readState();
var attributes = {
"class": ["tw-reveal"],
style: {}
};
if(this.hasParameter("class")) {
attributes["class"].push(this.params["class"]);
}
if(this.classes) {
$tw.utils.pushTop(attributes["class"],this.classes);
}
switch(this.params.type) {
case "popup":
attributes.style.position = "absolute";
attributes["class"].push("tw-popup");
break;
}
attributes.style = {display: this.isOpen ? (this.isBlock ? "block" : "inline") : "none"};
var child = $tw.Tree.Element(this.isBlock ? "div" : "span",attributes,this.isOpen ? this.content : [],{
events: ["click"],
eventHandler: this
});
child.execute(this.parents,this.tiddlerTitle);
return child;
};
exports.postRenderInDom = function() {
switch(this.params.type) {
case "popup":
if(this.isOpen) {
this.child.domNode.style.position = "absolute";
this.child.domNode.style.zIndex = "1000";
switch(this.params.position) {
case "left":
this.child.domNode.style.left = (this.popup.left - this.child.domNode.offsetWidth) + "px";
this.child.domNode.style.top = this.popup.top + "px";
break;
case "above":
this.child.domNode.style.left = this.popup.left + "px";
this.child.domNode.style.top = (this.popup.top - this.child.domNode.offsetHeight) + "px";
break;
case "aboveright":
this.child.domNode.style.left = (this.popup.left + this.popup.width) + "px";
this.child.domNode.style.top = (this.popup.top + this.popup.height - this.child.domNode.offsetHeight) + "px";
break;
case "right":
this.child.domNode.style.left = (this.popup.left + this.popup.width) + "px";
this.child.domNode.style.top = this.popup.top + "px";
break;
case "belowleft":
this.child.domNode.style.left = (this.popup.left + this.popup.width - this.child.domNode.offsetWidth) + "px";
this.child.domNode.style.top = (this.popup.top + this.popup.height) + "px";
break;
default: // Below
this.child.domNode.style.left = this.popup.left + "px";
this.child.domNode.style.top = (this.popup.top + this.popup.height) + "px";
break;
}
}
break;
}
};
exports.refreshInDom = function(changes) {
var needChildrenRefresh = true, // Avoid refreshing the children nodes if we don't need to
t;
// Re-read the open state
this.readState();
// Render the children if we're open and we don't have any children yet
if(this.isOpen && this.child.children.length === 0) {
// Install the children and execute them
this.child.children = this.content;
for(t=0; t<this.child.children.length; t++) {
this.child.children[t].execute(this.parents,this.tiddlerTitle);
this.child.children[t].renderInDom(this.child.domNode);
}
needChildrenRefresh = false; // Don't refresh the children if we've just created them
}
// Refresh the children
if(needChildrenRefresh) {
for(t=0; t<this.child.children.length; t++) {
this.child.children[t].refreshInDom(changes);
}
}
// Set the visibility of the children
this.child.domNode.style.display = this.isOpen ? (this.isBlock ? "block" : "inline") : "none";
// Position the content if required
this.postRenderInDom();
};
})();
-114
View File
@@ -1,114 +0,0 @@
/*\
title: $:/core/modules/macros/scrollable.js
type: application/javascript
module-type: macro
Creates a scrollable frame around its content
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "scrollable",
params: {
width: {byName: true, type: "text"},
height: {byName: true, type: "text"},
"class": {byName: true, type: "text"}
}
};
exports.executeMacro = function() {
var innerClasses = ["tw-scrollable-inner"],
innerAttributes = {
"class": innerClasses,
style: {
overflow: "visible",
position: "relative"
}
},
outerClasses = ["tw-scrollable","tw-scrollable-outer"],
outerAttributes = {
"class": outerClasses,
style: {
overflow: "auto",
"-webkit-overflow-scrolling": "touch",
"white-space": "nowrap"
}
};
if(this.hasParameter("class")) {
outerClasses.push(this.params["class"]);
}
if(this.classes) {
$tw.utils.pushTop(outerClasses,this.classes);
}
if(this.hasParameter("width")) {
outerAttributes.style.width = this.params.width;
}
if(this.hasParameter("height")) {
outerAttributes.style.height = this.params.height;
}
this.innerFrame = $tw.Tree.Element("div",innerAttributes,this.content);
this.outerFrame = $tw.Tree.Element("div",outerAttributes,[this.innerFrame],{
events: ["tw-scroll"],
eventHandler: this
});
this.outerFrame.execute(this.parents,this.tiddlerTitle);
return this.outerFrame;
};
exports.handleEvent = function(event) {
if(event.type === "tw-scroll") {
return this.handleScrollEvent(event);
}
return true;
}
exports.handleScrollEvent = function(event) {
var domNode = event.target,
bounds = {
left: domNode.offsetLeft,
top: domNode.offsetTop,
width: domNode.offsetWidth,
height: domNode.offsetHeight
};
// Walk up the tree adjusting the offset bounds by each offsetParent
while(domNode.offsetParent && domNode.offsetParent !== this.innerFrame.domNode) {
domNode = domNode.offsetParent;
bounds.left += domNode.offsetLeft;
bounds.top += domNode.offsetTop;
}
this.cancelScroll();
this.startTime = new Date();
this.startX = this.child.domNode.scrollLeft;
this.startY = this.child.domNode.scrollTop;
this.endX = bounds.left;
this.endY = bounds.top;
if((this.endX < this.startX) || (this.endX > (this.startX + this.child.domNode.offsetWidth)) || (this.endY < this.startY) || (this.endY > (this.startY + this.child.domNode.offsetHeight))) {
var self = this;
this.scrollTimerId = window.setInterval(function() {
var t = ((new Date()) - self.startTime) / $tw.config.preferences.animationDuration;
if(t >= 1) {
self.cancelScroll();
t = 1;
}
t = $tw.utils.slowInSlowOut(t);
self.child.domNode.scrollLeft = self.startX + (self.endX - self.startX) * t;
self.child.domNode.scrollTop = self.startY + (self.endY - self.startY) * t;
}, 10);
}
event.stopPropagation();
return false;
};
exports.cancelScroll = function() {
if(this.scrollTimerId) {
window.clearInterval(this.scrollTimerId);
this.scrollTimerId = null;
}
};
})();
-54
View File
@@ -1,54 +0,0 @@
/*\
title: $:/core/modules/macros/serialize.js
type: application/javascript
module-type: macro
Serialize macro
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "serialize",
params: {
filter: {byPos: 0, type: "filter"},
as: {byPos: 1, type: "text"},
removePrefix: {byName: true, type: "text"}
}
};
exports.executeMacro = function() {
var as = this.params.as || "text/plain",
t;
if(this.hasParameter("filter")) {
var titles = this.wiki.filterTiddlers(this.params.filter),
tiddlers = [],
result = [];
if(this.hasParameter("removePrefix")) {
for(t=0; t<titles.length; t++) {
var originalTiddler = this.wiki.getTiddler(titles[t]),
title = titles[t];
if(title.indexOf(this.params.removePrefix) === 0) {
title = title.substr(this.params.removePrefix.length);
tiddlers.push(new $tw.Tiddler(originalTiddler,{title: title}));
}
}
} else {
for(t=0; t<titles.length; t++) {
tiddlers.push(this.wiki.getTiddler(titles[t]));
}
}
result.push(this.wiki.serializeTiddlers(tiddlers,as));
return $tw.Tree.Element("pre",{},[
$tw.Tree.Text(result.join("\n"))
]);
}
return null;
};
})();
-177
View File
@@ -1,177 +0,0 @@
/*\
title: $:/core/modules/macros/slider.js
type: application/javascript
module-type: macro
!Introduction
The slider macro is used to selectively reveal a chunk of text. By default, it renders as a button that may be clicked or touched to reveal the enclosed text.
The enclosed text can be a string of WikiText or be taken from a target tiddler.
The current state of the slider can be stored as the string "open" or "closed" in a specified tiddler. If the value of that tiddler changes then the slider is automatically updated. If no state tiddler is specified then the state of the slider isn't retained, but the slider still works as expected.
!!Parameters
|`state` //(defaults to 1st parameter)// |The title of the tiddler to contain the current state of the slider |
|`default` |The initial state of the slider, either `open` or `closed` |
|`class` |A CSS class to be applied to the slider root element |
|`content` |The WikiText to be enclosed in the slider. Overrides the `target` parameter, if present |
|`target` //(defaults to 2nd parameter)// |The title of the tiddler that contains the enclosed text. Ignored if the `content` parameter is specified |
|`label` //(defaults to 3rd parameter)// |The plain text to be displayed as the label for the slider button |
|`tooltip` //(defaults to 4th parameter)// |The plain text tooltip to be displayed when the mouse hovers over the slider button |
!!Markup
The markup generated by the slider macro is:
{{{
<span class="tw-slider {user defined class}">
<a class="btn-info">{slider label}</a>
<div class="tw-slider-body" style="display:{state}">{slider content}</div>
</span>
}}}
!!Examples
A minimal slider:
{{{
<<slider target:MyTiddler>>
}}}
!!Notes
The slider is a good study example of a simple interactive macro.
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "slider",
params: {
state: {byPos: 0, type: "tiddler"},
target: {byPos: 1, type: "tiddler"},
label: {byPos: 2, type: "text"},
tooltip: {byPos: 3, type: "text"},
"default": {byName: true, type: "text"},
"class": {byName: true, type: "text"}
}
};
exports.getOpenState = function() {
if(this.hasParameter("state")) {
var stateTiddler = this.wiki.getTiddler(this.params.state);
if(stateTiddler) {
return stateTiddler.fields.text.trim() === "open";
}
}
if(this.hasParameter("default")) {
return this.params["default"] === "open";
}
return false;
};
exports.saveOpenState = function() {
if(this.hasParameter("state")) {
var stateTiddler = this.wiki.getTiddler(this.params.state) || {title: this.params.state, text: ""};
this.wiki.addTiddler(new $tw.Tiddler(stateTiddler,{text: this.isOpen ? "open" : "closed"}));
return true;
}
return false;
};
exports.getSliderChildren = function() {
// Use the target tiddler if specified
if(this.hasParameter("target")) {
return [$tw.Tree.Macro("tiddler",{
srcParams: {target: this.params.target},
wiki: this.wiki
})];
} else {
// Otherwise use the content of the macro
return this.content;
}
};
exports.handleEvent = function(event) {
if(event.type === "click") {
if(event.target === this.child.domNode.firstChild) {
this.isOpen = !this.isOpen;
if(!this.saveOpenState()) {
this.refreshInDom({});
}
event.preventDefault();
return false;
} else {
return true;
}
}
return true;
};
exports.executeMacro = function() {
this.isOpen = this.getOpenState();
var sliderChildren = [];
if(this.isOpen) {
sliderChildren = this.getSliderChildren();
}
var attributes = {
"class": ["tw-slider"]
};
if(this.hasParameter("class")) {
attributes["class"].push(this.params["class"]);
}
if(this.classes) {
$tw.utils.pushTop(attributes["class"],this.classes);
}
if(this.hasParameter("state")) {
attributes["data-tw-slider-type"] = this.params.state;
}
if(this.hasParameter("tooltip")) {
attributes.alt = this.params.tooltip;
attributes.title = this.params.tooltip;
}
var child = $tw.Tree.Element("span",
attributes,
[
$tw.Tree.Element("a",
{
"class": ["btn","btn-info"]
},[
$tw.Tree.Text(this.params.label ? this.params.label : this.params.target)
]
),
$tw.Tree.Element("div",
{
"class": ["tw-slider-body"],
"style": {"display": this.isOpen ? "block" : "none"}
},
sliderChildren
)
],{
events: ["click"],
eventHandler: this
}
);
child.execute(this.parents,this.tiddlerTitle);
return child;
};
exports.refreshInDom = function(changes) {
var needChildrenRefresh = true; // Avoid refreshing the children nodes if we don't need to
// If the state tiddler has changed then reset the open state
if(this.hasParameter("state") && $tw.utils.hop(changes,this.params.state)) {
this.isOpen = this.getOpenState();
}
// Render the children if the slider is open and we don't have any children yet
if(this.isOpen && this.child.children[1].children.length === 0) {
// Remove the existing dom node for the body
this.child.domNode.removeChild(this.child.children[1].domNode);
// Get the slider children and execute it
this.child.children[1].children = this.getSliderChildren();
this.child.children[1].execute(this.parents,this.tiddlerTitle);
this.child.children[1].renderInDom(this.child.domNode,null);
needChildrenRefresh = false; // Don't refresh the children if we've just created them
}
// Set the visibility of the slider children
this.child.children[1].domNode.style.display = this.isOpen ? "block" : "none";
// Refresh any children
if(needChildrenRefresh) {
this.child.refreshInDom(changes);
}
};
})();
-160
View File
@@ -1,160 +0,0 @@
/*\
title: $:/core/modules/macros/tiddler.js
type: application/javascript
module-type: macro
The tiddler macros transcludes another macro into the tiddler being rendered.
Parameters:
target: the title of the tiddler to transclude
template: the title of the tiddler to use as a template for the transcluded tiddler
with: optional parameters to be substituted into the rendered tiddler
The simplest case is to just supply a target tiddler:
{{{
<<tiddler Foo>> or <<transclude target:Foo>>
}}}
This will render the tiddler Foo within the current tiddler. If the tiddler Foo includes
the view macro (or other macros that reference the fields of the current tiddler), then the
fields of the tiddler Foo will be accessed.
If you want to transclude the tiddler as a template, so that the fields referenced by the view
macro are those of the tiddler doing the transcluding, then you can instead specify the tiddler
as a template:
{{{
<<tiddler template:Foo>>
}}}
The effect is the same as the previous example: the text of the tiddler Foo is rendered. The
difference is that the view macro will access the fields of the tiddler doing the transcluding.
The `target` and `template` parameters may be combined:
{{{
<<tiddler target:Foo template:Bar>>
}}}
Here, the text of the tiddler `Bar` will be transcluded, with the macros within it accessing the fields
of the tiddler `Foo`.
Finally, the `with` parameter is used to substitute values for the special markers $1, $2, $3 etc. The
substitutions are performed on the tiddler whose text is being rendered: either the tiddler named in
the `template` parameter or, if that parameter is missing, the tiddler named in the `target` parameter.
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "tiddler",
cascadeParams: true, // Cascade names of named parameters to following anonymous parameters
params: {
target: {byName: "default", type: "tiddler"},
targetVia: {byName: true, type: "tiddler"},
template: {byName: true, type: "tiddler"},
"with": {byName: true, type: "text", dependentAll: true}
}
};
exports.evaluateDependencies = function() {
var dependencies = new $tw.Dependencies(),
template = this.srcParams.template;
if(template === undefined) {
template = this.srcParams.target;
}
if(typeof template === "function") {
dependencies.dependentAll = true;
} else {
dependencies.addDependency(template,true);
}
var targetVia = this.srcParams.targetVia;
if(typeof targetVia === "function") {
dependencies.dependentAll = true;
} else {
dependencies.addDependency(targetVia,true);
}
return dependencies;
};
exports.executeMacro = function() {
var renderTitle, renderTemplateTitle, renderTemplateTree,
children, parseTree,
t,
parents = this.parents.slice(0),
parseOptions = {};
// If there's no render title specified then use the current tiddler title
if(this.hasParameter("target")) {
renderTitle = this.params.target;
} else if(this.hasParameter("targetVia")) {
renderTitle = this.wiki.getTextReference(this.params.targetVia,null,this.tiddlerTitle);
} else {
renderTitle = this.tiddlerTitle;
}
// Get the render tree for the template
if(this.content.length > 0) {
renderTemplateTree = this.content;
} else {
if(this.hasParameter("template")) {
renderTemplateTitle = this.params.template;
} else {
renderTemplateTitle = renderTitle;
}
// Check for recursion
if(parents.indexOf(this.params.templateTitle) !== -1) {
renderTemplateTree = $tw.Tree.errorNode("Tiddler recursion error in <<tiddler>> macro");
} else {
parents.push(renderTemplateTitle);
renderTemplateTree = [];
// Check for substitution parameters
if(this.hasParameter("with")) {
parseOptions["with"] = [undefined,this.params["with"]]; // TODO: Allow for more than one with: parameter
}
parseTree = this.wiki.parseTiddler(renderTemplateTitle,parseOptions);
children = parseTree ? parseTree.tree : [];
for(t=0; t<children.length; t++) {
renderTemplateTree.push(children[t].clone());
}
}
}
// Execute macros within the children
for(t=0; t<renderTemplateTree.length; t++) {
renderTemplateTree[t].execute(parents,renderTitle);
}
// Set up the attributes for the wrapper element
var attributes = {
"class": []
};
if(!this.wiki.tiddlerExists(renderTitle)) {
attributes["class"].push("tw-tiddler-missing");
}
// Return the children
return $tw.Tree.Element(this.isBlock ? "div" : "span",attributes,renderTemplateTree);
};
exports.refreshInDom = function(changes) {
var renderTitle;
// Set the class for missing tiddlers
if(this.hasParameter("target")) {
renderTitle = this.params.target;
} else {
renderTitle = this.tiddlerTitle;
}
if(renderTitle) {
$tw.utils.toggleClass(this.child.domNode,"tw-tiddler-missing",!this.wiki.tiddlerExists(renderTitle));
}
// Rerender the tiddler if it is impacted by the changes
if(this.dependencies.hasChanged(changes,this.renderTitle)) {
// Manually reexecute and rerender this macro
this.reexecuteInDom();
} else {
this.child.refreshInDom(changes);
}
};
})();
-25
View File
@@ -1,25 +0,0 @@
/*\
title: $:/core/modules/macros/version.js
type: application/javascript
module-type: macro
Version macro
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "version",
params: {
}
};
exports.executeMacro = function() {
return $tw.Tree.Text($tw.version);
};
})();
-58
View File
@@ -1,58 +0,0 @@
/*\
title: $:/core/modules/macros/video.js
type: application/javascript
module-type: macro
Video macro
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "video",
params: {
src: {byName: "default", type: "text"},
type: {byName: true, type: "text"},
width: {byName: true, type: "text"},
height: {byName: true, type: "text"}
}
};
exports.executeMacro = function() {
var src = this.params.src,
videoType = this.params.type || "vimeo",
videoWidth = this.params.width || 640,
videoHeight = this.params.height || 360;
switch(videoType) {
case "vimeo":
return $tw.Tree.Element("iframe",{
src: "http://player.vimeo.com/video/" + src + "?autoplay=0",
width: videoWidth,
height: videoHeight,
frameborder: 0
});
case "youtube":
return $tw.Tree.Element("iframe",{
type: "text/html",
src: "http://www.youtube.com/embed/" + src,
width: videoWidth,
height: videoHeight,
frameborder: 0
});
case "archiveorg":
return $tw.Tree.Element("iframe",{
src: "http://www.archive.org/embed/" + src,
width: videoWidth,
height: videoHeight,
frameborder: 0
});
default:
return null;
}
};
})();
-73
View File
@@ -1,73 +0,0 @@
/*\
title: $:/core/modules/macros/view.js
type: application/javascript
module-type: macro
View macro
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "view",
dependentOnContextTiddler: true,
params: {
field: {byPos: 0, type: "text"},
format: {byPos: 1, type: "text"},
template: {byPos: 2, type: "text"}
}
};
exports.executeMacro = function() {
var tiddler = this.wiki.getTiddler(this.tiddlerTitle),
field = this.hasParameter("field") ? this.params.field : "title",
value;
// Get the value to display
if(tiddler) {
if(field === "text") {
value = this.wiki.getTiddlerText(this.tiddlerTitle);
} else {
value = tiddler.fields[field];
}
} else { // Use a special value if the tiddler is missing
switch(field) {
case "text":
value = "";
break;
case "title":
value = this.tiddlerTitle;
break;
case "modified":
case "created":
value = new Date();
break;
default:
value = "Missing tiddler '" + this.tiddlerTitle + "'";
break;
}
}
// Figure out which viewer to use
// TODO: Tiddler field modules should be able to specify a field type from which the viewer is derived
var Viewer;
if(this.params.format) {
Viewer = this.wiki.macros.view.fieldviewers[this.params.format];
}
if(!Viewer) {
Viewer = this.wiki.macros.view.fieldviewers.text;
}
this.viewer = new Viewer(this,tiddler,field,value);
// Call the viewer to generate the content
return this.viewer.render();
};
exports.postRenderInDom = function() {
if(this.viewer.postRenderInDom) {
this.viewer.postRenderInDom();
}
};
})();
-33
View File
@@ -1,33 +0,0 @@
/*\
title: $:/core/modules/macros/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(viewMacro,tiddler,field,value) {
this.viewMacro = viewMacro;
this.tiddler = tiddler;
this.field = field;
this.value = value;
};
DateViewer.prototype.render = function() {
var template = this.viewMacro.params.template || "DD MMM YYYY";
if(this.value === undefined) {
return $tw.Tree.Text("");
} else {
return $tw.Tree.Text($tw.utils.formatDateString(this.value,template));
}
};
exports.date = DateViewer;
})();
-39
View File
@@ -1,39 +0,0 @@
/*\
title: $:/core/modules/macros/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(viewMacro,tiddler,field,value) {
this.viewMacro = viewMacro;
this.tiddler = tiddler;
this.field = field;
this.value = value;
};
LinkViewer.prototype.render = function() {
if(this.value === undefined) {
return $tw.Tree.Text("");
} else {
var link = $tw.Tree.Macro("link",{
srcParams: {to: this.value},
content: [$tw.Tree.Text(this.value)],
isBlock: this.viewMacro.isBlock,
wiki: this.viewMacro.wiki
});
link.execute(this.viewMacro.parents,this.viewMacro.tiddlerTitle);
return link;
}
};
exports.link = LinkViewer;
})();
@@ -1,75 +0,0 @@
/*\
title: $:/core/modules/macros/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(viewMacro,tiddler,field,value) {
this.viewMacro = viewMacro;
this.tiddler = tiddler;
this.field = field;
this.value = value;
};
RelativeDateViewer.prototype.render = function() {
if(!this.tiddler ||this.value === undefined) {
return $tw.Tree.Text("");
} else {
this.relativeDate = $tw.utils.getRelativeDate((new Date()) - this.value);
return $tw.Tree.Element(this.viewMacro.isBlock ? "div" : "span",{},[
$tw.Tree.Text(
this.relativeDate.description
)
]);
}
};
/*
Trigger the timer when the relative date is put into the DOM
*/
RelativeDateViewer.prototype.postRenderInDom = function() {
if(this.relativeDate) {
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(document,self.viewMacro.child.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.viewMacro.child.domNode.hasChildNodes()) {
this.viewMacro.child.domNode.removeChild(this.viewMacro.child.domNode.firstChild);
}
this.viewMacro.child.domNode.appendChild(document.createTextNode(this.relativeDate.description));
this.setTimer();
}
};
exports.relativedate = RelativeDateViewer;
})();
-37
View File
@@ -1,37 +0,0 @@
/*\
title: $:/core/modules/macros/view/viewers/text.js
type: application/javascript
module-type: fieldviewer
A viewer for viewing tiddler fields as plain text
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var TextViewer = function(viewMacro,tiddler,field,value) {
this.viewMacro = viewMacro;
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);
}
// Return the text
if(this.value === undefined || this.value === null) {
return $tw.Tree.Text("");
} else {
return $tw.Tree.Text(this.value);
}
};
exports.text = TextViewer;
})();
@@ -1,38 +0,0 @@
/*\
title: $:/core/modules/macros/view/viewers/transclude.js
type: application/javascript
module-type: fieldviewer
A viewer that transcludes the tiddler whose title is specified in the viewed field
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var TranscludeViewer = function(viewMacro,tiddler,field,value) {
this.viewMacro = viewMacro;
this.tiddler = tiddler;
this.field = field;
this.value = value;
};
TranscludeViewer.prototype.render = function() {
if(this.tiddler && this.viewMacro.params.field && (this.viewMacro.params.field in this.tiddler.fields)) {
var children = this.viewMacro.wiki.parseTiddler(this.tiddler.fields[this.viewMacro.params.field]).tree,
childrenClone = [],t;
for(t=0; t<children.length; t++) {
childrenClone.push(children[t].clone());
}
for(t=0; t<childrenClone.length; t++) {
childrenClone[t].execute(this.viewMacro.parents,this.viewMacro.tiddlerTitle);
}
return $tw.Tree.Element(this.viewMacro.isBlock ? "div" : "span",{},childrenClone);
}
};
exports.transclude = TranscludeViewer;
})();
@@ -1,49 +0,0 @@
/*\
title: $:/core/modules/macros/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(viewMacro,tiddler,field,value) {
this.viewMacro = viewMacro;
this.tiddler = tiddler;
this.field = field;
this.value = value;
};
WikifiedViewer.prototype.render = function() {
// Check for recursion
var parents = this.viewMacro.parents,
children,t,childrenClone = [];
if(this.tiddler && this.viewMacro.params.field === "text") {
if(parents.indexOf(this.tiddler.fields.title) !== -1) {
children = [$tw.Tree.errorNode("Tiddler recursion error in <<view>> macro")];
} else {
children = this.viewMacro.wiki.parseTiddler(this.tiddler.fields.title).tree;
}
parents = parents.slice(0);
parents.push(this.tiddler.fields.title);
} else {
children = this.viewMacro.wiki.parseText("text/vnd.tiddlywiki",this.value).tree;
}
// Clone and execute the parsed wikitext
for(t=0; t<children.length; t++) {
childrenClone.push(children[t].clone());
}
for(t=0; t<childrenClone.length; t++) {
childrenClone[t].execute(parents,this.viewMacro.tiddlerTitle);
}
return $tw.Tree.Element(this.viewMacro.isBlock ? "div" : "span",{},childrenClone);
};
exports.wikified = WikifiedViewer;
})();
-156
View File
@@ -1,156 +0,0 @@
/*\
title: $:/core/modules/macros/zoomable.js
type: application/javascript
module-type: macro
Creates a zoomable frame around its content
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "zoomable",
params: {
width: {byName: true, type: "text"},
height: {byName: true, type: "text"},
"class": {byName: true, type: "text"}
}
};
exports.executeMacro = function() {
var innerClasses = ["tw-zoomable-inner"],
innerAttributes = {
"class": innerClasses,
style: {
overflow: "visible",
position: "relative"
}
},
outerClasses = ["tw-zoomable","tw-zoomable-outer"],
outerAttributes = {
"class": outerClasses,
style: {
overflow: "hidden",
"white-space": "nowrap"
}
};
if(this.hasParameter("class")) {
outerClasses.push(this.params["class"]);
}
if(this.classes) {
$tw.utils.pushTop(outerClasses,this.classes);
}
if(this.hasParameter("width")) {
outerAttributes.style.width = this.params.width;
}
if(this.hasParameter("height")) {
outerAttributes.style.height = this.params.height;
}
var self = this;
this.innerFrame = $tw.Tree.Element("div",innerAttributes,this.content);
this.outerFrame = $tw.Tree.Element("div",outerAttributes,[this.innerFrame],{
events: ["tw-scroll","click"],
eventHandler: this
});
this.outerFrame.execute(this.parents,this.tiddlerTitle);
this.translateX = 0;
this.translateY = 0;
this.scale = 1;
return this.outerFrame;
};
exports.postRenderInDom = function() {
this.zoomAll();
};
/*
Bring a dom node into view by setting the viewport (translation and scale factors) appropriately.
The calculations are a little hairy. The problem is that we want to deal with coordinates that take into account CSS transformations applied to elements. The most reliable way to do that is to use getBoundingClientRect, which returns the bounding rectangle in screen coordinates of an element, taking into account any transformations.
So, we measure the position of the target element and then adjust it to compensate for the current viewport settings.
*/
exports.setViewPort = function(domNode) {
var zoomPosString = domNode.getAttribute("data-tw-zoom");
if(zoomPosString) {
var zoomPos = JSON.parse(zoomPosString);
if(zoomPos) {
// Compute the transform for the inner frame
this.translateX = -zoomPos.x;
this.translateY = -zoomPos.y;
this.scale = this.outerFrame.domNode.offsetWidth / zoomPos.w;
$tw.utils.setStyle(this.innerFrame.domNode,[
{transition: $tw.utils.roundTripPropertyName("transform") + " " + $tw.config.preferences.animationDurationMs + " ease-in-out"},
{transformOrigin: "0% 0%"},
{transform: "translate(" + this.translateX * this.scale + "px," + this.translateY * this.scale + "px) scale(" + this.scale + ")"}
]);
}
}
};
exports.zoomAll = function() {
var bounds = {left: 0, top: 0, right: 0, bottom: 0},
scanChildren = function(nodes) {
for(var c=0; c<nodes.length; c++) {
var node = nodes[c];
if(node.getAttribute && node.getAttribute("data-tw-zoom")) {
var zoom = JSON.parse(node.getAttribute("data-tw-zoom"));
if(zoom === true) {
zoom = {
x: node.offsetLeft,
y: node.offsetTop,
w: node.scrollWidth,
h: node.scrollHeight
};
}
if(zoom.x < bounds.left) {
bounds.left = zoom.x;
}
if(zoom.y < bounds.top) {
bounds.top = zoom.y;
}
if((zoom.x + zoom.w) > bounds.right) {
bounds.right = zoom.x + zoom.w;
}
if((zoom.y + zoom.h) > bounds.bottom) {
bounds.bottom = zoom.y + zoom.h;
}
}
if(node.hasChildNodes()) {
scanChildren(node.childNodes);
}
}
};
scanChildren(this.innerFrame.domNode.childNodes);
this.translateX = bounds.left;
this.translateY = bounds.top;
this.scale = this.outerFrame.domNode.offsetWidth / (bounds.right - bounds.left);
$tw.utils.setStyle(this.innerFrame.domNode,[
{transition: $tw.utils.roundTripPropertyName("transform") + " " + $tw.config.preferences.animationDurationMs + " ease-in-out"},
{transformOrigin: "0% 0%"},
{transform: "translate(" + this.translateX * this.scale + "px," + this.translateY * this.scale + "px) scale(" + this.scale + ")"}
]);
};
exports.handleEvent = function(event) {
if(event.type === "tw-scroll") {
return this.handleScrollEvent(event);
}
if(event.type === "click") {
this.zoomAll();
return false;
}
return true;
}
exports.handleScrollEvent = function(event) {
this.setViewPort(event.target);
event.stopPropagation();
return false;
};
})();