Merge branch 'master' into json-ops

This commit is contained in:
jeremy@jermolene.com
2022-04-06 17:37:21 +01:00
249 changed files with 3164 additions and 904 deletions
+50 -42
View File
@@ -8,46 +8,54 @@ Saves individual tiddlers in their raw text or binary format to the specified fi
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "save",
synchronous: true
};
var Command = function(params,commander,callback) {
this.params = params;
this.commander = commander;
this.callback = callback;
};
Command.prototype.execute = function() {
if(this.params.length < 1) {
return "Missing filename filter";
}
var self = this,
fs = require("fs"),
path = require("path"),
wiki = this.commander.wiki,
tiddlerFilter = this.params[0],
filenameFilter = this.params[1] || "[is[tiddler]]",
tiddlers = wiki.filterTiddlers(tiddlerFilter);
$tw.utils.each(tiddlers,function(title) {
var tiddler = self.commander.wiki.getTiddler(title),
type = tiddler.fields.type || "text/vnd.tiddlywiki",
contentTypeInfo = $tw.config.contentTypeInfo[type] || {encoding: "utf8"},
filepath = path.resolve(self.commander.outputPath,wiki.filterTiddlers(filenameFilter,$tw.rootWidget,wiki.makeTiddlerIterator([title]))[0]);
if(self.commander.verbose) {
console.log("Saving \"" + title + "\" to \"" + filepath + "\"");
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "save",
synchronous: true
};
var Command = function(params,commander,callback) {
this.params = params;
this.commander = commander;
this.callback = callback;
};
Command.prototype.execute = function() {
if(this.params.length < 1) {
return "Missing filename filter";
}
$tw.utils.createFileDirectories(filepath);
fs.writeFileSync(filepath,tiddler.fields.text,contentTypeInfo.encoding);
});
return null;
};
exports.Command = Command;
})();
var self = this,
fs = require("fs"),
path = require("path"),
result = null,
wiki = this.commander.wiki,
tiddlerFilter = this.params[0],
filenameFilter = this.params[1] || "[is[tiddler]]",
tiddlers = wiki.filterTiddlers(tiddlerFilter);
$tw.utils.each(tiddlers,function(title) {
if(!result) {
var tiddler = self.commander.wiki.getTiddler(title);
if(tiddler) {
var type = tiddler.fields.type || "text/vnd.tiddlywiki",
contentTypeInfo = $tw.config.contentTypeInfo[type] || {encoding: "utf8"},
filepath = path.resolve(self.commander.outputPath,wiki.filterTiddlers(filenameFilter,$tw.rootWidget,wiki.makeTiddlerIterator([title]))[0]);
if(self.commander.verbose) {
console.log("Saving \"" + title + "\" to \"" + filepath + "\"");
}
$tw.utils.createFileDirectories(filepath);
fs.writeFileSync(filepath,tiddler.fields.text,contentTypeInfo.encoding);
} else {
result = "Tiddler '" + title + "' not found";
}
}
});
return result;
};
exports.Command = Command;
})();
+2 -1
View File
@@ -87,7 +87,8 @@ exports.butlast = function(source,operator,options) {
source(function(tiddler,title) {
results.push(title);
});
return results.slice(0,-count);
var index = count === 0 ? results.length : -count;
return results.slice(0,index);
};
exports.bl = exports.butlast;
+11 -7
View File
@@ -80,6 +80,7 @@ PutSaver.prototype.save = function(text,method,callback) {
if(this.etag) {
headers["If-Match"] = this.etag;
}
$tw.notifier.display("$:/language/Notifications/Save/Starting");
$tw.utils.httpRequest({
url: this.uri(),
type: "PUT",
@@ -87,17 +88,20 @@ PutSaver.prototype.save = function(text,method,callback) {
data: text,
callback: function(err,data,xhr) {
if(err) {
// response is textual: "XMLHttpRequest error code: 412"
var status = Number(err.substring(err.indexOf(':') + 2, err.length))
var status = xhr.status,
errorMsg = err;
if(status === 412) { // file changed on server
callback($tw.language.getString("Error/PutEditConflict"));
errorMsg = $tw.language.getString("Error/PutEditConflict");
} else if(status === 401) { // authentication required
callback($tw.language.getString("Error/PutUnauthorized"));
errorMsg = $tw.language.getString("Error/PutUnauthorized");
} else if(status === 403) { // permission denied
callback($tw.language.getString("Error/PutForbidden"));
} else {
callback(err); // fail
errorMsg = $tw.language.getString("Error/PutForbidden");
}
if (xhr.responseText) {
// treat any server response like a plain text error explanation
errorMsg = errorMsg + "\n\n" + xhr.responseText;
}
callback(errorMsg); // fail
} else {
self.etag = xhr.getResponseHeader("ETag");
if(self.etag == null) {
+1 -1
View File
@@ -64,6 +64,7 @@ UploadSaver.prototype.save = function(text,method,callback) {
var tail = "\r\n--" + boundary + "--\r\n",
data = head.join("\r\n") + text + tail;
// Do the HTTP post
$tw.notifier.display("$:/language/Notifications/Save/Starting");
var http = new XMLHttpRequest();
http.open("POST",url,true,username,password);
http.setRequestHeader("Content-Type","multipart/form-data; charset=UTF-8; boundary=" + boundary);
@@ -81,7 +82,6 @@ UploadSaver.prototype.save = function(text,method,callback) {
} catch(ex) {
return callback($tw.language.getString("Error/Caption") + ":" + ex);
}
$tw.notifier.display("$:/language/Notifications/Save/Starting");
return true;
};
+7 -2
View File
@@ -42,12 +42,17 @@ exports.startup = function() {
$tw.styleWidgetNode = $tw.wiki.makeTranscludeWidget(PAGE_STYLESHEET_TITLE,{document: $tw.fakeDocument});
$tw.styleContainer = $tw.fakeDocument.createElement("style");
$tw.styleWidgetNode.render($tw.styleContainer,null);
$tw.styleWidgetNode.assignedStyles = $tw.styleContainer.textContent;
$tw.styleElement = document.createElement("style");
$tw.styleElement.innerHTML = $tw.styleContainer.textContent;
$tw.styleElement.innerHTML = $tw.styleWidgetNode.assignedStyles;
document.head.insertBefore($tw.styleElement,document.head.firstChild);
$tw.wiki.addEventListener("change",$tw.perf.report("styleRefresh",function(changes) {
if($tw.styleWidgetNode.refresh(changes,$tw.styleContainer,null)) {
$tw.styleElement.innerHTML = $tw.styleContainer.textContent;
var newStyles = $tw.styleContainer.textContent;
if(newStyles !== $tw.styleWidgetNode.assignedStyles) {
$tw.styleWidgetNode.assignedStyles = newStyles;
$tw.styleElement.innerHTML = $tw.styleWidgetNode.assignedStyles;
}
}
}));
// Display the $:/core/ui/PageTemplate tiddler to kick off the display
+20 -9
View File
@@ -20,6 +20,8 @@ exports.synchronous = true;
// Global to keep track of open windows (hashmap by title)
$tw.windows = {};
// Default template to use for new windows
var DEFAULT_WINDOW_TEMPLATE = "$:/core/templates/single.tiddler.window";
exports.startup = function() {
// Handle open window message
@@ -29,24 +31,25 @@ exports.startup = function() {
title = event.param || event.tiddlerTitle,
paramObject = event.paramObject || {},
windowTitle = paramObject.windowTitle || title,
template = paramObject.template || "$:/core/templates/single.tiddler.window",
windowID = paramObject.windowID || title,
template = paramObject.template || DEFAULT_WINDOW_TEMPLATE,
width = paramObject.width || "700",
height = paramObject.height || "600",
top = paramObject.top,
left = paramObject.left,
variables = $tw.utils.extend({},paramObject,{currentTiddler: title});
variables = $tw.utils.extend({},paramObject,{currentTiddler: title, "tv-window-id": windowID});
// Open the window
var srcWindow,
srcDocument;
// In case that popup blockers deny opening a new window
try {
srcWindow = window.open("","external-" + title,"scrollbars,width=" + width + ",height=" + height + (top ? ",top=" + top : "" ) + (left ? ",left=" + left : "" )),
srcWindow = window.open("","external-" + windowID,"scrollbars,width=" + width + ",height=" + height + (top ? ",top=" + top : "" ) + (left ? ",left=" + left : "" )),
srcDocument = srcWindow.document;
}
catch(e) {
return;
}
$tw.windows[title] = srcWindow;
$tw.windows[windowID] = srcWindow;
// Check for reopening the same window
if(srcWindow.haveInitialisedWindow) {
return;
@@ -56,7 +59,7 @@ exports.startup = function() {
srcDocument.close();
srcDocument.title = windowTitle;
srcWindow.addEventListener("beforeunload",function(event) {
delete $tw.windows[title];
delete $tw.windows[windowID];
$tw.wiki.removeEventListener("change",refreshHandler);
},false);
// Set up the styles
@@ -90,13 +93,21 @@ exports.startup = function() {
srcWindow.document.documentElement.addEventListener("click",$tw.popup,true);
srcWindow.haveInitialisedWindow = true;
});
// Close open windows when unloading main window
$tw.addUnloadTask(function() {
$tw.rootWidget.addEventListener("tm-close-window",function(event) {
var windowID = event.param,
win = $tw.windows[windowID];
if(win) {
win.close();
}
});
var closeAllWindows = function() {
$tw.utils.each($tw.windows,function(win) {
win.close();
});
});
}
$tw.rootWidget.addEventListener("tm-close-all-windows",closeAllWindows);
// Close open windows when unloading main window
$tw.addUnloadTask(closeAllWindows);
};
})();
+34 -11
View File
@@ -13,8 +13,12 @@ Parse tree utility functions.
"use strict";
exports.addAttributeToParseTreeNode = function(node,name,value) {
var attribute = {name: name, type: "string", value: value};
node.attributes = node.attributes || {};
node.attributes[name] = {type: "string", value: value};
node.attributes[name] = attribute;
if(node.orderedAttributes) {
node.orderedAttributes.push(attribute);
}
};
exports.getAttributeValueFromParseTreeNode = function(node,name,defaultValue) {
@@ -25,26 +29,45 @@ exports.getAttributeValueFromParseTreeNode = function(node,name,defaultValue) {
};
exports.addClassToParseTreeNode = function(node,classString) {
var classes = [];
var classes = [],
attribute;
node.attributes = node.attributes || {};
node.attributes["class"] = node.attributes["class"] || {type: "string", value: ""};
if(node.attributes["class"].type === "string") {
if(node.attributes["class"].value !== "") {
classes = node.attributes["class"].value.split(" ");
attribute = node.attributes["class"];
if(!attribute) {
// If the class attribute does not exist, we must create it first.
attribute = {name: "class", type: "string", value: ""};
node.attributes["class"] = attribute;
if(node.orderedAttributes) {
// If there are orderedAttributes, we've got to add them there too.
node.orderedAttributes.push(attribute);
}
}
if(attribute.type === "string") {
if(attribute.value !== "") {
classes = attribute.value.split(" ");
}
if(classString !== "") {
$tw.utils.pushTop(classes,classString.split(" "));
}
node.attributes["class"].value = classes.join(" ");
attribute.value = classes.join(" ");
}
};
exports.addStyleToParseTreeNode = function(node,name,value) {
node.attributes = node.attributes || {};
node.attributes.style = node.attributes.style || {type: "string", value: ""};
if(node.attributes.style.type === "string") {
node.attributes.style.value += name + ":" + value + ";";
var attribute;
node.attributes = node.attributes || {};
attribute = node.attributes.style;
if(!attribute) {
attribute = {name: "style", type: "string", value: ""};
node.attributes.style = attribute;
if(node.orderedAttributes) {
// If there are orderedAttributes, we've got to add them there too.
node.orderedAttributes.push(attribute);
}
}
if(attribute.type === "string") {
attribute.value += name + ":" + value + ";";
}
};
exports.findParseTreeNode = function(nodeArray,search) {
+2 -2
View File
@@ -71,8 +71,8 @@ ActionListopsWidget.prototype.invokeAction = function(triggeringWidget,
}
if(this.subfilter) {
var inputList = this.wiki.getTiddlerList(this.target,field,index),
subfilter = $tw.utils.stringifyList(inputList) + " " + this.subfilter;
this.wiki.setText(this.target, field, index, $tw.utils.stringifyList(this.wiki.filterTiddlers(subfilter,this)));
subfilter = "[all[]] " + this.subfilter;
this.wiki.setText(this.target, field, index, $tw.utils.stringifyList(this.wiki.filterTiddlers(subfilter,this,this.wiki.makeTiddlerIterator(inputList))));
}
if(this.filtertags) {
var tiddler = this.wiki.getTiddler(this.target),
+1 -1
View File
@@ -247,7 +247,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
*/
ButtonWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.actions || changedAttributes.to || changedAttributes.message || changedAttributes.param || changedAttributes.set || changedAttributes.setTo || changedAttributes.popup || changedAttributes.hover || changedAttributes.selectedClass || changedAttributes.style || changedAttributes.dragFilter || changedAttributes.dragTiddler || (this.set && changedTiddlers[this.set]) || (this.popup && changedTiddlers[this.popup]) || (this.popupTitle && changedTiddlers[this.popupTitle]) || changedAttributes.setTitle || changedAttributes.setField || changedAttributes.setIndex || changedAttributes.popupTitle || changedAttributes.disabled) {
if(changedAttributes.actions || changedAttributes.to || changedAttributes.message || changedAttributes.param || changedAttributes.set || changedAttributes.setTo || changedAttributes.popup || changedAttributes.hover || changedAttributes.selectedClass || changedAttributes.style || changedAttributes.dragFilter || changedAttributes.dragTiddler || (this.set && changedTiddlers[this.set]) || (this.popup && changedTiddlers[this.popup]) || (this.popupTitle && changedTiddlers[this.popupTitle]) || changedAttributes.setTitle || changedAttributes.setField || changedAttributes.setIndex || changedAttributes.popupTitle || changedAttributes.disabled || changedAttributes["default"]) {
this.refreshSelf();
return true;
} else if(changedAttributes["class"]) {
+102 -13
View File
@@ -35,11 +35,12 @@ CheckboxWidget.prototype.render = function(parent,nextSibling) {
this.execute();
// Create our elements
this.labelDomNode = this.document.createElement("label");
this.labelDomNode.setAttribute("class",this.checkboxClass);
this.labelDomNode.setAttribute("class","tc-checkbox " + this.checkboxClass);
this.inputDomNode = this.document.createElement("input");
this.inputDomNode.setAttribute("type","checkbox");
if(this.getValue()) {
this.inputDomNode.setAttribute("checked","true");
$tw.utils.addClass(this.labelDomNode,"tc-checkbox-checked");
}
if(this.isDisabled === "yes") {
this.inputDomNode.setAttribute("disabled",true);
@@ -59,7 +60,7 @@ CheckboxWidget.prototype.render = function(parent,nextSibling) {
CheckboxWidget.prototype.getValue = function() {
var tiddler = this.wiki.getTiddler(this.checkboxTitle);
if(tiddler) {
if(tiddler || this.checkboxFilter) {
if(this.checkboxTag) {
if(this.checkboxInvertTag) {
return !tiddler.hasTag(this.checkboxTag);
@@ -67,12 +68,17 @@ CheckboxWidget.prototype.getValue = function() {
return tiddler.hasTag(this.checkboxTag);
}
}
if(this.checkboxField) {
if(this.checkboxField || this.checkboxIndex) {
// Same logic applies to fields and indexes
var value;
if($tw.utils.hop(tiddler.fields,this.checkboxField)) {
value = tiddler.fields[this.checkboxField] || "";
if(this.checkboxField) {
if($tw.utils.hop(tiddler.fields,this.checkboxField)) {
value = tiddler.fields[this.checkboxField] || "";
} else {
value = this.checkboxDefault || "";
}
} else {
value = this.checkboxDefault || "";
value = this.wiki.extractTiddlerDataItem(tiddler,this.checkboxIndex,this.checkboxDefault || "");
}
if(value === this.checkboxChecked) {
return true;
@@ -80,15 +86,46 @@ CheckboxWidget.prototype.getValue = function() {
if(value === this.checkboxUnchecked) {
return false;
}
// Neither value found: were both specified?
if(this.checkboxChecked && !this.checkboxUnchecked) {
return false; // Absence of checked value
}
if(this.checkboxUnchecked && !this.checkboxChecked) {
return true; // Absence of unchecked value
}
}
if(this.checkboxIndex) {
var value = this.wiki.extractTiddlerDataItem(tiddler,this.checkboxIndex,this.checkboxDefault || "");
if(value === this.checkboxChecked) {
if(this.checkboxListField || this.checkboxListIndex || this.checkboxFilter) {
// Same logic applies to lists and filters
var list;
if(this.checkboxListField) {
if($tw.utils.hop(tiddler.fields,this.checkboxListField)) {
list = tiddler.getFieldList(this.checkboxListField);
} else {
list = $tw.utils.parseStringArray(this.checkboxDefault || "") || [];
}
} else if (this.checkboxListIndex) {
list = $tw.utils.parseStringArray(this.wiki.extractTiddlerDataItem(tiddler,this.checkboxListIndex,this.checkboxDefault || "")) || [];
} else {
list = this.wiki.filterTiddlers(this.checkboxFilter,this) || [];
}
if(list.indexOf(this.checkboxChecked) !== -1) {
return true;
}
if(value === this.checkboxUnchecked) {
if(list.indexOf(this.checkboxUnchecked) !== -1) {
return false;
}
// Neither one present
if(this.checkboxChecked && !this.checkboxUnchecked) {
return false; // Absence of checked value
}
if(this.checkboxUnchecked && !this.checkboxChecked) {
return true; // Absence of unchecked value
}
if(this.checkboxChecked && this.checkboxUnchecked) {
return false; // Both specified but neither found: default to false
}
// Neither specified, so empty list is false, non-empty is true
return !!list.length;
}
} else {
if(this.checkboxTag) {
@@ -114,7 +151,8 @@ CheckboxWidget.prototype.handleChangeEvent = function(event) {
hasChanged = false,
tagCheck = false,
hasTag = tiddler && tiddler.hasTag(this.checkboxTag),
value = checked ? this.checkboxChecked : this.checkboxUnchecked;
value = checked ? this.checkboxChecked : this.checkboxUnchecked,
notValue = checked ? this.checkboxUnchecked : this.checkboxChecked;
if(this.checkboxTag && this.checkboxInvertTag === "yes") {
tagCheck = hasTag === checked;
} else {
@@ -148,9 +186,51 @@ CheckboxWidget.prototype.handleChangeEvent = function(event) {
hasChanged = true;
}
}
// Set the list field (or index) if specified
if(this.checkboxListField || this.checkboxListIndex) {
var listContents, oldPos, newPos;
if(this.checkboxListField) {
listContents = tiddler.getFieldList(this.checkboxListField);
} else {
listContents = $tw.utils.parseStringArray(this.wiki.extractTiddlerDataItem(this.checkboxTitle,this.checkboxListIndex) || "") || [];
}
oldPos = notValue ? listContents.indexOf(notValue) : -1;
newPos = value ? listContents.indexOf(value) : -1;
if(oldPos === -1 && newPos !== -1) {
// old value absent, new value present: no change needed
} else if(oldPos === -1) {
// neither one was present
if(value) {
listContents.push(value);
hasChanged = true;
} else {
// value unspecified? then leave list unchanged
}
} else if(newPos === -1) {
// old value present, new value absent
if(value) {
listContents[oldPos] = value;
hasChanged = true;
} else {
listContents.splice(oldPos, 1)
hasChanged = true;
}
} else {
// both were present: just remove the old one, leave new alone
listContents.splice(oldPos, 1)
hasChanged = true;
}
if(this.checkboxListField) {
newFields[this.checkboxListField] = $tw.utils.stringifyList(listContents);
}
// The listIndex case will be handled in the if(hasChanged) block below
}
if(hasChanged) {
if(this.checkboxIndex) {
this.wiki.setText(this.checkboxTitle,"",this.checkboxIndex,value);
} else if(this.checkboxListIndex) {
var listIndexValue = (listContents && listContents.length) ? $tw.utils.stringifyList(listContents) : undefined;
this.wiki.setText(this.checkboxTitle,"",this.checkboxListIndex,listIndexValue);
} else {
this.wiki.addTiddler(new $tw.Tiddler(this.wiki.getCreationFields(),fallbackFields,tiddler,newFields,this.wiki.getModificationFields()));
}
@@ -179,6 +259,9 @@ CheckboxWidget.prototype.execute = function() {
this.checkboxTag = this.getAttribute("tag");
this.checkboxField = this.getAttribute("field");
this.checkboxIndex = this.getAttribute("index");
this.checkboxListField = this.getAttribute("listField");
this.checkboxListIndex = this.getAttribute("listIndex");
this.checkboxFilter = this.getAttribute("filter");
this.checkboxChecked = this.getAttribute("checked");
this.checkboxUnchecked = this.getAttribute("unchecked");
this.checkboxDefault = this.getAttribute("default");
@@ -194,14 +277,20 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
*/
CheckboxWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.tiddler || changedAttributes.tag || changedAttributes.invertTag || changedAttributes.field || changedAttributes.index || changedAttributes.checked || changedAttributes.unchecked || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.disabled) {
if(changedAttributes.tiddler || changedAttributes.tag || changedAttributes.invertTag || changedAttributes.field || changedAttributes.index || changedAttributes.listField || changedAttributes.filter || changedAttributes.checked || changedAttributes.unchecked || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.disabled) {
this.refreshSelf();
return true;
} else {
var refreshed = false;
if(changedTiddlers[this.checkboxTitle]) {
this.inputDomNode.checked = this.getValue();
var isChecked = this.getValue();
this.inputDomNode.checked = isChecked;
refreshed = true;
if(isChecked) {
$tw.utils.addClass(this.labelDomNode,"tc-checkbox-checked");
} else {
$tw.utils.removeClass(this.labelDomNode,"tc-checkbox-checked");
}
}
return this.refreshChildren(changedTiddlers) || refreshed;
}
+37 -33
View File
@@ -46,6 +46,7 @@ EventWidget.prototype.render = function(parent,nextSibling) {
$tw.utils.each(this.types,function(type) {
domNode.addEventListener(type,function(event) {
var selector = self.getAttribute("selector"),
matchSelector = self.getAttribute("matchSelector"),
actions = self.getAttribute("$"+type) || self.getAttribute("actions-"+type),
stopPropagation = self.getAttribute("stopPropagation","onaction"),
selectedNode = event.target,
@@ -56,46 +57,49 @@ EventWidget.prototype.render = function(parent,nextSibling) {
if(selectedNode.nodeType === 3) {
selectedNode = selectedNode.parentNode;
}
// Check that the selected node matches any matchSelector
if(matchSelector && !$tw.utils.domMatchesSelector(selectedNode,matchSelector)) {
return false;
}
if(selector) {
// Search ancestors for a node that matches the selector
while(!$tw.utils.domMatchesSelector(selectedNode,selector) && selectedNode !== domNode) {
selectedNode = selectedNode.parentNode;
}
// If we found one, copy the attributes as variables, otherwise exit
if($tw.utils.domMatchesSelector(selectedNode,selector)) {
// Only set up variables if we have actions to invoke
if(actions) {
$tw.utils.each(selectedNode.attributes,function(attribute) {
variables["dom-" + attribute.name] = attribute.value.toString();
});
//Add a variable with a popup coordinate string for the selected node
variables["tv-popup-coords"] = "(" + selectedNode.offsetLeft + "," + selectedNode.offsetTop +"," + selectedNode.offsetWidth + "," + selectedNode.offsetHeight + ")";
//Add variables for offset of selected node
variables["tv-selectednode-posx"] = selectedNode.offsetLeft.toString();
variables["tv-selectednode-posy"] = selectedNode.offsetTop.toString();
variables["tv-selectednode-width"] = selectedNode.offsetWidth.toString();
variables["tv-selectednode-height"] = selectedNode.offsetHeight.toString();
if(event.clientX && event.clientY) {
//Add variables for event X and Y position relative to selected node
selectedNodeRect = selectedNode.getBoundingClientRect();
variables["event-fromselected-posx"] = (event.clientX - selectedNodeRect.left).toString();
variables["event-fromselected-posy"] = (event.clientY - selectedNodeRect.top).toString();
//Add variables for event X and Y position relative to event catcher node
catcherNodeRect = self.domNode.getBoundingClientRect();
variables["event-fromcatcher-posx"] = (event.clientX - catcherNodeRect.left).toString();
variables["event-fromcatcher-posy"] = (event.clientY - catcherNodeRect.top).toString();
//Add variables for event X and Y position relative to the viewport
variables["event-fromviewport-posx"] = event.clientX.toString();
variables["event-fromviewport-posy"] = event.clientY.toString();
}
}
} else {
// Exit if we didn't find one
if(selectedNode === domNode) {
return false;
}
// Only set up variables if we have actions to invoke
if(actions) {
$tw.utils.each(selectedNode.attributes,function(attribute) {
variables["dom-" + attribute.name] = attribute.value.toString();
});
//Add a variable with a popup coordinate string for the selected node
variables["tv-popup-coords"] = "(" + selectedNode.offsetLeft + "," + selectedNode.offsetTop +"," + selectedNode.offsetWidth + "," + selectedNode.offsetHeight + ")";
//Add variables for offset of selected node
variables["tv-selectednode-posx"] = selectedNode.offsetLeft.toString();
variables["tv-selectednode-posy"] = selectedNode.offsetTop.toString();
variables["tv-selectednode-width"] = selectedNode.offsetWidth.toString();
variables["tv-selectednode-height"] = selectedNode.offsetHeight.toString();
if(event.clientX && event.clientY) {
//Add variables for event X and Y position relative to selected node
selectedNodeRect = selectedNode.getBoundingClientRect();
variables["event-fromselected-posx"] = (event.clientX - selectedNodeRect.left).toString();
variables["event-fromselected-posy"] = (event.clientY - selectedNodeRect.top).toString();
//Add variables for event X and Y position relative to event catcher node
catcherNodeRect = self.domNode.getBoundingClientRect();
variables["event-fromcatcher-posx"] = (event.clientX - catcherNodeRect.left).toString();
variables["event-fromcatcher-posy"] = (event.clientY - catcherNodeRect.top).toString();
//Add variables for event X and Y position relative to the viewport
variables["event-fromviewport-posx"] = event.clientX.toString();
variables["event-fromviewport-posy"] = event.clientY.toString();
}
}
}
// Execute our actions with the variables
if(actions) {
+2
View File
@@ -159,6 +159,8 @@ ScrollableWidget.prototype.render = function(parent,nextSibling) {
// Create elements
this.outerDomNode = this.document.createElement("div");
$tw.utils.setStyle(this.outerDomNode,[
{overflowY: "auto"},
{overflowX: "auto"},
{webkitOverflowScrolling: "touch"}
]);
this.innerDomNode = this.document.createElement("div");