diff --git a/core/modules/config.js b/core/modules/config.js index 446c92710..e012a7d5f 100644 --- a/core/modules/config.js +++ b/core/modules/config.js @@ -16,6 +16,7 @@ exports.preferences = {}; exports.preferences.animationDuration = 400; exports.preferences.animationDurationMs = exports.preferences.animationDuration + "ms"; +exports.preferences.notificationDuration = 3 * 1000; exports.preferences.jsonSpaces = 4; exports.dateFormats = { diff --git a/core/modules/startup.js b/core/modules/startup.js index b356308fe..c4b439eb9 100644 --- a/core/modules/startup.js +++ b/core/modules/startup.js @@ -65,6 +65,11 @@ exports.startup = function() { document.addEventListener("tw-modal",function(event) { $tw.modal.display(event.param); },false); + // Install the notification mechanism + $tw.notifier = new $tw.utils.Notifier($tw.wiki); + document.addEventListener("tw-notify",function(event) { + $tw.notifier.display(event.param); + },false); // Install the scroller $tw.pageScroller = new $tw.utils.PageScroller(); document.addEventListener("tw-scroll",$tw.pageScroller,false); diff --git a/core/modules/utils/dom/notifier.js b/core/modules/utils/dom/notifier.js new file mode 100644 index 000000000..b4373bca9 --- /dev/null +++ b/core/modules/utils/dom/notifier.js @@ -0,0 +1,81 @@ +/*\ +title: $:/core/modules/utils/dom/notifier.js +type: application/javascript +module-type: utils + +Notifier mechanism + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +var Notifier = function(wiki) { + this.wiki = wiki; +}; + +/* +Display a notification + title: Title of tiddler containing the notification text + options: see below +Options include: +*/ +Notifier.prototype.display = function(title,options) { + options = options || {}; + // Create the wrapper divs + var notification = document.createElement("div"), + tiddler = this.wiki.getTiddler(title), + d = $tw.config.preferences.animationDuration + "ms"; + // Don't do anything if the tiddler doesn't exist + if(!tiddler) { + return; + } + // Add classes + $tw.utils.addClass(notification,"tw-notification"); + // Render the body of the notification + var bodyParser = this.wiki.parseTiddler(title), + bodyRenderTree = new $tw.WikiRenderTree(bodyParser,{wiki: $tw.wiki}); + bodyRenderTree.execute({tiddlerTitle: title}); + bodyRenderTree.renderInDom(notification); + this.wiki.addEventListener("change",function(changes) { + bodyRenderTree.refreshInDom(changes); + }); + // Set the initial styles for the notification + $tw.utils.setStyle(notification,[ + {opacity: "0"}, + {transformOrigin: "0% 0%"}, + {transform: "translateY(" + (-window.innerHeight) + "px)"}, + {transition: "opacity " + d + " ease-out, " + $tw.utils.roundTripPropertyName("transform") + " " + $tw.config.preferences.animationDurationMs + " ease-in-out"} + ]); + // Add the notification to the DOM + document.body.appendChild(notification); + // Force layout + $tw.utils.forceLayout(notification); + // Set final animated styles + $tw.utils.setStyle(notification,[ + {opacity: "1.0"}, + {transform: "translateY(0px)"} + ]); + // Set a timer to remove the notification + window.setTimeout(function() { + // Force layout and animate the notification away + $tw.utils.forceLayout(notification); + $tw.utils.setStyle(notification,[ + {opacity: "0.0"}, + {transform: "translateY(" + (-window.innerHeight) + "px)"} + ]); + // Set up an event for the transition end + notification.addEventListener($tw.utils.convertEventName("transitionEnd"),function(event) { + if(notification.parentNode) { + // Remove the modal message from the DOM + document.body.removeChild(notification); + } + },false); + },$tw.config.preferences.notificationDuration); +}; + +exports.Notifier = Notifier; + +})(); diff --git a/themes/tiddlywiki/snowwhite/base.tid b/themes/tiddlywiki/snowwhite/base.tid index 633e4fbe6..454d180fb 100644 --- a/themes/tiddlywiki/snowwhite/base.tid +++ b/themes/tiddlywiki/snowwhite/base.tid @@ -486,6 +486,25 @@ canvas.tw-edit-bitmapeditor { <>; } +/* +** Notifications +*/ + +.tw-notification { + position: fixed; + top: 1em; + right: 1em; + z-index: 1000; + max-width: 20em; + padding: 0em 1em 0em 1em; + background-color: #ffd; + border: 1px solid #999; + border: 1px solid rgba(0,0,0,.3); + <> + <> + text-shadow: 0 1px 0 rgba(255,255,255, 0.8); +} + /* ** Tabs */