1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-11-17 15:24:50 +00:00

Added support for store events and basic refreshing

1s after loading you'll see the link to TiddlyWiki5 flip from italic to
normal text as that tiddler is created on a timer
This commit is contained in:
Jeremy Ruston 2012-01-14 15:49:12 +00:00
parent 054977c912
commit b7d0942625
3 changed files with 160 additions and 10 deletions

View File

@ -109,6 +109,16 @@ var App = function() {
var div = document.createElement("div"); var div = document.createElement("div");
div.innerHTML = this.store.renderTiddler("text/html","PageTemplate"); div.innerHTML = this.store.renderTiddler("text/html","PageTemplate");
document.body.appendChild(div); document.body.appendChild(div);
var me = this;
window.setInterval(function() {
me.store.addTiddler(new Tiddler({
title: "TiddlyWiki5",
text: "This is a newly created tiddler!"
}));
},3000);
this.store.addEventListener("",function() {
me.store.refreshDomNode(div,me.store.getTiddler("PageTemplate"));
});
} }
}; };

View File

@ -22,6 +22,9 @@ var WikiStore = function WikiStore(options) {
this.macros = {}; this.macros = {};
this.tiddlerSerializers = {}; this.tiddlerSerializers = {};
this.tiddlerDeserializers = {}; this.tiddlerDeserializers = {};
this.eventListeners = []; // Array of {filter:,listener:}
this.eventsTriggered = false;
this.changedTiddlers = {}; // Hashmap of {title: "created|modified|deleted"}
this.sandbox = options.sandbox; this.sandbox = options.sandbox;
this.shadows = options.shadowStore !== undefined ? options.shadowStore : new WikiStore({ this.shadows = options.shadowStore !== undefined ? options.shadowStore : new WikiStore({
shadowStore: null shadowStore: null
@ -42,6 +45,73 @@ WikiStore.prototype.registerTiddlerDeserializer = function(extension,mimeType,de
this.tiddlerDeserializers[mimeType] = deserializer; this.tiddlerDeserializers[mimeType] = deserializer;
}; };
WikiStore.prototype.addEventListener = function(filter,listener) {
this.eventListeners.push({
filter: filter,
listener: listener
});
};
WikiStore.prototype.removeEventListener = function(listener) {
for(var c=this.eventListeners.length-1; c>=0; c--) {
var l = this.eventListeners[c];
if(l.listener === listener) {
this.eventListeners.splice(c,1);
}
}
};
/*
Causes a tiddler to be marked as changed, so that event listeners are triggered for it
type: Type of change to be registered for the tiddler "created", "modified" or "deleted"
If the tiddler is already touched, the resultant touch type is as follows:
If the tiddler is already marked "created",
... attempts to mark it "modified" leave it "created"
... attempts to mark it "deleted" succeed
If the tiddler is already marked "modified",
... attempts to mark it "deleted" succeed
If the tiddler is already marked "deleted",
... attempts to mark it "created" succeed
... attempts to mark it "modified" fail
*/
WikiStore.prototype.touchTiddler = function(type,title) {
var existingType = this.changedTiddlers[title];
if(existingType === undefined && type === "modified") {
type = "created";
}
if(existingType === "modified" && type === "created") {
type = "modified";
}
if(existingType === "deleted" && type === "created") {
type = "modified";
}
this.changedTiddlers[title] = type;
this.triggerEvents();
};
/*
Trigger the execution of the event dispatcher at the next tick, if it is not already triggered
*/
WikiStore.prototype.triggerEvents = function() {
if(!this.eventsTriggered) {
var me = this;
utils.nextTick(function() {
var changes = me.changedTiddlers;
me.changedTiddlers = {};
me.eventsTriggered = false;
for(var e=0; e<me.eventListeners.length; e++) {
var listener = me.eventListeners[e];
listener.listener(changes);
}
});
this.eventsTriggered = true;
}
};
WikiStore.prototype.getTiddler = function(title) { WikiStore.prototype.getTiddler = function(title) {
var t = this.tiddlers[title]; var t = this.tiddlers[title];
if(t instanceof Tiddler) { if(t instanceof Tiddler) {
@ -74,6 +144,7 @@ WikiStore.prototype.tiddlerExists = function(title) {
WikiStore.prototype.addTiddler = function(tiddler) { WikiStore.prototype.addTiddler = function(tiddler) {
this.tiddlers[tiddler.fields.title] = tiddler; this.tiddlers[tiddler.fields.title] = tiddler;
this.touchTiddler("modified",tiddler.fields.title);
}; };
WikiStore.prototype.forEachTiddler = function(/* [sortField,[excludeTag,]]callback */) { WikiStore.prototype.forEachTiddler = function(/* [sortField,[excludeTag,]]callback */) {
@ -163,17 +234,45 @@ WikiStore.prototype.deserializeTiddlers = function(type,text,srcFields) {
} }
}; };
WikiStore.prototype.classesForLink = function(target) { WikiStore.prototype.adjustClassesForLink = function(classes,target) {
var className = "", var externalRegExp = /(?:file|http|https|mailto|ftp|irc|news|data):[^\s'"]+(?:\/|\b)/i,
externalRegExp = /(?:file|http|https|mailto|ftp|irc|news|data):[^\s'"]+(?:\/|\b)/i; setClass = function(className) {
if (this.tiddlerExists(target)) { if(classes.indexOf(className) === -1) {
className = "linkInternalResolves"; classes.push(className);
} else if(externalRegExp.test(target)) {
className = "linkExternal";
} else {
className = "linkInternalMissing";
} }
return className !== "" ? " class=\"" + className + "\"" : ""; },
removeClass = function(className) {
var p = classes.indexOf(className);
if(p !== -1) {
classes.splice(p,1);
}
};
// Make sure we've got the main link class
setClass("tw-tiddlylink");
// Check if it's an internal link
if (this.tiddlerExists(target)) {
removeClass("tw-tiddlylink-external");
setClass("tw-tiddlylink-internal");
setClass("tw-tiddlylink-resolves");
removeClass("tw-tiddlylink-missing");
} else if(externalRegExp.test(target)) {
setClass("tw-tiddlylink-external");
removeClass("tw-tiddlylink-internal");
removeClass("tw-tiddlylink-resolves");
removeClass("tw-tiddlylink-missing");
} else {
removeClass("tw-tiddlylink-external");
setClass("tw-tiddlylink-internal");
removeClass("tw-tiddlylink-resolves");
setClass("tw-tiddlylink-missing");
}
return classes;
};
WikiStore.prototype.classesForLink = function(target) {
var classes = ["tw-tiddlylink"];
this.adjustClassesForLink(classes,target);
return " class=\"" + classes.join(" ") + "\"";
}; };
WikiStore.prototype.parseText = function(type,text) { WikiStore.prototype.parseText = function(type,text) {
@ -258,6 +357,47 @@ WikiStore.prototype.renderTiddler = function(type,title,asTitle) {
return null; return null;
}; };
/*
Refresh a DOM node so that it reflects the current state of the store
The refresh processing is:
1. If the node is a link, check the link classes correctly reflect the status of the target tiddler. Recursively process any children. Exit
2. If the node is a macro, and dependencies have changed, re-render the macro into the DOM node. Exit
3. If the node is a macro and the dependencies haven't changed, recursively process each child node of the macro. Exit
Arguments
node - the DOM node to be processed
tiddler - the tiddler providing context for the rendering
*/
WikiStore.prototype.refreshDomNode = function(node,tiddler) {
// Process links
if(node.className) {
var classes = node.className.split(" ");
if(classes.indexOf("tw-tiddlylink") !== -1) {
var target = node.getAttribute("href");
node.className = this.adjustClassesForLink(classes,target).join(" ");
}
}
// Process macros
var macro = node.getAttribute && node.getAttribute("data-tw-macro"),
params = node.getAttribute && node.getAttribute("data-tw-params");
if(macro && params) {
}
// Process children
if(node.hasChildNodes()) {
this.refreshDomChildren(node,tiddler);
}
};
WikiStore.prototype.refreshDomChildren = function(node,tiddler) {
var nodes = node.childNodes;
for(var c=0; c<nodes.length; c++) {
this.refreshDomNode(nodes[c],tiddler);
}
};
WikiStore.prototype.installMacro = function(macro) { WikiStore.prototype.installMacro = function(macro) {
this.macros[macro.name] = macro; this.macros[macro.name] = macro;
}; };

View File

@ -81,17 +81,17 @@ a:hover {
color: #fff; color: #fff;
} }
a.linkExternal { a.tw-tiddlylink {
font-style: normal; font-style: normal;
font-weight: normal; font-weight: normal;
} }
a.linkInternalResolves { a.tw-tiddlylink-resolves {
font-style: normal; font-style: normal;
font-weight: bold; font-weight: bold;
} }
a.linkInternalMissing { a.tw-tiddlylink-missing {
font-style: italic; font-style: italic;
} }