1/*global define*/ 2(function (global, undefined) { 3 "use strict"; 4 5 var document = global.document, 6 Alertify; 7 8 Alertify = function () { 9 10 var _alertify = {}, 11 dialogs = {}, 12 isopen = false, 13 keys = { ENTER: 13, ESC: 27, SPACE: 32 }, 14 queue = [], 15 $, btnCancel, btnOK, btnReset, btnResetBack, btnFocus, elCallee, elCover, elDialog, elLog, form, input, getTransitionEvent; 16 17 /** 18 * Markup pieces 19 * @type {Object} 20 */ 21 dialogs = { 22 buttons : { 23 holder : "<nav class=\"alertify-buttons\">{{buttons}}</nav>", 24 submit : "<button type=\"submit\" class=\"alert-button alert-button-ok\" id=\"alertify-ok\">{{ok}}</button>", 25 ok : "<button class=\"alert-button alert-button-ok\" id=\"alertify-ok\">{{ok}}</button>", 26 cancel : "<button class=\"alert-button alert-button-cancel\" id=\"alertify-cancel\">{{cancel}}</button>" 27 }, 28 input : "<div class=\"alertify-text-wrapper\"><input type=\"text\" class=\"alertify-text\" id=\"alertify-text\"></div>", 29 message : "<p class=\"alertify-message\">{{message}}</p>", 30 log : "<article class=\"alertify-log{{class}}\">{{message}}</article>" 31 }; 32 33 /** 34 * Return the proper transitionend event 35 * @return {String} Transition type string 36 */ 37 getTransitionEvent = function () { 38 var t, 39 type, 40 supported = false, 41 el = document.createElement("fakeelement"), 42 transitions = { 43 "WebkitTransition" : "webkitTransitionEnd", 44 "MozTransition" : "transitionend", 45 "OTransition" : "otransitionend", 46 "transition" : "transitionend" 47 }; 48 49 for (t in transitions) { 50 if (el.style[t] !== undefined) { 51 type = transitions[t]; 52 supported = true; 53 break; 54 } 55 } 56 57 return { 58 type : type, 59 supported : supported 60 }; 61 }; 62 63 /** 64 * Shorthand for document.getElementById() 65 * 66 * @param {String} id A specific element ID 67 * @return {Object} HTML element 68 */ 69 $ = function (id) { 70 return document.getElementById(id); 71 }; 72 73 /** 74 * Alertify private object 75 * @type {Object} 76 */ 77 _alertify = { 78 79 /** 80 * Labels object 81 * @type {Object} 82 */ 83 labels : { 84 ok : "OK", 85 cancel : "Cancelar" 86 }, 87 88 /** 89 * Delay number 90 * @type {Number} 91 */ 92 delay : 5000, 93 94 /** 95 * Whether buttons are reversed (default is secondary/primary) 96 * @type {Boolean} 97 */ 98 buttonReverse : false, 99 100 /** 101 * Which button should be focused by default 102 * @type {String} "ok" (default), "cancel", or "none" 103 */ 104 buttonFocus : "ok", 105 106 /** 107 * Set the transition event on load 108 * @type {[type]} 109 */ 110 transition : undefined, 111 112 /** 113 * Set the proper button click events 114 * 115 * @param {Function} fn [Optional] Callback function 116 * 117 * @return {undefined} 118 */ 119 addListeners : function (fn) { 120 var hasOK = (typeof btnOK !== "undefined"), 121 hasCancel = (typeof btnCancel !== "undefined"), 122 hasInput = (typeof input !== "undefined"), 123 val = "", 124 self = this, 125 ok, cancel, common, key, reset; 126 127 // ok event handler 128 ok = function (event) { 129 if (typeof event.preventDefault !== "undefined") event.preventDefault(); 130 common(event); 131 if (typeof input !== "undefined") val = input.value; 132 if (typeof fn === "function") { 133 if (typeof input !== "undefined") { 134 fn(true, val); 135 } 136 else fn(true); 137 } 138 return false; 139 }; 140 141 // cancel event handler 142 cancel = function (event) { 143 if (typeof event.preventDefault !== "undefined") event.preventDefault(); 144 common(event); 145 if (typeof fn === "function") fn(false); 146 return false; 147 }; 148 149 // common event handler (keyup, ok and cancel) 150 common = function (event) { 151 self.hide(); 152 self.unbind(document.body, "keyup", key); 153 self.unbind(btnReset, "focus", reset); 154 if (hasOK) self.unbind(btnOK, "click", ok); 155 if (hasCancel) self.unbind(btnCancel, "click", cancel); 156 }; 157 158 // keyup handler 159 key = function (event) { 160 var keyCode = event.keyCode; 161 if ((keyCode === keys.SPACE && !hasInput) || (hasInput && keyCode === keys.ENTER)) ok(event); 162 if (keyCode === keys.ESC && hasCancel) cancel(event); 163 }; 164 165 // reset focus to first item in the dialog 166 reset = function (event) { 167 if (hasInput) input.focus(); 168 else if (!hasCancel || self.buttonReverse) btnOK.focus(); 169 else btnCancel.focus(); 170 }; 171 172 // handle reset focus link 173 // this ensures that the keyboard focus does not 174 // ever leave the dialog box until an action has 175 // been taken
176 this.bind(btnReset, "focus", reset); 177 this.bind(btnResetBack, "focus", reset); 178 // handle OK click 179 if (hasOK) this.bind(btnOK, "click", ok); 180 // handle Cancel click 181 if (hasCancel) this.bind(btnCancel, "click", cancel); 182 // listen for keys, Cancel => ESC 183 this.bind(document.body, "keyup", key); 184 if (!this.transition.supported) { 185 this.setFocus(); 186 } 187 }, 188 189 /** 190 * Bind events to elements 191 * 192 * @param {Object} el HTML Object 193 * @param {Event} event Event to attach to element 194 * @param {Function} fn Callback function 195 * 196 * @return {undefined} 197 */ 198 bind : function (el, event, fn) { 199 if (typeof el.addEventListener === "function") { 200 el.addEventListener(event, fn, false); 201 } else if (el.attachEvent) { 202 el.attachEvent("on" + event, fn); 203 } 204 }, 205 206 /** 207 * Use alertify as the global error handler (using window.onerror) 208 * 209 * @return {boolean} success 210 */ 211 handleErrors : function () { 212 if (typeof global.onerror !== "undefined") { 213 var self = this; 214 global.onerror = function (msg, url, line) { 215 self.error("[" + msg + " on line " + line + " of " + url + "]", 0); 216 }; 217 return true; 218 } else { 219 return false; 220 } 221 }, 222 223 /** 224 * Append button HTML strings 225 * 226 * @param {String} secondary The secondary button HTML string 227 * @param {String} primary The primary button HTML string 228 * 229 * @return {String} The appended button HTML strings 230 */ 231 appendButtons : function (secondary, primary) { 232 return this.buttonReverse ? primary + secondary : secondary + primary; 233 }, 234 235 /** 236 * Build the proper message box 237 * 238 * @param {Object} item Current object in the queue 239 * 240 * @return {String} An HTML string of the message box 241 */ 242 build : function (item) { 243 var html = "", 244 type = item.type, 245 message = item.message, 246 css = item.cssClass || ""; 247 248 html += "<div class=\"alertify-dialog\">"; 249 html += "<a id=\"alertify-resetFocusBack\" class=\"alertify-resetFocus\" href=\"#\">Reset Focus</a>"; 250 251 if (_alertify.buttonFocus === "none") html += "<a href=\"#\" id=\"alertify-noneFocus\" class=\"alertify-hidden\"></a>"; 252 253 // doens't require an actual form 254 if (type === "prompt") html += "<div id=\"alertify-form\">"; 255 256 html += "<article class=\"alertify-inner\"><span style='Color:black;'>"; 257 html += dialogs.message.replace("{{message}}", message); 258 html += "</span>"; 259 260 if (type === "prompt") html += dialogs.input; 261 262 html += dialogs.buttons.holder; 263 html += "</article>"; 264 265 if (type === "prompt") html += "</div>"; 266 267 html += "<a id=\"alertify-resetFocus\" class=\"alertify-resetFocus\" href=\"#\">Reset Focus</a>"; 268 html += "</div>"; 269 270 switch (type) { 271 case "confirm": 272 html = html.replace("{{buttons}}", this.appendButtons(dialogs.buttons.cancel, dialogs.buttons.ok)); 273 html = html.replace("{{ok}}", this.labels.ok).replace("{{cancel}}", this.labels.cancel); 274 break; 275 case "prompt": 276 html = html.replace("{{buttons}}", this.appendButtons(dialogs.buttons.cancel, dialogs.buttons.submit)); 277 html = html.replace("{{ok}}", this.labels.ok).replace("{{cancel}}", this.labels.cancel); 278 break; 279 case "alert": 280 html = html.replace("{{buttons}}", dialogs.buttons.ok); 281 html = html.replace("{{ok}}", this.labels.ok); 282 break; 283 default: 284 break; 285 } 286 287 elDialog.className = "alertify alertify-" + type + " " + css; 288 elCover.className = "alertify-cover"; 289 return html; 290 }, 291 292 /** 293 * Close the log messages 294 * 295 * @param {Object} elem HTML Element of log message to close 296 * @param {Number} wait [optional] Time (in ms) to wait before automatically hiding the message, if 0 never hide 297 * 298 * @return {undefined} 299 */ 300 close : function (elem, wait) { 301 // Unary Plus: +"2" === 2 302 var timer = (wait && !isNaN(wait)) ? +wait : this.delay, 303 self = this, 304 hideElement, transitionDone; 305 306 // set click event on log messages 307 this.bind(elem, "click", function () { 308 hideElement(elem); 309 }); 310 // Hide the dialog box after transition 311 // This ensure it doens't block any element from being clicked 312 transitionDone = function (event) { 313 event.stopPropagation(); 314 // unbind event so function only gets called once 315 self.unbind(this, self.transition.type, transitionDone); 316 // remove log message 317 elLog.removeChild(this);
318 if (!elLog.hasChildNodes()) elLog.className += " alertify-logs-hidden"; 319 }; 320 // this sets the hide class to transition out 321 // or removes the child if css transitions aren't supported 322 hideElement = function (el) { 323 // ensure element exists 324 if (typeof el !== "undefined" && el.parentNode === elLog) { 325 // whether CSS transition exists 326 if (self.transition.supported) { 327 self.bind(el, self.transition.type, transitionDone); 328 el.className += " alertify-log-hide"; 329 } else { 330 elLog.removeChild(el); 331 if (!elLog.hasChildNodes()) elLog.className += " alertify-logs-hidden"; 332 } 333 } 334 }; 335 // never close (until click) if wait is set to 0 336 if (wait === 0) return; 337 // set timeout to auto close the log message 338 setTimeout(function () { hideElement(elem); }, timer); 339 }, 340 341 /** 342 * Create a dialog box 343 * 344 * @param {String} message The message passed from the callee 345 * @param {String} type Type of dialog to create 346 * @param {Function} fn [Optional] Callback function 347 * @param {String} placeholder [Optional] Default value for prompt input field 348 * @param {String} cssClass [Optional] Class(es) to append to dialog box 349 * 350 * @return {Object} 351 */ 352 dialog : function (message, type, fn, placeholder, cssClass) { 353 // set the current active element 354 // this allows the keyboard focus to be resetted 355 // after the dialog box is closed 356 elCallee = document.activeElement; 357 // check to ensure the alertify dialog element 358 // has been successfully created 359 var check = function () { 360 if ((elLog && elLog.scrollTop !== null) && (elCover && elCover.scrollTop !== null)) return; 361 else check(); 362 }; 363 // error catching 364 if (typeof message !== "string") throw new Error("message must be a string"); 365 if (typeof type !== "string") throw new Error("type must be a string"); 366 if (typeof fn !== "undefined" && typeof fn !== "function") throw new Error("fn must be a function"); 367 // initialize alertify if it hasn't already been done 368 this.init(); 369 check(); 370 371 queue.push({ type: type, message: message, callback: fn, placeholder: placeholder, cssClass: cssClass }); 372 if (!isopen) this.setup(); 373 374 return this; 375 }, 376 377 /** 378 * Extend the log method to create custom methods 379 * 380 * @param {String} type Custom method name 381 * 382 * @return {Function} 383 */ 384 extend : function (type) { 385 if (typeof type !== "string") throw new Error("extend method must have exactly one paramter"); 386 return function (message, wait) { 387 this.log(message, type, wait); 388 return this; 389 }; 390 }, 391 392 /** 393 * Hide the dialog and rest to defaults 394 * 395 * @return {undefined} 396 */ 397 hide : function () { 398 var transitionDone, 399 self = this; 400 // remove reference from queue 401 queue.splice(0,1); 402 // if items remaining in the queue 403 if (queue.length > 0) this.setup(true); 404 else { 405 isopen = false; 406 // Hide the dialog box after transition 407 // This ensure it doens't block any element from being clicked 408 transitionDone = function (event) { 409 event.stopPropagation(); 410 // unbind event so function only gets called once 411 self.unbind(elDialog, self.transition.type, transitionDone); 412 }; 413 // whether CSS transition exists 414 if (this.transition.supported) { 415 this.bind(elDialog, this.transition.type, transitionDone); 416 elDialog.className = "alertify alertify-hide alertify-hidden"; 417 } else { 418 elDialog.className = "alertify alertify-hide alertify-hidden alertify-isHidden"; 419 } 420 elCover.className = "alertify-cover alertify-cover-hidden"; 421 // set focus to the last element or body 422 // after the dialog is closed 423 elCallee.focus(); 424 } 425 }, 426 427 /** 428 * Initialize Alertify 429 * Create the 2 main elements 430 * 431 * @return {undefined} 432 */ 433 init : function () { 434 // ensure legacy browsers support html5 tags 435 document.createElement("nav"); 436 document.createElement("article"); 437 document.createElement("section"); 438 // cover
439 if ($("alertify-cover") == null) { 440 elCover = document.createElement("div"); 441 elCover.setAttribute("id", "alertify-cover"); 442 elCover.className = "alertify-cover alertify-cover-hidden"; 443 document.body.appendChild(elCover); 444 } 445 // main element 446 if ($("alertify") == null) { 447 isopen = false; 448 queue = []; 449 elDialog = document.createElement("section"); 450 elDialog.setAttribute("id", "alertify"); 451 elDialog.className = "alertify alertify-hidden"; 452 document.body.appendChild(elDialog); 453 } 454 // log element 455 if ($("alertify-logs") == null) { 456 elLog = document.createElement("section"); 457 elLog.setAttribute("id", "alertify-logs"); 458 elLog.className = "alertify-logs alertify-logs-hidden"; 459 document.body.appendChild(elLog); 460 } 461 // set tabindex attribute on body element 462 // this allows script to give it focus 463 // after the dialog is closed 464 document.body.setAttribute("tabindex", "0"); 465 // set transition type 466 this.transition = getTransitionEvent(); 467 }, 468 469 /** 470 * Show a new log message box 471 * 472 * @param {String} message The message passed from the callee 473 * @param {String} type [Optional] Optional type of log message 474 * @param {Number} wait [Optional] Time (in ms) to wait before auto-hiding the log 475 * 476 * @return {Object} 477 */ 478 log : function (message, type, wait) { 479 // check to ensure the alertify dialog element 480 // has been successfully created 481 var check = function () { 482 if (elLog && elLog.scrollTop !== null) return; 483 else check(); 484 }; 485 // initialize alertify if it hasn't already been done 486 this.init(); 487 check(); 488 489 elLog.className = "alertify-logs"; 490 this.notify(message, type, wait); 491 return this; 492 }, 493 494 /** 495 * Add new log message 496 * If a type is passed, a class name "alertify-log-{type}" will get added. 497 * This allows for custom look and feel for various types of notifications. 498 * 499 * @param {String} message The message passed from the callee 500 * @param {String} type [Optional] Type of log message 501 * @param {Number} wait [Optional] Time (in ms) to wait before auto-hiding 502 * 503 * @return {undefined} 504 */ 505 notify : function (message, type, wait) { 506 var log = document.createElement("article"); 507 log.className = "alertify-log" + ((typeof type === "string" && type !== "") ? " alertify-log-" + type : ""); 508 log.innerHTML = message; 509 // append child 510 elLog.appendChild(log); 511 // triggers the CSS animation 512 setTimeout(function() { log.className = log.className + " alertify-log-show"; }, 50); 513 this.close(log, wait); 514 }, 515 516 /** 517 * Set properties 518 * 519 * @param {Object} args Passing parameters 520 * 521 * @return {undefined} 522 */ 523 set : function (args) { 524 var k; 525 // error catching 526 if (typeof args !== "object" && args instanceof Array) throw new Error("args must be an object"); 527 // set parameters 528 for (k in args) { 529 if (args.hasOwnProperty(k)) { 530 this[k] = args[k]; 531 } 532 } 533 }, 534 535 /** 536 * Common place to set focus to proper element 537 * 538 * @return {undefined} 539 */ 540 setFocus : function () { 541 if (input) { 542 input.focus(); 543 input.select(); 544 } 545 else btnFocus.focus(); 546 }, 547 548 /** 549 * Initiate all the required pieces for the dialog box 550 * 551 * @return {undefined} 552 */ 553 setup : function (fromQueue) { 554 var item = queue[0], 555 self = this, 556 transitionDone; 557 558 // dialog is open 559 isopen = true; 560 // Set button focus after transition 561 transitionDone = function (event) { 562 event.stopPropagation(); 563 self.setFocus(); 564 // unbind event so function only gets called once 565 self.unbind(elDialog, self.transition.type, transitionDone); 566 }; 567 // whether CSS transition exists 568 if (this.transition.supported && !fromQueue) { 569 this.bind(elDialog, this.transition.type, transitionDone); 570 } 571 // build the proper dialog HTML 572 elDialog.innerHTML = this.build(item); 573 // assign all the common elements 574 btnReset = $("alertify-resetFocus"); 575 btnResetBack = $("alertify-resetFocusBack"); 576 btnOK = $("alertify-ok") || undefined; 577 btnCancel = $("alertify-cancel") || undefined; 578 btnFocus = (_alertify.buttonFocus === "cancel") ? btnCancel : ((_alertify.buttonFocus === "none") ? $("alertify-noneFocus") : btnOK), 579 input = $("alertify-text") || undefined; 580 form = $("alertify-form") || undefined; 581 // add placeholder value to the input field 582 if (typeof item.placeholder === "string" && item.placeholder !== "") input.value = item.placeholder; 583 if (fromQueue) this.setFocus(); 584 this.addListeners(item.callback); 585 }, 586 587 /** 588 * Unbind events to elements 589 * 590 * @param {Object} el HTML Object 591 * @param {Event} event Event to detach to element 592 * @param {Function} fn Callback function 593 * 594 * @return {undefined} 595 */ 596 unbind : function (el, event, fn) { 597 if (typeof el.removeEventListener === "function") { 598 el.removeEventListener(event, fn, false); 599 } else if (el.detachEvent) { 600 el.detachEvent("on" + event, fn); 601 } 602 } 603 }; 604 605 return { 606 alert : function (message, fn, cssClass) { _alertify.dialog(message, "alert", fn, "", cssClass); return this; },
607 confirm : function (message, fn, cssClass) { _alertify.dialog(message, "confirm", fn, "", cssClass); return this; }, 608 extend : _alertify.extend, 609 init : _alertify.init, 610 log : function (message, type, wait) { _alertify.log(message, type, wait); return this; }, 611 prompt : function (message, fn, placeholder, cssClass) { _alertify.dialog(message, "prompt", fn, placeholder, cssClass); return this; }, 612 success : function (message, wait) { _alertify.log(message, "success", wait); return this; }, 613 error : function (message, wait) { _alertify.log(message, "error", wait); return this; }, 614 set : function (args) { _alertify.set(args); }, 615 labels : _alertify.labels, 616 debug : _alertify.handleErrors 617 }; 618 }; 619 620 // AMD and window support 621 if (typeof define === "function") { 622 define([], function () { return new Alertify(); }); 623 } else if (typeof global.alertify === "undefined") { 624 global.alertify = new Alertify(); 625 } 626 627}(this));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.