diff --git a/core/modules/new_widgets/list.js b/core/modules/new_widgets/list.js index 38dcf08da..dec75687e 100755 --- a/core/modules/new_widgets/list.js +++ b/core/modules/new_widgets/list.js @@ -41,6 +41,9 @@ ListWidget.prototype.render = function(parent,nextSibling) { this.computeAttributes(); this.execute(); this.renderChildren(parent,nextSibling); + // Construct the storyview + var StoryView = this.storyViews[this.storyViewName]; + this.storyview = StoryView ? new StoryView(this) : null; }; /* @@ -69,9 +72,6 @@ ListWidget.prototype.execute = function() { this.makeChildWidgets(members); // Clear the last history this.history = []; - // Construct the storyview - var StoryView = this.storyViews[this.storyViewName]; - this.storyview = StoryView ? new StoryView(this) : null; }; ListWidget.prototype.getTiddlerList = function() { diff --git a/core/modules/new_widgets/widget.js b/core/modules/new_widgets/widget.js index 9b4e25146..6714c722c 100755 --- a/core/modules/new_widgets/widget.js +++ b/core/modules/new_widgets/widget.js @@ -293,6 +293,32 @@ Widget.prototype.makeChildWidget = function(parseTreeNode) { }); }; +/* +Get the next sibling of this widget +*/ +Widget.prototype.nextSibling = function() { + if(this.parentWidget) { + var index = this.parentWidget.children.indexOf(this); + if(index !== -1 && index < this.parentWidget.children.length-1) { + return this.parentWidget.children[index+1]; + } + } + return null; +}; + +/* +Get the previous sibling of this widget +*/ +Widget.prototype.previousSibling = function() { + if(this.parentWidget) { + var index = this.parentWidget.children.indexOf(this); + if(index !== -1 && index > 0) { + return this.parentWidget.children[index-1]; + } + } + return null; +}; + /* Render the children of this widget into the DOM */ diff --git a/core/modules/storyviews/zoomin.js b/core/modules/storyviews/zoomin.js new file mode 100644 index 000000000..495090bb2 --- /dev/null +++ b/core/modules/storyviews/zoomin.js @@ -0,0 +1,173 @@ +/*\ +title: $:/core/modules/storyviews/zoomin.js +type: application/javascript +module-type: storyview + +Zooms between individual tiddlers + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +var ZoominListView = function(listWidget) { + var self = this; + this.listWidget = listWidget; + // Make all the tiddlers position absolute, and hide all but the first one + $tw.utils.each(this.listWidget.children,function(itemWidget,index) { + var domNode = itemWidget.findFirstDomNode(); + if(index) { + domNode.style.display = "none"; + } else { + self.currentTiddlerDomNode = domNode; + } + domNode.style.position = "absolute"; + }); +} + +function findTitleWidget() { + return null; +} + +ZoominListView.prototype.navigateTo = function(historyInfo) { + var duration = $tw.utils.getAnimationDuration(), + listElementIndex = this.listWidget.findListItem(0,historyInfo.title); + if(listElementIndex === undefined) { + return; + } + var listItemWidget = this.listWidget.children[listElementIndex], + targetElement = listItemWidget.findFirstDomNode(); + // Make the new tiddler be position absolute and visible so that we can measure it + $tw.utils.setStyle(targetElement,[ + {position: "absolute"}, + {display: "block"}, + {transformOrigin: "0 0"}, + {transform: "translateX(0px) translateY(0px) scale(1)"}, + {transition: "none"}, + {opacity: "0.0"} + ]); + // Get the position of the source node, or use the centre of the window as the source position + var sourceBounds = historyInfo.fromPageRect || { + left: window.innerWidth/2 - 2, + top: window.innerHeight/2 - 2, + width: window.innerWidth/8, + height: window.innerHeight/8 + }; + // Try to find the title node in the target tiddler + var titleWidget = findTitleWidget(listItemWidget) || listItemWidget, + zoomBounds = titleWidget.findFirstDomNode().getBoundingClientRect(); + // Compute the transform for the target tiddler to make the title lie over the source rectange + var targetBounds = targetElement.getBoundingClientRect(), + scale = sourceBounds.width / zoomBounds.width, + x = sourceBounds.left - targetBounds.left - (zoomBounds.left - targetBounds.left) * scale, + y = sourceBounds.top - targetBounds.top - (zoomBounds.top - targetBounds.top) * scale; + // Transform the target tiddler to its starting position + $tw.utils.setStyle(targetElement,[ + {transform: "translateX(" + x + "px) translateY(" + y + "px) scale(" + scale + ")"} + ]); + // Force layout + $tw.utils.forceLayout(targetElement); + // Apply the ending transitions with a timeout to ensure that the previously applied transformations are applied first + var self = this, + prevCurrentTiddler = this.currentTiddlerDomNode; + this.currentTiddlerDomNode = targetElement; + // Transform the target tiddler to its natural size + $tw.utils.setStyle(targetElement,[ + {transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms ease-in, opacity " + duration + "ms ease-in"}, + {opacity: "1.0"}, + {transform: "translateX(0px) translateY(0px) scale(1)"}, + {zIndex: "500"}, + ]); + // Transform the previous tiddler out of the way and then hide it + if(prevCurrentTiddler && prevCurrentTiddler !== targetElement) { + var scale = zoomBounds.width / sourceBounds.width; + x = zoomBounds.left - targetBounds.left - (sourceBounds.left - targetBounds.left) * scale; + y = zoomBounds.top - targetBounds.top - (sourceBounds.top - targetBounds.top) * scale; + $tw.utils.setStyle(prevCurrentTiddler,[ + {transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms ease-in, opacity " + duration + "ms ease-in"}, + {opacity: "0.0"}, + {transformOrigin: "0 0"}, + {transform: "translateX(" + x + "px) translateY(" + y + "px) scale(" + scale + ")"}, + {zIndex: "0"} + ]); + // Hide the tiddler when the transition has finished + setTimeout(function() { + if(self.currentTiddlerDomNode !== prevCurrentTiddler) { + prevCurrentTiddler.style.display = "none"; + } + },duration); + } + // Scroll the target into view +// $tw.pageScroller.scrollIntoView(targetElement); +}; + +ZoominListView.prototype.insert = function(widget) { + var targetElement = widget.findFirstDomNode(); + // Make the newly inserted node position absolute and hidden + $tw.utils.setStyle(targetElement,[ + {display: "none"}, + {position: "absolute"} + ]); +}; + +ZoominListView.prototype.remove = function(widget) { + var targetElement = widget.findFirstDomNode(), + duration = $tw.utils.getAnimationDuration(); + // Set up the tiddler that is being closed + $tw.utils.setStyle(targetElement,[ + {position: "absolute"}, + {display: "block"}, + {transformOrigin: "50% 50%"}, + {transform: "translateX(0px) translateY(0px) scale(1)"}, + {transition: "none"}, + {zIndex: "0"} + ]); + // We'll move back to the previous or next element in the story + var toWidget = widget.previousSibling(); + if(!toWidget) { + toWidget = widget.nextSibling(); + } + var toWidgetDomNode = toWidget && toWidget.findFirstDomNode(); + // Set up the tiddler we're moving back in + if(toWidgetDomNode) { + $tw.utils.setStyle(toWidgetDomNode,[ + {position: "absolute"}, + {display: "block"}, + {transformOrigin: "50% 50%"}, + {transform: "translateX(0px) translateY(0px) scale(10)"}, + {transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms ease-in, opacity " + duration + "ms ease-in"}, + {opacity: "0"}, + {zIndex: "500"} + ]); + this.currentTiddlerDomNode = toWidgetDomNode; + } + // Animate them both + // Force layout + $tw.utils.forceLayout(this.listWidget.parentDomNode); + // First, the tiddler we're closing + $tw.utils.setStyle(targetElement,[ + {transformOrigin: "50% 50%"}, + {transform: "translateX(0px) translateY(0px) scale(0.1)"}, + {transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms ease-in, opacity " + duration + "ms ease-in"}, + {opacity: "0"}, + {zIndex: "0"} + ]); + setTimeout(function() { + // Delete the DOM node when the transition is over + widget.removeChildDomNodes(); + },duration); + // Now the tiddler we're going back to + if(toWidgetDomNode) { + $tw.utils.setStyle(toWidgetDomNode,[ + {transform: "translateX(0px) translateY(0px) scale(1)"}, + {opacity: "1"} + ]); + } + return true; // Indicate that we'll delete the DOM node +}; + +exports.zoomin = ZoominListView; + +})(); \ No newline at end of file diff --git a/themes/tiddlywiki/snowwhite/ThemeTweaks.tid b/themes/tiddlywiki/snowwhite/ThemeTweaks.tid index b3d2a0ef2..942b64887 100644 --- a/themes/tiddlywiki/snowwhite/ThemeTweaks.tid +++ b/themes/tiddlywiki/snowwhite/ThemeTweaks.tid @@ -34,4 +34,5 @@ You can tweak certain aspects of the ''Snow White'' theme. * Story top position //(the distance between the top of the screen ad the top margin of the story river or tiddler area)//: <$edit-text tiddler="$:/themes/tiddlywiki/snowwhite/metrics" index="storytop" default="" tag="input"/> * Story right //(the distance between the left side of the screen and the left margin of the sidebar area)//: <$edit-text tiddler="$:/themes/tiddlywiki/snowwhite/metrics" index="storyright" default="" tag="input"/> * Story width //(the width of the story river or tiddler area)//: <$edit-text tiddler="$:/themes/tiddlywiki/snowwhite/metrics" index="storywidth" default="" tag="input"/> +* Tiddler width //(the width of individual tiddlers -- used for zoomin storyview)//: <$edit-text tiddler="$:/themes/tiddlywiki/snowwhite/metrics" index="tiddlerwidth" default="" tag="input"/> diff --git a/themes/tiddlywiki/snowwhite/base.tid b/themes/tiddlywiki/snowwhite/base.tid index 5d4978311..f4d6bc800 100644 --- a/themes/tiddlywiki/snowwhite/base.tid +++ b/themes/tiddlywiki/snowwhite/base.tid @@ -366,6 +366,7 @@ a.tw-tiddlylink-external { } .story-river { + position: relative; padding: 0; } } @@ -385,7 +386,7 @@ a.tw-tiddlylink-external { } .story-river { - position: absolute; + position: relative; left: {{$:/themes/tiddlywiki/snowwhite/metrics##storyleft}}; top: {{$:/themes/tiddlywiki/snowwhite/metrics##storytop}}; width: {{$:/themes/tiddlywiki/snowwhite/metrics##storywidth}}; @@ -408,6 +409,7 @@ a.tw-tiddlylink-external { */ .tw-tiddler-frame { + width: {{$:/themes/tiddlywiki/snowwhite/metrics##tiddlerwidth}}; margin-bottom: 28px; background-color: {{$:/themes/tiddlywiki/snowwhite/colourmappings##tiddlerbackground}}; } diff --git a/themes/tiddlywiki/snowwhite/metrics.tid b/themes/tiddlywiki/snowwhite/metrics.tid index b4d40cedb..356a5e4c3 100644 --- a/themes/tiddlywiki/snowwhite/metrics.tid +++ b/themes/tiddlywiki/snowwhite/metrics.tid @@ -7,3 +7,4 @@ storyleft: `0px` storytop: `0px` storyright: `770px` storywidth: `770px` +tiddlerwidth: `686px`