/*\ title: $:/core/modules/startup/render.js type: application/javascript module-type: startup Title, stylesheet and page rendering \*/ (function(){ /*jslint node: true, browser: true */ /*global $tw: false */ "use strict"; // Export name and synchronous status exports.name = "render"; exports.platforms = ["browser"]; exports.after = ["story"]; exports.synchronous = true; // Default story and history lists var PAGE_TITLE_TITLE = "$:/core/wiki/title"; var PAGE_STYLESHEET_TITLE = "$:/core/ui/PageStylesheet"; var PAGE_TEMPLATE_TITLE = "$:/core/ui/RootTemplate"; // Time (in ms) that we defer refreshing changes to draft tiddlers var DRAFT_TIDDLER_TIMEOUT_TITLE = "$:/config/Drafts/TypingTimeout"; var THROTTLE_REFRESH_TIMEOUT = 400; exports.startup = function() { // Set up the title $tw.titleWidgetNode = $tw.wiki.makeTranscludeWidget(PAGE_TITLE_TITLE, { document: $tw.fakeDocument, parseAsInline: true, importPageMacros: true, }); $tw.titleContainer = $tw.fakeDocument.createElement("div"); $tw.titleWidgetNode.render($tw.titleContainer,null); document.title = $tw.titleContainer.textContent; $tw.wiki.addEventListener("change",function(changes) { if($tw.titleWidgetNode.refresh(changes,$tw.titleContainer,null)) { document.title = $tw.titleContainer.textContent; } }); // 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); // Prepare refresh mechanism var mainDeferredChanges = Object.create(null), styleDeferredChanges = Object.create(null), mainTimerId, styleTimerId, throttledRefreshFn = function(changes,options) { options = options || {}; // Check if only tiddlers that are throttled have changed var onlyThrottledTiddlersHaveChanged = true; var deferredChanges = options.mainCondition ? mainDeferredChanges : styleDeferredChanges; for(var title in changes) { var tiddler = $tw.wiki.getTiddler(title); if(!$tw.wiki.isVolatileTiddler(title) && (!tiddler || !(tiddler.hasField("draft.of") || tiddler.hasField("throttle.refresh") || (options.mainCondition && tiddler.hasField("throttle.refresh.main")) || (options.styleCondition && tiddler.hasField("throttle.refresh.style"))))) { onlyThrottledTiddlersHaveChanged = false; } } // Defer the change if only drafts have changed if(options.mainCondition) { if(mainTimerId) { clearTimeout(mainTimerId); } mainTimerId = null; } else if(options.styleCondition) { if(styleTimerId) { clearTimeout(styleTimerId); } styleTimerId = null; } if(onlyThrottledTiddlersHaveChanged) { var timeout = parseInt($tw.wiki.getTiddlerText(DRAFT_TIDDLER_TIMEOUT_TITLE,""),10); if(isNaN(timeout)) { timeout = THROTTLE_REFRESH_TIMEOUT; } if(options.mainCondition) { mainTimerId = setTimeout(options.throttledRefresh,timeout); } else if(options.styleCondition) { styleTimerId = setTimeout(options.throttledRefresh,timeout); } $tw.utils.extend(deferredChanges,changes); } else { $tw.utils.extend(deferredChanges,changes); options.callback(); } }; function refresh() { // Process the refresh $tw.hooks.invokeHook("th-page-refreshing"); $tw.pageWidgetNode.refresh(mainDeferredChanges); mainDeferredChanges = Object.create(null); $tw.hooks.invokeHook("th-page-refreshed"); } function styleRefresh() { if($tw.styleWidgetNode.refresh(styleDeferredChanges,$tw.styleContainer,null)) { var newStyles = $tw.styleContainer.textContent; if(newStyles !== $tw.styleWidgetNode.assignedStyles) { $tw.styleWidgetNode.assignedStyles = newStyles; $tw.styleElement.innerHTML = $tw.styleWidgetNode.assignedStyles; } } styleDeferredChanges = Object.create(null); } var mainThrottledRefresh = $tw.perf.report("throttledMainRefresh",refresh), styleThrottledRefresh = $tw.perf.report("throttledStyleRefresh",styleRefresh); $tw.wiki.addEventListener("change",$tw.perf.report("styleRefresh",function(changes) { throttledRefreshFn(changes,{ throttledRefresh: styleThrottledRefresh, callback: styleRefresh, mainCondition: false, styleCondition: true }); })); // Display the $:/core/ui/PageTemplate tiddler to kick off the display $tw.perf.report("mainRender",function() { $tw.pageWidgetNode = $tw.wiki.makeTranscludeWidget(PAGE_TEMPLATE_TITLE,{document: document, parentWidget: $tw.rootWidget, recursionMarker: "no"}); $tw.pageContainer = document.createElement("div"); $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"); })(); // Remove any splash screen elements var removeList = document.querySelectorAll(".tc-remove-when-wiki-loaded"); $tw.utils.each(removeList,function(removeItem) { if(removeItem.parentNode) { removeItem.parentNode.removeChild(removeItem); } }); // Add the change event handler $tw.wiki.addEventListener("change",$tw.perf.report("mainRefresh",function(changes) { throttledRefreshFn(changes,{ throttledRefresh: mainThrottledRefresh, callback: refresh, mainCondition: true, styleCondition: false }); })); // Fix up the link between the root widget and the page container $tw.rootWidget.domNodes = [$tw.pageContainer]; $tw.rootWidget.children = [$tw.pageWidgetNode]; // Run any post-render startup actions $tw.rootWidget.invokeActionsByTag("$:/tags/StartupAction/PostRender"); }; })();