From 9de17aa206b21df5c4e29e61bba5d6b49aca6c71 Mon Sep 17 00:00:00 2001 From: Jermolene Date: Mon, 17 Mar 2014 10:50:18 +0000 Subject: [PATCH] Make shadowTiddlers, pluginTiddlers and pluginInfo be private to the Wiki object constructor --- boot/boot.js | 265 ++++++++++--------- core/modules/filters/is/shadow.js | 2 +- core/modules/filters/shadowsource.js | 6 +- core/modules/pluginswitcher.js | 10 +- core/modules/wiki.js | 13 +- editions/test/tiddlers/tests/test-filters.js | 60 +++-- 6 files changed, 193 insertions(+), 163 deletions(-) diff --git a/boot/boot.js b/boot/boot.js index 418936418..2afc44d9d 100644 --- a/boot/boot.js +++ b/boot/boot.js @@ -798,39 +798,56 @@ $tw.modules.define("$:/boot/tiddlerfields/list","tiddlerfield",{ /////////////////////////// Barebones wiki store /* -Construct a wiki store object +Wiki constructor. State is stored in private members that only a small number of privileged accessor methods have direct access. Methods added via the prototype have to use these accessors and cannot access the state data directly. +options include: +shadowTiddlers: Array of shadow tiddlers to be added */ -$tw.Wiki = function() { +$tw.Wiki = function(options) { + options = options || {}; var self = this, - tiddlers = {}; // Hashmap of tiddlers - this.pluginTiddlers = []; // Array of tiddlers containing registered plugins, ordered by priority - this.pluginInfo = {}; // Hashmap of parsed plugin content - this.shadowTiddlers = {}; // Hashmap by title of {source:, tiddler:} - // Methods that need access to the private members + tiddlers = {}, // Hashmap of tiddlers + pluginTiddlers = [], // Array of tiddlers containing registered plugins, ordered by priority + pluginInfo = {}, // Hashmap of parsed plugin content + shadowTiddlers = options.shadowTiddlers || {}; // Hashmap by title of {source:, tiddler:} + + // Add a tiddler to the store this.addTiddler = function(tiddler) { if(!(tiddler instanceof $tw.Tiddler)) { tiddler = new $tw.Tiddler(tiddler); } - // Get the title - var title = tiddler.fields.title; // Save the tiddler - if(title) { - tiddlers[title] = tiddler; - this.clearCache(title); - this.clearGlobalCache(); - this.enqueueTiddlerEvent(title); + if(tiddler) { + var title = tiddler.fields.title; + if(title) { + tiddlers[title] = tiddler; + this.clearCache(title); + this.clearGlobalCache(); + this.enqueueTiddlerEvent(title); + } } }; + + // Delete a tiddler + this.deleteTiddler = function(title) { + delete tiddlers[title]; + this.clearCache(title); + this.clearGlobalCache(); + this.enqueueTiddlerEvent(title,true); + }; + + // Get a tiddler from the store this.getTiddler = function(title) { var t = tiddlers[title]; if(t instanceof $tw.Tiddler) { return t; - } else if(title !== undefined && $tw.utils.hop(self.shadowTiddlers,title)) { - return self.shadowTiddlers[title].tiddler; + } else if(title !== undefined && $tw.utils.hop(shadowTiddlers,title)) { + return shadowTiddlers[title].tiddler; } else { return undefined; } }; + + // Get a hashmap of all tiddler titles this.getAllTitles = function() { var results = {}; for(var title in tiddlers) { @@ -838,20 +855,122 @@ $tw.Wiki = function() { } return results; }; + + // Iterate through all tiddler titles this.each = function(callback) { for(var title in tiddlers) { callback(tiddlers[title],title); } }; + + // Iterate through all shadow tiddler titles + this.eachShadow = function(callback) { + for(var title in shadowTiddlers) { + var shadowInfo = shadowTiddlers[title]; + callback(shadowInfo.tiddler,title); + } + }; + + // Test for the existence of a tiddler this.tiddlerExists = function(title) { return !!$tw.utils.hop(tiddlers,title); }; - this.deleteTiddler = function(title) { - delete tiddlers[title]; - this.clearCache(title); - this.clearGlobalCache(); - this.enqueueTiddlerEvent(title,true); + + // Determines if a tiddler is a shadow tiddler, regardless of whether it has been overridden by a real tiddler + this.isShadowTiddler = function(title) { + return $tw.utils.hop(shadowTiddlers,title); }; + + this.getShadowSource = function(title) { + if($tw.utils.hop(shadowTiddlers,title)) { + return shadowTiddlers[title].source; + } + return null; + }; + + // Read plugin info for all plugins + this.readPluginInfo = function() { + for(var title in tiddlers) { + var tiddler = tiddlers[title]; + if(tiddler.fields.type === "application/json" && tiddler.hasField("plugin-type")) { + pluginInfo[tiddler.fields.title] = JSON.parse(tiddler.fields.text); + } + + } + }; + + // Register the plugin tiddlers of a particular type, optionally restricting registration to an array of tiddler titles. Return the array of titles affected + this.registerPluginTiddlers = function(pluginType,titles) { + var self = this, + registeredTitles = [], + checkTiddler = function(tiddler) { + if(tiddler && tiddler.fields.type === "application/json" && tiddler.fields["plugin-type"] === pluginType) { + pluginTiddlers.push(tiddler); + registeredTitles.push(tiddler.fields.title); + } + }; + if(titles) { + $tw.utils.each(titles,function(title) { + checkTiddler(self.getTiddler(title)); + }); + } else { + this.each(function(tiddler,title) { + checkTiddler(tiddler); + }); + } + return registeredTitles; + }; + + // Unregister the plugin tiddlers of a particular type, returning an array of the titles affected + this.unregisterPluginTiddlers = function(pluginType) { + var self = this, + titles = []; + // Remove any previous registered plugins of this type + for(var t=pluginTiddlers.length-1; t>=0; t--) { + var tiddler = pluginTiddlers[t]; + if(tiddler.fields["plugin-type"] === pluginType) { + titles.push(tiddler.fields.title); + pluginTiddlers.splice(t,1); + } + } + return titles; + }; + + // Unpack the currently registered plugins, creating shadow tiddlers for their constituent tiddlers + this.unpackPluginTiddlers = function() { + var self = this; + // Sort the plugin titles by the `plugin-priority` field + pluginTiddlers.sort(function(a,b) { + if("plugin-priority" in a.fields && "plugin-priority" in b.fields) { + return a.fields["plugin-priority"] - b.fields["plugin-priority"]; + } else if("plugin-priority" in a.fields) { + return -1; + } else if("plugin-priority" in b.fields) { + return +1; + } else if(a.fields.title < b.fields.title) { + return -1; + } else if(a.fields.title === b.fields.title) { + return 0; + } else { + return +1; + } + }); + // Now go through the plugins in ascending order and assign the shadows + shadowTiddlers = {}; + $tw.utils.each(pluginTiddlers,function(tiddler) { + // Extract the constituent tiddlers + $tw.utils.each(pluginInfo[tiddler.fields.title].tiddlers,function(constituentTiddler,constituentTitle) { + // Save the tiddler object + if(constituentTitle) { + shadowTiddlers[constituentTitle] = { + source: tiddler.fields.title, + tiddler: new $tw.Tiddler(constituentTiddler,{title: constituentTitle}) + }; + } + }); + }); + }; + }; // Dummy methods that will be filled in after boot @@ -859,103 +978,13 @@ $tw.Wiki.prototype.clearCache = $tw.Wiki.prototype.clearGlobalCache = $tw.Wiki.prototype.enqueueTiddlerEvent = function() {}; +// Add an array of tiddlers $tw.Wiki.prototype.addTiddlers = function(tiddlers) { for(var t=0; t=0; t--) { - var tiddler = this.pluginTiddlers[t]; - if(tiddler.fields["plugin-type"] === pluginType) { - titles.push(tiddler.fields.title); - this.pluginTiddlers.splice(t,1); - } - } - return titles; -}; - -/* -Unpack the currently registered plugins, creating shadow tiddlers for their constituent tiddlers -*/ -$tw.Wiki.prototype.unpackPluginTiddlers = function() { - var self = this; - // Sort the plugin titles by the `plugin-priority` field - this.pluginTiddlers.sort(function(a,b) { - if("plugin-priority" in a.fields && "plugin-priority" in b.fields) { - return a.fields["plugin-priority"] - b.fields["plugin-priority"]; - } else if("plugin-priority" in a.fields) { - return -1; - } else if("plugin-priority" in b.fields) { - return +1; - } else if(a.fields.title < b.fields.title) { - return -1; - } else if(a.fields.title === b.fields.title) { - return 0; - } else { - return +1; - } - }); - // Now go through the plugins in ascending order and assign the shadows - this.shadowTiddlers = {}; - $tw.utils.each(this.pluginTiddlers,function(tiddler) { - // Extract the constituent tiddlers - $tw.utils.each(self.pluginInfo[tiddler.fields.title].tiddlers,function(constituentTiddler,constituentTitle) { - // Save the tiddler object - if(constituentTitle) { - self.shadowTiddlers[constituentTitle] = { - source: tiddler.fields.title, - tiddler: new $tw.Tiddler(constituentTiddler,{title: constituentTitle}) - }; - } - }); - }); -}; - /* Define all modules stored in ordinary tiddlers */ @@ -985,13 +1014,11 @@ Register all the module tiddlers that have a module type */ $tw.Wiki.prototype.defineShadowModules = function() { var self = this; - $tw.utils.each(this.shadowTiddlers,function(element,title) { - var tiddler = self.getTiddler(title); - if(!self.tiddlerExists(title)) { // Don't define the module if it is overidden by an ordinary tiddler - if(tiddler.hasField("module-type")) { - // Define the module - $tw.modules.define(tiddler.fields.title,tiddler.fields["module-type"],tiddler.fields.text); - } + this.eachShadow(function(tiddler,title) { + // Don't define the module if it is overidden by an ordinary tiddler + if(!self.tiddlerExists(title) && tiddler.hasField("module-type")) { + // Define the module + $tw.modules.define(tiddler.fields.title,tiddler.fields["module-type"],tiddler.fields.text); } }); }; diff --git a/core/modules/filters/is/shadow.js b/core/modules/filters/is/shadow.js index 4ea734240..dfd99c2b7 100644 --- a/core/modules/filters/is/shadow.js +++ b/core/modules/filters/is/shadow.js @@ -34,7 +34,7 @@ exports.shadow = function(source,prefix,options) { }); } else { if(prefix !== "!") { - $tw.utils.each(options.wiki.shadowTiddlers,function(tiddler,title) { + options.wiki.eachShadow(function(tiddler,title) { results.push(title); }); } else { diff --git a/core/modules/filters/shadowsource.js b/core/modules/filters/shadowsource.js index e1d7d36d2..d34a51b91 100644 --- a/core/modules/filters/shadowsource.js +++ b/core/modules/filters/shadowsource.js @@ -18,9 +18,9 @@ Export our filter function exports.shadowsource = function(source,operator,options) { var results = [], pushShadowSource = function(title) { - var shadowInfo = options.wiki.shadowTiddlers[title]; - if(shadowInfo) { - $tw.utils.pushTop(results,shadowInfo.source); + var source = options.wiki.getShadowSource(title); + if(source) { + $tw.utils.pushTop(results,source); } }; // Iterate through the source tiddlers diff --git a/core/modules/pluginswitcher.js b/core/modules/pluginswitcher.js index 473e1b351..1d38b5f33 100644 --- a/core/modules/pluginswitcher.js +++ b/core/modules/pluginswitcher.js @@ -62,8 +62,9 @@ PluginSwitcher.prototype.switchPlugins = function() { var unregisteredTiddlers = $tw.wiki.unregisterPluginTiddlers(this.pluginType); // Accumulate the titles of shadow tiddlers that have changed as a result of this switch var changedTiddlers = {}; - $tw.utils.each(this.wiki.shadowTiddlers,function(shadowInfo,title) { - if(unregisteredTiddlers.indexOf(shadowInfo.source) !== -1) { + this.wiki.eachShadow(function(tiddler,title) { + var source = self.wiki.getShadowSource(title); + if(unregisteredTiddlers.indexOf(source) !== -1) { changedTiddlers[title] = true; // isDeleted? } }); @@ -72,8 +73,9 @@ PluginSwitcher.prototype.switchPlugins = function() { // Unpack the current theme tiddlers $tw.wiki.unpackPluginTiddlers(); // Accumulate the affected shadow tiddlers - $tw.utils.each(this.wiki.shadowTiddlers,function(shadowInfo,title) { - if(registeredTiddlers.indexOf(shadowInfo.source) !== -1) { + this.wiki.eachShadow(function(tiddler,title) { + var source = self.wiki.getShadowSource(title); + if(registeredTiddlers.indexOf(source) !== -1) { changedTiddlers[title] = false; // isDeleted? } }); diff --git a/core/modules/wiki.js b/core/modules/wiki.js index 5e2fda05e..838004f40 100755 --- a/core/modules/wiki.js +++ b/core/modules/wiki.js @@ -178,13 +178,6 @@ exports.isTemporaryTiddler = function(title) { return title.indexOf("$:/temp/") === 0; }; -/* -Determines if a tiddler is a shadow tiddler, regardless of whether it has been overridden by a real tiddler -*/ -exports.isShadowTiddler = function(title) { - return $tw.utils.hop(this.shadowTiddlers,title); -}; - exports.isImageTiddler = function(title) { var tiddler = this.getTiddler(title); if(tiddler) { @@ -453,12 +446,12 @@ exports.getTagMap = function() { }, title, tiddler; // Collect up all the tags - for(title in self.shadowTiddlers) { + self.eachShadow(function(tiddler,title) { if(!self.tiddlerExists(title)) { - tiddler = self.shadowTiddlers[title].tiddler; + tiddler = self.getTiddler(title); storeTags(tiddler.fields.tags,title); } - } + }); self.each(function(tiddler,title) { storeTags(tiddler.fields.tags,title); }); diff --git a/editions/test/tiddlers/tests/test-filters.js b/editions/test/tiddlers/tests/test-filters.js index a236da15b..c59a21a4e 100644 --- a/editions/test/tiddlers/tests/test-filters.js +++ b/editions/test/tiddlers/tests/test-filters.js @@ -15,13 +15,36 @@ Tests the filtering mechanism. describe("Filter tests", function() { // Create a wiki - var wiki = new $tw.Wiki(); - - // Some helpers - var addShadowTiddler = function(fields) { - var tiddler = new $tw.Tiddler(fields); - wiki.shadowTiddlers[tiddler.fields.title] = {tiddler: tiddler}; - }; + var wiki = new $tw.Wiki({ + shadowTiddlers: { + "$:/TiddlerFive": { + tiddler: new $tw.Tiddler({title: "$:/TiddlerFive", + text: "Everything in federation", + tags: ["two"] + }), + }, + "TiddlerSix": { + tiddler: new $tw.Tiddler({title: "TiddlerSix", + text: "Missing inaction from TiddlerOne", + tags: [] + }), + }, + "TiddlerSeventh": { + tiddler: new $tw.Tiddler({title: "TiddlerSeventh", + text: "", + list: "TiddlerOne [[Tiddler Three]] [[a fourth tiddler]] MissingTiddler", + tags: [] + }), + }, + "Tiddler8": { + tiddler: new $tw.Tiddler({title: "Tiddler8", + text: "Tidd", + tags: [], + "test-field": "JoeBloggs" + }) + } + } + }); // Add a few tiddlers wiki.addTiddler({ @@ -52,28 +75,13 @@ describe("Filter tests", function() { text: "This is the text of tiddler [[one]]", list: "[[Tiddler Three]] [[TiddlerOne]]", modifier: "JohnDoe"}); - // And some shadows - addShadowTiddler({ - title: "$:/TiddlerFive", - text: "Everything in federation", - tags: ["two"]}); - addShadowTiddler({ - title: "TiddlerSix", - text: "Missing inaction from TiddlerOne", - tags: []}); - addShadowTiddler({ - title: "TiddlerSeventh", - text: "", - list: "TiddlerOne [[Tiddler Three]] [[a fourth tiddler]] MissingTiddler", - tags: []}); - addShadowTiddler({ - title: "Tiddler8", - text: "Tidd", - tags: [], - "test-field": "JoeBloggs"}); // Our tests + it("should retrieve shadow tiddlers", function() { + expect(wiki.getTiddlerText("Tiddler8")).toBe("Tidd"); + }); + it("should handle the title operator", function() { expect(wiki.filterTiddlers("TiddlerOne [title[$:/TiddlerTwo]] [[Tiddler Three]]").join(",")).toBe("TiddlerOne,$:/TiddlerTwo,Tiddler Three"); expect(wiki.filterTiddlers("[!title[Tiddler Three]]").join(",")).toBe("TiddlerOne,$:/TiddlerTwo,a fourth tiddler,one");