1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-11-27 03:57:21 +00:00

Add a new scroller story view

This is the default story view
This commit is contained in:
Jeremy Ruston 2012-05-19 12:59:16 +01:00
parent 19d308dd9c
commit 3e899d8daf
3 changed files with 200 additions and 94 deletions

View File

@ -28,4 +28,8 @@ exports.dateFormats = {
exports.htmlEntities = {quot:34, amp:38, apos:39, lt:60, gt:62, nbsp:160, iexcl:161, cent:162, pound:163, curren:164, yen:165, brvbar:166, sect:167, uml:168, copy:169, ordf:170, laquo:171, not:172, shy:173, reg:174, macr:175, deg:176, plusmn:177, sup2:178, sup3:179, acute:180, micro:181, para:182, middot:183, cedil:184, sup1:185, ordm:186, raquo:187, frac14:188, frac12:189, frac34:190, iquest:191, Agrave:192, Aacute:193, Acirc:194, Atilde:195, Auml:196, Aring:197, AElig:198, Ccedil:199, Egrave:200, Eacute:201, Ecirc:202, Euml:203, Igrave:204, Iacute:205, Icirc:206, Iuml:207, ETH:208, Ntilde:209, Ograve:210, Oacute:211, Ocirc:212, Otilde:213, Ouml:214, times:215, Oslash:216, Ugrave:217, Uacute:218, Ucirc:219, Uuml:220, Yacute:221, THORN:222, szlig:223, agrave:224, aacute:225, acirc:226, atilde:227, auml:228, aring:229, aelig:230, ccedil:231, egrave:232, eacute:233, ecirc:234, euml:235, igrave:236, iacute:237, icirc:238, iuml:239, eth:240, ntilde:241, ograve:242, oacute:243, ocirc:244, otilde:245, ouml:246, divide:247, oslash:248, ugrave:249, uacute:250, ucirc:251, uuml:252, yacute:253, thorn:254, yuml:255, OElig:338, oelig:339, Scaron:352, scaron:353, Yuml:376, fnof:402, circ:710, tilde:732, Alpha:913, Beta:914, Gamma:915, Delta:916, Epsilon:917, Zeta:918, Eta:919, Theta:920, Iota:921, Kappa:922, Lambda:923, Mu:924, Nu:925, Xi:926, Omicron:927, Pi:928, Rho:929, Sigma:931, Tau:932, Upsilon:933, Phi:934, Chi:935, Psi:936, Omega:937, alpha:945, beta:946, gamma:947, delta:948, epsilon:949, zeta:950, eta:951, theta:952, iota:953, kappa:954, lambda:955, mu:956, nu:957, xi:958, omicron:959, pi:960, rho:961, sigmaf:962, sigma:963, tau:964, upsilon:965, phi:966, chi:967, psi:968, omega:969, thetasym:977, upsih:978, piv:982, ensp:8194, emsp:8195, thinsp:8201, zwnj:8204, zwj:8205, lrm:8206, rlm:8207, ndash:8211, mdash:8212, lsquo:8216, rsquo:8217, sbquo:8218, ldquo:8220, rdquo:8221, bdquo:8222, dagger:8224, Dagger:8225, bull:8226, hellip:8230, permil:8240, prime:8242, Prime:8243, lsaquo:8249, rsaquo:8250, oline:8254, frasl:8260, euro:8364, image:8465, weierp:8472, real:8476, trade:8482, alefsym:8501, larr:8592, uarr:8593, rarr:8594, darr:8595, harr:8596, crarr:8629, lArr:8656, uArr:8657, rArr:8658, dArr:8659, hArr:8660, forall:8704, part:8706, exist:8707, empty:8709, nabla:8711, isin:8712, notin:8713, ni:8715, prod:8719, sum:8721, minus:8722, lowast:8727, radic:8730, prop:8733, infin:8734, ang:8736, and:8743, or:8744, cap:8745, cup:8746, int:8747, there4:8756, sim:8764, cong:8773, asymp:8776, ne:8800, equiv:8801, le:8804, ge:8805, sub:8834, sup:8835, nsub:8836, sube:8838, supe:8839, oplus:8853, otimes:8855, perp:8869, sdot:8901, lceil:8968, rceil:8969, lfloor:8970, rfloor:8971, lang:9001, rang:9002, loz:9674, spades:9824, clubs:9827, hearts:9829, diams:9830 };
exports.preferences = {
animationDuration: 400
}
})();

View File

@ -20,17 +20,6 @@ The storyview is a plugin that extends the story macro to implement different na
/*global $tw: false */
"use strict";
function scrollToTop(duration) {
if (duration < 0) {
return;
}
var delta = (-document.body.scrollTop/duration) * 10;
window.setTimeout(function() {
document.body.scrollTop = document.body.scrollTop + delta;
scrollToTop(duration-10);
}, 10);
}
exports.info = {
name: "story",
params: {
@ -43,89 +32,118 @@ exports.info = {
};
exports.handleEvent = function(event) {
var template, storyTiddler, story, storyRecord, tiddler, storyTiddlerModified, t;
switch(event.type) {
case "tw-navigate":
// Navigate to a specified tiddler
template = this.hasParameter("defaultViewTemplate") ? this.params.defaultViewTemplate : "ViewTemplate";
storyTiddler = this.wiki.getTiddler(this.params.story);
story = {tiddlers: []};
if(storyTiddler && $tw.utils.hop(storyTiddler.fields,"text")) {
story = JSON.parse(storyTiddler.fields.text);
}
story.tiddlers.unshift({title: event.navigateTo, template: template});
this.wiki.addTiddler(new $tw.Tiddler(storyTiddler,{text: JSON.stringify(story)}));
scrollToTop(400);
event.stopPropagation();
return false;
case "tw-EditTiddler":
// Put the specified tiddler into edit mode
template = this.hasParameter("defaultEditTemplate") ? this.params.defaultEditTemplate : "EditTemplate";
storyTiddler = this.wiki.getTiddler(this.params.story);
story = {tiddlers: []};
if(storyTiddler && $tw.utils.hop(storyTiddler.fields,"text")) {
story = JSON.parse(storyTiddler.fields.text);
}
for(t=0; t<story.tiddlers.length; t++) {
storyRecord = story.tiddlers[t];
if(storyRecord.title === event.tiddlerTitle && storyRecord.template !== template) {
storyRecord.title = "Draft " + (new Date()) + " of " + event.tiddlerTitle;
storyRecord.template = template;
tiddler = this.wiki.getTiddler(event.tiddlerTitle);
this.wiki.addTiddler(new $tw.Tiddler(
{
text: "Type the text for the tiddler '" + event.tiddlerTitle + "'"
},
tiddler,
{
title: storyRecord.title,
"draft.title": event.tiddlerTitle,
"draft.of": event.tiddlerTitle
}));
}
}
this.wiki.addTiddler(new $tw.Tiddler(storyTiddler,{text: JSON.stringify(story)}));
event.stopPropagation();
return false;
case "tw-SaveTiddler":
template = this.hasParameter("defaultViewTemplate") ? this.params.defaultEditTemplate : "ViewTemplate";
storyTiddler = this.wiki.getTiddler(this.params.story);
story = {tiddlers: []};
storyTiddlerModified = false;
if(storyTiddler && $tw.utils.hop(storyTiddler.fields,"text")) {
story = JSON.parse(storyTiddler.fields.text);
}
for(t=0; t<story.tiddlers.length; t++) {
storyRecord = story.tiddlers[t];
if(storyRecord.title === event.tiddlerTitle && storyRecord.template !== template) {
tiddler = this.wiki.getTiddler(storyRecord.title);
if(tiddler && $tw.utils.hop(tiddler.fields,"draft.title")) {
// Save the draft tiddler as the real tiddler
this.wiki.addTiddler(new $tw.Tiddler(tiddler,{title: tiddler.fields["draft.title"],"draft.title": undefined, "draft.of": undefined}));
// Remove the draft tiddler
this.wiki.deleteTiddler(storyRecord.title);
// Remove the original tiddler if we're renaming it
if(tiddler.fields["draft.of"] !== tiddler.fields["draft.title"]) {
this.wiki.deleteTiddler(tiddler.fields["draft.of"]);
}
// Make the story record point to the newly saved tiddler
storyRecord.title = tiddler.fields["draft.title"];
storyRecord.template = template;
// Check if we're modifying the story tiddler itself
if(tiddler.fields["draft.title"] === this.params.story) {
storyTiddlerModified = true;
}
}
}
}
if(!storyTiddlerModified) {
this.wiki.addTiddler(new $tw.Tiddler(storyTiddler,{text: JSON.stringify(story)}));
}
event.stopPropagation();
return false;
if(this.eventMap[event.type]) {
this.eventMap[event.type].call(this,event);
}
};
exports.eventMap = {};
// Navigate to a specified tiddler
exports.eventMap["tw-navigate"] = function(event) {
var template = this.params.defaultViewTemplate || "ViewTemplate",
storyTiddler = this.wiki.getTiddler(this.params.story),
story = {tiddlers: []},
navTiddler,t,tiddler;
// Get the story
if(storyTiddler && $tw.utils.hop(storyTiddler.fields,"text")) {
story = JSON.parse(storyTiddler.fields.text);
}
// See if the tiddler we want is already there
for(t=0; t<story.tiddlers.length; t++) {
if(story.tiddlers[t].title === event.navigateTo) {
navTiddler = t;
}
}
if(typeof(navTiddler) !== "undefined") {
// If we found our tiddler, just tell the storyview to navigate to it
if(this.storyview && this.storyview.navigate) {
this.storyview.navigate(this.children[0].children[navTiddler],false,event);
}
} else {
// Add the tiddler to the bottom of the story (subsequently there will be a refreshInDom() call which is when we'll actually do the navigation)
story.tiddlers.push({title: event.navigateTo, template: template});
this.wiki.addTiddler(new $tw.Tiddler(storyTiddler,{text: JSON.stringify(story)}));
// Record the details of the navigation for us to pick up in refreshInDom()
this.lastNavigationEvent = event;
}
event.stopPropagation();
return false;
};
// Place a tiddler in edit mode
exports.eventMap["tw-EditTiddler"] = function(event) {
var template, storyTiddler, story, storyRecord, tiddler, t;
// Put the specified tiddler into edit mode
template = this.params.defaultEditTemplate || "EditTemplate";
storyTiddler = this.wiki.getTiddler(this.params.story);
story = {tiddlers: []};
if(storyTiddler && $tw.utils.hop(storyTiddler.fields,"text")) {
story = JSON.parse(storyTiddler.fields.text);
}
for(t=0; t<story.tiddlers.length; t++) {
storyRecord = story.tiddlers[t];
if(storyRecord.title === event.tiddlerTitle && storyRecord.template !== template) {
storyRecord.title = "Draft " + (new Date()) + " of " + event.tiddlerTitle;
storyRecord.template = template;
tiddler = this.wiki.getTiddler(event.tiddlerTitle);
this.wiki.addTiddler(new $tw.Tiddler(
{
text: "Type the text for the tiddler '" + event.tiddlerTitle + "'"
},
tiddler,
{
title: storyRecord.title,
"draft.title": event.tiddlerTitle,
"draft.of": event.tiddlerTitle
}));
}
}
this.wiki.addTiddler(new $tw.Tiddler(storyTiddler,{text: JSON.stringify(story)}));
event.stopPropagation();
return false;
};
// Take a tiddler out of edit mode, saving the changes
exports.eventMap["tw-SaveTiddler"] = function(event) {
var template, storyTiddler, story, storyRecord, tiddler, storyTiddlerModified, t;
template = this.params.defaultEditTemplate || "ViewTemplate";
storyTiddler = this.wiki.getTiddler(this.params.story);
story = {tiddlers: []};
storyTiddlerModified = false;
if(storyTiddler && $tw.utils.hop(storyTiddler.fields,"text")) {
story = JSON.parse(storyTiddler.fields.text);
}
for(t=0; t<story.tiddlers.length; t++) {
storyRecord = story.tiddlers[t];
if(storyRecord.title === event.tiddlerTitle && storyRecord.template !== template) {
tiddler = this.wiki.getTiddler(storyRecord.title);
if(tiddler && $tw.utils.hop(tiddler.fields,"draft.title")) {
// Save the draft tiddler as the real tiddler
this.wiki.addTiddler(new $tw.Tiddler(tiddler,{title: tiddler.fields["draft.title"],"draft.title": undefined, "draft.of": undefined}));
// Remove the draft tiddler
this.wiki.deleteTiddler(storyRecord.title);
// Remove the original tiddler if we're renaming it
if(tiddler.fields["draft.of"] !== tiddler.fields["draft.title"]) {
this.wiki.deleteTiddler(tiddler.fields["draft.of"]);
}
// Make the story record point to the newly saved tiddler
storyRecord.title = tiddler.fields["draft.title"];
storyRecord.template = template;
// Check if we're modifying the story tiddler itself
if(tiddler.fields["draft.title"] === this.params.story) {
storyTiddlerModified = true;
}
}
}
}
if(!storyTiddlerModified) {
this.wiki.addTiddler(new $tw.Tiddler(storyTiddler,{text: JSON.stringify(story)}));
}
event.stopPropagation();
return false;
};
exports.executeMacro = function() {
var storyJson = JSON.parse(this.wiki.getTiddlerText(this.params.story)),
storyNode = $tw.Tree.Element("div",{},[]);
@ -146,6 +164,12 @@ exports.postRenderInDom = function() {
if(StoryView) {
this.storyview = new StoryView(this);
};
if(!this.storyview) {
StoryView = this.wiki.macros.story.viewers["scroller"];
if(StoryView) {
this.storyview = new StoryView(this);
}
}
};
exports.refreshInDom = function(changes) {
@ -183,8 +207,9 @@ exports.refreshInDom = function(changes) {
m.execute(this.parents,this.tiddlerTitle);
m.renderInDom(this.children[0].domNode,this.children[0].domNode.childNodes[t]);
this.children[0].children.splice(t,0,m);
if(this.storyview && this.storyview.tiddlerAdded) {
this.storyview.tiddlerAdded(this.children[0].children[t]);
// Invoke the storyview to animate the navigation
if(this.storyview && this.storyview.navigate) {
this.storyview.navigate(this.children[0].children[t],true,this.lastNavigationEvent);
}
} else {
// Delete any nodes preceding the one we want
@ -210,10 +235,13 @@ exports.refreshInDom = function(changes) {
this.children[0].children.splice(story.tiddlers.length,this.children[0].children.length-story.tiddlers.length);
}
} else {
// If our dependencies didn't change, just refresh the children
for(t=0; t<this.children.length; t++) {
this.children[t].refreshInDom(changes);
}
}
// Clear the details of the last navigation
this.lastNavigationEvent = undefined;
};
})();

View File

@ -0,0 +1,74 @@
/*\
title: $:/core/modules/macros/story/views/scroller.js
type: application/javascript
module-type: storyview
A storyview that shows a sequence of tiddlers and navigates by scrolling
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
function slowInSlowOut(t) {
return (1 - ((Math.cos(t * Math.PI) + 1) / 2));
}
function animate(animList,duration) {
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);
for(var a=0; a<animList.length; a++) {
var anim = animList[a];
document.body[anim.property] = anim.from + (anim.to - anim.from) * t;
}
}, 10);
}
/*
Check if the top left corner of a given element is currently visible, given the scroll position
*/
function isVisible(element) {
var x = element.offsetLeft, y = element.offsetTop;
return (x >= document.body.scrollLeft) &&
(x < (document.body.scrollLeft + window.innerHeight)) &&
(y >= document.body.scrollTop) &&
(y < (document.body.scrollTop + window.innerHeight));
}
/*
Smoothly scroll an element back into view if needed
*/
function scrollIntoView(element) {
if(!isVisible(element)) {
animate([
{property: "scrollLeft", from: document.body.scrollLeft, to: element.offsetLeft},
{property: "scrollTop", from: document.body.scrollTop, to: element.offsetTop}
],$tw.config.preferences.animationDuration);
}
}
function Scroller(story) {
this.story = story;
}
/*
Visualise navigation to the specified tiddler macro, optionally specifying a source node for the visualisation
targetTiddlerNode: tree node of the tiddler macro we're navigating to
isNew: true if the node we're navigating to has just been added to the DOM
sourceNode: optional tree node that initiated the navigation
*/
Scroller.prototype.navigate = function(targetTiddlerNode,isNew,sourceEvent) {
scrollIntoView(targetTiddlerNode.domNode);
};
exports.scroller = Scroller;
})();