diff --git a/editions/tw5.com/tiddlywiki.info b/editions/tw5.com/tiddlywiki.info index e7571e22f..781ce12a5 100644 --- a/editions/tw5.com/tiddlywiki.info +++ b/editions/tw5.com/tiddlywiki.info @@ -1,5 +1,6 @@ { "plugins": [ + "tiddlywiki/cecily", "tiddlywiki/fullscreen", "tiddlywiki/googleanalytics", "tiddlywiki/nodewebkitsaver", diff --git a/plugins/tiddlywiki/cecily/cecily.js b/plugins/tiddlywiki/cecily/cecily.js new file mode 100644 index 000000000..84c331182 --- /dev/null +++ b/plugins/tiddlywiki/cecily/cecily.js @@ -0,0 +1,143 @@ +/*\ +title: $:/plugins/tiddlywiki/cecily/cecily.js +type: application/javascript +module-type: storyview + +Positions tiddlers on a 2D map + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +var CecilyStoryView = function(listWidget) { + var self = this; + this.listWidget = listWidget; + // Load the map + this.loadMap(); + // Position the existing tiddlers + $tw.utils.each(this.listWidget.children,function(itemWidget,index) { + var domNode = itemWidget.findFirstDomNode(); + domNode.style.position = "absolute"; + var title = itemWidget.parseTreeNode.itemTitle; + self.positionTiddler(title,domNode); + }); +}; + +CecilyStoryView.prototype.navigateTo = function(historyInfo) { + var listElementIndex = this.listWidget.findListItem(0,historyInfo.title); + if(listElementIndex === undefined) { + return; + } + var listItemWidget = this.listWidget.children[listElementIndex], + targetElement = listItemWidget.findFirstDomNode(); + // Scroll the node into view + this.listWidget.dispatchEvent({type: "tw-scroll", target: targetElement}); +}; + +CecilyStoryView.prototype.insert = function(widget) { + var domNode = widget.findFirstDomNode(), + duration = $tw.utils.getAnimationDuration(); + // Make the newly inserted node position absolute + $tw.utils.setStyle(domNode,[ + {position: "absolute"}, + {transition: ""}, + {opacity: "0.0"} + ]); + // Position it + var title = widget.parseTreeNode.itemTitle; + this.positionTiddler(title,domNode); + $tw.utils.forceLayout(domNode); + // Animate it in + $tw.utils.setStyle(domNode,[ + {transition: "opacity " + duration + "ms ease-out"}, + {opacity: "1.0"} + ]); +}; + +CecilyStoryView.prototype.remove = function(widget) { + var targetElement = widget.findFirstDomNode(), + duration = $tw.utils.getAnimationDuration(); + // Remove the widget at the end of the transition + setTimeout(function() { + widget.removeChildDomNodes(); + },duration); + // Animate the closure + $tw.utils.setStyle(targetElement,[ + {transition: "none"}, + {opacity: "1.0"} + ]); + $tw.utils.forceLayout(targetElement); + $tw.utils.setStyle(targetElement,[ + {transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms ease-in-out, " + + "opacity " + duration + "ms ease-in-out"}, + {transform: "scale(0.01)"}, + {opacity: "0.0"} + ]); +}; + +/* +Load the current map +*/ +CecilyStoryView.prototype.loadMap = function() { + this.map = this.listWidget.wiki.getTiddlerData(this.getMapTiddlerTitle(),{ + positions: {}, + newTiddlerPosition: {x: 0, y: 0} + }); +}; + +CecilyStoryView.prototype.getMapTiddlerTitle = function() { + return this.listWidget.getAttribute("map","$:/TiddlerMap"); +}; + +/* +Position a tiddler according to the map +*/ +CecilyStoryView.prototype.positionTiddler = function(title,domNode) { + var pos = this.lookupTiddlerInMap(title,domNode), + scale = pos.w/domNode.offsetWidth; + $tw.utils.setStyle(domNode,[ + {transformOrigin: "0% 0%"}, + {transform: "translateX(" + pos.x + "px) translateY(" + pos.y + "px) scale(" + scale + ")"} + ]); +}; + +// Get the position of a particular tiddler +CecilyStoryView.prototype.lookupTiddlerInMap = function(title,domNode) { + // If this is a draft tiddler then look for the position of the original tiddler + var tiddler = this.listWidget.wiki.getTiddler(title); + if(tiddler) { + var draftOf = tiddler.fields["draft.of"]; + if(draftOf && this.map.positions[draftOf]) { + return this.map.positions[draftOf] + } + } + // Try looking the target tiddler 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: 200, + h: 200 + }; + this.map.newTiddlerPosition.x += newPosition.w * 1.1; + 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; + return newPosition; +}; + +exports.cecily = CecilyStoryView; + +})(); diff --git a/plugins/tiddlywiki/cecily/plugin.info b/plugins/tiddlywiki/cecily/plugin.info new file mode 100644 index 000000000..1463a4a58 --- /dev/null +++ b/plugins/tiddlywiki/cecily/plugin.info @@ -0,0 +1,6 @@ +{ + "title": "$:/plugins/tiddlywiki/cecily", + "description": "Zoomable User Interface for TiddlyWiki", + "author": "JeremyRuston", + "core-version": ">=5.0.0" +}