1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-11-23 18:17:20 +00:00

Re-introduce listviews

Now called storyviews because they're aware of the history structure as
well as the list structure.
This commit is contained in:
Jeremy Ruston 2013-11-04 22:22:28 +00:00
parent 63243c5855
commit 7c250fd7fe
4 changed files with 158 additions and 12 deletions

View File

@ -19,6 +19,12 @@ The list widget creates list element sub-widgets that reach back into the list w
*/
var ListWidget = function(parseTreeNode,options) {
// Initialise the storyviews if they've not been done already
if(!this.storyViews) {
ListWidget.prototype.storyViews = {};
$tw.modules.applyMethods("storyview",this.storyViews);
}
// Main initialisation inherited from widget.js
this.initialise(parseTreeNode,options);
};
@ -45,6 +51,8 @@ ListWidget.prototype.execute = function() {
this.template = this.getAttribute("template");
this.editTemplate = this.getAttribute("editTemplate");
this.variableName = this.getAttribute("variable","currentTiddler");
this.storyViewName = this.getAttribute("storyview");
this.historyTitle = this.getAttribute("history");
// Compose the list elements
this.list = this.getTiddlerList();
var members = [],
@ -59,6 +67,11 @@ ListWidget.prototype.execute = function() {
}
// Construct the child widgets
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() {
@ -111,13 +124,40 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
ListWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
// Completely refresh if any of our attributes have changed
if(changedAttributes.filter || changedAttributes.template || changedAttributes.editTemplate || changedAttributes.emptyMessage) {
if(changedAttributes.filter || changedAttributes.template || changedAttributes.editTemplate || changedAttributes.emptyMessage || changedAttributes.storyview || changedAttributes.history) {
this.refreshSelf();
return true;
} else {
// Handle any changes to the list
return this.handleListChanges(changedTiddlers);
var hasChanged = this.handleListChanges(changedTiddlers);
// Handle any changes to the history stack
if(this.historyTitle && changedTiddlers[this.historyTitle]) {
this.handleHistoryChanges();
}
return hasChanged;
}
};
/*
Handle any changes to the history list
*/
ListWidget.prototype.handleHistoryChanges = function() {
// Get the history data
var newHistory = this.wiki.getTiddlerData(this.historyTitle,[]);
// Ignore any entries of the history that match the previous history
var entry = 0;
while(entry < newHistory.length && entry < this.history.length && newHistory[entry].title === this.history[entry].title) {
entry++;
}
// Navigate forwards to each of the new tiddlers
while(entry < newHistory.length) {
if(this.storyview && this.storyview.navigateTo) {
this.storyview.navigateTo(newHistory[entry]);
}
entry++;
}
// Update the history
this.history = newHistory;
};
/*
@ -192,20 +232,30 @@ ListWidget.prototype.findListItem = function(startIndex,title) {
Insert a new list item at the specified index
*/
ListWidget.prototype.insertListItem = function(index,title) {
var newItem = this.makeChildWidget(this.makeItemTemplate(title));
newItem.parentDomNode = this.parentDomNode; // Hack to enable findNextSiblingDomNode() to work
this.children.splice(index,0,newItem);
var nextSibling = newItem.findNextSiblingDomNode();
newItem.render(this.parentDomNode,nextSibling);
// Create, insert and render the new child widgets
var widget = this.makeChildWidget(this.makeItemTemplate(title));
widget.parentDomNode = this.parentDomNode; // Hack to enable findNextSiblingDomNode() to work
this.children.splice(index,0,widget);
var nextSibling = widget.findNextSiblingDomNode();
widget.render(this.parentDomNode,nextSibling);
// Animate the insertion if required
if(this.storyview && this.storyview.insert) {
this.storyview.insert(widget);
}
return true;
};
/*
Remvoe the specified list item
Remove the specified list item
*/
ListWidget.prototype.removeListItem = function(index) {
// Remove the DOM nodes owned by this item
this.children[index].removeChildDomNodes();
var widget = this.children[index];
// Animate the removal if required
if(this.storyview && this.storyview.remove) {
this.storyview.remove(widget);
} else {
widget.removeChildDomNodes();
}
// Remove the child widget
this.children.splice(index,1);
};

View File

@ -78,7 +78,9 @@ exports.startup = function() {
});
// Install the scroller
$tw.pageScroller = new $tw.utils.PageScroller();
$tw.rootWidget.addEventListener("tw-scroll",$tw.pageScroller);
$tw.rootWidget.addEventListener("tw-scroll",function(event) {
$tw.pageScroller.handleEvent(event);
});
// Install the save action handler
$tw.wiki.initSavers();
$tw.rootWidget.addEventListener("tw-save-wiki",function(event) {

View File

@ -0,0 +1,94 @@
/*\
title: $:/core/modules/storyviews/classic.js
type: application/javascript
module-type: storyview
Views the story as a linear sequence
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var ClassicStoryView = function(listWidget) {
this.listWidget = listWidget;
}
ClassicStoryView.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});
};
ClassicStoryView.prototype.insert = function(widget) {
var targetElement = widget.findFirstDomNode(),
duration = $tw.utils.getAnimationDuration();
// Get the current height of the tiddler
var computedStyle = window.getComputedStyle(targetElement),
currMarginBottom = parseInt(computedStyle.marginBottom,10),
currMarginTop = parseInt(computedStyle.marginTop,10),
currHeight = targetElement.offsetHeight + currMarginTop;
// Reset the margin once the transition is over
setTimeout(function() {
$tw.utils.setStyle(targetElement,[
{transition: "none"},
{marginBottom: ""}
]);
},duration);
// Set up the initial position of the element
$tw.utils.setStyle(targetElement,[
{transition: "none"},
{marginBottom: (-currHeight) + "px"},
{opacity: "0.0"}
]);
$tw.utils.forceLayout(targetElement);
// Transition to the final position
$tw.utils.setStyle(targetElement,[
{transition: "opacity " + duration + "ms ease-in-out, " +
"margin-bottom " + duration + "ms ease-in-out"},
{marginBottom: currMarginBottom + "px"},
{opacity: "1.0"}
]);
};
ClassicStoryView.prototype.remove = function(widget) {
var targetElement = widget.findFirstDomNode(),
duration = $tw.utils.getAnimationDuration();
// Get the current height of the tiddler
var currWidth = targetElement.offsetWidth,
computedStyle = window.getComputedStyle(targetElement),
currMarginBottom = parseInt(computedStyle.marginBottom,10),
currMarginTop = parseInt(computedStyle.marginTop,10),
currHeight = targetElement.offsetHeight + currMarginTop;
// Remove the dom nodes of the widget at the end of the transition
setTimeout(function() {
widget.removeChildDomNodes();
},duration);
// Animate the closure
$tw.utils.setStyle(targetElement,[
{transition: "none"},
{transform: "translateX(0px)"},
{marginBottom: currMarginBottom + "px"},
{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, " +
"margin-bottom " + duration + "ms ease-in-out"},
{transform: "translateX(-" + currWidth + "px)"},
{marginBottom: (-currHeight) + "px"},
{opacity: "0.0"}
]);
};
exports.classic = ClassicStoryView;
})();

View File

@ -26,7 +26,7 @@ title: $:/core/ui/PageTemplate
<section class="story-river">
<!-- The main story -->
<$list filter="[list[$:/StoryList]]" history="$:/HistoryList" template="$:/core/ui/ViewTemplate" editTemplate="$:/core/ui/EditTemplate" listview={{$:/view}} />
<$list filter="[list[$:/StoryList]]" history="$:/HistoryList" template="$:/core/ui/ViewTemplate" editTemplate="$:/core/ui/EditTemplate" storyview={{$:/view}} />
<!-- End of story river -->
</section>