mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-27 03:57:21 +00:00
Further refactoring of the boot process and module mechanism
This commit is contained in:
parent
539b64b626
commit
9281fa8786
239
core/boot.js
239
core/boot.js
@ -29,11 +29,16 @@ In practice, each module is wrapped in a separate script block.
|
||||
/////////////////////////// Setting up $tw
|
||||
|
||||
// Set up $tw global for the server
|
||||
if(typeof(window) === "undefined" && !global.$tw) {
|
||||
global.$tw = {}; // No `browser` member for the server
|
||||
if(typeof(window) === "undefined") {
|
||||
global.$tw = global.$tw || {}; // No `browser` member for the server
|
||||
exports.$tw = $tw; // Export $tw for when boot.js is required directly in node.js
|
||||
}
|
||||
|
||||
// Include bootprefix if we're on the server
|
||||
if(!$tw.browser) {
|
||||
require("./bootprefix.js");
|
||||
}
|
||||
|
||||
// Crypto helper object
|
||||
|
||||
// Setup crypto
|
||||
@ -57,7 +62,6 @@ var Crypto = function() {
|
||||
password = window.prompt("Enter password to decrypt TiddlyWiki");
|
||||
}
|
||||
};
|
||||
|
||||
this.setPassword = function(newPassword) {
|
||||
password = newPassword;
|
||||
};
|
||||
@ -293,19 +297,6 @@ if(!$tw.browser) {
|
||||
|
||||
/////////////////////////// Module mechanism
|
||||
|
||||
/*
|
||||
Register the exports of a single module in the $tw.modules.types hashmap
|
||||
*/
|
||||
$tw.modules.registerModuleExports = function(name,moduleType,moduleExports) {
|
||||
if(!$tw.utils.hop($tw.modules.types,moduleType)) {
|
||||
$tw.modules.types[moduleType] = {};
|
||||
}
|
||||
if($tw.utils.hop($tw.modules.types[moduleType],name)) {
|
||||
console.log("Warning: Reregistering module - " + name);
|
||||
}
|
||||
$tw.modules.types[moduleType][name] = moduleExports;
|
||||
};
|
||||
|
||||
/*
|
||||
Apply a callback to each module of a particular type
|
||||
moduleType: type of modules to enumerate
|
||||
@ -316,7 +307,7 @@ $tw.modules.forEachModuleOfType = function(moduleType,callback) {
|
||||
if(modules) {
|
||||
for(var title in modules) {
|
||||
if($tw.utils.hop(modules,title)) {
|
||||
callback(title,modules[title]);
|
||||
callback(title,$tw.modules.execute(title));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -379,6 +370,7 @@ $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
|
||||
*/
|
||||
@ -387,17 +379,17 @@ $tw.Tiddler.fieldModules = {};
|
||||
/*
|
||||
Register and install the built in tiddler field modules
|
||||
*/
|
||||
$tw.modules.registerModuleExports("$:/boot/tiddlerfields/modified","tiddlerfield",{
|
||||
$tw.modules.define("$:/boot/tiddlerfields/modified","tiddlerfield",{
|
||||
name: "modified",
|
||||
parse: $tw.utils.parseDate,
|
||||
stringify: $tw.utils.stringifyDate
|
||||
});
|
||||
$tw.modules.registerModuleExports("$:/boot/tiddlerfields/created","tiddlerfield",{
|
||||
$tw.modules.define("$:/boot/tiddlerfields/created","tiddlerfield",{
|
||||
name: "created",
|
||||
parse: $tw.utils.parseDate,
|
||||
stringify: $tw.utils.stringifyDate
|
||||
});
|
||||
$tw.modules.registerModuleExports("$:/boot/tiddlerfields/tags","tiddlerfield",{
|
||||
$tw.modules.define("$:/boot/tiddlerfields/tags","tiddlerfield",{
|
||||
name: "tags",
|
||||
parse: $tw.utils.parseStringArray,
|
||||
stringify: function(value) {
|
||||
@ -412,8 +404,6 @@ $tw.modules.registerModuleExports("$:/boot/tiddlerfields/tags","tiddlerfield",{
|
||||
return result.join(" ");
|
||||
}
|
||||
});
|
||||
// Install built in tiddler fields module so that they are available immediately
|
||||
$tw.Tiddler.fieldModules = $tw.modules.getModulesByTypeAsHashmap("tiddlerfield");
|
||||
|
||||
/////////////////////////// Barebones wiki store
|
||||
|
||||
@ -422,6 +412,8 @@ Construct a wiki store object
|
||||
*/
|
||||
$tw.Wiki = function() {
|
||||
this.tiddlers = {};
|
||||
this.bundles = {}; // Hashmap of plugin information by title
|
||||
this.bundledTiddlers = {}; // Hashmap of constituent tiddlers from plugins by title
|
||||
};
|
||||
|
||||
$tw.Wiki.prototype.addTiddler = function(tiddler) {
|
||||
@ -441,8 +433,6 @@ $tw.Wiki.prototype.addTiddlers = function(tiddlers) {
|
||||
Extract constituent tiddlers from bundle tiddlers so that we can easily access them in getTiddler()
|
||||
*/
|
||||
$tw.Wiki.prototype.unpackBundleTiddlers = function() {
|
||||
this.bundles = {}; // Hashmap of plugin information by title
|
||||
this.bundledTiddlers = {}; // Hashmap of constituent tiddlers from plugins by title
|
||||
// Collect up all the plugin tiddlers
|
||||
for(var title in this.tiddlers) {
|
||||
var tiddler = this.tiddlers[title];
|
||||
@ -463,52 +453,36 @@ $tw.Wiki.prototype.unpackBundleTiddlers = function() {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Define all modules stored in ordinary tiddlers
|
||||
*/
|
||||
$tw.Wiki.prototype.defineTiddlerModules = function() {
|
||||
for(var title in this.tiddlers) {
|
||||
if($tw.utils.hop(this.tiddlers,title)) {
|
||||
var tiddler = this.getTiddler(title);
|
||||
if(tiddler.fields.type === "application/javascript" && tiddler.hasField("module-type")) {
|
||||
// Define the module
|
||||
$tw.modules.define(tiddler.fields.title,tiddler.fields["module-type"],tiddler.fields.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Register all the module tiddlers that have a module type
|
||||
*/
|
||||
$tw.Wiki.prototype.registerModuleTiddlers = function() {
|
||||
/*jslint evil: true */
|
||||
var title, tiddler;
|
||||
// If in the browser, define any modules from bundles
|
||||
if($tw.browser) {
|
||||
for(title in $tw.wiki.bundledTiddlers) {
|
||||
if($tw.utils.hop($tw.wiki.bundledTiddlers,title)) {
|
||||
tiddler = $tw.wiki.getTiddler(title);
|
||||
if(!$tw.utils.hop($tw.wiki.tiddlers,title)) {
|
||||
if(tiddler.fields.type === "application/javascript" && tiddler.hasField("module-type")) {
|
||||
// Define the module
|
||||
var source = [
|
||||
"(function(module,exports,require) {",
|
||||
tiddler.fields.text,
|
||||
"})"
|
||||
];
|
||||
$tw.modules.define(tiddler.fields.title,tiddler.fields["module-type"],window["eval"](source.join("")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
if(!$tw.utils.hop($tw.wiki.tiddlers,title)) {
|
||||
$tw.Wiki.prototype.defineBundledModules = function() {
|
||||
for(var title in this.bundledTiddlers) {
|
||||
if($tw.utils.hop(this.bundledTiddlers,title)) {
|
||||
var tiddler = this.getTiddler(title);
|
||||
if(!$tw.utils.hop(this.tiddlers,title)) {
|
||||
if(tiddler.fields.type === "application/javascript" && tiddler.hasField("module-type")) {
|
||||
// Execute and register the module
|
||||
$tw.modules.registerModuleExports(title,tiddler.fields["module-type"],$tw.modules.execute(title));
|
||||
// Define the module
|
||||
$tw.modules.define(tiddler.fields.title,tiddler.fields["module-type"],tiddler.fields.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Register and execute any modules in ordinary tiddlers
|
||||
for(title in $tw.wiki.tiddlers) {
|
||||
if($tw.utils.hop($tw.wiki.tiddlers,title)) {
|
||||
tiddler = $tw.wiki.getTiddler(title);
|
||||
if(tiddler.fields.type === "application/javascript" && tiddler.hasField("module-type")) {
|
||||
$tw.modules.registerModuleExports(title,tiddler.fields["module-type"],$tw.modules.execute(title));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$tw.Wiki.prototype.getTiddler = function(title) {
|
||||
@ -558,7 +532,7 @@ $tw.Wiki.prototype.deserializeTiddlers = function(type,text,srcFields) {
|
||||
/*
|
||||
Register the built in tiddler deserializer modules
|
||||
*/
|
||||
$tw.modules.registerModuleExports("$:/boot/tiddlerdeserializer/js","tiddlerdeserializer",{
|
||||
$tw.modules.define("$:/boot/tiddlerdeserializer/js","tiddlerdeserializer",{
|
||||
"application/javascript": function(text,fields) {
|
||||
var headerCommentRegExp = new RegExp($tw.config.jsModuleHeaderRegExpString,"mg"),
|
||||
match = headerCommentRegExp.exec(text);
|
||||
@ -569,7 +543,7 @@ $tw.modules.registerModuleExports("$:/boot/tiddlerdeserializer/js","tiddlerdeser
|
||||
return [fields];
|
||||
}
|
||||
});
|
||||
$tw.modules.registerModuleExports("$:/boot/tiddlerdeserializer/tid","tiddlerdeserializer",{
|
||||
$tw.modules.define("$:/boot/tiddlerdeserializer/tid","tiddlerdeserializer",{
|
||||
"application/x-tiddler": function(text,fields) {
|
||||
var split = text.split(/\r?\n\r?\n/mg);
|
||||
if(split.length > 1) {
|
||||
@ -581,30 +555,27 @@ $tw.modules.registerModuleExports("$:/boot/tiddlerdeserializer/tid","tiddlerdese
|
||||
return [fields];
|
||||
}
|
||||
});
|
||||
$tw.modules.registerModuleExports("$:/boot/tiddlerdeserializer/txt","tiddlerdeserializer",{
|
||||
$tw.modules.define("$:/boot/tiddlerdeserializer/txt","tiddlerdeserializer",{
|
||||
"text/plain": function(text,fields) {
|
||||
fields.text = text;
|
||||
fields.type = "text/plain";
|
||||
return [fields];
|
||||
}
|
||||
});
|
||||
$tw.modules.registerModuleExports("$:/boot/tiddlerdeserializer/html","tiddlerdeserializer",{
|
||||
$tw.modules.define("$:/boot/tiddlerdeserializer/html","tiddlerdeserializer",{
|
||||
"text/html": function(text,fields) {
|
||||
fields.text = text;
|
||||
fields.type = "text/html";
|
||||
return [fields];
|
||||
}
|
||||
});
|
||||
$tw.modules.registerModuleExports("$:/boot/tiddlerdeserializer/json","tiddlerdeserializer",{
|
||||
$tw.modules.define("$:/boot/tiddlerdeserializer/json","tiddlerdeserializer",{
|
||||
"application/json": function(text,fields) {
|
||||
var tiddlers = JSON.parse(text);
|
||||
return tiddlers;
|
||||
}
|
||||
});
|
||||
|
||||
// Install the tiddler deserializer modules so they are immediately available
|
||||
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
|
||||
|
||||
/////////////////////////// Intermediate initialisation
|
||||
|
||||
/*
|
||||
@ -625,23 +596,29 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
|
||||
return $tw.modules.execute(modRequire,name);
|
||||
},
|
||||
exports = {},
|
||||
module = $tw.modules.titles[name];
|
||||
if(!module) {
|
||||
moduleInfo = $tw.modules.titles[name];
|
||||
if(!moduleInfo) {
|
||||
throw new Error("Cannot find module named '" + moduleName + "' required by module '" + moduleRoot + "', resolved to " + name);
|
||||
}
|
||||
if(module.exports) {
|
||||
return module.exports;
|
||||
} else {
|
||||
module.exports = {};
|
||||
module.fn(module,module.exports,require);
|
||||
return module.exports;
|
||||
if(!moduleInfo.exports) {
|
||||
if(typeof moduleInfo.definition === "string") { // String
|
||||
moduleInfo.definition = window["eval"]("(function(module,exports,require) {" + moduleInfo.definition + "})");
|
||||
moduleInfo.exports = {};
|
||||
moduleInfo.definition(moduleInfo,moduleInfo.exports,require);
|
||||
} else if(typeof moduleInfo.definition === "function") { // Function
|
||||
moduleInfo.exports = {};
|
||||
moduleInfo.definition(moduleInfo,moduleInfo.exports,require);
|
||||
} else { // Object
|
||||
moduleInfo.exports = moduleInfo.definition;
|
||||
}
|
||||
}
|
||||
return moduleInfo.exports;
|
||||
};
|
||||
|
||||
/*
|
||||
Register a deserializer that can extract tiddlers from the DOM
|
||||
*/
|
||||
$tw.modules.registerModuleExports("$:/boot/tiddlerdeserializer/dom","tiddlerdeserializer",{
|
||||
$tw.modules.define("$:/boot/tiddlerdeserializer/dom","tiddlerdeserializer",{
|
||||
"(DOM)": function(node) {
|
||||
var extractTextTiddlers = function(node) {
|
||||
var e = node.firstChild;
|
||||
@ -714,8 +691,26 @@ $tw.modules.registerModuleExports("$:/boot/tiddlerdeserializer/dom","tiddlerdese
|
||||
return result;
|
||||
}
|
||||
});
|
||||
// Install the tiddler deserializer modules
|
||||
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
|
||||
|
||||
$tw.loadTiddlers = function() {
|
||||
// In the browser, we load tiddlers from certain elements
|
||||
var containerIds = [
|
||||
"libraryModules",
|
||||
"modules",
|
||||
"bootKernelPrefix",
|
||||
"bootKernel",
|
||||
"styleArea",
|
||||
"storeArea",
|
||||
"shadowArea"
|
||||
];
|
||||
for(var 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);
|
||||
}
|
||||
};
|
||||
|
||||
// End of if($tw.browser)
|
||||
}
|
||||
@ -827,10 +822,10 @@ Execute the module named 'moduleName'. The name can optionally be relative to th
|
||||
*/
|
||||
$tw.modules.execute = function(moduleName,moduleRoot) {
|
||||
var name = moduleRoot ? $tw.utils.resolvePath(moduleName,moduleRoot) : moduleName,
|
||||
module = $tw.modules.titles[name],
|
||||
moduleInfo = $tw.modules.titles[name],
|
||||
tiddler = $tw.wiki.getTiddler(name),
|
||||
sandbox = {
|
||||
module: module,
|
||||
module: moduleInfo,
|
||||
exports: {},
|
||||
console: console,
|
||||
process: process,
|
||||
@ -839,61 +834,38 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
|
||||
return $tw.modules.execute(title,name);
|
||||
}
|
||||
};
|
||||
if(!tiddler || tiddler.fields.type !== "application/javascript") {
|
||||
// If there is no tiddler with that name, let node try to find it
|
||||
if(!moduleInfo) {
|
||||
// If we don't have a module with that name, let node.js try to find it
|
||||
return require(moduleName);
|
||||
}
|
||||
// Define the module if it is not defined
|
||||
module = module || {
|
||||
moduleType: tiddler.fields["module-type"]
|
||||
};
|
||||
$tw.modules.titles[name] = module;
|
||||
// Execute it to get its exports if we haven't already done so
|
||||
if(!module.exports) {
|
||||
// Execute the module if we haven't already done so
|
||||
if(!moduleInfo.exports) {
|
||||
try {
|
||||
vm.runInNewContext(tiddler.fields.text,sandbox,tiddler.fields.title);
|
||||
// Check the type of the definition
|
||||
if(typeof moduleInfo.definition === "string") { // String
|
||||
vm.runInNewContext(moduleInfo.definition,sandbox,tiddler.fields.title);
|
||||
moduleInfo.exports = sandbox.exports;
|
||||
} else if(typeof moduleInfo.definition === "function") { // Function
|
||||
moduleInfo.exports = moduleInfo.definition(moduleInfo,sandbox.require,moduleInfo.exports);
|
||||
} else { // Object
|
||||
moduleInfo.exports = moduleInfo.definition;
|
||||
}
|
||||
} catch(e) {
|
||||
throw "Error executing boot module " + tiddler.fields.title + ":\n" + e;
|
||||
throw "Error executing boot module " + name + ":\n" + e;
|
||||
}
|
||||
module.exports = sandbox.exports;
|
||||
}
|
||||
// Return the exports of the module
|
||||
return module.exports;
|
||||
return moduleInfo.exports;
|
||||
};
|
||||
|
||||
// End of if(!$tw.browser)
|
||||
}
|
||||
|
||||
/////////////////////////// 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 {
|
||||
$tw.loadTiddlers = function() {
|
||||
// On the server, we load tiddlers from specified folders
|
||||
var folders = [
|
||||
$tw.boot.bootPath,
|
||||
path.resolve($tw.boot.wikiPath,$tw.config.wikiShadowsSubDir),
|
||||
path.resolve($tw.boot.wikiPath,$tw.config.wikiTiddlersSubDir)
|
||||
];
|
||||
for(t=0; t<folders.length; t++) {
|
||||
for(var t=0; t<folders.length; t++) {
|
||||
$tw.wiki.addTiddlers($tw.loadTiddlersFromPath(folders[t]));
|
||||
}
|
||||
// Load any plugins listed in the wiki info file
|
||||
@ -919,14 +891,27 @@ if($tw.browser) {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// End of if(!$tw.browser)
|
||||
}
|
||||
|
||||
// Install plugins
|
||||
/////////////////////////// Final initialisation
|
||||
|
||||
|
||||
// Install built in tiddler fields modules
|
||||
$tw.Tiddler.fieldModules = $tw.modules.getModulesByTypeAsHashmap("tiddlerfield");
|
||||
// Install the tiddler deserializer modules
|
||||
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
|
||||
// Load tiddlers
|
||||
$tw.loadTiddlers();
|
||||
// Unpack bundle tiddlers
|
||||
$tw.wiki.unpackBundleTiddlers();
|
||||
|
||||
// Register typed modules from the tiddlers we've just loaded
|
||||
$tw.wiki.registerModuleTiddlers();
|
||||
|
||||
if(!$tw.browser) {
|
||||
$tw.wiki.defineTiddlerModules();
|
||||
}
|
||||
$tw.wiki.defineBundledModules();
|
||||
// Run any startup modules
|
||||
$tw.modules.forEachModuleOfType("startup",function(title,module) {
|
||||
if(module.startup) {
|
||||
|
@ -13,26 +13,58 @@ See Boot.js for further details of the boot process.
|
||||
\*/
|
||||
|
||||
// Set up $tw global for the browser
|
||||
if(window && !window.$tw) {
|
||||
window.$tw = {browser: {}};
|
||||
if(typeof(window) === "undefined") {
|
||||
global.$tw = global.$tw || {}; // No `browser` member for the server
|
||||
} else {
|
||||
window.$tw = window.$tw || {browser: {}};
|
||||
}
|
||||
|
||||
$tw.modules = {titles: {}}; // hashmap by module name of {fn:, exports:, moduleType:}
|
||||
/*
|
||||
Information about each module is kept in an object with these members:
|
||||
moduleType: type of module
|
||||
definition: object, function or string defining the module; see below
|
||||
exports: exports of the module, filled in after execution
|
||||
|
||||
The `definition` can be of several types:
|
||||
|
||||
* An object can be used to directly specify the exports of the module
|
||||
* A function with the arguments `module,require,exports` that returns `exports`
|
||||
* A string function body with the same arguments
|
||||
|
||||
Each moduleInfo object is stored in two hashmaps: $tw.modules.titles and $tw.modules.types. The first is indexed by title and the second is indexed by type and then title
|
||||
*/
|
||||
$tw.modules = {
|
||||
titles: {}, // hashmap by module name of moduleInfo
|
||||
types: {} // hashmap by module type and then name of moduleInfo
|
||||
};
|
||||
|
||||
/*
|
||||
Define a JavaScript tiddler module for later execution
|
||||
moduleName: name of module being defined
|
||||
moduleType: type of module
|
||||
fn: function defining the module, called with the arguments (module,require,exports)
|
||||
definition: module definition; see discussion above
|
||||
*/
|
||||
$tw.modules.define = function(moduleName,moduleType,fn) {
|
||||
$tw.modules.define = function(moduleName,moduleType,definition) {
|
||||
/*jslint evil: true */
|
||||
// Create the moduleInfo
|
||||
var moduleInfo = {
|
||||
moduleType: moduleType,
|
||||
definition: definition,
|
||||
exports: undefined
|
||||
};
|
||||
// Store the module in the titles hashmap
|
||||
if(Object.prototype.hasOwnProperty.call($tw.modules.titles,moduleName)) {
|
||||
console.log("Warning: Redefined module - " + moduleName);
|
||||
}
|
||||
$tw.modules.titles[moduleName] = {
|
||||
moduleType: moduleType,
|
||||
fn: fn
|
||||
};
|
||||
$tw.modules.titles[moduleName] = moduleInfo;
|
||||
// Store the module in the types hashmap
|
||||
if(!Object.prototype.hasOwnProperty.call($tw.modules.types,moduleType)) {
|
||||
$tw.modules.types[moduleType] = {};
|
||||
}
|
||||
if(Object.prototype.hasOwnProperty.call($tw.modules.types[moduleType],moduleName)) {
|
||||
console.log("Warning: Redefined module - " + moduleName);
|
||||
}
|
||||
$tw.modules.types[moduleType][moduleName] = moduleInfo;
|
||||
};
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user