vendor: 15,586 bytes, lines 1-566
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-2014 VojtÄch DobeÅ¡ 7 * @license MIT 8 * 9 * @version 2.3.0 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|string} settings or URL 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 ($.type(settings) === 'string') { 158 settings = {url: settings}; 159 } 160 if (!settings.nette && ui && e) { 161 var $el = $(ui), xhr, originalBeforeSend; 162 var analyze = settings.nette = { 163 e: e, 164 ui: ui, 165 el: $el, 166 isForm: $el.is('form'), 167 isSubmit: $el.is('input[type=submit]') || $el.is('button[type=submit]'), 168 isImage: $el.is('input[type=image]'), 169 form: null 170 }; 171 172 if (analyze.isSubmit || analyze.isImage) { 173 analyze.form = analyze.el.closest('form'); 174 } else if (analyze.isForm) { 175 analyze.form = analyze.el; 176 } 177 178 if (!settings.url) { 179 settings.url = analyze.form ? analyze.form.attr('action') || window.location.pathname + window.location.search : ui.href; 180 } 181 if (!settings.type) { 182 settings.type = analyze.form ? analyze.form.attr('method') : 'get'; 183 } 184 185 if ($el.is('[data-ajax-off]')) { 186 var rawOff = $el.attr('data-ajax-off'); 187 if (rawOff.indexOf('[') === 0) { 188 settings.off = $el.data('ajaxOff'); 189 } else if (rawOff.indexOf(',') !== -1) { 190 settings.off = rawOff.split(','); 191 } else if (rawOff.indexOf(' ') !== -1) { 192 settings.off = rawOff.split(' '); 193 } else { 194 settings.off = rawOff; 195 } 196 if (typeof settings.off === 'string') settings.off = [settings.off]; 197 settings.off = $.grep($.each(settings.off, function (off) { 198 return $.trim(off); 199 }), function (off) { 200 return off.length; 201 }); 202 } 203 } 204 205 inner.fire({ 206 name: 'prepare', 207 off: settings.off || {} 208 }, settings); 209 if (settings.prepare) { 210 settings.prepare(settings); 211 } 212 213 originalBeforeSend = settings.beforeSend; 214 settings.beforeSend = function (xhr, settings) { 215 var result = inner.fire({ 216 name: 'before', 217 off: settings.off || {} 218 }, xhr, settings); 219 if ((result || result === undefined) && originalBeforeSend) { 220 result = originalBeforeSend(xhr, settings); 221 } 222 return result; 223 }; 224 225 return this.handleXHR($.ajax(settings), settings); 226 }; 227 228 /** 229 * Binds extension callbacks to existing XHR object 230 * 231 * @param {jqXHR|null} 232 * @param {object} settings 233 * @return {jqXHR|null} 234 */ 235 this.handleXHR = function (xhr, settings) { 236 settings = settings || {}; 237 238 if (xhr && (typeof xhr.statusText === 'undefined' || xhr.statusText !== 'canceled')) { 239 xhr.done(function (payload, status, xhr) { 240 inner.fire({ 241 name: 'success', 242 off: settings.off || {} 243 }, payload, status, xhr, settings); 244 }).fail(function (xhr, status, error) { 245 inner.fire({ 246 name: 'error', 247 off: settings.off || {} 248 }, xhr, status, error, settings); 249 }).always(function (xhr, status) { 250 inner.fire({ 251 name: 'complete', 252 off: settings.off || {} 253 }, xhr, status, settings); 254 }); 255 inner.fire({ 256 name: 'start', 257 off: settings.off || {} 258 }, xhr, settings); 259 if (settings.start) { 260 settings.start(xhr, settings); 261 } 262 } 263 return xhr; 264 }; 265}; 266 267$.nette = new ($.extend(nette, $.nette ? $.nette : {})); 268 269$.fn.netteAjax = function (e, options) { 270 return $.nette.ajax(options || {}, this[0], e); 271}; 272 273$.fn.netteAjaxOff = function () { 274 return this.off('.nette'); 275}; 276 277$.nette.ext('validation', { 278 before: function (xhr, settings) { 279 if (!settings.nette) return true; 280 else var analyze = settings.nette; 281 var e = analyze.e; 282 283 var validate = $.extend(this.defaults, settings.validate || (function () { 284 if (!analyze.el.is('[data-ajax-validate]')) return; 285 var attr = analyze.el.data('ajaxValidate'); 286 if (attr === false) return { 287 keys: false, 288 url: false, 289 form: false 290 }; else if (typeof attr === 'object') return attr; 291 })() || {}); 292 293 var passEvent = false; 294 if (analyze.el.attr('data-ajax-pass') !== undefined) { 295 passEvent = analyze.el.data('ajaxPass'); 296 passEvent = typeof passEvent === 'bool' ? passEvent : true; 297 } 298 299 if (validate.keys) { 300 // thx to @vrana 301 var explicitNoAjax = e.button || e.ctrlKey || e.shiftKey || e.altKey || e.metaKey; 302 303 if (analyze.form) { 304 if (explicitNoAjax && analyze.isSubmit) { 305 this.explicitNoAjax = true; 306 return false; 307 } else if (analyze.isForm && this.explicitNoAjax) { 308 this.explicitNoAjax = false; 309 return false; 310 } 311 } else if (explicitNoAjax) return false; 312 } 313 314 if (validate.form && analyze.form) { 315 if (analyze.isSubmit || analyze.isImage) { 316 analyze.form.get(0)["nette-submittedBy"] = analyze.el.get(0); 317 } 318 var notValid; 319 if ((typeof Nette.version === 'undefined' || Nette.version == '2.3')) { // Nette 2.3 and older 320 var ie = this.ie(); 321 notValid = (analyze.form.get(0).onsubmit && analyze.form.get(0).onsubmit((typeof ie !== 'undefined' && ie < 9) ? undefined : e) === false); 322 } else { // Nette 2.4 and up 323 notValid = ((analyze.form.get(0).onsubmit ? analyze.form.triggerHandler('submit') : Nette.validateForm(analyze.form.get(0))) === false) 324 } 325 if (notValid) { 326 e.stopImmediatePropagation(); 327 e.preventDefault(); 328 return false; 329 } 330 } 331 332 if (validate.url) { 333 // thx to @vrana 334 var urlToValidate = analyze.form ? settings.url : analyze.el.attr('href'); 335 // Check if URL is absolute 336 if (/(?:^[a-z][a-z0-9+.-]*:|\/\/)/.test(urlToValidate)) { 337 // Parse absolute URL 338 var parsedUrl = new URL(urlToValidate); 339 if (/:|^#/.test(parsedUrl['pathname'] + parsedUrl['search'] + parsedUrl['hash'])) return false; 340 } else { 341 if (/:|^#/.test(urlToValidate)) return false; 342 } 343 } 344 345 if (!passEvent) { 346 e.stopPropagation(); 347 e.preventDefault(); 348 xhr._returnFalse = true; // for IE 8 349 } 350 return true; 351 } 352}, { 353 defaults: { 354 keys: true, 355 url: true, 356 form: true 357 }, 358 explicitNoAjax: false, 359 ie: function (undefined) { // http://james.padolsey.com/javascript/detect-ie-in-js-using-conditional-comments/ 360 var v = 3; 361 var div = document.createElement('div'); 362 var all = div.getElementsByTagName('i'); 363 while ( 364 div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->', 365 all[0] 366 ); 367 return v > 4 ? v : undefined; 368 } 369}); 370 371$.nette.ext('forms', { 372 init: function () { 373 var snippets; 374 if (!window.Nette || !(snippets = this.ext('snippets'))) return; 375 376 snippets.after(function ($el) { 377 $el.find('form').each(function() { 378 window.Nette.initForm(this); 379 }); 380 }); 381 }, 382 prepare: function (settings) { 383 var analyze = settings.nette; 384 if (!analyze || !analyze.form) return; 385 var e = analyze.e; 386 var originalData = settings.data || {}; 387 var data = {}; 388 389 if (analyze.isSubmit) { 390 data[analyze.el.attr('name')] = analyze.el.val() || ''; 391 } else if (analyze.isImage) { 392 var offset = analyze.el.offset(); 393 var name = analyze.el.attr('name'); 394 var dataOffset = [ Math.max(0, e.pageX - offset.left), Math.max(0, e.pageY - offset.top) ]; 395 396 if (name.indexOf('[', 0) !== -1) { // inside a container 397 data[name] = dataOffset; 398 } else { 399 data[name + '.x'] = dataOffset[0]; 400 data[name + '.y'] = dataOffset[1]; 401 } 402 } 403 404 // https://developer.mozilla.org/en-US/docs/Web/Guide/Using_FormData_Objects#Sending_files_using_a_FormData_object 405 var formMethod = analyze.form.attr('method'); 406 if (formMethod && formMethod.toLowerCase() === 'post' && 'FormData' in window) { 407 var formData = new FormData(analyze.form[0]); 408 for (var i in data) { 409 formData.append(i, data[i]); 410 } 411 412 if (typeof originalData !== 'string') { 413 for (var i in originalData) { 414 formData.append(i, originalData[i]); 415 } 416 } 417 418 settings.data = formData; 419 settings.processData = false; 420 settings.contentType = false; 421 } else { 422 if (typeof originalData !== 'string') { 423 originalData = $.param(originalData); 424 } 425 data = $.param(data); 426 settings.data = analyze.form.serialize() + (data ? '&' + data : '') + '&' + originalData; 427 } 428 } 429}); 430 431// default snippet handler 432$.nette.ext('snippets', { 433 success: function (payload) { 434 if (payload.snippets) { 435 this.updateSnippets(payload.snippets); 436 } 437 } 438}, { 439 beforeQueue: $.Callbacks(), 440 afterQueue: $.Callbacks(), 441 completeQueue: $.Callbacks(), 442 before: function (callback) { 443 this.beforeQueue.add(callback); 444 }, 445 after: function (callback) { 446 this.afterQueue.add(callback); 447 }, 448 complete: function (callback) { 449 this.completeQueue.add(callback); 450 }, 451 updateSnippets: function (snippets, back) { 452 var that = this; 453 var elements = []; 454 for (var i in snippets) { 455 var $el = this.getElement(i); 456 if ($el.get(0)) { 457 elements.push($el.get(0)); 458 } 459 this.updateSnippet($el, snippets[i], back); 460 } 461 $(elements).promise().done(function () { 462 that.completeQueue.fire(); 463 }); 464 }, 465 updateSnippet: function ($el, html, back) { 466 // Fix for setting document title in IE 467 if ($el.is('title')) { 468 document.title = html; 469 } else { 470 this.beforeQueue.fire($el); 471 this.applySnippet($el, html, back); 472 this.afterQueue.fire($el); 473 } 474 }, 475 getElement: function (id) { 476 return $('#' + this.escapeSelector(id)); 477 }, 478 applySnippet: function ($el, html, back) { 479 if (!back && $el.is('[data-ajax-append]')) { 480 $el.append(html); 481 } else if (!back && $el.is('[data-ajax-prepend]')) { 482 $el.prepend(html); 483 } else if ($el.html() != html || /<[^>]*script/.test(html)) { 484 $el.html(html); 485 } 486 }, 487 escapeSelector: function (selector) { 488 // thx to @uestla (https://github.com/uestla) 489 return selector.replace(/[\!"#\$%&'\(\)\*\+,\.\/:;<=>\?@\[\\\]\^`\{\|\}~]/g, '\\$&'); 490 } 491}); 492 493// support $this->redirect() 494$.nette.ext('redirect', { 495 success: function (payload) { 496 if (payload.redirect) { 497 window.location.href = payload.redirect; 498 return false; 499 } 500 } 501}); 502 503// current page state 504$.nette.ext('state', { 505 success: function (payload) { 506 if (payload.state) { 507 this.state = payload.state; 508 } 509 } 510}, {state: null}); 511 512// abort last request if new started 513$.nette.ext('unique', { 514 start: function (xhr) { 515 if (this.xhr) { 516 this.xhr.abort(); 517 } 518 this.xhr = xhr; 519 }, 520 complete: function () { 521 this.xhr = null; 522 } 523}, {xhr: null}); 524 525// option to abort by ESC (thx to @vrana) 526$.nette.ext('abort', { 527 init: function () { 528 $('body').keydown($.proxy(function (e) { 529 if (this.xhr && (e.keyCode.toString() === '27' // Esc 530 && !(e.ctrlKey || e.shiftKey || e.altKey || e.metaKey)) 531 ) { 532 this.xhr.abort(); 533 } 534 }, this)); 535 }, 536 start: function (xhr) { 537 this.xhr = xhr; 538 }, 539 complete: function () { 540 this.xhr = null; 541 } 542}, {xhr: null}); 543 544$.nette.ext('load', { 545 success: function () { 546 $.nette.load(); 547 } 548}); 549 550// default ajaxification (can be overridden in init()) 551$.nette.ext('init', { 552 load: function (rh) { 553 $(this.linkSelector).off('click.nette', rh).on('click.nette', rh); 554 $(this.formSelector).off('submit.nette', rh).on('submit.nette', rh) 555 .off('click.nette', ':image', rh).on('click.nette', ':image', rh) 556 .off('click.nette', ':submit', rh).on('click.nette', ':submit', rh); 557 $(this.buttonSelector).closest('form') 558 .off('click.nette', this.buttonSelector, rh).on('click.nette', this.buttonSelector, rh); 559 } 560}, { 561 linkSelector: 'a.ajax', 562 formSelector: 'form.ajax', 563 buttonSelector: 'input.ajax[type="submit"], button.ajax[type="submit"], input.ajax[type="image"]' 564}); 565 566})(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.