diff --git a/core/modules/startup/render.js b/core/modules/startup/render.js index 43ef48207..c97b87dae 100644 --- a/core/modules/startup/render.js +++ b/core/modules/startup/render.js @@ -18,6 +18,7 @@ exports.synchronous = true; // Default story and history lists var PAGE_TITLE_TITLE = "$:/core/wiki/title"; var PAGE_STYLESHEET_TITLE = "$:/core/ui/PageStylesheet"; +var ROOT_STYLESHEET_TITLE = "$:/core/ui/RootStylesheet"; var PAGE_TEMPLATE_TITLE = "$:/core/ui/RootTemplate"; // Time (in ms) that we defer refreshing changes to draft tiddlers @@ -44,22 +45,13 @@ exports.startup = function() { publishTitle(); } }); - // Set up the styles - $tw.styleWidgetNode = $tw.wiki.makeTranscludeWidget(PAGE_STYLESHEET_TITLE,{document: $tw.fakeDocument}); - $tw.styleContainer = $tw.fakeDocument.createElement("style"); - $tw.styleWidgetNode.render($tw.styleContainer,null); - $tw.styleWidgetNode.assignedStyles = $tw.styleContainer.textContent; - $tw.styleElement = document.createElement("style"); - $tw.styleElement.innerHTML = $tw.styleWidgetNode.assignedStyles; - document.head.insertBefore($tw.styleElement,document.head.firstChild); + + var styleParser = $tw.wiki.parseTiddler(ROOT_STYLESHEET_TITLE,{parseAsInline: true}), + styleWidgetNode = $tw.wiki.makeWidget(styleParser,{document: document}); + styleWidgetNode.render(document.head,null); + $tw.wiki.addEventListener("change",$tw.perf.report("styleRefresh",function(changes) { - if($tw.styleWidgetNode.refresh(changes,$tw.styleContainer,null)) { - var newStyles = $tw.styleContainer.textContent; - if(newStyles !== $tw.styleWidgetNode.assignedStyles) { - $tw.styleWidgetNode.assignedStyles = newStyles; - $tw.styleElement.innerHTML = $tw.styleWidgetNode.assignedStyles; - } - } + styleWidgetNode.refresh(changes,document.head,null); })); // Display the $:/core/ui/PageTemplate tiddler to kick off the display $tw.perf.report("mainRender",function() { @@ -68,7 +60,7 @@ exports.startup = function() { $tw.utils.addClass($tw.pageContainer,"tc-page-container-wrapper"); document.body.insertBefore($tw.pageContainer,document.body.firstChild); $tw.pageWidgetNode.render($tw.pageContainer,null); - $tw.hooks.invokeHook("th-page-refreshed"); + $tw.hooks.invokeHook("th-page-refreshed"); })(); // Remove any splash screen elements var removeList = document.querySelectorAll(".tc-remove-when-wiki-loaded"); diff --git a/core/modules/startup/windows.js b/core/modules/startup/windows.js index 39a2f59d6..3fa70d127 100644 --- a/core/modules/startup/windows.js +++ b/core/modules/startup/windows.js @@ -63,24 +63,16 @@ exports.startup = function() { $tw.eventBus.emit("window:closed",{windowID}); },false); // Set up the styles - var styleWidgetNode = $tw.wiki.makeTranscludeWidget("$:/core/ui/PageStylesheet",{ - document: $tw.fakeDocument, - variables: variables, - importPageMacros: true}), - styleContainer = $tw.fakeDocument.createElement("style"); - styleWidgetNode.render(styleContainer,null); - var styleElement = srcDocument.createElement("style"); - styleElement.innerHTML = styleContainer.textContent; - srcDocument.head.insertBefore(styleElement,srcDocument.head.firstChild); + var styleParser = $tw.wiki.parseTiddler("$:/core/ui/RootStylesheet",{parseAsInline: true}), + styleWidgetNode = $tw.wiki.makeWidget(styleParser,{document: srcDocument}); + styleWidgetNode.render(srcDocument.head,null); // Render the text of the tiddler var parser = $tw.wiki.parseTiddler(template), widgetNode = $tw.wiki.makeWidget(parser,{document: srcDocument, parentWidget: $tw.rootWidget, variables: variables}); widgetNode.render(srcDocument.body,srcDocument.body.firstChild); // Function to handle refreshes refreshHandler = function(changes) { - if(styleWidgetNode.refresh(changes,styleContainer,null)) { - styleElement.innerHTML = styleContainer.textContent; - } + styleWidgetNode.refresh(changes); widgetNode.refresh(changes); }; $tw.wiki.addEventListener("change",refreshHandler); diff --git a/core/modules/widgets/view.js b/core/modules/widgets/view.js index e7c808645..e20c4f07a 100755 --- a/core/modules/widgets/view.js +++ b/core/modules/widgets/view.js @@ -9,215 +9,376 @@ View widget "use strict"; -var Widget = require("$:/core/modules/widgets/widget.js").widget; - -var ViewWidget = function(parseTreeNode,options) { - this.initialise(parseTreeNode,options); -}; +const Widget = require("$:/core/modules/widgets/widget.js").widget; /* -Inherit from the base widget class +========================================== +ViewHandler Base Class +========================================== +Base class for all view format handlers. +Provides common functionality and defines the interface for subclasses. */ -ViewWidget.prototype = new Widget(); - -/* -Render this widget into the DOM -*/ -ViewWidget.prototype.render = function(parent,nextSibling) { - this.parentDomNode = parent; - this.computeAttributes(); - this.execute(); - if(this.text) { - var textNode = this.document.createTextNode(this.text); - parent.insertBefore(textNode,nextSibling); - this.domNodes.push(textNode); - } else { - this.makeChildWidgets(); - this.renderChildren(parent,nextSibling); +class ViewHandler { + constructor(widget) { + this.widget = widget; + this.wiki = widget.wiki; + this.document = widget.document; + this.viewTitle = widget.viewTitle; + this.viewField = widget.viewField; + this.viewIndex = widget.viewIndex; + this.viewSubtiddler = widget.viewSubtiddler; + this.viewTemplate = widget.viewTemplate; + this.viewMode = widget.viewMode; } -}; -/* -Compute the internal state of the widget -*/ -ViewWidget.prototype.execute = function() { - // Get parameters from our attributes - this.viewTitle = this.getAttribute("tiddler",this.getVariable("currentTiddler")); - this.viewSubtiddler = this.getAttribute("subtiddler"); - this.viewField = this.getAttribute("field","text"); - this.viewIndex = this.getAttribute("index"); - this.viewFormat = this.getAttribute("format","text"); - this.viewTemplate = this.getAttribute("template",""); - this.viewMode = this.getAttribute("mode","block"); - switch(this.viewFormat) { - case "htmlwikified": - this.text = this.getValueAsHtmlWikified(this.viewMode); - break; - case "plainwikified": - this.text = this.getValueAsPlainWikified(this.viewMode); - break; - case "htmlencodedplainwikified": - this.text = this.getValueAsHtmlEncodedPlainWikified(this.viewMode); - break; - case "htmlencoded": - this.text = this.getValueAsHtmlEncoded(); - break; - case "htmltextencoded": - this.text = this.getValueAsHtmlTextEncoded(); - break; - case "urlencoded": - this.text = this.getValueAsUrlEncoded(); - break; - case "doubleurlencoded": - this.text = this.getValueAsDoubleUrlEncoded(); - break; - case "date": - this.text = this.getValueAsDate(this.viewTemplate); - break; - case "relativedate": - this.text = this.getValueAsRelativeDate(); - break; - case "stripcomments": - this.text = this.getValueAsStrippedComments(); - break; - case "jsencoded": - this.text = this.getValueAsJsEncoded(); - break; - default: // "text" - this.text = this.getValueAsText(); - break; + render(parent, nextSibling) { + this.text = this.getValue(); + this.createTextNode(parent, nextSibling); } -}; -/* -The various formatter functions are baked into this widget for the moment. Eventually they will be replaced by macro functions -*/ + getValue() { + return this.widget.getValueAsText(); + } -/* -Retrieve the value of the widget. Options are: -asString: Optionally return the value as a string -*/ -ViewWidget.prototype.getValue = function(options) { - options = options || {}; - var value = options.asString ? "" : undefined; - if(this.viewIndex) { - value = this.wiki.extractTiddlerDataItem(this.viewTitle,this.viewIndex); - } else { - var tiddler; - if(this.viewSubtiddler) { - tiddler = this.wiki.getSubTiddler(this.viewTitle,this.viewSubtiddler); + createTextNode(parent, nextSibling) { + if(this.text) { + const textNode = this.document.createTextNode(this.text); + parent.insertBefore(textNode, nextSibling); + this.widget.domNodes.push(textNode); } else { - tiddler = this.wiki.getTiddler(this.viewTitle); - } - if(tiddler) { - if(this.viewField === "text" && !this.viewSubtiddler) { - // Calling getTiddlerText() triggers lazy loading of skinny tiddlers - value = this.wiki.getTiddlerText(this.viewTitle); - } else { - if($tw.utils.hop(tiddler.fields,this.viewField)) { - if(options.asString) { - value = tiddler.getFieldString(this.viewField); - } else { - value = tiddler.fields[this.viewField]; - } - } - } - } else { - if(this.viewField === "title") { - value = this.viewTitle; - } + this.widget.makeChildWidgets(); + this.widget.renderChildren(parent, nextSibling); } } - return value; -}; -ViewWidget.prototype.getValueAsText = function() { - return this.getValue({asString: true}); -}; - -ViewWidget.prototype.getValueAsHtmlWikified = function(mode) { - return this.wiki.renderText("text/html","text/vnd.tiddlywiki",this.getValueAsText(),{ - parseAsInline: mode !== "block", - parentWidget: this - }); -}; - -ViewWidget.prototype.getValueAsPlainWikified = function(mode) { - return this.wiki.renderText("text/plain","text/vnd.tiddlywiki",this.getValueAsText(),{ - parseAsInline: mode !== "block", - parentWidget: this - }); -}; - -ViewWidget.prototype.getValueAsHtmlEncodedPlainWikified = function(mode) { - return $tw.utils.htmlEncode(this.wiki.renderText("text/plain","text/vnd.tiddlywiki",this.getValueAsText(),{ - parseAsInline: mode !== "block", - parentWidget: this - })); -}; - -ViewWidget.prototype.getValueAsHtmlEncoded = function() { - return $tw.utils.htmlEncode(this.getValueAsText()); -}; - -ViewWidget.prototype.getValueAsHtmlTextEncoded = function() { - return $tw.utils.htmlTextEncode(this.getValueAsText()); -}; - -ViewWidget.prototype.getValueAsUrlEncoded = function() { - return $tw.utils.encodeURIComponentExtended(this.getValueAsText()); -}; - -ViewWidget.prototype.getValueAsDoubleUrlEncoded = function() { - return $tw.utils.encodeURIComponentExtended($tw.utils.encodeURIComponentExtended(this.getValueAsText())); -}; - -ViewWidget.prototype.getValueAsDate = function(format) { - format = format || "YYYY MM DD 0hh:0mm"; - var value = $tw.utils.parseDate(this.getValue()); - if(value && $tw.utils.isDate(value) && value.toString() !== "Invalid Date") { - return $tw.utils.formatDateString(value,format); - } else { - return ""; - } -}; - -ViewWidget.prototype.getValueAsRelativeDate = function(format) { - var value = $tw.utils.parseDate(this.getValue()); - if(value && $tw.utils.isDate(value) && value.toString() !== "Invalid Date") { - return $tw.utils.getRelativeDate((new Date()) - (new Date(value))).description; - } else { - return ""; - } -}; - -ViewWidget.prototype.getValueAsStrippedComments = function() { - var lines = this.getValueAsText().split("\n"), - out = []; - for(var line=0; linetag[$:/core/wiki/rawmarkup]] ||$:/core/templates/plain-text-tiddler}}} {{{ [enlisttag[$:/tags/RawMarkup]] ||$:/core/templates/plain-text-tiddler}}} {{{ [enlisttag[$:/tags/RawMarkupWikified]] ||$:/core/templates/raw-static-tiddler}}}` + diff --git a/core/ui/RootStylesheet.tid b/core/ui/RootStylesheet.tid new file mode 100644 index 000000000..aca3b3ac9 --- /dev/null +++ b/core/ui/RootStylesheet.tid @@ -0,0 +1,15 @@ +title: $:/core/ui/RootStylesheet +code-body: yes + +\import [subfilter{$:/core/config/GlobalImportFilter}] +\whitespace trim +<$let currentTiddler={{$:/language}} languageTitle={{!!name}}> + + <$list filter="[all[shadows+tiddlers]tag[$:/tags/Stylesheet]!is[draft]] -[[$:/themes/tiddlywiki/vanilla/reset]]"> + + + diff --git a/editions/tw5.com/tiddlers/releasenotes/5.4.0/#8130 - root-stylesheet-refresh.tid b/editions/tw5.com/tiddlers/releasenotes/5.4.0/#8130 - root-stylesheet-refresh.tid new file mode 100644 index 000000000..f1ee3073e --- /dev/null +++ b/editions/tw5.com/tiddlers/releasenotes/5.4.0/#8130 - root-stylesheet-refresh.tid @@ -0,0 +1,17 @@ +title: $:/changenotes/5.4.0/#8130 +created: 20251212171804335 +modified: 20251212171804335 +tags: $:/tags/ChangeNote +change-type: performance +change-category: internal +description: Different Stylesheets are now included as single `