1 2/** 3 * Cookie plugin 1.0 4 * 5 * Copyright (c) 2006 Klaus Hartl (stilbuero.de) 6 * Dual licensed under the MIT and GPL licenses: 7 * http://www.opensource.org/licenses/mit-license.php 8 * http://www.gnu.org/licenses/gpl.html 9 * 10 */ 11jQuery.cookie=function(b,j,m){if(typeof j!="undefined"){m=m||{};if(j===null){j="";m.expires=-1}var e="";if(m.expires&&(typeof m.expires=="number"||m.expires.toUTCString)){var f;if(typeof m.expires=="number"){f=new Date();f.setTime(f.getTime()+(m.expires*24*60*60*1000))}else{f=m.expires}e="; expires="+f.toUTCString()}var l=m.path?"; path="+(m.path):"";var g=m.domain?"; domain="+(m.domain):"";var a=m.secure?"; secure":"";document.cookie=[b,"=",encodeURIComponent(j),e,l,g,a].join("")}else{var d=null;if(document.cookie&&document.cookie!=""){var k=document.cookie.split(";");for(var h=0;h<k.length;h++){var c=jQuery.trim(k[h]);if(c.substring(0,b.length+1)==(b+"=")){d=decodeURIComponent(c.substring(b.length+1));break}}}return d}}; 12; 13/*! 14 * jQuery Form Plugin 15 * version: 3.09 (16-APR-2012) 16 * @requires jQuery v1.3.2 or later 17 * 18 * Examples and documentation at: http://malsup.com/jquery/form/ 19 * Project repository: https://github.com/malsup/form 20 * Dual licensed under the MIT and GPL licenses: 21 * http://malsup.github.com/mit-license.txt 22 * http://malsup.github.com/gpl-license-v2.txt 23 */ 24/*global ActiveXObject alert */ 25;(function($) { 26"use strict"; 27 28/* 29 Usage Note: 30 ----------- 31 Do not use both ajaxSubmit and ajaxForm on the same form. These 32 functions are mutually exclusive. Use ajaxSubmit if you want 33 to bind your own submit handler to the form. For example, 34 35 $(document).ready(function() { 36 $('#myForm').on('submit', function(e) { 37 e.preventDefault(); // <-- important 38 $(this).ajaxSubmit({ 39 target: '#output' 40 }); 41 }); 42 }); 43 44 Use ajaxForm when you want the plugin to manage all the event binding 45 for you. For example, 46 47 $(document).ready(function() { 48 $('#myForm').ajaxForm({ 49 target: '#output' 50 }); 51 }); 52 53 You can also use ajaxForm with delegation (requires jQuery v1.7+), so the 54 form does not have to exist when you invoke ajaxForm: 55 56 $('#myForm').ajaxForm({ 57 delegation: true, 58 target: '#output' 59 }); 60 61 When using ajaxForm, the ajaxSubmit function will be invoked for you 62 at the appropriate time. 63*/ 64 65/** 66 * Feature detection 67 */ 68var feature = {}; 69feature.fileapi = $("<input type='file'/>").get(0).files !== undefined; 70feature.formdata = window.FormData !== undefined; 71 72/** 73 * ajaxSubmit() provides a mechanism for immediately submitting 74 * an HTML form using AJAX. 75 */ 76$.fn.ajaxSubmit = function(options) { 77 /*jshint scripturl:true */ 78 79 // fast fail if nothing selected (http://dev.jquery.com/ticket/2752) 80 if (!this.length) { 81 log('ajaxSubmit: skipping submit process - no element selected'); 82 return this; 83 } 84 85 var method, action, url, $form = this; 86 87 if (typeof options == 'function') { 88 options = { success: options }; 89 } 90 91 method = this.attr('method'); 92 action = this.attr('action'); 93 url = (typeof action === 'string') ? $.trim(action) : ''; 94 url = url || window.location.href || ''; 95 if (url) { 96 // clean url (don't include hash vaue) 97 url = (url.match(/^([^#]+)/)||[])[1]; 98 } 99 100 options = $.extend(true, { 101 url: url, 102 success: $.ajaxSettings.success, 103 type: method || 'GET', 104 iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' 105 }, options); 106 107 // hook for manipulating the form data before it is extracted; 108 // convenient for use with rich editors like tinyMCE or FCKEditor 109 var veto = {}; 110 this.trigger('form-pre-serialize', [this, options, veto]); 111 if (veto.veto) { 112 log('ajaxSubmit: submit vetoed via form-pre-serialize trigger'); 113 return this; 114 } 115 116 // provide opportunity to alter form data before it is serialized 117 if (options.beforeSerialize && options.beforeSerialize(this, options) === false) { 118 log('ajaxSubmit: submit aborted via beforeSerialize callback'); 119 return this; 120 } 121 122 var traditional = options.traditional; 123 if ( traditional === undefined ) { 124 traditional = $.ajaxSettings.traditional; 125 } 126 127 var elements = []; 128 var qx, a = this.formToArray(options.semantic, elements); 129 if (options.data) { 130 options.extraData = options.data; 131 qx = $.param(options.data, traditional); 132 } 133 134 // give pre-submit callback an opportunity to abort the submit 135 if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) { 136 log('ajaxSubmit: submit aborted via beforeSubmit callback'); 137 return this; 138 } 139 140 // fire vetoable 'validate' event 141 this.trigger('form-submit-validate', [a, this, options, veto]); 142 if (veto.veto) { 143 log('ajaxSubmit: submit vetoed via form-submit-validate trigger'); 144 return this; 145 } 146 147 var q = $.param(a, traditional); 148 if (qx) { 149 q = ( q ? (q + '&' + qx) : qx ); 150 } 151 if (options.type.toUpperCase() == 'GET') { 152 options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q; 153 options.data = null; // data is null for 'get' 154 } 155 else { 156 options.data = q; // data is the query string for 'post' 157 } 158 159 var callbacks = []; 160 if (options.resetForm) { 161 callbacks.push(function() { $form.resetForm(); }); 162 } 163 if (options.clearForm) { 164 callbacks.push(function() { $form.clearForm(options.includeHidden); }); 165 } 166 167 // perform a load on the target only if dataType is not provided 168 if (!options.dataType && options.target) { 169 var oldSuccess = options.success || function(){}; 170 callbacks.push(function(data) { 171 var fn = options.replaceTarget ? 'replaceWith' : 'html'; 172 $(options.target)[fn](data).each(oldSuccess, arguments); 173 }); 174 } 175 else if (options.success) { 176 callbacks.push(options.success); 177 } 178 179 options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg 180 var context = options.context || options; // jQuery 1.4+ supports scope context 181 for (var i=0, max=callbacks.length; i < max; i++) { 182 callbacks[i].apply(context, [data, status, xhr || $form, $form]); 183 } 184 }; 185 186 // are there files to upload? 187 var fileInputs = $('input:file:enabled[value]', this); // [value] (issue #113) 188 var hasFileInputs = fileInputs.length > 0; 189 var mp = 'multipart/form-data'; 190 var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp); 191 192 var fileAPI = feature.fileapi && feature.formdata; 193 log("fileAPI :" + fileAPI); 194 var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI; 195 196 // options.iframe allows user to force iframe mode 197 // 06-NOV-09: now defaulting to iframe mode if file input is detected 198 if (options.iframe !== false && (options.iframe || shouldUseFrame)) { 199 // hack to fix Safari hang (thanks to Tim Molendijk for this) 200 // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d 201 if (options.closeKeepAlive) { 202 $.get(options.closeKeepAlive, function() { 203 fileUploadIframe(a); 204 }); 205 } 206 else { 207 fileUploadIframe(a); 208 } 209 } 210 else if ((hasFileInputs || multipart) && fileAPI) { 211 fileUploadXhr(a); 212 } 213 else { 214 $.ajax(options); 215 } 216 217 // clear element array 218 for (var k=0; k < elements.length; k++) 219 elements[k] = null; 220 221 // fire 'notify' event 222 this.trigger('form-submit-notify', [this, options]); 223 return this; 224 225 // This is a utility function to fix deep serialization issues when doing file uploads 226 // eg params show up as "[object Object]" rather than what it should be 227 function formDeepSerialize(extraData){ 228 var serialized = $.param(extraData).replace(/\+/g, '%20').split('&'); 229 var result = {}; 230 var n; 231 for(var i=0, l=serialized.length; i < l; i++){ 232 n = serialized[i].split('=')
233 result[decodeURIComponent(n[0])] = decodeURIComponent(n[1]) 234 } 235 return result; 236 } 237 238 // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz) 239 function fileUploadXhr(a) { 240 var formdata = new FormData(); 241 242 for (var i=0; i < a.length; i++) { 243 formdata.append(a[i].name, a[i].value); 244 } 245 246 if (options.extraData) { 247 var serializedData = formDeepSerialize(options.extraData); 248 for (var p in serializedData) 249 if (serializedData.hasOwnProperty(p)) 250 formdata.append(p, serializedData[p]); 251 } 252 253 options.data = null; 254 255 var s = $.extend(true, {}, $.ajaxSettings, options, { 256 contentType: false, 257 processData: false, 258 cache: false, 259 type: 'POST' 260 }); 261 262 if (options.uploadProgress) { 263 // workaround because jqXHR does not expose upload property 264 s.xhr = function() { 265 var xhr = jQuery.ajaxSettings.xhr(); 266 if (xhr.upload) { 267 xhr.upload.onprogress = function(event) { 268 var percent = 0; 269 var position = event.loaded || event.position; /*event.position is deprecated*/ 270 var total = event.total; 271 if (event.lengthComputable) { 272 percent = Math.ceil(position / total * 100); 273 } 274 options.uploadProgress(event, position, total, percent); 275 }; 276 } 277 return xhr; 278 }; 279 } 280 281 s.data = null; 282 var beforeSend = s.beforeSend; 283 s.beforeSend = function(xhr, o) { 284 o.data = formdata; 285 if(beforeSend) 286 beforeSend.call(o, xhr, options); 287 }; 288 $.ajax(s); 289 } 290 291 // private function for handling file uploads (hat tip to YAHOO!) 292 function fileUploadIframe(a) { 293 var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle; 294 var useProp = !!$.fn.prop; 295 296 if ($(':input[name=submit],:input[id=submit]', form).length) { 297 // if there is an input with a name or id of 'submit' then we won't be 298 // able to invoke the submit fn on the form (at least not x-browser) 299 alert('Error: Form elements must not have name or id of "submit".'); 300 return; 301 } 302 303 if (a) { 304 // ensure that every serialized input is still enabled 305 for (i=0; i < elements.length; i++) { 306 el = $(elements[i]); 307 if ( useProp ) 308 el.prop('disabled', false); 309 else 310 el.removeAttr('disabled'); 311 } 312 } 313 314 s = $.extend(true, {}, $.ajaxSettings, options); 315 s.context = s.context || s; 316 id = 'jqFormIO' + (new Date().getTime()); 317 if (s.iframeTarget) { 318 $io = $(s.iframeTarget); 319 n = $io.attr('name'); 320 if (!n) 321 $io.attr('name', id); 322 else 323 id = n; 324 } 325 else { 326 $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />'); 327 $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' }); 328 } 329 io = $io[0]; 330 331 332 xhr = { // mock object 333 aborted: 0, 334 responseText: null, 335 responseXML: null, 336 status: 0, 337 statusText: 'n/a', 338 getAllResponseHeaders: function() {}, 339 getResponseHeader: function() {}, 340 setRequestHeader: function() {}, 341 abort: function(status) { 342 var e = (status === 'timeout' ? 'timeout' : 'aborted'); 343 log('aborting upload... ' + e); 344 this.aborted = 1; 345 $io.attr('src', s.iframeSrc); // abort op in progress 346 xhr.error = e; 347 if (s.error) 348 s.error.call(s.context, xhr, e, status); 349 if (g) 350 $.event.trigger("ajaxError", [xhr, s, e]); 351 if (s.complete) 352 s.complete.call(s.context, xhr, e); 353 } 354 }; 355 356 g = s.global;
357 // trigger ajax global events so that activity/block indicators work like normal 358 if (g && 0 === $.active++) { 359 $.event.trigger("ajaxStart"); 360 } 361 if (g) { 362 $.event.trigger("ajaxSend", [xhr, s]); 363 } 364 365 if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) { 366 if (s.global) { 367 $.active--; 368 } 369 return; 370 } 371 if (xhr.aborted) { 372 return; 373 } 374 375 // add submitting element to data if we know it 376 sub = form.clk; 377 if (sub) { 378 n = sub.name; 379 if (n && !sub.disabled) { 380 s.extraData = s.extraData || {}; 381 s.extraData[n] = sub.value; 382 if (sub.type == "image") { 383 s.extraData[n+'.x'] = form.clk_x; 384 s.extraData[n+'.y'] = form.clk_y; 385 } 386 } 387 } 388 389 var CLIENT_TIMEOUT_ABORT = 1; 390 var SERVER_ABORT = 2; 391 392 function getDoc(frame) { 393 var doc = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument ? frame.contentDocument : frame.document; 394 return doc; 395 } 396 397 // Rails CSRF hack (thanks to Yvan Barthelemy) 398 var csrf_token = $('meta[name=csrf-token]').attr('content'); 399 var csrf_param = $('meta[name=csrf-param]').attr('content'); 400 if (csrf_param && csrf_token) { 401 s.extraData = s.extraData || {}; 402 s.extraData[csrf_param] = csrf_token; 403 } 404 405 // take a breath so that pending repaints get some cpu time before the upload starts 406 function doSubmit() { 407 // make sure form attrs are set 408 var t = $form.attr('target'), a = $form.attr('action'); 409 410 // update form attrs in IE friendly way 411 form.setAttribute('target',id); 412 if (!method) { 413 form.setAttribute('method', 'POST'); 414 } 415 if (a != s.url) { 416 form.setAttribute('action', s.url); 417 } 418 419 // ie borks in some cases when setting encoding 420 if (! s.skipEncodingOverride && (!method || /post/i.test(method))) { 421 $form.attr({ 422 encoding: 'multipart/form-data', 423 enctype: 'multipart/form-data' 424 }); 425 } 426 427 // support timout 428 if (s.timeout) { 429 timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout); 430 } 431 432 // look for server aborts 433 function checkState() { 434 try { 435 var state = getDoc(io).readyState; 436 log('state = ' + state); 437 if (state && state.toLowerCase() == 'uninitialized') 438 setTimeout(checkState,50); 439 } 440 catch(e) { 441 log('Server abort: ' , e, ' (', e.name, ')'); 442 cb(SERVER_ABORT); 443 if (timeoutHandle) 444 clearTimeout(timeoutHandle); 445 timeoutHandle = undefined; 446 } 447 } 448 449 // add "extra" data to form if provided in options 450 var extraInputs = []; 451 try { 452 if (s.extraData) { 453 for (var n in s.extraData) { 454 if (s.extraData.hasOwnProperty(n)) { 455 extraInputs.push( 456 $('<input type="hidden" name="'+n+'">').attr('value',s.extraData[n]) 457 .appendTo(form)[0]); 458 } 459 } 460 } 461 462 if (!s.iframeTarget) { 463 // add iframe to doc and submit the form 464 $io.appendTo('body'); 465 if (io.attachEvent) 466 io.attachEvent('onload', cb); 467 else 468 io.addEventListener('load', cb, false); 469 } 470 setTimeout(checkState,15); 471 form.submit(); 472 } 473 finally { 474 // reset attrs and remove "extra" input elements 475 form.setAttribute('action',a); 476 if(t) { 477 form.setAttribute('target', t); 478 } else { 479 $form.removeAttr('target'); 480 } 481 $(extraInputs).remove(); 482 } 483 } 484 485 if (s.forceSync) { 486 doSubmit(); 487 } 488 else { 489 setTimeout(doSubmit, 10); // this lets dom updates render 490 } 491 492 var data, doc, domCheckCount = 50, callbackProcessed; 493 494 function cb(e) { 495 if (xhr.aborted || callbackProcessed) { 496 return; 497 } 498 try { 499 doc = getDoc(io); 500 } 501 catch(ex) { 502 log('cannot access response document: ', ex); 503 e = SERVER_ABORT; 504 } 505 if (e === CLIENT_TIMEOUT_ABORT && xhr) { 506 xhr.abort('timeout'); 507 return; 508 } 509 else if (e == SERVER_ABORT && xhr) { 510 xhr.abort('server abort'); 511 return; 512 } 513 514 if (!doc || doc.location.href == s.iframeSrc) { 515 // response not received yet 516 if (!timedOut) 517 return; 518 } 519 if (io.detachEvent) 520 io.detachEvent('onload', cb); 521 else 522 io.removeEventListener('load', cb, false); 523 524 var status = 'success', errMsg; 525 try { 526 if (timedOut) { 527 throw 'timeout'; 528 } 529 530 var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc); 531 log('isXml='+isXml); 532 if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) { 533 if (--domCheckCount) { 534 // in some browsers (Opera) the iframe DOM is not always traversable when 535 // the onload callback fires, so we loop a bit to accommodate 536 log('requeing onLoad callback, DOM not available'); 537 setTimeout(cb, 250); 538 return; 539 } 540 // let this fall through because server response could be an empty document 541 //log('Could not access iframe DOM after mutiple tries.'); 542 //throw 'DOMException: not available'; 543 } 544 545 //log('response detected'); 546 var docRoot = doc.body ? doc.body : doc.documentElement; 547 xhr.responseText = docRoot ? docRoot.innerHTML : null; 548 xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc; 549 if (isXml) 550 s.dataType = 'xml'; 551 xhr.getResponseHeader = function(header){ 552 var headers = {'content-type': s.dataType}; 553 return headers[header]; 554 }; 555 // support for XHR 'status' & 'statusText' emulation : 556 if (docRoot) { 557 xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status; 558 xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText; 559 } 560 561 var dt = (s.dataType || '').toLowerCase(); 562 var scr = /(json|script|text)/.test(dt); 563 if (scr || s.textarea) { 564 // see if user embedded response in textarea 565 var ta = doc.getElementsByTagName('textarea')[0]; 566 if (ta) { 567 xhr.responseText = ta.value; 568 // support for XHR 'status' & 'statusText' emulation : 569 xhr.status = Number( ta.getAttribute('status') ) || xhr.status; 570 xhr.statusText = ta.getAttribute('statusText') || xhr.statusText; 571 } 572 else if (scr) { 573 // account for browsers injecting pre around json response 574 var pre = doc.getElementsByTagName('pre')[0]; 575 var b = doc.getElementsByTagName('body')[0]; 576 if (pre) { 577 xhr.responseText = pre.textContent ? pre.textContent : pre.innerText; 578 } 579 else if (b) { 580 xhr.responseText = b.textContent ? b.textContent : b.innerText; 581 } 582 } 583 } 584 else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) { 585 xhr.responseXML = toXml(xhr.responseText); 586 } 587 588 try { 589 data = httpData(xhr, dt, s); 590 } 591 catch (e) { 592 status = 'parsererror'; 593 xhr.error = errMsg = (e || status); 594 } 595 } 596 catch (e) { 597 log('error caught: ',e); 598 status = 'error'; 599 xhr.error = errMsg = (e || status); 600 } 601 602 if (xhr.aborted) { 603 log('upload aborted'); 604 status = null; 605 } 606 607 if (xhr.status) { // we've set xhr.status 608 status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error'; 609 } 610 611 // ordering of these callbacks/triggers is odd, but that's how $.ajax does it 612 if (status === 'success') { 613 if (s.success) 614 s.success.call(s.context, data, 'success', xhr); 615 if (g) 616 $.event.trigger("ajaxSuccess", [xhr, s]); 617 } 618 else if (status) { 619 if (errMsg === undefined) 620 errMsg = xhr.statusText; 621 if (s.error) 622 s.error.call(s.context, xhr, status, errMsg); 623 if (g) 624 $.event.trigger("ajaxError", [xhr, s, errMsg]); 625 } 626 627 if (g)
628 $.event.trigger("ajaxComplete", [xhr, s]); 629 630 if (g && ! --$.active) { 631 $.event.trigger("ajaxStop"); 632 } 633 634 if (s.complete) 635 s.complete.call(s.context, xhr, status); 636 637 callbackProcessed = true; 638 if (s.timeout) 639 clearTimeout(timeoutHandle); 640 641 // clean up 642 setTimeout(function() { 643 if (!s.iframeTarget) 644 $io.remove(); 645 xhr.responseXML = null; 646 }, 100); 647 } 648 649 var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+) 650 if (window.ActiveXObject) { 651 doc = new ActiveXObject('Microsoft.XMLDOM'); 652 doc.async = 'false'; 653 doc.loadXML(s); 654 } 655 else { 656 doc = (new DOMParser()).parseFromString(s, 'text/xml'); 657 } 658 return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null; 659 }; 660 var parseJSON = $.parseJSON || function(s) { 661 /*jslint evil:true */ 662 return window['eval']('(' + s + ')'); 663 }; 664 665 var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4 666 667 var ct = xhr.getResponseHeader('content-type') || '', 668 xml = type === 'xml' || !type && ct.indexOf('xml') >= 0, 669 data = xml ? xhr.responseXML : xhr.responseText; 670 671 if (xml && data.documentElement.nodeName === 'parsererror') { 672 if ($.error) 673 $.error('parsererror'); 674 } 675 if (s && s.dataFilter) { 676 data = s.dataFilter(data, type); 677 } 678 if (typeof data === 'string') { 679 if (type === 'json' || !type && ct.indexOf('json') >= 0) { 680 data = parseJSON(data); 681 } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) { 682 $.globalEval(data); 683 } 684 } 685 return data; 686 }; 687 } 688}; 689 690/** 691 * ajaxForm() provides a mechanism for fully automating form submission. 692 * 693 * The advantages of using this method instead of ajaxSubmit() are: 694 * 695 * 1: This method will include coordinates for <input type="image" /> elements (if the element 696 * is used to submit the form). 697 * 2. This method will include the submit element's name/value data (for the element that was 698 * used to submit the form). 699 * 3. This method binds the submit() method to the form for you. 700 * 701 * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely 702 * passes the options argument along after properly binding events for submit elements and 703 * the form itself. 704 */ 705$.fn.ajaxForm = function(options) { 706 options = options || {}; 707 options.delegation = options.delegation && $.isFunction($.fn.on); 708 709 // in jQuery 1.3+ we can fix mistakes with the ready state 710 if (!options.delegation && this.length === 0) { 711 var o = { s: this.selector, c: this.context }; 712 if (!$.isReady && o.s) { 713 log('DOM not ready, queuing ajaxForm'); 714 $(function() { 715 $(o.s,o.c).ajaxForm(options); 716 }); 717 return this; 718 } 719 // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready() 720 log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)')); 721 return this; 722 } 723 724 if ( options.delegation ) { 725 $(document) 726 .off('submit.form-plugin', this.selector, doAjaxSubmit) 727 .off('click.form-plugin', this.selector, captureSubmittingElement) 728 .on('submit.form-plugin', this.selector, options, doAjaxSubmit) 729 .on('click.form-plugin', this.selector, options, captureSubmittingElement); 730 return this; 731 } 732 733 return this.ajaxFormUnbind() 734 .bind('submit.form-plugin', options, doAjaxSubmit) 735 .bind('click.form-plugin', options, captureSubmittingElement); 736}; 737 738// private event handlers 739function doAjaxSubmit(e) { 740 /*jshint validthis:true */ 741 var options = e.data; 742 if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed 743 e.preventDefault(); 744 $(this).ajaxSubmit(options); 745 } 746} 747 748function captureSubmittingElement(e) { 749 /*jshint validthis:true */ 750 var target = e.target; 751 var $el = $(target); 752 if (!($el.is(":submit,input:image"))) { 753 // is this a child element of the submit el? (ex: a span within a button) 754 var t = $el.closest(':submit'); 755 if (t.length === 0) { 756 return; 757 } 758 target = t[0]; 759 } 760 var form = this; 761 form.clk = target; 762 if (target.type == 'image') { 763 if (e.offsetX !== undefined) { 764 form.clk_x = e.offsetX; 765 form.clk_y = e.offsetY; 766 } else if (typeof $.fn.offset == 'function') { 767 var offset = $el.offset(); 768 form.clk_x = e.pageX - offset.left; 769 form.clk_y = e.pageY - offset.top; 770 } else { 771 form.clk_x = e.pageX - target.offsetLeft; 772 form.clk_y = e.pageY - target.offsetTop; 773 } 774 } 775 // clear form vars 776 setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100); 777} 778 779 780// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm 781$.fn.ajaxFormUnbind = function() { 782 return this.unbind('submit.form-plugin click.form-plugin'); 783}; 784 785/** 786 * formToArray() gathers form element data into an array of objects that can 787 * be passed to any of the following ajax functions: $.get, $.post, or load. 788 * Each object in the array has both a 'name' and 'value' property. An example of 789 * an array for a simple login form might be: 790 * 791 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ] 792 * 793 * It is this array that is passed to pre-submit callback functions provided to the 794 * ajaxSubmit() and ajaxForm() methods. 795 */ 796$.fn.formToArray = function(semantic, elements) { 797 var a = []; 798 if (this.length === 0) { 799 return a; 800 } 801 802 var form = this[0]; 803 var els = semantic ? form.getElementsByTagName('*') : form.elements; 804 if (!els) { 805 return a; 806 } 807 808 var i,j,n,v,el,max,jmax; 809 for(i=0, max=els.length; i < max; i++) { 810 el = els[i]; 811 n = el.name; 812 if (!n) { 813 continue; 814 } 815 816 if (semantic && form.clk && el.type == "image") { 817 // handle image inputs on the fly when semantic == true 818 if(!el.disabled && form.clk == el) { 819 a.push({name: n, value: $(el).val(), type: el.type }); 820 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); 821 } 822 continue; 823 } 824 825 v = $.fieldValue(el, true); 826 if (v && v.constructor == Array) { 827 if (elements) 828 elements.push(el); 829 for(j=0, jmax=v.length; j < jmax; j++) { 830 a.push({name: n, value: v[j]}); 831 } 832 } 833 else if (feature.fileapi && el.type == 'file' && !el.disabled) { 834 if (elements) 835 elements.push(el); 836 var files = el.files; 837 if (files.length) { 838 for (j=0; j < files.length; j++) { 839 a.push({name: n, value: files[j], type: el.type}); 840 } 841 } 842 else { 843 // #180 844 a.push({ name: n, value: '', type: el.type }); 845 } 846 } 847 else if (v !== null && typeof v != 'undefined') { 848 if (elements) 849 elements.push(el); 850 a.push({name: n, value: v, type: el.type, required: el.required}); 851 } 852 } 853 854 if (!semantic && form.clk) { 855 // input type=='image' are not found in elements array! handle it here 856 var $input = $(form.clk), input = $input[0]; 857 n = input.name; 858 if (n && !input.disabled && input.type == 'image') { 859 a.push({name: n, value: $input.val()}); 860 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); 861 } 862 } 863 return a; 864}; 865 866/** 867 * Serializes form data into a 'submittable' string. This method will return a string 868 * in the format: name1=value1&name2=value2 869 */
870$.fn.formSerialize = function(semantic) { 871 //hand off to jQuery.param for proper encoding 872 return $.param(this.formToArray(semantic)); 873}; 874 875/** 876 * Serializes all field elements in the jQuery object into a query string. 877 * This method will return a string in the format: name1=value1&name2=value2 878 */ 879$.fn.fieldSerialize = function(successful) { 880 var a = []; 881 this.each(function() { 882 var n = this.name; 883 if (!n) { 884 return; 885 } 886 var v = $.fieldValue(this, successful); 887 if (v && v.constructor == Array) { 888 for (var i=0,max=v.length; i < max; i++) { 889 a.push({name: n, value: v[i]}); 890 } 891 } 892 else if (v !== null && typeof v != 'undefined') { 893 a.push({name: this.name, value: v}); 894 } 895 }); 896 //hand off to jQuery.param for proper encoding 897 return $.param(a); 898}; 899 900/** 901 * Returns the value(s) of the element in the matched set. For example, consider the following form: 902 * 903 * <form><fieldset> 904 * <input name="A" type="text" /> 905 * <input name="A" type="text" /> 906 * <input name="B" type="checkbox" value="B1" /> 907 * <input name="B" type="checkbox" value="B2"/> 908 * <input name="C" type="radio" value="C1" /> 909 * <input name="C" type="radio" value="C2" /> 910 * </fieldset></form> 911 * 912 * var v = $(':text').fieldValue(); 913 * // if no values are entered into the text inputs 914 * v == ['',''] 915 * // if values entered into the text inputs are 'foo' and 'bar' 916 * v == ['foo','bar'] 917 * 918 * var v = $(':checkbox').fieldValue(); 919 * // if neither checkbox is checked 920 * v === undefined 921 * // if both checkboxes are checked 922 * v == ['B1', 'B2'] 923 * 924 * var v = $(':radio').fieldValue(); 925 * // if neither radio is checked 926 * v === undefined 927 * // if first radio is checked 928 * v == ['C1'] 929 * 930 * The successful argument controls whether or not the field element must be 'successful' 931 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls). 932 * The default value of the successful argument is true. If this value is false the value(s) 933 * for each element is returned. 934 * 935 * Note: This method *always* returns an array. If no valid value can be determined the 936 * array will be empty, otherwise it will contain one or more values. 937 */ 938$.fn.fieldValue = function(successful) { 939 for (var val=[], i=0, max=this.length; i < max; i++) { 940 var el = this[i]; 941 var v = $.fieldValue(el, successful); 942 if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) { 943 continue; 944 } 945 if (v.constructor == Array) 946 $.merge(val, v); 947 else 948 val.push(v); 949 } 950 return val; 951}; 952 953/** 954 * Returns the value of the field element. 955 */ 956$.fieldValue = function(el, successful) { 957 var n = el.name, t = el.type, tag = el.tagName.toLowerCase(); 958 if (successful === undefined) { 959 successful = true; 960 } 961 962 if (successful && (!n || el.disabled || t == 'reset' || t == 'button' || 963 (t == 'checkbox' || t == 'radio') && !el.checked || 964 (t == 'submit' || t == 'image') && el.form && el.form.clk != el || 965 tag == 'select' && el.selectedIndex == -1)) { 966 return null; 967 } 968 969 if (tag == 'select') { 970 var index = el.selectedIndex; 971 if (index < 0) { 972 return null; 973 } 974 var a = [], ops = el.options; 975 var one = (t == 'select-one'); 976 var max = (one ? index+1 : ops.length); 977 for(var i=(one ? index : 0); i < max; i++) { 978 var op = ops[i]; 979 if (op.selected) { 980 var v = op.value; 981 if (!v) { // extra pain for IE... 982 v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value; 983 } 984 if (one) { 985 return v; 986 } 987 a.push(v); 988 } 989 } 990 return a; 991 } 992 return $(el).val(); 993}; 994 995/** 996 * Clears the form data. Takes the following actions on the form's input fields: 997 * - input text fields will have their 'value' property set to the empty string 998 * - select elements will have their 'selectedIndex' property set to -1 999 * - checkbox and radio inputs will have their 'checked' property set to false 1000 * - inputs of type submit, button, reset, and hidden will *not* be effected 1001 * - button elements will *not* be effected 1002 */ 1003$.fn.clearForm = function(includeHidden) { 1004 return this.each(function() { 1005 $('input,select,textarea', this).clearFields(includeHidden); 1006 }); 1007}; 1008 1009/** 1010 * Clears the selected form elements. 1011 */ 1012$.fn.clearFields = $.fn.clearInputs = function(includeHidden) { 1013 var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list 1014 return this.each(function() { 1015 var t = this.type, tag = this.tagName.toLowerCase(); 1016 if (re.test(t) || tag == 'textarea') { 1017 this.value = ''; 1018 } 1019 else if (t == 'checkbox' || t == 'radio') { 1020 this.checked = false;
1021 } 1022 else if (tag == 'select') { 1023 this.selectedIndex = -1; 1024 } 1025 else if (includeHidden) { 1026 // includeHidden can be the valud true, or it can be a selector string 1027 // indicating a special test; for example: 1028 // $('#myForm').clearForm('.special:hidden') 1029 // the above would clean hidden inputs that have the class of 'special' 1030 if ( (includeHidden === true && /hidden/.test(t)) || 1031 (typeof includeHidden == 'string' && $(this).is(includeHidden)) ) 1032 this.value = ''; 1033 } 1034 }); 1035}; 1036 1037/** 1038 * Resets the form data. Causes all form elements to be reset to their original value. 1039 */ 1040$.fn.resetForm = function() { 1041 return this.each(function() { 1042 // guard against an input with the name of 'reset' 1043 // note that IE reports the reset function as an 'object' 1044 if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) { 1045 this.reset(); 1046 } 1047 }); 1048}; 1049 1050/** 1051 * Enables or disables any matching elements. 1052 */ 1053$.fn.enable = function(b) { 1054 if (b === undefined) { 1055 b = true; 1056 } 1057 return this.each(function() { 1058 this.disabled = !b; 1059 }); 1060}; 1061 1062/** 1063 * Checks/unchecks any matching checkboxes or radio buttons and 1064 * selects/deselects and matching option elements. 1065 */ 1066$.fn.selected = function(select) { 1067 if (select === undefined) { 1068 select = true; 1069 } 1070 return this.each(function() { 1071 var t = this.type; 1072 if (t == 'checkbox' || t == 'radio') { 1073 this.checked = select; 1074 } 1075 else if (this.tagName.toLowerCase() == 'option') { 1076 var $sel = $(this).parent('select'); 1077 if (select && $sel[0] && $sel[0].type == 'select-one') { 1078 // deselect all other options 1079 $sel.find('option').selected(false); 1080 } 1081 this.selected = select; 1082 } 1083 }); 1084}; 1085 1086// expose debug var 1087$.fn.ajaxSubmit.debug = false; 1088 1089// helper fn for console logging 1090function log() { 1091 if (!$.fn.ajaxSubmit.debug) 1092 return; 1093 var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,''); 1094 if (window.console && window.console.log) { 1095 window.console.log(msg); 1096 } 1097 else if (window.opera && window.opera.postError) { 1098 window.opera.postError(msg); 1099 } 1100} 1101 1102})(jQuery); 1103; 1104 1105/* 1106 * jQuery UI Accordion 1.8.7 1107 * 1108 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) 1109 * Dual licensed under the MIT or GPL Version 2 licenses. 1110 * http://jquery.org/license 1111 * 1112 * http://docs.jquery.com/UI/Accordion 1113 * 1114 * Depends: 1115 * jquery.ui.core.js 1116 * jquery.ui.widget.js 1117 */ 1118(function(c){c.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var a=this,b=a.options;a.running=0;a.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix"); 1119a.headers=a.element.find(b.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){b.disabled||c(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){b.disabled||c(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){b.disabled||c(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){b.disabled||c(this).removeClass("ui-state-focus")});a.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom"); 1120if(b.navigation){var d=a.element.find("a").filter(b.navigationFilter).eq(0);if(d.length){var f=d.closest(".ui-accordion-header");a.active=f.length?f:d.closest(".ui-accordion-content").prev()}}a.active=a._findActive(a.active||b.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");a.active.next().addClass("ui-accordion-content-active");a._createIcons();a.resize();a.element.attr("role","tablist");a.headers.attr("role","tab").bind("keydown.accordion", 1121function(g){return a._keydown(g)}).next().attr("role","tabpanel");a.headers.not(a.active||"").attr({"aria-expanded":"false",tabIndex:-1}).next().hide();a.active.length?a.active.attr({"aria-expanded":"true",tabIndex:0}):a.headers.eq(0).attr("tabIndex",0);c.browser.safari||a.headers.find("a").attr("tabIndex",-1);b.event&&a.headers.bind(b.event.split(" ").join(".accordion ")+".accordion",function(g){a._clickHandler.call(a,g,this);g.preventDefault()})},_createIcons:function(){var a=this.options;if(a.icons){c("<span></span>").addClass("ui-icon "+ 1122a.icons.header).prependTo(this.headers);this.active.children(".ui-icon").toggleClass(a.icons.header).toggleClass(a.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var a=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("tabIndex"); 1123this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");if(a.autoHeight||a.fillHeight)b.css("height","");return c.Widget.prototype.destroy.call(this)},_setOption:function(a,b){c.Widget.prototype._setOption.apply(this,arguments);a=="active"&&this.activate(b);if(a=="icons"){this._destroyIcons(); 1124b&&this._createIcons()}if(a=="disabled")this.headers.add(this.headers.next())[b?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")}
1124,_keydown:function(a){if(!(this.options.disabled||a.altKey||a.ctrlKey)){var b=c.ui.keyCode,d=this.headers.length,f=this.headers.index(a.target),g=false;switch(a.keyCode){case b.RIGHT:case b.DOWN:g=this.headers[(f+1)%d];break;case b.LEFT:case b.UP:g=this.headers[(f-1+d)%d];break;case b.SPACE:case b.ENTER:this._clickHandler({target:a.target},a.target); 1125a.preventDefault()}if(g){c(a.target).attr("tabIndex",-1);c(g).attr("tabIndex",0);g.focus();return false}return true}},resize:function(){var a=this.options,b;if(a.fillSpace){if(c.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}b=this.element.parent().height();c.browser.msie&&this.element.parent().css("overflow",d);this.headers.each(function(){b-=c(this).outerHeight(true)});this.headers.next().each(function(){c(this).height(Math.max(0,b-c(this).innerHeight()+ 1126c(this).height()))}).css("overflow","auto")}else if(a.autoHeight){b=0;this.headers.next().each(function(){b=Math.max(b,c(this).height("").height())}).height(b)}return this},activate:function(a){this.options.active=a;a=this._findActive(a)[0];this._clickHandler({target:a},a);return this},_findActive:function(a){return a?typeof a==="number"?this.headers.filter(":eq("+a+")"):this.headers.not(this.headers.not(a)):a===false?c([]):this.headers.filter(":eq(0)")},_clickHandler:function(a,b){var d=this.options; 1127if(!d.disabled)if(a.target){a=c(a.currentTarget||b);b=a[0]===this.active[0];d.active=d.collapsible&&b?false:this.headers.index(a);if(!(this.running||!d.collapsible&&b)){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);if(!b){a.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected); 1128a.next().addClass("ui-accordion-content-active")}h=a.next();f=this.active.next();g={options:d,newHeader:b&&d.collapsible?c([]):a,oldHeader:this.active,newContent:b&&d.collapsible?c([]):h,oldContent:f};d=this.headers.index(this.active[0])>this.headers.index(a[0]);this.active=b?c([]):a;this._toggle(h,f,g,b,d)}}else if(d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header); 1129this.active.next().addClass("ui-accordion-content-active");var f=this.active.next(),g={options:d,newHeader:c([]),oldHeader:d.active,newContent:c([]),oldContent:f},h=this.active=c([]);this._toggle(h,f,g)}},_toggle:function(a,b,d,f,g){var h=this,e=h.options;h.toShow=a;h.toHide=b;h.data=d;var j=function(){if(h)return h._completed.apply(h,arguments)};h._trigger("changestart",null,h.data);h.running=b.size()===0?a.size():b.size();if(e.animated){d={};d=e.collapsible&&f?{toShow:c([]),toHide:b,complete:j, 1130down:g,autoHeight:e.autoHeight||e.fillSpace}:{toShow:a,toHide:b,complete:j,down:g,autoHeight:e.autoHeight||e.fillSpace};if(!e.proxied)e.proxied=e.animated;if(!e.proxiedDuration)e.proxiedDuration=e.duration;e.animated=c.isFunction(e.proxied)?e.proxied(d):e.proxied;e.duration=c.isFunction(e.proxiedDuration)?e.proxiedDuration(d):e.proxiedDuration;f=c.ui.accordion.animations;var i=e.duration,k=e.animated;if(k&&!f[k]&&!c.easing[k])k="slide";f[k]||(f[k]=function(l){this.slide(l,{easing:k,duration:i||700})}); 1131f[k](d)}else{if(e.collapsible&&f)a.toggle();else{b.hide();a.show()}j(true)}b.prev().attr({"aria-expanded":"false",tabIndex:-1}).blur();a.prev().attr({"aria-expanded":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");this._trigger("change",null,this.data)}}});c.extend(c.ui.accordion,{version:"1.8.7",animations:{slide:function(a, 1132b){a=c.extend({easing:"swing",duration:300},a,b);if(a.toHide.size())if(a.toShow.size()){var d=a.toShow.css("overflow"),f=0,g={},h={},e;b=a.toShow;e=b[0].style.width;b.width(parseInt(b.parent().width(),10)-parseInt(b.css("paddingLeft"),10)-parseInt(b.css("paddingRight"),10)-(parseInt(b.css("borderLeftWidth"),10)||0)-(parseInt(b.css("borderRightWidth"),10)||0));c.each(["height","paddingTop","paddingBottom"],function(j,i){h[i]="hide";j=(""+c.css(a.toShow[0],i)).match(/^([\d+-.]+)(.*)$/);g[i]={value:j[1], 1133unit:j[2]||"px"}});a.toShow.css({height:0,overflow:"hidden"}).show();a.toHide.filter(":hidden").each(a.complete).end().filter(":visible").animate(h,{step:function(j,i){if
1133(i.prop=="height")f=i.end-i.start===0?0:(i.now-i.start)/(i.end-i.start);a.toShow[0].style[i.prop]=f*g[i.prop].value+g[i.prop].unit},duration:a.duration,easing:a.easing,complete:function(){a.autoHeight||a.toShow.css("height","");a.toShow.css({width:e,overflow:d});a.complete()}})}else a.toHide.animate({height:"hide",paddingTop:"hide", 1134paddingBottom:"hide"},a);else a.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},a)},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1E3:200})}}})})(jQuery); 1135; 1136(function ($) { 1137 1138/** 1139 * Provides Ajax page updating via jQuery $.ajax (Asynchronous JavaScript and XML). 1140 * 1141 * Ajax is a method of making a request via JavaScript while viewing an HTML 1142 * page. The request returns an array of commands encoded in JSON, which is 1143 * then executed to make any changes that are necessary to the page. 1144 * 1145 * Drupal uses this file to enhance form elements with #ajax['path'] and 1146 * #ajax['wrapper'] properties. If set, this file will automatically be included 1147 * to provide Ajax capabilities. 1148 */ 1149 1150Drupal.ajax = Drupal.ajax || {}; 1151 1152/** 1153 * Attaches the Ajax behavior to each Ajax form element. 1154 */ 1155Drupal.behaviors.AJAX = { 1156 attach: function (context, settings) { 1157 // Load all Ajax behaviors specified in the settings. 1158 for (var base in settings.ajax) { 1159 if (!$('#' + base + '.ajax-processed').length) { 1160 var element_settings = settings.ajax[base]; 1161 1162 if (typeof element_settings.selector == 'undefined') { 1163 element_settings.selector = '#' + base; 1164 } 1165 $(element_settings.selector).each(function () { 1166 element_settings.element = this; 1167 Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings); 1168 }); 1169 1170 $('#' + base).addClass('ajax-processed'); 1171 } 1172 } 1173 1174 // Bind Ajax behaviors to all items showing the class. 1175 $('.use-ajax:not(.ajax-processed)').addClass('ajax-processed').each(function () { 1176 var element_settings = {}; 1177 // Clicked links look better with the throbber than the progress bar. 1178 element_settings.progress = { 'type': 'throbber' }; 1179 1180 // For anchor tags, these will go to the target of the anchor rather 1181 // than the usual location. 1182 if ($(this).attr('href')) { 1183 element_settings.url = $(this).attr('href'); 1184 element_settings.event = 'click'; 1185 } 1186 var base = $(this).attr('id'); 1187 Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings); 1188 }); 1189 1190 // This class means to submit the form to the action using Ajax. 1191 $('.use-ajax-submit:not(.ajax-processed)').addClass('ajax-processed').each(function () { 1192 var element_settings = {}; 1193 1194 // Ajax submits specified in this manner automatically submit to the 1195 // normal form action. 1196 element_settings.url = $(this.form).attr('action'); 1197 // Form submit button clicks need to tell the form what was clicked so 1198 // it gets passed in the POST request. 1199 element_settings.setClick = true; 1200 // Form buttons use the 'click' event rather than mousedown. 1201 element_settings.event = 'click'; 1202 // Clicked form buttons look better with the throbber than the progress bar. 1203 element_settings.progress = { 'type': 'throbber' }; 1204 1205 var base = $(this).attr('id'); 1206 Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings); 1207 }); 1208 } 1209}; 1210 1211/** 1212 * Ajax object. 1213 * 1214 * All Ajax objects on a page are accessible through the global Drupal.ajax 1215 * object and are keyed by the submit button's ID. You can access them from 1216 * your module's JavaScript file to override properties or functions. 1217 * 1218 * For example, if your Ajax enabled button has the ID 'edit-submit', you can 1219 * redefine the function that is called to insert the new content like this 1220 * (inside a Drupal.behaviors attach block): 1221 * @code 1222 * Drupal.behaviors.myCustomAJAXStuff = { 1223 * attach: function (context, settings) { 1224 * Drupal.ajax['edit-submit'].commands.insert = function (ajax, response, status) { 1225 * new_content = $(response.data); 1226 * $('#my-wrapper').append(new_content); 1227 * alert('New content was appended to #my-wrapper'); 1228 * } 1229 * } 1230 * }; 1231 * @endcode 1232 */ 1233Drupal.ajax = function (base, element, element_settings) { 1234 var defaults = { 1235 url: 'system/ajax', 1236 event: 'mousedown', 1237 keypress: true, 1238 selector: '#' + base, 1239 effect: 'none', 1240 speed: 'none', 1241 method: 'replaceWith', 1242 progress: { 1243 type: 'throbber', 1244 message: Drupal.t('Please wait...') 1245 }, 1246 submit: { 1247 'js': true 1248 } 1249 }; 1250 1251 $.extend(this, defaults, element_settings); 1252 1253 this.element = element; 1254 this.element_settings = element_settings; 1255 1256 // Replacing 'nojs' with 'ajax' in the URL allows for an easy method to let 1257 // the server detect when it needs to degrade gracefully. 1258 // There are five scenarios to check for: 1259 // 1. /nojs/ 1260 // 2. /nojs$ - The end of a URL string. 1261 // 3. /nojs? - Followed by a query (with clean URLs enabled). 1262 // E.g.: path/nojs?destination=foobar 1263 // 4. /nojs& - Followed by a query (without clean URLs enabled). 1264 // E.g.: ?q=path/nojs&destination=foobar 1265 // 5. /nojs# - Followed by a fragment. 1266 // E.g.: path/nojs#myfragment 1267 this.url = element_settings.url.replace(/\/nojs(\/|$|\?|&|#)/g, '/ajax$1'); 1268 this.wrapper = '#' + element_settings.wrapper; 1269 1270 // If there isn't a form, jQuery.ajax() will be used instead, allowing us to 1271 // bind Ajax to links as well. 1272 if (this.element.form) { 1273 this.form = $(this.element.form); 1274 } 1275 1276 // Set the options for the ajaxSubmit function. 1277 // The 'this' variable will not persist inside of the options object. 1278 var ajax = this; 1279 ajax.options = { 1280 url: ajax.url, 1281 data: ajax.submit, 1282 beforeSerialize: function (element_settings, options) { 1283 return ajax.beforeSerialize(element_settings, options); 1284 }, 1285 beforeSubmit: function (form_values, element_settings, options) { 1286 ajax.ajaxing = true; 1287 return ajax.beforeSubmit(form_values, element_settings, options); 1288 }, 1289 beforeSend: function (xmlhttprequest, options) { 1290 ajax.ajaxing = true; 1291 return ajax.beforeSend(xmlhttprequest, options); 1292 }, 1293 success: function (response, status) { 1294 // Sanity check for browser support (object expected). 1295 // When using iFrame uploads, responses must be returned as a string. 1296 if (typeof response == 'string') { 1297 response = $.parseJSON(response); 1298 } 1299 return ajax.success(response, status); 1300 }, 1301 complete: function (response, status) { 1302 ajax.ajaxing = false;
1303 if (status == 'error' || status == 'parsererror') { 1304 return ajax.error(response, ajax.url); 1305 } 1306 }, 1307 dataType: 'json', 1308 type: 'POST' 1309 }; 1310 1311 // Bind the ajaxSubmit function to the element event. 1312 $(ajax.element).bind(element_settings.event, function (event) { 1313 return ajax.eventResponse(this, event); 1314 }); 1315 1316 // If necessary, enable keyboard submission so that Ajax behaviors 1317 // can be triggered through keyboard input as well as e.g. a mousedown 1318 // action. 1319 if (element_settings.keypress) { 1320 $(ajax.element).keypress(function (event) { 1321 return ajax.keypressResponse(this, event); 1322 }); 1323 } 1324 1325 // If necessary, prevent the browser default action of an additional event. 1326 // For example, prevent the browser default action of a click, even if the 1327 // AJAX behavior binds to mousedown. 1328 if (element_settings.prevent) { 1329 $(ajax.element).bind(element_settings.prevent, false); 1330 } 1331}; 1332 1333/** 1334 * Handle a key press. 1335 * 1336 * The Ajax object will, if instructed, bind to a key press response. This 1337 * will test to see if the key press is valid to trigger this event and 1338 * if it is, trigger it for us and prevent other keypresses from triggering. 1339 * In this case we're handling RETURN and SPACEBAR keypresses (event codes 13 1340 * and 32. RETURN is often used to submit a form when in a textfield, and 1341 * SPACE is often used to activate an element without submitting. 1342 */ 1343Drupal.ajax.prototype.keypressResponse = function (element, event) { 1344 // Create a synonym for this to reduce code confusion. 1345 var ajax = this; 1346 1347 // Detect enter key and space bar and allow the standard response for them, 1348 // except for form elements of type 'text' and 'textarea', where the 1349 // spacebar activation causes inappropriate activation if #ajax['keypress'] is 1350 // TRUE. On a text-type widget a space should always be a space. 1351 if (event.which == 13 || (event.which == 32 && element.type != 'text' && element.type != 'textarea')) { 1352 $(ajax.element_settings.element).trigger(ajax.element_settings.event); 1353 return false; 1354 } 1355}; 1356 1357/** 1358 * Handle an event that triggers an Ajax response. 1359 * 1360 * When an event that triggers an Ajax response happens, this method will 1361 * perform the actual Ajax call. It is bound to the event using 1362 * bind() in the constructor, and it uses the options specified on the 1363 * ajax object. 1364 */ 1365Drupal.ajax.prototype.eventResponse = function (element, event) { 1366 // Create a synonym for this to reduce code confusion. 1367 var ajax = this; 1368 1369 // Do not perform another ajax command if one is already in progress. 1370 if (ajax.ajaxing) { 1371 return false; 1372 } 1373 1374 try { 1375 if (ajax.form) { 1376 // If setClick is set, we must set this to ensure that the button's 1377 // value is passed. 1378 if (ajax.setClick) { 1379 // Mark the clicked button. 'form.clk' is a special variable for 1380 // ajaxSubmit that tells the system which element got clicked to 1381 // trigger the submit. Without it there would be no 'op' or 1382 // equivalent. 1383 element.form.clk = element; 1384 } 1385 1386 ajax.form.ajaxSubmit(ajax.options); 1387 } 1388 else { 1389 ajax.beforeSerialize(ajax.element, ajax.options); 1390 $.ajax(ajax.options); 1391 } 1392 } 1393 catch (e) { 1394 // Unset the ajax.ajaxing flag here because it won't be unset during 1395 // the complete response. 1396 ajax.ajaxing = false; 1397 alert("An error occurred while attempting to process " + ajax.options.url + ": " + e.message); 1398 } 1399 1400 // For radio/checkbox, allow the default event. On IE, this means letting 1401 // it actually check the box. 1402 if (typeof element.type != 'undefined' && (element.type == 'checkbox' || element.type == 'radio')) { 1403 return true; 1404 } 1405 else { 1406 return false; 1407 } 1408 1409}; 1410 1411/** 1412 * Handler for the form serialization. 1413 * 1414 * Runs before the beforeSend() handler (see below), and unlike that one, runs 1415 * before field data is collected. 1416 */ 1417Drupal.ajax.prototype.beforeSerialize = function (element, options) { 1418 // Allow detaching behaviors to update field values before collecting them. 1419 // This is only needed when field values are added to the POST data, so only 1420 // when there is a form such that this.form.ajaxSubmit() is used instead of 1421 // $.ajax(). When there is no form and $.ajax() is used, beforeSerialize() 1422 // isn't called, but don't rely on that: explicitly check this.form. 1423 if (this.form) { 1424 var settings = this.settings || Drupal.settings; 1425 Drupal.detachBehaviors(this.form, settings, 'serialize'); 1426 } 1427 1428 // Prevent duplicate HTML ids in the returned markup. 1429 // @see drupal_html_id() 1430 options.data['ajax_html_ids[]'] = []; 1431 $('[id]').each(function () { 1432 options.data['ajax_html_ids[]'].push(this.id); 1433 }); 1434 1435 // Allow Drupal to return new JavaScript and CSS files to load without 1436 // returning the ones already loaded. 1437 // @see ajax_base_page_theme() 1438 // @see drupal_get_css() 1439 // @see drupal_get_js() 1440 options.data['ajax_page_state[theme]'] = Drupal.settings.ajaxPageState.theme; 1441 options.data['ajax_page_state[theme_token]'] = Drupal.settings.ajaxPageState.theme_token; 1442 for (var key in Drupal.settings.ajaxPageState.css) { 1443 options.data['ajax_page_state[css][' + key + ']'] = 1; 1444 } 1445 for (var key in Drupal.settings.ajaxPageState.js) { 1446 options.data['ajax_page_state[js][' + key + ']'] = 1; 1447 } 1448}; 1449 1450/** 1451 * Modify form values prior to form submission. 1452 */ 1453Drupal.ajax.prototype.beforeSubmit = function (form_values, element, options) { 1454 // This function is left empty to make it simple to override for modules 1455 // that wish to add functionality here. 1456}; 1457 1458/** 1459 * Prepare the Ajax request before it is sent. 1460 */ 1461Drupal.ajax.prototype.beforeSend = function (xmlhttprequest, options) { 1462 // For forms without file inputs, the jQuery Form plugin serializes the form 1463 // values, and then calls jQuery's $.ajax() function, which invokes this 1464 // handler. In this circumstance, options.extraData is never used. For forms 1465 // with file inputs, the jQuery Form plugin uses the browser's normal form 1466 // submission mechanism, but captures the response in a hidden IFRAME. In this 1467 // circumstance, it calls this handler first, and then appends hidden fields 1468 // to the form to submit the values in options.extraData. There is no simple 1469 // way to know which submission mechanism will be used, so we add to extraData 1470 // regardless, and allow it to be ignored in the former case. 1471 if (this.form) { 1472 options.extraData = options.extraData || {}; 1473 1474 // Let the server know when the IFRAME submission mechanism is used. The 1475 // server can use this information to wrap the JSON response in a TEXTAREA, 1476 // as per http://jquery.malsup.com/form/#file-upload. 1477 options.extraData.ajax_iframe_upload = '1'; 1478 1479 // The triggering element is about to be disabled (see below), but if it 1480 // contains a value (e.g., a checkbox, textfield, select, etc.), ensure that 1481 // value is included in the submission. As per above, submissions that use 1482 // $.ajax() are already serialized prior to the element being disabled, so 1483 // this is only needed for IFRAME submissions. 1484 var v = $.fieldValue(this.element); 1485 if (v !== null) { 1486 options.extraData[this.element.name] = v; 1487 } 1488 } 1489 1490 // Disable the element that received the change to prevent user interface 1491 // interaction while the Ajax request is in progress. ajax.ajaxing prevents 1492 // the element from triggering a new request, but does not prevent the user 1493 // from changing its value. 1494 $(this.element).addClass('progress-disabled').attr('disabled', true); 1495 1496 // Insert progressbar or throbber. 1497 if (this.progress.type == 'bar') { 1498 var progressBar = new Drupal.progressBar('ajax-progress-' + this.element.i
1498d, eval(this.progress.update_callback), this.progress.method, eval(this.progress.error_callback)); 1499 if (this.progress.message) { 1500 progressBar.setProgress(-1, this.progress.message); 1501 } 1502 if (this.progress.url) { 1503 progressBar.startMonitoring(this.progress.url, this.progress.interval || 1500); 1504 } 1505 this.progress.element = $(progressBar.element).addClass('ajax-progress ajax-progress-bar'); 1506 this.progress.object = progressBar; 1507 $(this.element).after(this.progress.element); 1508 } 1509 else if (this.progress.type == 'throbber') { 1510 this.progress.element = $('<div class="ajax-progress ajax-progress-throbber"><div class="throbber"> </div></div>'); 1511 if (this.progress.message) { 1512 $('.throbber', this.progress.element).after('<div class="message">' + this.progress.message + '</div>'); 1513 } 1514 $(this.element).after(this.progress.element); 1515 } 1516}; 1517 1518/** 1519 * Handler for the form redirection completion. 1520 */ 1521Drupal.ajax.prototype.success = function (response, status) { 1522 // Remove the progress element. 1523 if (this.progress.element) { 1524 $(this.progress.element).remove(); 1525 } 1526 if (this.progress.object) { 1527 this.progress.object.stopMonitoring(); 1528 } 1529 $(this.element).removeClass('progress-disabled').removeAttr('disabled'); 1530 1531 Drupal.freezeHeight(); 1532 1533 for (var i in response) { 1534 if (response.hasOwnProperty(i) && response[i]['command'] && this.commands[response[i]['command']]) { 1535 this.commands[response[i]['command']](this, response[i], status); 1536 } 1537 } 1538 1539 // Reattach behaviors, if they were detached in beforeSerialize(). The 1540 // attachBehaviors() called on the new content from processing the response 1541 // commands is not sufficient, because behaviors from the entire form need 1542 // to be reattached. 1543 if (this.form) { 1544 var settings = this.settings || Drupal.settings; 1545 Drupal.attachBehaviors(this.form, settings); 1546 } 1547 1548 Drupal.unfreezeHeight(); 1549 1550 // Remove any response-specific settings so they don't get used on the next 1551 // call by mistake. 1552 this.settings = null; 1553}; 1554 1555/** 1556 * Build an effect object which tells us how to apply the effect when adding new HTML. 1557 */ 1558Drupal.ajax.prototype.getEffect = function (response) { 1559 var type = response.effect || this.effect; 1560 var speed = response.speed || this.speed; 1561 1562 var effect = {}; 1563 if (type == 'none') { 1564 effect.showEffect = 'show'; 1565 effect.hideEffect = 'hide'; 1566 effect.showSpeed = ''; 1567 } 1568 else if (type == 'fade') { 1569 effect.showEffect = 'fadeIn'; 1570 effect.hideEffect = 'fadeOut'; 1571 effect.showSpeed = speed; 1572 } 1573 else { 1574 effect.showEffect = type + 'Toggle'; 1575 effect.hideEffect = type + 'Toggle'; 1576 effect.showSpeed = speed; 1577 } 1578 1579 return effect; 1580}; 1581 1582/** 1583 * Handler for the form redirection error. 1584 */ 1585Drupal.ajax.prototype.error = function (response, uri) { 1586 alert(Drupal.ajaxError(response, uri)); 1587 // Remove the progress element. 1588 if (this.progress.element) { 1589 $(this.progress.element).remove(); 1590 } 1591 if (this.progress.object) { 1592 this.progress.object.stopMonitoring(); 1593 } 1594 // Undo hide. 1595 $(this.wrapper).show(); 1596 // Re-enable the element. 1597 $(this.element).removeClass('progress-disabled').removeAttr('disabled'); 1598 // Reattach behaviors, if they were detached in beforeSerialize(). 1599 if (this.form) { 1600 var settings = response.settings || this.settings || Drupal.settings; 1601 Drupal.attachBehaviors(this.form, settings); 1602 } 1603}; 1604 1605/** 1606 * Provide a series of commands that the server can request the client perform. 1607 */ 1608Drupal.ajax.prototype.commands = { 1609 /** 1610 * Command to insert new content into the DOM. 1611 */ 1612 insert: function (ajax, response, status) { 1613 // Get information from the response. If it is not there, default to 1614 // our presets. 1615 var wrapper = response.selector ? $(response.selector) : $(ajax.wrapper); 1616 var method = response.method || ajax.method; 1617 var effect = ajax.getEffect(response); 1618 1619 // We don't know what response.data contains: it might be a string of text 1620 // without HTML, so don't rely on jQuery correctly iterpreting 1621 // $(response.data) as new HTML rather than a CSS selector. Also, if 1622 // response.data contains top-level text nodes, they get lost with either 1623 // $(response.data) or $('<div></div>').replaceWith(response.data). 1624 var new_content_wrapped = $('<div></div>').html(response.data); 1625 var new_content = new_content_wrapped.contents(); 1626 1627 // For legacy reasons, the effects processing code assumes that new_content 1628 // consists of a single top-level element. Also, it has not been 1629 // sufficiently tested whether attachBehaviors() can be successfully called 1630 // with a context object that includes top-level text nodes. However, to 1631 // give developers full control of the HTML appearing in the page, and to 1632 // enable Ajax content to be inserted in places where DIV elements are not 1633 // allowed (e.g., within TABLE, TR, and SPAN parents), we check if the new 1634 // content satisfies the requirement of a single top-level element, and 1635 // only use the container DIV created above when it doesn't. For more 1636 // information, please see http://drupal.org/node/736066. 1637 if (new_content.length != 1 || new_content.get(0).nodeType != 1) { 1638 new_content = new_content_wrapped; 1639 } 1640 1641 // If removing content from the wrapper, detach behaviors first. 1642 switch (method) { 1643 case 'html': 1644 case 'replaceWith': 1645 case 'replaceAll': 1646 case 'empty': 1647 case 'remove': 1648 var settings = response.settings || ajax.settings || Drupal.settings; 1649 Drupal.detachBehaviors(wrapper, settings); 1650 } 1651 1652 // Add the new content to the page. 1653 wrapper[method](new_content); 1654 1655 // Immediately hide the new content if we're using any effects. 1656 if (effect.showEffect != 'show') { 1657 new_content.hide(); 1658 } 1659 1660 // Determine which effect to use and what content will receive the 1661 // effect, then show the new content. 1662 if ($('.ajax-new-content', new_content).length > 0) { 1663 $('.ajax-new-content', new_content).hide(); 1664 new_content.show(); 1665 $('.ajax-new-content', new_content)[effect.showEffect](effect.showSpeed); 1666 } 1667 else if (effect.showEffect != 'show') { 1668 new_content[effect.showEffect](effect.showSpeed); 1669 } 1670 1671 // Attach all JavaScript behaviors to the new content, if it was successfully 1672 // added to the page, this if statement allows #ajax['wrapper'] to be 1673 // optional. 1674 if (new_content.parents('html').length > 0) { 1675 // Apply any settings from the returned JSON if available. 1676 var settings = response.settings || ajax.settings || Drupal.settings; 1677 Drupal.attachBehaviors(new_content, settings); 1678 } 1679 }, 1680 1681 /** 1682 * Command to remove a chunk from the page. 1683 */ 1684 remove: function (ajax, response, status) { 1685 var settings = response.settings || ajax.settings || Drupal.settings; 1686 Drupal.detachBehaviors($(response.selector), settings); 1687 $(response.selector).remove(); 1688 }, 1689 1690 /** 1691 * Command to mark a chunk changed. 1692 */ 1693 changed: function (ajax, response, status) { 1694 if (!$(response.selector).hasClass('ajax-changed')) { 1695 $(response.selector).addClass('ajax-changed'); 1696 if (response.asterisk) { 1697 $(response.selector).find(response.asterisk).append(' <span class="ajax-changed">*</span> '); 1698 } 1699 } 1700 }, 1701 1702 /** 1703 * Command to provide an alert. 1704 */ 1705 alert: function (ajax, response, status) { 1706 alert(response.text, response.title); 1707 }, 1708 1709 /** 1710 * Command to provide the jQuery css() function. 1711 */ 1712 css: function (ajax, response, status) { 1713 $(response.selector).css(response.argument); 1714 }, 1715 1716 /** 1717 * Command to set the settings that will be used for other commands in this response. 1718 */ 1719 settings: function (ajax, response, status) { 1720 if (response.merge) { 1721 $.extend(true, Drupal.settings, response.settings); 1722 } 1723 else { 1724 ajax.settings = response.settings; 1725 } 1726 }, 1727 1728 /** 1729 * Command to attach data using jQuery's data API. 1730 */ 1731 data: function (ajax, response, status) { 1732 $(response.selector).data(response.name, response.value); 1733 }, 1734 1735 /** 1736 * Command to apply a jQuery method. 1737 */ 1738 invoke: function (ajax, response, status) { 1739 var $element = $(response.selector); 1740 $element[response.method].apply($element, response.arguments); 1741 }, 1742 1743 /** 1744 * Command to restripe a table. 1745 */ 1746 restripe: function (ajax, response, status) { 1747 // :even and :odd are reversed because jQuery counts from 0 and 1748 // we count from 1, so we're out of sync. 1749 // Match immediate children of the parent element to allow nesting. 1750 $('> tbody > tr:visible, > tr:visible', $(response.selector)) 1751 .removeClass('odd even') 1752 .filter(':even').addClass('odd').end() 1753 .filter(':odd').addClass('even'); 1754 } 1755}; 1756 1757})(jQuery); 1758;
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.