2013-10-12 16:05:13 +00:00
|
|
|
/*\
|
2013-11-08 08:47:00 +00:00
|
|
|
title: $:/core/modules/widgets/reveal.js
|
2013-10-12 16:05:13 +00:00
|
|
|
type: application/javascript
|
2013-11-08 08:47:00 +00:00
|
|
|
module-type: widget
|
2013-10-12 16:05:13 +00:00
|
|
|
|
|
|
|
Reveal widget
|
|
|
|
|
|
|
|
\*/
|
|
|
|
(function(){
|
|
|
|
|
|
|
|
/*jslint node: true, browser: true */
|
|
|
|
/*global $tw: false */
|
|
|
|
"use strict";
|
|
|
|
|
2013-11-08 08:47:00 +00:00
|
|
|
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
2013-10-12 16:05:13 +00:00
|
|
|
|
|
|
|
var RevealWidget = function(parseTreeNode,options) {
|
|
|
|
this.initialise(parseTreeNode,options);
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
Inherit from the base widget class
|
|
|
|
*/
|
|
|
|
RevealWidget.prototype = new Widget();
|
|
|
|
|
|
|
|
/*
|
|
|
|
Render this widget into the DOM
|
|
|
|
*/
|
|
|
|
RevealWidget.prototype.render = function(parent,nextSibling) {
|
|
|
|
this.parentDomNode = parent;
|
|
|
|
this.computeAttributes();
|
|
|
|
this.execute();
|
2013-10-16 15:29:35 +00:00
|
|
|
var domNode = this.document.createElement(this.parseTreeNode.isBlock ? "div" : "span");
|
2013-11-01 17:23:08 +00:00
|
|
|
var classes = this["class"].split(" ") || [];
|
|
|
|
classes.push("tw-reveal");
|
|
|
|
domNode.className = classes.join(" ");
|
2013-10-12 16:05:13 +00:00
|
|
|
parent.insertBefore(domNode,nextSibling);
|
|
|
|
this.renderChildren(domNode,null);
|
2013-10-14 22:32:01 +00:00
|
|
|
if(!domNode.isTiddlyWikiFakeDom && this.type === "popup" && this.isOpen) {
|
|
|
|
this.positionPopup(domNode);
|
|
|
|
}
|
2013-10-15 20:06:52 +00:00
|
|
|
if(!this.isOpen) {
|
|
|
|
domNode.setAttribute("hidden","true")
|
|
|
|
}
|
2013-10-12 16:05:13 +00:00
|
|
|
this.domNodes.push(domNode);
|
|
|
|
};
|
|
|
|
|
2013-10-14 22:32:01 +00:00
|
|
|
RevealWidget.prototype.positionPopup = function(domNode) {
|
|
|
|
domNode.style.position = "absolute";
|
|
|
|
domNode.style.zIndex = "1000";
|
|
|
|
switch(this.position) {
|
|
|
|
case "left":
|
|
|
|
domNode.style.left = (this.popup.left - domNode.offsetWidth) + "px";
|
|
|
|
domNode.style.top = this.popup.top + "px";
|
|
|
|
break;
|
|
|
|
case "above":
|
|
|
|
domNode.style.left = this.popup.left + "px";
|
|
|
|
domNode.style.top = (this.popup.top - domNode.offsetHeight) + "px";
|
|
|
|
break;
|
|
|
|
case "aboveright":
|
|
|
|
domNode.style.left = (this.popup.left + this.popup.width) + "px";
|
|
|
|
domNode.style.top = (this.popup.top + this.popup.height - domNode.offsetHeight) + "px";
|
|
|
|
break;
|
|
|
|
case "right":
|
|
|
|
domNode.style.left = (this.popup.left + this.popup.width) + "px";
|
|
|
|
domNode.style.top = this.popup.top + "px";
|
|
|
|
break;
|
|
|
|
case "belowleft":
|
|
|
|
domNode.style.left = (this.popup.left + this.popup.width - domNode.offsetWidth) + "px";
|
|
|
|
domNode.style.top = (this.popup.top + this.popup.height) + "px";
|
|
|
|
break;
|
|
|
|
default: // Below
|
|
|
|
domNode.style.left = this.popup.left + "px";
|
|
|
|
domNode.style.top = (this.popup.top + this.popup.height) + "px";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-10-12 16:05:13 +00:00
|
|
|
/*
|
|
|
|
Compute the internal state of the widget
|
|
|
|
*/
|
|
|
|
RevealWidget.prototype.execute = function() {
|
|
|
|
// Get our parameters
|
|
|
|
this.state = this.getAttribute("state");
|
|
|
|
this.type = this.getAttribute("type");
|
|
|
|
this.text = this.getAttribute("text");
|
|
|
|
this.position = this.getAttribute("position");
|
2013-11-01 17:23:08 +00:00
|
|
|
this["class"] = this.getAttribute("class","");
|
2013-10-12 16:05:13 +00:00
|
|
|
this["default"] = this.getAttribute("default","");
|
|
|
|
this.animate = this.getAttribute("animate","no");
|
2013-11-02 09:21:11 +00:00
|
|
|
this.openAnimation = this.animate === "no" ? undefined : "open";
|
|
|
|
this.closeAnimation = this.animate === "no" ? undefined : "close";
|
2013-10-12 16:05:13 +00:00
|
|
|
// Compute the title of the state tiddler and read it
|
|
|
|
this.stateTitle = this.state;
|
|
|
|
this.readState();
|
|
|
|
// Construct the child widgets
|
|
|
|
var childNodes = this.isOpen ? this.parseTreeNode.children : [];
|
2013-11-01 17:23:08 +00:00
|
|
|
this.hasChildNodes = this.isOpen;
|
2013-10-12 16:05:13 +00:00
|
|
|
this.makeChildWidgets(childNodes);
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
Read the state tiddler
|
|
|
|
*/
|
|
|
|
RevealWidget.prototype.readState = function() {
|
|
|
|
// Read the information from the state tiddler
|
|
|
|
if(this.stateTitle) {
|
2013-10-28 23:40:45 +00:00
|
|
|
var state = this.wiki.getTextReference(this.stateTitle,this["default"],this.getVariable("currentTiddler"));
|
2013-10-12 16:05:13 +00:00
|
|
|
switch(this.type) {
|
|
|
|
case "popup":
|
|
|
|
this.readPopupState(state);
|
|
|
|
break;
|
|
|
|
case "match":
|
|
|
|
this.readMatchState(state);
|
|
|
|
break;
|
|
|
|
case "nomatch":
|
|
|
|
this.readMatchState(state);
|
|
|
|
this.isOpen = !this.isOpen;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
RevealWidget.prototype.readMatchState = function(state) {
|
|
|
|
this.isOpen = state === this.text;
|
|
|
|
};
|
|
|
|
|
|
|
|
RevealWidget.prototype.readPopupState = function(state) {
|
|
|
|
var popupLocationRegExp = /^\((-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+),(-?[0-9\.E]+)\)$/,
|
|
|
|
match = popupLocationRegExp.exec(state);
|
|
|
|
// Check if the state matches the location regexp
|
|
|
|
if(match) {
|
|
|
|
// If so, we're open
|
|
|
|
this.isOpen = true;
|
|
|
|
// Get the location
|
|
|
|
this.popup = {
|
|
|
|
left: parseFloat(match[1]),
|
|
|
|
top: parseFloat(match[2]),
|
|
|
|
width: parseFloat(match[3]),
|
|
|
|
height: parseFloat(match[4])
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
// If not, we're closed
|
|
|
|
this.isOpen = false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
|
|
|
*/
|
|
|
|
RevealWidget.prototype.refresh = function(changedTiddlers) {
|
|
|
|
var changedAttributes = this.computeAttributes();
|
2013-11-02 15:42:24 +00:00
|
|
|
if(changedAttributes.state || changedAttributes.type || changedAttributes.text || changedAttributes.position || changedAttributes["default"] || changedAttributes.animate) {
|
2013-10-12 16:05:13 +00:00
|
|
|
this.refreshSelf();
|
|
|
|
return true;
|
|
|
|
} else {
|
2013-11-01 17:23:08 +00:00
|
|
|
var refreshed = false;
|
|
|
|
if(changedTiddlers[this.stateTitle]) {
|
|
|
|
this.updateState();
|
|
|
|
refreshed = true;
|
|
|
|
}
|
|
|
|
return this.refreshChildren(changedTiddlers) || refreshed;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
Called by refresh() to dynamically show or hide the content
|
|
|
|
*/
|
|
|
|
RevealWidget.prototype.updateState = function() {
|
|
|
|
// Read the current state
|
|
|
|
this.readState();
|
|
|
|
// Construct the child nodes if needed
|
|
|
|
var domNode = this.domNodes[0];
|
|
|
|
if(this.isOpen && !this.hasChildNodes) {
|
|
|
|
this.hasChildNodes = true;
|
|
|
|
this.makeChildWidgets(this.parseTreeNode.children);
|
|
|
|
this.renderChildren(domNode,null);
|
|
|
|
}
|
|
|
|
// Animate our DOM node
|
|
|
|
if(!domNode.isTiddlyWikiFakeDom && this.type === "popup" && this.isOpen) {
|
|
|
|
this.positionPopup(domNode);
|
|
|
|
}
|
|
|
|
if(this.isOpen) {
|
|
|
|
domNode.removeAttribute("hidden");
|
2013-11-02 09:21:11 +00:00
|
|
|
$tw.anim.perform(this.openAnimation,domNode);
|
2013-11-01 17:23:08 +00:00
|
|
|
} else {
|
2013-11-02 09:21:11 +00:00
|
|
|
$tw.anim.perform(this.closeAnimation,domNode,{callback: function() {
|
2013-11-01 17:23:08 +00:00
|
|
|
domNode.setAttribute("hidden","true");
|
|
|
|
}});
|
2013-10-12 16:05:13 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
Remove any DOM nodes created by this widget or its children
|
|
|
|
*/
|
|
|
|
RevealWidget.prototype.removeChildDomNodes = function() {
|
|
|
|
$tw.utils.each(this.domNodes,function(domNode) {
|
|
|
|
domNode.parentNode.removeChild(domNode);
|
|
|
|
});
|
|
|
|
this.domNodes = [];
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.reveal = RevealWidget;
|
|
|
|
|
|
|
|
})();
|