vendor: 5,420 bytes, lines 1-181
1/** 2 * AJAX Nette Framework plugin for jQuery 3 * 4 * @copyright Copyright (c) 2009, 2010 Jan Marek 5 * @copyright Copyright (c) 2009, 2010 David Grudl 6 * @copyright Copyright (c) 2012 VojtÄch DobeÅ¡ 7 * @license MIT 8 * 9 * @version 1.2.2 10 */ 11 12(function(window, $, undefined) { 13 14if (typeof $ !== 'function') { 15 return console.error('nette.ajax.js: jQuery is missing, load it please'); 16} 17 18var nette = function () { 19 var inner = { 20 self: this, 21 initialized: false, 22 contexts: {}, 23 on: { 24 init: {}, 25 load: {}, 26 prepare: {}, 27 before: {}, 28 start: {}, 29 success: {}, 30 complete: {}, 31 error: {} 32 }, 33 fire: function () { 34 var result = true; 35 var args = Array.prototype.slice.call(arguments); 36 var props = args.shift(); 37 var name = (typeof props === 'string') ? props : props.name; 38 var off = (typeof props === 'object') ? props.off || {} : {}; 39 args.push(inner.self); 40 $.each(inner.on[name], function (index, reaction) { 41 if (reaction === undefined || $.inArray(index, off) !== -1) return true; 42 var temp = reaction.apply(inner.contexts[index], args); 43 return result = (temp === undefined || temp); 44 }); 45 return result; 46 }, 47 requestHandler: function (e) { 48 var xhr = inner.self.ajax({}, this, e); 49 if (xhr && xhr._returnFalse) { // for IE 8 50 return false; 51 } 52 }, 53 ext: function (callbacks, context, name) { 54 while (!name) { 55 name = 'ext_' + Math.random(); 56 if (inner.contexts[name]) { 57 name = undefined; 58 } 59 } 60 61 $.each(callbacks, function (event, callback) { 62 inner.on[event][name] = callback; 63 }); 64 inner.contexts[name] = $.extend(context ? context : {}, { 65 name: function () { 66 return name; 67 }, 68 ext: function (name, force) { 69 var ext = inner.contexts[name]; 70 if (!ext && force) throw "Extension '" + this.name() + "' depends on disabled extension '" + name + "'."; 71 return ext; 72 } 73 }); 74 } 75 }; 76 77 /** 78 * Allows manipulation with extensions. 79 * When called with 1. argument only, it returns extension with given name. 80 * When called with 2. argument equal to false, it removes extension entirely. 81 * When called with 2. argument equal to hash of event callbacks, it adds new extension. 82 * 83 * @param {string} Name of extension 84 * @param {bool|object|null} Set of callbacks for any events OR false for removing extension. 85 * @param {object|null} Context for added extension 86 * @return {$.nette|object} Provides a fluent interface OR returns extensions with given name 87 */ 88 this.ext = function (name, callbacks, context) { 89 if (typeof name === 'object') { 90 inner.ext(name, callbacks); 91 } else if (callbacks === undefined) { 92 return inner.contexts[name]; 93 } else if (!callbacks) { 94 $.each(['init', 'load', 'prepare', 'before', 'start', 'success', 'complete', 'error'], function (index, event) { 95 inner.on[event][name] = undefined; 96 }); 97 inner.contexts[name] = undefined; 98 } else if (typeof name === 'string' && inner.contexts[name] !== undefined) { 99 throw "Cannot override already registered nette-ajax extension '" + name + "'."; 100 } else { 101 inner.ext(callbacks, context, name); 102 } 103 return this; 104 }; 105 106 /** 107 * Initializes the plugin: 108 * - fires 'init' event, then 'load' event 109 * - when called with any arguments, it will override default 'init' extension 110 * with provided callbacks 111 * 112 * @param {function|object|null} Callback for 'load' event or entire set of callbacks for any events 113 * @param {object|null} Context provided for callbacks in first argument 114 * @return {$.nette} Provides a fluent interface 115 */ 116 this.init = function (load, loadContext) { 117 if (inner.initialized) throw 'Cannot initialize nette-ajax twice.'; 118 119 if (typeof load === 'function') { 120 this.ext('init', null); 121 this.ext('init', { 122 load: load 123 }, loadContext); 124 } else if (typeof load === 'object') { 125 this.ext('init', null); 126 this.ext('init', load, loadContext); 127 } else if (load !== undefined) { 128 throw 'Argument of init() can be function or function-hash only.'; 129 } 130 131 inner.initialized = true; 132 133 inner.fire('init'); 134 this.load(); 135 return this; 136 }; 137 138 /** 139 * Fires 'load' event 140 * 141 * @return {$.nette} Provides a fluent interface 142 */ 143 this.load = function () { 144 inner.fire('load', inner.requestHandler); 145 return this; 146 }; 147 148 /** 149 * Executes AJAX request. Attaches listeners and events. 150 * 151 * @param {object} settings 152 * @param {Element|null} ussually Anchor or Form 153 * @param {event|null} event causing the request 154 * @return {jqXHR|null} 155 */ 156 this.ajax = function (settings, ui, e) { 157 if (!settings.nette && ui && e) { 158 var $el = $(ui), xhr, originalBeforeSend; 159 var analyze = settings.nette = { 160 e: e, 161 ui: ui, 162 el: $el, 163 isForm: $el.is('form'), 164 isSubmit: $el.is('input[type=submit]') || $el.is('button[type=submit]'), 165 isImage: $el.is('input[type=image]'), 166 form: null 167 }; 168 169 if (analyze.isSubmit || analyze.isImage) { 170 analyze.form = analyze.el.closest('form'); 171 } else if (analyze.isForm) { 172 analyze.form = analyze.el; 173 } 174 175 if (!settings.url) { 176 settings.url = analyze.form ? analyze.form.attr('action') : ui.href; 177 } 178 if (!settings.type) { 179 settings.type = analyze.form ? analyze.form.attr('method') : 'get'; 180 } 181
182 if ($el.is('[data-ajax-off]')) { 183 var rawOff = $el.attr('data-ajax-off'); 184 if (rawOff.indexOf('[') === 0) { 185 settings.off = $el.data('ajaxOff'); 186 } else if (rawOff.indexOf(',') !== -1) { 187 settings.off = rawOff.split(','); 188 } else if (rawOff.indexOf(' ') !== -1) { 189 settings.off = rawOff.split(' '); 190 } else { 191 settings.off = rawOff; 192 } 193 if (typeof settings.off === 'string') settings.off = [settings.off]; 194 settings.off = $.grep($.each(settings.off, function (off) { 195 return $.trim(off); 196 }), function (off) { 197 return off.length; 198 }); 199 } 200 } 201 202 inner.fire({ 203 name: 'prepare', 204 off: settings.off || {} 205 }, settings); 206 if (settings.prepare) { 207 settings.prepare(settings); 208 } 209 210 originalBeforeSend = settings.beforeSend; 211 settings.beforeSend = function (xhr, settings) { 212 var result = inner.fire({ 213 name: 'before', 214 off: settings.off || {} 215 }, xhr, settings); 216 if ((result || result === undefined) && originalBeforeSend) { 217 result = originalBeforeSend(xhr, settings); 218 } 219 return result; 220 }; 221 222 return this.handleXHR($.ajax(settings), settings); 223 }; 224 225 /** 226 * Binds extension callbacks to existing XHR object 227 * 228 * @param {jqXHR|null} 229 * @param {object} settings 230 * @return {jqXHR|null} 231 */ 232 this.handleXHR = function (xhr, settings) { 233 settings = settings || {}; 234 235 if (xhr && (typeof xhr.statusText === 'undefined' || xhr.statusText !== 'canceled')) { 236 xhr.done(function (payload, status, xhr) { 237 inner.fire({ 238 name: 'success', 239 off: settings.off || {} 240 }, payload, status, xhr, settings); 241 }).fail(function (xhr, status, error) { 242 inner.fire({ 243 name: 'error', 244 off: settings.off || {} 245 }, xhr, status, error, settings); 246 }).always(function (xhr, status) { 247 inner.fire({ 248 name: 'complete', 249 off: settings.off || {} 250 }, xhr, status, settings); 251 }); 252 inner.fire({ 253 name: 'start', 254 off: settings.off || {} 255 }, xhr, settings); 256 if (settings.start) { 257 settings.start(xhr, settings); 258 } 259 } 260 return xhr; 261 }; 262}; 263 264$.nette = new ($.extend(nette, $.nette ? $.nette : {})); 265 266$.fn.netteAjax = function (e, options) { 267 return $.nette.ajax(options || {}, this[0], e); 268}; 269 270$.fn.netteAjaxOff = function () { 271 return this.off('.nette'); 272}; 273 274$.nette.ext('validation', { 275 before: function (xhr, settings) { 276 if (!settings.nette) return true; 277 else var analyze = settings.nette; 278 var e = analyze.e; 279 280 var validate = $.extend({ 281 keys: true, 282 url: true, 283 form: true 284 }, settings.validate || (function () { 285 if (!analyze.el.is('[data-ajax-validate]')) return; 286 var attr = analyze.el.data('ajaxValidate'); 287 if (attr === false) return { 288 keys: false, 289 url: false, 290 form: false 291 }; else if (typeof attr === 'object') return attr; 292 })() || {}); 293 294 var passEvent = false; 295 if (analyze.el.attr('data-ajax-pass') !== undefined) { 296 passEvent = analyze.el.data('ajaxPass'); 297 passEvent = typeof passEvent === 'bool' ? passEvent : true; 298 } 299 300 if (validate.keys) { 301 // thx to @vrana 302 var explicitNoAjax = e.button || e.ctrlKey || e.shiftKey || e.altKey || e.metaKey; 303 304 if (analyze.form) { 305 if (explicitNoAjax && analyze.isSubmit) { 306 this.explicitNoAjax = true; 307 return false; 308 } else if (analyze.isForm && this.explicitNoAjax) { 309 this.explicitNoAjax = false; 310 return false; 311 } 312 } else if (explicitNoAjax) return false; 313 } 314 315 if (validate.form && analyze.form && !((analyze.isSubmit || analyze.isImage) && analyze.el.attr('formnovalidate') !== undefined)) { 316 var ie = this.ie(); 317 if (analyze.form.get(0).onsubmit && analyze.form.get(0).onsubmit((typeof ie !== 'undefined' && ie < 9) ? undefined : e) === false) { 318 e.stopImmediatePropagation(); 319 e.preventDefault(); 320 return false; 321 } 322 } 323 324 if (validate.url) { 325 // thx to @vrana 326 if (/:|^#/.test(analyze.form ? settings.url : analyze.el.attr('href'))) return false; 327 } 328 329 if (!passEvent) { 330 e.stopPropagation(); 331 e.preventDefault(); 332 xhr._returnFalse = true; // for IE 8 333 } 334 return true; 335 } 336}, { 337 explicitNoAjax: false, 338 ie: function (undefined) { // http://james.padolsey.com/javascript/detect-ie-in-js-using-conditional-comments/ 339 var v = 3; 340 var div = document.createElement('div'); 341 var all = div.getElementsByTagName('i'); 342 while ( 343 div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->', 344 all[0] 345 ); 346 return v > 4 ? v : undefined; 347 } 348}); 349 350$.nette.ext('forms', { 351 init: function () { 352 var snippets; 353 if (!window.Nette || !(snippets = this.ext('snippets'))) return; 354 355 snippets.after(function ($el) { 356 $el.find('form').each(function() { 357 window.Nette.initForm(this); 358 }); 359 }); 360 }, 361 prepare: function (settings) { 362 var analyze = settings.nette; 363 if (!analyze || !analyze.form) return; 364 var e = analyze.e; 365 var originalData = settings.data || {}; 366 var formData = {}; 367 368 if (analyze.isSubmit) {
vendor: 4,137 bytes, lines 369-526
369 formData[analyze.el.attr('name')] = analyze.el.val() || ''; 370 } else if (analyze.isImage) { 371 var offset = analyze.el.offset(); 372 var name = analyze.el.attr('name'); 373 var dataOffset = [ Math.max(0, e.pageX - offset.left), Math.max(0, e.pageY - offset.top) ]; 374 375 if (name.indexOf('[', 0) !== -1) { // inside a container 376 formData[name] = dataOffset; 377 } else { 378 formData[name + '.x'] = dataOffset[0]; 379 formData[name + '.y'] = dataOffset[1]; 380 } 381 } 382 383 if (typeof originalData !== 'string') { 384 originalData = $.param(originalData); 385 } 386 formData = $.param(formData); 387 settings.data = analyze.form.serialize() + (formData ? '&' + formData : '') + '&' + originalData; 388 } 389}); 390 391// default snippet handler 392$.nette.ext('snippets', { 393 success: function (payload) { 394 if (payload.snippets) { 395 this.updateSnippets(payload.snippets); 396 } 397 } 398}, { 399 beforeQueue: $.Callbacks(), 400 afterQueue: $.Callbacks(), 401 completeQueue: $.Callbacks(), 402 before: function (callback) { 403 this.beforeQueue.add(callback); 404 }, 405 after: function (callback) { 406 this.afterQueue.add(callback); 407 }, 408 complete: function (callback) { 409 this.completeQueue.add(callback); 410 }, 411 updateSnippets: function (snippets, back) { 412 var that = this; 413 var elements = []; 414 for (var i in snippets) { 415 var $el = this.getElement(i); 416 if ($el.get(0)) { 417 elements.push($el.get(0)); 418 } 419 this.updateSnippet($el, snippets[i], back); 420 } 421 $(elements).promise().done(function () { 422 that.completeQueue.fire(); 423 }); 424 }, 425 updateSnippet: function ($el, html, back) { 426 // Fix for setting document title in IE 427 if ($el.is('title')) { 428 document.title = html; 429 } else { 430 this.beforeQueue.fire($el); 431 this.applySnippet($el, html, back); 432 this.afterQueue.fire($el); 433 } 434 }, 435 getElement: function (id) { 436 return $('#' + this.escapeSelector(id)); 437 }, 438 applySnippet: function ($el, html, back) { 439 if (!back && $el.is('[data-ajax-append]')) { 440 $el.append(html); 441 } else if (!back && $el.is('[data-ajax-prepend]')) { 442 $el.prepend(html); 443 } else { 444 $el.html(html); 445 } 446 }, 447 escapeSelector: function (selector) { 448 // thx to @uestla (https://github.com/uestla) 449 return selector.replace(/[\!"#\$%&'\(\)\*\+,\.\/:;<=>\?@\[\\\]\^`\{\|\}~]/g, '\\$&'); 450 } 451}); 452 453// support $this->redirect() 454$.nette.ext('redirect', { 455 success: function (payload) { 456 if (payload.redirect) { 457 window.location.href = payload.redirect; 458 return false; 459 } 460 } 461}); 462 463// current page state 464$.nette.ext('state', { 465 success: function (payload) { 466 if (payload.state) { 467 this.state = payload.state; 468 } 469 } 470}, {state: null}); 471 472// abort last request if new started 473$.nette.ext('unique', { 474 start: function (xhr) { 475 if (this.xhr) { 476 this.xhr.abort(); 477 } 478 this.xhr = xhr; 479 }, 480 complete: function () { 481 this.xhr = null; 482 } 483}, {xhr: null}); 484 485// option to abort by ESC (thx to @vrana) 486$.nette.ext('abort', { 487 init: function () { 488 $('body').keydown($.proxy(function (e) { 489 if (this.xhr && (e.keyCode.toString() === '27' // Esc 490 && !(e.ctrlKey || e.shiftKey || e.altKey || e.metaKey)) 491 ) { 492 this.xhr.abort(); 493 } 494 }, this)); 495 }, 496 start: function (xhr) { 497 this.xhr = xhr; 498 }, 499 complete: function () { 500 this.xhr = null; 501 } 502}, {xhr: null}); 503 504$.nette.ext('load', { 505 success: function () { 506 $.nette.load(); 507 } 508}); 509 510// default ajaxification (can be overridden in init()) 511$.nette.ext('init', { 512 load: function (rh) { 513 $(this.linkSelector).off('click.nette', rh).on('click.nette', rh); 514 $(this.formSelector).off('submit.nette', rh).on('submit.nette', rh) 515 .off('click.nette', ':image', rh).on('click.nette', ':image', rh) 516 .off('click.nette', ':submit', rh).on('click.nette', ':submit', rh); 517 $(this.buttonSelector).closest('form') 518 .off('click.nette', this.buttonSelector, rh).on('click.nette', this.buttonSelector, rh); 519 } 520}, { 521 linkSelector: 'a.ajax', 522 formSelector: 'form.ajax', 523 buttonSelector: 'input.ajax[type="submit"], button.ajax[type="submit"], input.ajax[type="image"]' 524}); 525 526})(window, window.jQuery);
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.