",
- log : "{{message}}"
- };
-
- /**
- * Return the proper transitionend event
- * @return {String} Transition type string
- */
- getTransitionEvent = function () {
- var t,
- type,
- supported = false,
- el = document.createElement("fakeelement"),
- transitions = {
- "WebkitTransition" : "webkitTransitionEnd",
- "MozTransition" : "transitionend",
- "OTransition" : "otransitionend",
- "transition" : "transitionend"
- };
-
- for (t in transitions) {
- if (el.style[t] !== undefined) {
- type = transitions[t];
- supported = true;
- break;
- }
- }
-
- return {
- type : type,
- supported : supported
- };
- };
-
- /**
- * Shorthand for document.getElementById()
- *
- * @param {String} id A specific element ID
- * @return {Object} HTML element
- */
- $ = function (id) {
- return document.getElementById(id);
- };
-
- /**
- * Alertify private object
- * @type {Object}
- */
- _alertify = {
-
- /**
- * Labels object
- * @type {Object}
- */
- labels : {
- ok : "OK",
- cancel : "Cancel"
- },
-
- /**
- * Delay number
- * @type {Number}
- */
- delay : 5000,
-
- /**
- * Whether buttons are reversed (default is secondary/primary)
- * @type {Boolean}
- */
- buttonReverse : false,
-
- /**
- * Which button should be focused by default
- * @type {String} "ok" (default), "cancel", or "none"
- */
- buttonFocus : "ok",
-
- /**
- * Set the transition event on load
- * @type {[type]}
- */
- transition : undefined,
-
- /**
- * Set the proper button click events
- *
- * @param {Function} fn [Optional] Callback function
- *
- * @return {undefined}
- */
- addListeners : function (fn) {
- var hasOK = (typeof btnOK !== "undefined"),
- hasCancel = (typeof btnCancel !== "undefined"),
- hasInput = (typeof input !== "undefined"),
- val = "",
- self = this,
- ok, cancel, common, key, reset;
-
- // ok event handler
- ok = function (event) {
- if (typeof event.preventDefault !== "undefined") event.preventDefault();
- common(event);
- if (typeof input !== "undefined") val = input.value;
- if (typeof fn === "function") {
- if (typeof input !== "undefined") {
- fn(true, val);
- }
- else fn(true);
- }
- return false;
- };
-
- // cancel event handler
- cancel = function (event) {
- if (typeof event.preventDefault !== "undefined") event.preventDefault();
- common(event);
- if (typeof fn === "function") fn(false);
- return false;
- };
-
- // common event handler (keyup, ok and cancel)
- common = function (event) {
- self.hide();
- self.unbind(document.body, "keyup", key);
- self.unbind(btnReset, "focus", reset);
- if (hasOK) self.unbind(btnOK, "click", ok);
- if (hasCancel) self.unbind(btnCancel, "click", cancel);
- };
-
- // keyup handler
- key = function (event) {
- var keyCode = event.keyCode;
- if ((keyCode === keys.SPACE && !hasInput) || (hasInput && keyCode === keys.ENTER)) ok(event);
- if (keyCode === keys.ESC && hasCancel) cancel(event);
- };
-
- // reset focus to first item in the dialog
- reset = function (event) {
- if (hasInput) input.focus();
- else if (!hasCancel || self.buttonReverse) btnOK.focus();
- else btnCancel.focus();
- };
-
- // handle reset focus link
- // this ensures that the keyboard focus does not
- // ever leave the dialog box until an action has
- // been taken
- this.bind(btnReset, "focus", reset);
- this.bind(btnResetBack, "focus", reset);
- // handle OK click
- if (hasOK) this.bind(btnOK, "click", ok);
- // handle Cancel click
- if (hasCancel) this.bind(btnCancel, "click", cancel);
- // listen for keys, Cancel => ESC
- this.bind(document.body, "keyup", key);
- if (!this.transition.supported) {
- this.setFocus();
- }
- },
-
- /**
- * Bind events to elements
- *
- * @param {Object} el HTML Object
- * @param {Event} event Event to attach to element
- * @param {Function} fn Callback function
- *
- * @return {undefined}
- */
- bind : function (el, event, fn) {
- if (typeof el.addEventListener === "function") {
- el.addEventListener(event, fn, false);
- } else if (el.attachEvent) {
- el.attachEvent("on" + event, fn);
- }
- },
-
- /**
- * Use alertify as the global error handler (using window.onerror)
- *
- * @return {boolean} success
- */
- handleErrors : function () {
- if (typeof global.onerror !== "undefined") {
- var self = this;
- global.onerror = function (msg, url, line) {
- self.error("[" + msg + " on line " + line + " of " + url + "]", 0);
- };
- return true;
- } else {
- return false;
- }
- },
-
- /**
- * Append button HTML strings
- *
- * @param {String} secondary The secondary button HTML string
- * @param {String} primary The primary button HTML string
- *
- * @return {String} The appended button HTML strings
- */
- appendButtons : function (secondary, primary) {
- return this.buttonReverse ? primary + secondary : secondary + primary;
- },
-
- /**
- * Build the proper message box
- *
- * @param {Object} item Current object in the queue
- *
- * @return {String} An HTML string of the message box
- */
- build : function (item) {
- var html = "",
- type = item.type,
- message = item.message,
- css = item.cssClass || "";
-
- html += "
";
- html += "Reset Focus";
-
- if (_alertify.buttonFocus === "none") html += "";
-
- // doens't require an actual form
- if (type === "prompt") html += "
";
-
- html += "";
- html += dialogs.message.replace("{{message}}", message);
-
- if (type === "prompt") html += dialogs.input;
-
- html += dialogs.buttons.holder;
- html += "";
-
- if (type === "prompt") html += "
";
-
- switch (type) {
- case "confirm":
- html = html.replace("{{buttons}}", this.appendButtons(dialogs.buttons.cancel, dialogs.buttons.ok));
- html = html.replace("{{ok}}", this.labels.ok).replace("{{cancel}}", this.labels.cancel);
- break;
- case "prompt":
- html = html.replace("{{buttons}}", this.appendButtons(dialogs.buttons.cancel, dialogs.buttons.submit));
- html = html.replace("{{ok}}", this.labels.ok).replace("{{cancel}}", this.labels.cancel);
- break;
- case "alert":
- html = html.replace("{{buttons}}", dialogs.buttons.ok);
- html = html.replace("{{ok}}", this.labels.ok);
- break;
- default:
- break;
- }
-
- elDialog.className = "alertify alertify-" + type + " " + css;
- elCover.className = "alertify-cover";
- return html;
- },
-
- /**
- * Close the log messages
- *
- * @param {Object} elem HTML Element of log message to close
- * @param {Number} wait [optional] Time (in ms) to wait before automatically hiding the message, if 0 never hide
- *
- * @return {undefined}
- */
- close : function (elem, wait) {
- // Unary Plus: +"2" === 2
- var timer = (wait && !isNaN(wait)) ? +wait : this.delay,
- self = this,
- hideElement, transitionDone;
-
- // set click event on log messages
- this.bind(elem, "click", function () {
- hideElement(elem);
- });
- // Hide the dialog box after transition
- // This ensure it doens't block any element from being clicked
- transitionDone = function (event) {
- event.stopPropagation();
- // unbind event so function only gets called once
- self.unbind(this, self.transition.type, transitionDone);
- // remove log message
- elLog.removeChild(this);
- if (!elLog.hasChildNodes()) elLog.className += " alertify-logs-hidden";
- };
- // this sets the hide class to transition out
- // or removes the child if css transitions aren't supported
- hideElement = function (el) {
- // ensure element exists
- if (typeof el !== "undefined" && el.parentNode === elLog) {
- // whether CSS transition exists
- if (self.transition.supported) {
- self.bind(el, self.transition.type, transitionDone);
- el.className += " alertify-log-hide";
- } else {
- elLog.removeChild(el);
- if (!elLog.hasChildNodes()) elLog.className += " alertify-logs-hidden";
- }
- }
- };
- // never close (until click) if wait is set to 0
- if (wait === 0) return;
- // set timeout to auto close the log message
- setTimeout(function () { hideElement(elem); }, timer);
- },
-
- /**
- * Create a dialog box
- *
- * @param {String} message The message passed from the callee
- * @param {String} type Type of dialog to create
- * @param {Function} fn [Optional] Callback function
- * @param {String} placeholder [Optional] Default value for prompt input field
- * @param {String} cssClass [Optional] Class(es) to append to dialog box
- *
- * @return {Object}
- */
- dialog : function (message, type, fn, placeholder, cssClass) {
- // set the current active element
- // this allows the keyboard focus to be resetted
- // after the dialog box is closed
- elCallee = document.activeElement;
- // check to ensure the alertify dialog element
- // has been successfully created
- var check = function () {
- if ((elLog && elLog.scrollTop !== null) && (elCover && elCover.scrollTop !== null)) return;
- else check();
- };
- // error catching
- if (typeof message !== "string") throw new Error("message must be a string");
- if (typeof type !== "string") throw new Error("type must be a string");
- if (typeof fn !== "undefined" && typeof fn !== "function") throw new Error("fn must be a function");
- // initialize alertify if it hasn't already been done
- this.init();
- check();
-
- queue.push({ type: type, message: message, callback: fn, placeholder: placeholder, cssClass: cssClass });
- if (!isopen) this.setup();
-
- return this;
- },
-
- /**
- * Extend the log method to create custom methods
- *
- * @param {String} type Custom method name
- *
- * @return {Function}
- */
- extend : function (type) {
- if (typeof type !== "string") throw new Error("extend method must have exactly one paramter");
- return function (message, wait) {
- this.log(message, type, wait);
- return this;
- };
- },
-
- /**
- * Hide the dialog and rest to defaults
- *
- * @return {undefined}
- */
- hide : function () {
- var transitionDone,
- self = this;
- // remove reference from queue
- queue.splice(0,1);
- // if items remaining in the queue
- if (queue.length > 0) this.setup(true);
- else {
- isopen = false;
- // Hide the dialog box after transition
- // This ensure it doens't block any element from being clicked
- transitionDone = function (event) {
- event.stopPropagation();
- // unbind event so function only gets called once
- self.unbind(elDialog, self.transition.type, transitionDone);
- };
- // whether CSS transition exists
- if (this.transition.supported) {
- this.bind(elDialog, this.transition.type, transitionDone);
- elDialog.className = "alertify alertify-hide alertify-hidden";
- } else {
- elDialog.className = "alertify alertify-hide alertify-hidden alertify-isHidden";
- }
- elCover.className = "alertify-cover alertify-cover-hidden";
- // set focus to the last element or body
- // after the dialog is closed
- elCallee.focus();
- }
- },
-
- /**
- * Initialize Alertify
- * Create the 2 main elements
- *
- * @return {undefined}
- */
- init : function () {
- // ensure legacy browsers support html5 tags
- document.createElement("nav");
- document.createElement("article");
- document.createElement("section");
- // cover
- if ($("alertify-cover") == null) {
- elCover = document.createElement("div");
- elCover.setAttribute("id", "alertify-cover");
- elCover.className = "alertify-cover alertify-cover-hidden";
- document.body.appendChild(elCover);
- }
- // main element
- if ($("alertify") == null) {
- isopen = false;
- queue = [];
- elDialog = document.createElement("section");
- elDialog.setAttribute("id", "alertify");
- elDialog.className = "alertify alertify-hidden";
- document.body.appendChild(elDialog);
- }
- // log element
- if ($("alertify-logs") == null) {
- elLog = document.createElement("section");
- elLog.setAttribute("id", "alertify-logs");
- elLog.className = "alertify-logs alertify-logs-hidden";
- document.body.appendChild(elLog);
- }
- // set tabindex attribute on body element
- // this allows script to give it focus
- // after the dialog is closed
- document.body.setAttribute("tabindex", "0");
- // set transition type
- this.transition = getTransitionEvent();
- },
-
- /**
- * Show a new log message box
- *
- * @param {String} message The message passed from the callee
- * @param {String} type [Optional] Optional type of log message
- * @param {Number} wait [Optional] Time (in ms) to wait before auto-hiding the log
- *
- * @return {Object}
- */
- log : function (message, type, wait) {
- // check to ensure the alertify dialog element
- // has been successfully created
- var check = function () {
- if (elLog && elLog.scrollTop !== null) return;
- else check();
- };
- // initialize alertify if it hasn't already been done
- this.init();
- check();
-
- elLog.className = "alertify-logs";
- this.notify(message, type, wait);
- return this;
- },
-
- /**
- * Add new log message
- * If a type is passed, a class name "alertify-log-{type}" will get added.
- * This allows for custom look and feel for various types of notifications.
- *
- * @param {String} message The message passed from the callee
- * @param {String} type [Optional] Type of log message
- * @param {Number} wait [Optional] Time (in ms) to wait before auto-hiding
- *
- * @return {undefined}
- */
- notify : function (message, type, wait) {
- var log = document.createElement("article");
- log.className = "alertify-log" + ((typeof type === "string" && type !== "") ? " alertify-log-" + type : "");
- log.innerHTML = message;
- // append child
- elLog.appendChild(log);
- // triggers the CSS animation
- setTimeout(function() { log.className = log.className + " alertify-log-show"; }, 50);
- this.close(log, wait);
- },
-
- /**
- * Set properties
- *
- * @param {Object} args Passing parameters
- *
- * @return {undefined}
- */
- set : function (args) {
- var k;
- // error catching
- if (typeof args !== "object" && args instanceof Array) throw new Error("args must be an object");
- // set parameters
- for (k in args) {
- if (args.hasOwnProperty(k)) {
- this[k] = args[k];
- }
- }
- },
-
- /**
- * Common place to set focus to proper element
- *
- * @return {undefined}
- */
- setFocus : function () {
- if (input) {
- input.focus();
- input.select();
- }
- else btnFocus.focus();
- },
-
- /**
- * Initiate all the required pieces for the dialog box
- *
- * @return {undefined}
- */
- setup : function (fromQueue) {
- var item = queue[0],
- self = this,
- transitionDone;
-
- // dialog is open
- isopen = true;
- // Set button focus after transition
- transitionDone = function (event) {
- event.stopPropagation();
- self.setFocus();
- // unbind event so function only gets called once
- self.unbind(elDialog, self.transition.type, transitionDone);
- };
- // whether CSS transition exists
- if (this.transition.supported && !fromQueue) {
- this.bind(elDialog, this.transition.type, transitionDone);
- }
- // build the proper dialog HTML
- elDialog.innerHTML = this.build(item);
- // assign all the common elements
- btnReset = $("alertify-resetFocus");
- btnResetBack = $("alertify-resetFocusBack");
- btnOK = $("alertify-ok") || undefined;
- btnCancel = $("alertify-cancel") || undefined;
- btnFocus = (_alertify.buttonFocus === "cancel") ? btnCancel : ((_alertify.buttonFocus === "none") ? $("alertify-noneFocus") : btnOK),
- input = $("alertify-text") || undefined;
- form = $("alertify-form") || undefined;
- // add placeholder value to the input field
- if (typeof item.placeholder === "string" && item.placeholder !== "") input.value = item.placeholder;
- if (fromQueue) this.setFocus();
- this.addListeners(item.callback);
- },
-
- /**
- * Unbind events to elements
- *
- * @param {Object} el HTML Object
- * @param {Event} event Event to detach to element
- * @param {Function} fn Callback function
- *
- * @return {undefined}
- */
- unbind : function (el, event, fn) {
- if (typeof el.removeEventListener === "function") {
- el.removeEventListener(event, fn, false);
- } else if (el.detachEvent) {
- el.detachEvent("on" + event, fn);
- }
- }
- };
-
- return {
- alert : function (message, fn, cssClass) { _alertify.dialog(message, "alert", fn, "", cssClass); return this; },
- confirm : function (message, fn, cssClass) { _alertify.dialog(message, "confirm", fn, "", cssClass); return this; },
- extend : _alertify.extend,
- init : _alertify.init,
- log : function (message, type, wait) { _alertify.log(message, type, wait); return this; },
- prompt : function (message, fn, placeholder, cssClass) { _alertify.dialog(message, "prompt", fn, placeholder, cssClass); return this; },
- success : function (message, wait) { _alertify.log(message, "success", wait); return this; },
- error : function (message, wait) { _alertify.log(message, "error", wait); return this; },
- set : function (args) { _alertify.set(args); },
- labels : _alertify.labels,
- debug : _alertify.handleErrors
- };
- };
-
- // AMD and window support
- if (typeof define === "function") {
- define([], function () { return new Alertify(); });
- } else if (typeof global.alertify === "undefined") {
- global.alertify = new Alertify();
- }
-
-}(this));
+ "use strict";
+
+ var document = global.document,
+ Alertify;
+
+ Alertify = function () {
+
+ var _alertify = {},
+ dialogs = {},
+ isopen = false,
+ keys = {ENTER: 13, ESC: 27, SPACE: 32},
+ queue = [],
+ $, btnCancel, btnOK, btnReset, btnResetBack, btnFocus, elCallee, elCover, elDialog, elLog, form, input, getTransitionEvent, uniqueId;
+
+ /**
+ * Markup pieces
+ * @type {Object}
+ */
+ dialogs = {
+ buttons: {
+ holder: "",
+ submit: "",
+ ok: "",
+ cancel: ""
+ },
+ input: "",
+ message: "
{{message}}
",
+ log: "{{message}}"
+ };
+
+ /**
+ * Return the proper transitionend event
+ * @return {String} Transition type string
+ */
+ getTransitionEvent = function () {
+ var t,
+ type,
+ supported = false,
+ el = document.createElement("fakeelement"),
+ transitions = {
+ "WebkitTransition": "webkitTransitionEnd",
+ "MozTransition": "transitionend",
+ "OTransition": "otransitionend",
+ "transition": "transitionend"
+ };
+
+ for (t in transitions) {
+ if (el.style[t] !== undefined) {
+ type = transitions[t];
+ supported = true;
+ break;
+ }
+ }
+
+ return {
+ type: type,
+ supported: supported
+ };
+ };
+
+ /**
+ * Shorthand for document.getElementById()
+ *
+ * @param {String} id A specific element ID
+ * @return {Object} HTML element
+ */
+ $ = function (id) {
+ return document.getElementById(id);
+ };
+
+ /**
+ * Alertify private object
+ * @type {Object}
+ */
+ _alertify = {
+ /**
+ * Labels object
+ * @type {Object}
+ */
+ labels: {
+ ok: "OK",
+ cancel: "Cancel"
+ },
+
+ /**
+ * Delay number
+ * @type {Number}
+ */
+ delay: 5000,
+
+ /**
+ * Whether buttons are reversed (default is secondary/primary)
+ * @type {Boolean}
+ */
+ buttonReverse: false,
+
+ /**
+ * Which button should be focused by default
+ * @type {String} "ok" (default), "cancel", or "none"
+ */
+ buttonFocus: "ok",
+
+ /**
+ * Set the transition event on load
+ * @type {[type]}
+ */
+ transition: undefined,
+
+ /**
+ * Set the proper button click events
+ *
+ * @param {Function} fn [Optional] Callback function
+ *
+ * @return {undefined}
+ */
+ addListeners: function (fn) {
+ var hasOK = (typeof btnOK !== "undefined"),
+ hasCancel = (typeof btnCancel !== "undefined"),
+ hasInput = (typeof input !== "undefined"),
+ val = "",
+ self = this,
+ ok, cancel, common, key, reset;
+
+ // ok event handler
+ ok = function (event) {
+ if (typeof event.preventDefault !== "undefined") event.preventDefault();
+ common(event);
+ if (typeof input !== "undefined") val = input.value;
+ if (typeof fn === "function") {
+ if (typeof input !== "undefined") {
+ fn(true, val);
+ }
+ else fn(true);
+ }
+ return false;
+ };
+
+ // cancel event handler
+ cancel = function (event) {
+ if (typeof event.preventDefault !== "undefined") event.preventDefault();
+ common(event);
+ if (typeof fn === "function") fn(false);
+ return false;
+ };
+
+ // common event handler (keyup, ok and cancel)
+ common = function (event) {
+ self.hide();
+ self.unbind(document.body, "keyup", key);
+ self.unbind(btnReset, "focus", reset);
+ if (hasOK) self.unbind(btnOK, "click", ok);
+ if (hasCancel) self.unbind(btnCancel, "click", cancel);
+ };
+
+ // keyup handler
+ key = function (event) {
+ var keyCode = event.keyCode;
+ if ((keyCode === keys.SPACE && !hasInput) || (hasInput && keyCode === keys.ENTER)) ok(event);
+ if (keyCode === keys.ESC && hasCancel) cancel(event);
+ };
+
+ // reset focus to first item in the dialog
+ reset = function (event) {
+ if (hasInput) input.focus();
+ else if (!hasCancel || self.buttonReverse) btnOK.focus();
+ else btnCancel.focus();
+ };
+
+ // handle reset focus link
+ // this ensures that the keyboard focus does not
+ // ever leave the dialog box until an action has
+ // been taken
+ this.bind(btnReset, "focus", reset);
+ this.bind(btnResetBack, "focus", reset);
+ // handle OK click
+ if (hasOK) this.bind(btnOK, "click", ok);
+ // handle Cancel click
+ if (hasCancel) this.bind(btnCancel, "click", cancel);
+ // listen for keys, Cancel => ESC
+ this.bind(document.body, "keyup", key);
+ if (!this.transition.supported) {
+ this.setFocus();
+ }
+ },
+
+ /**
+ * Bind events to elements
+ *
+ * @param {Object} el HTML Object
+ * @param {Event} event Event to attach to element
+ * @param {Function} fn Callback function
+ *
+ * @return {undefined}
+ */
+ bind: function (el, event, fn) {
+ if (typeof el.addEventListener === "function") {
+ el.addEventListener(event, fn, false);
+ } else if (el.attachEvent) {
+ el.attachEvent("on" + event, fn);
+ }
+ },
+
+ /**
+ * Use alertify as the global error handler (using window.onerror)
+ *
+ * @return {boolean} success
+ */
+ handleErrors: function () {
+ if (typeof global.onerror !== "undefined") {
+ var self = this;
+ global.onerror = function (msg, url, line) {
+ self.error("[" + msg + " on line " + line + " of " + url + "]", 0);
+ };
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Append button HTML strings
+ *
+ * @param {String} secondary The secondary button HTML string
+ * @param {String} primary The primary button HTML string
+ *
+ * @return {String} The appended button HTML strings
+ */
+ appendButtons: function (secondary, primary) {
+ return this.buttonReverse ? primary + secondary : secondary + primary;
+ },
+
+ /**
+ * Build the proper message box
+ *
+ * @param {Object} item Current object in the queue
+ *
+ * @return {String} An HTML string of the message box
+ */
+ build: function (item) {
+ var html = "",
+ type = item.type,
+ message = item.message,
+ css = item.cssClass || "";
+
+ html += "
";
+ html += "Reset Focus";
+
+ if (_alertify.buttonFocus === "none") html += "";
+
+ // doens't require an actual form
+ if (type === "prompt") html += "
";
+
+ html += "";
+ html += dialogs.message.replace("{{message}}", message);
+
+ if (type === "prompt") html += dialogs.input;
+
+ html += dialogs.buttons.holder;
+ html += "";
+
+ if (type === "prompt") html += "
",c){case"confirm":b=b.replace("{{buttons}}",this.appendButtons(r.buttons.cancel,r.buttons.ok)),b=b.replace("{{ok}}",this.labels.ok).replace("{{cancel}}",this.labels.cancel);break;case"prompt":b=b.replace("{{buttons}}",this.appendButtons(r.buttons.cancel,r.buttons.submit)),b=b.replace("{{ok}}",this.labels.ok).replace("{{cancel}}",this.labels.cancel);break;case"alert":b=b.replace("{{buttons}}",r.buttons.ok),b=b.replace("{{ok}}",this.labels.ok)}return l.className="alertify alertify-"+c+" "+e,k.className="alertify-cover",b},close:function(a,b){var c,d,e=b&&!isNaN(b)?+b:this.delay,f=this;this.bind(a,"click",function(){c(a)}),d=function(a){a.stopPropagation(),f.unbind(this,f.transition.type,d),m.removeChild(this),m.hasChildNodes()||(m.className+=" alertify-logs-hidden")},c=function(a){"undefined"!=typeof a&&a.parentNode===m&&(f.transition.supported?(f.bind(a,f.transition.type,d),a.className+=" alertify-log-hide"):(m.removeChild(a),m.hasChildNodes()||(m.className+=" alertify-logs-hidden")))},0!==b&&setTimeout(function(){c(a)},e)},dialog:function(a,b,c,e,f){j=d.activeElement;var g=function(){m&&null!==m.scrollTop&&k&&null!==k.scrollTop||g()};if("string"!=typeof a)throw new Error("message must be a string");if("string"!=typeof b)throw new Error("type must be a string");if("undefined"!=typeof c&&"function"!=typeof c)throw new Error("fn must be a function");return this.init(),g(),u.push({type:b,message:a,callback:c,placeholder:e,cssClass:f}),s||this.setup(),this},extend:function(a){if("string"!=typeof a)throw new Error("extend method must have exactly one paramter");return function(b,c){return this.log(b,a,c),this}},hide:function(){var a,b=this;u.splice(0,1),u.length>0?this.setup(!0):(s=!1,a=function(c){c.stopPropagation(),b.unbind(l,b.transition.type,a)},this.transition.supported?(this.bind(l,this.transition.type,a),l.className="alertify alertify-hide alertify-hidden"):l.className="alertify alertify-hide alertify-hidden alertify-isHidden",k.className="alertify-cover alertify-cover-hidden",j.focus())},init:function(){d.createElement("nav"),d.createElement("article"),d.createElement("section"),null==c("alertify-cover")&&(k=d.createElement("div"),k.setAttribute("id","alertify-cover"),k.className="alertify-cover alertify-cover-hidden",d.body.appendChild(k)),null==c("alertify")&&(s=!1,u=[],l=d.createElement("section"),l.setAttribute("id","alertify"),l.className="alertify alertify-hidden",d.body.appendChild(l)),null==c("alertify-logs")&&(m=d.createElement("section"),m.setAttribute("id","alertify-logs"),m.className="alertify-logs alertify-logs-hidden",d.body.appendChild(m)),d.body.setAttribute("tabindex","0"),this.transition=p()},log:function(a,b,c){var d=function(){m&&null!==m.scrollTop||d()};return this.init(),d(),m.className="alertify-logs",this.notify(a,b,c),this},notify:function(a,b,c){var e=d.createElement("article");e.className="alertify-log"+("string"==typeof b&&""!==b?" alertify-log-"+b:""),e.innerHTML=a,m.appendChild(e),setTimeout(function(){e.className=e.className+" alertify-log-show"},50),this.close(e,c)},set:function(a){var b;if("object"!=typeof a&&a instanceof Array)throw new Error("args must be an object");for(b in a)a.hasOwnProperty(b)&&(this[b]=a[b])},setFocus:function(){o?(o.focus(),o.select()):i.focus()},setup:function(a){var d,j=u[0],k=this;s=!0,d=function(a){a.stopPropagation(),k.setFocus(),k.unbind(l,k.transition.type,d)},this.transition.supported&&!a&&this.bind(l,this.transition.type,d),l.innerHTML=this.build(j),g=c("alertify-resetFocus"),h=c("alertify-resetFocusBack"),f=c("alertify-ok")||b,e=c("alertify-cancel")||b,i="cancel"===q.buttonFocus?e:"none"===q.buttonFocus?c("alertify-noneFocus"):f,o=c("alertify-text")||b,n=c("alertify-form")||b,"string"==typeof j.placeholder&&""!==j.placeholder&&(o.value=j.placeholder),a&&this.setFocus(),this.addListeners(j.callback)},unbind:function(a,b,c){"function"==typeof a.removeEventListener?a.removeEventListener(b,c,!1):a.detachEvent&&a.detachEvent("on"+b,c)}},{alert:function(a,b,c){return q.dialog(a,"alert",b,"",c),this},confirm:function(a,b,c){return q.dialog(a,"confirm",b,"",c),this},extend:q.extend,init:q.init,log:function(a,b,c){return q.log(a,b,c),this},prompt:function(a,b,c,d){return q.dialog(a,"prompt",b,c,d),this},success:function(a,b){return q.log(a,"success",b),this},error:function(a,b){return q.log(a,"error",b),this},set:function(a){q.set(a)},labels:q.labels,debug:q.handleErrors}},"function"==typeof define?define([],function(){return new c}):"undefined"==typeof a.alertify&&(a.alertify=new c)}(this);
\ No newline at end of file
+!function(a,b){"use strict";var d,c=a.document;d=function(){var i,j,k,l,m,n,o,p,q,r,s,t,u,v,d={},e={},f=!1,g={ENTER:13,ESC:27,SPACE:32},h=[];return e={buttons:{holder:'',submit:'',ok:'',cancel:''},input:'',message:'
{{message}}
',log:'{{message}}'},u=function(){var a,d,e=!1,f=c.createElement("fakeelement"),g={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"otransitionend",transition:"transitionend"};for(a in g)if(f.style[a]!==b){d=g[a],e=!0;break}return{type:d,supported:e}},i=function(a){return c.getElementById(a)},d={labels:{ok:"OK",cancel:"Cancel"},delay:5e3,buttonReverse:!1,buttonFocus:"ok",transition:b,addListeners:function(a){var i,n,o,p,q,b="undefined"!=typeof k,d="undefined"!=typeof j,e="undefined"!=typeof t,f="",h=this;i=function(b){return"undefined"!=typeof b.preventDefault&&b.preventDefault(),o(b),"undefined"!=typeof t&&(f=t.value),"function"==typeof a&&("undefined"!=typeof t?a(!0,f):a(!0)),!1},n=function(b){return"undefined"!=typeof b.preventDefault&&b.preventDefault(),o(b),"function"==typeof a&&a(!1),!1},o=function(a){h.hide(),h.unbind(c.body,"keyup",p),h.unbind(l,"focus",q),b&&h.unbind(k,"click",i),d&&h.unbind(j,"click",n)},p=function(a){var b=a.keyCode;(b===g.SPACE&&!e||e&&b===g.ENTER)&&i(a),b===g.ESC&&d&&n(a)},q=function(a){e?t.focus():!d||h.buttonReverse?k.focus():j.focus()},this.bind(l,"focus",q),this.bind(m,"focus",q),b&&this.bind(k,"click",i),d&&this.bind(j,"click",n),this.bind(c.body,"keyup",p),this.transition.supported||this.setFocus()},bind:function(a,b,c){"function"==typeof a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent&&a.attachEvent("on"+b,c)},handleErrors:function(){if("undefined"!=typeof a.onerror){var b=this;return a.onerror=function(a,c,d){b.error("["+a+" on line "+d+" of "+c+"]",0)},!0}return!1},appendButtons:function(a,b){return this.buttonReverse?b+a:a+b},build:function(a){var b="",c=a.type,f=a.message,g=a.cssClass||"";switch(b+='