mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-09-22 17:28:44 +00:00
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:
@@ -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
|
||||
});
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
})();
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
})();
|
||||
@@ -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;
|
||||
|
||||
})();
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -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;
|
||||
|
||||
})();
|
||||
@@ -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
|
||||
});
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
})();
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -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;
|
||||
|
||||
})();
|
||||
@@ -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;
|
||||
|
||||
})();
|
||||
@@ -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;
|
||||
|
||||
})();
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user