/*jslint browser: true */ /*global jQuery: true */ /** * jQuery Cookie plugin * * Copyright (c) 2010 Klaus Hartl (stilbuero.de) * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html * */ // TODO JsDoc /** * Create a cookie with the given key and value and other optional parameters. * * @example $.cookie('the_cookie', 'the_value'); * @desc Set the value of a cookie. * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true }); * @desc Create a cookie with all available options. * @example $.cookie('the_cookie', 'the_value'); * @desc Create a session cookie. * @example $.cookie('the_cookie', null); * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain * used when the cookie was set. * * @param String key The key of the cookie. * @param String value The value of the cookie. * @param Object options An object literal containing key/value pairs to provide optional cookie attributes. * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object. * If a negative value is specified (e.g. a date in the past), the cookie will be deleted. * If set to null or omitted, the cookie will be a session cookie and will not be retained * when the the browser exits. * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie). * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie). * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will * require a secure protocol (like HTTPS). * @type undefined * * @name $.cookie * @cat Plugins/Cookie * @author Klaus Hartl/klaus.hartl@stilbuero.de */ /** * Get the value of a cookie with the given key. * * @example $.cookie('the_cookie'); * @desc Get the value of a cookie. * * @param String key The key of the cookie. * @return The value of the cookie. * @type String * * @name $.cookie * @cat Plugins/Cookie * @author Klaus Hartl/klaus.hartl@stilbuero.de */ jQuery.cookie = function (key, value, options) { // key and value given, set cookie... if (arguments.length > 1 && (value === null || typeof value !== "object")) { options = jQuery.extend({}, options); if (value === null) { options.expires = -1; } if (typeof options.expires === 'number') { var days = options.expires, t = options.expires = new Date(); t.setDate(t.getDate() + days); } return (document.cookie = [ encodeURIComponent(key), '=', options.raw ? String(value) : encodeURIComponent(String(value)), options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE options.path ? '; path=' + options.path : '', options.domain ? '; domain=' + options.domain : '', options.secure ? '; secure' : '' ].join('')); } // key and possibly options given, get cookie... options = value || {}; var result, decode = options.raw ? function (s) { return s; } : decodeURIComponent; return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? decode(result[1]) : null; }; ; /*! * jQuery Form Plugin * version: 3.51.0-2014.06.20 * Requires jQuery v1.5 or later * Copyright (c) 2014 M. Alsup * Examples and documentation at: http://malsup.com/jquery/form/ * Project repository: https://github.com/malsup/form * Dual licensed under the MIT and GPL licenses. * https://github.com/malsup/form#copyright-and-license */ !function(e){"use strict";"function"==typeof define&&define.amd?define(["jquery"],e):e("undefined"!=typeof jQuery?jQuery:window.Zepto)}(function(e){"use strict";function t(t){var r=t.data;t.isDefaultPrevented()||(t.preventDefault(),e(t.target).ajaxSubmit(r))}function r(t){var r=t.target,a=e(r);if(!a.is("[type=submit],[type=image]")){var n=a.closest("[type=submit]");if(0===n.length)return;r=n[0]}var i=this;if(i.clk=r,"image"==r.type)if(void 0!==t.offsetX)i.clk_x=t.offsetX,i.clk_y=t.offsetY;else if("function"==typeof e.fn.offset){var o=a.offset();i.clk_x=t.pageX-o.left,i.clk_y=t.pageY-o.top}else i.clk_x=t.pageX-r.offsetLeft,i.clk_y=t.pageY-r.offsetTop;setTimeout(function(){i.clk=i.clk_x=i.clk_y=null},100)}function a(){if(e.fn.ajaxSubmit.debug){var t="[jquery.form] "+Array.prototype.join.call(arguments,"");window.console&&window.console.log?window.console.log(t):window.opera&&window.opera.postError&&window.opera.postError(t)}}var n={};n.fileapi=void 0!==e("").get(0).files,n.formdata=void 0!==window.FormData;var i=!!e.fn.prop;e.fn.attr2=function(){if(!i)return this.attr.apply(this,arguments);var e=this.prop.apply(this,arguments);return e&&e.jquery||"string"==typeof e?e:this.attr.apply(this,arguments)},e.fn.ajaxSubmit=function(t){function r(r){var a,n,i=e.param(r,t.traditional).split("&"),o=i.length,s=[];for(a=0;o>a;a++)i[a]=i[a].replace(/\+/g," "),n=i[a].split("="),s.push([decodeURIComponent(n[0]),decodeURIComponent(n[1])]);return s}function o(a){for(var n=new FormData,i=0;i').val(m.extraData[d].value).appendTo(w)[0]:e('').val(m.extraData[d]).appendTo(w)[0]);m.iframeTarget||v.appendTo("body"),g.attachEvent?g.attachEvent("onload",s):g.addEventListener("load",s,!1),setTimeout(t,15);try{w.submit()}catch(h){var x=document.createElement("form").submit;x.apply(w)}}finally{w.setAttribute("action",i),w.setAttribute("enctype",c),r?w.setAttribute("target",r):f.removeAttr("target"),e(l).remove()}}function s(t){if(!x.aborted&&!F){if(M=n(g),M||(a("cannot access response document"),t=k),t===D&&x)return x.abort("timeout"),void S.reject(x,"timeout");if(t==k&&x)return x.abort("server abort"),void S.reject(x,"error","server abort");if(M&&M.location.href!=m.iframeSrc||T){g.detachEvent?g.detachEvent("onload",s):g.removeEventListener("load",s,!1);var r,i="success";try{if(T)throw"timeout";var o="xml"==m.dataType||M.XMLDocument||e.isXMLDoc(M);if(a("isXml="+o),!o&&window.opera&&(null===M.body||!M.body.innerHTML)&&--O)return a("requeing onLoad callback, DOM not available"),void setTimeout(s,250);var u=M.body?M.body:M.documentElement;x.responseText=u?u.innerHTML:null,x.responseXML=M.XMLDocument?M.XMLDocument:M,o&&(m.dataType="xml"),x.getResponseHeader=function(e){var t={"content-type":m.dataType};return t[e.toLowerCase()]},u&&(x.status=Number(u.getAttribute("status"))||x.status,x.statusText=u.getAttribute("statusText")||x.statusText);var c=(m.dataType||"").toLowerCase(),l=/(json|script|text)/.test(c);if(l||m.textarea){var f=M.getElementsByTagName("textarea")[0];if(f)x.responseText=f.value,x.status=Number(f.getAttribute("status"))||x.status,x.statusText=f.getAttribute("statusText")||x.statusText;else if(l){var p=M.getElementsByTagName("pre")[0],h=M.getElementsByTagName("body")[0];p?x.responseText=p.textContent?p.textContent:p.innerText:h&&(x.responseText=h.textContent?h.textContent:h.innerText)}}else"xml"==c&&!x.responseXML&&x.responseText&&(x.responseXML=X(x.responseText));try{E=_(x,c,m)}catch(y){i="parsererror",x.error=r=y||i}}catch(y){a("error caught: ",y),i="error",x.error=r=y||i}x.aborted&&(a("upload aborted"),i=null),x.status&&(i=x.status>=200&&x.status<300||304===x.status?"success":"error"),"success"===i?(m.success&&m.success.call(m.context,E,"success",x),S.resolve(x.responseText,"success",x),d&&e.event.trigger("ajaxSuccess",[x,m])):i&&(void 0===r&&(r=x.statusText),m.error&&m.error.call(m.context,x,i,r),S.reject(x,"error",r),d&&e.event.trigger("ajaxError",[x,m,r])),d&&e.event.trigger("ajaxComplete",[x,m]),d&&!--e.active&&e.event.trigger("ajaxStop"),m.complete&&m.complete.call(m.context,x,i),F=!0,m.timeout&&clearTimeout(j),setTimeout(function(){m.iframeTarget?v.attr("src",m.iframeSrc):v.remove(),x.responseXML=null},100)}}}var c,l,m,d,p,v,g,x,y,b,T,j,w=f[0],S=e.Deferred();if(S.abort=function(e){x.abort(e)},r)for(l=0;l'),v.css({position:"absolute",top:"-1000px",left:"-1000px"})),g=v[0],x={aborted:0,responseText:null,responseXML:null,status:0,statusText:"n/a",getAllResponseHeaders:function(){},getResponseHeader:function(){},setRequestHeader:function(){},abort:function(t){var r="timeout"===t?"timeout":"aborted";a("aborting upload... "+r),this.aborted=1;try{g.contentWindow.document.execCommand&&g.contentWindow.document.execCommand("Stop")}catch(n){}v.attr("src",m.iframeSrc),x.error=r,m.error&&m.error.call(m.context,x,r,t),d&&e.event.trigger("ajaxError",[x,m,r]),m.complete&&m.complete.call(m.context,x,r)}},d=m.global,d&&0===e.active++&&e.event.trigger("ajaxStart"),d&&e.event.trigger("ajaxSend",[x,m]),m.beforeSend&&m.beforeSend.call(m.context,x,m)===!1)return m.global&&e.active--,S.reject(),S;if(x.aborted)return S.reject(),S;y=w.clk,y&&(b=y.name,b&&!y.disabled&&(m.extraData=m.extraData||{},m.extraData[b]=y.value,"image"==y.type&&(m.extraData[b+".x"]=w.clk_x,m.extraData[b+".y"]=w.clk_y)));var D=1,k=2,A=e("meta[name=csrf-token]").attr("content"),L=e("meta[name=csrf-param]").attr("content");L&&A&&(m.extraData=m.extraData||{},m.extraData[L]=A),m.forceSync?o():setTimeout(o,10);var E,M,F,O=50,X=e.parseXML||function(e,t){return window.ActiveXObject?(t=new ActiveXObject("Microsoft.XMLDOM"),t.async="false",t.loadXML(e)):t=(new DOMParser).parseFromString(e,"text/xml"),t&&t.documentElement&&"parsererror"!=t.documentElement.nodeName?t:null},C=e.parseJSON||function(e){return window.eval("("+e+")")},_=function(t,r,a){var n=t.getResponseHeader("content-type")||"",i="xml"===r||!r&&n.indexOf("xml")>=0,o=i?t.responseXML:t.responseText;return i&&"parsererror"===o.documentElement.nodeName&&e.error&&e.error("parsererror"),a&&a.dataFilter&&(o=a.dataFilter(o,r)),"string"==typeof o&&("json"===r||!r&&n.indexOf("json")>=0?o=C(o):("script"===r||!r&&n.indexOf("javascript")>=0)&&e.globalEval(o)),o};return S}if(!this.length)return a("ajaxSubmit: skipping submit process - no element selected"),this;var u,c,l,f=this;"function"==typeof t?t={success:t}:void 0===t&&(t={}),u=t.type||this.attr2("method"),c=t.url||this.attr2("action"),l="string"==typeof c?e.trim(c):"",l=l||window.location.href||"",l&&(l=(l.match(/^([^#]+)/)||[])[1]),t=e.extend(!0,{url:l,success:e.ajaxSettings.success,type:u||e.ajaxSettings.type,iframeSrc:/^https/i.test(window.location.href||"")?"javascript:false":"about:blank"},t);var m={};if(this.trigger("form-pre-serialize",[this,t,m]),m.veto)return a("ajaxSubmit: submit vetoed via form-pre-serialize trigger"),this;if(t.beforeSerialize&&t.beforeSerialize(this,t)===!1)return a("ajaxSubmit: submit aborted via beforeSerialize callback"),this;var d=t.traditional;void 0===d&&(d=e.ajaxSettings.traditional);var p,h=[],v=this.formToArray(t.semantic,h);if(t.data&&(t.extraData=t.data,p=e.param(t.data,d)),t.beforeSubmit&&t.beforeSubmit(v,this,t)===!1)return a("ajaxSubmit: submit aborted via beforeSubmit callback"),this;if(this.trigger("form-submit-validate",[v,this,t,m]),m.veto)return a("ajaxSubmit: submit vetoed via form-submit-validate trigger"),this;var g=e.param(v,d);p&&(g=g?g+"&"+p:p),"GET"==t.type.toUpperCase()?(t.url+=(t.url.indexOf("?")>=0?"&":"?")+g,t.data=null):t.data=g;var x=[];if(t.resetForm&&x.push(function(){f.resetForm()}),t.clearForm&&x.push(function(){f.clearForm(t.includeHidden)}),!t.dataType&&t.target){var y=t.success||function(){};x.push(function(r){var a=t.replaceTarget?"replaceWith":"html";e(t.target)[a](r).each(y,arguments)})}else t.success&&x.push(t.success);if(t.success=function(e,r,a){for(var n=t.context||this,i=0,o=x.length;o>i;i++)x[i].apply(n,[e,r,a||f,f])},t.error){var b=t.error;t.error=function(e,r,a){var n=t.context||this;b.apply(n,[e,r,a,f])}}if(t.complete){var T=t.complete;t.complete=function(e,r){var a=t.context||this;T.apply(a,[e,r,f])}}var j=e("input[type=file]:enabled",this).filter(function(){return""!==e(this).val()}),w=j.length>0,S="multipart/form-data",D=f.attr("enctype")==S||f.attr("encoding")==S,k=n.fileapi&&n.formdata;a("fileAPI :"+k);var A,L=(w||D)&&!k;t.iframe!==!1&&(t.iframe||L)?t.closeKeepAlive?e.get(t.closeKeepAlive,function(){A=s(v)}):A=s(v):A=(w||D)&&k?o(v):e.ajax(t),f.removeData("jqxhr").data("jqxhr",A);for(var E=0;Ec;c++)if(d=u[c],f=d.name,f&&!d.disabled)if(t&&o.clk&&"image"==d.type)o.clk==d&&(a.push({name:f,value:e(d).val(),type:d.type}),a.push({name:f+".x",value:o.clk_x},{name:f+".y",value:o.clk_y}));else if(m=e.fieldValue(d,!0),m&&m.constructor==Array)for(r&&r.push(d),l=0,h=m.length;h>l;l++)a.push({name:f,value:m[l]});else if(n.fileapi&&"file"==d.type){r&&r.push(d);var v=d.files;if(v.length)for(l=0;li;i++)r.push({name:a,value:n[i]});else null!==n&&"undefined"!=typeof n&&r.push({name:this.name,value:n})}}),e.param(r)},e.fn.fieldValue=function(t){for(var r=[],a=0,n=this.length;n>a;a++){var i=this[a],o=e.fieldValue(i,t);null===o||"undefined"==typeof o||o.constructor==Array&&!o.length||(o.constructor==Array?e.merge(r,o):r.push(o))}return r},e.fieldValue=function(t,r){var a=t.name,n=t.type,i=t.tagName.toLowerCase();if(void 0===r&&(r=!0),r&&(!a||t.disabled||"reset"==n||"button"==n||("checkbox"==n||"radio"==n)&&!t.checked||("submit"==n||"image"==n)&&t.form&&t.form.clk!=t||"select"==i&&-1==t.selectedIndex))return null;if("select"==i){var o=t.selectedIndex;if(0>o)return null;for(var s=[],u=t.options,c="select-one"==n,l=c?o+1:u.length,f=c?o:0;l>f;f++){var m=u[f];if(m.selected){var d=m.value;if(d||(d=m.attributes&&m.attributes.value&&!m.attributes.value.specified?m.text:m.value),c)return d;s.push(d)}}return s}return e(t).val()},e.fn.clearForm=function(t){return this.each(function(){e("input,select,textarea",this).clearFields(t)})},e.fn.clearFields=e.fn.clearInputs=function(t){var r=/^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i;return this.each(function(){var a=this.type,n=this.tagName.toLowerCase();r.test(a)||"textarea"==n?this.value="":"checkbox"==a||"radio"==a?this.checked=!1:"select"==n?this.selectedIndex=-1:"file"==a?/MSIE/.test(navigator.userAgent)?e(this).replaceWith(e(this).clone(!0)):e(this).val(""):t&&(t===!0&&/hidden/.test(a)||"string"==typeof t&&e(this).is(t))&&(this.value="")})},e.fn.resetForm=function(){return this.each(function(){("function"==typeof this.reset||"object"==typeof this.reset&&!this.reset.nodeType)&&this.reset()})},e.fn.enable=function(e){return void 0===e&&(e=!0),this.each(function(){this.disabled=!e})},e.fn.selected=function(t){return void 0===t&&(t=!0),this.each(function(){var r=this.type;if("checkbox"==r||"radio"==r)this.checked=t;else if("option"==this.tagName.toLowerCase()){var a=e(this).parent("select");t&&a[0]&&"select-one"==a[0].type&&a.find("option").selected(!1),this.selected=t}})},e.fn.ajaxSubmit.debug=!1});; (function($,l,n,j,d){var f=$(j),k=[],m=-99999,i=false,o=false,g="waypoint.reached",c={init:function(q,p){this.each(function(){var u=$(this),r=h(u),t=r<0?$.fn[l].defaults:k[r].options,s=$.extend({},t,p);s.offset=s.offset==="bottom-in-view"?function(){return $[n]("viewportHeight")-$(this).outerHeight()}:s.offset;if(r<0)k.push({element:u,offset:u.offset().top,options:s});else k[r].options=s;q&&u.bind(g,q)});$[n]("refresh");return this},remove:function(){return this.each(function(){var p=h($(this));if(p>= 0)k.splice(p,1)})},destroy:function(){return this.unbind(g)[l]("remove")}};function h(q){var p=k.length-1;while(p>=0&&k[p].element[0]!==q[0])p-=1;return p}function b(q,p){q.element.trigger(g,p);if(q.options.triggerOnce)q.element[l]("destroy")}function e(){var q=f.scrollTop(),p=q>m,r=$.grep(k,function(t,s){return p?t.offset>m&&t.offset<=q:t.offset<=m&&t.offset>q});if(!m||!q)$[n]("refresh");m=q;if(!r.length)return;if($[n].settings.continuous)$.each(p?r:r.reverse(),function(t,s){b(s,[p?"down":"up"])}); else b(r[p?r.length-1:0],[p?"down":"up"])}$.fn[l]=function(p){if(c[p])return c[p].apply(this,Array.prototype.slice.call(arguments,1));else if(typeof p==="function"||!p)return c.init.apply(this,arguments);else if(typeof p==="object")return c.init.apply(this,[null,p]);else $.error("Method "+p+" does not exist on jQuery"+l)};$.fn[l].defaults={offset:0,triggerOnce:false};var a={refresh:function(){$.each(k,function(r,t){var p=0,s=t.offset;if(typeof t.options.offset==="function")p=t.options.offset.apply(t.element); else if(typeof t.options.offset==="string")var q=parseFloat(t.options.offset),p=t.options.offset.indexOf("%")?Math.ceil($[n]("viewportHeight")*(q/100)):q;else p=t.options.offset;t.offset=t.element.offset().top-p;if(m>s&&m<=t.offset)b(t,["up"]);else if(m=t.offset)b(t,["down"])});k.sort(function(q,p){return q.offset-p.offset})},viewportHeight:function(){return j.innerHeight?j.innerHeight:f.height()},aggregate:function(){var p=$();$.each(k,function(q,r){p=p.add(r.element)});return p}};$[n]=function(p){if(a[p])return a[p].apply(this); else return a.aggregate()};$[n].settings={continuous:true,resizeThrottle:200,scrollThrottle:100};f.scroll(function(){if(!i){i=true;j.setTimeout(function(){e();i=false},$[n].settings.scrollThrottle)}}).resize(function(){if(!o){o=true;j.setTimeout(function(){$[n]("refresh");o=false},$[n].settings.resizeThrottle)}}).load(function(){$[n]("refresh");e()})})(jQuery,"waypoint","waypoints",this);; (function ($) { /** * Provides Ajax page updating via jQuery $.ajax (Asynchronous JavaScript and XML). * * Ajax is a method of making a request via JavaScript while viewing an HTML * page. The request returns an array of commands encoded in JSON, which is * then executed to make any changes that are necessary to the page. * * Drupal uses this file to enhance form elements with #ajax['path'] and * #ajax['wrapper'] properties. If set, this file will automatically be included * to provide Ajax capabilities. */ Drupal.ajax = Drupal.ajax || {}; Drupal.settings.urlIsAjaxTrusted = Drupal.settings.urlIsAjaxTrusted || {}; /** * Attaches the Ajax behavior to each Ajax form element. */ Drupal.behaviors.AJAX = { attach: function (context, settings) { // Load all Ajax behaviors specified in the settings. for (var base in settings.ajax) { if (!$('#' + base + '.ajax-processed').length) { var element_settings = settings.ajax[base]; if (typeof element_settings.selector == 'undefined') { element_settings.selector = '#' + base; } $(element_settings.selector).each(function () { element_settings.element = this; Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings); }); $('#' + base).addClass('ajax-processed'); } } // Bind Ajax behaviors to all items showing the class. $('.use-ajax:not(.ajax-processed)').addClass('ajax-processed').each(function () { var element_settings = {}; // Clicked links look better with the throbber than the progress bar. element_settings.progress = { 'type': 'throbber' }; // For anchor tags, these will go to the target of the anchor rather // than the usual location. if ($(this).attr('href')) { element_settings.url = $(this).attr('href'); element_settings.event = 'click'; } var base = $(this).attr('id'); Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings); }); // This class means to submit the form to the action using Ajax. $('.use-ajax-submit:not(.ajax-processed)').addClass('ajax-processed').each(function () { var element_settings = {}; // Ajax submits specified in this manner automatically submit to the // normal form action. element_settings.url = $(this.form).attr('action'); // Form submit button clicks need to tell the form what was clicked so // it gets passed in the POST request. element_settings.setClick = true; // Form buttons use the 'click' event rather than mousedown. element_settings.event = 'click'; // Clicked form buttons look better with the throbber than the progress bar. element_settings.progress = { 'type': 'throbber' }; var base = $(this).attr('id'); Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings); }); } }; /** * Ajax object. * * All Ajax objects on a page are accessible through the global Drupal.ajax * object and are keyed by the submit button's ID. You can access them from * your module's JavaScript file to override properties or functions. * * For example, if your Ajax enabled button has the ID 'edit-submit', you can * redefine the function that is called to insert the new content like this * (inside a Drupal.behaviors attach block): * @code * Drupal.behaviors.myCustomAJAXStuff = { * attach: function (context, settings) { * Drupal.ajax['edit-submit'].commands.insert = function (ajax, response, status) { * new_content = $(response.data); * $('#my-wrapper').append(new_content); * alert('New content was appended to #my-wrapper'); * } * } * }; * @endcode */ Drupal.ajax = function (base, element, element_settings) { var defaults = { url: 'system/ajax', event: 'mousedown', keypress: true, selector: '#' + base, effect: 'none', speed: 'none', method: 'replaceWith', progress: { type: 'throbber', message: Drupal.t('Please wait...') }, submit: { 'js': true } }; $.extend(this, defaults, element_settings); this.element = element; this.element_settings = element_settings; // Replacing 'nojs' with 'ajax' in the URL allows for an easy method to let // the server detect when it needs to degrade gracefully. // There are five scenarios to check for: // 1. /nojs/ // 2. /nojs$ - The end of a URL string. // 3. /nojs? - Followed by a query (with clean URLs enabled). // E.g.: path/nojs?destination=foobar // 4. /nojs& - Followed by a query (without clean URLs enabled). // E.g.: ?q=path/nojs&destination=foobar // 5. /nojs# - Followed by a fragment. // E.g.: path/nojs#myfragment this.url = element_settings.url.replace(/\/nojs(\/|$|\?|&|#)/g, '/ajax$1'); // If the 'nojs' version of the URL is trusted, also trust the 'ajax' version. if (Drupal.settings.urlIsAjaxTrusted[element_settings.url]) { Drupal.settings.urlIsAjaxTrusted[this.url] = true; } this.wrapper = '#' + element_settings.wrapper; // If there isn't a form, jQuery.ajax() will be used instead, allowing us to // bind Ajax to links as well. if (this.element.form) { this.form = $(this.element.form); } // Set the options for the ajaxSubmit function. // The 'this' variable will not persist inside of the options object. var ajax = this; ajax.options = { url: ajax.url, data: ajax.submit, beforeSerialize: function (element_settings, options) { return ajax.beforeSerialize(element_settings, options); }, beforeSubmit: function (form_values, element_settings, options) { ajax.ajaxing = true; return ajax.beforeSubmit(form_values, element_settings, options); }, beforeSend: function (xmlhttprequest, options) { ajax.ajaxing = true; return ajax.beforeSend(xmlhttprequest, options); }, success: function (response, status, xmlhttprequest) { // Sanity check for browser support (object expected). // When using iFrame uploads, responses must be returned as a string. if (typeof response == 'string') { response = $.parseJSON(response); } // Prior to invoking the response's commands, verify that they can be // trusted by checking for a response header. See // ajax_set_verification_header() for details. // - Empty responses are harmless so can bypass verification. This avoids // an alert message for server-generated no-op responses that skip Ajax // rendering. // - Ajax objects with trusted URLs (e.g., ones defined server-side via // #ajax) can bypass header verification. This is especially useful for // Ajax with multipart forms. Because IFRAME transport is used, the // response headers cannot be accessed for verification. if (response !== null && !Drupal.settings.urlIsAjaxTrusted[ajax.url]) { if (xmlhttprequest.getResponseHeader('X-Drupal-Ajax-Token') !== '1') { var customMessage = Drupal.t("The response failed verification so will not be processed."); return ajax.error(xmlhttprequest, ajax.url, customMessage); } } return ajax.success(response, status); }, complete: function (xmlhttprequest, status) { ajax.ajaxing = false; if (status == 'error' || status == 'parsererror') { return ajax.error(xmlhttprequest, ajax.url); } }, dataType: 'json', type: 'POST' }; // Bind the ajaxSubmit function to the element event. $(ajax.element).bind(element_settings.event, function (event) { if (!Drupal.settings.urlIsAjaxTrusted[ajax.url] && !Drupal.urlIsLocal(ajax.url)) { throw new Error(Drupal.t('The callback URL is not local and not trusted: !url', {'!url': ajax.url})); } return ajax.eventResponse(this, event); }); // If necessary, enable keyboard submission so that Ajax behaviors // can be triggered through keyboard input as well as e.g. a mousedown // action. if (element_settings.keypress) { $(ajax.element).keypress(function (event) { return ajax.keypressResponse(this, event); }); } // If necessary, prevent the browser default action of an additional event. // For example, prevent the browser default action of a click, even if the // AJAX behavior binds to mousedown. if (element_settings.prevent) { $(ajax.element).bind(element_settings.prevent, false); } }; /** * Handle a key press. * * The Ajax object will, if instructed, bind to a key press response. This * will test to see if the key press is valid to trigger this event and * if it is, trigger it for us and prevent other keypresses from triggering. * In this case we're handling RETURN and SPACEBAR keypresses (event codes 13 * and 32. RETURN is often used to submit a form when in a textfield, and * SPACE is often used to activate an element without submitting. */ Drupal.ajax.prototype.keypressResponse = function (element, event) { // Create a synonym for this to reduce code confusion. var ajax = this; // Detect enter key and space bar and allow the standard response for them, // except for form elements of type 'text' and 'textarea', where the // spacebar activation causes inappropriate activation if #ajax['keypress'] is // TRUE. On a text-type widget a space should always be a space. if (event.which == 13 || (event.which == 32 && element.type != 'text' && element.type != 'textarea')) { $(ajax.element_settings.element).trigger(ajax.element_settings.event); return false; } }; /** * Handle an event that triggers an Ajax response. * * When an event that triggers an Ajax response happens, this method will * perform the actual Ajax call. It is bound to the event using * bind() in the constructor, and it uses the options specified on the * ajax object. */ Drupal.ajax.prototype.eventResponse = function (element, event) { // Create a synonym for this to reduce code confusion. var ajax = this; // Do not perform another ajax command if one is already in progress. if (ajax.ajaxing) { return false; } try { if (ajax.form) { // If setClick is set, we must set this to ensure that the button's // value is passed. if (ajax.setClick) { // Mark the clicked button. 'form.clk' is a special variable for // ajaxSubmit that tells the system which element got clicked to // trigger the submit. Without it there would be no 'op' or // equivalent. element.form.clk = element; } ajax.form.ajaxSubmit(ajax.options); } else { ajax.beforeSerialize(ajax.element, ajax.options); $.ajax(ajax.options); } } catch (e) { // Unset the ajax.ajaxing flag here because it won't be unset during // the complete response. ajax.ajaxing = false; alert("An error occurred while attempting to process " + ajax.options.url + ": " + e.message); } // For radio/checkbox, allow the default event. On IE, this means letting // it actually check the box. if (typeof element.type != 'undefined' && (element.type == 'checkbox' || element.type == 'radio')) { return true; } else { return false; } }; /** * Handler for the form serialization. * * Runs before the beforeSend() handler (see below), and unlike that one, runs * before field data is collected. */ Drupal.ajax.prototype.beforeSerialize = function (element, options) { // Allow detaching behaviors to update field values before collecting them. // This is only needed when field values are added to the POST data, so only // when there is a form such that this.form.ajaxSubmit() is used instead of // $.ajax(). When there is no form and $.ajax() is used, beforeSerialize() // isn't called, but don't rely on that: explicitly check this.form. if (this.form) { var settings = this.settings || Drupal.settings; Drupal.detachBehaviors(this.form, settings, 'serialize'); } // Prevent duplicate HTML ids in the returned markup. // @see drupal_html_id() options.data['ajax_html_ids[]'] = []; $('[id]').each(function () { options.data['ajax_html_ids[]'].push(this.id); }); // Allow Drupal to return new JavaScript and CSS files to load without // returning the ones already loaded. // @see ajax_base_page_theme() // @see drupal_get_css() // @see drupal_get_js() options.data['ajax_page_state[theme]'] = Drupal.settings.ajaxPageState.theme; options.data['ajax_page_state[theme_token]'] = Drupal.settings.ajaxPageState.theme_token; for (var key in Drupal.settings.ajaxPageState.css) { options.data['ajax_page_state[css][' + key + ']'] = 1; } for (var key in Drupal.settings.ajaxPageState.js) { options.data['ajax_page_state[js][' + key + ']'] = 1; } }; /** * Modify form values prior to form submission. */ Drupal.ajax.prototype.beforeSubmit = function (form_values, element, options) { // This function is left empty to make it simple to override for modules // that wish to add functionality here. }; /** * Prepare the Ajax request before it is sent. */ Drupal.ajax.prototype.beforeSend = function (xmlhttprequest, options) { // For forms without file inputs, the jQuery Form plugin serializes the form // values, and then calls jQuery's $.ajax() function, which invokes this // handler. In this circumstance, options.extraData is never used. For forms // with file inputs, the jQuery Form plugin uses the browser's normal form // submission mechanism, but captures the response in a hidden IFRAME. In this // circumstance, it calls this handler first, and then appends hidden fields // to the form to submit the values in options.extraData. There is no simple // way to know which submission mechanism will be used, so we add to extraData // regardless, and allow it to be ignored in the former case. if (this.form) { options.extraData = options.extraData || {}; // Let the server know when the IFRAME submission mechanism is used. The // server can use this information to wrap the JSON response in a TEXTAREA, // as per http://jquery.malsup.com/form/#file-upload. options.extraData.ajax_iframe_upload = '1'; // The triggering element is about to be disabled (see below), but if it // contains a value (e.g., a checkbox, textfield, select, etc.), ensure that // value is included in the submission. As per above, submissions that use // $.ajax() are already serialized prior to the element being disabled, so // this is only needed for IFRAME submissions. var v = $.fieldValue(this.element); if (v !== null) { options.extraData[this.element.name] = Drupal.checkPlain(v); } } // Disable the element that received the change to prevent user interface // interaction while the Ajax request is in progress. ajax.ajaxing prevents // the element from triggering a new request, but does not prevent the user // from changing its value. $(this.element).addClass('progress-disabled').attr('disabled', true); // Insert progressbar or throbber. if (this.progress.type == 'bar') { var progressBar = new Drupal.progressBar('ajax-progress-' + this.element.id, eval(this.progress.update_callback), this.progress.method, eval(this.progress.error_callback)); if (this.progress.message) { progressBar.setProgress(-1, this.progress.message); } if (this.progress.url) { progressBar.startMonitoring(this.progress.url, this.progress.interval || 1500); } this.progress.element = $(progressBar.element).addClass('ajax-progress ajax-progress-bar'); this.progress.object = progressBar; $(this.element).after(this.progress.element); } else if (this.progress.type == 'throbber') { this.progress.element = $('
 
'); if (this.progress.message) { $('.throbber', this.progress.element).after('
' + this.progress.message + '
'); } $(this.element).after(this.progress.element); } }; /** * Handler for the form redirection completion. */ Drupal.ajax.prototype.success = function (response, status) { // Remove the progress element. if (this.progress.element) { $(this.progress.element).remove(); } if (this.progress.object) { this.progress.object.stopMonitoring(); } $(this.element).removeClass('progress-disabled').removeAttr('disabled'); Drupal.freezeHeight(); for (var i in response) { if (response.hasOwnProperty(i) && response[i]['command'] && this.commands[response[i]['command']]) { this.commands[response[i]['command']](this, response[i], status); } } // Reattach behaviors, if they were detached in beforeSerialize(). The // attachBehaviors() called on the new content from processing the response // commands is not sufficient, because behaviors from the entire form need // to be reattached. if (this.form) { var settings = this.settings || Drupal.settings; Drupal.attachBehaviors(this.form, settings); } Drupal.unfreezeHeight(); // Remove any response-specific settings so they don't get used on the next // call by mistake. this.settings = null; }; /** * Build an effect object which tells us how to apply the effect when adding new HTML. */ Drupal.ajax.prototype.getEffect = function (response) { var type = response.effect || this.effect; var speed = response.speed || this.speed; var effect = {}; if (type == 'none') { effect.showEffect = 'show'; effect.hideEffect = 'hide'; effect.showSpeed = ''; } else if (type == 'fade') { effect.showEffect = 'fadeIn'; effect.hideEffect = 'fadeOut'; effect.showSpeed = speed; } else { effect.showEffect = type + 'Toggle'; effect.hideEffect = type + 'Toggle'; effect.showSpeed = speed; } return effect; }; /** * Handler for the form redirection error. */ Drupal.ajax.prototype.error = function (xmlhttprequest, uri, customMessage) { alert(Drupal.ajaxError(xmlhttprequest, uri, customMessage)); // Remove the progress element. if (this.progress.element) { $(this.progress.element).remove(); } if (this.progress.object) { this.progress.object.stopMonitoring(); } // Undo hide. $(this.wrapper).show(); // Re-enable the element. $(this.element).removeClass('progress-disabled').removeAttr('disabled'); // Reattach behaviors, if they were detached in beforeSerialize(). if (this.form) { var settings = this.settings || Drupal.settings; Drupal.attachBehaviors(this.form, settings); } }; /** * Provide a series of commands that the server can request the client perform. */ Drupal.ajax.prototype.commands = { /** * Command to insert new content into the DOM. */ insert: function (ajax, response, status) { // Get information from the response. If it is not there, default to // our presets. var wrapper = response.selector ? $(response.selector) : $(ajax.wrapper); var method = response.method || ajax.method; var effect = ajax.getEffect(response); // We don't know what response.data contains: it might be a string of text // without HTML, so don't rely on jQuery correctly iterpreting // $(response.data) as new HTML rather than a CSS selector. Also, if // response.data contains top-level text nodes, they get lost with either // $(response.data) or $('
').replaceWith(response.data). var new_content_wrapped = $('
').html(response.data); var new_content = new_content_wrapped.contents(); // For legacy reasons, the effects processing code assumes that new_content // consists of a single top-level element. Also, it has not been // sufficiently tested whether attachBehaviors() can be successfully called // with a context object that includes top-level text nodes. However, to // give developers full control of the HTML appearing in the page, and to // enable Ajax content to be inserted in places where DIV elements are not // allowed (e.g., within TABLE, TR, and SPAN parents), we check if the new // content satisfies the requirement of a single top-level element, and // only use the container DIV created above when it doesn't. For more // information, please see http://drupal.org/node/736066. if (new_content.length != 1 || new_content.get(0).nodeType != 1) { new_content = new_content_wrapped; } // If removing content from the wrapper, detach behaviors first. switch (method) { case 'html': case 'replaceWith': case 'replaceAll': case 'empty': case 'remove': var settings = response.settings || ajax.settings || Drupal.settings; Drupal.detachBehaviors(wrapper, settings); } // Add the new content to the page. wrapper[method](new_content); // Immediately hide the new content if we're using any effects. if (effect.showEffect != 'show') { new_content.hide(); } // Determine which effect to use and what content will receive the // effect, then show the new content. if ($('.ajax-new-content', new_content).length > 0) { $('.ajax-new-content', new_content).hide(); new_content.show(); $('.ajax-new-content', new_content)[effect.showEffect](effect.showSpeed); } else if (effect.showEffect != 'show') { new_content[effect.showEffect](effect.showSpeed); } // Attach all JavaScript behaviors to the new content, if it was successfully // added to the page, this if statement allows #ajax['wrapper'] to be // optional. if (new_content.parents('html').length > 0) { // Apply any settings from the returned JSON if available. var settings = response.settings || ajax.settings || Drupal.settings; Drupal.attachBehaviors(new_content, settings); } }, /** * Command to remove a chunk from the page. */ remove: function (ajax, response, status) { var settings = response.settings || ajax.settings || Drupal.settings; Drupal.detachBehaviors($(response.selector), settings); $(response.selector).remove(); }, /** * Command to mark a chunk changed. */ changed: function (ajax, response, status) { if (!$(response.selector).hasClass('ajax-changed')) { $(response.selector).addClass('ajax-changed'); if (response.asterisk) { $(response.selector).find(response.asterisk).append(' * '); } } }, /** * Command to provide an alert. */ alert: function (ajax, response, status) { alert(response.text, response.title); }, /** * Command to provide the jQuery css() function. */ css: function (ajax, response, status) { $(response.selector).css(response.argument); }, /** * Command to set the settings that will be used for other commands in this response. */ settings: function (ajax, response, status) { if (response.merge) { $.extend(true, Drupal.settings, response.settings); } else { ajax.settings = response.settings; } }, /** * Command to attach data using jQuery's data API. */ data: function (ajax, response, status) { $(response.selector).data(response.name, response.value); }, /** * Command to apply a jQuery method. */ invoke: function (ajax, response, status) { var $element = $(response.selector); $element[response.method].apply($element, response.arguments); }, /** * Command to restripe a table. */ restripe: function (ajax, response, status) { // :even and :odd are reversed because jQuery counts from 0 and // we count from 1, so we're out of sync. // Match immediate children of the parent element to allow nesting. $('> tbody > tr:visible, > tr:visible', $(response.selector)) .removeClass('odd even') .filter(':even').addClass('odd').end() .filter(':odd').addClass('even'); }, /** * Command to add css. * * Uses the proprietary addImport method if available as browsers which * support that method ignore @import statements in dynamically added * stylesheets. */ add_css: function (ajax, response, status) { // Add the styles in the normal way. $('head').prepend(response.data); // Add imports in the styles using the addImport method if available. var match, importMatch = /^@import url\("(.*)"\);$/igm; if (document.styleSheets[0].addImport && importMatch.test(response.data)) { importMatch.lastIndex = 0; while (match = importMatch.exec(response.data)) { document.styleSheets[0].addImport(match[1]); } } }, /** * Command to update a form's build ID. */ updateBuildId: function(ajax, response, status) { $('input[name="form_build_id"][value="' + response['old'] + '"]').val(response['new']); } }; })(jQuery); ; (function (D) { var beforeSerialize = D.ajax.prototype.beforeSerialize; D.ajax.prototype.beforeSerialize = function (element, options) { beforeSerialize.call(this, element, options); options.data['ajax_page_state[jquery_version]'] = D.settings.ajaxPageState.jquery_version; } })(Drupal); ;