diff --git a/src/static/js/accounts.js b/src/static/js/accounts.js index f70601a..db1befa 100644 --- a/src/static/js/accounts.js +++ b/src/static/js/accounts.js @@ -97,7 +97,11 @@ var AccountController = function($scope, $http, $rootScope, $window) { } $http.put(url, angular.toJson(account)).success(function(data) { - message("success", "Save", data); + $.pnotify({ + type: "success", + title: "Save", + text: data + }); $scope.editingAccount = null; $scope.savedAccount = null; @@ -114,7 +118,11 @@ var AccountController = function($scope, $http, $rootScope, $window) { // Function to remove of an entry. $scope.accountRemove = function(account, modalScope) { $http.delete("/api/accounts/" + account.id).success(function (data) { - message("success", "Save", data); + $.pnotify({ + type: "success", + title: "Save", + text: data + }); // Reload accounts to update solds. $scope.loadAccounts(); diff --git a/src/static/js/entries.js b/src/static/js/entries.js index 9295392..cced6ef 100644 --- a/src/static/js/entries.js +++ b/src/static/js/entries.js @@ -14,12 +14,6 @@ You should have received a copy of the GNU Affero General Public License along with Accountant. If not, see . */ -// Util function to show a message in message placeholder. -function message(alertType, title, message) { - $(".alert").alert('close'); - $("#message-placeholder").append('

' + title + '

' + message + '
'); -} - var EntryController = function($scope, $http, $rootScope, $filter) { // Entry store and selection $scope.entries = []; @@ -277,7 +271,11 @@ var EntryController = function($scope, $http, $rootScope, $filter) { // Ajax call to save an entry $http.put(url, angular.toJson(entry)).success(function(data) { - message("success", "Save", data); + $.pnotify({ + type: "success", + title: "Save", + text: data + }); // $scope.savedItem = null; @@ -291,14 +289,22 @@ var EntryController = function($scope, $http, $rootScope, $filter) { // Cancel current editing. if (!$scope.isNew(entry)) { $http.delete("/api/entries/" + entry.id).success(function (result) { - message("success", "Delete", result); + $.pnotify({ + type: "success", + title: "Delete", + text: result + }); // Send the "entry removed" event. $scope.$emit("entryRemovedEvent", entry); $scope.closeModal(modalScope); }).error(function (data) { - message("error", "Delete", data); + $.pnotify({ + type: "error", + title: "Delete", + text: data + }); $scope.closeModal(modalScope); }); @@ -387,8 +393,3 @@ var EntryController = function($scope, $http, $rootScope, $filter) { }); }; -// Default AJAX error handler. -//$(document).ajaxError(function(event, xhr, settings) { -// message("error", xhr.statusText, xhr.responseText); -//}); - diff --git a/src/static/js/scheduler.js b/src/static/js/scheduler.js index cbb44ec..8ca4f74 100644 --- a/src/static/js/scheduler.js +++ b/src/static/js/scheduler.js @@ -14,12 +14,6 @@ You should have received a copy of the GNU Affero General Public License along with Accountant. If not, see . */ -// Util function to show a message in message placeholder. -function message(alertType, title, message) { - $(".alert").alert('close'); - $("#message-placeholder").append('

' + title + '

' + message + '
'); -} - var SchedulerController = function($scope, $http, $rootScope, $filter) { // Operations store and selection $scope.operations = []; @@ -109,7 +103,12 @@ var SchedulerController = function($scope, $http, $rootScope, $filter) { } $http.put(url, angular.toJson(operation)).success(function(data) { - message("success", "Save", data); + $.pnotify({ + type: "success", + title: "Save", + text: data + }); + $scope.$emit("operationSavedEvent", operation); }); }; @@ -163,14 +162,22 @@ var SchedulerController = function($scope, $http, $rootScope, $filter) { // Cancel current editing. if (!$scope.isNew(operation)) { $http.delete("/api/scheduled_operations/" + operation.id).success(function (result) { - message("success", "Delete", result); + $.pnotify({ + type: "success", + title: "Delete", + text: result + }); // Send the "entry removed" event. $scope.$emit("operationRemovedEvent", operation); $scope.closeModal(modalScope); }).error(function (data) { - message("error", "Delete", data); + $.pnotify({ + type: "error", + title: "Delete", + text: data + }); $scope.closeModal(modalScope); }); diff --git a/src/static/third-party/pines-notify/jquery.pnotify.default.css b/src/static/third-party/pines-notify/jquery.pnotify.default.css new file mode 100644 index 0000000..de1068a --- /dev/null +++ b/src/static/third-party/pines-notify/jquery.pnotify.default.css @@ -0,0 +1,83 @@ +/* +Document : jquery.pnotify.default.css +Created on : Nov 23, 2009, 3:14:10 PM +Author : Hunter Perrin +Version : 1.2.0 +Link : http://pinesframework.org/pnotify/ +Description: + Default styling for Pines Notify jQuery plugin. +*/ +/* -- Notice */ +.ui-pnotify { +top: 25px; +right: 25px; +position: absolute; +height: auto; +/* Ensures notices are above everything */ +z-index: 9999; +} +/* Hides position: fixed from IE6 */ +html > body .ui-pnotify { +position: fixed; +} +.ui-pnotify .ui-pnotify-shadow { +-webkit-box-shadow: 0px 2px 10px rgba(50, 50, 50, 0.5); +-moz-box-shadow: 0px 2px 10px rgba(50, 50, 50, 0.5); +box-shadow: 0px 2px 10px rgba(50, 50, 50, 0.5); +} +.ui-pnotify-container { +background-position: 0 0; +padding: .8em; +height: 100%; +margin: 0; +} +.ui-pnotify-sharp { +-webkit-border-radius: 0; +-moz-border-radius: 0; +border-radius: 0; +} +.ui-pnotify-closer, .ui-pnotify-sticker { +float: right; +margin-left: .2em; +} +.ui-pnotify-title { +display: block; +margin-bottom: .4em; +} +.ui-pnotify-text { +display: block; +} +.ui-pnotify-icon, .ui-pnotify-icon span { +display: block; +float: left; +margin-right: .2em; +} +/* -- History Pulldown */ +.ui-pnotify-history-container { +position: absolute; +top: 0; +right: 18px; +width: 70px; +border-top: none; +padding: 0; +-webkit-border-top-left-radius: 0; +-moz-border-top-left-radius: 0; +border-top-left-radius: 0; +-webkit-border-top-right-radius: 0; +-moz-border-top-right-radius: 0; +border-top-right-radius: 0; +/* Ensures history container is above notices. */ +z-index: 10000; +} +.ui-pnotify-history-container .ui-pnotify-history-header { +padding: 2px; +} +.ui-pnotify-history-container button { +cursor: pointer; +display: block; +width: 100%; +} +.ui-pnotify-history-container .ui-pnotify-history-pulldown { +display: block; +margin: 0 auto; +} \ No newline at end of file diff --git a/src/static/third-party/pines-notify/jquery.pnotify.js b/src/static/third-party/pines-notify/jquery.pnotify.js new file mode 100644 index 0000000..f72893d --- /dev/null +++ b/src/static/third-party/pines-notify/jquery.pnotify.js @@ -0,0 +1,912 @@ +/* + * jQuery Pines Notify (pnotify) Plugin 1.2.0 + * + * http://pinesframework.org/pnotify/ + * Copyright (c) 2009-2012 Hunter Perrin + * + * Triple license under the GPL, LGPL, and MPL: + * http://www.gnu.org/licenses/gpl.html + * http://www.gnu.org/licenses/lgpl.html + * http://www.mozilla.org/MPL/MPL-1.1.html + */ + +(function($) { + var history_handle_top, + timer, + body, + jwindow = $(window), + styling = { + jqueryui: { + container: "ui-widget ui-widget-content ui-corner-all", + notice: "ui-state-highlight", + // (The actual jQUI notice icon looks terrible.) + notice_icon: "ui-icon ui-icon-info", + info: "", + info_icon: "ui-icon ui-icon-info", + success: "ui-state-default", + success_icon: "ui-icon ui-icon-circle-check", + error: "ui-state-error", + error_icon: "ui-icon ui-icon-alert", + closer: "ui-icon ui-icon-close", + pin_up: "ui-icon ui-icon-pin-w", + pin_down: "ui-icon ui-icon-pin-s", + hi_menu: "ui-state-default ui-corner-bottom", + hi_btn: "ui-state-default ui-corner-all", + hi_btnhov: "ui-state-hover", + hi_hnd: "ui-icon ui-icon-grip-dotted-horizontal" + }, + bootstrap: { + container: "alert", + notice: "", + notice_icon: "icon-exclamation-sign", + info: "alert-info", + info_icon: "icon-info-sign", + success: "alert-success", + success_icon: "icon-ok-sign", + error: "alert-error", + error_icon: "icon-warning-sign", + closer: "icon-remove", + pin_up: "icon-pause", + pin_down: "icon-play", + hi_menu: "well", + hi_btn: "btn", + hi_btnhov: "", + hi_hnd: "icon-chevron-down" + } + }; + // Set global variables. + var do_when_ready = function(){ + body = $("body"); + jwindow = $(window); + // Reposition the notices when the window resizes. + jwindow.bind('resize', function(){ + if (timer) + clearTimeout(timer); + timer = setTimeout($.pnotify_position_all, 10); + }); + }; + if (document.body) + do_when_ready(); + else + $(do_when_ready); + $.extend({ + pnotify_remove_all: function () { + var notices_data = jwindow.data("pnotify"); + /* POA: Added null-check */ + if (notices_data && notices_data.length) { + $.each(notices_data, function(){ + if (this.pnotify_remove) + this.pnotify_remove(); + }); + } + }, + pnotify_position_all: function () { + // This timer is used for queueing this function so it doesn't run + // repeatedly. + if (timer) + clearTimeout(timer); + timer = null; + // Get all the notices. + var notices_data = jwindow.data("pnotify"); + if (!notices_data || !notices_data.length) + return; + // Reset the next position data. + $.each(notices_data, function(){ + var s = this.opts.stack; + if (!s) return; + s.nextpos1 = s.firstpos1; + s.nextpos2 = s.firstpos2; + s.addpos2 = 0; + s.animation = true; + }); + $.each(notices_data, function(){ + this.pnotify_position(); + }); + }, + pnotify: function(options) { + // Stores what is currently being animated (in or out). + var animating; + + // Build main options. + var opts; + if (typeof options != "object") { + opts = $.extend({}, $.pnotify.defaults); + opts.text = options; + } else { + opts = $.extend({}, $.pnotify.defaults, options); + } + // Translate old pnotify_ style options. + for (var i in opts) { + if (typeof i == "string" && i.match(/^pnotify_/)) + opts[i.replace(/^pnotify_/, "")] = opts[i]; + } + + if (opts.before_init) { + if (opts.before_init(opts) === false) + return null; + } + + // This keeps track of the last element the mouse was over, so + // mouseleave, mouseenter, etc can be called. + var nonblock_last_elem; + // This is used to pass events through the notice if it is non-blocking. + var nonblock_pass = function(e, e_name){ + pnotify.css("display", "none"); + var element_below = document.elementFromPoint(e.clientX, e.clientY); + pnotify.css("display", "block"); + var jelement_below = $(element_below); + var cursor_style = jelement_below.css("cursor"); + pnotify.css("cursor", cursor_style != "auto" ? cursor_style : "default"); + // If the element changed, call mouseenter, mouseleave, etc. + if (!nonblock_last_elem || nonblock_last_elem.get(0) != element_below) { + if (nonblock_last_elem) { + dom_event.call(nonblock_last_elem.get(0), "mouseleave", e.originalEvent); + dom_event.call(nonblock_last_elem.get(0), "mouseout", e.originalEvent); + } + dom_event.call(element_below, "mouseenter", e.originalEvent); + dom_event.call(element_below, "mouseover", e.originalEvent); + } + dom_event.call(element_below, e_name, e.originalEvent); + // Remember the latest element the mouse was over. + nonblock_last_elem = jelement_below; + }; + + // Get our styling object. + var styles = styling[opts.styling]; + + // Create our widget. + // Stop animation, reset the removal timer, and show the close + // button when the user mouses over. + var pnotify = $("
", { + "class": "ui-pnotify "+opts.addclass, + "css": {"display": "none"}, + "mouseenter": function(e){ + if (opts.nonblock) e.stopPropagation(); + if (opts.mouse_reset && animating == "out") { + // If it's animating out, animate back in really quickly. + pnotify.stop(true); + animating = "in"; + pnotify.css("height", "auto").animate({"width": opts.width, "opacity": opts.nonblock ? opts.nonblock_opacity : opts.opacity}, "fast"); + } + if (opts.nonblock) { + // If it's non-blocking, animate to the other opacity. + pnotify.animate({"opacity": opts.nonblock_opacity}, "fast"); + } + // Stop the close timer. + if (opts.hide && opts.mouse_reset) pnotify.pnotify_cancel_remove(); + // Show the buttons. + if (opts.sticker && !opts.nonblock) pnotify.sticker.trigger("pnotify_icon").css("visibility", "visible"); + if (opts.closer && !opts.nonblock) pnotify.closer.css("visibility", "visible"); + }, + "mouseleave": function(e){ + if (opts.nonblock) e.stopPropagation(); + nonblock_last_elem = null; + pnotify.css("cursor", "auto"); + // Animate back to the normal opacity. + if (opts.nonblock && animating != "out") + pnotify.animate({"opacity": opts.opacity}, "fast"); + // Start the close timer. + if (opts.hide && opts.mouse_reset) pnotify.pnotify_queue_remove(); + // Hide the buttons. + if (opts.sticker_hover) + pnotify.sticker.css("visibility", "hidden"); + if (opts.closer_hover) + pnotify.closer.css("visibility", "hidden"); + $.pnotify_position_all(); + }, + "mouseover": function(e){ + if (opts.nonblock) e.stopPropagation(); + }, + "mouseout": function(e){ + if (opts.nonblock) e.stopPropagation(); + }, + "mousemove": function(e){ + if (opts.nonblock) { + e.stopPropagation(); + nonblock_pass(e, "onmousemove"); + } + }, + "mousedown": function(e){ + if (opts.nonblock) { + e.stopPropagation(); + e.preventDefault(); + nonblock_pass(e, "onmousedown"); + } + }, + "mouseup": function(e){ + if (opts.nonblock) { + e.stopPropagation(); + e.preventDefault(); + nonblock_pass(e, "onmouseup"); + } + }, + "click": function(e){ + if (opts.nonblock) { + e.stopPropagation(); + nonblock_pass(e, "onclick"); + } + }, + "dblclick": function(e){ + if (opts.nonblock) { + e.stopPropagation(); + nonblock_pass(e, "ondblclick"); + } + } + }); + pnotify.opts = opts; + // Create a container for the notice contents. + pnotify.container = $("
", {"class": styles.container+" ui-pnotify-container "+(opts.type == "error" ? styles.error : (opts.type == "info" ? styles.info : (opts.type == "success" ? styles.success : styles.notice)))}) + .appendTo(pnotify); + if (opts.cornerclass != "") + pnotify.container.removeClass("ui-corner-all").addClass(opts.cornerclass); + // Create a drop shadow. + if (opts.shadow) + pnotify.container.addClass("ui-pnotify-shadow"); + + // The current version of Pines Notify. + pnotify.pnotify_version = "1.2.0"; + + // This function is for updating the notice. + pnotify.pnotify = function(options) { + // Update the notice. + var old_opts = opts; + if (typeof options == "string") + opts.text = options; + else + opts = $.extend({}, opts, options); + // Translate old pnotify_ style options. + for (var i in opts) { + if (typeof i == "string" && i.match(/^pnotify_/)) + opts[i.replace(/^pnotify_/, "")] = opts[i]; + } + pnotify.opts = opts; + // Update the corner class. + if (opts.cornerclass != old_opts.cornerclass) + pnotify.container.removeClass("ui-corner-all").addClass(opts.cornerclass); + // Update the shadow. + if (opts.shadow != old_opts.shadow) { + if (opts.shadow) + pnotify.container.addClass("ui-pnotify-shadow"); + else + pnotify.container.removeClass("ui-pnotify-shadow"); + } + // Update the additional classes. + if (opts.addclass === false) + pnotify.removeClass(old_opts.addclass); + else if (opts.addclass !== old_opts.addclass) + pnotify.removeClass(old_opts.addclass).addClass(opts.addclass); + // Update the title. + if (opts.title === false) + pnotify.title_container.slideUp("fast"); + else if (opts.title !== old_opts.title) { + if (opts.title_escape) + pnotify.title_container.text(opts.title).slideDown(200); + else + pnotify.title_container.html(opts.title).slideDown(200); + } + // Update the text. + if (opts.text === false) { + pnotify.text_container.slideUp("fast"); + } else if (opts.text !== old_opts.text) { + if (opts.text_escape) + pnotify.text_container.text(opts.text).slideDown(200); + else + pnotify.text_container.html(opts.insert_brs ? String(opts.text).replace(/\n/g, "
") : opts.text).slideDown(200); + } + // Update values for history menu access. + pnotify.pnotify_history = opts.history; + pnotify.pnotify_hide = opts.hide; + // Change the notice type. + if (opts.type != old_opts.type) + pnotify.container.removeClass(styles.error+" "+styles.notice+" "+styles.success+" "+styles.info).addClass(opts.type == "error" ? styles.error : (opts.type == "info" ? styles.info : (opts.type == "success" ? styles.success : styles.notice))); + if (opts.icon !== old_opts.icon || (opts.icon === true && opts.type != old_opts.type)) { + // Remove any old icon. + pnotify.container.find("div.ui-pnotify-icon").remove(); + if (opts.icon !== false) { + // Build the new icon. + $("
", {"class": "ui-pnotify-icon"}) + .append($("", {"class": opts.icon === true ? (opts.type == "error" ? styles.error_icon : (opts.type == "info" ? styles.info_icon : (opts.type == "success" ? styles.success_icon : styles.notice_icon))) : opts.icon})) + .prependTo(pnotify.container); + } + } + // Update the width. + if (opts.width !== old_opts.width) + pnotify.animate({width: opts.width}); + // Update the minimum height. + if (opts.min_height !== old_opts.min_height) + pnotify.container.animate({minHeight: opts.min_height}); + // Update the opacity. + if (opts.opacity !== old_opts.opacity) + pnotify.fadeTo(opts.animate_speed, opts.opacity); + // Update the sticker and closer buttons. + if (!opts.closer || opts.nonblock) + pnotify.closer.css("display", "none"); + else + pnotify.closer.css("display", "block"); + if (!opts.sticker || opts.nonblock) + pnotify.sticker.css("display", "none"); + else + pnotify.sticker.css("display", "block"); + // Update the sticker icon. + pnotify.sticker.trigger("pnotify_icon"); + // Update the hover status of the buttons. + if (opts.sticker_hover) + pnotify.sticker.css("visibility", "hidden"); + else if (!opts.nonblock) + pnotify.sticker.css("visibility", "visible"); + if (opts.closer_hover) + pnotify.closer.css("visibility", "hidden"); + else if (!opts.nonblock) + pnotify.closer.css("visibility", "visible"); + // Update the timed hiding. + if (!opts.hide) + pnotify.pnotify_cancel_remove(); + else if (!old_opts.hide) + pnotify.pnotify_queue_remove(); + pnotify.pnotify_queue_position(); + return pnotify; + }; + + // Position the notice. dont_skip_hidden causes the notice to + // position even if it's not visible. + pnotify.pnotify_position = function(dont_skip_hidden){ + // Get the notice's stack. + var s = pnotify.opts.stack; + if (!s) return; + if (!s.nextpos1) + s.nextpos1 = s.firstpos1; + if (!s.nextpos2) + s.nextpos2 = s.firstpos2; + if (!s.addpos2) + s.addpos2 = 0; + var hidden = pnotify.css("display") == "none"; + // Skip this notice if it's not shown. + if (!hidden || dont_skip_hidden) { + var curpos1, curpos2; + // Store what will need to be animated. + var animate = {}; + // Calculate the current pos1 value. + var csspos1; + switch (s.dir1) { + case "down": + csspos1 = "top"; + break; + case "up": + csspos1 = "bottom"; + break; + case "left": + csspos1 = "right"; + break; + case "right": + csspos1 = "left"; + break; + } + curpos1 = parseInt(pnotify.css(csspos1)); + if (isNaN(curpos1)) + curpos1 = 0; + // Remember the first pos1, so the first visible notice goes there. + if (typeof s.firstpos1 == "undefined" && !hidden) { + s.firstpos1 = curpos1; + s.nextpos1 = s.firstpos1; + } + // Calculate the current pos2 value. + var csspos2; + switch (s.dir2) { + case "down": + csspos2 = "top"; + break; + case "up": + csspos2 = "bottom"; + break; + case "left": + csspos2 = "right"; + break; + case "right": + csspos2 = "left"; + break; + } + curpos2 = parseInt(pnotify.css(csspos2)); + if (isNaN(curpos2)) + curpos2 = 0; + // Remember the first pos2, so the first visible notice goes there. + if (typeof s.firstpos2 == "undefined" && !hidden) { + s.firstpos2 = curpos2; + s.nextpos2 = s.firstpos2; + } + // Check that it's not beyond the viewport edge. + if ((s.dir1 == "down" && s.nextpos1 + pnotify.height() > jwindow.height()) || + (s.dir1 == "up" && s.nextpos1 + pnotify.height() > jwindow.height()) || + (s.dir1 == "left" && s.nextpos1 + pnotify.width() > jwindow.width()) || + (s.dir1 == "right" && s.nextpos1 + pnotify.width() > jwindow.width()) ) { + // If it is, it needs to go back to the first pos1, and over on pos2. + s.nextpos1 = s.firstpos1; + s.nextpos2 += s.addpos2 + (typeof s.spacing2 == "undefined" ? 25 : s.spacing2); + s.addpos2 = 0; + } + // Animate if we're moving on dir2. + if (s.animation && s.nextpos2 < curpos2) { + switch (s.dir2) { + case "down": + animate.top = s.nextpos2+"px"; + break; + case "up": + animate.bottom = s.nextpos2+"px"; + break; + case "left": + animate.right = s.nextpos2+"px"; + break; + case "right": + animate.left = s.nextpos2+"px"; + break; + } + } else + pnotify.css(csspos2, s.nextpos2+"px"); + // Keep track of the widest/tallest notice in the column/row, so we can push the next column/row. + switch (s.dir2) { + case "down": + case "up": + if (pnotify.outerHeight(true) > s.addpos2) + s.addpos2 = pnotify.height(); + break; + case "left": + case "right": + if (pnotify.outerWidth(true) > s.addpos2) + s.addpos2 = pnotify.width(); + break; + } + // Move the notice on dir1. + if (s.nextpos1) { + // Animate if we're moving toward the first pos. + if (s.animation && (curpos1 > s.nextpos1 || animate.top || animate.bottom || animate.right || animate.left)) { + switch (s.dir1) { + case "down": + animate.top = s.nextpos1+"px"; + break; + case "up": + animate.bottom = s.nextpos1+"px"; + break; + case "left": + animate.right = s.nextpos1+"px"; + break; + case "right": + animate.left = s.nextpos1+"px"; + break; + } + } else + pnotify.css(csspos1, s.nextpos1+"px"); + } + // Run the animation. + if (animate.top || animate.bottom || animate.right || animate.left) + pnotify.animate(animate, {duration: 500, queue: false}); + // Calculate the next dir1 position. + switch (s.dir1) { + case "down": + case "up": + s.nextpos1 += pnotify.height() + (typeof s.spacing1 == "undefined" ? 25 : s.spacing1); + break; + case "left": + case "right": + s.nextpos1 += pnotify.width() + (typeof s.spacing1 == "undefined" ? 25 : s.spacing1); + break; + } + } + }; + + // Queue the positiona all function so it doesn't run repeatedly and + // use up resources. + pnotify.pnotify_queue_position = function(milliseconds){ + if (timer) + clearTimeout(timer); + if (!milliseconds) + milliseconds = 10; + timer = setTimeout($.pnotify_position_all, milliseconds); + }; + + // Display the notice. + pnotify.pnotify_display = function() { + // If the notice is not in the DOM, append it. + if (!pnotify.parent().length) + pnotify.appendTo(body); + // Run callback. + if (opts.before_open) { + if (opts.before_open(pnotify) === false) + return; + } + // Try to put it in the right position. + if (opts.stack.push != "top") + pnotify.pnotify_position(true); + // First show it, then set its opacity, then hide it. + if (opts.animation == "fade" || opts.animation.effect_in == "fade") { + // If it's fading in, it should start at 0. + pnotify.show().fadeTo(0, 0).hide(); + } else { + // Or else it should be set to the opacity. + if (opts.opacity != 1) + pnotify.show().fadeTo(0, opts.opacity).hide(); + } + pnotify.animate_in(function(){ + if (opts.after_open) + opts.after_open(pnotify); + + pnotify.pnotify_queue_position(); + + // Now set it to hide. + if (opts.hide) + pnotify.pnotify_queue_remove(); + }); + }; + + // Remove the notice. + pnotify.pnotify_remove = function() { + if (pnotify.timer) { + window.clearTimeout(pnotify.timer); + pnotify.timer = null; + } + // Run callback. + if (opts.before_close) { + if (opts.before_close(pnotify) === false) + return; + } + pnotify.animate_out(function(){ + if (opts.after_close) { + if (opts.after_close(pnotify) === false) + return; + } + pnotify.pnotify_queue_position(); + // If we're supposed to remove the notice from the DOM, do it. + if (opts.remove) + pnotify.detach(); + }); + }; + + // Animate the notice in. + pnotify.animate_in = function(callback){ + // Declare that the notice is animating in. (Or has completed animating in.) + animating = "in"; + var animation; + if (typeof opts.animation.effect_in != "undefined") + animation = opts.animation.effect_in; + else + animation = opts.animation; + if (animation == "none") { + pnotify.show(); + callback(); + } else if (animation == "show") + pnotify.show(opts.animate_speed, callback); + else if (animation == "fade") + pnotify.show().fadeTo(opts.animate_speed, opts.opacity, callback); + else if (animation == "slide") + pnotify.slideDown(opts.animate_speed, callback); + else if (typeof animation == "function") + animation("in", callback, pnotify); + else + pnotify.show(animation, (typeof opts.animation.options_in == "object" ? opts.animation.options_in : {}), opts.animate_speed, callback); + }; + + // Animate the notice out. + pnotify.animate_out = function(callback){ + // Declare that the notice is animating out. (Or has completed animating out.) + animating = "out"; + var animation; + if (typeof opts.animation.effect_out != "undefined") + animation = opts.animation.effect_out; + else + animation = opts.animation; + if (animation == "none") { + pnotify.hide(); + callback(); + } else if (animation == "show") + pnotify.hide(opts.animate_speed, callback); + else if (animation == "fade") + pnotify.fadeOut(opts.animate_speed, callback); + else if (animation == "slide") + pnotify.slideUp(opts.animate_speed, callback); + else if (typeof animation == "function") + animation("out", callback, pnotify); + else + pnotify.hide(animation, (typeof opts.animation.options_out == "object" ? opts.animation.options_out : {}), opts.animate_speed, callback); + }; + + // Cancel any pending removal timer. + pnotify.pnotify_cancel_remove = function() { + if (pnotify.timer) + window.clearTimeout(pnotify.timer); + }; + + // Queue a removal timer. + pnotify.pnotify_queue_remove = function() { + // Cancel any current removal timer. + pnotify.pnotify_cancel_remove(); + pnotify.timer = window.setTimeout(function(){ + pnotify.pnotify_remove(); + }, (isNaN(opts.delay) ? 0 : opts.delay)); + }; + + // Provide a button to close the notice. + pnotify.closer = $("
", { + "class": "ui-pnotify-closer", + "css": {"cursor": "pointer", "visibility": opts.closer_hover ? "hidden" : "visible"}, + "click": function(){ + pnotify.pnotify_remove(); + pnotify.sticker.css("visibility", "hidden"); + pnotify.closer.css("visibility", "hidden"); + } + }) + .append($("", {"class": styles.closer})) + .appendTo(pnotify.container); + if (!opts.closer || opts.nonblock) + pnotify.closer.css("display", "none"); + + // Provide a button to stick the notice. + pnotify.sticker = $("
", { + "class": "ui-pnotify-sticker", + "css": {"cursor": "pointer", "visibility": opts.sticker_hover ? "hidden" : "visible"}, + "click": function(){ + opts.hide = !opts.hide; + if (opts.hide) + pnotify.pnotify_queue_remove(); + else + pnotify.pnotify_cancel_remove(); + $(this).trigger("pnotify_icon"); + } + }) + .bind("pnotify_icon", function(){ + $(this).children().removeClass(styles.pin_up+" "+styles.pin_down).addClass(opts.hide ? styles.pin_up : styles.pin_down); + }) + .append($("", {"class": styles.pin_up})) + .appendTo(pnotify.container); + if (!opts.sticker || opts.nonblock) + pnotify.sticker.css("display", "none"); + + // Add the appropriate icon. + if (opts.icon !== false) { + $("
", {"class": "ui-pnotify-icon"}) + .append($("", {"class": opts.icon === true ? (opts.type == "error" ? styles.error_icon : (opts.type == "info" ? styles.info_icon : (opts.type == "success" ? styles.success_icon : styles.notice_icon))) : opts.icon})) + .prependTo(pnotify.container); + } + + // Add a title. + pnotify.title_container = $("

", { + "class": "ui-pnotify-title" + }) + .appendTo(pnotify.container); + if (opts.title === false) + pnotify.title_container.hide(); + else if (opts.title_escape) + pnotify.title_container.text(opts.title); + else + pnotify.title_container.html(opts.title); + + // Add text. + pnotify.text_container = $("
", { + "class": "ui-pnotify-text" + }) + .appendTo(pnotify.container); + if (opts.text === false) + pnotify.text_container.hide(); + else if (opts.text_escape) + pnotify.text_container.text(opts.text); + else + pnotify.text_container.html(opts.insert_brs ? String(opts.text).replace(/\n/g, "
") : opts.text); + + // Set width and min height. + if (typeof opts.width == "string") + pnotify.css("width", opts.width); + if (typeof opts.min_height == "string") + pnotify.container.css("min-height", opts.min_height); + + // The history variable controls whether the notice gets redisplayed + // by the history pull down. + pnotify.pnotify_history = opts.history; + // The hide variable controls whether the history pull down should + // queue a removal timer. + pnotify.pnotify_hide = opts.hide; + + // Add the notice to the notice array. + var notices_data = jwindow.data("pnotify"); + if (notices_data == null || typeof notices_data != "object") + notices_data = []; + if (opts.stack.push == "top") + notices_data = $.merge([pnotify], notices_data); + else + notices_data = $.merge(notices_data, [pnotify]); + jwindow.data("pnotify", notices_data); + // Now position all the notices if they are to push to the top. + if (opts.stack.push == "top") + pnotify.pnotify_queue_position(1); + + // Run callback. + if (opts.after_init) + opts.after_init(pnotify); + + if (opts.history) { + // If there isn't a history pull down, create one. + var history_menu = jwindow.data("pnotify_history"); + if (typeof history_menu == "undefined") { + history_menu = $("
", { + "class": "ui-pnotify-history-container "+styles.hi_menu, + "mouseleave": function(){ + history_menu.animate({top: "-"+history_handle_top+"px"}, {duration: 100, queue: false}); + } + }) + .append($("
", {"class": "ui-pnotify-history-header", "text": "Redisplay"})) + .append($("
- -
-
-
-
diff --git a/src/templates/layout.html b/src/templates/layout.html index 2d10b6e..9b1e85d 100644 --- a/src/templates/layout.html +++ b/src/templates/layout.html @@ -13,7 +13,7 @@ You should have received a copy of the GNU Affero General Public License along with Accountant. If not, see . - #} +#} @@ -29,6 +29,9 @@ + + + @@ -104,6 +107,9 @@ + + + {% block js %}{% endblock %}