mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-12-24 17:10:29 +00:00
Lots of fixes to storyview mechanism
And a new scroller mechanism
This commit is contained in:
parent
a21d96adc1
commit
f412dd19d9
@ -17,8 +17,6 @@ exports.info = {
|
|||||||
params: {
|
params: {
|
||||||
story: {byName: "default", type: "text"}, // Actually a tiddler, but we don't want it to be a dependency
|
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
|
history: {byName: "default", type: "text"}, // Actually a tiddler, but we don't want it to be a dependency
|
||||||
defaultViewTemplate: {byName: true, type: "tiddler"},
|
|
||||||
defaultEditTemplate: {byName: true, type: "tiddler"},
|
|
||||||
set: {byName: true, type: "tiddler"}
|
set: {byName: true, type: "tiddler"}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -64,8 +62,7 @@ exports.eventMap["tw-navigate"] = function(event) {
|
|||||||
// Update the story tiddler if specified
|
// Update the story tiddler if specified
|
||||||
if(this.hasParameter("story")) {
|
if(this.hasParameter("story")) {
|
||||||
this.getStory();
|
this.getStory();
|
||||||
var template = this.params.defaultViewTemplate || "$:/templates/ViewTemplate",
|
var t,tiddler,slot;
|
||||||
t,tiddler,slot;
|
|
||||||
// See if the tiddler is already there
|
// See if the tiddler is already there
|
||||||
for(t=0; t<this.story.tiddlers.length; t++) {
|
for(t=0; t<this.story.tiddlers.length; t++) {
|
||||||
if(this.story.tiddlers[t].title === event.navigateTo) {
|
if(this.story.tiddlers[t].title === event.navigateTo) {
|
||||||
@ -102,13 +99,46 @@ exports.eventMap["tw-navigate"] = function(event) {
|
|||||||
this.history.stack.push({
|
this.history.stack.push({
|
||||||
title: event.navigateTo,
|
title: event.navigateTo,
|
||||||
fromTitle: event.navigateFromTitle,
|
fromTitle: event.navigateFromTitle,
|
||||||
fromPosition: event.navigateFrom.getNodeBounds()
|
fromPosition: event.navigateFrom.getNodeBounds(),
|
||||||
|
scrollPosition: $tw.utils.getScrollPosition()
|
||||||
});
|
});
|
||||||
this.saveHistory();
|
this.saveHistory();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Navigate to a specified tiddler
|
||||||
|
exports.eventMap["tw-NavigateBack"] = function(event) {
|
||||||
|
// Pop a record record off the top of the history stack
|
||||||
|
this.getHistory();
|
||||||
|
if(this.history.stack.length < 2) {
|
||||||
|
return false; // Bail if there is not enough entries on the history stack
|
||||||
|
}
|
||||||
|
var fromHistoryInfo = this.history.stack.pop(),
|
||||||
|
toHistoryInfo = this.history.stack[this.history.stack.length-1];
|
||||||
|
this.saveHistory();
|
||||||
|
// Make sure that the tiddler we're navigating back to is open in the story
|
||||||
|
if(this.hasParameter("story") && toHistoryInfo) {
|
||||||
|
this.getStory();
|
||||||
|
var t,tiddler,slot;
|
||||||
|
// See if the tiddler is already there
|
||||||
|
for(t=0; t<this.story.tiddlers.length; t++) {
|
||||||
|
if(this.story.tiddlers[t].title === toHistoryInfo.title) {
|
||||||
|
tiddler = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If not we need to add it
|
||||||
|
if(tiddler === undefined) {
|
||||||
|
// Add the tiddler
|
||||||
|
this.story.tiddlers.splice(slot,0,{title: toHistoryInfo.title});
|
||||||
|
// Save the story
|
||||||
|
this.saveStory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event.stopPropagation();
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
// Place a tiddler in edit mode
|
// Place a tiddler in edit mode
|
||||||
exports.eventMap["tw-EditTiddler"] = function(event) {
|
exports.eventMap["tw-EditTiddler"] = function(event) {
|
||||||
if(this.hasParameter("story")) {
|
if(this.hasParameter("story")) {
|
||||||
@ -204,7 +234,7 @@ exports.executeMacro = function() {
|
|||||||
this.content[t].execute(this.parents,this.tiddlerTitle);
|
this.content[t].execute(this.parents,this.tiddlerTitle);
|
||||||
}
|
}
|
||||||
return $tw.Tree.Element("div",attributes,this.content,{
|
return $tw.Tree.Element("div",attributes,this.content,{
|
||||||
events: ["tw-navigate","tw-EditTiddler","tw-SaveTiddler","tw-CloseTiddler"],
|
events: ["tw-navigate","tw-EditTiddler","tw-SaveTiddler","tw-CloseTiddler","tw-NavigateBack"],
|
||||||
eventHandler: this
|
eventHandler: this
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -19,7 +19,11 @@ And the history tiddler is the stack of tiddlers that were navigated to in turn:
|
|||||||
|
|
||||||
{
|
{
|
||||||
stack: [
|
stack: [
|
||||||
{title: <string>}
|
{
|
||||||
|
title: <string>,
|
||||||
|
fromTitle: <string>,
|
||||||
|
fromPosition: {bottom: <num>, height: <num>, top: <num>, right: <num>, left: <num>, width: <num>}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,6 +136,9 @@ exports.removeStoryElement = function(storyElementIndex) {
|
|||||||
// Only delete the DOM element if the storyview.remove() returned false
|
// Only delete the DOM element if the storyview.remove() returned false
|
||||||
storyElement.domNode.parentNode.removeChild(storyElement.domNode);
|
storyElement.domNode.parentNode.removeChild(storyElement.domNode);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Always delete the story element if we didn't invoke the storyview
|
||||||
|
storyElement.domNode.parentNode.removeChild(storyElement.domNode);
|
||||||
}
|
}
|
||||||
// Then delete the actual renderer node
|
// Then delete the actual renderer node
|
||||||
this.storyNode.children.splice(storyElementIndex,1);
|
this.storyNode.children.splice(storyElementIndex,1);
|
||||||
@ -169,8 +176,10 @@ exports.executeMacro = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
exports.postRenderInDom = function() {
|
exports.postRenderInDom = function() {
|
||||||
// Reset the record of the previous history stack
|
// Get the history object and use it to set the previous history
|
||||||
this.prevHistory = {stack: []};
|
this.getHistory();
|
||||||
|
this.prevHistory = this.history;
|
||||||
|
this.history = null;
|
||||||
// Instantiate the story view
|
// Instantiate the story view
|
||||||
var storyviewName;
|
var storyviewName;
|
||||||
if(this.hasParameter("storyviewTiddler")) {
|
if(this.hasParameter("storyviewTiddler")) {
|
||||||
@ -278,7 +287,7 @@ exports.processHistoryChange = function() {
|
|||||||
// Read the history tiddler
|
// Read the history tiddler
|
||||||
this.getHistory();
|
this.getHistory();
|
||||||
if(this.storyview) {
|
if(this.storyview) {
|
||||||
var t,index,
|
var t,indexTo,indexFrom,
|
||||||
topCommon = Math.min(this.history.stack.length,this.prevHistory.stack.length);
|
topCommon = Math.min(this.history.stack.length,this.prevHistory.stack.length);
|
||||||
// Find the common heritage of the new history stack and the previous one
|
// Find the common heritage of the new history stack and the previous one
|
||||||
for(t=0; t<topCommon; t++) {
|
for(t=0; t<topCommon; t++) {
|
||||||
@ -289,16 +298,21 @@ exports.processHistoryChange = function() {
|
|||||||
}
|
}
|
||||||
// We now navigate backwards through the previous history to get back to the common ancestor
|
// We now navigate backwards through the previous history to get back to the common ancestor
|
||||||
for(t=this.prevHistory.stack.length-1; t>=topCommon; t--) {
|
for(t=this.prevHistory.stack.length-1; t>=topCommon; t--) {
|
||||||
index = this.findStoryElementByTitle(0,this.prevHistory.stack[t].title);
|
indexTo = this.findStoryElementByTitle(0,this.prevHistory.stack[t].fromTitle);
|
||||||
if(index !== undefined && this.storyview.navigateBack) {
|
indexFrom = this.findStoryElementByTitle(0,this.prevHistory.stack[t].title);
|
||||||
this.storyview.navigateBack(this.storyNode.children[index],this.history.stack[t]);
|
// Call the story view if it defines a navigateBack() method
|
||||||
|
if(indexTo !== undefined && indexFrom !== undefined && this.storyview.navigateBack) {
|
||||||
|
this.storyview.navigateBack(this.storyNode.children[indexTo],this.storyNode.children[indexFrom],this.prevHistory.stack[t]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// And now we navigate forwards through the new history to get to the latest tiddler
|
// And now we navigate forwards through the new history to get to the latest tiddler
|
||||||
for(t=topCommon; t<this.history.stack.length; t++) {
|
for(t=topCommon; t<this.history.stack.length; t++) {
|
||||||
index = this.findStoryElementByTitle(0,this.history.stack[t].title);
|
indexTo = this.findStoryElementByTitle(0,this.history.stack[t].title);
|
||||||
if(index !== undefined && this.storyview.navigateForward) {
|
indexFrom = this.findStoryElementByTitle(0,this.history.stack[t].fromTitle);
|
||||||
this.storyview.navigateForward(this.storyNode.children[index],this.history.stack[t]);
|
if(indexTo !== undefined && this.storyview.navigateForward) {
|
||||||
|
this.storyview.navigateForward(this.storyNode.children[indexTo],
|
||||||
|
indexFrom !== undefined ? this.storyNode.children[indexFrom] : undefined,
|
||||||
|
this.history.stack[t]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ ClassicScroller.prototype.remove = function(storyElementNode) {
|
|||||||
}
|
}
|
||||||
},false);
|
},false);
|
||||||
// Animate the closure
|
// Animate the closure
|
||||||
var d = ($tw.config.preferences.animationDuration/1000).toFixed(8) + "s";
|
var d = $tw.config.preferences.animationDuration + "ms";
|
||||||
wrapperElement.style[$tw.browser.transition] = "-" + $tw.browser.prefix.toLowerCase() + "-transform " + d + " ease-in-out, " +
|
wrapperElement.style[$tw.browser.transition] = "-" + $tw.browser.prefix.toLowerCase() + "-transform " + d + " ease-in-out, " +
|
||||||
"opacity " + d + " ease-out, " +
|
"opacity " + d + " ease-out, " +
|
||||||
"height " + d + " ease-in-out";
|
"height " + d + " ease-in-out";
|
||||||
@ -48,12 +48,12 @@ ClassicScroller.prototype.remove = function(storyElementNode) {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
ClassicScroller.prototype.navigateBack = function(storyElementNode,historyInfo) {
|
ClassicScroller.prototype.navigateBack = function(toStoryElement,fromStoryElement,historyInfo) {
|
||||||
$tw.utils.scrollIntoView(storyElementNode.domNode);
|
$tw.scroller.scrollIntoView(toStoryElement.domNode);
|
||||||
};
|
};
|
||||||
|
|
||||||
ClassicScroller.prototype.navigateForward = function(storyElementNode,historyInfo) {
|
ClassicScroller.prototype.navigateForward = function(toStoryElement,fromStoryElement,historyInfo) {
|
||||||
$tw.utils.scrollIntoView(storyElementNode.domNode);
|
$tw.scroller.scrollIntoView(toStoryElement.domNode);
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.classic = ClassicScroller;
|
exports.classic = ClassicScroller;
|
||||||
|
@ -30,13 +30,23 @@ function SidewaysView(story) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Visualise navigation to a new tiddler
|
||||||
|
toStoryElementNode: tree node of the tiddler macro we're navigating to
|
||||||
|
fromStoryElementNode: optionally, tree node of the tiddler we're navigating from
|
||||||
|
historyInfo: record from the history tiddler corresponding to this navigation
|
||||||
|
*/
|
||||||
|
SidewaysView.prototype.navigateForward = function(toStoryElement,fromStoryElement,historyInfo) {
|
||||||
|
$tw.scroller.scrollIntoView(toStoryElement.domNode);
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Visualise insertion of the specified tiddler macro, optionally specifying a source node for the visualisation
|
Visualise insertion of the specified tiddler macro, optionally specifying a source node for the visualisation
|
||||||
storyElementNode: tree node of the tiddler macro we're navigating to
|
storyElementNode: tree node of the tiddler macro we're navigating to
|
||||||
*/
|
*/
|
||||||
SidewaysView.prototype.insert = function(storyElementNode) {
|
SidewaysView.prototype.insert = function(storyElementNode) {
|
||||||
setStoryElementStyles(storyElementNode.domNode);
|
setStoryElementStyles(storyElementNode.domNode);
|
||||||
$tw.utils.scrollIntoView(storyElementNode.domNode);
|
$tw.scroller.scrollIntoView(storyElementNode.domNode);
|
||||||
};
|
};
|
||||||
|
|
||||||
SidewaysView.prototype.remove = function(storyElementNode) {
|
SidewaysView.prototype.remove = function(storyElementNode) {
|
||||||
@ -48,7 +58,7 @@ SidewaysView.prototype.remove = function(storyElementNode) {
|
|||||||
targetElement.parentNode.insertBefore(wrapperElement,targetElement);
|
targetElement.parentNode.insertBefore(wrapperElement,targetElement);
|
||||||
wrapperElement.appendChild(targetElement);
|
wrapperElement.appendChild(targetElement);
|
||||||
// Animate the closure
|
// Animate the closure
|
||||||
var d = ($tw.config.preferences.animationDuration/1000).toFixed(8) + "s";
|
var d = $tw.config.preferences.animationDuration + "ms";
|
||||||
wrapperElement.style.display = "inline-block";
|
wrapperElement.style.display = "inline-block";
|
||||||
wrapperElement.style[$tw.browser.transformorigin] = "0% 0%";
|
wrapperElement.style[$tw.browser.transformorigin] = "0% 0%";
|
||||||
wrapperElement.style[$tw.browser.transform] = "translateY(0px)";
|
wrapperElement.style[$tw.browser.transform] = "translateY(0px)";
|
||||||
|
@ -3,7 +3,11 @@ title: $:/core/modules/macros/story/views/zoomin.js
|
|||||||
type: application/javascript
|
type: application/javascript
|
||||||
module-type: storyview
|
module-type: storyview
|
||||||
|
|
||||||
A storyview that shows a single tiddler and navigates by zooming into links
|
A storyview that shows a single tiddler and navigates by zooming into links.
|
||||||
|
|
||||||
|
To do this, the story wrapper is set to `position:relative` and then each of the story elements to `position:absolute`. This results in all of the tiddlers being stacked on top of one another flush with the top left of the story wrapper.
|
||||||
|
|
||||||
|
Navigating between tiddlers is accomplished by switching the story nodes between `display:block` and `display:none`, but the implementation is considerably more complex due to the animation.
|
||||||
|
|
||||||
\*/
|
\*/
|
||||||
(function(){
|
(function(){
|
||||||
@ -16,6 +20,8 @@ function Zoomin(story) {
|
|||||||
// Save the story
|
// Save the story
|
||||||
this.story = story;
|
this.story = story;
|
||||||
this.storyNode = this.story.child.domNode;
|
this.storyNode = this.story.child.domNode;
|
||||||
|
// Set the current tiddler
|
||||||
|
this.currentTiddler = this.story.child.children[0];
|
||||||
// Make all the tiddlers position absolute, and hide all but the first one
|
// Make all the tiddlers position absolute, and hide all but the first one
|
||||||
this.storyNode.style.position = "relative";
|
this.storyNode.style.position = "relative";
|
||||||
for(var t=0; t<this.storyNode.children.length; t++) {
|
for(var t=0; t<this.storyNode.children.length; t++) {
|
||||||
@ -24,10 +30,6 @@ function Zoomin(story) {
|
|||||||
}
|
}
|
||||||
this.storyNode.children[t].style.position = "absolute";
|
this.storyNode.children[t].style.position = "absolute";
|
||||||
}
|
}
|
||||||
// Record the current tiddler node
|
|
||||||
this.currTiddler = this.story.child.children[0];
|
|
||||||
// Set up the stack of previously viewed tiddlers
|
|
||||||
this.prevTiddlers = [this.currTiddler.children[0].params.target];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -55,128 +57,120 @@ function findTitleNode(node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Visualise removal of the the specified tiddler macro, optionally specifying a source node for the visualisation
|
Visualise navigation to a new tiddler
|
||||||
storyElementNode: tree node of the tiddler macro we're navigating to
|
toStoryElementNode: tree node of the tiddler macro we're navigating to
|
||||||
|
fromStoryElementNode: optionally, tree node of the tiddler we're navigating from
|
||||||
|
historyInfo: record from the history tiddler corresponding to this navigation
|
||||||
*/
|
*/
|
||||||
Zoomin.prototype.navigateForward = function(storyElementNode,historyInfo) {
|
Zoomin.prototype.navigateForward = function(toStoryElement,fromStoryElement,historyInfo) {
|
||||||
// Do nothing if the target tiddler is already the current tiddler
|
// Make the new tiddler be position absolute and visible so that we can measure it
|
||||||
if(storyElementNode === this.currTiddler) {
|
toStoryElement.domNode.style.position = "absolute";
|
||||||
return;
|
toStoryElement.domNode.style.display = "block";
|
||||||
}
|
toStoryElement.domNode.style[$tw.browser.transformorigin] = "0 0";
|
||||||
// Make the new tiddler be position absolute and visible
|
toStoryElement.domNode.style[$tw.browser.transform] = "translateX(0px) translateY(0px) scale(1)";
|
||||||
storyElementNode.domNode.style.position = "absolute";
|
toStoryElement.domNode.style[$tw.browser.transition] = "none";
|
||||||
storyElementNode.domNode.style.display = "block";
|
toStoryElement.domNode.style.opacity = "0.0";
|
||||||
storyElementNode.domNode.style[$tw.browser.transformorigin] = "0 0";
|
|
||||||
storyElementNode.domNode.style[$tw.browser.transform] = "translateX(0px) translateY(0px) scale(1)";
|
|
||||||
storyElementNode.domNode.style[$tw.browser.transition] = "none";
|
|
||||||
// Get the position of the source node, or use the centre of the window as the source position
|
// Get the position of the source node, or use the centre of the window as the source position
|
||||||
var sourceBounds = historyInfo.fromPosition || {
|
var sourceBounds = historyInfo.fromPosition || {
|
||||||
left: window.innerWidth/2 - 2,
|
left: window.innerWidth/2 - 2,
|
||||||
top: window.innerHeight/2 - 2,
|
top: window.innerHeight/2 - 2,
|
||||||
width: 4,
|
width: window.innerWidth/8,
|
||||||
height: 4
|
height: window.innerHeight/8
|
||||||
};
|
};
|
||||||
// Try to find the title node in the target tiddler
|
// Try to find the title node in the target tiddler
|
||||||
var titleNode = findTitleNode(storyElementNode) || storyElementNode;
|
var titleNode = findTitleNode(toStoryElement) || toStoryElement,
|
||||||
|
titleBounds = titleNode.getNodeBounds();
|
||||||
// Compute the transform for the target tiddler to make the title lie over the source rectange
|
// Compute the transform for the target tiddler to make the title lie over the source rectange
|
||||||
var targetBounds = storyElementNode.getNodeBounds(),
|
var targetBounds = toStoryElement.getNodeBounds(),
|
||||||
titleBounds = titleNode.getNodeBounds(),
|
|
||||||
scale = sourceBounds.width / titleBounds.width,
|
scale = sourceBounds.width / titleBounds.width,
|
||||||
x = sourceBounds.left - targetBounds.left - (titleBounds.left - targetBounds.left) * scale,
|
x = sourceBounds.left - targetBounds.left - (titleBounds.left - targetBounds.left) * scale,
|
||||||
y = sourceBounds.top - targetBounds.top - (titleBounds.top - targetBounds.top) * scale;
|
y = sourceBounds.top - targetBounds.top - (titleBounds.top - targetBounds.top) * scale;
|
||||||
// Transform the target tiddler
|
// Transform the target tiddler to its starting position
|
||||||
storyElementNode.domNode.style[$tw.browser.transform] = "translateX(" + x + "px) translateY(" + y + "px) scale(" + scale + ")";
|
toStoryElement.domNode.style[$tw.browser.transform] = "translateX(" + x + "px) translateY(" + y + "px) scale(" + scale + ")";
|
||||||
// Get the animation duration
|
// Get the animation duration
|
||||||
var d = ($tw.config.preferences.animationDuration/1000).toFixed(8) + "s";
|
var d = $tw.config.preferences.animationDuration + "ms";
|
||||||
// Apply the ending transitions with a timeout to ensure that the previously applied transformations are applied first
|
// Apply the ending transitions with a timeout to ensure that the previously applied transformations are applied first
|
||||||
var self = this,
|
var self = this,
|
||||||
currTiddler = this.currTiddler;
|
prevCurrentTiddler = this.currentTiddler;
|
||||||
|
this.currentTiddler = toStoryElement;
|
||||||
$tw.utils.nextTick(function() {
|
$tw.utils.nextTick(function() {
|
||||||
// Transform the target tiddler
|
// Transform the target tiddler to its natural size
|
||||||
var currTiddlerBounds = currTiddler.getNodeBounds(),
|
toStoryElement.domNode.style[$tw.browser.transition] = "-" + $tw.browser.prefix.toLowerCase() + "-transform " + d + " ease-in-out, opacity " + d + " ease-out";
|
||||||
x = (currTiddlerBounds.left - targetBounds.left),
|
toStoryElement.domNode.style.opacity = "1.0";
|
||||||
y = (currTiddlerBounds.top - targetBounds.top);
|
toStoryElement.domNode.style[$tw.browser.transform] = "translateX(0px) translateY(0px) scale(1)";
|
||||||
storyElementNode.domNode.style[$tw.browser.transition] = "-" + $tw.browser.prefix.toLowerCase() + "-transform " + d + " ease-in-out, opacity " + d + " ease-out";
|
toStoryElement.domNode.style.zIndex = "500";
|
||||||
storyElementNode.domNode.style.opacity = "1.0";
|
// Transform the previous tiddler out of the way and then hide it
|
||||||
storyElementNode.domNode.style[$tw.browser.transform] = "translateX(" + x + "px) translateY(" + y + "px) scale(1)";
|
if(prevCurrentTiddler && prevCurrentTiddler !== toStoryElement) {
|
||||||
storyElementNode.domNode.style.zIndex = "500";
|
var scale = titleBounds.width / sourceBounds.width;
|
||||||
// Transform the current tiddler
|
x = titleBounds.left - targetBounds.left - (sourceBounds.left - targetBounds.left) * scale;
|
||||||
var scale = titleBounds.width / sourceBounds.width;
|
y = titleBounds.top - targetBounds.top - (sourceBounds.top - targetBounds.top) * scale;
|
||||||
x = titleBounds.left - targetBounds.left - (sourceBounds.left - currTiddlerBounds.left) * scale;
|
prevCurrentTiddler.domNode.style[$tw.browser.transition] = "-" + $tw.browser.prefix.toLowerCase() + "-transform " + d + " ease-in-out, opacity " + d + " ease-out";
|
||||||
y = titleBounds.top - targetBounds.top - (sourceBounds.top - currTiddlerBounds.top) * scale;
|
prevCurrentTiddler.domNode.style.opacity = "0.0";
|
||||||
currTiddler.domNode.style[$tw.browser.transition] = "-" + $tw.browser.prefix.toLowerCase() + "-transform " + d + " ease-in-out, opacity " + d + " ease-out";
|
prevCurrentTiddler.domNode.style[$tw.browser.transformorigin] = "0 0";
|
||||||
currTiddler.domNode.style.opacity = "0.0";
|
prevCurrentTiddler.domNode.style[$tw.browser.transform] = "translateX(" + x + "px) translateY(" + y + "px) scale(" + scale + ")";
|
||||||
currTiddler.domNode.style[$tw.browser.transformorigin] = "0 0";
|
prevCurrentTiddler.domNode.style.zIndex = "0";
|
||||||
currTiddler.domNode.style[$tw.browser.transform] = "translateX(" + x + "px) translateY(" + y + "px) scale(" + scale + ")";
|
var eventHandler = function(event) {
|
||||||
currTiddler.domNode.style.zIndex = "0";
|
// Hide the DOM node when the transition is over
|
||||||
|
if(self.currentTiddler !== prevCurrentTiddler) {
|
||||||
|
prevCurrentTiddler.domNode.style.display = "none";
|
||||||
|
}
|
||||||
|
prevCurrentTiddler.domNode.removeEventListener($tw.browser.transitionEnd,eventHandler,true);
|
||||||
|
};
|
||||||
|
prevCurrentTiddler.domNode.addEventListener($tw.browser.transitionEnd,eventHandler,true);
|
||||||
|
}
|
||||||
|
// Scroll the target into view
|
||||||
|
$tw.scroller.scrollIntoView(toStoryElement.domNode);
|
||||||
});
|
});
|
||||||
// Record the new current tiddler
|
|
||||||
this.currTiddler = storyElementNode;
|
|
||||||
// Save the tiddler in the stack
|
|
||||||
this.prevTiddlers.push(storyElementNode.children[0].params.target);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Visualise removing a tiddler
|
Visualise navigating back to the previous tiddler
|
||||||
|
toStoryElement: story element being navigated back to
|
||||||
|
fromStoryElement: story element being navigated back from
|
||||||
|
historyInfo: member of the history stack[] array being navigated back through
|
||||||
*/
|
*/
|
||||||
Zoomin.prototype.remove = function(storyElementNode) {
|
Zoomin.prototype.navigateBack = function(toStoryElement,fromStoryElement,historyInfo) {
|
||||||
// Remove the last entry from the navigation stack, which will be to navigate to the current tiddler
|
|
||||||
this.prevTiddlers.pop();
|
|
||||||
// Find the top entry in the navigation stack that still exists
|
|
||||||
var storyElementIndex,storyElement;
|
|
||||||
while(this.prevTiddlers.length > 0) {
|
|
||||||
var title = this.prevTiddlers.pop();
|
|
||||||
storyElementIndex = this.story.findStoryElementByTitle(0,title);
|
|
||||||
if(storyElementIndex !== undefined) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(storyElementIndex !== undefined) {
|
|
||||||
storyElement = this.story.storyNode.children[storyElementIndex];
|
|
||||||
}
|
|
||||||
// Get the animation duration
|
// Get the animation duration
|
||||||
var d = ($tw.config.preferences.animationDuration/1000).toFixed(8) + "s";
|
var d = $tw.config.preferences.animationDuration + "ms";
|
||||||
// Set up the tiddler that is being closed
|
// Set up the tiddler that is being closed
|
||||||
storyElementNode.domNode.style.position = "absolute";
|
if(fromStoryElement) {
|
||||||
storyElementNode.domNode.style.display = "block";
|
fromStoryElement.domNode.style.position = "absolute";
|
||||||
storyElementNode.domNode.style[$tw.browser.transformorigin] = "50% 50%";
|
fromStoryElement.domNode.style.display = "block";
|
||||||
storyElementNode.domNode.style[$tw.browser.transform] = "translateX(0px) translateY(0px) scale(1)";
|
fromStoryElement.domNode.style[$tw.browser.transformorigin] = "50% 50%";
|
||||||
storyElementNode.domNode.style[$tw.browser.transition] = "none";
|
fromStoryElement.domNode.style[$tw.browser.transform] = "translateX(0px) translateY(0px) scale(1)";
|
||||||
storyElementNode.domNode.style.zIndex = "0";
|
fromStoryElement.domNode.style[$tw.browser.transition] = "none";
|
||||||
// Set up the tiddler we're moving back in
|
fromStoryElement.domNode.style.zIndex = "0";
|
||||||
if(storyElement !== undefined) {
|
|
||||||
storyElement.domNode.style.position = "absolute";
|
|
||||||
storyElement.domNode.style.display = "block";
|
|
||||||
storyElement.domNode.style[$tw.browser.transformorigin] = "50% 50%";
|
|
||||||
storyElement.domNode.style[$tw.browser.transform] = "translateX(0px) translateY(0px) scale(10)";
|
|
||||||
storyElement.domNode.style[$tw.browser.transition] = "-" + $tw.browser.prefix.toLowerCase() + "-transform " + d + " ease-in-out, opacity " + d + " ease-out";
|
|
||||||
storyElement.domNode.style.opacity = "0.0";
|
|
||||||
storyElement.domNode.style.zIndex = "500";
|
|
||||||
// Push the tiddler we're moving back to back on the stack
|
|
||||||
this.prevTiddlers.push(storyElement.children[0].params.target);
|
|
||||||
this.currTiddler = storyElement;
|
|
||||||
} else {
|
|
||||||
this.currTiddler = null;
|
|
||||||
}
|
}
|
||||||
|
// Set up the tiddler we're moving back in
|
||||||
|
toStoryElement.domNode.style.position = "absolute";
|
||||||
|
toStoryElement.domNode.style.display = "block";
|
||||||
|
toStoryElement.domNode.style[$tw.browser.transformorigin] = "50% 50%";
|
||||||
|
toStoryElement.domNode.style[$tw.browser.transform] = "translateX(0px) translateY(0px) scale(10)";
|
||||||
|
toStoryElement.domNode.style[$tw.browser.transition] = "-" + $tw.browser.prefix.toLowerCase() + "-transform " + d + " ease-in-out, opacity " + d + " ease-out";
|
||||||
|
toStoryElement.domNode.style.opacity = "0.0";
|
||||||
|
toStoryElement.domNode.style.zIndex = "500";
|
||||||
|
this.currentTiddler = toStoryElement;
|
||||||
// Animate them both
|
// Animate them both
|
||||||
$tw.utils.nextTick(function() {
|
$tw.utils.nextTick(function() {
|
||||||
// First, the tiddler we're closing
|
// First, the tiddler we're closing
|
||||||
storyElementNode.domNode.style[$tw.browser.transition] = "-" + $tw.browser.prefix.toLowerCase() + "-transform " + d + " ease-in-out, opacity " + d + " ease-out";
|
if(fromStoryElement) {
|
||||||
storyElementNode.domNode.style.opacity = "0.0";
|
fromStoryElement.domNode.style[$tw.browser.transition] = "-" + $tw.browser.prefix.toLowerCase() + "-transform " + d + " ease-in-out, opacity " + d + " ease-out";
|
||||||
storyElementNode.domNode.style[$tw.browser.transformorigin] = "50% 50%";
|
fromStoryElement.domNode.style.opacity = "0.0";
|
||||||
storyElementNode.domNode.style[$tw.browser.transform] = "translateX(0px) translateY(0px) scale(0.1)";
|
fromStoryElement.domNode.style[$tw.browser.transformorigin] = "50% 50%";
|
||||||
storyElementNode.domNode.style.zIndex = "0";
|
fromStoryElement.domNode.style[$tw.browser.transform] = "translateX(0px) translateY(0px) scale(0.1)";
|
||||||
storyElementNode.domNode.addEventListener($tw.browser.transitionEnd,function(event) {
|
fromStoryElement.domNode.style.zIndex = "0";
|
||||||
// Delete the DOM node when the transition is over
|
var eventHandler = function(event) {
|
||||||
if(storyElementNode.domNode.parentNode) {
|
// Delete the DOM node when the transition is over
|
||||||
storyElementNode.domNode.parentNode.removeChild(storyElementNode.domNode);
|
if(fromStoryElement.domNode.parentNode) {
|
||||||
}
|
fromStoryElement.domNode.parentNode.removeChild(fromStoryElement.domNode);
|
||||||
},true);
|
}
|
||||||
// Now the tiddler we're going back to
|
fromStoryElement.domNode.removeEventListener($tw.browser.transitionEnd,eventHandler,true);
|
||||||
if(storyElement !== undefined) {
|
};
|
||||||
storyElement.domNode.style[$tw.browser.transform] = "translateX(0px) translateY(0px) scale(1)";
|
fromStoryElement.domNode.addEventListener($tw.browser.transitionEnd,eventHandler,true);
|
||||||
storyElement.domNode.style.opacity = "1.0";
|
|
||||||
}
|
}
|
||||||
|
// Now the tiddler we're going back to
|
||||||
|
toStoryElement.domNode.style[$tw.browser.transform] = "translateX(0px) translateY(0px) scale(1)";
|
||||||
|
toStoryElement.domNode.style.opacity = "1.0";
|
||||||
});
|
});
|
||||||
return true; // Indicate that we'll delete the DOM node
|
return true; // Indicate that we'll delete the DOM node
|
||||||
};
|
};
|
||||||
|
59
core/modules/scroller.js
Normal file
59
core/modules/scroller.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/scroller.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: utils
|
||||||
|
|
||||||
|
Plugin that creates a $tw.utils.Scroller object prototype that manages scrolling in the browser
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var slowInSlowOut = function(t) {
|
||||||
|
return (1 - ((Math.cos(t * Math.PI) + 1) / 2));
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Creates a Scroller object
|
||||||
|
*/
|
||||||
|
var Scroller = function() {
|
||||||
|
};
|
||||||
|
|
||||||
|
Scroller.prototype.cancel = function() {
|
||||||
|
if(this.timerId) {
|
||||||
|
window.clearInterval(this.timerId);
|
||||||
|
this.timerId = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Smoothly scroll an element back into view if needed
|
||||||
|
*/
|
||||||
|
Scroller.prototype.scrollIntoView = function(element) {
|
||||||
|
var scrollPosition = $tw.utils.getScrollPosition();
|
||||||
|
this.cancel();
|
||||||
|
this.startTime = new Date();
|
||||||
|
this.startX = scrollPosition.x;
|
||||||
|
this.startY = scrollPosition.y;
|
||||||
|
this.endX = element.offsetLeft;
|
||||||
|
this.endY = element.offsetTop;
|
||||||
|
if((this.endX < this.startX) || (this.endX > (this.startX + window.innerWidth)) || (this.endY < this.startY) || (this.endY > (this.startY + window.innerHeight))) {
|
||||||
|
var self = this;
|
||||||
|
this.timerId = window.setInterval(function() {
|
||||||
|
var t = ((new Date()) - self.startTime) / $tw.config.preferences.animationDuration;
|
||||||
|
if(t >= 1) {
|
||||||
|
self.cancel();
|
||||||
|
t = 1;
|
||||||
|
}
|
||||||
|
t = slowInSlowOut(t);
|
||||||
|
window.scrollTo(self.startX + (self.endX - self.startX) * t,self.startY + (self.endY - self.startY) * t);
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.Scroller = Scroller;
|
||||||
|
|
||||||
|
})();
|
@ -76,34 +76,18 @@ exports.applyStyleSheet = function(id,css) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Smoothly scroll an element back into view if needed
|
Get the scroll position of the viewport
|
||||||
|
Returns:
|
||||||
|
{
|
||||||
|
x: horizontal scroll position in pixels,
|
||||||
|
y: vertical scroll position in pixels
|
||||||
|
}
|
||||||
*/
|
*/
|
||||||
exports.scrollIntoView = function(element) {
|
exports.getScrollPosition = function() {
|
||||||
var slowInSlowOut = function(t) {
|
if("scrollX" in window) {
|
||||||
return (1 - ((Math.cos(t * Math.PI) + 1) / 2));
|
return {x: window.scrollX, y: window.scrollY};
|
||||||
},
|
} else {
|
||||||
animateScroll = function(startX,startY,endX,endY,duration) {
|
return {x: document.documentElement.scrollLeft, y: document.documentElement.scrollTop};
|
||||||
var startTime = new Date(),
|
|
||||||
timerId = window.setInterval(function() {
|
|
||||||
var t = ((new Date()) - startTime) / duration;
|
|
||||||
if(t >= 1) {
|
|
||||||
window.clearInterval(timerId);
|
|
||||||
t = 1;
|
|
||||||
}
|
|
||||||
t = slowInSlowOut(t);
|
|
||||||
var x = startX + (endX - startX) * t,
|
|
||||||
y = startY + (endY - startY) * t;
|
|
||||||
window.scrollTo(x,y);
|
|
||||||
}, 10);
|
|
||||||
},
|
|
||||||
x = element.offsetLeft,
|
|
||||||
y = element.offsetTop,
|
|
||||||
winWidth = window.innerWidth,
|
|
||||||
winHeight = window.innerHeight,
|
|
||||||
scrollLeft = window.scrollX || document.documentElement.scrollLeft,
|
|
||||||
scrollTop = window.scrollY || document.documentElement.scrollTop;
|
|
||||||
if((x < scrollLeft) || (x > (scrollLeft + winWidth)) || (y < scrollTop) || (y > (scrollTop + winHeight))) {
|
|
||||||
animateScroll(scrollLeft,scrollTop,x,y,$tw.config.preferences.animationDuration);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user