diff --git a/boot/boot.js b/boot/boot.js index 7161da3bd..bc974c6d5 100644 --- a/boot/boot.js +++ b/boot/boot.js @@ -1738,7 +1738,8 @@ $tw.boot.startup = function(options) { languagesEnvVar: "TIDDLYWIKI_LANGUAGE_PATH", editionsEnvVar: "TIDDLYWIKI_EDITION_PATH" }, - log: {} // Log flags + log: {}, // Log flags + unloadTasks: [] }); if(!$tw.boot.tasks.readBrowserTiddlers) { // For writable tiddler files, a hashmap of title to {filepath:,type:,hasMetaFile:} @@ -1797,6 +1798,20 @@ $tw.boot.startup = function(options) { // Install the tiddler deserializer modules $tw.Wiki.tiddlerDeserializerModules = Object.create(null); $tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules); + // Call unload handlers in the browser + if($tw.browser) { + window.onbeforeunload = function(event) { + event = event || {}; + var result; + $tw.utils.each($tw.unloadTasks,function(task) { + var r = task(event); + if(r) { + result = r; + } + }); + return result; + } + } // Load tiddlers if($tw.boot.tasks.readBrowserTiddlers) { $tw.loadTiddlersBrowser(); @@ -1833,6 +1848,15 @@ $tw.boot.startup = function(options) { $tw.boot.executeNextStartupTask(); }; +/* +Add another unload task +*/ +$tw.addUnloadTask = function(task) { + if($tw.unloadTasks.indexOf(task) === -1) { + $tw.unloadTasks.push(task); + } +} + /* Execute the remaining eligible startup tasks */ diff --git a/core/language/en-GB/ControlPanel.multids b/core/language/en-GB/ControlPanel.multids index f9ea31ff8..6b291ebf6 100644 --- a/core/language/en-GB/ControlPanel.multids +++ b/core/language/en-GB/ControlPanel.multids @@ -88,6 +88,13 @@ Settings/ToolbarButtons/Icons/Description: Include icon Settings/ToolbarButtons/Text/Description: Include text Settings/DefaultSidebarTab/Caption: Default Sidebar Tab Settings/DefaultSidebarTab/Hint: Specify which sidebar tab is displayed by default +Settings/LinkToBehaviour/Caption: Tiddler Opening Behaviour +Settings/LinkToBehaviour/InsideRiver/Hint: Navigation from //within// the story river +Settings/LinkToBehaviour/OutsideRiver/Hint: Navigation from //outside// the story river +Settings/LinkToBehaviour/OpenAbove: Open above the current tiddler +Settings/LinkToBehaviour/OpenBelow: Open below the current tiddler +Settings/LinkToBehaviour/OpenAtTop: Open at the top of the story river +Settings/LinkToBehaviour/OpenAtBottom: Open at the bottom of the story river StoryView/Caption: Story View StoryView/Prompt: Current view: Theme/Caption: Theme diff --git a/core/modules/saver-handler.js b/core/modules/saver-handler.js index 3344495c7..78e0598a6 100644 --- a/core/modules/saver-handler.js +++ b/core/modules/saver-handler.js @@ -75,14 +75,14 @@ function SaverHandler(options) { } }); // Set up our beforeunload handler - window.onbeforeunload = function(event) { + $tw.addUnloadTask(function(event) { var confirmationMessage; if(self.isDirty()) { confirmationMessage = $tw.language.getString("UnsavedChangesWarning"); event.returnValue = confirmationMessage; // Gecko } return confirmationMessage; - }; + }); } // Install the save action handlers if($tw.browser) { diff --git a/core/modules/startup/windows.js b/core/modules/startup/windows.js index 14920061b..d2a5517e3 100644 --- a/core/modules/startup/windows.js +++ b/core/modules/startup/windows.js @@ -18,7 +18,11 @@ exports.platforms = ["browser"]; exports.after = ["startup"]; exports.synchronous = true; +// Global to keep track of open windows (hashmap by title) +var windows = {}; + exports.startup = function() { + // Handle open window message $tw.rootWidget.addEventListener("tm-open-window",function(event) { // Get the parameters var refreshHandler, @@ -30,6 +34,7 @@ exports.startup = function() { // Open the window var srcWindow = window.open("","external-" + title,"width=" + width + ",height=" + height), srcDocument = srcWindow.document; + windows[title] = srcWindow; // Check for reopening the same window if(srcWindow.haveInitialisedWindow) { return; @@ -39,6 +44,7 @@ exports.startup = function() { srcDocument.close(); srcDocument.title = title; srcWindow.addEventListener("beforeunload",function(event) { + delete windows[title]; $tw.wiki.removeEventListener("change",refreshHandler); },false); // Set up the styles @@ -50,8 +56,8 @@ exports.startup = function() { srcDocument.head.insertBefore(styleElement,srcDocument.head.firstChild); // Render the text of the tiddler var parser = $tw.wiki.parseTiddler(template), - widgetNode = $tw.wiki.makeWidget(parser,{document: srcDocument, variables: {currentTiddler: title}}); - widgetNode.render(srcDocument.body,null); + widgetNode = $tw.wiki.makeWidget(parser,{document: srcDocument, parentWidget: $tw.rootWidget, variables: {currentTiddler: title}}); + widgetNode.render(srcDocument.body,srcDocument.body.firstChild); // Function to handle refreshes refreshHandler = function(changes) { if(styleWidgetNode.refresh(changes,styleContainer,null)) { @@ -62,6 +68,13 @@ exports.startup = function() { $tw.wiki.addEventListener("change",refreshHandler); srcWindow.haveInitialisedWindow = true; }); + // Close open windows when unloading main window + $tw.addUnloadTask(function() { + $tw.utils.each(windows,function(win) { + win.close(); + }); + }); + }; })(); diff --git a/core/modules/syncer.js b/core/modules/syncer.js index 617c54155..223998e1c 100644 --- a/core/modules/syncer.js +++ b/core/modules/syncer.js @@ -39,14 +39,14 @@ function Syncer(options) { // Browser event handlers if($tw.browser) { // Set up our beforeunload handler - window.onbeforeunload = function(event) { + $tw.addUnloadTask(function(event) { var confirmationMessage; if(self.isDirty()) { confirmationMessage = $tw.language.getString("UnsavedChangesWarning"); event.returnValue = confirmationMessage; // Gecko } return confirmationMessage; - }; + }); // Listen out for login/logout/refresh events in the browser $tw.rootWidget.addEventListener("tm-login",function() { self.handleLoginEvent(); diff --git a/core/modules/widgets/navigator.js b/core/modules/widgets/navigator.js index 7809df383..1a66990be 100755 --- a/core/modules/widgets/navigator.js +++ b/core/modules/widgets/navigator.js @@ -85,11 +85,6 @@ NavigatorWidget.prototype.saveStoryList = function(storyList) { )); }; -NavigatorWidget.prototype.findTitleInStory = function(storyList,title,defaultIndex) { - var p = storyList.indexOf(title); - return p === -1 ? defaultIndex : p; -}; - NavigatorWidget.prototype.removeTitleFromStory = function(storyList,title) { var p = storyList.indexOf(title); while(p !== -1) { @@ -115,19 +110,52 @@ NavigatorWidget.prototype.replaceFirstTitleInStory = function(storyList,oldTitle NavigatorWidget.prototype.addToStory = function(title,fromTitle) { var storyList = this.getStoryList(); - if(storyList) { - // See if the tiddler is already there - var slot = this.findTitleInStory(storyList,title,-1); - // If not we need to add it - if(slot === -1) { - // First we try to find the position of the story element we navigated from - slot = this.findTitleInStory(storyList,fromTitle,-1) + 1; - // Add the tiddler - storyList.splice(slot,0,title); - // Save the story - this.saveStoryList(storyList); + // Quit if we cannot get hold of the story list + if(!storyList) { + return; + } + // See if the tiddler is already there + var slot = storyList.indexOf(title); + // Quit if it already exists in the story river + if(slot >= 0) { + return; + } + // First we try to find the position of the story element we navigated from + var fromIndex = storyList.indexOf(fromTitle); + if(fromIndex >= 0) { + // How to open internal links that were clicked from *within* the story river? + var openLinkFromInsideRiver = $tw.wiki.getTiddlerText("$:/config/Navigation/openLinkFromInsideRiver","below"); + // The tiddler is added from inside the river + // Determine where to insert the tiddler; Fallback is "below" + switch(openLinkFromInsideRiver) { + case "top": + slot = 0; + break; + case "bottom": + slot = storyList.length; + break; + case "above": + slot = fromIndex; + break; + default: + slot = fromIndex + 1; + } + } else { + // The tiddler is opened from outside the river. + var openLinkFromOutsideRiver = $tw.wiki.getTiddlerText("$:/config/Navigation/openLinkFromOutsideRiver","top"); + // Determine where to insert the tiddler; Default is "top" + if(openLinkFromOutsideRiver === "bottom") { + // Insert at bottom + slot = storyList.length; + } else { + // Insert at top + slot = 0; } } + // Add the tiddler + storyList.splice(slot,0,title); + // Save the story + this.saveStoryList(storyList); }; /* diff --git a/core/modules/widgets/widget.js b/core/modules/widgets/widget.js index bbcf5b025..53c5ea46b 100755 --- a/core/modules/widgets/widget.js +++ b/core/modules/widgets/widget.js @@ -434,7 +434,9 @@ if(index === -1) { var grandParent = parent.parentWidget; if(grandParent && parent.parentDomNode === this.parentDomNode) { index = grandParent.children.indexOf(parent); - return parent.findNextSiblingDomNode(index); + if(index !== -1) { + return parent.findNextSiblingDomNode(index); + } } return null; }; diff --git a/core/ui/ControlPanel/Settings/LinkToBehaviour.tid b/core/ui/ControlPanel/Settings/LinkToBehaviour.tid new file mode 100644 index 000000000..0dbd1973c --- /dev/null +++ b/core/ui/ControlPanel/Settings/LinkToBehaviour.tid @@ -0,0 +1,21 @@ +title: $:/core/ui/ControlPanel/Settings/LinkToBehaviour +tags: $:/tags/ControlPanel/Settings +caption: {{$:/language/ControlPanel/Settings/LinkToBehaviour/Caption}} + +\define lingo-base() $:/language/ControlPanel/Settings/LinkToBehaviour/ + +<$link to="$:/config/Navigation/openLinkFromInsideRiver"><> + +<$select tiddler="$:/config/Navigation/openLinkFromInsideRiver"> + + + + + + +<$link to="$:/config/Navigation/openLinkFromOutsideRiver"><> + +<$select tiddler="$:/config/Navigation/openLinkFromOutsideRiver"> + + + diff --git a/core/wiki/config/OpenLinkFromInsideRiver.tid b/core/wiki/config/OpenLinkFromInsideRiver.tid new file mode 100644 index 000000000..3beb24053 --- /dev/null +++ b/core/wiki/config/OpenLinkFromInsideRiver.tid @@ -0,0 +1,2 @@ +title: $:/config/Navigation/openLinkFromInsideRiver +text: below \ No newline at end of file diff --git a/core/wiki/config/OpenLinkFromOutsideRiver.tid b/core/wiki/config/OpenLinkFromOutsideRiver.tid new file mode 100644 index 000000000..07577385e --- /dev/null +++ b/core/wiki/config/OpenLinkFromOutsideRiver.tid @@ -0,0 +1,2 @@ +title: $:/config/Navigation/openLinkFromOutsideRiver +text: top \ No newline at end of file diff --git a/editions/fr-FR/tiddlers/Latest.tid b/editions/fr-FR/tiddlers/Latest.tid index 44886901c..83d34f54e 100644 --- a/editions/fr-FR/tiddlers/Latest.tid +++ b/editions/fr-FR/tiddlers/Latest.tid @@ -24,3 +24,5 @@ Les informations, articles, ressources et exemples les plus récents. + + diff --git a/editions/prerelease/tiddlers/system/TiddlyWiki Pre-release.tid b/editions/prerelease/tiddlers/system/TiddlyWiki Pre-release.tid index 3de79fc5a..fe203f8f9 100644 --- a/editions/prerelease/tiddlers/system/TiddlyWiki Pre-release.tid +++ b/editions/prerelease/tiddlers/system/TiddlyWiki Pre-release.tid @@ -11,6 +11,18 @@ It is provided for testing purposes. Please don't try to use it for anything imp ! Features for 5.1.9 +!! New "Fluid story, fixed sidebar" mode + +In response to popular demand, it is now possible to arrange the main window so that the sidebar has a fixed width and the story river expands to fill the remaining space. + +To switch it on, visit ''Theme Tweaks'' in the $:/ControlPanel ''Appearance'' tab and use the following options: + +* Sidebar layout: +** ''Fixed story, fluid sidebar'' (default) - the story river has a fixed width and the sidebar fills the remaining space +** ''Fluid story, fixed sidebar'' - the story river expands to fill horizontal space remaining after the fixed width sidebar +* Sidebar width: +** The width of the sidebar. Can be specified in pixels (eg ''350px''), a percentage (eg ''25%'') or other [[CSS unit|https://developer.mozilla.org/en/docs/Web/CSS/length]] + !! New Tiddler Toolbar Button: "Open in new window" An experimental new tiddler toolbar button opens a single tiddler in a separate pop-up browser window. The tiddler will be dynamically updated just as in the main window. There are several uses: diff --git a/editions/tw5.com/tiddlers/community/Latest.tid b/editions/tw5.com/tiddlers/community/Latest.tid index b4e1f2cb7..3b754ab53 100644 --- a/editions/tw5.com/tiddlers/community/Latest.tid +++ b/editions/tw5.com/tiddlers/community/Latest.tid @@ -21,3 +21,5 @@ The latest news, articles, resources and examples. + + diff --git a/editions/tw5.com/tiddlers/nodejs/Installing TiddlyWiki on Node.js.tid b/editions/tw5.com/tiddlers/nodejs/Installing TiddlyWiki on Node.js.tid index bc5a164ac..9f51cc4bb 100644 --- a/editions/tw5.com/tiddlers/nodejs/Installing TiddlyWiki on Node.js.tid +++ b/editions/tw5.com/tiddlers/nodejs/Installing TiddlyWiki on Node.js.tid @@ -19,3 +19,7 @@ type: text/vnd.tiddlywiki ## Try editing and creating tiddlers The `-g` flag causes TiddlyWiki to be installed globally. Without it, TiddlyWiki will only be available in the directory where you installed it. + +If you are using Debian or Debian-based Linux and you are reciving a `node: command not found` error though node.js package is installed, you may need to create a symbolic link between `nodejs` and `node`. Consult your distro's manual and `whereis` to correctly create a link. See github [[issue 1434|http://github.com/Jermolene/TiddlyWiki5/issues/1434]] + +Example Debian v8.0: `sudo ln -s /usr/bin/nodejs /usr/bin/node` \ No newline at end of file diff --git a/themes/tiddlywiki/vanilla/ThemeTweaks.tid b/themes/tiddlywiki/vanilla/ThemeTweaks.tid index 129e3c12b..bfc4075b0 100644 --- a/themes/tiddlywiki/vanilla/ThemeTweaks.tid +++ b/themes/tiddlywiki/vanilla/ThemeTweaks.tid @@ -42,6 +42,7 @@ You can tweak certain aspects of the ''Vanilla'' theme. ! Options +|[[Sidebar layout|$:/themes/tiddlywiki/vanilla/options/sidebarlayout]] |<$select tiddler="$:/themes/tiddlywiki/vanilla/options/sidebarlayout"> | |[[Sticky titles|$:/themes/tiddlywiki/vanilla/options/stickytitles]]
//Causes tiddler titles to "stick" to the top of the browser window. Caution: Does not work at all with Chrome, and causes some layout issues in Firefox// |<$select tiddler="$:/themes/tiddlywiki/vanilla/options/stickytitles"> | ! Settings @@ -64,3 +65,4 @@ You can tweak certain aspects of the ''Vanilla'' theme. |[[Story width|$:/themes/tiddlywiki/vanilla/metrics/storywidth]]
//the overall width of the story river// |^<$edit-text tiddler="$:/themes/tiddlywiki/vanilla/metrics/storywidth" default="" tag="input"/> | |[[Tiddler width|$:/themes/tiddlywiki/vanilla/metrics/tiddlerwidth]]
//within the story river//
|^<$edit-text tiddler="$:/themes/tiddlywiki/vanilla/metrics/tiddlerwidth" default="" tag="input"/> | |[[Sidebar breakpoint|$:/themes/tiddlywiki/vanilla/metrics/sidebarbreakpoint]]
//the minimum page width at which the story
river and sidebar will appear side by side// |^<$edit-text tiddler="$:/themes/tiddlywiki/vanilla/metrics/sidebarbreakpoint" default="" tag="input"/> | +|[[Sidebar width|$:/themes/tiddlywiki/vanilla/metrics/sidebarwidth]]
//the width of the sidebar in fluid-fixed layout// |^<$edit-text tiddler="$:/themes/tiddlywiki/vanilla/metrics/sidebarwidth" default="" tag="input"/> | diff --git a/themes/tiddlywiki/vanilla/base.tid b/themes/tiddlywiki/vanilla/base.tid index b47476a9b..5a282ed27 100644 --- a/themes/tiddlywiki/vanilla/base.tid +++ b/themes/tiddlywiki/vanilla/base.tid @@ -21,7 +21,16 @@ background-size:` {{$:/themes/tiddlywiki/vanilla/settings/backgroundimagesize}}` \end -\rules only filteredtranscludeinline transcludeinline macrodef macrocallinline +\define if-fluid-fixed(text,hiddenSidebarText) +<$reveal state="$:/themes/tiddlywiki/vanilla/options/sidebarlayout" type="match" text="fluid-fixed"> +$text$ +<$reveal state="$:/state/sidebar" type="nomatch" text="yes" default="yes"> +$hiddenSidebarText$ + + +\end + +\rules only filteredtranscludeinline transcludeinline macrodef macrocallinline macrocallblock /* ** Start with the normalize CSS reset, and then belay some of its effects @@ -66,10 +75,6 @@ body.tc-body { <> } -body.tc-body.tc-single-tiddler-window { - margin: 1em; -} - h1, h2, h3, h4, h5, h6 { line-height: 1.2; font-weight: 300; @@ -345,6 +350,7 @@ button svg, button img { height: 2em; width: 2em; vertical-align: middle; + fill: <>; } .tc-sidebar-lists input { @@ -821,6 +827,59 @@ canvas.tc-edit-bitmapeditor { overflow: hidden; /* https://github.com/Jermolene/TiddlyWiki5/issues/282 */ } +html body.tc-body.tc-single-tiddler-window { + margin: 1em; + background: <>; +} + +/* +** Adjustments for fluid-fixed mode +*/ + +@media (min-width: {{$:/themes/tiddlywiki/vanilla/metrics/sidebarbreakpoint}}) { + +<> + +} + /* ** Toolbar buttons */ @@ -1740,6 +1799,7 @@ body.tc-dirty span.tc-dirty-indicator, body.tc-dirty span.tc-dirty-indicator svg opacity: 1; min-width: 100%; min-height: 100%; + max-width: 100%; } .tc-thumbnail-wrapper:hover .tc-thumbnail-image svg, diff --git a/themes/tiddlywiki/vanilla/metrics.multids b/themes/tiddlywiki/vanilla/metrics.multids index 174c0b00f..3607bd6c9 100644 --- a/themes/tiddlywiki/vanilla/metrics.multids +++ b/themes/tiddlywiki/vanilla/metrics.multids @@ -10,3 +10,4 @@ storyright: 770px storywidth: 770px tiddlerwidth: 686px sidebarbreakpoint: 960px +sidebarwidth: 350px diff --git a/themes/tiddlywiki/vanilla/options.multids b/themes/tiddlywiki/vanilla/options.multids index e8189b8c2..d06b052aa 100644 --- a/themes/tiddlywiki/vanilla/options.multids +++ b/themes/tiddlywiki/vanilla/options.multids @@ -1,3 +1,4 @@ title: $:/themes/tiddlywiki/vanilla/options/ stickytitles: no +sidebarlayout: fluid-fixed