diff --git a/core/modules/startup.js b/core/modules/startup.js index f087d3354..20f9ad98d 100644 --- a/core/modules/startup.js +++ b/core/modules/startup.js @@ -89,21 +89,9 @@ exports.startup = function() { document.addEventListener("tw-clear-password",function(event) { $tw.crypto.setPassword(null); }); - // Unpack the current theme tiddlers - $tw.wiki.unpackPluginTiddlers("theme"); - // Apply stylesheets - var stylesheetTiddlers = $tw.wiki.filterTiddlers("[is[shadow]tag[$:/tags/stylesheet]]"); - $tw.utils.each(stylesheetTiddlers,function(title,index) { - // Stylesheets don't refresh, yet - var parser = $tw.wiki.parseTiddler(title), - renderTree = new $tw.WikiRenderTree(parser,{wiki: $tw.wiki}); - renderTree.execute({tiddlerTitle: title}); - var styleNode = document.createElement("style"); - styleNode.type = "text/css"; - var text = renderTree.render("text/plain"); - styleNode.appendChild(document.createTextNode(text)); - document.getElementsByTagName("head")[0].appendChild(styleNode); - }); + // Kick off the theme and the stylesheet manager + $tw.themeManager = new $tw.ThemeManager($tw.wiki); + $tw.stylesheetManager = new $tw.utils.StylesheetManager($tw.wiki); // If we're being viewed on a data: URI then give instructions for how to save if(document.location.protocol === "data:") { $tw.utils.dispatchCustomEvent(document,"tw-modal",{ diff --git a/core/modules/themes.js b/core/modules/themes.js new file mode 100644 index 000000000..a2df8a535 --- /dev/null +++ b/core/modules/themes.js @@ -0,0 +1,23 @@ +/*\ +title: $:/core/modules/themes.js +type: application/javascript +module-type: global + +Manages themes and styling. + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +function ThemeManager(wiki) { + this.wiki = wiki; + // Unpack the current theme tiddlers + $tw.wiki.unpackPluginTiddlers("theme"); +} + +exports.ThemeManager = ThemeManager; + +})(); diff --git a/core/modules/utils/dom/styles.js b/core/modules/utils/dom/styles.js new file mode 100644 index 000000000..cf076a695 --- /dev/null +++ b/core/modules/utils/dom/styles.js @@ -0,0 +1,78 @@ +/*\ +title: $:/core/modules/utils/styles.js +type: application/javascript +module-type: utils + +The stylesheet manager automatically renders any tiddlers tagged "$:/tags/stylesheet" as HTML style elements. + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +var STYLESHEET_ID_PREFIX = "tw-tiddler-stylesheet-", + STYLESHEET_TAG = "$:/tags/stylesheet"; + +function StylesheetManager(wiki) { + this.wiki = wiki; + this.stylesheets = {}; // Hashmap of currently rendered stylesheets + // Apply initial stylesheets + var self = this, + stylesheetTiddlers = this.wiki.filterTiddlers("[is[shadow]!has[draft.of]tag[" + STYLESHEET_TAG + "]]"); + $tw.utils.each(stylesheetTiddlers,function(title,index) { + self.addStylesheet(title); + }); + // Listen out for changes + this.wiki.addEventListener("change",function(changes) { + self.handleTiddlerChanges(changes); + }); +} + +StylesheetManager.prototype.addStylesheet = function(title) { + // Record the stylesheet in the hashmap + this.stylesheets[title] = true; + // Parse the tiddler and render as plain text + var parser = this.wiki.parseTiddler(title), + renderTree = new $tw.WikiRenderTree(parser,{wiki: this.wiki}); + renderTree.execute({tiddlerTitle: title}); + var text = renderTree.render("text/plain"); + // Create a style element and put it in the document + var styleNode = document.createElement("style"); + styleNode.setAttribute("type","text/css"); + styleNode.setAttribute("id",STYLESHEET_ID_PREFIX + title); + styleNode.appendChild(document.createTextNode(text)); + document.getElementsByTagName("head")[0].appendChild(styleNode); +}; + +StylesheetManager.prototype.removeStylesheet = function(title) { + // Remove the stylesheet from the hashmap + if($tw.utils.hop(this.stylesheets,title)) { + delete this.stylesheets[title]; + } + // Remove the stylesheet from the document + var styleNode = document.getElementById(STYLESHEET_ID_PREFIX + title); + if(styleNode) { + styleNode.parentNode.removeChild(styleNode); + } +}; + +StylesheetManager.prototype.handleTiddlerChanges = function(changes) { + var self = this; + $tw.utils.each(changes,function(change,title) { + // Remove any existing stylesheet for the changed tiddler + if($tw.utils.hop(self.stylesheets,title)) { + self.removeStylesheet(title); + } + // Add the stylesheet if it is tagged and not a draft + var tiddler = self.wiki.getTiddler(title); + if(tiddler && tiddler.hasTag(STYLESHEET_TAG) && !tiddler.hasField("draft.of")) { + self.addStylesheet(title); + } + }); +}; + +exports.StylesheetManager = StylesheetManager; + +})();