1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-11-27 12:07:19 +00:00

Refactoring plugin implementation

Including introducing the terminology "tiddler bundles"
This commit is contained in:
Jeremy Ruston 2012-11-12 22:16:49 +00:00
parent c04f11f3ff
commit 3b11713e88
5 changed files with 119 additions and 112 deletions

View File

@ -82,9 +82,6 @@ $tw.modules = $tw.modules || {};
$tw.modules.titles = $tw.modules.titles || {}; // hashmap by module title of {fn:, exports:, moduleType:} $tw.modules.titles = $tw.modules.titles || {}; // hashmap by module title of {fn:, exports:, moduleType:}
$tw.modules.types = $tw.modules.types || {}; // hashmap by module type of array of exports $tw.modules.types = $tw.modules.types || {}; // hashmap by module type of array of exports
// Plugin information
$tw.plugins = $tw.plugins || {};
// Config object // Config object
$tw.config = $tw.config || {}; $tw.config = $tw.config || {};
@ -259,7 +256,7 @@ $tw.utils.resolvePath = function(sourcepath,rootpath) {
}; };
/* /*
Returns true if the `actual` version is greater than or equal to the `required` version. Both are in `x.y.` format. Returns true if the `actual` version is greater than or equal to the `required` version. Both are in `x.y.z` format.
*/ */
$tw.utils.checkVersions = function(required,actual) { $tw.utils.checkVersions = function(required,actual) {
var targetVersion = required.split("."), var targetVersion = required.split("."),
@ -364,6 +361,9 @@ $tw.Tiddler = function(/* [fields,] fields */) {
} }
}; };
$tw.Tiddler.prototype.hasField = function(field) {
return $tw.utils.hop(this.fields,field);
};
/* /*
Hashmap of field modules by field name Hashmap of field modules by field name
*/ */
@ -423,25 +423,25 @@ $tw.Wiki.prototype.addTiddlers = function(tiddlers) {
}; };
/* /*
Extract tiddlers stored in plugins so that we can easily access them in getTiddler() Extract constituent tiddlers from bundle tiddlers so that we can easily access them in getTiddler()
*/ */
$tw.Wiki.prototype.installPlugins = function() { $tw.Wiki.prototype.unpackBundleTiddlers = function() {
this.plugins = {}; // Hashmap of plugin information by title this.bundles = {}; // Hashmap of plugin information by title
this.pluginTiddlers = {}; // Hashmap of constituent tiddlers from plugins by title this.bundledTiddlers = {}; // Hashmap of constituent tiddlers from plugins by title
// Collect up all the plugin tiddlers // Collect up all the plugin tiddlers
for(var title in this.tiddlers) { for(var title in this.tiddlers) {
var tiddler = this.tiddlers[title]; var tiddler = this.tiddlers[title];
if(tiddler.fields.type === "application/json" && "plugin" in tiddler.fields) { if(tiddler.fields.type === "application/json" && tiddler.hasField("bundle")) {
// Save the plugin information // Save the bundle information
var pluginInfo = this.plugins[title] = JSON.parse(tiddler.fields.text); var bundleInfo = this.bundles[title] = JSON.parse(tiddler.fields.text);
// Extract the constituent tiddlers // Extract the constituent tiddlers
for(var t in pluginInfo.tiddlers) { for(var t in bundleInfo.tiddlers) {
var constituentTiddler = pluginInfo.tiddlers[t], var constituentTiddler = bundleInfo.tiddlers[t],
constituentTitle = pluginInfo.title + "/" + t; constituentTitle = bundleInfo.title + "/" + t;
// Don't overwrite tiddlers that already exist // Don't overwrite tiddlers that already exist
if(!(constituentTitle in this.pluginTiddlers)) { if(!(constituentTitle in this.bundledTiddlers)) {
// Save the tiddler object // Save the tiddler object
this.pluginTiddlers[constituentTitle] = new $tw.Tiddler(constituentTiddler,{title: constituentTitle}); this.bundledTiddlers[constituentTitle] = new $tw.Tiddler(constituentTiddler,{title: constituentTitle});
} }
} }
} }
@ -454,12 +454,13 @@ Register all the module tiddlers that have a module type
$tw.Wiki.prototype.registerModuleTiddlers = function() { $tw.Wiki.prototype.registerModuleTiddlers = function() {
/*jslint evil: true */ /*jslint evil: true */
var title, tiddler; var title, tiddler;
// If in the browser, define any modules from plugins // If in the browser, define any modules from bundles
if($tw.browser) { if($tw.browser) {
for(title in $tw.wiki.pluginTiddlers) { for(title in $tw.wiki.bundledTiddlers) {
if($tw.utils.hop($tw.wiki.bundledTiddlers,title)) {
tiddler = $tw.wiki.getTiddler(title); tiddler = $tw.wiki.getTiddler(title);
if(!(title in $tw.wiki.tiddlers)) { if(!$tw.utils.hop($tw.wiki.tiddlers,title)) {
if(tiddler.fields.type === "application/javascript" && "module-type" in tiddler.fields) { if(tiddler.fields.type === "application/javascript" && tiddler.hasField("module-type")) {
// Define the module // Define the module
var source = [ var source = [
"(function(module,exports,require) {", "(function(module,exports,require) {",
@ -471,37 +472,44 @@ $tw.Wiki.prototype.registerModuleTiddlers = function() {
} }
} }
} }
// Register and execute any modules from plugins }
for(title in $tw.wiki.pluginTiddlers) { // Register and execute any modules from bundles
for(title in $tw.wiki.bundledTiddlers) {
if($tw.utils.hop($tw.wiki.bundledTiddlers,title)) {
tiddler = $tw.wiki.getTiddler(title); tiddler = $tw.wiki.getTiddler(title);
if(!(title in $tw.wiki.tiddlers)) { if(!$tw.utils.hop($tw.wiki.tiddlers,title)) {
if(tiddler.fields.type === "application/javascript" && "module-type" in tiddler.fields) { if(tiddler.fields.type === "application/javascript" && tiddler.hasField("module-type")) {
// Execute and register the module // Execute and register the module
$tw.modules.registerModuleExports(title,tiddler.fields["module-type"],$tw.modules.execute(title)); $tw.modules.registerModuleExports(title,tiddler.fields["module-type"],$tw.modules.execute(title));
} }
} }
} }
}
// Register and execute any modules in ordinary tiddlers // Register and execute any modules in ordinary tiddlers
if($tw.browser) { if($tw.browser) {
for(title in $tw.modules.titles) { for(title in $tw.modules.titles) {
if($tw.utils.hop($tw.modules.titles,title)) {
$tw.modules.registerModuleExports(title,$tw.modules.titles[title].moduleType,$tw.modules.execute(title)); $tw.modules.registerModuleExports(title,$tw.modules.titles[title].moduleType,$tw.modules.execute(title));
} }
}
} else { } else {
for(title in $tw.wiki.tiddlers) { for(title in $tw.wiki.tiddlers) {
if($tw.utils.hop($tw.wiki.tiddlers,title)) {
tiddler = $tw.wiki.getTiddler(title); tiddler = $tw.wiki.getTiddler(title);
if(tiddler.fields.type === "application/javascript" && tiddler.fields["module-type"] !== undefined) { if(tiddler.fields.type === "application/javascript" && tiddler.hasField("module-type")) {
$tw.modules.registerModuleExports(title,tiddler.fields["module-type"],$tw.modules.execute(title)); $tw.modules.registerModuleExports(title,tiddler.fields["module-type"],$tw.modules.execute(title));
} }
} }
} }
}
}; };
$tw.Wiki.prototype.getTiddler = function(title) { $tw.Wiki.prototype.getTiddler = function(title) {
var t = this.tiddlers[title]; var t = this.tiddlers[title];
if(t instanceof $tw.Tiddler) { if(t instanceof $tw.Tiddler) {
return t; return t;
} else if(title in this.pluginTiddlers) { } else if($tw.utils.hop(this.bundledTiddlers,title)) {
return this.pluginTiddlers[title]; return this.bundledTiddlers[title];
} else { } else {
return null; return null;
} }
@ -702,22 +710,6 @@ $tw.modules.registerModuleExports("$:/boot/tiddlerdeserializer/dom","tiddlerdese
// Install the tiddler deserializer modules // Install the tiddler deserializer modules
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules); $tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
// Load the JavaScript system tiddlers from the DOM
$tw.wiki.addTiddlers($tw.wiki.deserializeTiddlers("(DOM)",document.getElementById("libraryModules")));
$tw.wiki.addTiddlers($tw.wiki.deserializeTiddlers("(DOM)",document.getElementById("modules")));
$tw.wiki.addTiddlers($tw.wiki.deserializeTiddlers("(DOM)",document.getElementById("bootKernelPrefix")));
$tw.wiki.addTiddlers($tw.wiki.deserializeTiddlers("(DOM)",document.getElementById("bootKernel")));
// Load the stylesheet tiddlers from the DOM
$tw.wiki.addTiddlers($tw.wiki.deserializeTiddlers("(DOM)",document.getElementById("styleArea")));
// Load the main store tiddlers from the DOM
$tw.wiki.addTiddlers($tw.wiki.deserializeTiddlers("(DOM)",document.getElementById("storeArea")));
// Load the shadow tiddlers from the DOM
$tw.wiki.addTiddlers($tw.wiki.deserializeTiddlers("(DOM)",document.getElementById("shadowArea")));
// Load any preloaded tiddlers
if($tw.preloadTiddlers) {
$tw.wiki.addTiddlers($tw.preloadTiddlers);
}
// End of if($tw.browser) // End of if($tw.browser)
} }
@ -728,7 +720,7 @@ if(!$tw.browser) {
/* /*
Load the tiddlers contained in a particular file (and optionally extract fields from the accompanying .meta file) Load the tiddlers contained in a particular file (and optionally extract fields from the accompanying .meta file)
*/ */
$tw.extractTiddlersFromFile = function(filepath,fields) { $tw.loadTiddlersFromFile = function(filepath,fields) {
var ext = path.extname(filepath), var ext = path.extname(filepath),
extensionInfo = $tw.config.fileExtensionInfo[ext], extensionInfo = $tw.config.fileExtensionInfo[ext],
typeInfo = extensionInfo ? $tw.config.contentTypeInfo[extensionInfo.type] : null, typeInfo = extensionInfo ? $tw.config.contentTypeInfo[extensionInfo.type] : null,
@ -747,8 +739,7 @@ $tw.extractTiddlersFromFile = function(filepath,fields) {
/* /*
Load all the tiddlers from a directory Load all the tiddlers from a directory
*/ */
$tw.extractTiddlersFromPath = function(filepath,basetitle,excludeRegExp) { $tw.loadTiddlersFromPath = function(filepath,excludeRegExp) {
basetitle = basetitle || "$:/plugins";
excludeRegExp = excludeRegExp || /^\.DS_Store$|.meta$/; excludeRegExp = excludeRegExp || /^\.DS_Store$|.meta$/;
var tiddlers = [], var tiddlers = [],
stat, files, pluginInfo, pluginTiddlers, f, file, titlePrefix, t, filesInfo, p, tidInfo, typeInfo, text; stat, files, pluginInfo, pluginTiddlers, f, file, titlePrefix, t, filesInfo, p, tidInfo, typeInfo, text;
@ -756,33 +747,8 @@ $tw.extractTiddlersFromPath = function(filepath,basetitle,excludeRegExp) {
stat = fs.statSync(filepath); stat = fs.statSync(filepath);
if(stat.isDirectory()) { if(stat.isDirectory()) {
files = fs.readdirSync(filepath); files = fs.readdirSync(filepath);
// Look for a tiddlywiki.plugin file
if(files.indexOf("tiddlywiki.plugin") !== -1) {
// Read the plugin information
pluginInfo = JSON.parse(fs.readFileSync(filepath + "/tiddlywiki.plugin").toString("utf8"));
// Read the plugin files
pluginTiddlers = [];
for(f=0; f<files.length; f++) {
file = files[f];
if(!excludeRegExp.test(file) && file !== "tiddlywiki.plugin" && file !== "tiddlywiki.files") {
pluginTiddlers.push.apply(pluginTiddlers,$tw.extractTiddlersFromPath(filepath + "/" + file,basetitle + "/" + file,excludeRegExp));
}
}
// Save the plugin tiddlers into the plugin
pluginInfo.tiddlers = pluginInfo.tiddlers || {};
titlePrefix = pluginInfo.title + "/";
for(t=0; t<pluginTiddlers.length; t++) {
// Check that the constituent tiddler has the plugin title as a prefix
if(pluginTiddlers[t].title.indexOf(titlePrefix) === 0 && pluginTiddlers[t].title.length > titlePrefix.length) {
pluginInfo.tiddlers[pluginTiddlers[t].title.substr(titlePrefix.length)] = pluginTiddlers[t];
} else {
throw "The plugin '" + pluginInfo.title + "' cannot contain a tiddler titled '" + pluginTiddlers[t].title + "'";
}
}
// Save the plugin tiddler
tiddlers.push({title: pluginInfo.title, type: "application/json", plugin: "yes", text: JSON.stringify(pluginInfo)});
// Look for a tiddlywiki.files file // Look for a tiddlywiki.files file
} else if(files.indexOf("tiddlywiki.files") !== -1) { if(files.indexOf("tiddlywiki.files") !== -1) {
// If so, process the files it describes // If so, process the files it describes
filesInfo = JSON.parse(fs.readFileSync(filepath + "/tiddlywiki.files").toString("utf8")); filesInfo = JSON.parse(fs.readFileSync(filepath + "/tiddlywiki.files").toString("utf8"));
for(p=0; p<filesInfo.tiddlers.length; p++) { for(p=0; p<filesInfo.tiddlers.length; p++) {
@ -797,22 +763,49 @@ $tw.extractTiddlersFromPath = function(filepath,basetitle,excludeRegExp) {
for(f=0; f<files.length; f++) { for(f=0; f<files.length; f++) {
file = files[f]; file = files[f];
if(!excludeRegExp.test(file)) { if(!excludeRegExp.test(file)) {
tiddlers.push.apply(tiddlers,$tw.extractTiddlersFromPath(filepath + "/" + file,basetitle + "/" + file,excludeRegExp)); tiddlers.push.apply(tiddlers,$tw.loadTiddlersFromPath(filepath + "/" + file,excludeRegExp));
} }
} }
} }
} else if(stat.isFile()) { } else if(stat.isFile()) {
tiddlers.push.apply(tiddlers,$tw.extractTiddlersFromFile(filepath,{title: basetitle})); tiddlers.push.apply(tiddlers,$tw.loadTiddlersFromFile(filepath));
} }
} }
return tiddlers; return tiddlers;
}; };
/* /*
Load all the tiddlers from a directory Load the tiddlers from a bundle folder, and package them up into a proper JSON bundle tiddler
*/ */
$tw.loadTiddlersFromFolder = function(filepath,basetitle,excludeRegExp) { $tw.loadBundleFolder = function(filepath,excludeRegExp) {
$tw.wiki.addTiddlers($tw.extractTiddlersFromPath(filepath,basetitle,excludeRegExp)); // Read the plugin information
var bundleInfo = JSON.parse(fs.readFileSync(filepath).toString("utf8"));
// Read the bundle files
var bundleTiddlers = [];
for(f=0; f<files.length; f++) {
file = files[f];
if(!excludeRegExp.test(file) && file !== "plugin.bundle" && file !== "tiddlywiki.files") {
bundleTiddlers.push.apply(bundleTiddlers,$tw.loadTiddlersFromPath(filepath + "/" + file,excludeRegExp));
}
}
// Save the bundle tiddlers into the bundle
bundleInfo.tiddlers = bundleInfo.tiddlers || {};
var titlePrefix = bundleInfo.title + "/";
for(t=0; t<bundleTiddlers.length; t++) {
// Check that the constituent tiddler has the bundle title as a prefix
if(bundleTiddlers[t].title.indexOf(titlePrefix) === 0 && bundleTiddlers[t].title.length > titlePrefix.length) {
bundleInfo.tiddlers[bundleTiddlers[t].title.substr(titlePrefix.length)] = bundleTiddlers[t];
} else {
throw "The bundle '" + bundleInfo.title + "' cannot contain a tiddler titled '" + bundleTiddlers[t].title + "'";
}
}
// Save the bundle tiddler
return {
title: bundleInfo.title,
type: "application/json",
bundle: "yes",
text: JSON.stringify(bundleInfo)
};
}; };
/* /*
@ -854,28 +847,46 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
return module.exports; return module.exports;
}; };
// Load modules from the modules directory
$tw.loadTiddlersFromFolder(path.resolve($tw.boot.bootPath,$tw.config.bootModuleSubDir));
// Load up the shadow tiddlers in the root of the core directory
$tw.loadTiddlersFromFolder($tw.boot.bootPath,"$:/core",/^\.DS_Store$|.meta$|^modules$/);
// Load any plugins in the wiki plugins directory
$tw.loadTiddlersFromFolder(path.resolve($tw.boot.wikiPath,$tw.config.wikiPluginsSubDir));
// HACK: to be replaced when we re-establish sync plugins
// Load shadow tiddlers from wiki shadows directory
$tw.loadTiddlersFromFolder(path.resolve($tw.boot.wikiPath,$tw.config.wikiShadowsSubDir));
// Load tiddlers from wiki tiddlers directory
$tw.loadTiddlersFromFolder(path.resolve($tw.boot.wikiPath,$tw.config.wikiTiddlersSubDir));
// End of if(!$tw.browser) // End of if(!$tw.browser)
} }
/////////////////////////// Final initialisation /////////////////////////// Final initialisation
// Load tiddlers
var t;
if($tw.browser) {
// In the browser, we load tiddlers from certain elements
var containerIds = [
"libraryModules",
"modules",
"bootKernelPrefix",
"bootKernel",
"styleArea",
"storeArea",
"shadowArea"
];
for(t=0; t<containerIds.length; t++) {
$tw.wiki.addTiddlers($tw.wiki.deserializeTiddlers("(DOM)",document.getElementById(containerIds[t])));
}
// Load any preloaded tiddlers
if($tw.preloadTiddlers) {
$tw.wiki.addTiddlers($tw.preloadTiddlers);
}
} else {
// On the server, we load tiddlers from specified folders
var folders = [
$tw.boot.bootPath,
path.resolve($tw.boot.wikiPath,$tw.config.wikiPluginsSubDir),
path.resolve($tw.boot.wikiPath,$tw.config.wikiShadowsSubDir),
path.resolve($tw.boot.wikiPath,$tw.config.wikiTiddlersSubDir)
];
for(t=0; t<folders.length; t++) {
$tw.wiki.addTiddlers($tw.loadTiddlersFromPath(folders[t]));
}
}
// Install plugins // Install plugins
$tw.wiki.installPlugins(); $tw.wiki.unpackBundleTiddlers();
// Register typed modules from the tiddlers we've just loaded // Register typed modules from the tiddlers we've just loaded
$tw.wiki.registerModuleTiddlers(); $tw.wiki.registerModuleTiddlers();

View File

@ -16,10 +16,6 @@ exports.hasTag = function(tag) {
return this.fields.tags && this.fields.tags.indexOf(tag) !== -1; return this.fields.tags && this.fields.tags.indexOf(tag) !== -1;
}; };
exports.hasField = function(field) {
return $tw.utils.hop(this.fields,field);
};
exports.isShadow = function() { exports.isShadow = function() {
if(!$tw.utils.hop(this,"shadowFlag")) { if(!$tw.utils.hop(this,"shadowFlag")) {
this.shadowFlag = this.fields.title.indexOf("$:/") === 0; this.shadowFlag = this.fields.title.indexOf("$:/") === 0;

View File

@ -1,6 +1,6 @@
title: TemporaryTestPlugin title: TemporaryTestPlugin
type: application/json type: application/json
plugin: yes bundle: yes
{ {
"title": "$:/plugins/tiddlywiki/test", "title": "$:/plugins/tiddlywiki/test",