1var gsb = gsb || {}; 2 /* Start variables_LABELS */ 3 var PRINT_PAGE_TEXT = 'drucken'; 4 var PRINT_TOOLTIP = 'Seite drucken (öffnet Dialog)'; 5 var PRINT_BUTTON_TEXT = 'Datenblatt drucken'; 6 var PRINT_BUTTON_TOOLTIP = 'Datenblatt drucken (öffnet Dialog)'; 7 var TWOCLICKSHARE_TITLE = 'Inhalte teilen'; 8 var TWOCLICKSHARE_FORMLINKTEXT = 'Freunden per E-Mail schicken'; 9 var NAV_MOBILE_MENU = 'Menü'; 10 var NAV_MOBILE_SEARCH = 'Suchen'; 11 var SHOW_LESS = 'Weniger anzeigen'; 12 var SHOW_MORE = 'Mehr anzeigen'; 13 var SHOW_LESS_ARTICLE = 'Schließen'; 14 var SHOW_MORE_ARTICLE = 'weiterlesen'; 15 var CLOSE = 'Schließen'; 16 var NEXT = 'Nächste Seite'; 17 var BACK = 'Vorherige Seite'; 18 var NEXT_INACTIVE = 'Keine nächste Seite'; 19 var BACK_INACTIVE = 'Keine vorherige Seite'; 20 var PLAY = 'Animation starten'; 21 var PAUSE = 'Animation stoppen'; 22 var PAGE = 'Seite'; 23 var MOBILE_AURAL = 'Mobiles Menü'; 24 var FIRST_BACK = 'zurück'; 25 var BACK_BUTTON = 'zurück'; 26 var BACKTOFIRST_BUTTON = 'zurück zu'; 27 var HIDE_TD = 'Spalte ausblenden'; 28 var PAGELINK = 'Zur Ãbersicht'; 29 var DATEPICKER_TEXT = 'Datum auswählen'; 30 31 /* Ende variables_LABELS */ 32 /* Start variables_IMG */ 33 var image_url_next = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/forward_active.svg?__blob=normal&v=1'; 34 var image_url_back = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/back_active.svg?__blob=normal&v=1'; 35 var image_url_back_g = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/back_inactive.svg?__blob=normal&v=1'; 36 var image_url_next_g = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/forward_inactive.svg?__blob=normal&v=1'; 37 var image_url_paused = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/pause.png?__blob=normal&v=1'; 38 var image_url_play = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/play.svg?__blob=normal&v=1'; 39 var image_url_mobile_back_button = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/navigation_back.svg?__blob=normal&v=1'; 40 var image_url_mobile_backtofirst_button = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/navigation_backtofirst.svg?__blob=normal&v=1'; 41 var image_url_hide_td = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/hide_td.svg?__blob=normal&v=1'; 42 var image_url_calendar = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/calendar.svg?__blob=normal&v=1'; 43 var image_url_logo_scrolled = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/logo-ohneuntertitel.svg?__blob=normal&v=1'; 44 var image_url_mejs_controls = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/Images/icons/mediaelement/mejs-controls.svg?__blob=normal&v=2'; 45 46 /* Ende variables_IMG */ 47 /* Start variables_JSON */ 48 var json_url_mobileMenu = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Modules/MobileNavigation/DE/MobileNavigation?view=renderMobileNavigation'; 49 var json_url_mobileSearch = 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Forms/Suche/DE/Servicesuche_Autosuggest_Formular?view=renderJSON'; 50 51 /* Ende variables_JSON */ 52gsb.jsComponents = { 53 config: {}, 54 definitions: { 55 bundle_multimedia: { 56 scriptList: [ 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Frontend/JavaScript/init/bundle_multimedia.js?v=2' ] 57 }, 58 } 59}; 60 /* Start custom.modernizr */ 61 /*! Modernizr 2.6.2 (Custom Build) | MIT & BSD 62 * Build: http://modernizr.com/download/#-inlinesvg-svg-svgclippaths-touch-shiv-mq-cssclasses-teststyles-prefixes-ie8compat-load 63 */ 64; 65window.Modernizr = function(a, b, c) { 66 function y(a) { 67 j.cssText = a 68 } 69 70 function z(a, b) { 71 return y(m.join(a + ";") + (b || "")) 72 } 73 74 function A(a, b) { 75 return typeof a === b 76 } 77 78 function B(a, b) {
vendor: 6,574 bytes, lines 79-215
79 return !!~("" + a).indexOf(b) 80 } 81 82 function C(a, b, d) { 83 for (var e in a) { 84 var f = b[a[e]]; 85 if (f !== c) return d === !1 ? a[e] : A(f, "function") ? f.bind(d || b) : f 86 } 87 return !1 88 } 89 var d = "2.6.2", 90 e = {}, 91 f = !0, 92 g = b.documentElement, 93 h = "modernizr", 94 i = b.createElement(h), 95 j = i.style, 96 k, l = {}.toString, 97 m = " -webkit- -moz- -o- -ms- ".split(" "), 98 n = { 99 svg: "http://www.w3.org/2000/svg" 100 }, 101 o = {}, 102 p = {}, 103 q = {}, 104 r = [], 105 s = r.slice, 106 t, u = function(a, c, d, e) { 107 var f, i, j, k, l = b.createElement("div"), 108 m = b.body, 109 n = m || b.createElement("body"); 110 if (parseInt(d, 10)) 111 while (d--) j = b.createElement("div"), j.id = e ? e[d] : h + (d + 1), l.appendChild(j); 112 return f = ["­", '<style id="s', h, '">', a, "</style>"].join(""), l.id = h, (m ? l : n).innerHTML += f, n.appendChild(l), m || (n.style.background = "", n.style.overflow = "hidden", k = g.style.overflow, g.style.overflow = "hidden", g.appendChild(n)), i = c(l, a), m ? l.parentNode.removeChild(l) : (n.parentNode.removeChild(n), g.style.overflow = k), !!i 113 }, 114 v = function(b) { 115 var c = a.matchMedia || a.msMatchMedia; 116 if (c) return c(b).matches; 117 var d; 118 return u("@media " + b + " { #" + h + " { position: absolute; } }", function(b) { 119 d = (a.getComputedStyle ? getComputedStyle(b, null) : b.currentStyle)["position"] == "absolute" 120 }), d 121 }, 122 w = {}.hasOwnProperty, 123 x; 124 !A(w, "undefined") && !A(w.call, "undefined") ? x = function(a, b) { 125 return w.call(a, b) 126 } : x = function(a, b) { 127 return b in a && A(a.constructor.prototype[b], "undefined") 128 }, Function.prototype.bind || (Function.prototype.bind = function(b) { 129 var c = this; 130 if (typeof c != "function") throw new TypeError; 131 var d = s.call(arguments, 1), 132 e = function() { 133 if (this instanceof e) { 134 var a = function() {}; 135 a.prototype = c.prototype; 136 var f = new a, 137 g = c.apply(f, d.concat(s.call(arguments))); 138 return Object(g) === g ? g : f 139 } 140 return c.apply(b, d.concat(s.call(arguments))) 141 }; 142 return e 143 }), o.touch = function() { 144 var c; 145 return "ontouchstart" in a || a.DocumentTouch && b instanceof DocumentTouch ? c = !0 : u(["@media (", m.join("touch-enabled),("), h, ")", "{#modernizr{top:9px;position:absolute}}"].join(""), function(a) { 146 c = a.offsetTop === 9 147 }), c 148 }, o.svg = function() { 149 return !!b.createElementNS && !!b.createElementNS(n.svg, "svg").createSVGRect 150 }, o.inlinesvg = function() { 151 var a = b.createElement("div"); 152 return a.innerHTML = "<svg/>", (a.firstChild && a.firstChild.namespaceURI) == n.svg 153 }, o.svgclippaths = function() { 154 return !!b.createElementNS && /SVGClipPath/.test(l.call(b.createElementNS(n.svg, "clipPath"))) 155 }; 156 for (var D in o) x(o, D) && (t = D.toLowerCase(), e[t] = o[D](), r.push((e[t] ? "" : "no-") + t)); 157 return e.addTest = function(a, b) { 158 if (typeof a == "object") 159 for (var d in a) x(a, d) && e.addTest(d, a[d]); 160 else { 161 a = a.toLowerCase(); 162 if (e[a] !== c) return e; 163 b = typeof b == "function" ? b() : b, typeof f != "undefined" && f && (g.className += " " + (b ? "" : "no-") + a), e[a] = b 164 } 165 return e 166 }, y(""), i = k = null, 167 function(a, b) { 168 function k(a, b) { 169 var c = a.createElement("p"), 170 d = a.getElementsByTagName("head")[0] || a.documentElement; 171 return c.innerHTML = "x<style>" + b + "</style>", d.insertBefore(c.lastChild, d.firstChild) 172 } 173 174 function l() { 175 var a = r.elements; 176 return typeof a == "string" ? a.split(" ") : a 177 } 178 179 function m(a) { 180 var b = i[a[g]]; 181 return b || (b = {}, h++, a[g] = h, i[h] = b), b 182 } 183 184 function n(a, c, f) { 185 c || (c = b); 186 if (j) return c.createElement(a); 187 f || (f = m(c)); 188 var g; 189 return f.cache[a] ? g = f.cache[a].cloneNode() : e.test(a) ? g = (f.cache[a] = f.createElem(a)).cloneNode() : g = f.createElem(a), g.canHaveChildren && !d.test(a) ? f.frag.appendChild(g) : g 190 } 191 192 function o(a, c) { 193 a || (a = b); 194 if (j) return a.createDocumentFragment(); 195 c = c || m(a); 196 var d = c.frag.cloneNode(), 197 e = 0, 198 f = l(), 199 g = f.length; 200 for (; e < g; e++) d.createElement(f[e]); 201 return d 202 } 203 204 function p(a, b) { 205 b.cache || (b.cache = {}, b.createElem = a.createElement, b.createFrag = a.createDocumentFragment, b.frag = b.createFrag()), a.createElement = function(c) { 206 return r.shivMethods ? n(c, a, b) : b.createElem(c) 207 }, a.createDocumentFragment = Function("h,f", "return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&(" + l().join().replace(/\w+/g, function(a) { 208 return b.createElem(a), b.frag.createElement(a), 'c("' + a + '")' 209 }) + ");return n}")(r, b.frag) 210 } 211 212 function q(a) { 213 a || (a = b); 214 var c = m(a); 215 return r.shivCSS && !f && !c.hasCSS && (c.hasCSS = !!k(a, "article,aside,figcaption,figure,footer,header,hgroup,nav,section{dis
vendor: 12,571 bytes, lines 215-544
215play:block}mark{background:#FF0;color:#000}")), j || p(a, c), a 216 } 217 var c = a.html5 || {}, 218 d = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i, 219 e = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i, 220 f, g = "_html5shiv", 221 h = 0, 222 i = {}, 223 j; 224 (function() { 225 try { 226 var a = b.createElement("a"); 227 a.innerHTML = "<xyz></xyz>", f = "hidden" in a, j = a.childNodes.length == 1 || function() { 228 b.createElement("a"); 229 var a = b.createDocumentFragment(); 230 return typeof a.cloneNode == "undefined" || typeof a.createDocumentFragment == "undefined" || typeof a.createElement == "undefined" 231 }() 232 } catch (c) { 233 f = !0, j = !0 234 } 235 })(); 236 var r = { 237 elements: c.elements || "abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video", 238 shivCSS: c.shivCSS !== !1, 239 supportsUnknownElements: j, 240 shivMethods: c.shivMethods !== !1, 241 type: "default", 242 shivDocument: q, 243 createElement: n, 244 createDocumentFragment: o 245 }; 246 a.html5 = r, q(b) 247 }(this, b), e._version = d, e._prefixes = m, e.mq = v, e.testStyles = u, g.className = g.className.replace(/(^|\s)no-js(\s|$)/, "$1$2") + (f ? " js " + r.join(" ") : ""), e 248 }(this, this.document), 249 function(a, b, c) { 250 function d(a) { 251 return "[object Function]" == o.call(a) 252 } 253 254 function e(a) { 255 return "string" == typeof a 256 } 257 258 function f() {} 259 260 function g(a) { 261 return !a || "loaded" == a || "complete" == a || "uninitialized" == a 262 } 263 264 function h() { 265 var a = p.shift(); 266 q = 1, a ? a.t ? m(function() { 267 ("c" == a.t ? B.injectCss : B.injectJs)(a.s, 0, a.a, a.x, a.e, 1) 268 }, 0) : (a(), h()) : q = 0 269 } 270 271 function i(a, c, d, e, f, i, j) { 272 function k(b) { 273 if (!o && g(l.readyState) && (u.r = o = 1, !q && h(), l.onload = l.onreadystatechange = null, b)) { 274 "img" != a && m(function() { 275 t.removeChild(l) 276 }, 50); 277 for (var d in y[c]) y[c].hasOwnProperty(d) && y[c][d].onload() 278 } 279 } 280 var j = j || B.errorTimeout, 281 l = b.createElement(a), 282 o = 0, 283 r = 0, 284 u = { 285 t: d, 286 s: c, 287 e: f, 288 a: i, 289 x: j 290 }; 291 1 === y[c] && (r = 1, y[c] = []), "object" == a ? l.data = c : (l.src = c, l.type = a), l.width = l.height = "0", l.onerror = l.onload = l.onreadystatechange = function() { 292 k.call(this, r) 293 }, p.splice(e, 0, u), "img" != a && (r || 2 === y[c] ? (t.insertBefore(l, s ? null : n), m(k, j)) : y[c].push(l)) 294 } 295 296 function j(a, b, c, d, f) { 297 return q = 0, b = b || "j", e(a) ? i("c" == b ? v : u, a, b, this.i++, c, d, f) : (p.splice(this.i++, 0, a), 1 == p.length && h()), this 298 } 299 300 function k() { 301 var a = B; 302 return a.loader = { 303 load: j, 304 i: 0 305 }, a 306 } 307 var l = b.documentElement, 308 m = a.setTimeout, 309 n = b.getElementsByTagName("script")[0], 310 o = {}.toString, 311 p = [], 312 q = 0, 313 r = "MozAppearance" in l.style, 314 s = r && !!b.createRange().compareNode, 315 t = s ? l : n.parentNode, 316 l = a.opera && "[object Opera]" == o.call(a.opera), 317 l = !!b.attachEvent && !l, 318 u = r ? "object" : l ? "script" : "img", 319 v = l ? "script" : u, 320 w = Array.isArray || function(a) { 321 return "[object Array]" == o.call(a) 322 }, 323 x = [], 324 y = {}, 325 z = { 326 timeout: function(a, b) { 327 return b.length && (a.timeout = b[0]), a 328 } 329 }, 330 A, B; 331 B = function(a) { 332 function b(a) { 333 var a = a.split("!"), 334 b = x.length, 335 c = a.pop(), 336 d = a.length, 337 c = { 338 url: c, 339 origUrl: c, 340 prefixes: a 341 }, 342 e, f, g; 343 for (f = 0; f < d; f++) g = a[f].split("="), (e = z[g.shift()]) && (c = e(c, g)); 344 for (f = 0; f < b; f++) c = x[f](c); 345 return c 346 } 347 348 function g(a, e, f, g, h) { 349 var i = b(a), 350 j = i.autoCallback; 351 i.url.split(".").pop().split("?").shift(), i.bypass || (e && (e = d(e) ? e : e[a] || e[g] || e[a.split("/").pop().split("?")[0]]), i.instead ? i.instead(a, e, f, g, h) : (y[i.url] ? i.noexec = !0 : y[i.url] = 1, f.load(i.url, i.forceCSS || !i.forceJS && "css" == i.url.split(".").pop().split("?").shift() ? "c" : c, i.noexec, i.attrs, i.timeout), (d(e) || d(j)) && f.load(function() { 352 k(), e && e(i.origUrl, h, g), j && j(i.origUrl, h, g), y[i.url] = 2 353 }))) 354 } 355 356 function h(a, b) { 357 function c(a, c) { 358 if (a) { 359 if (e(a)) c || (j = function() { 360 var a = [].slice.call(arguments); 361 k.apply(this, a), l() 362 }), g(a, j, b, 0, h); 363 else if (Object(a) === a) 364 for (n in m = function() { 365 var b = 0, 366 c; 367 for (c in a) a.hasOwnProperty(c) && b++; 368 return b 369 }(), a) a.hasOwnProperty(n) && (!c && !--m && (d(j) ? j = function() { 370 var a = [].slice.call(arguments); 371 k.apply(this, a), l() 372 } : j[n] = function(a) { 373 return function() { 374 var b = [].slice.call(arguments); 375 a && a.apply(this, b), l() 376 } 377 }(k[n])), g(a[n], j, b, n, h)) 378 } else !c && l() 379 } 380 var h = !!a.test, 381 i = a.load || a.both, 382 j = a.callback || f, 383 k = j, 384 l = a.complete || f, 385 m, n; 386 c(h ? a.yep : a.nope, !!i), i && c(i) 387 } 388 var i, j, l = this.yepnope.loader; 389 if (e(a)) g(a, 0, l, 0); 390 else if (w(a)) 391 for (i = 0; i < a.length; i++) j = a[i], e(j) ? g(j, 0, l, 0) : w(j) ? B(j) : Object(j) === j && h(j, l); 392 else Object(a) === a && h(a, l) 393 }, B.addPrefix = function(a, b) { 394 z[a] = b 395 }, B.addFilter = function(a) { 396 x.push(a) 397 }, B.errorTimeout = 1e4, null == b.readyState && b.addEventListener && (b.readyState = "loading", b.addEventListener("DOMContentLoaded", A = function() { 398 b.removeEventListener("DOMContentLoaded", A, 0), b.readyState = "complete" 399 }, 0)), a.yepnope = k(), a.yepnope.executeStack = h, a.yepnope.injectJs = function(a, c, d, e, i, j) { 400 var k = b.createElement("script"), 401 l, o, e = e || B.errorTimeout; 402 k.src = a; 403 for (o in d) k.setAttribute(o, d[o]); 404 c = j ? h : c || f, k.onreadystatechange = k.onload = function() { 405 !l && g(k.readyState) && (l = 1, c(), k.onload = k.onreadystatechange = null) 406 }, m(function() { 407 l || (l = 1, c(1)) 408 }, e), i ? k.onload() : n.parentNode.insertBefore(k, n) 409 }, a.yepnope.injectCss = function(a, c, d, e, g, i) { 410 var e = b.createElement("link"), 411 j, c = i ? h : c || f; 412 e.href = a, e.rel = "stylesheet", e.type = "text/css"; 413 for (j in d) e.setAttribute(j, d[j]); 414 g || (n.parentNode.insertBefore(e, n), m(c, 0)) 415 } 416 }(this, document), Modernizr.load = function() { 417 yepnope.apply(window, [].slice.call(arguments, 0)) 418 }, Modernizr.addTest("ie8compat", function() { 419 return !window.addEventListener && document.documentMode && document.documentMode === 7 420 }); 421 /* Ende custom.modernizr */ 422 /* Start jquery */ 423 /*! 424 * jQuery JavaScript Library v1.11.1 425 * http://jquery.com/ 426 * 427 * Includes Sizzle.js 428 * http://sizzlejs.com/ 429 * 430 * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors 431 * Released under the MIT license 432 * http://jquery.org/license 433 * 434 * Date: 2014-05-01T17:42Z 435 */ 436 437(function( global, factory ) { 438 439 if ( typeof module === "object" && typeof module.exports === "object" ) { 440 // For CommonJS and CommonJS-like environments where a proper window is present, 441 // execute the factory and get jQuery 442 // For environments that do not inherently posses a window with a document 443 // (such as Node.js), expose a jQuery-making factory as module.exports 444 // This accentuates the need for the creation of a real window 445 // e.g. var jQuery = require("jquery")(window); 446 // See ticket #14549 for more info 447 module.exports = global.document ? 448 factory( global, true ) : 449 function( w ) { 450 if ( !w.document ) { 451 throw new Error( "jQuery requires a window with a document" ); 452 } 453 return factory( w ); 454 }; 455 } else { 456 factory( global ); 457 } 458 459// Pass this if window is not defined yet 460}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { 461 462// Can't do this because several apps including ASP.NET trace 463// the stack via arguments.caller.callee and Firefox dies if 464// you try to trace through "use strict" call chains. (#13335) 465// Support: Firefox 18+ 466// 467 468var deletedIds = []; 469 470var slice = deletedIds.slice; 471 472var concat = deletedIds.concat; 473 474var push = deletedIds.push; 475 476var indexOf = deletedIds.indexOf; 477 478var class2type = {}; 479 480var toString = class2type.toString; 481 482var hasOwn = class2type.hasOwnProperty; 483 484var support = {}; 485 486var 487 version = "1.11.1", 488 489 // Define a local copy of jQuery 490 jQuery = function( selector, context ) { 491 // The jQuery object is actually just the init constructor 'enhanced' 492 // Need init if jQuery is called (just allow error to be thrown if not included) 493 return new jQuery.fn.init( selector, context ); 494 }, 495 496 // Support: Android<4.1, IE<9 497 // Make sure we trim BOM and NBSP 498 rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, 499 500 // Matches dashed string for camelizing 501 rmsPrefix = /^-ms-/, 502 rdashAlpha = /-([\da-z])/gi, 503 504 // Used by jQuery.camelCase as callback to replace() 505 fcamelCase = function( all, letter ) { 506 return letter.toUpperCase(); 507 }; 508 509jQuery.fn = jQuery.prototype = { 510 // The current version of jQuery being used 511 jquery: version, 512 513 constructor: jQuery, 514 515 // Start with an empty selector 516 selector: "", 517 518 // The default length of a jQuery object is 0 519 length: 0, 520 521 toArray: function() { 522 return slice.call( this ); 523 }, 524 525 // Get the Nth element in the matched element set OR 526 // Get the whole matched element set as a clean array 527 get: function( num ) { 528 return num != null ? 529 530 // Return just the one element from the set 531 ( num < 0 ? this[ num + this.length ] : this[ num ] ) : 532 533 // Return all the elements in a clean array 534 slice.call( this ); 535 }, 536 537 // Take an array of elements and push it onto the stack 538 // (returning the new matched element set) 539 pushStack: function( elems ) { 540 541 // Build a new jQuery matched element set 542 var ret = jQuery.merge( this.constructor(), elems ); 543 544 // Add the old object onto the stack (as a reference)
vendor: 278,655 bytes, lines 545-10591
545 ret.prevObject = this; 546 ret.context = this.context; 547 548 // Return the newly-formed element set 549 return ret; 550 }, 551 552 // Execute a callback for every element in the matched set. 553 // (You can seed the arguments with an array of args, but this is 554 // only used internally.) 555 each: function( callback, args ) { 556 return jQuery.each( this, callback, args ); 557 }, 558 559 map: function( callback ) { 560 return this.pushStack( jQuery.map(this, function( elem, i ) { 561 return callback.call( elem, i, elem ); 562 })); 563 }, 564 565 slice: function() { 566 return this.pushStack( slice.apply( this, arguments ) ); 567 }, 568 569 first: function() { 570 return this.eq( 0 ); 571 }, 572 573 last: function() { 574 return this.eq( -1 ); 575 }, 576 577 eq: function( i ) { 578 var len = this.length, 579 j = +i + ( i < 0 ? len : 0 ); 580 return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); 581 }, 582 583 end: function() { 584 return this.prevObject || this.constructor(null); 585 }, 586 587 // For internal use only. 588 // Behaves like an Array's method, not like a jQuery method. 589 push: push, 590 sort: deletedIds.sort, 591 splice: deletedIds.splice 592}; 593 594jQuery.extend = jQuery.fn.extend = function() { 595 var src, copyIsArray, copy, name, options, clone, 596 target = arguments[0] || {}, 597 i = 1, 598 length = arguments.length, 599 deep = false; 600 601 // Handle a deep copy situation 602 if ( typeof target === "boolean" ) { 603 deep = target; 604 605 // skip the boolean and the target 606 target = arguments[ i ] || {}; 607 i++; 608 } 609 610 // Handle case when target is a string or something (possible in deep copy) 611 if ( typeof target !== "object" && !jQuery.isFunction(target) ) { 612 target = {}; 613 } 614 615 // extend jQuery itself if only one argument is passed 616 if ( i === length ) { 617 target = this; 618 i--; 619 } 620 621 for ( ; i < length; i++ ) { 622 // Only deal with non-null/undefined values 623 if ( (options = arguments[ i ]) != null ) { 624 // Extend the base object 625 for ( name in options ) { 626 src = target[ name ]; 627 copy = options[ name ]; 628 629 // Prevent never-ending loop 630 if ( target === copy ) { 631 continue; 632 } 633 634 // Recurse if we're merging plain objects or arrays 635 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { 636 if ( copyIsArray ) { 637 copyIsArray = false; 638 clone = src && jQuery.isArray(src) ? src : []; 639 640 } else { 641 clone = src && jQuery.isPlainObject(src) ? src : {}; 642 } 643 644 // Never move original objects, clone them 645 target[ name ] = jQuery.extend( deep, clone, copy ); 646 647 // Don't bring in undefined values 648 } else if ( copy !== undefined ) { 649 target[ name ] = copy; 650 } 651 } 652 } 653 } 654 655 // Return the modified object 656 return target; 657}; 658 659jQuery.extend({ 660 // Unique for each copy of jQuery on the page 661 expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), 662 663 // Assume jQuery is ready without the ready module 664 isReady: true, 665 666 error: function( msg ) { 667 throw new Error( msg ); 668 }, 669 670 noop: function() {}, 671 672 // See test/unit/core.js for details concerning isFunction. 673 // Since version 1.3, DOM methods and functions like alert 674 // aren't supported. They return false on IE (#2968). 675 isFunction: function( obj ) { 676 return jQuery.type(obj) === "function"; 677 }, 678 679 isArray: Array.isArray || function( obj ) { 680 return jQuery.type(obj) === "array"; 681 }, 682 683 isWindow: function( obj ) { 684 /* jshint eqeqeq: false */ 685 return obj != null && obj == obj.window; 686 }, 687 688 isNumeric: function( obj ) { 689 // parseFloat NaNs numeric-cast false positives (null|true|false|"") 690 // ...but misinterprets leading-number strings, particularly hex literals ("0x...") 691 // subtraction forces infinities to NaN 692 return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0; 693 }, 694 695 isEmptyObject: function( obj ) { 696 var name; 697 for ( name in obj ) { 698 return false; 699 } 700 return true; 701 }, 702 703 isPlainObject: function( obj ) { 704 var key; 705 706 // Must be an Object. 707 // Because of IE, we also have to check the presence of the constructor property. 708 // Make sure that DOM nodes and window objects don't pass through, as well 709 if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { 710 return false; 711 } 712 713 try { 714 // Not own constructor property must be Object 715 if ( obj.constructor && 716 !hasOwn.call(obj, "constructor") && 717 !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { 718 return false; 719 } 720 } catch ( e ) { 721 // IE8,9 Will throw exceptions on certain host objects #9897 722 return false; 723 } 724 725 // Support: IE<9 726 // Handle iteration over inherited properties before own properties. 727 if ( support.ownLast ) { 728 for ( key in obj ) { 729 return hasOwn.call( obj, key ); 730 } 731 } 732 733 // Own properties are enumerated firstly, so to speed up, 734 // if last one is own, then all properties are own. 735 for ( key in obj ) {} 736 737 return key === undefined || hasOwn.call( obj, key ); 738 }, 739 740 type: function( obj ) { 741 if ( obj == null ) { 742 return obj + ""; 743 } 744 return typeof obj === "object" || typeof obj === "function" ? 745 class2type[ toString.call(obj) ] || "object" : 746 typeof obj; 747 }, 748 749 // Evaluates a script in a global context 750 // Workarounds based on findings by Jim Driscoll 751 // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context 752 globalEval: function( data ) { 753 if ( data && jQuery.trim( data ) ) { 754 // We use execScript on Internet Explorer 755 // We use an anonymous function so that context is window 756 // rather than jQuery in Firefox 757 ( window.execScript || function( data ) { 758 window[ "eval" ].call( window, data ); 759 } )( data ); 760 } 761 }, 762 763 // Convert dashed to camelCase; used by the css and data modules 764 // Microsoft forgot to hump their vendor prefix (#9572) 765 camelCase: function( string ) { 766 return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); 767 }, 768 769 nodeName: function( elem, name ) { 770 return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); 771 }, 772 773 // args is for internal usage only 774 each: function( obj, callback, args ) { 775 var value, 776 i = 0, 777 length = obj.length, 778 isArray = isArraylike( obj ); 779 780 if ( args ) { 781 if ( isArray ) { 782 for ( ; i < length; i++ ) { 783 value = callback.apply( obj[ i ], args ); 784 785 if ( value === false ) { 786 break; 787 } 788 } 789 } else { 790 for ( i in obj ) { 791 value = callback.apply( obj[ i ], args ); 792 793 if ( value === false ) { 794 break; 795 } 796 } 797 } 798 799 // A special, fast, case for the most common use of each 800 } else { 801 if ( isArray ) { 802 for ( ; i < length; i++ ) { 803 value = callback.call( obj[ i ], i, obj[ i ] ); 804 805 if ( value === false ) { 806 break; 807 } 808 } 809 } else { 810 for ( i in obj ) { 811 value = callback.call( obj[ i ], i, obj[ i ] ); 812 813 if ( value === false ) { 814 break; 815 } 816 } 817 } 818 } 819 820 return obj; 821 }, 822 823 // Support: Android<4.1, IE<9 824 trim: function( text ) { 825 return text == null ? 826 "" : 827 ( text + "" ).replace( rtrim, "" ); 828 }, 829 830 // results is for internal usage only 831 makeArray: function( arr, results ) { 832 var ret = results || []; 833 834 if ( arr != null ) { 835 if ( isArraylike( Object(arr) ) ) { 836 jQuery.merge( ret, 837 typeof arr === "string" ? 838 [ arr ] : arr 839 ); 840 } else { 841 push.call( ret, arr ); 842 } 843 } 844 845 return ret; 846 }, 847 848 inArray: function( elem, arr, i ) { 849 var len; 850 851 if ( arr ) { 852 if ( indexOf ) { 853 return indexOf.call( arr, elem, i ); 854 } 855 856 len = arr.length; 857 i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; 858 859 for ( ; i < len; i++ ) { 860 // Skip accessing in sparse arrays 861 if ( i in arr && arr[ i ] === elem ) { 862 return i; 863 } 864 } 865 } 866 867 return -1; 868 }, 869 870 merge: function( first, second ) { 871 var len = +second.length, 872 j = 0, 873 i = first.length; 874 875 while ( j < len ) { 876 first[ i++ ] = second[ j++ ]; 877 } 878 879 // Support: IE<9 880 // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists) 881 if ( len !== len ) { 882 while ( second[j] !== undefined ) { 883 first[ i++ ] = second[ j++ ]; 884 } 885 } 886 887 first.length = i; 888 889 return first; 890 }, 891 892 grep: function( elems, callback, invert ) { 893 var callbackInverse, 894 matches = [], 895 i = 0, 896 length = elems.length, 897 callbackExpect = !invert; 898 899 // Go through the array, only saving the items 900 // that pass the validator function 901 for ( ; i < length; i++ ) { 902 callbackInverse = !callback( elems[ i ], i ); 903 if ( callbackInverse !== callbackExpect ) { 904 matches.push( elems[ i ] ); 905 } 906 } 907 908 return matches; 909 }, 910 911 // arg is for internal usage only 912 map: function( elems, callback, arg ) { 913 var value, 914 i = 0, 915 length = elems.length, 916 isArray = isArraylike( elems ), 917 ret = []; 918 919 // Go through the array, translating each of the items to their new values 920 if ( isArray ) { 921 for ( ; i < length; i++ ) { 922 value = callback( elems[ i ], i, arg ); 923 924 if ( value != null ) { 925 ret.push( value ); 926 } 927 } 928 929 // Go through every key on the object, 930 } else { 931 for ( i in elems ) { 932 value = callback( elems[ i ], i, arg ); 933 934 if ( value != null ) { 935 ret.push( value ); 936 } 937 } 938 } 939 940 // Flatten any nested arrays 941 return concat.apply( [], ret ); 942 }, 943 944 // A global GUID counter for objects 945 guid: 1, 946 947 // Bind a function to a context, optionally partially applying any 948 // arguments. 949 proxy: function( fn, context ) { 950 var args, proxy, tmp; 951 952 if ( typeof context === "string" ) { 953 tmp = fn[ context ]; 954 context = fn; 955 fn = tmp; 956 } 957 958 // Quick check to determine if target is callable, in the spec 959 // this throws a TypeError, but we will just return undefined. 960 if ( !jQuery.isFunction( fn ) ) { 961 return undefined; 962 } 963 964 // Simulated bind 965 args = slice.call( arguments, 2 ); 966 proxy = function() { 967 return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); 968 }; 969 970 // Set the guid of unique handler to the same of original handler, so it can be removed 971 proxy.guid = fn.guid = fn.guid || jQuery.guid++; 972 973 return proxy; 974 }, 975 976 now: function() { 977 return +( new Date() ); 978 }, 979 980 // jQuery.support is not used in Core but other projects attach their 981 // properties to it so it needs to exist. 982 support: support 983}); 984 985// Populate the class2type map 986jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { 987 class2type[ "[object " + name + "]" ] = name.toLowerCase(); 988}); 989 990function isArraylike( obj ) { 991 var length = obj.length, 992 type = jQuery.type( obj ); 993 994 if ( type === "function" || jQuery.isWindow( obj ) ) { 995 return false; 996 } 997 998 if ( obj.nodeType === 1 && length ) { 999 return true; 1000 } 1001 1002 return type === "array" || length === 0 || 1003 typeof length === "number" && length > 0 && ( length - 1 ) in obj; 1004} 1005var Sizzle = 1006/*! 1007 * Sizzle CSS Selector Engine v1.10.19 1008 * http://sizzlejs.com/ 1009 * 1010 * Copyright 2013 jQuery Foundation, Inc. and other contributors 1011 * Released under the MIT license 1012 * http://jquery.org/license 1013 * 1014 * Date: 2014-04-18 1015 */ 1016(function( window ) { 1017 1018var i, 1019 support, 1020 Expr, 1021 getText, 1022 isXML, 1023 tokenize, 1024 compile, 1025 select, 1026 outermostContext, 1027 sortInput, 1028 hasDuplicate, 1029 1030 // Local document vars 1031 setDocument, 1032 document, 1033 docElem, 1034 documentIsHTML, 1035 rbuggyQSA, 1036 rbuggyMatches, 1037 matches, 1038 contains, 1039 1040 // Instance-specific data 1041 expando = "sizzle" + -(new Date()), 1042 preferredDoc = window.document, 1043 dirruns = 0, 1044 done = 0, 1045 classCache = createCache(), 1046 tokenCache = createCache(), 1047 compilerCache = createCache(), 1048 sortOrder = function( a, b ) { 1049 if ( a === b ) { 1050 hasDuplicate = true; 1051 } 1052 return 0; 1053 }, 1054 1055 // General-purpose constants 1056 strundefined = typeof undefined, 1057 MAX_NEGATIVE = 1 << 31, 1058 1059 // Instance methods 1060 hasOwn = ({}).hasOwnProperty, 1061 arr = [], 1062 pop = arr.pop, 1063 push_native = arr.push, 1064 push = arr.push, 1065 slice = arr.slice, 1066 // Use a stripped-down indexOf if we can't use a native one 1067 indexOf = arr.indexOf || function( elem ) { 1068 var i = 0, 1069 len = this.length; 1070 for ( ; i < len; i++ ) { 1071 if ( this[i] === elem ) { 1072 return i; 1073 } 1074 } 1075 return -1; 1076 }, 1077 1078 booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", 1079 1080 // Regular expressions 1081 1082 // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace 1083 whitespace = "[\\x20\\t\\r\\n\\f]", 1084 // http://www.w3.org/TR/css3-syntax/#characters 1085 characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", 1086 1087 // Loosely modeled on CSS identifier characters 1088 // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors 1089 // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier 1090 identifier = characterEncoding.replace( "w", "w#" ), 1091 1092 // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors 1093 attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace + 1094 // Operator (capture 2) 1095 "*([*^$|!~]?=)" + whitespace + 1096 // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" 1097 "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + 1098 "*\\]", 1099 1100 pseudos = ":(" + characterEncoding + ")(?:\\((" + 1101 // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: 1102 // 1. quoted (capture 3; capture 4 or capture 5) 1103 "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + 1104 // 2. simple (capture 6) 1105 "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + 1106 // 3. anything else (capture 2) 1107 ".*" + 1108 ")\\)|)", 1109 1110 // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter 1111 rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), 1112 1113 rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), 1114 rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), 1115 1116 rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), 1117 1118 rpseudo = new RegExp( pseudos ), 1119 ridentifier = new RegExp( "^" + identifier + "$" ), 1120 1121 matchExpr = { 1122 "ID": new RegExp( "^#(" + characterEncoding + ")" ), 1123 "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), 1124 "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), 1125 "ATTR": new RegExp( "^" + attributes ), 1126 "PSEUDO": new RegExp( "^" + pseudos ), 1127 "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + 1128 "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + 1129 "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), 1130 "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), 1131 // For use in libraries implementing .is() 1132 // We use this for POS matching in `select` 1133 "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + 1134 whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) 1135 }, 1136 1137 rinputs = /^(?:input|select|textarea|button)$/i, 1138 rheader = /^h\d$/i, 1139 1140 rnative = /^[^{]+\{\s*\[native \w/, 1141 1142 // Easily-parseable/retrievable ID or TAG or CLASS selectors 1143 rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, 1144 1145 rsibling = /[+~]/, 1146 rescape = /'|\\/g, 1147 1148 // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters 1149 runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), 1150 funescape = function( _, escaped, escapedWhitespace ) { 1151 var high = "0x" + escaped - 0x10000; 1152 // NaN means non-codepoint 1153 // Support: Firefox<24 1154 // Workaround erroneous numeric interpretation of +"0x" 1155 return high !== high || escapedWhitespace ? 1156 escaped : 1157 high < 0 ? 1158 // BMP codepoint 1159 String.fromCharCode( high + 0x10000 ) : 1160 // Supplemental Plane codepoint (surrogate pair) 1161 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); 1162 }; 1163 1164// Optimize for push.apply( _, NodeList ) 1165try { 1166 push.apply( 1167 (arr = slice.call( preferredDoc.childNodes )), 1168 preferredDoc.childNodes 1169 ); 1170 // Support: Android<4.0 1171 // Detect silently failing push.apply 1172 arr[ preferredDoc.childNodes.length ].nodeType; 1173} catch ( e ) { 1174 push = { apply: arr.length ? 1175 1176 // Leverage slice if possible 1177 function( target, els ) { 1178 push_native.apply( target, slice.call(els) ); 1179 } : 1180 1181 // Support: IE<9 1182 // Otherwise append directly 1183 function( target, els ) { 1184 var j = target.length, 1185 i = 0; 1186 // Can't trust NodeList.length 1187 while ( (target[j++] = els[i++]) ) {} 1188 target.length = j - 1; 1189 } 1190 }; 1191} 1192 1193function Sizzle( selector, context, results, seed ) { 1194 var match, elem, m, nodeType, 1195 // QSA vars 1196 i, groups, old, nid, newContext, newSelector; 1197 1198 if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { 1199 setDocument( context ); 1200 } 1201 1202 context = context || document; 1203 results = results || []; 1204 1205 if ( !selector || typeof selector !== "string" ) { 1206 return results; 1207 } 1208 1209 if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { 1210 return []; 1211 } 1212 1213 if ( documentIsHTML && !seed ) { 1214 1215 // Shortcuts 1216 if ( (match = rquickExpr.exec( selector )) ) { 1217 // Speed-up: Sizzle("#ID") 1218 if ( (m = match[1]) ) { 1219 if ( nodeType === 9 ) { 1220 elem = context.getElementById( m ); 1221 // Check parentNode to catch when Blackberry 4.6 returns 1222 // nodes that are no longer in the document (jQuery #6963) 1223 if ( elem && elem.parentNode ) { 1224 // Handle the case where IE, Opera, and Webkit return items 1225 // by name instead of ID 1226 if ( elem.id === m ) { 1227 results.push( elem ); 1228 return results; 1229 } 1230 } else { 1231 return results; 1232 } 1233 } else { 1234 // Context is not a document 1235 if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && 1236 contains( context, elem ) && elem.id === m ) { 1237 results.push( elem ); 1238 return results; 1239 } 1240 } 1241 1242 // Speed-up: Sizzle("TAG") 1243 } else if ( match[2] ) { 1244 push.apply( results, context.getElementsByTagName( selector ) ); 1245 return results; 1246 1247 // Speed-up: Sizzle(".CLASS") 1248 } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) { 1249 push.apply( results, context.getElementsByClassName( m ) ); 1250 return results; 1251 } 1252 } 1253 1254 // QSA path 1255 if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { 1256 nid = old = expando; 1257 newContext = context; 1258 newSelector = nodeType === 9 && selector; 1259 1260 // qSA works strangely on Element-rooted queries 1261 // We can work around this by specifying an extra ID on the root 1262 // and working up from there (Thanks to Andrew Dupont for the technique) 1263 // IE 8 doesn't work on object elements 1264 if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { 1265 groups = tokenize( selector ); 1266 1267 if ( (old = context.getAttribute("id")) ) { 1268 nid = old.replace( rescape, "\\$&" ); 1269 } else { 1270 context.setAttribute( "id", nid ); 1271 } 1272 nid = "[id='" + nid + "'] "; 1273 1274 i = groups.length; 1275 while ( i-- ) { 1276 groups[i] = nid + toSelector( groups[i] ); 1277 } 1278 newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context; 1279 newSelector = groups.join(","); 1280 } 1281 1282 if ( newSelector ) { 1283 try { 1284 push.apply( results, 1285 newContext.querySelectorAll( newSelector ) 1286 ); 1287 return results; 1288 } catch(qsaError) { 1289 } finally { 1290 if ( !old ) { 1291 context.removeAttribute("id"); 1292 } 1293 } 1294 } 1295 } 1296 } 1297 1298 // All others 1299 return select( selector.replace( rtrim, "$1" ), context, results, seed ); 1300} 1301 1302/** 1303 * Create key-value caches of limited size 1304 * @returns {Function(string, Object)} Returns the Object data after storing it on itself with 1305 * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) 1306 * deleting the oldest entry 1307 */ 1308function createCache() { 1309 var keys = []; 1310 1311 function cache( key, value ) { 1312 // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) 1313 if ( keys.push( key + " " ) > Expr.cacheLength ) { 1314 // Only keep the most recent entries 1315 delete cache[ keys.shift() ]; 1316 } 1317 return (cache[ key + " " ] = value); 1318 } 1319 return cache; 1320} 1321 1322/** 1323 * Mark a function for special use by Sizzle 1324 * @param {Function} fn The function to mark 1325 */ 1326function markFunction( fn ) { 1327 fn[ expando ] = true; 1328 return fn; 1329} 1330 1331/** 1332 * Support testing using an element 1333 * @param {Function} fn Passed the created div and expects a boolean result 1334 */ 1335function assert( fn ) { 1336 var div = document.createElement("div"); 1337 1338 try { 1339 return !!fn( div ); 1340 } catch (e) { 1341 return false; 1342 } finally { 1343 // Remove from its parent by default 1344 if ( div.parentNode ) { 1345 div.parentNode.removeChild( div ); 1346 } 1347 // release memory in IE 1348 div = null; 1349 } 1350} 1351 1352/** 1353 * Adds the same handler for all of the specified attrs 1354 * @param {String} attrs Pipe-separated list of attributes 1355 * @param {Function} handler The method that will be applied 1356 */ 1357function addHandle( attrs, handler ) { 1358 var arr = attrs.split("|"), 1359 i = attrs.length; 1360 1361 while ( i-- ) { 1362 Expr.attrHandle[ arr[i] ] = handler; 1363 } 1364} 1365 1366/** 1367 * Checks document order of two siblings 1368 * @param {Element} a 1369 * @param {Element} b 1370 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b 1371 */ 1372function siblingCheck( a, b ) { 1373 var cur = b && a, 1374 diff = cur && a.nodeType === 1 && b.nodeType === 1 && 1375 ( ~b.sourceIndex || MAX_NEGATIVE ) - 1376 ( ~a.sourceIndex || MAX_NEGATIVE ); 1377 1378 // Use IE sourceIndex if available on both nodes 1379 if ( diff ) { 1380 return diff; 1381 } 1382 1383 // Check if b follows a 1384 if ( cur ) { 1385 while ( (cur = cur.nextSibling) ) { 1386 if ( cur === b ) { 1387 return -1; 1388 } 1389 } 1390 } 1391 1392 return a ? 1 : -1; 1393} 1394 1395/** 1396 * Returns a function to use in pseudos for input types 1397 * @param {String} type 1398 */ 1399function createInputPseudo( type ) { 1400 return function( elem ) { 1401 var name = elem.nodeName.toLowerCase(); 1402 return name === "input" && elem.type === type; 1403 }; 1404} 1405 1406/** 1407 * Returns a function to use in pseudos for buttons 1408 * @param {String} type 1409 */ 1410function createButtonPseudo( type ) { 1411 return function( elem ) { 1412 var name = elem.nodeName.toLowerCase(); 1413 return (name === "input" || name === "button") && elem.type === type; 1414 }; 1415} 1416 1417/** 1418 * Returns a function to use in pseudos for positionals 1419 * @param {Function} fn 1420 */ 1421function createPositionalPseudo( fn ) { 1422 return markFunction(function( argument ) { 1423 argument = +argument; 1424 return markFunction(function( seed, matches ) { 1425 var j, 1426 matchIndexes = fn( [], seed.length, argument ), 1427 i = matchIndexes.length; 1428 1429 // Match elements found at the specified indexes 1430 while ( i-- ) { 1431 if ( seed[ (j = matchIndexes[i]) ] ) { 1432 seed[j] = !(matches[j] = seed[j]); 1433 } 1434 } 1435 }); 1436 }); 1437} 1438 1439/** 1440 * Checks a node for validity as a Sizzle context 1441 * @param {Element|Object=} context 1442 * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value 1443 */ 1444function testContext( context ) { 1445 return context && typeof context.getElementsByTagName !== strundefined && context; 1446} 1447 1448// Expose support vars for convenience 1449support = Sizzle.support = {}; 1450 1451/** 1452 * Detects XML nodes 1453 * @param {Element|Object} elem An element or a document 1454 * @returns {Boolean} True iff elem is a non-HTML XML node 1455 */ 1456isXML = Sizzle.isXML = function( elem ) { 1457 // documentElement is verified for cases where it doesn't yet exist 1458 // (such as loading iframes in IE - #4833) 1459 var documentElement = elem && (elem.ownerDocument || elem).documentElement; 1460 return documentElement ? documentElement.nodeName !== "HTML" : false; 1461}; 1462 1463/** 1464 * Sets document-related variables once based on the current document 1465 * @param {Element|Object} [doc] An element or document object to use to set the document 1466 * @returns {Object} Returns the current document 1467 */ 1468setDocument = Sizzle.setDocument = function( node ) { 1469 var hasCompare, 1470 doc = node ? node.ownerDocument || node : preferredDoc, 1471 parent = doc.defaultView; 1472 1473 // If no document and documentElement is available, return 1474 if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { 1475 return document; 1476 } 1477 1478 // Set our document 1479 document = doc; 1480 docElem = doc.documentElement; 1481 1482 // Support tests 1483 documentIsHTML = !isXML( doc ); 1484 1485 // Support: IE>8 1486 // If iframe document is assigned to "document" variable and if iframe has been reloaded, 1487 // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936 1488 // IE6-8 do not support the defaultView property so parent will be undefined 1489 if ( parent && parent !== parent.top ) { 1490 // IE11 does not have attachEvent, so all must suffer 1491 if ( parent.addEventListener ) { 1492 parent.addEventListener( "unload", function() { 1493 setDocument(); 1494 }, false ); 1495 } else if ( parent.attachEvent ) { 1496 parent.attachEvent( "onunload", function() { 1497 setDocument(); 1498 }); 1499 } 1500 } 1501 1502 /* Attributes 1503 ---------------------------------------------------------------------- */ 1504 1505 // Support: IE<8 1506 // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans) 1507 support.attributes = assert(function( div ) { 1508 div.className = "i"; 1509 return !div.getAttribute("className"); 1510 }); 1511 1512 /* getElement(s)By* 1513 ---------------------------------------------------------------------- */ 1514 1515 // Check if getElementsByTagName("*") returns only elements 1516 support.getElementsByTagName = assert(function( div ) { 1517 div.appendChild( doc.createComment("") ); 1518 return !div.getElementsByTagName("*").length; 1519 }); 1520 1521 // Check if getElementsByClassName can be trusted 1522 support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) { 1523 div.innerHTML = "<div class='a'></div><div class='a i'></div>"; 1524 1525 // Support: Safari<4 1526 // Catch class over-caching 1527 div.firstChild.className = "i"; 1528 // Support: Opera<10 1529 // Catch gEBCN failure to find non-leading classes 1530 return div.getElementsByClassName("i").length === 2; 1531 }); 1532 1533 // Support: IE<10 1534 // Check if getElementById returns elements by name 1535 // The broken getElementById methods don't pick up programatically-set names, 1536 // so use a roundabout getElementsByName test 1537 support.getById = assert(function( div ) { 1538 docElem.appendChild( div ).id = expando; 1539 return !doc.getElementsByName || !doc.getElementsByName( expando ).length; 1540 }); 1541 1542 // ID find and filter 1543 if ( support.getById ) { 1544 Expr.find["ID"] = function( id, context ) { 1545 if ( typeof context.getElementById !== strundefined && documentIsHTML ) { 1546 var m = context.getElementById( id ); 1547 // Check parentNode to catch when Blackberry 4.6 returns 1548 // nodes that are no longer in the document #6963 1549 return m && m.parentNode ? [ m ] : []; 1550 } 1551 }; 1552 Expr.filter["ID"] = function( id ) { 1553 var attrId = id.replace( runescape, funescape ); 1554 return function( elem ) { 1555 return elem.getAttribute("id") === attrId; 1556 }; 1557 }; 1558 } else { 1559 // Support: IE6/7 1560 // getElementById is not reliable as a find shortcut 1561 delete Expr.find["ID"]; 1562 1563 Expr.filter["ID"] = function( id ) { 1564 var attrId = id.replace( runescape, funescape ); 1565 return function( elem ) { 1566 var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); 1567 return node && node.value === attrId; 1568 }; 1569 }; 1570 } 1571 1572 // Tag 1573 Expr.find["TAG"] = support.getElementsByTagName ? 1574 function( tag, context ) { 1575 if ( typeof context.getElementsByTagName !== strundefined ) { 1576 return context.getElementsByTagName( tag ); 1577 } 1578 } : 1579 function( tag, context ) { 1580 var elem, 1581 tmp = [], 1582 i = 0, 1583 results = context.getElementsByTagName( tag ); 1584 1585 // Filter out possible comments 1586 if ( tag === "*" ) { 1587 while ( (elem = results[i++]) ) { 1588 if ( elem.nodeType === 1 ) { 1589 tmp.push( elem ); 1590 } 1591 } 1592 1593 return tmp; 1594 } 1595 return results; 1596 }; 1597 1598 // Class 1599 Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { 1600 if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) { 1601 return context.getElementsByClassName( className ); 1602 } 1603 }; 1604 1605 /* QSA/matchesSelector 1606 ---------------------------------------------------------------------- */ 1607 1608 // QSA and matchesSelector support 1609 1610 // matchesSelector(:active) reports false when true (IE9/Opera 11.5) 1611 rbuggyMatches = []; 1612 1613 // qSa(:focus) reports false when true (Chrome 21) 1614 // We allow this because of a bug in IE8/9 that throws an error 1615 // whenever `document.activeElement` is accessed on an iframe 1616 // So, we allow :focus to pass through QSA all the time to avoid the IE error 1617 // See http://bugs.jquery.com/ticket/13378 1618 rbuggyQSA = []; 1619 1620 if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) { 1621 // Build QSA regex 1622 // Regex strategy adopted from Diego Perini 1623 assert(function( div ) { 1624 // Select is set to empty string on purpose 1625 // This is to test IE's treatment of not explicitly 1626 // setting a boolean content attribute, 1627 // since its presence should be enough 1628 // http://bugs.jquery.com/ticket/12359 1629 div.innerHTML = "<select msallowclip=''><option selected=''></option></select>"; 1630 1631 // Support: IE8, Opera 11-12.16 1632 // Nothing should be selected when empty strings follow ^= or $= or *= 1633 // The test attribute must be unknown in Opera but "safe" for WinRT 1634 // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section 1635 if ( div.querySelectorAll("[msallowclip^='']").length ) { 1636 rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); 1637 } 1638 1639 // Support: IE8 1640 // Boolean attributes and "value" are not treated correctly 1641 if ( !div.querySelectorAll("[selected]").length ) { 1642 rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); 1643 } 1644 1645 // Webkit/Opera - :checked should return selected option elements 1646 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked 1647 // IE8 throws error here and will not see later tests 1648 if ( !div.querySelectorAll(":checked").length ) { 1649 rbuggyQSA.push(":checked"); 1650 } 1651 }); 1652 1653 assert(function( div ) { 1654 // Support: Windows 8 Native Apps 1655 // The type and name attributes are restricted during .innerHTML assignment 1656 var input = doc.createElement("input"); 1657 input.setAttribute( "type", "hidden" ); 1658 div.appendChild( input ).setAttribute( "name", "D" ); 1659 1660 // Support: IE8 1661 // Enforce case-sensitivity of name attribute 1662 if ( div.querySelectorAll("[name=d]").length ) { 1663 rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); 1664 } 1665 1666 // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) 1667 // IE8 throws error here and will not see later tests 1668 if ( !div.querySelectorAll(":enabled").length ) { 1669 rbuggyQSA.push( ":enabled", ":disabled" ); 1670 } 1671 1672 // Opera 10-11 does not throw on post-comma invalid pseudos 1673 div.querySelectorAll("*,:x"); 1674 rbuggyQSA.push(",.*:"); 1675 }); 1676 } 1677 1678 if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || 1679 docElem.webkitMatchesSelector || 1680 docElem.mozMatchesSelector || 1681 docElem.oMatchesSelector || 1682 docElem.msMatchesSelector) )) ) { 1683 1684 assert(function( div ) { 1685 // Check to see if it's possible to do matchesSelector 1686 // on a disconnected node (IE 9) 1687 support.disconnectedMatch = matches.call( div, "div" ); 1688 1689 // This should fail with an exception 1690 // Gecko does not error, returns false instead 1691 matches.call( div, "[s!='']:x" ); 1692 rbuggyMatches.push( "!=", pseudos ); 1693 }); 1694 } 1695 1696 rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); 1697 rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); 1698 1699 /* Contains 1700 ---------------------------------------------------------------------- */ 1701 hasCompare = rnative.test( docElem.compareDocumentPosition ); 1702 1703 // Element contains another 1704 // Purposefully does not implement inclusive descendent 1705 // As in, an element does not contain itself 1706 contains = hasCompare || rnative.test( docElem.contains ) ? 1707 function( a, b ) { 1708 var adown = a.nodeType === 9 ? a.documentElement : a, 1709 bup = b && b.parentNode; 1710 return a === bup || !!( bup && bup.nodeType === 1 && ( 1711 adown.contains ? 1712 adown.contains( bup ) : 1713 a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 1714 )); 1715 } : 1716 function( a, b ) { 1717 if ( b ) { 1718 while ( (b = b.parentNode) ) { 1719 if ( b === a ) { 1720 return true; 1721 } 1722 } 1723 } 1724 return false; 1725 }; 1726 1727 /* Sorting 1728 ---------------------------------------------------------------------- */ 1729 1730 // Document order sorting 1731 sortOrder = hasCompare ? 1732 function( a, b ) { 1733 1734 // Flag for duplicate removal 1735 if ( a === b ) { 1736 hasDuplicate = true; 1737 return 0; 1738 } 1739 1740 // Sort on method existence if only one input has compareDocumentPosition 1741 var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; 1742 if ( compare ) { 1743 return compare; 1744 } 1745 1746 // Calculate position if both inputs belong to the same document 1747 compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? 1748 a.compareDocumentPosition( b ) : 1749 1750 // Otherwise we know they are disconnected 1751 1; 1752 1753 // Disconnected nodes 1754 if ( compare & 1 || 1755 (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { 1756 1757 // Choose the first element that is related to our preferred document 1758 if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { 1759 return -1; 1760 } 1761 if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { 1762 return 1; 1763 } 1764 1765 // Maintain original order 1766 return sortInput ? 1767 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : 1768 0; 1769 } 1770 1771 return compare & 4 ? -1 : 1; 1772 } : 1773 function( a, b ) { 1774 // Exit early if the nodes are identical 1775 if ( a === b ) { 1776 hasDuplicate = true; 1777 return 0; 1778 } 1779 1780 var cur, 1781 i = 0, 1782 aup = a.parentNode, 1783 bup = b.parentNode, 1784 ap = [ a ], 1785 bp = [ b ]; 1786 1787 // Parentless nodes are either documents or disconnected 1788 if ( !aup || !bup ) { 1789 return a === doc ? -1 : 1790 b === doc ? 1 : 1791 aup ? -1 : 1792 bup ? 1 : 1793 sortInput ? 1794 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : 1795 0; 1796 1797 // If the nodes are siblings, we can do a quick check 1798 } else if ( aup === bup ) { 1799 return siblingCheck( a, b ); 1800 } 1801 1802 // Otherwise we need full lists of their ancestors for comparison 1803 cur = a; 1804 while ( (cur = cur.parentNode) ) { 1805 ap.unshift( cur ); 1806 } 1807 cur = b; 1808 while ( (cur = cur.parentNode) ) { 1809 bp.unshift( cur ); 1810 } 1811 1812 // Walk down the tree looking for a discrepancy 1813 while ( ap[i] === bp[i] ) { 1814 i++; 1815 } 1816 1817 return i ? 1818 // Do a sibling check if the nodes have a common ancestor 1819 siblingCheck( ap[i], bp[i] ) : 1820 1821 // Otherwise nodes in our document sort first 1822 ap[i] === preferredDoc ? -1 : 1823 bp[i] === preferredDoc ? 1 : 1824 0; 1825 }; 1826 1827 return doc; 1828}; 1829 1830Sizzle.matches = function( expr, elements ) { 1831 return Sizzle( expr, null, null, elements ); 1832}; 1833 1834Sizzle.matchesSelector = function( elem, expr ) { 1835 // Set document vars if needed 1836 if ( ( elem.ownerDocument || elem ) !== document ) { 1837 setDocument( elem ); 1838 } 1839 1840 // Make sure that attribute selectors are quoted 1841 expr = expr.replace( rattributeQuotes, "='$1']" ); 1842 1843 if ( support.matchesSelector && documentIsHTML && 1844 ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && 1845 ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { 1846 1847 try { 1848 var ret = matches.call( elem, expr ); 1849 1850 // IE 9's matchesSelector returns false on disconnected nodes 1851 if ( ret || support.disconnectedMatch || 1852 // As well, disconnected nodes are said to be in a document 1853 // fragment in IE 9 1854 elem.document && elem.document.nodeType !== 11 ) { 1855 return ret; 1856 } 1857 } catch(e) {} 1858 } 1859 1860 return Sizzle( expr, document, null, [ elem ] ).length > 0; 1861}; 1862 1863Sizzle.contains = function( context, elem ) { 1864 // Set document vars if needed 1865 if ( ( context.ownerDocument || context ) !== document ) { 1866 setDocument( context ); 1867 } 1868 return contains( context, elem ); 1869}; 1870 1871Sizzle.attr = function( elem, name ) { 1872 // Set document vars if needed 1873 if ( ( elem.ownerDocument || elem ) !== document ) { 1874 setDocument( elem ); 1875 } 1876 1877 var fn = Expr.attrHandle[ name.toLowerCase() ], 1878 // Don't get fooled by Object.prototype properties (jQuery #13807) 1879 val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? 1880 fn( elem, name, !documentIsHTML ) : 1881 undefined; 1882 1883 return val !== undefined ? 1884 val : 1885 support.attributes || !documentIsHTML ? 1886 elem.getAttribute( name ) : 1887 (val = elem.getAttributeNode(name)) && val.specified ? 1888 val.value : 1889 null; 1890}; 1891 1892Sizzle.error = function( msg ) { 1893 throw new Error( "Syntax error, unrecognized expression: " + msg ); 1894}; 1895 1896/** 1897 * Document sorting and removing duplicates 1898 * @param {ArrayLike} results 1899 */ 1900Sizzle.uniqueSort = function( results ) { 1901 var elem, 1902 duplicates = [], 1903 j = 0, 1904 i = 0; 1905 1906 // Unless we *know* we can detect duplicates, assume their presence 1907 hasDuplicate = !support.detectDuplicates; 1908 sortInput = !support.sortStable && results.slice( 0 ); 1909 results.sort( sortOrder ); 1910 1911 if ( hasDuplicate ) { 1912 while ( (elem = results[i++]) ) { 1913 if ( elem === results[ i ] ) { 1914 j = duplicates.push( i ); 1915 } 1916 } 1917 while ( j-- ) { 1918 results.splice( duplicates[ j ], 1 ); 1919 } 1920 } 1921 1922 // Clear input after sorting to release objects 1923 // See https://github.com/jquery/sizzle/pull/225 1924 sortInput = null; 1925 1926 return results; 1927}; 1928 1929/** 1930 * Utility function for retrieving the text value of an array of DOM nodes 1931 * @param {Array|Element} elem 1932 */ 1933getText = Sizzle.getText = function( elem ) { 1934 var node, 1935 ret = "", 1936 i = 0, 1937 nodeType = elem.nodeType; 1938 1939 if ( !nodeType ) { 1940 // If no nodeType, this is expected to be an array 1941 while ( (node = elem[i++]) ) { 1942 // Do not traverse comment nodes 1943 ret += getText( node ); 1944 } 1945 } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { 1946 // Use textContent for elements 1947 // innerText usage removed for consistency of new lines (jQuery #11153) 1948 if ( typeof elem.textContent === "string" ) { 1949 return elem.textContent; 1950 } else { 1951 // Traverse its children 1952 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { 1953 ret += getText( elem ); 1954 } 1955 } 1956 } else if ( nodeType === 3 || nodeType === 4 ) { 1957 return elem.nodeValue; 1958 } 1959 // Do not include comment or processing instruction nodes 1960 1961 return ret; 1962}; 1963 1964Expr = Sizzle.selectors = { 1965 1966 // Can be adjusted by the user 1967 cacheLength: 50, 1968 1969 createPseudo: markFunction, 1970 1971 match: matchExpr, 1972 1973 attrHandle: {}, 1974 1975 find: {}, 1976 1977 relative: { 1978 ">": { dir: "parentNode", first: true }, 1979 " ": { dir: "parentNode" }, 1980 "+": { dir: "previousSibling", first: true }, 1981 "~": { dir: "previousSibling" } 1982 }, 1983 1984 preFilter: { 1985 "ATTR": function( match ) { 1986 match[1] = match[1].replace( runescape, funescape ); 1987 1988 // Move the given value to match[3] whether quoted or unquoted 1989 match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); 1990 1991 if ( match[2] === "~=" ) { 1992 match[3] = " " + match[3] + " "; 1993 } 1994 1995 return match.slice( 0, 4 ); 1996 }, 1997 1998 "CHILD": function( match ) { 1999 /* matches from matchExpr["CHILD"] 2000 1 type (only|nth|...) 2001 2 what (child|of-type) 2002 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) 2003 4 xn-component of xn+y argument ([+-]?\d*n|) 2004 5 sign of xn-component 2005 6 x of xn-component 2006 7 sign of y-component 2007 8 y of y-component 2008 */ 2009 match[1] = match[1].toLowerCase(); 2010 2011 if ( match[1].slice( 0, 3 ) === "nth" ) { 2012 // nth-* requires argument 2013 if ( !match[3] ) { 2014 Sizzle.error( match[0] ); 2015 } 2016 2017 // numeric x and y parameters for Expr.filter.CHILD 2018 // remember that false/true cast respectively to 0/1 2019 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); 2020 match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); 2021 2022 // other types prohibit arguments 2023 } else if ( match[3] ) { 2024 Sizzle.error( match[0] ); 2025 } 2026 2027 return match; 2028 }, 2029 2030 "PSEUDO": function( match ) { 2031 var excess, 2032 unquoted = !match[6] && match[2]; 2033 2034 if ( matchExpr["CHILD"].test( match[0] ) ) { 2035 return null; 2036 } 2037 2038 // Accept quoted arguments as-is 2039 if ( match[3] ) { 2040 match[2] = match[4] || match[5] || ""; 2041 2042 // Strip excess characters from unquoted arguments 2043 } else if ( unquoted && rpseudo.test( unquoted ) && 2044 // Get excess from tokenize (recursively) 2045 (excess = tokenize( unquoted, true )) && 2046 // advance to the next closing parenthesis 2047 (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { 2048 2049 // excess is a negative index 2050 match[0] = match[0].slice( 0, excess ); 2051 match[2] = unquoted.slice( 0, excess ); 2052 } 2053 2054 // Return only captures needed by the pseudo filter method (type and argument) 2055 return match.slice( 0, 3 ); 2056 } 2057 }, 2058 2059 filter: { 2060 2061 "TAG": function( nodeNameSelector ) { 2062 var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); 2063 return nodeNameSelector === "*" ? 2064 function() { return true; } : 2065 function( elem ) { 2066 return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; 2067 }; 2068 }, 2069 2070 "CLASS": function( className ) { 2071 var pattern = classCache[ className + " " ]; 2072 2073 return pattern || 2074 (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && 2075 classCache( className, function( elem ) { 2076 return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" ); 2077 }); 2078 }, 2079 2080 "ATTR": function( name, operator, check ) { 2081 return function( elem ) { 2082 var result = Sizzle.attr( elem, name ); 2083 2084 if ( result == null ) { 2085 return operator === "!="; 2086 } 2087 if ( !operator ) { 2088 return true; 2089 } 2090 2091 result += ""; 2092 2093 return operator === "=" ? result === check : 2094 operator === "!=" ? result !== check : 2095 operator === "^=" ? check && result.indexOf( check ) === 0 : 2096 operator === "*=" ? check && result.indexOf( check ) > -1 : 2097 operator === "$=" ? check && result.slice( -check.length ) === check : 2098 operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : 2099 operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : 2100 false; 2101 }; 2102 }, 2103 2104 "CHILD": function( type, what, argument, first, last ) { 2105 var simple = type.slice( 0, 3 ) !== "nth", 2106 forward = type.slice( -4 ) !== "last", 2107 ofType = what === "of-type"; 2108 2109 return first === 1 && last === 0 ? 2110 2111 // Shortcut for :nth-*(n) 2112 function( elem ) { 2113 return !!elem.parentNode; 2114 } : 2115 2116 function( elem, context, xml ) { 2117 var cache, outerCache, node, diff, nodeIndex, start, 2118 dir = simple !== forward ? "nextSibling" : "previousSibling", 2119 parent = elem.parentNode, 2120 name = ofType && elem.nodeName.toLowerCase(), 2121 useCache = !xml && !ofType; 2122 2123 if ( parent ) { 2124 2125 // :(first|last|only)-(child|of-type) 2126 if ( simple ) { 2127 while ( dir ) { 2128 node = elem; 2129 while ( (node = node[ dir ]) ) { 2130 if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { 2131 return false; 2132 } 2133 } 2134 // Reverse direction for :only-* (if we haven't yet done so) 2135 start = dir = type === "only" && !start && "nextSibling"; 2136 } 2137 return true; 2138 } 2139 2140 start = [ forward ? parent.firstChild : parent.lastChild ]; 2141 2142 // non-xml :nth-child(...) stores cache data on `parent` 2143 if ( forward && useCache ) { 2144 // Seek `elem` from a previously-cached index 2145 outerCache = parent[ expando ] || (parent[ expando ] = {}); 2146 cache = outerCache[ type ] || []; 2147 nodeIndex = cache[0] === dirruns && cache[1]; 2148 diff = cache[0] === dirruns && cache[2]; 2149 node = nodeIndex && parent.childNodes[ nodeIndex ]; 2150 2151 while ( (node = ++nodeIndex && node && node[ dir ] || 2152 2153 // Fallback to seeking `elem` from the start 2154 (diff = nodeIndex = 0) || start.pop()) ) { 2155 2156 // When found, cache indexes on `parent` and break 2157 if ( node.nodeType === 1 && ++diff && node === elem ) { 2158 outerCache[ type ] = [ dirruns, nodeIndex, diff ]; 2159 break; 2160 } 2161 } 2162 2163 // Use previously-cached element index if available 2164 } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { 2165 diff = cache[1]; 2166 2167 // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) 2168 } else { 2169 // Use the same loop as above to seek `elem` from the start 2170 while ( (node = ++nodeIndex && node && node[ dir ] || 2171 (diff = nodeIndex = 0) || start.pop()) ) { 2172 2173 if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { 2174 // Cache the index of each encountered element 2175 if ( useCache ) { 2176 (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; 2177 } 2178 2179 if ( node === elem ) { 2180 break; 2181 } 2182 } 2183 } 2184 } 2185 2186 // Incorporate the offset, then check against cycle size 2187 diff -= last; 2188 return diff === first || ( diff % first === 0 && diff / first >= 0 ); 2189 } 2190 }; 2191 }, 2192 2193 "PSEUDO": function( pseudo, argument ) { 2194 // pseudo-class names are case-insensitive 2195 // http://www.w3.org/TR/selectors/#pseudo-classes 2196 // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters 2197 // Remember that setFilters inherits from pseudos 2198 var args, 2199 fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || 2200 Sizzle.error( "unsupported pseudo: " + pseudo ); 2201 2202 // The user may use createPseudo to indicate that 2203 // arguments are needed to create the filter function 2204 // just as Sizzle does 2205 if ( fn[ expando ] ) { 2206 return fn( argument ); 2207 } 2208 2209 // But maintain support for old signatures 2210 if ( fn.length > 1 ) { 2211 args = [ pseudo, pseudo, "", argument ]; 2212 return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? 2213 markFunction(function( seed, matches ) { 2214 var idx, 2215 matched = fn( seed, argument ), 2216 i = matched.length; 2217 while ( i-- ) { 2218 idx = indexOf.call( seed, matched[i] ); 2219 seed[ idx ] = !( matches[ idx ] = matched[i] ); 2220 } 2221 }) : 2222 function( elem ) { 2223 return fn( elem, 0, args ); 2224 }; 2225 } 2226 2227 return fn; 2228 } 2229 }, 2230 2231 pseudos: { 2232 // Potentially complex pseudos 2233 "not": markFunction(function( selector ) { 2234 // Trim the selector passed to compile 2235 // to avoid treating leading and trailing 2236 // spaces as combinators 2237 var input = [], 2238 results = [], 2239 matcher = compile( selector.replace( rtrim, "$1" ) ); 2240 2241 return matcher[ expando ] ? 2242 markFunction(function( seed, matches, context, xml ) { 2243 var elem, 2244 unmatched = matcher( seed, null, xml, [] ), 2245 i = seed.length; 2246 2247 // Match elements unmatched by `matcher` 2248 while ( i-- ) { 2249 if ( (elem = unmatched[i]) ) { 2250 seed[i] = !(matches[i] = elem); 2251 } 2252 } 2253 }) : 2254 function( elem, context, xml ) { 2255 input[0] = elem; 2256 matcher( input, null, xml, results ); 2257 return !results.pop(); 2258 }; 2259 }), 2260 2261 "has": markFunction(function( selector ) { 2262 return function( elem ) { 2263 return Sizzle( selector, elem ).length > 0; 2264 }; 2265 }), 2266 2267 "contains": markFunction(function( text ) { 2268 return function( elem ) { 2269 return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; 2270 }; 2271 }), 2272 2273 // "Whether an element is represented by a :lang() selector 2274 // is based solely on the element's language value 2275 // being equal to the identifier C, 2276 // or beginning with the identifier C immediately followed by "-". 2277 // The matching of C against the element's language value is performed case-insensitively. 2278 // The identifier C does not have to be a valid language name." 2279 // http://www.w3.org/TR/selectors/#lang-pseudo 2280 "lang": markFunction( function( lang ) { 2281 // lang value must be a valid identifier 2282 if ( !ridentifier.test(lang || "") ) { 2283 Sizzle.error( "unsupported lang: " + lang ); 2284 } 2285 lang = lang.replace( runescape, funescape ).toLowerCase(); 2286 return function( elem ) { 2287 var elemLang; 2288 do { 2289 if ( (elemLang = documentIsHTML ? 2290 elem.lang : 2291 elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { 2292 2293 elemLang = elemLang.toLowerCase(); 2294 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; 2295 } 2296 } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); 2297 return false; 2298 }; 2299 }), 2300 2301 // Miscellaneous 2302 "target": function( elem ) { 2303 var hash = window.location && window.location.hash; 2304 return hash && hash.slice( 1 ) === elem.id; 2305 }, 2306 2307 "root": function( elem ) { 2308 return elem === docElem; 2309 }, 2310 2311 "focus": function( elem ) { 2312 return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); 2313 }, 2314 2315 // Boolean properties 2316 "enabled": function( elem ) { 2317 return elem.disabled === false; 2318 }, 2319 2320 "disabled": function( elem ) { 2321 return elem.disabled === true; 2322 }, 2323 2324 "checked": function( elem ) { 2325 // In CSS3, :checked should return both checked and selected elements 2326 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked 2327 var nodeName = elem.nodeName.toLowerCase(); 2328 return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); 2329 }, 2330 2331 "selected": function( elem ) { 2332 // Accessing this property makes selected-by-default 2333 // options in Safari work properly 2334 if ( elem.parentNode ) { 2335 elem.parentNode.selectedIndex; 2336 } 2337 2338 return elem.selected === true; 2339 }, 2340 2341 // Contents 2342 "empty": function( elem ) { 2343 // http://www.w3.org/TR/selectors/#empty-pseudo 2344 // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), 2345 // but not by others (comment: 8; processing instruction: 7; etc.) 2346 // nodeType < 6 works because attributes (2) do not appear as children 2347 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { 2348 if ( elem.nodeType < 6 ) { 2349 return false; 2350 } 2351 } 2352 return true; 2353 }, 2354 2355 "parent": function( elem ) { 2356 return !Expr.pseudos["empty"]( elem ); 2357 }, 2358 2359 // Element/input types 2360 "header": function( elem ) { 2361 return rheader.test( elem.nodeName ); 2362 }, 2363 2364 "input": function( elem ) { 2365 return rinputs.test( elem.nodeName ); 2366 }, 2367 2368 "button": function( elem ) { 2369 var name = elem.nodeName.toLowerCase(); 2370 return name === "input" && elem.type === "button" || name === "button"; 2371 }, 2372 2373 "text": function( elem ) { 2374 var attr; 2375 return elem.nodeName.toLowerCase() === "input" && 2376 elem.type === "text" && 2377 2378 // Support: IE<8 2379 // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" 2380 ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); 2381 }, 2382 2383 // Position-in-collection 2384 "first": createPositionalPseudo(function() { 2385 return [ 0 ]; 2386 }), 2387 2388 "last": createPositionalPseudo(function( matchIndexes, length ) { 2389 return [ length - 1 ]; 2390 }), 2391 2392 "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { 2393 return [ argument < 0 ? argument + length : argument ]; 2394 }), 2395 2396 "even": createPositionalPseudo(function( matchIndexes, length ) { 2397 var i = 0; 2398 for ( ; i < length; i += 2 ) { 2399 matchIndexes.push( i ); 2400 } 2401 return matchIndexes; 2402 }), 2403 2404 "odd": createPositionalPseudo(function( matchIndexes, length ) { 2405 var i = 1; 2406 for ( ; i < length; i += 2 ) { 2407 matchIndexes.push( i ); 2408 } 2409 return matchIndexes; 2410 }), 2411 2412 "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { 2413 var i = argument < 0 ? argument + length : argument; 2414 for ( ; --i >= 0; ) { 2415 matchIndexes.push( i ); 2416 } 2417 return matchIndexes; 2418 }), 2419 2420 "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { 2421 var i = argument < 0 ? argument + length : argument; 2422 for ( ; ++i < length; ) { 2423 matchIndexes.push( i ); 2424 } 2425 return matchIndexes; 2426 }) 2427 } 2428}; 2429 2430Expr.pseudos["nth"] = Expr.pseudos["eq"]; 2431 2432// Add button/input type pseudos 2433for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { 2434 Expr.pseudos[ i ] = createInputPseudo( i ); 2435} 2436for ( i in { submit: true, reset: true } ) { 2437 Expr.pseudos[ i ] = createButtonPseudo( i ); 2438} 2439 2440// Easy API for creating new setFilters 2441function setFilters() {} 2442setFilters.prototype = Expr.filters = Expr.pseudos; 2443Expr.setFilters = new setFilters(); 2444 2445tokenize = Sizzle.tokenize = function( selector, parseOnly ) { 2446 var matched, match, tokens, type, 2447 soFar, groups, preFilters, 2448 cached = tokenCache[ selector + " " ]; 2449 2450 if ( cached ) { 2451 return parseOnly ? 0 : cached.slice( 0 ); 2452 } 2453 2454 soFar = selector; 2455 groups = []; 2456 preFilters = Expr.preFilter; 2457 2458 while ( soFar ) { 2459 2460 // Comma and first run 2461 if ( !matched || (match = rcomma.exec( soFar )) ) { 2462 if ( match ) { 2463 // Don't consume trailing commas as valid 2464 soFar = soFar.slice( match[0].length ) || soFar; 2465 } 2466 groups.push( (tokens = []) ); 2467 } 2468 2469 matched = false; 2470 2471 // Combinators 2472 if ( (match = rcombinators.exec( soFar )) ) { 2473 matched = match.shift(); 2474 tokens.push({ 2475 value: matched, 2476 // Cast descendant combinators to space 2477 type: match[0].replace( rtrim, " " ) 2478 }); 2479 soFar = soFar.slice( matched.length ); 2480 } 2481 2482 // Filters 2483 for ( type in Expr.filter ) { 2484 if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || 2485 (match = preFilters[ type ]( match ))) ) { 2486 matched = match.shift(); 2487 tokens.push({ 2488 value: matched, 2489 type: type, 2490 matches: match 2491 }); 2492 soFar = soFar.slice( matched.length ); 2493 } 2494 } 2495 2496 if ( !matched ) { 2497 break; 2498 } 2499 } 2500 2501 // Return the length of the invalid excess 2502 // if we're just parsing 2503 // Otherwise, throw an error or return tokens 2504 return parseOnly ? 2505 soFar.length : 2506 soFar ? 2507 Sizzle.error( selector ) : 2508 // Cache the tokens 2509 tokenCache( selector, groups ).slice( 0 ); 2510}; 2511 2512function toSelector( tokens ) { 2513 var i = 0, 2514 len = tokens.length, 2515 selector = ""; 2516 for ( ; i < len; i++ ) { 2517 selector += tokens[i].value; 2518 } 2519 return selector; 2520} 2521 2522function addCombinator( matcher, combinator, base ) { 2523 var dir = combinator.dir, 2524 checkNonElements = base && dir === "parentNode", 2525 doneName = done++; 2526 2527 return combinator.first ? 2528 // Check against closest ancestor/preceding element 2529 function( elem, context, xml ) { 2530 while ( (elem = elem[ dir ]) ) { 2531 if ( elem.nodeType === 1 || checkNonElements ) { 2532 return matcher( elem, context, xml ); 2533 } 2534 } 2535 } : 2536 2537 // Check against all ancestor/preceding elements 2538 function( elem, context, xml ) { 2539 var oldCache, outerCache, 2540 newCache = [ dirruns, doneName ]; 2541 2542 // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching 2543 if ( xml ) { 2544 while ( (elem = elem[ dir ]) ) { 2545 if ( elem.nodeType === 1 || checkNonElements ) { 2546 if ( matcher( elem, context, xml ) ) { 2547 return true; 2548 } 2549 } 2550 } 2551 } else { 2552 while ( (elem = elem[ dir ]) ) { 2553 if ( elem.nodeType === 1 || checkNonElements ) { 2554 outerCache = elem[ expando ] || (elem[ expando ] = {}); 2555 if ( (oldCache = outerCache[ dir ]) && 2556 oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { 2557 2558 // Assign to newCache so results back-propagate to previous elements 2559 return (newCache[ 2 ] = oldCache[ 2 ]); 2560 } else { 2561 // Reuse newcache so results back-propagate to previous elements 2562 outerCache[ dir ] = newCache; 2563 2564 // A match means we're done; a fail means we have to keep checking 2565 if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { 2566 return true; 2567 } 2568 } 2569 } 2570 } 2571 } 2572 }; 2573} 2574 2575function elementMatcher( matchers ) { 2576 return matchers.length > 1 ? 2577 function( elem, context, xml ) { 2578 var i = matchers.length; 2579 while ( i-- ) { 2580 if ( !matchers[i]( elem, context, xml ) ) { 2581 return false; 2582 } 2583 } 2584 return true; 2585 } : 2586 matchers[0]; 2587} 2588 2589function multipleContexts( selector, contexts, results ) { 2590 var i = 0, 2591 len = contexts.length; 2592 for ( ; i < len; i++ ) { 2593 Sizzle( selector, contexts[i], results ); 2594 } 2595 return results; 2596} 2597 2598function condense( unmatched, map, filter, context, xml ) { 2599 var elem, 2600 newUnmatched = [], 2601 i = 0, 2602 len = unmatched.length, 2603 mapped = map != null; 2604 2605 for ( ; i < len; i++ ) { 2606 if ( (elem = unmatched[i]) ) { 2607 if ( !filter || filter( elem, context, xml ) ) { 2608 newUnmatched.push( elem ); 2609 if ( mapped ) { 2610 map.push( i ); 2611 } 2612 } 2613 } 2614 } 2615 2616 return newUnmatched; 2617} 2618 2619function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { 2620 if ( postFilter && !postFilter[ expando ] ) { 2621 postFilter = setMatcher( postFilter ); 2622 } 2623 if ( postFinder && !postFinder[ expando ] ) { 2624 postFinder = setMatcher( postFinder, postSelector ); 2625 } 2626 return markFunction(function( seed, results, context, xml ) { 2627 var temp, i, elem, 2628 preMap = [], 2629 postMap = [], 2630 preexisting = results.length, 2631 2632 // Get initial elements from seed or context 2633 elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), 2634 2635 // Prefilter to get matcher input, preserving a map for seed-results synchronization 2636 matcherIn = preFilter && ( seed || !selector ) ? 2637 condense( elems, preMap, preFilter, context, xml ) : 2638 elems, 2639 2640 matcherOut = matcher ? 2641 // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, 2642 postFinder || ( seed ? preFilter : preexisting || postFilter ) ? 2643 2644 // ...intermediate processing is necessary 2645 [] : 2646 2647 // ...otherwise use results directly 2648 results : 2649 matcherIn; 2650 2651 // Find primary matches 2652 if ( matcher ) { 2653 matcher( matcherIn, matcherOut, context, xml ); 2654 } 2655 2656 // Apply postFilter 2657 if ( postFilter ) { 2658 temp = condense( matcherOut, postMap ); 2659 postFilter( temp, [], context, xml ); 2660 2661 // Un-match failing elements by moving them back to matcherIn 2662 i = temp.length; 2663 while ( i-- ) { 2664 if ( (elem = temp[i]) ) { 2665 matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); 2666 } 2667 } 2668 } 2669 2670 if ( seed ) { 2671 if ( postFinder || preFilter ) { 2672 if ( postFinder ) { 2673 // Get the final matcherOut by condensing this intermediate into postFinder contexts 2674 temp = []; 2675 i = matcherOut.length; 2676 while ( i-- ) { 2677 if ( (elem = matcherOut[i]) ) { 2678 // Restore matcherIn since elem is not yet a final match 2679 temp.push( (matcherIn[i] = elem) ); 2680 } 2681 } 2682 postFinder( null, (matcherOut = []), temp, xml ); 2683 } 2684 2685 // Move matched elements from seed to results to keep them synchronized 2686 i = matcherOut.length; 2687 while ( i-- ) { 2688 if ( (elem = matcherOut[i]) && 2689 (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { 2690 2691 seed[temp] = !(results[temp] = elem); 2692 } 2693 } 2694 } 2695 2696 // Add elements to results, through postFinder if defined 2697 } else { 2698 matcherOut = condense( 2699 matcherOut === results ? 2700 matcherOut.splice( preexisting, matcherOut.length ) : 2701 matcherOut 2702 ); 2703 if ( postFinder ) { 2704 postFinder( null, results, matcherOut, xml ); 2705 } else { 2706 push.apply( results, matcherOut ); 2707 } 2708 } 2709 }); 2710} 2711 2712function matcherFromTokens( tokens ) { 2713 var checkContext, matcher, j, 2714 len = tokens.length, 2715 leadingRelative = Expr.relative[ tokens[0].type ], 2716 implicitRelative = leadingRelative || Expr.relative[" "], 2717 i = leadingRelative ? 1 : 0, 2718 2719 // The foundational matcher ensures that elements are reachable from top-level context(s) 2720 matchContext = addCombinator( function( elem ) { 2721 return elem === checkContext; 2722 }, implicitRelative, true ), 2723 matchAnyContext = addCombinator( function( elem ) { 2724 return indexOf.call( checkContext, elem ) > -1; 2725 }, implicitRelative, true ), 2726 matchers = [ function( elem, context, xml ) { 2727 return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( 2728 (checkContext = context).nodeType ? 2729 matchContext( elem, context, xml ) : 2730 matchAnyContext( elem, context, xml ) ); 2731 } ]; 2732 2733 for ( ; i < len; i++ ) { 2734 if ( (matcher = Expr.relative[ tokens[i].type ]) ) { 2735 matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; 2736 } else { 2737 matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); 2738 2739 // Return special upon seeing a positional matcher 2740 if ( matcher[ expando ] ) { 2741 // Find the next relative operator (if any) for proper handling 2742 j = ++i; 2743 for ( ; j < len; j++ ) { 2744 if ( Expr.relative[ tokens[j].type ] ) { 2745 break; 2746 } 2747 } 2748 return setMatcher( 2749 i > 1 && elementMatcher( matchers ), 2750 i > 1 && toSelector( 2751 // If the preceding token was a descendant combinator, insert an implicit any-element `*` 2752 tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) 2753 ).replace( rtrim, "$1" ), 2754 matcher, 2755 i < j && matcherFromTokens( tokens.slice( i, j ) ), 2756 j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), 2757 j < len && toSelector( tokens ) 2758 ); 2759 } 2760 matchers.push( matcher ); 2761 } 2762 } 2763 2764 return elementMatcher( matchers ); 2765} 2766 2767function matcherFromGroupMatchers( elementMatchers, setMatchers ) { 2768 var bySet = setMatchers.length > 0, 2769 byElement = elementMatchers.length > 0, 2770 superMatcher = function( seed, context, xml, results, outermost ) { 2771 var elem, j, matcher, 2772 matchedCount = 0, 2773 i = "0", 2774 unmatched = seed && [], 2775 setMatched = [], 2776 contextBackup = outermostContext, 2777 // We must always have either seed elements or outermost context 2778 elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), 2779 // Use integer dirruns iff this is the outermost matcher 2780 dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), 2781 len = elems.length; 2782 2783 if ( outermost ) { 2784 outermostContext = context !== document && context; 2785 } 2786 2787 // Add elements passing elementMatchers directly to results 2788 // Keep `i` a string if there are no elements so `matchedCount` will be "00" below 2789 // Support: IE<9, Safari 2790 // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id 2791 for ( ; i !== len && (elem = elems[i]) != null; i++ ) { 2792 if ( byElement && elem ) { 2793 j = 0; 2794 while ( (matcher = elementMatchers[j++]) ) { 2795 if ( matcher( elem, context, xml ) ) { 2796 results.push( elem ); 2797 break; 2798 } 2799 } 2800 if ( outermost ) { 2801 dirruns = dirrunsUnique; 2802 } 2803 } 2804 2805 // Track unmatched elements for set filters 2806 if ( bySet ) { 2807 // They will have gone through all possible matchers 2808 if ( (elem = !matcher && elem) ) { 2809 matchedCount--; 2810 } 2811 2812 // Lengthen the array for every element, matched or not 2813 if ( seed ) { 2814 unmatched.push( elem ); 2815 } 2816 } 2817 } 2818 2819 // Apply set filters to unmatched elements 2820 matchedCount += i; 2821 if ( bySet && i !== matchedCount ) { 2822 j = 0; 2823 while ( (matcher = setMatchers[j++]) ) { 2824 matcher( unmatched, setMatched, context, xml ); 2825 } 2826 2827 if ( seed ) { 2828 // Reintegrate element matches to eliminate the need for sorting 2829 if ( matchedCount > 0 ) { 2830 while ( i-- ) { 2831 if ( !(unmatched[i] || setMatched[i]) ) { 2832 setMatched[i] = pop.call( results ); 2833 } 2834 } 2835 } 2836 2837 // Discard index placeholder values to get only actual matches 2838 setMatched = condense( setMatched ); 2839 } 2840 2841 // Add matches to results 2842 push.apply( results, setMatched ); 2843 2844 // Seedless set matches succeeding multiple successful matchers stipulate sorting 2845 if ( outermost && !seed && setMatched.length > 0 && 2846 ( matchedCount + setMatchers.length ) > 1 ) { 2847 2848 Sizzle.uniqueSort( results ); 2849 } 2850 } 2851 2852 // Override manipulation of globals by nested matchers 2853 if ( outermost ) { 2854 dirruns = dirrunsUnique; 2855 outermostContext = contextBackup; 2856 } 2857 2858 return unmatched; 2859 }; 2860 2861 return bySet ? 2862 markFunction( superMatcher ) : 2863 superMatcher; 2864} 2865 2866compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { 2867 var i, 2868 setMatchers = [], 2869 elementMatchers = [], 2870 cached = compilerCache[ selector + " " ]; 2871 2872 if ( !cached ) { 2873 // Generate a function of recursive functions that can be used to check each element 2874 if ( !match ) { 2875 match = tokenize( selector ); 2876 } 2877 i = match.length; 2878 while ( i-- ) { 2879 cached = matcherFromTokens( match[i] ); 2880 if ( cached[ expando ] ) { 2881 setMatchers.push( cached ); 2882 } else { 2883 elementMatchers.push( cached ); 2884 } 2885 } 2886 2887 // Cache the compiled function 2888 cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); 2889 2890 // Save selector and tokenization 2891 cached.selector = selector; 2892 } 2893 return cached; 2894}; 2895 2896/** 2897 * A low-level selection function that works with Sizzle's compiled 2898 * selector functions 2899 * @param {String|Function} selector A selector or a pre-compiled 2900 * selector function built with Sizzle.compile 2901 * @param {Element} context 2902 * @param {Array} [results] 2903 * @param {Array} [seed] A set of elements to match against 2904 */ 2905select = Sizzle.select = function( selector, context, results, seed ) { 2906 var i, tokens, token, type, find, 2907 compiled = typeof selector === "function" && selector, 2908 match = !seed && tokenize( (selector = compiled.selector || selector) ); 2909 2910 results = results || []; 2911 2912 // Try to minimize operations if there is no seed and only one group 2913 if ( match.length === 1 ) { 2914 2915 // Take a shortcut and set the context if the root selector is an ID 2916 tokens = match[0] = match[0].slice( 0 ); 2917 if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && 2918 support.getById && context.nodeType === 9 && documentIsHTML && 2919 Expr.relative[ tokens[1].type ] ) { 2920 2921 context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; 2922 if ( !context ) { 2923 return results; 2924 2925 // Precompiled matchers will still verify ancestry, so step up a level 2926 } else if ( compiled ) { 2927 context = context.parentNode; 2928 } 2929 2930 selector = selector.slice( tokens.shift().value.length ); 2931 } 2932 2933 // Fetch a seed set for right-to-left matching 2934 i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; 2935 while ( i-- ) { 2936 token = tokens[i]; 2937 2938 // Abort if we hit a combinator 2939 if ( Expr.relative[ (type = token.type) ] ) { 2940 break; 2941 } 2942 if ( (find = Expr.find[ type ]) ) { 2943 // Search, expanding context for leading sibling combinators 2944 if ( (seed = find( 2945 token.matches[0].replace( runescape, funescape ), 2946 rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context 2947 )) ) { 2948 2949 // If seed is empty or no tokens remain, we can return early 2950 tokens.splice( i, 1 ); 2951 selector = seed.length && toSelector( tokens ); 2952 if ( !selector ) { 2953 push.apply( results, seed ); 2954 return results; 2955 } 2956 2957 break; 2958 } 2959 } 2960 } 2961 } 2962 2963 // Compile and execute a filtering function if one is not provided 2964 // Provide `match` to avoid retokenization if we modified the selector above 2965 ( compiled || compile( selector, match ) )( 2966 seed, 2967 context, 2968 !documentIsHTML, 2969 results, 2970 rsibling.test( selector ) && testContext( context.parentNode ) || context 2971 ); 2972 return results; 2973}; 2974 2975// One-time assignments 2976 2977// Sort stability 2978support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; 2979 2980// Support: Chrome<14 2981// Always assume duplicates if they aren't passed to the comparison function 2982support.detectDuplicates = !!hasDuplicate; 2983 2984// Initialize against the default document 2985setDocument(); 2986 2987// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) 2988// Detached nodes confoundingly follow *each other* 2989support.sortDetached = assert(function( div1 ) { 2990 // Should return 1, but returns 4 (following) 2991 return div1.compareDocumentPosition( document.createElement("div") ) & 1; 2992}); 2993 2994// Support: IE<8 2995// Prevent attribute/property "interpolation" 2996// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx 2997if ( !assert(function( div ) { 2998 div.innerHTML = "<a href='#'></a>"; 2999 return div.firstChild.getAttribute("href") === "#" ; 3000}) ) { 3001 addHandle( "type|href|height|width", function( elem, name, isXML ) { 3002 if ( !isXML ) { 3003 return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); 3004 } 3005 }); 3006} 3007 3008// Support: IE<9 3009// Use defaultValue in place of getAttribute("value") 3010if ( !support.attributes || !assert(function( div ) { 3011 div.innerHTML = "<input/>"; 3012 div.firstChild.setAttribute( "value", "" ); 3013 return div.firstChild.getAttribute( "value" ) === ""; 3014}) ) { 3015 addHandle( "value", function( elem, name, isXML ) { 3016 if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { 3017 return elem.defaultValue; 3018 } 3019 }); 3020} 3021 3022// Support: IE<9 3023// Use getAttributeNode to fetch booleans when getAttribute lies 3024if ( !assert(function( div ) { 3025 return div.getAttribute("disabled") == null; 3026}) ) { 3027 addHandle( booleans, function( elem, name, isXML ) { 3028 var val; 3029 if ( !isXML ) { 3030 return elem[ name ] === true ? name.toLowerCase() : 3031 (val = elem.getAttributeNode( name )) && val.specified ? 3032 val.value : 3033 null; 3034 } 3035 }); 3036} 3037 3038return Sizzle; 3039 3040})( window ); 3041 3042jQuery.find = Sizzle; 3043jQuery.expr = Sizzle.selectors; 3044jQuery.expr[":"] = jQuery.expr.pseudos; 3045jQuery.unique = Sizzle.uniqueSort; 3046jQuery.text = Sizzle.getText; 3047jQuery.isXMLDoc = Sizzle.isXML; 3048jQuery.contains = Sizzle.contains; 3049 3050var rneedsContext = jQuery.expr.match.needsContext; 3051 3052var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/); 3053 3054var risSimple = /^.[^:#\[\.,]*$/; 3055 3056// Implement the identical functionality for filter and not 3057function winnow( elements, qualifier, not ) { 3058 if ( jQuery.isFunction( qualifier ) ) { 3059 return jQuery.grep( elements, function( elem, i ) { 3060 /* jshint -W018 */ 3061 return !!qualifier.call( elem, i, elem ) !== not; 3062 }); 3063 3064 } 3065 3066 if ( qualifier.nodeType ) { 3067 return jQuery.grep( elements, function( elem ) { 3068 return ( elem === qualifier ) !== not; 3069 }); 3070 3071 } 3072 3073 if ( typeof qualifier === "string" ) { 3074 if ( risSimple.test( qualifier ) ) { 3075 return jQuery.filter( qualifier, elements, not ); 3076 } 3077 3078 qualifier = jQuery.filter( qualifier, elements ); 3079 } 3080 3081 return jQuery.grep( elements, function( elem ) { 3082 return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not; 3083 }); 3084} 3085 3086jQuery.filter = function( expr, elems, not ) { 3087 var elem = elems[ 0 ]; 3088 3089 if ( not ) { 3090 expr = ":not(" + expr + ")"; 3091 } 3092 3093 return elems.length === 1 && elem.nodeType === 1 ? 3094 jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : 3095 jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { 3096 return elem.nodeType === 1; 3097 })); 3098}; 3099 3100jQuery.fn.extend({ 3101 find: function( selector ) { 3102 var i, 3103 ret = [], 3104 self = this, 3105 len = self.length; 3106 3107 if ( typeof selector !== "string" ) { 3108 return this.pushStack( jQuery( selector ).filter(function() { 3109 for ( i = 0; i < len; i++ ) { 3110 if ( jQuery.contains( self[ i ], this ) ) { 3111 return true; 3112 } 3113 } 3114 }) ); 3115 } 3116 3117 for ( i = 0; i < len; i++ ) { 3118 jQuery.find( selector, self[ i ], ret ); 3119 } 3120 3121 // Needed because $( selector, context ) becomes $( context ).find( selector ) 3122 ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); 3123 ret.selector = this.selector ? this.selector + " " + selector : selector; 3124 return ret; 3125 }, 3126 filter: function( selector ) { 3127 return this.pushStack( winnow(this, selector || [], false) ); 3128 }, 3129 not: function( selector ) { 3130 return this.pushStack( winnow(this, selector || [], true) ); 3131 }, 3132 is: function( selector ) { 3133 return !!winnow( 3134 this, 3135 3136 // If this is a positional/relative selector, check membership in the returned set 3137 // so $("p:first").is("p:last") won't return true for a doc with two "p". 3138 typeof selector === "string" && rneedsContext.test( selector ) ? 3139 jQuery( selector ) : 3140 selector || [], 3141 false 3142 ).length; 3143 } 3144}); 3145 3146// Initialize a jQuery object 3147 3148// A central reference to the root jQuery(document) 3149var rootjQuery, 3150 3151 // Use the correct document accordingly with window argument (sandbox) 3152 document = window.document, 3153 3154 // A simple way to check for HTML strings 3155 // Prioritize #id over <tag> to avoid XSS via location.hash (#9521) 3156 // Strict HTML recognition (#11290: must start with <) 3157 rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, 3158 3159 init = jQuery.fn.init = function( selector, context ) { 3160 var match, elem; 3161 3162 // HANDLE: $(""), $(null), $(undefined), $(false) 3163 if ( !selector ) { 3164 return this; 3165 } 3166 3167 // Handle HTML strings 3168 if ( typeof selector === "string" ) { 3169 if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { 3170 // Assume that strings that start and end with <> are HTML and skip the regex check 3171 match = [ null, selector, null ]; 3172 3173 } else { 3174 match = rquickExpr.exec( selector ); 3175 } 3176 3177 // Match html or make sure no context is specified for #id 3178 if ( match && (match[1] || !context) ) { 3179 3180 // HANDLE: $(html) -> $(array) 3181 if ( match[1] ) { 3182 context = context instanceof jQuery ? context[0] : context; 3183 3184 // scripts is true for back-compat 3185 // Intentionally let the error be thrown if parseHTML is not present 3186 jQuery.merge( this, jQuery.parseHTML( 3187 match[1], 3188 context && context.nodeType ? context.ownerDocument || context : document, 3189 true 3190 ) ); 3191 3192 // HANDLE: $(html, props) 3193 if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { 3194 for ( match in context ) { 3195 // Properties of context are called as methods if possible 3196 if ( jQuery.isFunction( this[ match ] ) ) { 3197 this[ match ]( context[ match ] ); 3198 3199 // ...and otherwise set as attributes 3200 } else { 3201 this.attr( match, context[ match ] ); 3202 } 3203 } 3204 } 3205 3206 return this; 3207 3208 // HANDLE: $(#id) 3209 } else { 3210 elem = document.getElementById( match[2] ); 3211 3212 // Check parentNode to catch when Blackberry 4.6 returns 3213 // nodes that are no longer in the document #6963 3214 if ( elem && elem.parentNode ) { 3215 // Handle the case where IE and Opera return items 3216 // by name instead of ID 3217 if ( elem.id !== match[2] ) { 3218 return rootjQuery.find( selector ); 3219 } 3220 3221 // Otherwise, we inject the element directly into the jQuery object 3222 this.length = 1; 3223 this[0] = elem; 3224 } 3225 3226 this.context = document; 3227 this.selector = selector; 3228 return this; 3229 } 3230 3231 // HANDLE: $(expr, $(...)) 3232 } else if ( !context || context.jquery ) { 3233 return ( context || rootjQuery ).find( selector ); 3234 3235 // HANDLE: $(expr, context) 3236 // (which is just equivalent to: $(context).find(expr) 3237 } else { 3238 return this.constructor( context ).find( selector ); 3239 } 3240 3241 // HANDLE: $(DOMElement) 3242 } else if ( selector.nodeType ) { 3243 this.context = this[0] = selector; 3244 this.length = 1; 3245 return this; 3246 3247 // HANDLE: $(function) 3248 // Shortcut for document ready 3249 } else if ( jQuery.isFunction( selector ) ) { 3250 return typeof rootjQuery.ready !== "undefined" ? 3251 rootjQuery.ready( selector ) : 3252 // Execute immediately if ready is not present 3253 selector( jQuery ); 3254 } 3255 3256 if ( selector.selector !== undefined ) { 3257 this.selector = selector.selector; 3258 this.context = selector.context; 3259 } 3260 3261 return jQuery.makeArray( selector, this ); 3262 }; 3263 3264// Give the init function the jQuery prototype for later instantiation 3265init.prototype = jQuery.fn; 3266 3267// Initialize central reference 3268rootjQuery = jQuery( document ); 3269 3270var rparentsprev = /^(?:parents|prev(?:Until|All))/, 3271 // methods guaranteed to produce a unique set when starting from a unique set 3272 guaranteedUnique = { 3273 children: true, 3274 contents: true, 3275 next: true, 3276 prev: true 3277 }; 3278 3279jQuery.extend({ 3280 dir: function( elem, dir, until ) { 3281 var matched = [], 3282 cur = elem[ dir ]; 3283 3284 while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { 3285 if ( cur.nodeType === 1 ) { 3286 matched.push( cur ); 3287 } 3288 cur = cur[dir]; 3289 } 3290 return matched; 3291 }, 3292 3293 sibling: function( n, elem ) { 3294 var r = []; 3295 3296 for ( ; n; n = n.nextSibling ) { 3297 if ( n.nodeType === 1 && n !== elem ) { 3298 r.push( n ); 3299 } 3300 } 3301 3302 return r; 3303 } 3304}); 3305 3306jQuery.fn.extend({ 3307 has: function( target ) { 3308 var i, 3309 targets = jQuery( target, this ), 3310 len = targets.length; 3311 3312 return this.filter(function() { 3313 for ( i = 0; i < len; i++ ) { 3314 if ( jQuery.contains( this, targets[i] ) ) { 3315 return true; 3316 } 3317 } 3318 }); 3319 }, 3320 3321 closest: function( selectors, context ) { 3322 var cur, 3323 i = 0, 3324 l = this.length, 3325 matched = [], 3326 pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? 3327 jQuery( selectors, context || this.context ) : 3328 0; 3329 3330 for ( ; i < l; i++ ) { 3331 for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) { 3332 // Always skip document fragments 3333 if ( cur.nodeType < 11 && (pos ? 3334 pos.index(cur) > -1 : 3335 3336 // Don't pass non-elements to Sizzle 3337 cur.nodeType === 1 && 3338 jQuery.find.matchesSelector(cur, selectors)) ) { 3339 3340 matched.push( cur ); 3341 break; 3342 } 3343 } 3344 } 3345 3346 return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched ); 3347 }, 3348 3349 // Determine the position of an element within 3350 // the matched set of elements 3351 index: function( elem ) { 3352 3353 // No argument, return index in parent 3354 if ( !elem ) { 3355 return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1; 3356 } 3357 3358 // index in selector 3359 if ( typeof elem === "string" ) { 3360 return jQuery.inArray( this[0], jQuery( elem ) ); 3361 } 3362 3363 // Locate the position of the desired element 3364 return jQuery.inArray( 3365 // If it receives a jQuery object, the first element is used 3366 elem.jquery ? elem[0] : elem, this ); 3367 }, 3368 3369 add: function( selector, context ) { 3370 return this.pushStack( 3371 jQuery.unique( 3372 jQuery.merge( this.get(), jQuery( selector, context ) ) 3373 ) 3374 ); 3375 }, 3376 3377 addBack: function( selector ) { 3378 return this.add( selector == null ? 3379 this.prevObject : this.prevObject.filter(selector) 3380 ); 3381 } 3382}); 3383 3384function sibling( cur, dir ) { 3385 do { 3386 cur = cur[ dir ]; 3387 } while ( cur && cur.nodeType !== 1 ); 3388 3389 return cur; 3390} 3391 3392jQuery.each({ 3393 parent: function( elem ) { 3394 var parent = elem.parentNode; 3395 return parent && parent.nodeType !== 11 ? parent : null; 3396 }, 3397 parents: function( elem ) { 3398 return jQuery.dir( elem, "parentNode" ); 3399 }, 3400 parentsUntil: function( elem, i, until ) { 3401 return jQuery.dir( elem, "parentNode", until ); 3402 }, 3403 next: function( elem ) { 3404 return sibling( elem, "nextSibling" ); 3405 }, 3406 prev: function( elem ) { 3407 return sibling( elem, "previousSibling" ); 3408 }, 3409 nextAll: function( elem ) { 3410 return jQuery.dir( elem, "nextSibling" ); 3411 }, 3412 prevAll: function( elem ) { 3413 return jQuery.dir( elem, "previousSibling" ); 3414 }, 3415 nextUntil: function( elem, i, until ) { 3416 return jQuery.dir( elem, "nextSibling", until ); 3417 }, 3418 prevUntil: function( elem, i, until ) { 3419 return jQuery.dir( elem, "previousSibling", until ); 3420 }, 3421 siblings: function( elem ) { 3422 return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); 3423 }, 3424 children: function( elem ) { 3425 return jQuery.sibling( elem.firstChild ); 3426 }, 3427 contents: function( elem ) { 3428 return jQuery.nodeName( elem, "iframe" ) ? 3429 elem.contentDocument || elem.contentWindow.document : 3430 jQuery.merge( [], elem.childNodes ); 3431 } 3432}, function( name, fn ) { 3433 jQuery.fn[ name ] = function( until, selector ) { 3434 var ret = jQuery.map( this, fn, until ); 3435 3436 if ( name.slice( -5 ) !== "Until" ) { 3437 selector = until; 3438 } 3439 3440 if ( selector && typeof selector === "string" ) { 3441 ret = jQuery.filter( selector, ret ); 3442 } 3443 3444 if ( this.length > 1 ) { 3445 // Remove duplicates 3446 if ( !guaranteedUnique[ name ] ) { 3447 ret = jQuery.unique( ret ); 3448 } 3449 3450 // Reverse order for parents* and prev-derivatives 3451 if ( rparentsprev.test( name ) ) { 3452 ret = ret.reverse(); 3453 } 3454 } 3455 3456 return this.pushStack( ret ); 3457 }; 3458}); 3459var rnotwhite = (/\S+/g); 3460 3461// String to Object options format cache 3462var optionsCache = {}; 3463 3464// Convert String-formatted options into Object-formatted ones and store in cache 3465function createOptions( options ) { 3466 var object = optionsCache[ options ] = {}; 3467 jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { 3468 object[ flag ] = true; 3469 }); 3470 return object; 3471} 3472 3473/* 3474 * Create a callback list using the following parameters: 3475 * 3476 * options: an optional list of space-separated options that will change how 3477 * the callback list behaves or a more traditional option object 3478 * 3479 * By default a callback list will act like an event callback list and can be 3480 * "fired" multiple times. 3481 * 3482 * Possible options: 3483 * 3484 * once: will ensure the callback list can only be fired once (like a Deferred) 3485 * 3486 * memory: will keep track of previous values and will call any callback added 3487 * after the list has been fired right away with the latest "memorized" 3488 * values (like a Deferred) 3489 * 3490 * unique: will ensure a callback can only be added once (no duplicate in the list) 3491 * 3492 * stopOnFalse: interrupt callings when a callback returns false 3493 * 3494 */ 3495jQuery.Callbacks = function( options ) { 3496 3497 // Convert options from String-formatted to Object-formatted if needed 3498 // (we check in cache first) 3499 options = typeof options === "string" ? 3500 ( optionsCache[ options ] || createOptions( options ) ) : 3501 jQuery.extend( {}, options ); 3502 3503 var // Flag to know if list is currently firing 3504 firing, 3505 // Last fire value (for non-forgettable lists) 3506 memory, 3507 // Flag to know if list was already fired 3508 fired, 3509 // End of the loop when firing 3510 firingLength, 3511 // Index of currently firing callback (modified by remove if needed) 3512 firingIndex, 3513 // First callback to fire (used internally by add and fireWith) 3514 firingStart, 3515 // Actual callback list 3516 list = [], 3517 // Stack of fire calls for repeatable lists 3518 stack = !options.once && [], 3519 // Fire callbacks 3520 fire = function( data ) { 3521 memory = options.memory && data; 3522 fired = true; 3523 firingIndex = firingStart || 0; 3524 firingStart = 0; 3525 firingLength = list.length; 3526 firing = true; 3527 for ( ; list && firingIndex < firingLength; firingIndex++ ) { 3528 if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { 3529 memory = false; // To prevent further calls using add 3530 break; 3531 } 3532 } 3533 firing = false; 3534 if ( list ) { 3535 if ( stack ) { 3536 if ( stack.length ) { 3537 fire( stack.shift() ); 3538 } 3539 } else if ( memory ) { 3540 list = []; 3541 } else { 3542 self.disable(); 3543 } 3544 } 3545 }, 3546 // Actual Callbacks object 3547 self = { 3548 // Add a callback or a collection of callbacks to the list 3549 add: function() { 3550 if ( list ) { 3551 // First, we save the current length 3552 var start = list.length; 3553 (function add( args ) { 3554 jQuery.each( args, function( _, arg ) { 3555 var type = jQuery.type( arg ); 3556 if ( type === "function" ) { 3557 if ( !options.unique || !self.has( arg ) ) { 3558 list.push( arg ); 3559 } 3560 } else if ( arg && arg.length && type !== "string" ) { 3561 // Inspect recursively 3562 add( arg ); 3563 } 3564 }); 3565 })( arguments ); 3566 // Do we need to add the callbacks to the 3567 // current firing batch? 3568 if ( firing ) { 3569 firingLength = list.length; 3570 // With memory, if we're not firing then 3571 // we should call right away 3572 } else if ( memory ) { 3573 firingStart = start; 3574 fire( memory ); 3575 } 3576 } 3577 return this; 3578 }, 3579 // Remove a callback from the list 3580 remove: function() { 3581 if ( list ) { 3582 jQuery.each( arguments, function( _, arg ) { 3583 var index; 3584 while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { 3585 list.splice( index, 1 ); 3586 // Handle firing indexes 3587 if ( firing ) { 3588 if ( index <= firingLength ) { 3589 firingLength--; 3590 } 3591 if ( index <= firingIndex ) { 3592 firingIndex--; 3593 } 3594 } 3595 } 3596 }); 3597 } 3598 return this; 3599 }, 3600 // Check if a given callback is in the list. 3601 // If no argument is given, return whether or not list has callbacks attached. 3602 has: function( fn ) { 3603 return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); 3604 }, 3605 // Remove all callbacks from the list 3606 empty: function() { 3607 list = []; 3608 firingLength = 0; 3609 return this; 3610 }, 3611 // Have the list do nothing anymore 3612 disable: function() { 3613 list = stack = memory = undefined; 3614 return this; 3615 }, 3616 // Is it disabled? 3617 disabled: function() { 3618 return !list; 3619 }, 3620 // Lock the list in its current state 3621 lock: function() { 3622 stack = undefined; 3623 if ( !memory ) { 3624 self.disable(); 3625 } 3626 return this; 3627 }, 3628 // Is it locked? 3629 locked: function() { 3630 return !stack; 3631 }, 3632 // Call all callbacks with the given context and arguments 3633 fireWith: function( context, args ) { 3634 if ( list && ( !fired || stack ) ) { 3635 args = args || []; 3636 args = [ context, args.slice ? args.slice() : args ]; 3637 if ( firing ) { 3638 stack.push( args ); 3639 } else { 3640 fire( args ); 3641 } 3642 } 3643 return this; 3644 }, 3645 // Call all the callbacks with the given arguments 3646 fire: function() { 3647 self.fireWith( this, arguments ); 3648 return this; 3649 }, 3650 // To know if the callbacks have already been called at least once 3651 fired: function() { 3652 return !!fired; 3653 } 3654 }; 3655 3656 return self; 3657}; 3658 3659jQuery.extend({ 3660 3661 Deferred: function( func ) { 3662 var tuples = [ 3663 // action, add listener, listener list, final state 3664 [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], 3665 [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], 3666 [ "notify", "progress", jQuery.Callbacks("memory") ] 3667 ], 3668 state = "pending", 3669 promise = { 3670 state: function() { 3671 return state; 3672 }, 3673 always: function() { 3674 deferred.done( arguments ).fail( arguments ); 3675 return this; 3676 }, 3677 then: function( /* fnDone, fnFail, fnProgress */ ) { 3678 var fns = arguments; 3679 return jQuery.Deferred(function( newDefer ) { 3680 jQuery.each( tuples, function( i, tuple ) { 3681 var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; 3682 // deferred[ done | fail | progress ] for forwarding actions to newDefer 3683 deferred[ tuple[1] ](function() { 3684 var returned = fn && fn.apply( this, arguments ); 3685 if ( returned && jQuery.isFunction( returned.promise ) ) { 3686 returned.promise() 3687 .done( newDefer.resolve ) 3688 .fail( newDefer.reject ) 3689 .progress( newDefer.notify ); 3690 } else { 3691 newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); 3692 } 3693 }); 3694 }); 3695 fns = null; 3696 }).promise(); 3697 }, 3698 // Get a promise for this deferred 3699 // If obj is provided, the promise aspect is added to the object 3700 promise: function( obj ) { 3701 return obj != null ? jQuery.extend( obj, promise ) : promise; 3702 } 3703 }, 3704 deferred = {}; 3705 3706 // Keep pipe for back-compat 3707 promise.pipe = promise.then; 3708 3709 // Add list-specific methods 3710 jQuery.each( tuples, function( i, tuple ) { 3711 var list = tuple[ 2 ], 3712 stateString = tuple[ 3 ]; 3713 3714 // promise[ done | fail | progress ] = list.add 3715 promise[ tuple[1] ] = list.add; 3716 3717 // Handle state 3718 if ( stateString ) { 3719 list.add(function() { 3720 // state = [ resolved | rejected ] 3721 state = stateString; 3722 3723 // [ reject_list | resolve_list ].disable; progress_list.lock 3724 }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); 3725 } 3726 3727 // deferred[ resolve | reject | notify ] 3728 deferred[ tuple[0] ] = function() { 3729 deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); 3730 return this; 3731 }; 3732 deferred[ tuple[0] + "With" ] = list.fireWith; 3733 }); 3734 3735 // Make the deferred a promise 3736 promise.promise( deferred ); 3737 3738 // Call given func if any 3739 if ( func ) { 3740 func.call( deferred, deferred ); 3741 } 3742 3743 // All done! 3744 return deferred; 3745 }, 3746 3747 // Deferred helper 3748 when: function( subordinate /* , ..., subordinateN */ ) { 3749 var i = 0, 3750 resolveValues = slice.call( arguments ), 3751 length = resolveValues.length, 3752 3753 // the count of uncompleted subordinates 3754 remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, 3755 3756 // the master Deferred. If resolveValues consist of only a single Deferred, just use that. 3757 deferred = remaining === 1 ? subordinate : jQuery.Deferred(), 3758 3759 // Update function for both resolve and progress values 3760 updateFunc = function( i, contexts, values ) { 3761 return function( value ) { 3762 contexts[ i ] = this; 3763 values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; 3764 if ( values === progressValues ) { 3765 deferred.notifyWith( contexts, values ); 3766 3767 } else if ( !(--remaining) ) { 3768 deferred.resolveWith( contexts, values ); 3769 } 3770 }; 3771 }, 3772 3773 progressValues, progressContexts, resolveContexts; 3774 3775 // add listeners to Deferred subordinates; treat others as resolved 3776 if ( length > 1 ) { 3777 progressValues = new Array( length ); 3778 progressContexts = new Array( length ); 3779 resolveContexts = new Array( length ); 3780 for ( ; i < length; i++ ) { 3781 if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { 3782 resolveValues[ i ].promise() 3783 .done( updateFunc( i, resolveContexts, resolveValues ) ) 3784 .fail( deferred.reject ) 3785 .progress( updateFunc( i, progressContexts, progressValues ) ); 3786 } else { 3787 --remaining; 3788 } 3789 } 3790 } 3791 3792 // if we're not waiting on anything, resolve the master 3793 if ( !remaining ) { 3794 deferred.resolveWith( resolveContexts, resolveValues ); 3795 } 3796 3797 return deferred.promise(); 3798 } 3799}); 3800 3801// The deferred used on DOM ready 3802var readyList; 3803 3804jQuery.fn.ready = function( fn ) { 3805 // Add the callback 3806 jQuery.ready.promise().done( fn ); 3807 3808 return this; 3809}; 3810 3811jQuery.extend({ 3812 // Is the DOM ready to be used? Set to true once it occurs. 3813 isReady: false, 3814 3815 // A counter to track how many items to wait for before 3816 // the ready event fires. See #6781 3817 readyWait: 1, 3818 3819 // Hold (or release) the ready event 3820 holdReady: function( hold ) { 3821 if ( hold ) { 3822 jQuery.readyWait++; 3823 } else { 3824 jQuery.ready( true ); 3825 } 3826 }, 3827 3828 // Handle when the DOM is ready 3829 ready: function( wait ) { 3830 3831 // Abort if there are pending holds or we're already ready 3832 if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { 3833 return; 3834 } 3835 3836 // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). 3837 if ( !document.body ) { 3838 return setTimeout( jQuery.ready ); 3839 } 3840 3841 // Remember that the DOM is ready 3842 jQuery.isReady = true; 3843 3844 // If a normal DOM Ready event fired, decrement, and wait if need be 3845 if ( wait !== true && --jQuery.readyWait > 0 ) { 3846 return; 3847 } 3848 3849 // If there are functions bound, to execute 3850 readyList.resolveWith( document, [ jQuery ] ); 3851 3852 // Trigger any bound ready events 3853 if ( jQuery.fn.triggerHandler ) { 3854 jQuery( document ).triggerHandler( "ready" ); 3855 jQuery( document ).off( "ready" ); 3856 } 3857 } 3858}); 3859 3860/** 3861 * Clean-up method for dom ready events 3862 */ 3863function detach() { 3864 if ( document.addEventListener ) { 3865 document.removeEventListener( "DOMContentLoaded", completed, false ); 3866 window.removeEventListener( "load", completed, false ); 3867 3868 } else { 3869 document.detachEvent( "onreadystatechange", completed ); 3870 window.detachEvent( "onload", completed ); 3871 } 3872} 3873 3874/** 3875 * The ready event handler and self cleanup method 3876 */ 3877function completed() { 3878 // readyState === "complete" is good enough for us to call the dom ready in oldIE 3879 if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { 3880 detach(); 3881 jQuery.ready(); 3882 } 3883} 3884 3885jQuery.ready.promise = function( obj ) { 3886 if ( !readyList ) { 3887 3888 readyList = jQuery.Deferred(); 3889 3890 // Catch cases where $(document).ready() is called after the browser event has already occurred. 3891 // we once tried to use readyState "interactive" here, but it caused issues like the one 3892 // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 3893 if ( document.readyState === "complete" ) { 3894 // Handle it asynchronously to allow scripts the opportunity to delay ready 3895 setTimeout( jQuery.ready ); 3896 3897 // Standards-based browsers support DOMContentLoaded 3898 } else if ( document.addEventListener ) { 3899 // Use the handy event callback 3900 document.addEventListener( "DOMContentLoaded", completed, false ); 3901 3902 // A fallback to window.onload, that will always work 3903 window.addEventListener( "load", completed, false ); 3904 3905 // If IE event model is used 3906 } else { 3907 // Ensure firing before onload, maybe late but safe also for iframes 3908 document.attachEvent( "onreadystatechange", completed ); 3909 3910 // A fallback to window.onload, that will always work 3911 window.attachEvent( "onload", completed ); 3912 3913 // If IE and not a frame 3914 // continually check to see if the document is ready 3915 var top = false; 3916 3917 try { 3918 top = window.frameElement == null && document.documentElement; 3919 } catch(e) {} 3920 3921 if ( top && top.doScroll ) { 3922 (function doScrollCheck() { 3923 if ( !jQuery.isReady ) { 3924 3925 try { 3926 // Use the trick by Diego Perini 3927 // http://javascript.nwbox.com/IEContentLoaded/ 3928 top.doScroll("left"); 3929 } catch(e) { 3930 return setTimeout( doScrollCheck, 50 ); 3931 } 3932 3933 // detach all dom ready events 3934 detach(); 3935 3936 // and execute any waiting functions 3937 jQuery.ready(); 3938 } 3939 })(); 3940 } 3941 } 3942 } 3943 return readyList.promise( obj ); 3944}; 3945 3946var strundefined = typeof undefined; 3947 3948// Support: IE<9 3949// Iteration over object's inherited properties before its own 3950var i; 3951for ( i in jQuery( support ) ) { 3952 break; 3953} 3954support.ownLast = i !== "0"; 3955 3956// Note: most support tests are defined in their respective modules. 3957// false until the test is run 3958support.inlineBlockNeedsLayout = false; 3959 3960// Execute ASAP in case we need to set body.style.zoom 3961jQuery(function() { 3962 // Minified: var a,b,c,d 3963 var val, div, body, container; 3964 3965 body = document.getElementsByTagName( "body" )[ 0 ]; 3966 if ( !body || !body.style ) { 3967 // Return for frameset docs that don't have a body 3968 return; 3969 } 3970 3971 // Setup 3972 div = document.createElement( "div" ); 3973 container = document.createElement( "div" ); 3974 container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px"; 3975 body.appendChild( container ).appendChild( div ); 3976 3977 if ( typeof div.style.zoom !== strundefined ) { 3978 // Support: IE<8 3979 // Check if natively block-level elements act like inline-block 3980 // elements when setting their display to 'inline' and giving 3981 // them layout 3982 div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1"; 3983 3984 support.inlineBlockNeedsLayout = val = div.offsetWidth === 3; 3985 if ( val ) { 3986 // Prevent IE 6 from affecting layout for positioned elements #11048 3987 // Prevent IE from shrinking the body in IE 7 mode #12869 3988 // Support: IE<8 3989 body.style.zoom = 1; 3990 } 3991 } 3992 3993 body.removeChild( container ); 3994}); 3995 3996(function() { 3997 var div = document.createElement( "div" ); 3998 3999 // Execute the test only if not already executed in another module. 4000 if (support.deleteExpando == null) { 4001 // Support: IE<9 4002 support.deleteExpando = true; 4003 try { 4004 delete div.test; 4005 } catch( e ) { 4006 support.deleteExpando = false; 4007 } 4008 } 4009 4010 // Null elements to avoid leaks in IE. 4011 div = null; 4012})(); 4013 4014/** 4015 * Determines whether an object can have data 4016 */ 4017jQuery.acceptData = function( elem ) { 4018 var noData = jQuery.noData[ (elem.nodeName + " ").toLowerCase() ], 4019 nodeType = +elem.nodeType || 1; 4020 4021 // Do not set data on non-element DOM nodes because it will not be cleared (#8335). 4022 return nodeType !== 1 && nodeType !== 9 ? 4023 false : 4024 4025 // Nodes accept data unless otherwise specified; rejection can be conditional 4026 !noData || noData !== true && elem.getAttribute("classid") === noData; 4027}; 4028 4029var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, 4030 rmultiDash = /([A-Z])/g; 4031 4032function dataAttr( elem, key, data ) { 4033 // If nothing was found internally, try to fetch any 4034 // data from the HTML5 data-* attribute 4035 if ( data === undefined && elem.nodeType === 1 ) { 4036 4037 var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); 4038 4039 data = elem.getAttribute( name ); 4040 4041 if ( typeof data === "string" ) { 4042 try { 4043 data = data === "true" ? true : 4044 data === "false" ? false : 4045 data === "null" ? null : 4046 // Only convert to a number if it doesn't change the string 4047 +data + "" === data ? +data : 4048 rbrace.test( data ) ? jQuery.parseJSON( data ) : 4049 data; 4050 } catch( e ) {} 4051 4052 // Make sure we set the data so it isn't changed later 4053 jQuery.data( elem, key, data ); 4054 4055 } else { 4056 data = undefined; 4057 } 4058 } 4059 4060 return data; 4061} 4062 4063// checks a cache object for emptiness 4064function isEmptyDataObject( obj ) { 4065 var name; 4066 for ( name in obj ) { 4067 4068 // if the public data object is empty, the private is still empty 4069 if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { 4070 continue; 4071 } 4072 if ( name !== "toJSON" ) { 4073 return false; 4074 } 4075 } 4076 4077 return true; 4078} 4079 4080function internalData( elem, name, data, pvt /* Internal Use Only */ ) { 4081 if ( !jQuery.acceptData( elem ) ) { 4082 return; 4083 } 4084 4085 var ret, thisCache, 4086 internalKey = jQuery.expando, 4087 4088 // We have to handle DOM nodes and JS objects differently because IE6-7 4089 // can't GC object references properly across the DOM-JS boundary 4090 isNode = elem.nodeType, 4091 4092 // Only DOM nodes need the global jQuery cache; JS object data is 4093 // attached directly to the object so GC can occur automatically 4094 cache = isNode ? jQuery.cache : elem, 4095 4096 // Only defining an ID for JS objects if its cache already exists allows 4097 // the code to shortcut on the same path as a DOM node with no cache 4098 id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; 4099 4100 // Avoid doing any more work than we need to when trying to get data on an 4101 // object that has no data at all 4102 if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) { 4103 return; 4104 } 4105 4106 if ( !id ) { 4107 // Only DOM nodes need a new unique ID for each element since their data 4108 // ends up in the global cache 4109 if ( isNode ) { 4110 id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++; 4111 } else { 4112 id = internalKey; 4113 } 4114 } 4115 4116 if ( !cache[ id ] ) { 4117 // Avoid exposing jQuery metadata on plain JS objects when the object 4118 // is serialized using JSON.stringify 4119 cache[ id ] = isNode ? {} : { toJSON: jQuery.noop }; 4120 } 4121 4122 // An object can be passed to jQuery.data instead of a key/value pair; this gets 4123 // shallow copied over onto the existing cache 4124 if ( typeof name === "object" || typeof name === "function" ) { 4125 if ( pvt ) { 4126 cache[ id ] = jQuery.extend( cache[ id ], name ); 4127 } else { 4128 cache[ id ].data = jQuery.extend( cache[ id ].data, name ); 4129 } 4130 } 4131 4132 thisCache = cache[ id ]; 4133 4134 // jQuery data() is stored in a separate object inside the object's internal data 4135 // cache in order to avoid key collisions between internal data and user-defined 4136 // data. 4137 if ( !pvt ) { 4138 if ( !thisCache.data ) { 4139 thisCache.data = {}; 4140 } 4141 4142 thisCache = thisCache.data; 4143 } 4144 4145 if ( data !== undefined ) { 4146 thisCache[ jQuery.camelCase( name ) ] = data; 4147 } 4148 4149 // Check for both converted-to-camel and non-converted data property names 4150 // If a data property was specified 4151 if ( typeof name === "string" ) { 4152 4153 // First Try to find as-is property data 4154 ret = thisCache[ name ]; 4155 4156 // Test for null|undefined property data 4157 if ( ret == null ) { 4158 4159 // Try to find the camelCased property 4160 ret = thisCache[ jQuery.camelCase( name ) ]; 4161 } 4162 } else { 4163 ret = thisCache; 4164 } 4165 4166 return ret; 4167} 4168 4169function internalRemoveData( elem, name, pvt ) { 4170 if ( !jQuery.acceptData( elem ) ) { 4171 return; 4172 } 4173 4174 var thisCache, i, 4175 isNode = elem.nodeType, 4176 4177 // See jQuery.data for more information 4178 cache = isNode ? jQuery.cache : elem, 4179 id = isNode ? elem[ jQuery.expando ] : jQuery.expando; 4180 4181 // If there is already no cache entry for this object, there is no 4182 // purpose in continuing 4183 if ( !cache[ id ] ) { 4184 return; 4185 } 4186 4187 if ( name ) { 4188 4189 thisCache = pvt ? cache[ id ] : cache[ id ].data; 4190 4191 if ( thisCache ) { 4192 4193 // Support array or space separated string names for data keys 4194 if ( !jQuery.isArray( name ) ) { 4195 4196 // try the string as a key before any manipulation 4197 if ( name in thisCache ) { 4198 name = [ name ]; 4199 } else { 4200 4201 // split the camel cased version by spaces unless a key with the spaces exists 4202 name = jQuery.camelCase( name ); 4203 if ( name in thisCache ) { 4204 name = [ name ]; 4205 } else { 4206 name = name.split(" "); 4207 } 4208 } 4209 } else { 4210 // If "name" is an array of keys... 4211 // When data is initially created, via ("key", "val") signature, 4212 // keys will be converted to camelCase. 4213 // Since there is no way to tell _how_ a key was added, remove 4214 // both plain key and camelCase key. #12786 4215 // This will only penalize the array argument path. 4216 name = name.concat( jQuery.map( name, jQuery.camelCase ) ); 4217 } 4218 4219 i = name.length; 4220 while ( i-- ) { 4221 delete thisCache[ name[i] ]; 4222 } 4223 4224 // If there is no data left in the cache, we want to continue 4225 // and let the cache object itself get destroyed 4226 if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) { 4227 return; 4228 } 4229 } 4230 } 4231 4232 // See jQuery.data for more information 4233 if ( !pvt ) { 4234 delete cache[ id ].data; 4235 4236 // Don't destroy the parent cache unless the internal data object 4237 // had been the only thing left in it 4238 if ( !isEmptyDataObject( cache[ id ] ) ) { 4239 return; 4240 } 4241 } 4242 4243 // Destroy the cache 4244 if ( isNode ) { 4245 jQuery.cleanData( [ elem ], true ); 4246 4247 // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) 4248 /* jshint eqeqeq: false */ 4249 } else if ( support.deleteExpando || cache != cache.window ) { 4250 /* jshint eqeqeq: true */ 4251 delete cache[ id ]; 4252 4253 // When all else fails, null 4254 } else { 4255 cache[ id ] = null; 4256 } 4257} 4258 4259jQuery.extend({ 4260 cache: {}, 4261 4262 // The following elements (space-suffixed to avoid Object.prototype collisions) 4263 // throw uncatchable exceptions if you attempt to set expando properties 4264 noData: { 4265 "applet ": true, 4266 "embed ": true, 4267 // ...but Flash objects (which have this classid) *can* handle expandos 4268 "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" 4269 }, 4270 4271 hasData: function( elem ) { 4272 elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; 4273 return !!elem && !isEmptyDataObject( elem ); 4274 }, 4275 4276 data: function( elem, name, data ) { 4277 return internalData( elem, name, data ); 4278 }, 4279 4280 removeData: function( elem, name ) { 4281 return internalRemoveData( elem, name ); 4282 }, 4283 4284 // For internal use only. 4285 _data: function( elem, name, data ) { 4286 return internalData( elem, name, data, true ); 4287 }, 4288 4289 _removeData: function( elem, name ) { 4290 return internalRemoveData( elem, name, true ); 4291 } 4292}); 4293 4294jQuery.fn.extend({ 4295 data: function( key, value ) { 4296 var i, name, data, 4297 elem = this[0], 4298 attrs = elem && elem.attributes; 4299 4300 // Special expections of .data basically thwart jQuery.access, 4301 // so implement the relevant behavior ourselves 4302 4303 // Gets all values 4304 if ( key === undefined ) { 4305 if ( this.length ) { 4306 data = jQuery.data( elem ); 4307 4308 if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { 4309 i = attrs.length; 4310 while ( i-- ) { 4311 4312 // Support: IE11+ 4313 // The attrs elements can be null (#14894) 4314 if ( attrs[ i ] ) { 4315 name = attrs[ i ].name; 4316 if ( name.indexOf( "data-" ) === 0 ) { 4317 name = jQuery.camelCase( name.slice(5) ); 4318 dataAttr( elem, name, data[ name ] ); 4319 } 4320 } 4321 } 4322 jQuery._data( elem, "parsedAttrs", true ); 4323 } 4324 } 4325 4326 return data; 4327 } 4328 4329 // Sets multiple values 4330 if ( typeof key === "object" ) { 4331 return this.each(function() { 4332 jQuery.data( this, key ); 4333 }); 4334 } 4335 4336 return arguments.length > 1 ? 4337 4338 // Sets one value 4339 this.each(function() { 4340 jQuery.data( this, key, value ); 4341 }) : 4342 4343 // Gets one value 4344 // Try to fetch any internally stored data first 4345 elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined; 4346 }, 4347 4348 removeData: function( key ) { 4349 return this.each(function() { 4350 jQuery.removeData( this, key ); 4351 }); 4352 } 4353}); 4354 4355jQuery.extend({ 4356 queue: function( elem, type, data ) { 4357 var queue; 4358 4359 if ( elem ) { 4360 type = ( type || "fx" ) + "queue"; 4361 queue = jQuery._data( elem, type ); 4362 4363 // Speed up dequeue by getting out quickly if this is just a lookup 4364 if ( data ) { 4365 if ( !queue || jQuery.isArray(data) ) { 4366 queue = jQuery._data( elem, type, jQuery.makeArray(data) ); 4367 } else { 4368 queue.push( data ); 4369 } 4370 } 4371 return queue || []; 4372 } 4373 }, 4374 4375 dequeue: function( elem, type ) { 4376 type = type || "fx"; 4377 4378 var queue = jQuery.queue( elem, type ), 4379 startLength = queue.length, 4380 fn = queue.shift(), 4381 hooks = jQuery._queueHooks( elem, type ), 4382 next = function() { 4383 jQuery.dequeue( elem, type ); 4384 }; 4385 4386 // If the fx queue is dequeued, always remove the progress sentinel 4387 if ( fn === "inprogress" ) { 4388 fn = queue.shift(); 4389 startLength--; 4390 } 4391 4392 if ( fn ) { 4393 4394 // Add a progress sentinel to prevent the fx queue from being 4395 // automatically dequeued 4396 if ( type === "fx" ) { 4397 queue.unshift( "inprogress" ); 4398 } 4399 4400 // clear up the last queue stop function 4401 delete hooks.stop; 4402 fn.call( elem, next, hooks ); 4403 } 4404 4405 if ( !startLength && hooks ) { 4406 hooks.empty.fire(); 4407 } 4408 }, 4409 4410 // not intended for public consumption - generates a queueHooks object, or returns the current one 4411 _queueHooks: function( elem, type ) { 4412 var key = type + "queueHooks"; 4413 return jQuery._data( elem, key ) || jQuery._data( elem, key, { 4414 empty: jQuery.Callbacks("once memory").add(function() { 4415 jQuery._removeData( elem, type + "queue" ); 4416 jQuery._removeData( elem, key ); 4417 }) 4418 }); 4419 } 4420}); 4421 4422jQuery.fn.extend({ 4423 queue: function( type, data ) { 4424 var setter = 2; 4425 4426 if ( typeof type !== "string" ) { 4427 data = type; 4428 type = "fx"; 4429 setter--; 4430 } 4431 4432 if ( arguments.length < setter ) { 4433 return jQuery.queue( this[0], type ); 4434 } 4435 4436 return data === undefined ? 4437 this : 4438 this.each(function() { 4439 var queue = jQuery.queue( this, type, data ); 4440 4441 // ensure a hooks for this queue 4442 jQuery._queueHooks( this, type ); 4443 4444 if ( type === "fx" && queue[0] !== "inprogress" ) { 4445 jQuery.dequeue( this, type ); 4446 } 4447 }); 4448 }, 4449 dequeue: function( type ) { 4450 return this.each(function() { 4451 jQuery.dequeue( this, type ); 4452 }); 4453 }, 4454 clearQueue: function( type ) { 4455 return this.queue( type || "fx", [] ); 4456 }, 4457 // Get a promise resolved when queues of a certain type 4458 // are emptied (fx is the type by default) 4459 promise: function( type, obj ) { 4460 var tmp, 4461 count = 1, 4462 defer = jQuery.Deferred(), 4463 elements = this, 4464 i = this.length, 4465 resolve = function() { 4466 if ( !( --count ) ) { 4467 defer.resolveWith( elements, [ elements ] ); 4468 } 4469 }; 4470 4471 if ( typeof type !== "string" ) { 4472 obj = type; 4473 type = undefined; 4474 } 4475 type = type || "fx"; 4476 4477 while ( i-- ) { 4478 tmp = jQuery._data( elements[ i ], type + "queueHooks" ); 4479 if ( tmp && tmp.empty ) { 4480 count++; 4481 tmp.empty.add( resolve ); 4482 } 4483 } 4484 resolve(); 4485 return defer.promise( obj ); 4486 } 4487}); 4488var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source; 4489 4490var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; 4491 4492var isHidden = function( elem, el ) { 4493 // isHidden might be called from jQuery#filter function; 4494 // in that case, element will be second argument 4495 elem = el || elem; 4496 return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); 4497 }; 4498 4499// Multifunctional method to get and set values of a collection 4500// The value/s can optionally be executed if it's a function 4501var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) { 4502 var i = 0, 4503 length = elems.length, 4504 bulk = key == null; 4505 4506 // Sets many values 4507 if ( jQuery.type( key ) === "object" ) { 4508 chainable = true; 4509 for ( i in key ) { 4510 jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); 4511 } 4512 4513 // Sets one value 4514 } else if ( value !== undefined ) { 4515 chainable = true; 4516 4517 if ( !jQuery.isFunction( value ) ) { 4518 raw = true; 4519 } 4520 4521 if ( bulk ) { 4522 // Bulk operations run against the entire set 4523 if ( raw ) { 4524 fn.call( elems, value ); 4525 fn = null; 4526 4527 // ...except when executing function values 4528 } else { 4529 bulk = fn; 4530 fn = function( elem, key, value ) { 4531 return bulk.call( jQuery( elem ), value ); 4532 }; 4533 } 4534 } 4535 4536 if ( fn ) { 4537 for ( ; i < length; i++ ) { 4538 fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); 4539 } 4540 } 4541 } 4542 4543 return chainable ? 4544 elems : 4545 4546 // Gets 4547 bulk ? 4548 fn.call( elems ) : 4549 length ? fn( elems[0], key ) : emptyGet; 4550}; 4551var rcheckableType = (/^(?:checkbox|radio)$/i); 4552 4553(function() { 4554 // Minified: var a,b,c 4555 var input = document.createElement( "input" ), 4556 div = document.createElement( "div" ), 4557 fragment = document.createDocumentFragment(); 4558 4559 // Setup 4560 div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>"; 4561 4562 // IE strips leading whitespace when .innerHTML is used 4563 support.leadingWhitespace = div.firstChild.nodeType === 3; 4564 4565 // Make sure that tbody elements aren't automatically inserted 4566 // IE will insert them into empty tables 4567 support.tbody = !div.getElementsByTagName( "tbody" ).length; 4568 4569 // Make sure that link elements get serialized correctly by innerHTML 4570 // This requires a wrapper element in IE 4571 support.htmlSerialize = !!div.getElementsByTagName( "link" ).length; 4572 4573 // Makes sure cloning an html5 element does not cause problems 4574 // Where outerHTML is undefined, this still works 4575 support.html5Clone = 4576 document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav></:nav>"; 4577 4578 // Check if a disconnected checkbox will retain its checked 4579 // value of true after appended to the DOM (IE6/7) 4580 input.type = "checkbox"; 4581 input.checked = true; 4582 fragment.appendChild( input ); 4583 support.appendChecked = input.checked; 4584 4585 // Make sure textarea (and checkbox) defaultValue is properly cloned 4586 // Support: IE6-IE11+ 4587 div.innerHTML = "<textarea>x</textarea>"; 4588 support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; 4589 4590 // #11217 - WebKit loses check when the name is after the checked attribute 4591 fragment.appendChild( div ); 4592 div.innerHTML = "<input type='radio' checked='checked' name='t'/>"; 4593 4594 // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3 4595 // old WebKit doesn't clone checked state correctly in fragments 4596 support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; 4597 4598 // Support: IE<9 4599 // Opera does not clone events (and typeof div.attachEvent === undefined). 4600 // IE9-10 clones events bound via attachEvent, but they don't trigger with .click() 4601 support.noCloneEvent = true; 4602 if ( div.attachEvent ) { 4603 div.attachEvent( "onclick", function() { 4604 support.noCloneEvent = false; 4605 }); 4606 4607 div.cloneNode( true ).click(); 4608 } 4609 4610 // Execute the test only if not already executed in another module. 4611 if (support.deleteExpando == null) { 4612 // Support: IE<9 4613 support.deleteExpando = true; 4614 try { 4615 delete div.test; 4616 } catch( e ) { 4617 support.deleteExpando = false; 4618 } 4619 } 4620})(); 4621 4622(function() { 4623 var i, eventName, 4624 div = document.createElement( "div" ); 4625 4626 // Support: IE<9 (lack submit/change bubble), Firefox 23+ (lack focusin event) 4627 for ( i in { submit: true, change: true, focusin: true }) { 4628 eventName = "on" + i; 4629 4630 if ( !(support[ i + "Bubbles" ] = eventName in window) ) { 4631 // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP) 4632 div.setAttribute( eventName, "t" ); 4633 support[ i + "Bubbles" ] = div.attributes[ eventName ].expando === false; 4634 } 4635 } 4636 4637 // Null elements to avoid leaks in IE. 4638 div = null; 4639})(); 4640 4641var rformElems = /^(?:input|select|textarea)$/i, 4642 rkeyEvent = /^key/, 4643 rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/, 4644 rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, 4645 rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; 4646 4647function returnTrue() { 4648 return true; 4649} 4650 4651function returnFalse() { 4652 return false; 4653} 4654 4655function safeActiveElement() { 4656 try { 4657 return document.activeElement; 4658 } catch ( err ) { } 4659} 4660 4661/* 4662 * Helper functions for managing events -- not part of the public interface. 4663 * Props to Dean Edwards' addEvent library for many of the ideas. 4664 */ 4665jQuery.event = { 4666 4667 global: {}, 4668 4669 add: function( elem, types, handler, data, selector ) { 4670 var tmp, events, t, handleObjIn, 4671 special, eventHandle, handleObj, 4672 handlers, type, namespaces, origType, 4673 elemData = jQuery._data( elem ); 4674 4675 // Don't attach events to noData or text/comment nodes (but allow plain objects) 4676 if ( !elemData ) { 4677 return; 4678 } 4679 4680 // Caller can pass in an object of custom data in lieu of the handler 4681 if ( handler.handler ) { 4682 handleObjIn = handler; 4683 handler = handleObjIn.handler; 4684 selector = handleObjIn.selector; 4685 } 4686 4687 // Make sure that the handler has a unique ID, used to find/remove it later 4688 if ( !handler.guid ) { 4689 handler.guid = jQuery.guid++; 4690 } 4691 4692 // Init the element's event structure and main handler, if this is the first 4693 if ( !(events = elemData.events) ) { 4694 events = elemData.events = {}; 4695 } 4696 if ( !(eventHandle = elemData.handle) ) { 4697 eventHandle = elemData.handle = function( e ) { 4698 // Discard the second event of a jQuery.event.trigger() and 4699 // when an event is called after a page has unloaded 4700 return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ? 4701 jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : 4702 undefined; 4703 }; 4704 // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events 4705 eventHandle.elem = elem; 4706 } 4707 4708 // Handle multiple events separated by a space 4709 types = ( types || "" ).match( rnotwhite ) || [ "" ]; 4710 t = types.length; 4711 while ( t-- ) { 4712 tmp = rtypenamespace.exec( types[t] ) || []; 4713 type = origType = tmp[1]; 4714 namespaces = ( tmp[2] || "" ).split( "." ).sort(); 4715 4716 // There *must* be a type, no attaching namespace-only handlers 4717 if ( !type ) { 4718 continue; 4719 } 4720 4721 // If event changes its type, use the special event handlers for the changed type 4722 special = jQuery.event.special[ type ] || {}; 4723 4724 // If selector defined, determine special event api type, otherwise given type 4725 type = ( selector ? special.delegateType : special.bindType ) || type; 4726 4727 // Update special based on newly reset type 4728 special = jQuery.event.special[ type ] || {}; 4729 4730 // handleObj is passed to all event handlers 4731 handleObj = jQuery.extend({ 4732 type: type, 4733 origType: origType, 4734 data: data, 4735 handler: handler, 4736 guid: handler.guid, 4737 selector: selector, 4738 needsContext: selector && jQuery.expr.match.needsContext.test( selector ), 4739 namespace: namespaces.join(".") 4740 }, handleObjIn ); 4741 4742 // Init the event handler queue if we're the first 4743 if ( !(handlers = events[ type ]) ) { 4744 handlers = events[ type ] = []; 4745 handlers.delegateCount = 0; 4746 4747 // Only use addEventListener/attachEvent if the special events handler returns false 4748 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { 4749 // Bind the global event handler to the element 4750 if ( elem.addEventListener ) { 4751 elem.addEventListener( type, eventHandle, false ); 4752 4753 } else if ( elem.attachEvent ) { 4754 elem.attachEvent( "on" + type, eventHandle ); 4755 } 4756 } 4757 } 4758 4759 if ( special.add ) { 4760 special.add.call( elem, handleObj ); 4761 4762 if ( !handleObj.handler.guid ) { 4763 handleObj.handler.guid = handler.guid; 4764 } 4765 } 4766 4767 // Add to the element's handler list, delegates in front 4768 if ( selector ) { 4769 handlers.splice( handlers.delegateCount++, 0, handleObj ); 4770 } else { 4771 handlers.push( handleObj ); 4772 } 4773 4774 // Keep track of which events have ever been used, for event optimization 4775 jQuery.event.global[ type ] = true; 4776 } 4777 4778 // Nullify elem to prevent memory leaks in IE 4779 elem = null; 4780 }, 4781 4782 // Detach an event or set of events from an element 4783 remove: function( elem, types, handler, selector, mappedTypes ) { 4784 var j, handleObj, tmp, 4785 origCount, t, events, 4786 special, handlers, type, 4787 namespaces, origType, 4788 elemData = jQuery.hasData( elem ) && jQuery._data( elem ); 4789 4790 if ( !elemData || !(events = elemData.events) ) { 4791 return; 4792 } 4793 4794 // Once for each type.namespace in types; type may be omitted 4795 types = ( types || "" ).match( rnotwhite ) || [ "" ]; 4796 t = types.length; 4797 while ( t-- ) { 4798 tmp = rtypenamespace.exec( types[t] ) || []; 4799 type = origType = tmp[1]; 4800 namespaces = ( tmp[2] || "" ).split( "." ).sort(); 4801 4802 // Unbind all events (on this namespace, if provided) for the element 4803 if ( !type ) { 4804 for ( type in events ) { 4805 jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); 4806 } 4807 continue; 4808 } 4809 4810 special = jQuery.event.special[ type ] || {}; 4811 type = ( selector ? special.delegateType : special.bindType ) || type; 4812 handlers = events[ type ] || []; 4813 tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); 4814 4815 // Remove matching events 4816 origCount = j = handlers.length; 4817 while ( j-- ) { 4818 handleObj = handlers[ j ]; 4819 4820 if ( ( mappedTypes || origType === handleObj.origType ) && 4821 ( !handler || handler.guid === handleObj.guid ) && 4822 ( !tmp || tmp.test( handleObj.namespace ) ) && 4823 ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { 4824 handlers.splice( j, 1 ); 4825 4826 if ( handleObj.selector ) { 4827 handlers.delegateCount--; 4828 } 4829 if ( special.remove ) { 4830 special.remove.call( elem, handleObj ); 4831 } 4832 } 4833 } 4834 4835 // Remove generic event handler if we removed something and no more handlers exist 4836 // (avoids potential for endless recursion during removal of special event handlers) 4837 if ( origCount && !handlers.length ) { 4838 if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { 4839 jQuery.removeEvent( elem, type, elemData.handle ); 4840 } 4841 4842 delete events[ type ]; 4843 } 4844 } 4845 4846 // Remove the expando if it's no longer used 4847 if ( jQuery.isEmptyObject( events ) ) { 4848 delete elemData.handle; 4849 4850 // removeData also checks for emptiness and clears the expando if empty 4851 // so use it instead of delete 4852 jQuery._removeData( elem, "events" ); 4853 } 4854 }, 4855 4856 trigger: function( event, data, elem, onlyHandlers ) { 4857 var handle, ontype, cur, 4858 bubbleType, special, tmp, i, 4859 eventPath = [ elem || document ], 4860 type = hasOwn.call( event, "type" ) ? event.type : event, 4861 namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; 4862 4863 cur = tmp = elem = elem || document; 4864 4865 // Don't do events on text and comment nodes 4866 if ( elem.nodeType === 3 || elem.nodeType === 8 ) { 4867 return; 4868 } 4869 4870 // focus/blur morphs to focusin/out; ensure we're not firing them right now 4871 if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { 4872 return; 4873 } 4874 4875 if ( type.indexOf(".") >= 0 ) { 4876 // Namespaced trigger; create a regexp to match event type in handle() 4877 namespaces = type.split("."); 4878 type = namespaces.shift(); 4879 namespaces.sort(); 4880 } 4881 ontype = type.indexOf(":") < 0 && "on" + type; 4882 4883 // Caller can pass in a jQuery.Event object, Object, or just an event type string 4884 event = event[ jQuery.expando ] ? 4885 event : 4886 new jQuery.Event( type, typeof event === "object" && event ); 4887 4888 // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) 4889 event.isTrigger = onlyHandlers ? 2 : 3; 4890 event.namespace = namespaces.join("."); 4891 event.namespace_re = event.namespace ? 4892 new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : 4893 null; 4894 4895 // Clean up the event in case it is being reused 4896 event.result = undefined; 4897 if ( !event.target ) { 4898 event.target = elem; 4899 } 4900 4901 // Clone any incoming data and prepend the event, creating the handler arg list 4902 data = data == null ? 4903 [ event ] : 4904 jQuery.makeArray( data, [ event ] ); 4905 4906 // Allow special events to draw outside the lines 4907 special = jQuery.event.special[ type ] || {}; 4908 if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { 4909 return; 4910 } 4911 4912 // Determine event propagation path in advance, per W3C events spec (#9951) 4913 // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) 4914 if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { 4915 4916 bubbleType = special.delegateType || type; 4917 if ( !rfocusMorph.test( bubbleType + type ) ) { 4918 cur = cur.parentNode; 4919 } 4920 for ( ; cur; cur = cur.parentNode ) { 4921 eventPath.push( cur ); 4922 tmp = cur; 4923 } 4924 4925 // Only add window if we got to document (e.g., not plain obj or detached DOM) 4926 if ( tmp === (elem.ownerDocument || document) ) { 4927 eventPath.push( tmp.defaultView || tmp.parentWindow || window ); 4928 } 4929 } 4930 4931 // Fire handlers on the event path 4932 i = 0; 4933 while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { 4934 4935 event.type = i > 1 ? 4936 bubbleType : 4937 special.bindType || type; 4938 4939 // jQuery handler 4940 handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); 4941 if ( handle ) { 4942 handle.apply( cur, data ); 4943 } 4944 4945 // Native handler 4946 handle = ontype && cur[ ontype ]; 4947 if ( handle && handle.apply && jQuery.acceptData( cur ) ) { 4948 event.result = handle.apply( cur, data ); 4949 if ( event.result === false ) { 4950 event.preventDefault(); 4951 } 4952 } 4953 } 4954 event.type = type; 4955 4956 // If nobody prevented the default action, do it now 4957 if ( !onlyHandlers && !event.isDefaultPrevented() ) { 4958 4959 if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) && 4960 jQuery.acceptData( elem ) ) { 4961 4962 // Call a native DOM method on the target with the same name name as the event. 4963 // Can't use an .isFunction() check here because IE6/7 fails that test. 4964 // Don't do default actions on window, that's where global variables be (#6170) 4965 if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { 4966 4967 // Don't re-trigger an onFOO event when we call its FOO() method 4968 tmp = elem[ ontype ]; 4969 4970 if ( tmp ) { 4971 elem[ ontype ] = null; 4972 } 4973 4974 // Prevent re-triggering of the same event, since we already bubbled it above 4975 jQuery.event.triggered = type; 4976 try { 4977 elem[ type ](); 4978 } catch ( e ) { 4979 // IE<9 dies on focus/blur to hidden element (#1486,#12518) 4980 // only reproducible on winXP IE8 native, not IE9 in IE8 mode 4981 } 4982 jQuery.event.triggered = undefined; 4983 4984 if ( tmp ) { 4985 elem[ ontype ] = tmp; 4986 } 4987 } 4988 } 4989 } 4990 4991 return event.result; 4992 }, 4993 4994 dispatch: function( event ) { 4995 4996 // Make a writable jQuery.Event from the native event object 4997 event = jQuery.event.fix( event ); 4998 4999 var i, ret, handleObj, matched, j, 5000 handlerQueue = [], 5001 args = slice.call( arguments ), 5002 handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], 5003 special = jQuery.event.special[ event.type ] || {}; 5004 5005 // Use the fix-ed jQuery.Event rather than the (read-only) native event 5006 args[0] = event; 5007 event.delegateTarget = this; 5008 5009 // Call the preDispatch hook for the mapped type, and let it bail if desired 5010 if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { 5011 return; 5012 } 5013 5014 // Determine handlers 5015 handlerQueue = jQuery.event.handlers.call( this, event, handlers ); 5016 5017 // Run delegates first; they may want to stop propagation beneath us 5018 i = 0; 5019 while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { 5020 event.currentTarget = matched.elem; 5021 5022 j = 0; 5023 while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { 5024 5025 // Triggered event must either 1) have no namespace, or 5026 // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). 5027 if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { 5028 5029 event.handleObj = handleObj; 5030 event.data = handleObj.data; 5031 5032 ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) 5033 .apply( matched.elem, args ); 5034 5035 if ( ret !== undefined ) { 5036 if ( (event.result = ret) === false ) { 5037 event.preventDefault(); 5038 event.stopPropagation(); 5039 } 5040 } 5041 } 5042 } 5043 } 5044 5045 // Call the postDispatch hook for the mapped type 5046 if ( special.postDispatch ) { 5047 special.postDispatch.call( this, event ); 5048 } 5049 5050 return event.result; 5051 }, 5052 5053 handlers: function( event, handlers ) { 5054 var sel, handleObj, matches, i, 5055 handlerQueue = [], 5056 delegateCount = handlers.delegateCount, 5057 cur = event.target; 5058 5059 // Find delegate handlers 5060 // Black-hole SVG <use> instance trees (#13180) 5061 // Avoid non-left-click bubbling in Firefox (#3861) 5062 if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { 5063 5064 /* jshint eqeqeq: false */ 5065 for ( ; cur != this; cur = cur.parentNode || this ) { 5066 /* jshint eqeqeq: true */ 5067 5068 // Don't check non-elements (#13208) 5069 // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) 5070 if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { 5071 matches = []; 5072 for ( i = 0; i < delegateCount; i++ ) { 5073 handleObj = handlers[ i ]; 5074 5075 // Don't conflict with Object.prototype properties (#13203) 5076 sel = handleObj.selector + " "; 5077 5078 if ( matches[ sel ] === undefined ) { 5079 matches[ sel ] = handleObj.needsContext ? 5080 jQuery( sel, this ).index( cur ) >= 0 : 5081 jQuery.find( sel, this, null, [ cur ] ).length; 5082 } 5083 if ( matches[ sel ] ) { 5084 matches.push( handleObj ); 5085 } 5086 } 5087 if ( matches.length ) { 5088 handlerQueue.push({ elem: cur, handlers: matches }); 5089 } 5090 } 5091 } 5092 } 5093 5094 // Add the remaining (directly-bound) handlers 5095 if ( delegateCount < handlers.length ) { 5096 handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); 5097 } 5098 5099 return handlerQueue; 5100 }, 5101 5102 fix: function( event ) { 5103 if ( event[ jQuery.expando ] ) { 5104 return event; 5105 } 5106 5107 // Create a writable copy of the event object and normalize some properties 5108 var i, prop, copy, 5109 type = event.type, 5110 originalEvent = event, 5111 fixHook = this.fixHooks[ type ]; 5112 5113 if ( !fixHook ) { 5114 this.fixHooks[ type ] = fixHook = 5115 rmouseEvent.test( type ) ? this.mouseHooks : 5116 rkeyEvent.test( type ) ? this.keyHooks : 5117 {}; 5118 } 5119 copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; 5120 5121 event = new jQuery.Event( originalEvent ); 5122 5123 i = copy.length; 5124 while ( i-- ) { 5125 prop = copy[ i ]; 5126 event[ prop ] = originalEvent[ prop ]; 5127 } 5128 5129 // Support: IE<9 5130 // Fix target property (#1925) 5131 if ( !event.target ) { 5132 event.target = originalEvent.srcElement || document; 5133 } 5134 5135 // Support: Chrome 23+, Safari? 5136 // Target should not be a text node (#504, #13143) 5137 if ( event.target.nodeType === 3 ) { 5138 event.target = event.target.parentNode; 5139 } 5140 5141 // Support: IE<9 5142 // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) 5143 event.metaKey = !!event.metaKey; 5144 5145 return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; 5146 }, 5147 5148 // Includes some event props shared by KeyEvent and MouseEvent 5149 props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), 5150 5151 fixHooks: {}, 5152 5153 keyHooks: { 5154 props: "char charCode key keyCode".split(" "), 5155 filter: function( event, original ) { 5156 5157 // Add which for key events 5158 if ( event.which == null ) { 5159 event.which = original.charCode != null ? original.charCode : original.keyCode; 5160 } 5161 5162 return event; 5163 } 5164 }, 5165 5166 mouseHooks: { 5167 props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), 5168 filter: function( event, original ) { 5169 var body, eventDoc, doc, 5170 button = original.button, 5171 fromElement = original.fromElement; 5172 5173 // Calculate pageX/Y if missing and clientX/Y available 5174 if ( event.pageX == null && original.clientX != null ) { 5175 eventDoc = event.target.ownerDocument || document; 5176 doc = eventDoc.documentElement; 5177 body = eventDoc.body; 5178 5179 event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); 5180 event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); 5181 } 5182 5183 // Add relatedTarget, if necessary 5184 if ( !event.relatedTarget && fromElement ) { 5185 event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; 5186 } 5187 5188 // Add which for click: 1 === left; 2 === middle; 3 === right 5189 // Note: button is not normalized, so don't use it 5190 if ( !event.which && button !== undefined ) { 5191 event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); 5192 } 5193 5194 return event; 5195 } 5196 }, 5197 5198 special: { 5199 load: { 5200 // Prevent triggered image.load events from bubbling to window.load 5201 noBubble: true 5202 }, 5203 focus: { 5204 // Fire native event if possible so blur/focus sequence is correct 5205 trigger: function() { 5206 if ( this !== safeActiveElement() && this.focus ) { 5207 try { 5208 this.focus(); 5209 return false; 5210 } catch ( e ) { 5211 // Support: IE<9 5212 // If we error on focus to hidden element (#1486, #12518), 5213 // let .trigger() run the handlers 5214 } 5215 } 5216 }, 5217 delegateType: "focusin" 5218 }, 5219 blur: { 5220 trigger: function() { 5221 if ( this === safeActiveElement() && this.blur ) { 5222 this.blur(); 5223 return false; 5224 } 5225 }, 5226 delegateType: "focusout" 5227 }, 5228 click: { 5229 // For checkbox, fire native event so checked state will be right 5230 trigger: function() { 5231 if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { 5232 this.click(); 5233 return false; 5234 } 5235 }, 5236 5237 // For cross-browser consistency, don't fire native .click() on links 5238 _default: function( event ) { 5239 return jQuery.nodeName( event.target, "a" ); 5240 } 5241 }, 5242 5243 beforeunload: { 5244 postDispatch: function( event ) { 5245 5246 // Support: Firefox 20+ 5247 // Firefox doesn't alert if the returnValue field is not set. 5248 if ( event.result !== undefined && event.originalEvent ) { 5249 event.originalEvent.returnValue = event.result; 5250 } 5251 } 5252 } 5253 }, 5254 5255 simulate: function( type, elem, event, bubble ) { 5256 // Piggyback on a donor event to simulate a different one. 5257 // Fake originalEvent to avoid donor's stopPropagation, but if the 5258 // simulated event prevents default then we do the same on the donor. 5259 var e = jQuery.extend( 5260 new jQuery.Event(), 5261 event, 5262 { 5263 type: type, 5264 isSimulated: true, 5265 originalEvent: {} 5266 } 5267 ); 5268 if ( bubble ) { 5269 jQuery.event.trigger( e, null, elem ); 5270 } else { 5271 jQuery.event.dispatch.call( elem, e ); 5272 } 5273 if ( e.isDefaultPrevented() ) { 5274 event.preventDefault(); 5275 } 5276 } 5277}; 5278 5279jQuery.removeEvent = document.removeEventListener ? 5280 function( elem, type, handle ) { 5281 if ( elem.removeEventListener ) { 5282 elem.removeEventListener( type, handle, false ); 5283 } 5284 } : 5285 function( elem, type, handle ) { 5286 var name = "on" + type; 5287 5288 if ( elem.detachEvent ) { 5289 5290 // #8545, #7054, preventing memory leaks for custom events in IE6-8 5291 // detachEvent needed property on element, by name of that event, to properly expose it to GC 5292 if ( typeof elem[ name ] === strundefined ) { 5293 elem[ name ] = null; 5294 } 5295 5296 elem.detachEvent( name, handle ); 5297 } 5298 }; 5299 5300jQuery.Event = function( src, props ) { 5301 // Allow instantiation without the 'new' keyword 5302 if ( !(this instanceof jQuery.Event) ) { 5303 return new jQuery.Event( src, props ); 5304 } 5305 5306 // Event object 5307 if ( src && src.type ) { 5308 this.originalEvent = src; 5309 this.type = src.type; 5310 5311 // Events bubbling up the document may have been marked as prevented 5312 // by a handler lower down the tree; reflect the correct value. 5313 this.isDefaultPrevented = src.defaultPrevented || 5314 src.defaultPrevented === undefined && 5315 // Support: IE < 9, Android < 4.0 5316 src.returnValue === false ? 5317 returnTrue : 5318 returnFalse; 5319 5320 // Event type 5321 } else { 5322 this.type = src; 5323 } 5324 5325 // Put explicitly provided properties onto the event object 5326 if ( props ) { 5327 jQuery.extend( this, props ); 5328 } 5329 5330 // Create a timestamp if incoming event doesn't have one 5331 this.timeStamp = src && src.timeStamp || jQuery.now(); 5332 5333 // Mark it as fixed 5334 this[ jQuery.expando ] = true; 5335}; 5336 5337// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding 5338// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html 5339jQuery.Event.prototype = { 5340 isDefaultPrevented: returnFalse, 5341 isPropagationStopped: returnFalse, 5342 isImmediatePropagationStopped: returnFalse, 5343 5344 preventDefault: function() { 5345 var e = this.originalEvent; 5346 5347 this.isDefaultPrevented = returnTrue; 5348 if ( !e ) { 5349 return; 5350 } 5351 5352 // If preventDefault exists, run it on the original event 5353 if ( e.preventDefault ) { 5354 e.preventDefault(); 5355 5356 // Support: IE 5357 // Otherwise set the returnValue property of the original event to false 5358 } else { 5359 e.returnValue = false; 5360 } 5361 }, 5362 stopPropagation: function() { 5363 var e = this.originalEvent; 5364 5365 this.isPropagationStopped = returnTrue; 5366 if ( !e ) { 5367 return; 5368 } 5369 // If stopPropagation exists, run it on the original event 5370 if ( e.stopPropagation ) { 5371 e.stopPropagation(); 5372 } 5373 5374 // Support: IE 5375 // Set the cancelBubble property of the original event to true 5376 e.cancelBubble = true; 5377 }, 5378 stopImmediatePropagation: function() { 5379 var e = this.originalEvent; 5380 5381 this.isImmediatePropagationStopped = returnTrue; 5382 5383 if ( e && e.stopImmediatePropagation ) { 5384 e.stopImmediatePropagation(); 5385 } 5386 5387 this.stopPropagation(); 5388 } 5389}; 5390 5391// Create mouseenter/leave events using mouseover/out and event-time checks 5392jQuery.each({ 5393 mouseenter: "mouseover", 5394 mouseleave: "mouseout", 5395 pointerenter: "pointerover", 5396 pointerleave: "pointerout" 5397}, function( orig, fix ) { 5398 jQuery.event.special[ orig ] = { 5399 delegateType: fix, 5400 bindType: fix, 5401 5402 handle: function( event ) { 5403 var ret, 5404 target = this, 5405 related = event.relatedTarget, 5406 handleObj = event.handleObj; 5407 5408 // For mousenter/leave call the handler if related is outside the target. 5409 // NB: No relatedTarget if the mouse left/entered the browser window 5410 if ( !related || (related !== target && !jQuery.contains( target, related )) ) { 5411 event.type = handleObj.origType; 5412 ret = handleObj.handler.apply( this, arguments ); 5413 event.type = fix; 5414 } 5415 return ret; 5416 } 5417 }; 5418}); 5419 5420// IE submit delegation 5421if ( !support.submitBubbles ) { 5422 5423 jQuery.event.special.submit = { 5424 setup: function() { 5425 // Only need this for delegated form submit events 5426 if ( jQuery.nodeName( this, "form" ) ) { 5427 return false; 5428 } 5429 5430 // Lazy-add a submit handler when a descendant form may potentially be submitted 5431 jQuery.event.add( this, "click._submit keypress._submit", function( e ) { 5432 // Node name check avoids a VML-related crash in IE (#9807) 5433 var elem = e.target, 5434 form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; 5435 if ( form && !jQuery._data( form, "submitBubbles" ) ) { 5436 jQuery.event.add( form, "submit._submit", function( event ) { 5437 event._submit_bubble = true; 5438 }); 5439 jQuery._data( form, "submitBubbles", true ); 5440 } 5441 }); 5442 // return undefined since we don't need an event listener 5443 }, 5444 5445 postDispatch: function( event ) { 5446 // If form was submitted by the user, bubble the event up the tree 5447 if ( event._submit_bubble ) { 5448 delete event._submit_bubble; 5449 if ( this.parentNode && !event.isTrigger ) { 5450 jQuery.event.simulate( "submit", this.parentNode, event, true ); 5451 } 5452 } 5453 }, 5454 5455 teardown: function() { 5456 // Only need this for delegated form submit events 5457 if ( jQuery.nodeName( this, "form" ) ) { 5458 return false; 5459 } 5460 5461 // Remove delegated handlers; cleanData eventually reaps submit handlers attached above 5462 jQuery.event.remove( this, "._submit" ); 5463 } 5464 }; 5465} 5466 5467// IE change delegation and checkbox/radio fix 5468if ( !support.changeBubbles ) { 5469 5470 jQuery.event.special.change = { 5471 5472 setup: function() { 5473 5474 if ( rformElems.test( this.nodeName ) ) { 5475 // IE doesn't fire change on a check/radio until blur; trigger it on click 5476 // after a propertychange. Eat the blur-change in special.change.handle. 5477 // This still fires onchange a second time for check/radio after blur. 5478 if ( this.type === "checkbox" || this.type === "radio" ) { 5479 jQuery.event.add( this, "propertychange._change", function( event ) { 5480 if ( event.originalEvent.propertyName === "checked" ) { 5481 this._just_changed = true; 5482 } 5483 }); 5484 jQuery.event.add( this, "click._change", function( event ) { 5485 if ( this._just_changed && !event.isTrigger ) { 5486 this._just_changed = false; 5487 } 5488 // Allow triggered, simulated change events (#11500) 5489 jQuery.event.simulate( "change", this, event, true ); 5490 }); 5491 } 5492 return false; 5493 } 5494 // Delegated event; lazy-add a change handler on descendant inputs 5495 jQuery.event.add( this, "beforeactivate._change", function( e ) { 5496 var elem = e.target; 5497 5498 if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) { 5499 jQuery.event.add( elem, "change._change", function( event ) { 5500 if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { 5501 jQuery.event.simulate( "change", this.parentNode, event, true ); 5502 } 5503 }); 5504 jQuery._data( elem, "changeBubbles", true ); 5505 } 5506 }); 5507 }, 5508 5509 handle: function( event ) { 5510 var elem = event.target; 5511 5512 // Swallow native change events from checkbox/radio, we already triggered them above 5513 if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { 5514 return event.handleObj.handler.apply( this, arguments ); 5515 } 5516 }, 5517 5518 teardown: function() { 5519 jQuery.event.remove( this, "._change" ); 5520 5521 return !rformElems.test( this.nodeName ); 5522 } 5523 }; 5524} 5525 5526// Create "bubbling" focus and blur events 5527if ( !support.focusinBubbles ) { 5528 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { 5529 5530 // Attach a single capturing handler on the document while someone wants focusin/focusout 5531 var handler = function( event ) { 5532 jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); 5533 }; 5534 5535 jQuery.event.special[ fix ] = { 5536 setup: function() { 5537 var doc = this.ownerDocument || this, 5538 attaches = jQuery._data( doc, fix ); 5539 5540 if ( !attaches ) { 5541 doc.addEventListener( orig, handler, true ); 5542 } 5543 jQuery._data( doc, fix, ( attaches || 0 ) + 1 ); 5544 }, 5545 teardown: function() { 5546 var doc = this.ownerDocument || this, 5547 attaches = jQuery._data( doc, fix ) - 1; 5548 5549 if ( !attaches ) { 5550 doc.removeEventListener( orig, handler, true ); 5551 jQuery._removeData( doc, fix ); 5552 } else { 5553 jQuery._data( doc, fix, attaches ); 5554 } 5555 } 5556 }; 5557 }); 5558} 5559 5560jQuery.fn.extend({ 5561 5562 on: function( types, selector, data, fn, /*INTERNAL*/ one ) { 5563 var type, origFn; 5564 5565 // Types can be a map of types/handlers 5566 if ( typeof types === "object" ) { 5567 // ( types-Object, selector, data ) 5568 if ( typeof selector !== "string" ) { 5569 // ( types-Object, data ) 5570 data = data || selector; 5571 selector = undefined; 5572 } 5573 for ( type in types ) { 5574 this.on( type, selector, data, types[ type ], one ); 5575 } 5576 return this; 5577 } 5578 5579 if ( data == null && fn == null ) { 5580 // ( types, fn ) 5581 fn = selector; 5582 data = selector = undefined; 5583 } else if ( fn == null ) { 5584 if ( typeof selector === "string" ) { 5585 // ( types, selector, fn ) 5586 fn = data; 5587 data = undefined; 5588 } else { 5589 // ( types, data, fn ) 5590 fn = data; 5591 data = selector; 5592 selector = undefined; 5593 } 5594 } 5595 if ( fn === false ) { 5596 fn = returnFalse; 5597 } else if ( !fn ) { 5598 return this; 5599 } 5600 5601 if ( one === 1 ) { 5602 origFn = fn; 5603 fn = function( event ) { 5604 // Can use an empty set, since event contains the info 5605 jQuery().off( event ); 5606 return origFn.apply( this, arguments ); 5607 }; 5608 // Use same guid so caller can remove using origFn 5609 fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); 5610 } 5611 return this.each( function() { 5612 jQuery.event.add( this, types, fn, data, selector ); 5613 }); 5614 }, 5615 one: function( types, selector, data, fn ) { 5616 return this.on( types, selector, data, fn, 1 ); 5617 }, 5618 off: function( types, selector, fn ) { 5619 var handleObj, type; 5620 if ( types && types.preventDefault && types.handleObj ) { 5621 // ( event ) dispatched jQuery.Event 5622 handleObj = types.handleObj; 5623 jQuery( types.delegateTarget ).off( 5624 handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, 5625 handleObj.selector, 5626 handleObj.handler 5627 ); 5628 return this; 5629 } 5630 if ( typeof types === "object" ) { 5631 // ( types-object [, selector] ) 5632 for ( type in types ) { 5633 this.off( type, selector, types[ type ] ); 5634 } 5635 return this; 5636 } 5637 if ( selector === false || typeof selector === "function" ) { 5638 // ( types [, fn] ) 5639 fn = selector; 5640 selector = undefined; 5641 } 5642 if ( fn === false ) { 5643 fn = returnFalse; 5644 } 5645 return this.each(function() { 5646 jQuery.event.remove( this, types, fn, selector ); 5647 }); 5648 }, 5649 5650 trigger: function( type, data ) { 5651 return this.each(function() { 5652 jQuery.event.trigger( type, data, this ); 5653 }); 5654 }, 5655 triggerHandler: function( type, data ) { 5656 var elem = this[0]; 5657 if ( elem ) { 5658 return jQuery.event.trigger( type, data, elem, true ); 5659 } 5660 } 5661}); 5662 5663function createSafeFragment( document ) { 5664 var list = nodeNames.split( "|" ), 5665 safeFrag = document.createDocumentFragment(); 5666 5667 if ( safeFrag.createElement ) { 5668 while ( list.length ) { 5669 safeFrag.createElement( 5670 list.pop() 5671 ); 5672 } 5673 } 5674 return safeFrag; 5675} 5676 5677var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + 5678 "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", 5679 rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, 5680 rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), 5681 rleadingWhitespace = /^\s+/, 5682 rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, 5683 rtagName = /<([\w:]+)/, 5684 rtbody = /<tbody/i, 5685 rhtml = /<|&#?\w+;/, 5686 rnoInnerhtml = /<(?:script|style|link)/i, 5687 // checked="checked" or checked 5688 rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, 5689 rscriptType = /^$|\/(?:java|ecma)script/i, 5690 rscriptTypeMasked = /^true\/(.*)/, 5691 rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g, 5692 5693 // We have to close these tags to support XHTML (#13200) 5694 wrapMap = { 5695 option: [ 1, "<select multiple='multiple'>", "</select>" ], 5696 legend: [ 1, "<fieldset>", "</fieldset>" ], 5697 area: [ 1, "<map>", "</map>" ], 5698 param: [ 1, "<object>", "</object>" ], 5699 thead: [ 1, "<table>", "</table>" ], 5700 tr: [ 2, "<table><tbody>", "</tbody></table>" ], 5701 col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ], 5702 td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ], 5703 5704 // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, 5705 // unless wrapped in a div with non-breaking characters in front of it. 5706 _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>" ] 5707 }, 5708 safeFragment = createSafeFragment( document ), 5709 fragmentDiv = safeFragment.appendChild( document.createElement("div") ); 5710 5711wrapMap.optgroup = wrapMap.option; 5712wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; 5713wrapMap.th = wrapMap.td; 5714 5715function getAll( context, tag ) { 5716 var elems, elem, 5717 i = 0, 5718 found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName( tag || "*" ) : 5719 typeof context.querySelectorAll !== strundefined ? context.querySelectorAll( tag || "*" ) : 5720 undefined; 5721 5722 if ( !found ) { 5723 for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) { 5724 if ( !tag || jQuery.nodeName( elem, tag ) ) { 5725 found.push( elem ); 5726 } else { 5727 jQuery.merge( found, getAll( elem, tag ) ); 5728 } 5729 } 5730 } 5731 5732 return tag === undefined || tag && jQuery.nodeName( context, tag ) ? 5733 jQuery.merge( [ context ], found ) : 5734 found; 5735} 5736 5737// Used in buildFragment, fixes the defaultChecked property 5738function fixDefaultChecked( elem ) { 5739 if ( rcheckableType.test( elem.type ) ) { 5740 elem.defaultChecked = elem.checked; 5741 } 5742} 5743 5744// Support: IE<8 5745// Manipulating tables requires a tbody 5746function manipulationTarget( elem, content ) { 5747 return jQuery.nodeName( elem, "table" ) && 5748 jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? 5749 5750 elem.getElementsByTagName("tbody")[0] || 5751 elem.appendChild( elem.ownerDocument.createElement("tbody") ) : 5752 elem; 5753} 5754 5755// Replace/restore the type attribute of script elements for safe DOM manipulation 5756function disableScript( elem ) { 5757 elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type; 5758 return elem; 5759} 5760function restoreScript( elem ) { 5761 var match = rscriptTypeMasked.exec( elem.type ); 5762 if ( match ) { 5763 elem.type = match[1]; 5764 } else { 5765 elem.removeAttribute("type"); 5766 } 5767 return elem; 5768} 5769 5770// Mark scripts as having already been evaluated 5771function setGlobalEval( elems, refElements ) { 5772 var elem, 5773 i = 0; 5774 for ( ; (elem = elems[i]) != null; i++ ) { 5775 jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) ); 5776 } 5777} 5778 5779function cloneCopyEvent( src, dest ) { 5780 5781 if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { 5782 return; 5783 } 5784 5785 var type, i, l, 5786 oldData = jQuery._data( src ), 5787 curData = jQuery._data( dest, oldData ), 5788 events = oldData.events; 5789 5790 if ( events ) { 5791 delete curData.handle; 5792 curData.events = {}; 5793 5794 for ( type in events ) { 5795 for ( i = 0, l = events[ type ].length; i < l; i++ ) { 5796 jQuery.event.add( dest, type, events[ type ][ i ] ); 5797 } 5798 } 5799 } 5800 5801 // make the cloned public data object a copy from the original 5802 if ( curData.data ) { 5803 curData.data = jQuery.extend( {}, curData.data ); 5804 } 5805} 5806 5807function fixCloneNodeIssues( src, dest ) { 5808 var nodeName, e, data; 5809 5810 // We do not need to do anything for non-Elements 5811 if ( dest.nodeType !== 1 ) { 5812 return; 5813 } 5814 5815 nodeName = dest.nodeName.toLowerCase(); 5816 5817 // IE6-8 copies events bound via attachEvent when using cloneNode. 5818 if ( !support.noCloneEvent && dest[ jQuery.expando ] ) { 5819 data = jQuery._data( dest ); 5820 5821 for ( e in data.events ) { 5822 jQuery.removeEvent( dest, e, data.handle ); 5823 } 5824 5825 // Event data gets referenced instead of copied if the expando gets copied too 5826 dest.removeAttribute( jQuery.expando ); 5827 } 5828 5829 // IE blanks contents when cloning scripts, and tries to evaluate newly-set text 5830 if ( nodeName === "script" && dest.text !== src.text ) { 5831 disableScript( dest ).text = src.text; 5832 restoreScript( dest ); 5833 5834 // IE6-10 improperly clones children of object elements using classid. 5835 // IE10 throws NoModificationAllowedError if parent is null, #12132. 5836 } else if ( nodeName === "object" ) { 5837 if ( dest.parentNode ) { 5838 dest.outerHTML = src.outerHTML; 5839 } 5840 5841 // This path appears unavoidable for IE9. When cloning an object 5842 // element in IE9, the outerHTML strategy above is not sufficient. 5843 // If the src has innerHTML and the destination does not, 5844 // copy the src.innerHTML into the dest.innerHTML. #10324 5845 if ( support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { 5846 dest.innerHTML = src.innerHTML; 5847 } 5848 5849 } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { 5850 // IE6-8 fails to persist the checked state of a cloned checkbox 5851 // or radio button. Worse, IE6-7 fail to give the cloned element 5852 // a checked appearance if the defaultChecked value isn't also set 5853 5854 dest.defaultChecked = dest.checked = src.checked; 5855 5856 // IE6-7 get confused and end up setting the value of a cloned 5857 // checkbox/radio button to an empty string instead of "on" 5858 if ( dest.value !== src.value ) { 5859 dest.value = src.value; 5860 } 5861 5862 // IE6-8 fails to return the selected option to the default selected 5863 // state when cloning options 5864 } else if ( nodeName === "option" ) { 5865 dest.defaultSelected = dest.selected = src.defaultSelected; 5866 5867 // IE6-8 fails to set the defaultValue to the correct value when 5868 // cloning other types of input fields 5869 } else if ( nodeName === "input" || nodeName === "textarea" ) { 5870 dest.defaultValue = src.defaultValue; 5871 } 5872} 5873 5874jQuery.extend({ 5875 clone: function( elem, dataAndEvents, deepDataAndEvents ) { 5876 var destElements, node, clone, i, srcElements, 5877 inPage = jQuery.contains( elem.ownerDocument, elem ); 5878 5879 if ( support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { 5880 clone = elem.cloneNode( true ); 5881 5882 // IE<=8 does not properly clone detached, unknown element nodes 5883 } else { 5884 fragmentDiv.innerHTML = elem.outerHTML; 5885 fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); 5886 } 5887 5888 if ( (!support.noCloneEvent || !support.noCloneChecked) && 5889 (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { 5890 5891 // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 5892 destElements = getAll( clone ); 5893 srcElements = getAll( elem ); 5894 5895 // Fix all IE cloning issues 5896 for ( i = 0; (node = srcElements[i]) != null; ++i ) { 5897 // Ensure that the destination node is not null; Fixes #9587 5898 if ( destElements[i] ) { 5899 fixCloneNodeIssues( node, destElements[i] ); 5900 } 5901 } 5902 } 5903 5904 // Copy the events from the original to the clone 5905 if ( dataAndEvents ) { 5906 if ( deepDataAndEvents ) { 5907 srcElements = srcElements || getAll( elem ); 5908 destElements = destElements || getAll( clone ); 5909 5910 for ( i = 0; (node = srcElements[i]) != null; i++ ) { 5911 cloneCopyEvent( node, destElements[i] ); 5912 } 5913 } else { 5914 cloneCopyEvent( elem, clone ); 5915 } 5916 } 5917 5918 // Preserve script evaluation history 5919 destElements = getAll( clone, "script" ); 5920 if ( destElements.length > 0 ) { 5921 setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); 5922 } 5923 5924 destElements = srcElements = node = null; 5925 5926 // Return the cloned set 5927 return clone; 5928 }, 5929 5930 buildFragment: function( elems, context, scripts, selection ) { 5931 var j, elem, contains, 5932 tmp, tag, tbody, wrap, 5933 l = elems.length, 5934 5935 // Ensure a safe fragment 5936 safe = createSafeFragment( context ), 5937 5938 nodes = [], 5939 i = 0; 5940 5941 for ( ; i < l; i++ ) { 5942 elem = elems[ i ]; 5943 5944 if ( elem || elem === 0 ) { 5945 5946 // Add nodes directly 5947 if ( jQuery.type( elem ) === "object" ) { 5948 jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); 5949 5950 // Convert non-html into a text node 5951 } else if ( !rhtml.test( elem ) ) { 5952 nodes.push( context.createTextNode( elem ) ); 5953 5954 // Convert html into DOM nodes 5955 } else { 5956 tmp = tmp || safe.appendChild( context.createElement("div") ); 5957 5958 // Deserialize a standard representation 5959 tag = (rtagName.exec( elem ) || [ "", "" ])[ 1 ].toLowerCase(); 5960 wrap = wrapMap[ tag ] || wrapMap._default; 5961 5962 tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2]; 5963 5964 // Descend through wrappers to the right content 5965 j = wrap[0]; 5966 while ( j-- ) { 5967 tmp = tmp.lastChild; 5968 } 5969 5970 // Manually add leading whitespace removed by IE 5971 if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { 5972 nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) ); 5973 } 5974 5975 // Remove IE's autoinserted <tbody> from table fragments 5976 if ( !support.tbody ) { 5977 5978 // String was a <table>, *may* have spurious <tbody> 5979 elem = tag === "table" && !rtbody.test( elem ) ? 5980 tmp.firstChild : 5981 5982 // String was a bare <thead> or <tfoot> 5983 wrap[1] === "<table>" && !rtbody.test( elem ) ? 5984 tmp : 5985 0; 5986 5987 j = elem && elem.childNodes.length; 5988 while ( j-- ) { 5989 if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) { 5990 elem.removeChild( tbody ); 5991 } 5992 } 5993 } 5994 5995 jQuery.merge( nodes, tmp.childNodes ); 5996 5997 // Fix #12392 for WebKit and IE > 9 5998 tmp.textContent = ""; 5999 6000 // Fix #12392 for oldIE 6001 while ( tmp.firstChild ) { 6002 tmp.removeChild( tmp.firstChild ); 6003 } 6004 6005 // Remember the top-level container for proper cleanup 6006 tmp = safe.lastChild; 6007 } 6008 } 6009 } 6010 6011 // Fix #11356: Clear elements from fragment 6012 if ( tmp ) { 6013 safe.removeChild( tmp ); 6014 } 6015 6016 // Reset defaultChecked for any radios and checkboxes 6017 // about to be appended to the DOM in IE 6/7 (#8060) 6018 if ( !support.appendChecked ) { 6019 jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); 6020 } 6021 6022 i = 0; 6023 while ( (elem = nodes[ i++ ]) ) { 6024 6025 // #4087 - If origin and destination elements are the same, and this is 6026 // that element, do not do anything 6027 if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { 6028 continue; 6029 } 6030 6031 contains = jQuery.contains( elem.ownerDocument, elem ); 6032 6033 // Append to fragment 6034 tmp = getAll( safe.appendChild( elem ), "script" ); 6035 6036 // Preserve script evaluation history 6037 if ( contains ) { 6038 setGlobalEval( tmp ); 6039 } 6040 6041 // Capture executables 6042 if ( scripts ) { 6043 j = 0; 6044 while ( (elem = tmp[ j++ ]) ) { 6045 if ( rscriptType.test( elem.type || "" ) ) { 6046 scripts.push( elem ); 6047 } 6048 } 6049 } 6050 } 6051 6052 tmp = null; 6053 6054 return safe; 6055 }, 6056 6057 cleanData: function( elems, /* internal */ acceptData ) { 6058 var elem, type, id, data, 6059 i = 0, 6060 internalKey = jQuery.expando, 6061 cache = jQuery.cache, 6062 deleteExpando = support.deleteExpando, 6063 special = jQuery.event.special; 6064 6065 for ( ; (elem = elems[i]) != null; i++ ) { 6066 if ( acceptData || jQuery.acceptData( elem ) ) { 6067 6068 id = elem[ internalKey ]; 6069 data = id && cache[ id ]; 6070 6071 if ( data ) { 6072 if ( data.events ) { 6073 for ( type in data.events ) { 6074 if ( special[ type ] ) { 6075 jQuery.event.remove( elem, type ); 6076 6077 // This is a shortcut to avoid jQuery.event.remove's overhead 6078 } else { 6079 jQuery.removeEvent( elem, type, data.handle ); 6080 } 6081 } 6082 } 6083 6084 // Remove cache only if it was not already removed by jQuery.event.remove 6085 if ( cache[ id ] ) { 6086 6087 delete cache[ id ]; 6088 6089 // IE does not allow us to delete expando properties from nodes, 6090 // nor does it have a removeAttribute function on Document nodes; 6091 // we must handle all of these cases 6092 if ( deleteExpando ) { 6093 delete elem[ internalKey ]; 6094 6095 } else if ( typeof elem.removeAttribute !== strundefined ) { 6096 elem.removeAttribute( internalKey ); 6097 6098 } else { 6099 elem[ internalKey ] = null; 6100 } 6101 6102 deletedIds.push( id ); 6103 } 6104 } 6105 } 6106 } 6107 } 6108}); 6109 6110jQuery.fn.extend({ 6111 text: function( value ) { 6112 return access( this, function( value ) { 6113 return value === undefined ? 6114 jQuery.text( this ) : 6115 this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); 6116 }, null, value, arguments.length ); 6117 }, 6118 6119 append: function() { 6120 return this.domManip( arguments, function( elem ) { 6121 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { 6122 var target = manipulationTarget( this, elem ); 6123 target.appendChild( elem ); 6124 } 6125 }); 6126 }, 6127 6128 prepend: function() { 6129 return this.domManip( arguments, function( elem ) { 6130 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { 6131 var target = manipulationTarget( this, elem ); 6132 target.insertBefore( elem, target.firstChild ); 6133 } 6134 }); 6135 }, 6136 6137 before: function() { 6138 return this.domManip( arguments, function( elem ) { 6139 if ( this.parentNode ) { 6140 this.parentNode.insertBefore( elem, this ); 6141 } 6142 }); 6143 }, 6144 6145 after: function() { 6146 return this.domManip( arguments, function( elem ) { 6147 if ( this.parentNode ) { 6148 this.parentNode.insertBefore( elem, this.nextSibling ); 6149 } 6150 }); 6151 }, 6152 6153 remove: function( selector, keepData /* Internal Use Only */ ) { 6154 var elem, 6155 elems = selector ? jQuery.filter( selector, this ) : this, 6156 i = 0; 6157 6158 for ( ; (elem = elems[i]) != null; i++ ) { 6159 6160 if ( !keepData && elem.nodeType === 1 ) { 6161 jQuery.cleanData( getAll( elem ) ); 6162 } 6163 6164 if ( elem.parentNode ) { 6165 if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { 6166 setGlobalEval( getAll( elem, "script" ) ); 6167 } 6168 elem.parentNode.removeChild( elem ); 6169 } 6170 } 6171 6172 return this; 6173 }, 6174 6175 empty: function() { 6176 var elem, 6177 i = 0; 6178 6179 for ( ; (elem = this[i]) != null; i++ ) { 6180 // Remove element nodes and prevent memory leaks 6181 if ( elem.nodeType === 1 ) { 6182 jQuery.cleanData( getAll( elem, false ) ); 6183 } 6184 6185 // Remove any remaining nodes 6186 while ( elem.firstChild ) { 6187 elem.removeChild( elem.firstChild ); 6188 } 6189 6190 // If this is a select, ensure that it displays empty (#12336) 6191 // Support: IE<9 6192 if ( elem.options && jQuery.nodeName( elem, "select" ) ) { 6193 elem.options.length = 0; 6194 } 6195 } 6196 6197 return this; 6198 }, 6199 6200 clone: function( dataAndEvents, deepDataAndEvents ) { 6201 dataAndEvents = dataAndEvents == null ? false : dataAndEvents; 6202 deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; 6203 6204 return this.map(function() { 6205 return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); 6206 }); 6207 }, 6208 6209 html: function( value ) { 6210 return access( this, function( value ) { 6211 var elem = this[ 0 ] || {}, 6212 i = 0, 6213 l = this.length; 6214 6215 if ( value === undefined ) { 6216 return elem.nodeType === 1 ? 6217 elem.innerHTML.replace( rinlinejQuery, "" ) : 6218 undefined; 6219 } 6220 6221 // See if we can take a shortcut and just use innerHTML 6222 if ( typeof value === "string" && !rnoInnerhtml.test( value ) && 6223 ( support.htmlSerialize || !rnoshimcache.test( value ) ) && 6224 ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && 6225 !wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) { 6226 6227 value = value.replace( rxhtmlTag, "<$1></$2>" ); 6228 6229 try { 6230 for (; i < l; i++ ) { 6231 // Remove element nodes and prevent memory leaks 6232 elem = this[i] || {}; 6233 if ( elem.nodeType === 1 ) { 6234 jQuery.cleanData( getAll( elem, false ) ); 6235 elem.innerHTML = value; 6236 } 6237 } 6238 6239 elem = 0; 6240 6241 // If using innerHTML throws an exception, use the fallback method 6242 } catch(e) {} 6243 } 6244 6245 if ( elem ) { 6246 this.empty().append( value ); 6247 } 6248 }, null, value, arguments.length ); 6249 }, 6250 6251 replaceWith: function() { 6252 var arg = arguments[ 0 ]; 6253 6254 // Make the changes, replacing each context element with the new content 6255 this.domManip( arguments, function( elem ) { 6256 arg = this.parentNode; 6257 6258 jQuery.cleanData( getAll( this ) ); 6259 6260 if ( arg ) { 6261 arg.replaceChild( elem, this ); 6262 } 6263 }); 6264 6265 // Force removal if there was no new content (e.g., from empty arguments) 6266 return arg && (arg.length || arg.nodeType) ? this : this.remove(); 6267 }, 6268 6269 detach: function( selector ) { 6270 return this.remove( selector, true ); 6271 }, 6272 6273 domManip: function( args, callback ) { 6274 6275 // Flatten any nested arrays 6276 args = concat.apply( [], args ); 6277 6278 var first, node, hasScripts, 6279 scripts, doc, fragment, 6280 i = 0, 6281 l = this.length, 6282 set = this, 6283 iNoClone = l - 1, 6284 value = args[0], 6285 isFunction = jQuery.isFunction( value ); 6286 6287 // We can't cloneNode fragments that contain checked, in WebKit 6288 if ( isFunction || 6289 ( l > 1 && typeof value === "string" && 6290 !support.checkClone && rchecked.test( value ) ) ) { 6291 return this.each(function( index ) { 6292 var self = set.eq( index ); 6293 if ( isFunction ) { 6294 args[0] = value.call( this, index, self.html() ); 6295 } 6296 self.domManip( args, callback ); 6297 }); 6298 } 6299 6300 if ( l ) { 6301 fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); 6302 first = fragment.firstChild; 6303 6304 if ( fragment.childNodes.length === 1 ) { 6305 fragment = first; 6306 } 6307 6308 if ( first ) { 6309 scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); 6310 hasScripts = scripts.length; 6311 6312 // Use the original fragment for the last item instead of the first because it can end up 6313 // being emptied incorrectly in certain situations (#8070). 6314 for ( ; i < l; i++ ) { 6315 node = fragment; 6316 6317 if ( i !== iNoClone ) { 6318 node = jQuery.clone( node, true, true ); 6319 6320 // Keep references to cloned scripts for later restoration 6321 if ( hasScripts ) { 6322 jQuery.merge( scripts, getAll( node, "script" ) ); 6323 } 6324 } 6325 6326 callback.call( this[i], node, i ); 6327 } 6328 6329 if ( hasScripts ) { 6330 doc = scripts[ scripts.length - 1 ].ownerDocument; 6331 6332 // Reenable scripts 6333 jQuery.map( scripts, restoreScript ); 6334 6335 // Evaluate executable scripts on first document insertion 6336 for ( i = 0; i < hasScripts; i++ ) { 6337 node = scripts[ i ]; 6338 if ( rscriptType.test( node.type || "" ) && 6339 !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { 6340 6341 if ( node.src ) { 6342 // Optional AJAX dependency, but won't run scripts if not present 6343 if ( jQuery._evalUrl ) { 6344 jQuery._evalUrl( node.src ); 6345 } 6346 } else { 6347 jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) ); 6348 } 6349 } 6350 } 6351 } 6352 6353 // Fix #11809: Avoid leaking memory 6354 fragment = first = null; 6355 } 6356 } 6357 6358 return this; 6359 } 6360}); 6361 6362jQuery.each({ 6363 appendTo: "append", 6364 prependTo: "prepend", 6365 insertBefore: "before", 6366 insertAfter: "after", 6367 replaceAll: "replaceWith" 6368}, function( name, original ) { 6369 jQuery.fn[ name ] = function( selector ) { 6370 var elems, 6371 i = 0, 6372 ret = [], 6373 insert = jQuery( selector ), 6374 last = insert.length - 1; 6375 6376 for ( ; i <= last; i++ ) { 6377 elems = i === last ? this : this.clone(true); 6378 jQuery( insert[i] )[ original ]( elems ); 6379 6380 // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() 6381 push.apply( ret, elems.get() ); 6382 } 6383 6384 return this.pushStack( ret ); 6385 }; 6386}); 6387 6388var iframe, 6389 elemdisplay = {}; 6390 6391/** 6392 * Retrieve the actual display of a element 6393 * @param {String} name nodeName of the element 6394 * @param {Object} doc Document object 6395 */ 6396// Called only from within defaultDisplay 6397function actualDisplay( name, doc ) { 6398 var style, 6399 elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), 6400 6401 // getDefaultComputedStyle might be reliably used only on attached element 6402 display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ? 6403 6404 // Use of this method is a temporary fix (more like optmization) until something better comes along, 6405 // since it was removed from specification and supported only in FF 6406 style.display : jQuery.css( elem[ 0 ], "display" ); 6407 6408 // We don't have any data stored on the element, 6409 // so use "detach" method as fast way to get rid of the element 6410 elem.detach(); 6411 6412 return display; 6413} 6414 6415/** 6416 * Try to determine the default display value of an element 6417 * @param {String} nodeName 6418 */ 6419function defaultDisplay( nodeName ) { 6420 var doc = document, 6421 display = elemdisplay[ nodeName ]; 6422 6423 if ( !display ) { 6424 display = actualDisplay( nodeName, doc ); 6425 6426 // If the simple way fails, read from inside an iframe 6427 if ( display === "none" || !display ) { 6428 6429 // Use the already-created iframe if possible 6430 iframe = (iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" )).appendTo( doc.documentElement ); 6431 6432 // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse 6433 doc = ( iframe[ 0 ].contentWindow || iframe[ 0 ].contentDocument ).document; 6434 6435 // Support: IE 6436 doc.write(); 6437 doc.close(); 6438 6439 display = actualDisplay( nodeName, doc ); 6440 iframe.detach(); 6441 } 6442 6443 // Store the correct default display 6444 elemdisplay[ nodeName ] = display; 6445 } 6446 6447 return display; 6448} 6449 6450(function() { 6451 var shrinkWrapBlocksVal; 6452 6453 support.shrinkWrapBlocks = function() { 6454 if ( shrinkWrapBlocksVal != null ) { 6455 return shrinkWrapBlocksVal; 6456 } 6457 6458 // Will be changed later if needed. 6459 shrinkWrapBlocksVal = false; 6460 6461 // Minified: var b,c,d 6462 var div, body, container; 6463 6464 body = document.getElementsByTagName( "body" )[ 0 ]; 6465 if ( !body || !body.style ) { 6466 // Test fired too early or in an unsupported environment, exit. 6467 return; 6468 } 6469 6470 // Setup 6471 div = document.createElement( "div" ); 6472 container = document.createElement( "div" ); 6473 container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px"; 6474 body.appendChild( container ).appendChild( div ); 6475 6476 // Support: IE6 6477 // Check if elements with layout shrink-wrap their children 6478 if ( typeof div.style.zoom !== strundefined ) { 6479 // Reset CSS: box-sizing; display; margin; border 6480 div.style.cssText = 6481 // Support: Firefox<29, Android 2.3 6482 // Vendor-prefix box-sizing 6483 "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" + 6484 "box-sizing:content-box;display:block;margin:0;border:0;" + 6485 "padding:1px;width:1px;zoom:1"; 6486 div.appendChild( document.createElement( "div" ) ).style.width = "5px"; 6487 shrinkWrapBlocksVal = div.offsetWidth !== 3; 6488 } 6489 6490 body.removeChild( container ); 6491 6492 return shrinkWrapBlocksVal; 6493 }; 6494 6495})(); 6496var rmargin = (/^margin/); 6497 6498var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); 6499 6500var getStyles, curCSS, 6501 rposition = /^(top|right|bottom|left)$/; 6502 6503if ( window.getComputedStyle ) { 6504 getStyles = function( elem ) { 6505 return elem.ownerDocument.defaultView.getComputedStyle( elem, null ); 6506 }; 6507 6508 curCSS = function( elem, name, computed ) { 6509 var width, minWidth, maxWidth, ret, 6510 style = elem.style; 6511 6512 computed = computed || getStyles( elem ); 6513 6514 // getPropertyValue is only needed for .css('filter') in IE9, see #12537 6515 ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined; 6516 6517 if ( computed ) { 6518 6519 if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { 6520 ret = jQuery.style( elem, name ); 6521 } 6522 6523 // A tribute to the "awesome hack by Dean Edwards" 6524 // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right 6525 // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels 6526 // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values 6527 if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { 6528 6529 // Remember the original values 6530 width = style.width; 6531 minWidth = style.minWidth; 6532 maxWidth = style.maxWidth; 6533 6534 // Put in the new values to get a computed value out 6535 style.minWidth = style.maxWidth = style.width = ret; 6536 ret = computed.width; 6537 6538 // Revert the changed values 6539 style.width = width; 6540 style.minWidth = minWidth; 6541 style.maxWidth = maxWidth; 6542 } 6543 } 6544 6545 // Support: IE 6546 // IE returns zIndex value as an integer. 6547 return ret === undefined ? 6548 ret : 6549 ret + ""; 6550 }; 6551} else if ( document.documentElement.currentStyle ) { 6552 getStyles = function( elem ) { 6553 return elem.currentStyle; 6554 }; 6555 6556 curCSS = function( elem, name, computed ) { 6557 var left, rs, rsLeft, ret, 6558 style = elem.style; 6559 6560 computed = computed || getStyles( elem ); 6561 ret = computed ? computed[ name ] : undefined; 6562 6563 // Avoid setting ret to empty string here 6564 // so we don't default to auto 6565 if ( ret == null && style && style[ name ] ) { 6566 ret = style[ name ]; 6567 } 6568 6569 // From the awesome hack by Dean Edwards 6570 // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 6571 6572 // If we're not dealing with a regular pixel number 6573 // but a number that has a weird ending, we need to convert it to pixels 6574 // but not position css attributes, as those are proportional to the parent element instead 6575 // and we can't measure the parent instead because it might trigger a "stacking dolls" problem 6576 if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { 6577 6578 // Remember the original values 6579 left = style.left; 6580 rs = elem.runtimeStyle; 6581 rsLeft = rs && rs.left; 6582 6583 // Put in the new values to get a computed value out 6584 if ( rsLeft ) { 6585 rs.left = elem.currentStyle.left; 6586 } 6587 style.left = name === "fontSize" ? "1em" : ret; 6588 ret = style.pixelLeft + "px"; 6589 6590 // Revert the changed values 6591 style.left = left; 6592 if ( rsLeft ) { 6593 rs.left = rsLeft; 6594 } 6595 } 6596 6597 // Support: IE 6598 // IE returns zIndex value as an integer. 6599 return ret === undefined ? 6600 ret : 6601 ret + "" || "auto"; 6602 }; 6603} 6604 6605function addGetHookIf( conditionFn, hookFn ) { 6606 // Define the hook, we'll check on the first run if it's really needed. 6607 return { 6608 get: function() { 6609 var condition = conditionFn(); 6610 6611 if ( condition == null ) { 6612 // The test was not ready at this point; screw the hook this time 6613 // but check again when needed next time. 6614 return; 6615 } 6616 6617 if ( condition ) { 6618 // Hook not needed (or it's not possible to use it due to missing dependency), 6619 // remove it. 6620 // Since there are no other hooks for marginRight, remove the whole object. 6621 delete this.get; 6622 return; 6623 } 6624 6625 // Hook needed; redefine it so that the support test is not executed again. 6626 6627 return (this.get = hookFn).apply( this, arguments ); 6628 } 6629 }; 6630} 6631 6632(function() { 6633 // Minified: var b,c,d,e,f,g, h,i 6634 var div, style, a, pixelPositionVal, boxSizingReliableVal, 6635 reliableHiddenOffsetsVal, reliableMarginRightVal; 6636 6637 // Setup 6638 div = document.createElement( "div" ); 6639 div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>"; 6640 a = div.getElementsByTagName( "a" )[ 0 ]; 6641 style = a && a.style; 6642 6643 // Finish early in limited (non-browser) environments 6644 if ( !style ) { 6645 return; 6646 } 6647 6648 style.cssText = "float:left;opacity:.5"; 6649 6650 // Support: IE<9 6651 // Make sure that element opacity exists (as opposed to filter) 6652 support.opacity = style.opacity === "0.5"; 6653 6654 // Verify style float existence 6655 // (IE uses styleFloat instead of cssFloat) 6656 support.cssFloat = !!style.cssFloat; 6657 6658 div.style.backgroundClip = "content-box"; 6659 div.cloneNode( true ).style.backgroundClip = ""; 6660 support.clearCloneStyle = div.style.backgroundClip === "content-box"; 6661 6662 // Support: Firefox<29, Android 2.3 6663 // Vendor-prefix box-sizing 6664 support.boxSizing = style.boxSizing === "" || style.MozBoxSizing === "" || 6665 style.WebkitBoxSizing === ""; 6666 6667 jQuery.extend(support, { 6668 reliableHiddenOffsets: function() { 6669 if ( reliableHiddenOffsetsVal == null ) { 6670 computeStyleTests(); 6671 } 6672 return reliableHiddenOffsetsVal; 6673 }, 6674 6675 boxSizingReliable: function() { 6676 if ( boxSizingReliableVal == null ) { 6677 computeStyleTests(); 6678 } 6679 return boxSizingReliableVal; 6680 }, 6681 6682 pixelPosition: function() { 6683 if ( pixelPositionVal == null ) { 6684 computeStyleTests(); 6685 } 6686 return pixelPositionVal; 6687 }, 6688 6689 // Support: Android 2.3 6690 reliableMarginRight: function() { 6691 if ( reliableMarginRightVal == null ) { 6692 computeStyleTests(); 6693 } 6694 return reliableMarginRightVal; 6695 } 6696 }); 6697 6698 function computeStyleTests() { 6699 // Minified: var b,c,d,j 6700 var div, body, container, contents; 6701 6702 body = document.getElementsByTagName( "body" )[ 0 ]; 6703 if ( !body || !body.style ) { 6704 // Test fired too early or in an unsupported environment, exit. 6705 return; 6706 } 6707 6708 // Setup 6709 div = document.createElement( "div" ); 6710 container = document.createElement( "div" ); 6711 container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px"; 6712 body.appendChild( container ).appendChild( div ); 6713 6714 div.style.cssText = 6715 // Support: Firefox<29, Android 2.3 6716 // Vendor-prefix box-sizing 6717 "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" + 6718 "box-sizing:border-box;display:block;margin-top:1%;top:1%;" + 6719 "border:1px;padding:1px;width:4px;position:absolute"; 6720 6721 // Support: IE<9 6722 // Assume reasonable values in the absence of getComputedStyle 6723 pixelPositionVal = boxSizingReliableVal = false; 6724 reliableMarginRightVal = true; 6725 6726 // Check for getComputedStyle so that this code is not run in IE<9. 6727 if ( window.getComputedStyle ) { 6728 pixelPositionVal = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; 6729 boxSizingReliableVal = 6730 ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; 6731 6732 // Support: Android 2.3 6733 // Div with explicit width and no margin-right incorrectly 6734 // gets computed margin-right based on width of container (#3333) 6735 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right 6736 contents = div.appendChild( document.createElement( "div" ) ); 6737 6738 // Reset CSS: box-sizing; display; margin; border; padding 6739 contents.style.cssText = div.style.cssText = 6740 // Support: Firefox<29, Android 2.3 6741 // Vendor-prefix box-sizing 6742 "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" + 6743 "box-sizing:content-box;display:block;margin:0;border:0;padding:0"; 6744 contents.style.marginRight = contents.style.width = "0"; 6745 div.style.width = "1px"; 6746 6747 reliableMarginRightVal = 6748 !parseFloat( ( window.getComputedStyle( contents, null ) || {} ).marginRight ); 6749 } 6750 6751 // Support: IE8 6752 // Check if table cells still have offsetWidth/Height when they are set 6753 // to display:none and there are still other visible table cells in a 6754 // table row; if so, offsetWidth/Height are not reliable for use when 6755 // determining if an element has been hidden directly using 6756 // display:none (it is still safe to use offsets if a parent element is 6757 // hidden; don safety goggles and see bug #4512 for more information). 6758 div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>"; 6759 contents = div.getElementsByTagName( "td" ); 6760 contents[ 0 ].style.cssText = "margin:0;border:0;padding:0;display:none"; 6761 reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0; 6762 if ( reliableHiddenOffsetsVal ) { 6763 contents[ 0 ].style.display = ""; 6764 contents[ 1 ].style.display = "none"; 6765 reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0; 6766 } 6767 6768 body.removeChild( container ); 6769 } 6770 6771})(); 6772 6773// A method for quickly swapping in/out CSS properties to get correct calculations. 6774jQuery.swap = function( elem, options, callback, args ) { 6775 var ret, name, 6776 old = {}; 6777 6778 // Remember the old values, and insert the new ones 6779 for ( name in options ) { 6780 old[ name ] = elem.style[ name ]; 6781 elem.style[ name ] = options[ name ]; 6782 } 6783 6784 ret = callback.apply( elem, args || [] ); 6785 6786 // Revert the old values 6787 for ( name in options ) { 6788 elem.style[ name ] = old[ name ]; 6789 } 6790 6791 return ret; 6792}; 6793 6794var 6795 ralpha = /alpha\([^)]*\)/i, 6796 ropacity = /opacity\s*=\s*([^)]*)/, 6797 6798 // swappable if display is none or starts with table except "table", "table-cell", or "table-caption" 6799 // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display 6800 rdisplayswap = /^(none|table(?!-c[ea]).+)/, 6801 rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ), 6802 rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ), 6803 6804 cssShow = { position: "absolute", visibility: "hidden", display: "block" }, 6805 cssNormalTransform = { 6806 letterSpacing: "0", 6807 fontWeight: "400" 6808 }, 6809 6810 cssPrefixes = [ "Webkit", "O", "Moz", "ms" ]; 6811 6812// return a css property mapped to a potentially vendor prefixed property 6813function vendorPropName( style, name ) { 6814 6815 // shortcut for names that are not vendor prefixed 6816 if ( name in style ) { 6817 return name; 6818 } 6819 6820 // check for vendor prefixed names 6821 var capName = name.charAt(0).toUpperCase() + name.slice(1), 6822 origName = name, 6823 i = cssPrefixes.length; 6824 6825 while ( i-- ) { 6826 name = cssPrefixes[ i ] + capName; 6827 if ( name in style ) { 6828 return name; 6829 } 6830 } 6831 6832 return origName; 6833} 6834 6835function showHide( elements, show ) { 6836 var display, elem, hidden, 6837 values = [], 6838 index = 0, 6839 length = elements.length; 6840 6841 for ( ; index < length; index++ ) { 6842 elem = elements[ index ]; 6843 if ( !elem.style ) { 6844 continue; 6845 } 6846 6847 values[ index ] = jQuery._data( elem, "olddisplay" ); 6848 display = elem.style.display; 6849 if ( show ) { 6850 // Reset the inline display of this element to learn if it is 6851 // being hidden by cascaded rules or not 6852 if ( !values[ index ] && display === "none" ) { 6853 elem.style.display = ""; 6854 } 6855 6856 // Set elements which have been overridden with display: none 6857 // in a stylesheet to whatever the default browser style is 6858 // for such an element 6859 if ( elem.style.display === "" && isHidden( elem ) ) { 6860 values[ index ] = jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) ); 6861 } 6862 } else { 6863 hidden = isHidden( elem ); 6864 6865 if ( display && display !== "none" || !hidden ) { 6866 jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) ); 6867 } 6868 } 6869 } 6870 6871 // Set the display of most of the elements in a second loop 6872 // to avoid the constant reflow 6873 for ( index = 0; index < length; index++ ) { 6874 elem = elements[ index ]; 6875 if ( !elem.style ) { 6876 continue; 6877 } 6878 if ( !show || elem.style.display === "none" || elem.style.display === "" ) { 6879 elem.style.display = show ? values[ index ] || "" : "none"; 6880 } 6881 } 6882 6883 return elements; 6884} 6885 6886function setPositiveNumber( elem, value, subtract ) { 6887 var matches = rnumsplit.exec( value ); 6888 return matches ? 6889 // Guard against undefined "subtract", e.g., when used as in cssHooks 6890 Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : 6891 value; 6892} 6893 6894function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { 6895 var i = extra === ( isBorderBox ? "border" : "content" ) ? 6896 // If we already have the right measurement, avoid augmentation 6897 4 : 6898 // Otherwise initialize for horizontal or vertical properties 6899 name === "width" ? 1 : 0, 6900 6901 val = 0; 6902 6903 for ( ; i < 4; i += 2 ) { 6904 // both box models exclude margin, so add it if we want it 6905 if ( extra === "margin" ) { 6906 val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); 6907 } 6908 6909 if ( isBorderBox ) { 6910 // border-box includes padding, so remove it if we want content 6911 if ( extra === "content" ) { 6912 val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); 6913 } 6914 6915 // at this point, extra isn't border nor margin, so remove border 6916 if ( extra !== "margin" ) { 6917 val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); 6918 } 6919 } else { 6920 // at this point, extra isn't content, so add padding 6921 val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); 6922 6923 // at this point, extra isn't content nor padding, so add border 6924 if ( extra !== "padding" ) { 6925 val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); 6926 } 6927 } 6928 } 6929 6930 return val; 6931} 6932 6933function getWidthOrHeight( elem, name, extra ) { 6934 6935 // Start with offset property, which is equivalent to the border-box value 6936 var valueIsBorderBox = true, 6937 val = name === "width" ? elem.offsetWidth : elem.offsetHeight, 6938 styles = getStyles( elem ), 6939 isBorderBox = support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; 6940 6941 // some non-html elements return undefined for offsetWidth, so check for null/undefined 6942 // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 6943 // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 6944 if ( val <= 0 || val == null ) { 6945 // Fall back to computed then uncomputed css if necessary 6946 val = curCSS( elem, name, styles ); 6947 if ( val < 0 || val == null ) { 6948 val = elem.style[ name ]; 6949 } 6950 6951 // Computed unit is not pixels. Stop here and return. 6952 if ( rnumnonpx.test(val) ) { 6953 return val; 6954 } 6955 6956 // we need the check for style in case a browser which returns unreliable values 6957 // for getComputedStyle silently falls back to the reliable elem.style 6958 valueIsBorderBox = isBorderBox && ( support.boxSizingReliable() || val === elem.style[ name ] ); 6959 6960 // Normalize "", auto, and prepare for extra 6961 val = parseFloat( val ) || 0; 6962 } 6963 6964 // use the active box-sizing model to add/subtract irrelevant styles 6965 return ( val + 6966 augmentWidthOrHeight( 6967 elem, 6968 name, 6969 extra || ( isBorderBox ? "border" : "content" ), 6970 valueIsBorderBox, 6971 styles 6972 ) 6973 ) + "px"; 6974} 6975 6976jQuery.extend({ 6977 // Add in style property hooks for overriding the default 6978 // behavior of getting and setting a style property 6979 cssHooks: { 6980 opacity: { 6981 get: function( elem, computed ) { 6982 if ( computed ) { 6983 // We should always get a number back from opacity 6984 var ret = curCSS( elem, "opacity" ); 6985 return ret === "" ? "1" : ret; 6986 } 6987 } 6988 } 6989 }, 6990 6991 // Don't automatically add "px" to these possibly-unitless properties 6992 cssNumber: { 6993 "columnCount": true, 6994 "fillOpacity": true, 6995 "flexGrow": true, 6996 "flexShrink": true, 6997 "fontWeight": true, 6998 "lineHeight": true, 6999 "opacity": true, 7000 "order": true, 7001 "orphans": true, 7002 "widows": true, 7003 "zIndex": true, 7004 "zoom": true 7005 }, 7006 7007 // Add in properties whose names you wish to fix before 7008 // setting or getting the value 7009 cssProps: { 7010 // normalize float css property 7011 "float": support.cssFloat ? "cssFloat" : "styleFloat" 7012 }, 7013 7014 // Get and set the style property on a DOM Node 7015 style: function( elem, name, value, extra ) { 7016 // Don't set styles on text and comment nodes 7017 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { 7018 return; 7019 } 7020 7021 // Make sure that we're working with the right name 7022 var ret, type, hooks, 7023 origName = jQuery.camelCase( name ), 7024 style = elem.style; 7025 7026 name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); 7027 7028 // gets hook for the prefixed version 7029 // followed by the unprefixed version 7030 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; 7031 7032 // Check if we're setting a value 7033 if ( value !== undefined ) { 7034 type = typeof value; 7035 7036 // convert relative number strings (+= or -=) to relative numbers. #7345 7037 if ( type === "string" && (ret = rrelNum.exec( value )) ) { 7038 value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); 7039 // Fixes bug #9237 7040 type = "number"; 7041 } 7042 7043 // Make sure that null and NaN values aren't set. See: #7116 7044 if ( value == null || value !== value ) { 7045 return; 7046 } 7047 7048 // If a number was passed in, add 'px' to the (except for certain CSS properties) 7049 if ( type === "number" && !jQuery.cssNumber[ origName ] ) { 7050 value += "px"; 7051 } 7052 7053 // Fixes #8908, it can be done more correctly by specifing setters in cssHooks, 7054 // but it would mean to define eight (for every problematic property) identical functions 7055 if ( !support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) { 7056 style[ name ] = "inherit"; 7057 } 7058 7059 // If a hook was provided, use that value, otherwise just set the specified value 7060 if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { 7061 7062 // Support: IE 7063 // Swallow errors from 'invalid' CSS values (#5509) 7064 try { 7065 style[ name ] = value; 7066 } catch(e) {} 7067 } 7068 7069 } else { 7070 // If a hook was provided get the non-computed value from there 7071 if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { 7072 return ret; 7073 } 7074 7075 // Otherwise just get the value from the style object 7076 return style[ name ]; 7077 } 7078 }, 7079 7080 css: function( elem, name, extra, styles ) { 7081 var num, val, hooks, 7082 origName = jQuery.camelCase( name ); 7083 7084 // Make sure that we're working with the right name 7085 name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); 7086 7087 // gets hook for the prefixed version 7088 // followed by the unprefixed version 7089 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; 7090 7091 // If a hook was provided get the computed value from there 7092 if ( hooks && "get" in hooks ) { 7093 val = hooks.get( elem, true, extra ); 7094 } 7095 7096 // Otherwise, if a way to get the computed value exists, use that 7097 if ( val === undefined ) { 7098 val = curCSS( elem, name, styles ); 7099 } 7100 7101 //convert "normal" to computed value 7102 if ( val === "normal" && name in cssNormalTransform ) { 7103 val = cssNormalTransform[ name ]; 7104 } 7105 7106 // Return, converting to number if forced or a qualifier was provided and val looks numeric 7107 if ( extra === "" || extra ) { 7108 num = parseFloat( val ); 7109 return extra === true || jQuery.isNumeric( num ) ? num || 0 : val; 7110 } 7111 return val; 7112 } 7113}); 7114 7115jQuery.each([ "height", "width" ], function( i, name ) { 7116 jQuery.cssHooks[ name ] = { 7117 get: function( elem, computed, extra ) { 7118 if ( computed ) { 7119 // certain elements can have dimension info if we invisibly show them 7120 // however, it must have a current display style that would benefit from this 7121 return rdisplayswap.test( jQuery.css( elem, "display" ) ) && elem.offsetWidth === 0 ? 7122 jQuery.swap( elem, cssShow, function() { 7123 return getWidthOrHeight( elem, name, extra ); 7124 }) : 7125 getWidthOrHeight( elem, name, extra ); 7126 } 7127 }, 7128 7129 set: function( elem, value, extra ) { 7130 var styles = extra && getStyles( elem ); 7131 return setPositiveNumber( elem, value, extra ? 7132 augmentWidthOrHeight( 7133 elem, 7134 name, 7135 extra, 7136 support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box", 7137 styles 7138 ) : 0 7139 ); 7140 } 7141 }; 7142}); 7143 7144if ( !support.opacity ) { 7145 jQuery.cssHooks.opacity = { 7146 get: function( elem, computed ) { 7147 // IE uses filters for opacity 7148 return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? 7149 ( 0.01 * parseFloat( RegExp.$1 ) ) + "" : 7150 computed ? "1" : ""; 7151 }, 7152 7153 set: function( elem, value ) { 7154 var style = elem.style, 7155 currentStyle = elem.currentStyle, 7156 opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "", 7157 filter = currentStyle && currentStyle.filter || style.filter || ""; 7158 7159 // IE has trouble with opacity if it does not have layout 7160 // Force it by setting the zoom level 7161 style.zoom = 1; 7162 7163 // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652 7164 // if value === "", then remove inline opacity #12685 7165 if ( ( value >= 1 || value === "" ) && 7166 jQuery.trim( filter.replace( ralpha, "" ) ) === "" && 7167 style.removeAttribute ) { 7168 7169 // Setting style.filter to null, "" & " " still leave "filter:" in the cssText 7170 // if "filter:" is present at all, clearType is disabled, we want to avoid this 7171 // style.removeAttribute is IE Only, but so apparently is this code path... 7172 style.removeAttribute( "filter" ); 7173 7174 // if there is no filter style applied in a css rule or unset inline opacity, we are done 7175 if ( value === "" || currentStyle && !currentStyle.filter ) { 7176 return; 7177 } 7178 } 7179 7180 // otherwise, set new filter values 7181 style.filter = ralpha.test( filter ) ? 7182 filter.replace( ralpha, opacity ) : 7183 filter + " " + opacity; 7184 } 7185 }; 7186} 7187 7188jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight, 7189 function( elem, computed ) { 7190 if ( computed ) { 7191 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right 7192 // Work around by temporarily setting element display to inline-block 7193 return jQuery.swap( elem, { "display": "inline-block" }, 7194 curCSS, [ elem, "marginRight" ] ); 7195 } 7196 } 7197); 7198 7199// These hooks are used by animate to expand properties 7200jQuery.each({ 7201 margin: "", 7202 padding: "", 7203 border: "Width" 7204}, function( prefix, suffix ) { 7205 jQuery.cssHooks[ prefix + suffix ] = { 7206 expand: function( value ) { 7207 var i = 0, 7208 expanded = {}, 7209 7210 // assumes a single number if not a string 7211 parts = typeof value === "string" ? value.split(" ") : [ value ]; 7212 7213 for ( ; i < 4; i++ ) { 7214 expanded[ prefix + cssExpand[ i ] + suffix ] = 7215 parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; 7216 } 7217 7218 return expanded; 7219 } 7220 }; 7221 7222 if ( !rmargin.test( prefix ) ) { 7223 jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; 7224 } 7225}); 7226 7227jQuery.fn.extend({ 7228 css: function( name, value ) { 7229 return access( this, function( elem, name, value ) { 7230 var styles, len, 7231 map = {}, 7232 i = 0; 7233 7234 if ( jQuery.isArray( name ) ) { 7235 styles = getStyles( elem ); 7236 len = name.length; 7237 7238 for ( ; i < len; i++ ) { 7239 map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); 7240 } 7241 7242 return map; 7243 } 7244 7245 return value !== undefined ? 7246 jQuery.style( elem, name, value ) : 7247 jQuery.css( elem, name ); 7248 }, name, value, arguments.length > 1 ); 7249 }, 7250 show: function() { 7251 return showHide( this, true ); 7252 }, 7253 hide: function() { 7254 return showHide( this ); 7255 }, 7256 toggle: function( state ) { 7257 if ( typeof state === "boolean" ) { 7258 return state ? this.show() : this.hide(); 7259 } 7260 7261 return this.each(function() { 7262 if ( isHidden( this ) ) { 7263 jQuery( this ).show(); 7264 } else { 7265 jQuery( this ).hide(); 7266 } 7267 }); 7268 } 7269}); 7270 7271function Tween( elem, options, prop, end, easing ) { 7272 return new Tween.prototype.init( elem, options, prop, end, easing ); 7273} 7274jQuery.Tween = Tween; 7275 7276Tween.prototype = { 7277 constructor: Tween, 7278 init: function( elem, options, prop, end, easing, unit ) { 7279 this.elem = elem; 7280 this.prop = prop; 7281 this.easing = easing || "swing"; 7282 this.options = options; 7283 this.start = this.now = this.cur(); 7284 this.end = end; 7285 this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); 7286 }, 7287 cur: function() { 7288 var hooks = Tween.propHooks[ this.prop ]; 7289 7290 return hooks && hooks.get ? 7291 hooks.get( this ) : 7292 Tween.propHooks._default.get( this ); 7293 }, 7294 run: function( percent ) { 7295 var eased, 7296 hooks = Tween.propHooks[ this.prop ]; 7297 7298 if ( this.options.duration ) { 7299 this.pos = eased = jQuery.easing[ this.easing ]( 7300 percent, this.options.duration * percent, 0, 1, this.options.duration 7301 ); 7302 } else { 7303 this.pos = eased = percent; 7304 } 7305 this.now = ( this.end - this.start ) * eased + this.start; 7306 7307 if ( this.options.step ) { 7308 this.options.step.call( this.elem, this.now, this ); 7309 } 7310 7311 if ( hooks && hooks.set ) { 7312 hooks.set( this ); 7313 } else { 7314 Tween.propHooks._default.set( this ); 7315 } 7316 return this; 7317 } 7318}; 7319 7320Tween.prototype.init.prototype = Tween.prototype; 7321 7322Tween.propHooks = { 7323 _default: { 7324 get: function( tween ) { 7325 var result; 7326 7327 if ( tween.elem[ tween.prop ] != null && 7328 (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) { 7329 return tween.elem[ tween.prop ]; 7330 } 7331 7332 // passing an empty string as a 3rd parameter to .css will automatically 7333 // attempt a parseFloat and fallback to a string if the parse fails 7334 // so, simple values such as "10px" are parsed to Float. 7335 // complex values such as "rotate(1rad)" are returned as is. 7336 result = jQuery.css( tween.elem, tween.prop, "" ); 7337 // Empty strings, null, undefined and "auto" are converted to 0. 7338 return !result || result === "auto" ? 0 : result; 7339 }, 7340 set: function( tween ) { 7341 // use step hook for back compat - use cssHook if its there - use .style if its 7342 // available and use plain properties where available 7343 if ( jQuery.fx.step[ tween.prop ] ) { 7344 jQuery.fx.step[ tween.prop ]( tween ); 7345 } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) { 7346 jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); 7347 } else { 7348 tween.elem[ tween.prop ] = tween.now; 7349 } 7350 } 7351 } 7352}; 7353 7354// Support: IE <=9 7355// Panic based approach to setting things on disconnected nodes 7356 7357Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { 7358 set: function( tween ) { 7359 if ( tween.elem.nodeType && tween.elem.parentNode ) { 7360 tween.elem[ tween.prop ] = tween.now; 7361 } 7362 } 7363}; 7364 7365jQuery.easing = { 7366 linear: function( p ) { 7367 return p; 7368 }, 7369 swing: function( p ) { 7370 return 0.5 - Math.cos( p * Math.PI ) / 2; 7371 } 7372}; 7373 7374jQuery.fx = Tween.prototype.init; 7375 7376// Back Compat <1.8 extension point 7377jQuery.fx.step = {}; 7378 7379var 7380 fxNow, timerId, 7381 rfxtypes = /^(?:toggle|show|hide)$/, 7382 rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ), 7383 rrun = /queueHooks$/, 7384 animationPrefilters = [ defaultPrefilter ], 7385 tweeners = { 7386 "*": [ function( prop, value ) { 7387 var tween = this.createTween( prop, value ), 7388 target = tween.cur(), 7389 parts = rfxnum.exec( value ), 7390 unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), 7391 7392 // Starting value computation is required for potential unit mismatches 7393 start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) && 7394 rfxnum.exec( jQuery.css( tween.elem, prop ) ), 7395 scale = 1, 7396 maxIterations = 20; 7397 7398 if ( start && start[ 3 ] !== unit ) { 7399 // Trust units reported by jQuery.css 7400 unit = unit || start[ 3 ]; 7401 7402 // Make sure we update the tween properties later on 7403 parts = parts || []; 7404 7405 // Iteratively approximate from a nonzero starting point 7406 start = +target || 1; 7407 7408 do { 7409 // If previous iteration zeroed out, double until we get *something* 7410 // Use a string for doubling factor so we don't accidentally see scale as unchanged below 7411 scale = scale || ".5"; 7412 7413 // Adjust and apply 7414 start = start / scale; 7415 jQuery.style( tween.elem, prop, start + unit ); 7416 7417 // Update scale, tolerating zero or NaN from tween.cur() 7418 // And breaking the loop if scale is unchanged or perfect, or if we've just had enough 7419 } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations ); 7420 } 7421 7422 // Update tween properties 7423 if ( parts ) { 7424 start = tween.start = +start || +target || 0; 7425 tween.unit = unit; 7426 // If a +=/-= token was provided, we're doing a relative animation 7427 tween.end = parts[ 1 ] ? 7428 start + ( parts[ 1 ] + 1 ) * parts[ 2 ] : 7429 +parts[ 2 ]; 7430 } 7431 7432 return tween; 7433 } ] 7434 }; 7435 7436// Animations created synchronously will run synchronously 7437function createFxNow() { 7438 setTimeout(function() { 7439 fxNow = undefined; 7440 }); 7441 return ( fxNow = jQuery.now() ); 7442} 7443 7444// Generate parameters to create a standard animation 7445function genFx( type, includeWidth ) { 7446 var which, 7447 attrs = { height: type }, 7448 i = 0; 7449 7450 // if we include width, step value is 1 to do all cssExpand values, 7451 // if we don't include width, step value is 2 to skip over Left and Right 7452 includeWidth = includeWidth ? 1 : 0; 7453 for ( ; i < 4 ; i += 2 - includeWidth ) { 7454 which = cssExpand[ i ]; 7455 attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; 7456 } 7457 7458 if ( includeWidth ) { 7459 attrs.opacity = attrs.width = type; 7460 } 7461 7462 return attrs; 7463} 7464 7465function createTween( value, prop, animation ) { 7466 var tween, 7467 collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ), 7468 index = 0, 7469 length = collection.length; 7470 for ( ; index < length; index++ ) { 7471 if ( (tween = collection[ index ].call( animation, prop, value )) ) { 7472 7473 // we're done with this property 7474 return tween; 7475 } 7476 } 7477} 7478 7479function defaultPrefilter( elem, props, opts ) { 7480 /* jshint validthis: true */ 7481 var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay, 7482 anim = this, 7483 orig = {}, 7484 style = elem.style, 7485 hidden = elem.nodeType && isHidden( elem ), 7486 dataShow = jQuery._data( elem, "fxshow" ); 7487 7488 // handle queue: false promises 7489 if ( !opts.queue ) { 7490 hooks = jQuery._queueHooks( elem, "fx" ); 7491 if ( hooks.unqueued == null ) { 7492 hooks.unqueued = 0; 7493 oldfire = hooks.empty.fire; 7494 hooks.empty.fire = function() { 7495 if ( !hooks.unqueued ) { 7496 oldfire(); 7497 } 7498 }; 7499 } 7500 hooks.unqueued++; 7501 7502 anim.always(function() { 7503 // doing this makes sure that the complete handler will be called 7504 // before this completes 7505 anim.always(function() { 7506 hooks.unqueued--; 7507 if ( !jQuery.queue( elem, "fx" ).length ) { 7508 hooks.empty.fire(); 7509 } 7510 }); 7511 }); 7512 } 7513 7514 // height/width overflow pass 7515 if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) { 7516 // Make sure that nothing sneaks out 7517 // Record all 3 overflow attributes because IE does not 7518 // change the overflow attribute when overflowX and 7519 // overflowY are set to the same value 7520 opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; 7521 7522 // Set display property to inline-block for height/width 7523 // animations on inline elements that are having width/height animated 7524 display = jQuery.css( elem, "display" ); 7525 7526 // Test default display if display is currently "none" 7527 checkDisplay = display === "none" ? 7528 jQuery._data( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display; 7529 7530 if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) { 7531 7532 // inline-level elements accept inline-block; 7533 // block-level elements need to be inline with layout 7534 if ( !support.inlineBlockNeedsLayout || defaultDisplay( elem.nodeName ) === "inline" ) { 7535 style.display = "inline-block"; 7536 } else { 7537 style.zoom = 1; 7538 } 7539 } 7540 } 7541 7542 if ( opts.overflow ) { 7543 style.overflow = "hidden"; 7544 if ( !support.shrinkWrapBlocks() ) { 7545 anim.always(function() { 7546 style.overflow = opts.overflow[ 0 ]; 7547 style.overflowX = opts.overflow[ 1 ]; 7548 style.overflowY = opts.overflow[ 2 ]; 7549 }); 7550 } 7551 } 7552 7553 // show/hide pass 7554 for ( prop in props ) { 7555 value = props[ prop ]; 7556 if ( rfxtypes.exec( value ) ) { 7557 delete props[ prop ]; 7558 toggle = toggle || value === "toggle"; 7559 if ( value === ( hidden ? "hide" : "show" ) ) { 7560 7561 // If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden 7562 if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { 7563 hidden = true; 7564 } else { 7565 continue; 7566 } 7567 } 7568 orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); 7569 7570 // Any non-fx value stops us from restoring the original display value 7571 } else { 7572 display = undefined; 7573 } 7574 } 7575 7576 if ( !jQuery.isEmptyObject( orig ) ) { 7577 if ( dataShow ) { 7578 if ( "hidden" in dataShow ) { 7579 hidden = dataShow.hidden; 7580 } 7581 } else { 7582 dataShow = jQuery._data( elem, "fxshow", {} ); 7583 } 7584 7585 // store state if its toggle - enables .stop().toggle() to "reverse" 7586 if ( toggle ) { 7587 dataShow.hidden = !hidden; 7588 } 7589 if ( hidden ) { 7590 jQuery( elem ).show(); 7591 } else { 7592 anim.done(function() { 7593 jQuery( elem ).hide(); 7594 }); 7595 } 7596 anim.done(function() { 7597 var prop; 7598 jQuery._removeData( elem, "fxshow" ); 7599 for ( prop in orig ) { 7600 jQuery.style( elem, prop, orig[ prop ] ); 7601 } 7602 }); 7603 for ( prop in orig ) { 7604 tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); 7605 7606 if ( !( prop in dataShow ) ) { 7607 dataShow[ prop ] = tween.start; 7608 if ( hidden ) { 7609 tween.end = tween.start; 7610 tween.start = prop === "width" || prop === "height" ? 1 : 0; 7611 } 7612 } 7613 } 7614 7615 // If this is a noop like .hide().hide(), restore an overwritten display value 7616 } else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" ) { 7617 style.display = display; 7618 } 7619} 7620 7621function propFilter( props, specialEasing ) { 7622 var index, name, easing, value, hooks; 7623 7624 // camelCase, specialEasing and expand cssHook pass 7625 for ( index in props ) { 7626 name = jQuery.camelCase( index ); 7627 easing = specialEasing[ name ]; 7628 value = props[ index ]; 7629 if ( jQuery.isArray( value ) ) { 7630 easing = value[ 1 ]; 7631 value = props[ index ] = value[ 0 ]; 7632 } 7633 7634 if ( index !== name ) { 7635 props[ name ] = value; 7636 delete props[ index ]; 7637 } 7638 7639 hooks = jQuery.cssHooks[ name ]; 7640 if ( hooks && "expand" in hooks ) { 7641 value = hooks.expand( value ); 7642 delete props[ name ]; 7643 7644 // not quite $.extend, this wont overwrite keys already present. 7645 // also - reusing 'index' from above because we have the correct "name" 7646 for ( index in value ) { 7647 if ( !( index in props ) ) { 7648 props[ index ] = value[ index ]; 7649 specialEasing[ index ] = easing; 7650 } 7651 } 7652 } else { 7653 specialEasing[ name ] = easing; 7654 } 7655 } 7656} 7657 7658function Animation( elem, properties, options ) { 7659 var result, 7660 stopped, 7661 index = 0, 7662 length = animationPrefilters.length, 7663 deferred = jQuery.Deferred().always( function() { 7664 // don't match elem in the :animated selector 7665 delete tick.elem; 7666 }), 7667 tick = function() { 7668 if ( stopped ) { 7669 return false; 7670 } 7671 var currentTime = fxNow || createFxNow(), 7672 remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), 7673 // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497) 7674 temp = remaining / animation.duration || 0, 7675 percent = 1 - temp, 7676 index = 0, 7677 length = animation.tweens.length; 7678 7679 for ( ; index < length ; index++ ) { 7680 animation.tweens[ index ].run( percent ); 7681 } 7682 7683 deferred.notifyWith( elem, [ animation, percent, remaining ]); 7684 7685 if ( percent < 1 && length ) { 7686 return remaining; 7687 } else { 7688 deferred.resolveWith( elem, [ animation ] ); 7689 return false; 7690 } 7691 }, 7692 animation = deferred.promise({ 7693 elem: elem, 7694 props: jQuery.extend( {}, properties ), 7695 opts: jQuery.extend( true, { specialEasing: {} }, options ), 7696 originalProperties: properties, 7697 originalOptions: options, 7698 startTime: fxNow || createFxNow(), 7699 duration: options.duration, 7700 tweens: [], 7701 createTween: function( prop, end ) { 7702 var tween = jQuery.Tween( elem, animation.opts, prop, end, 7703 animation.opts.specialEasing[ prop ] || animation.opts.easing ); 7704 animation.tweens.push( tween ); 7705 return tween; 7706 }, 7707 stop: function( gotoEnd ) { 7708 var index = 0, 7709 // if we are going to the end, we want to run all the tweens 7710 // otherwise we skip this part 7711 length = gotoEnd ? animation.tweens.length : 0; 7712 if ( stopped ) { 7713 return this; 7714 } 7715 stopped = true; 7716 for ( ; index < length ; index++ ) { 7717 animation.tweens[ index ].run( 1 ); 7718 } 7719 7720 // resolve when we played the last frame 7721 // otherwise, reject 7722 if ( gotoEnd ) { 7723 deferred.resolveWith( elem, [ animation, gotoEnd ] ); 7724 } else { 7725 deferred.rejectWith( elem, [ animation, gotoEnd ] ); 7726 } 7727 return this; 7728 } 7729 }), 7730 props = animation.props; 7731 7732 propFilter( props, animation.opts.specialEasing ); 7733 7734 for ( ; index < length ; index++ ) { 7735 result = animationPrefilters[ index ].call( animation, elem, props, animation.opts ); 7736 if ( result ) { 7737 return result; 7738 } 7739 } 7740 7741 jQuery.map( props, createTween, animation ); 7742 7743 if ( jQuery.isFunction( animation.opts.start ) ) { 7744 animation.opts.start.call( elem, animation ); 7745 } 7746 7747 jQuery.fx.timer( 7748 jQuery.extend( tick, { 7749 elem: elem, 7750 anim: animation, 7751 queue: animation.opts.queue 7752 }) 7753 ); 7754 7755 // attach callbacks from options 7756 return animation.progress( animation.opts.progress ) 7757 .done( animation.opts.done, animation.opts.complete ) 7758 .fail( animation.opts.fail ) 7759 .always( animation.opts.always ); 7760} 7761 7762jQuery.Animation = jQuery.extend( Animation, { 7763 tweener: function( props, callback ) { 7764 if ( jQuery.isFunction( props ) ) { 7765 callback = props; 7766 props = [ "*" ]; 7767 } else { 7768 props = props.split(" "); 7769 } 7770 7771 var prop, 7772 index = 0, 7773 length = props.length; 7774 7775 for ( ; index < length ; index++ ) { 7776 prop = props[ index ]; 7777 tweeners[ prop ] = tweeners[ prop ] || []; 7778 tweeners[ prop ].unshift( callback ); 7779 } 7780 }, 7781 7782 prefilter: function( callback, prepend ) { 7783 if ( prepend ) { 7784 animationPrefilters.unshift( callback ); 7785 } else { 7786 animationPrefilters.push( callback ); 7787 } 7788 } 7789}); 7790 7791jQuery.speed = function( speed, easing, fn ) { 7792 var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { 7793 complete: fn || !fn && easing || 7794 jQuery.isFunction( speed ) && speed, 7795 duration: speed, 7796 easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing 7797 }; 7798 7799 opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : 7800 opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; 7801 7802 // normalize opt.queue - true/undefined/null -> "fx" 7803 if ( opt.queue == null || opt.queue === true ) { 7804 opt.queue = "fx"; 7805 } 7806 7807 // Queueing 7808 opt.old = opt.complete; 7809 7810 opt.complete = function() { 7811 if ( jQuery.isFunction( opt.old ) ) { 7812 opt.old.call( this ); 7813 } 7814 7815 if ( opt.queue ) { 7816 jQuery.dequeue( this, opt.queue ); 7817 } 7818 }; 7819 7820 return opt; 7821}; 7822 7823jQuery.fn.extend({ 7824 fadeTo: function( speed, to, easing, callback ) { 7825 7826 // show any hidden elements after setting opacity to 0 7827 return this.filter( isHidden ).css( "opacity", 0 ).show() 7828 7829 // animate to the value specified 7830 .end().animate({ opacity: to }, speed, easing, callback ); 7831 }, 7832 animate: function( prop, speed, easing, callback ) { 7833 var empty = jQuery.isEmptyObject( prop ), 7834 optall = jQuery.speed( speed, easing, callback ), 7835 doAnimation = function() { 7836 // Operate on a copy of prop so per-property easing won't be lost 7837 var anim = Animation( this, jQuery.extend( {}, prop ), optall ); 7838 7839 // Empty animations, or finishing resolves immediately 7840 if ( empty || jQuery._data( this, "finish" ) ) { 7841 anim.stop( true ); 7842 } 7843 }; 7844 doAnimation.finish = doAnimation; 7845 7846 return empty || optall.queue === false ? 7847 this.each( doAnimation ) : 7848 this.queue( optall.queue, doAnimation ); 7849 }, 7850 stop: function( type, clearQueue, gotoEnd ) { 7851 var stopQueue = function( hooks ) { 7852 var stop = hooks.stop; 7853 delete hooks.stop; 7854 stop( gotoEnd ); 7855 }; 7856 7857 if ( typeof type !== "string" ) { 7858 gotoEnd = clearQueue; 7859 clearQueue = type; 7860 type = undefined; 7861 } 7862 if ( clearQueue && type !== false ) { 7863 this.queue( type || "fx", [] ); 7864 } 7865 7866 return this.each(function() { 7867 var dequeue = true, 7868 index = type != null && type + "queueHooks", 7869 timers = jQuery.timers, 7870 data = jQuery._data( this ); 7871 7872 if ( index ) { 7873 if ( data[ index ] && data[ index ].stop ) { 7874 stopQueue( data[ index ] ); 7875 } 7876 } else { 7877 for ( index in data ) { 7878 if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { 7879 stopQueue( data[ index ] ); 7880 } 7881 } 7882 } 7883 7884 for ( index = timers.length; index--; ) { 7885 if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) { 7886 timers[ index ].anim.stop( gotoEnd ); 7887 dequeue = false; 7888 timers.splice( index, 1 ); 7889 } 7890 } 7891 7892 // start the next in the queue if the last step wasn't forced 7893 // timers currently will call their complete callbacks, which will dequeue 7894 // but only if they were gotoEnd 7895 if ( dequeue || !gotoEnd ) { 7896 jQuery.dequeue( this, type ); 7897 } 7898 }); 7899 }, 7900 finish: function( type ) { 7901 if ( type !== false ) { 7902 type = type || "fx"; 7903 } 7904 return this.each(function() { 7905 var index, 7906 data = jQuery._data( this ), 7907 queue = data[ type + "queue" ], 7908 hooks = data[ type + "queueHooks" ], 7909 timers = jQuery.timers, 7910 length = queue ? queue.length : 0; 7911 7912 // enable finishing flag on private data 7913 data.finish = true; 7914 7915 // empty the queue first 7916 jQuery.queue( this, type, [] ); 7917 7918 if ( hooks && hooks.stop ) { 7919 hooks.stop.call( this, true ); 7920 } 7921 7922 // look for any active animations, and finish them 7923 for ( index = timers.length; index--; ) { 7924 if ( timers[ index ].elem === this && timers[ index ].queue === type ) { 7925 timers[ index ].anim.stop( true ); 7926 timers.splice( index, 1 ); 7927 } 7928 } 7929 7930 // look for any animations in the old queue and finish them 7931 for ( index = 0; index < length; index++ ) { 7932 if ( queue[ index ] && queue[ index ].finish ) { 7933 queue[ index ].finish.call( this ); 7934 } 7935 } 7936 7937 // turn off finishing flag 7938 delete data.finish; 7939 }); 7940 } 7941}); 7942 7943jQuery.each([ "toggle", "show", "hide" ], function( i, name ) { 7944 var cssFn = jQuery.fn[ name ]; 7945 jQuery.fn[ name ] = function( speed, easing, callback ) { 7946 return speed == null || typeof speed === "boolean" ? 7947 cssFn.apply( this, arguments ) : 7948 this.animate( genFx( name, true ), speed, easing, callback ); 7949 }; 7950}); 7951 7952// Generate shortcuts for custom animations 7953jQuery.each({ 7954 slideDown: genFx("show"), 7955 slideUp: genFx("hide"), 7956 slideToggle: genFx("toggle"), 7957 fadeIn: { opacity: "show" }, 7958 fadeOut: { opacity: "hide" }, 7959 fadeToggle: { opacity: "toggle" } 7960}, function( name, props ) { 7961 jQuery.fn[ name ] = function( speed, easing, callback ) { 7962 return this.animate( props, speed, easing, callback ); 7963 }; 7964}); 7965 7966jQuery.timers = []; 7967jQuery.fx.tick = function() { 7968 var timer, 7969 timers = jQuery.timers, 7970 i = 0; 7971 7972 fxNow = jQuery.now(); 7973 7974 for ( ; i < timers.length; i++ ) { 7975 timer = timers[ i ]; 7976 // Checks the timer has not already been removed 7977 if ( !timer() && timers[ i ] === timer ) { 7978 timers.splice( i--, 1 ); 7979 } 7980 } 7981 7982 if ( !timers.length ) { 7983 jQuery.fx.stop(); 7984 } 7985 fxNow = undefined; 7986}; 7987 7988jQuery.fx.timer = function( timer ) { 7989 jQuery.timers.push( timer ); 7990 if ( timer() ) { 7991 jQuery.fx.start(); 7992 } else { 7993 jQuery.timers.pop(); 7994 } 7995}; 7996 7997jQuery.fx.interval = 13; 7998 7999jQuery.fx.start = function() { 8000 if ( !timerId ) { 8001 timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval ); 8002 } 8003}; 8004 8005jQuery.fx.stop = function() { 8006 clearInterval( timerId ); 8007 timerId = null; 8008}; 8009 8010jQuery.fx.speeds = { 8011 slow: 600, 8012 fast: 200, 8013 // Default speed 8014 _default: 400 8015}; 8016 8017// Based off of the plugin by Clint Helfers, with permission. 8018// http://blindsignals.com/index.php/2009/07/jquery-delay/ 8019jQuery.fn.delay = function( time, type ) { 8020 time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; 8021 type = type || "fx"; 8022 8023 return this.queue( type, function( next, hooks ) { 8024 var timeout = setTimeout( next, time ); 8025 hooks.stop = function() { 8026 clearTimeout( timeout ); 8027 }; 8028 }); 8029}; 8030 8031(function() { 8032 // Minified: var a,b,c,d,e 8033 var input, div, select, a, opt; 8034 8035 // Setup 8036 div = document.createElement( "div" ); 8037 div.setAttribute( "className", "t" ); 8038 div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>"; 8039 a = div.getElementsByTagName("a")[ 0 ]; 8040 8041 // First batch of tests. 8042 select = document.createElement("select"); 8043 opt = select.appendChild( document.createElement("option") ); 8044 input = div.getElementsByTagName("input")[ 0 ]; 8045 8046 a.style.cssText = "top:1px"; 8047 8048 // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) 8049 support.getSetAttribute = div.className !== "t"; 8050 8051 // Get the style information from getAttribute 8052 // (IE uses .cssText instead) 8053 support.style = /top/.test( a.getAttribute("style") ); 8054 8055 // Make sure that URLs aren't manipulated 8056 // (IE normalizes it by default) 8057 support.hrefNormalized = a.getAttribute("href") === "/a"; 8058 8059 // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere) 8060 support.checkOn = !!input.value; 8061 8062 // Make sure that a selected-by-default option has a working selected property. 8063 // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) 8064 support.optSelected = opt.selected; 8065 8066 // Tests for enctype support on a form (#6743) 8067 support.enctype = !!document.createElement("form").enctype; 8068 8069 // Make sure that the options inside disabled selects aren't marked as disabled 8070 // (WebKit marks them as disabled) 8071 select.disabled = true; 8072 support.optDisabled = !opt.disabled; 8073 8074 // Support: IE8 only 8075 // Check if we can trust getAttribute("value") 8076 input = document.createElement( "input" ); 8077 input.setAttribute( "value", "" ); 8078 support.input = input.getAttribute( "value" ) === ""; 8079 8080 // Check if an input maintains its value after becoming a radio 8081 input.value = "t"; 8082 input.setAttribute( "type", "radio" ); 8083 support.radioValue = input.value === "t"; 8084})(); 8085 8086var rreturn = /\r/g; 8087 8088jQuery.fn.extend({ 8089 val: function( value ) { 8090 var hooks, ret, isFunction, 8091 elem = this[0]; 8092 8093 if ( !arguments.length ) { 8094 if ( elem ) { 8095 hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; 8096 8097 if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { 8098 return ret; 8099 } 8100 8101 ret = elem.value; 8102 8103 return typeof ret === "string" ? 8104 // handle most common string cases 8105 ret.replace(rreturn, "") : 8106 // handle cases where value is null/undef or number 8107 ret == null ? "" : ret; 8108 } 8109 8110 return; 8111 } 8112 8113 isFunction = jQuery.isFunction( value ); 8114 8115 return this.each(function( i ) { 8116 var val; 8117 8118 if ( this.nodeType !== 1 ) { 8119 return; 8120 } 8121 8122 if ( isFunction ) { 8123 val = value.call( this, i, jQuery( this ).val() ); 8124 } else { 8125 val = value; 8126 } 8127 8128 // Treat null/undefined as ""; convert numbers to string 8129 if ( val == null ) { 8130 val = ""; 8131 } else if ( typeof val === "number" ) { 8132 val += ""; 8133 } else if ( jQuery.isArray( val ) ) { 8134 val = jQuery.map( val, function( value ) { 8135 return value == null ? "" : value + ""; 8136 }); 8137 } 8138 8139 hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; 8140 8141 // If set returns undefined, fall back to normal setting 8142 if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { 8143 this.value = val; 8144 } 8145 }); 8146 } 8147}); 8148 8149jQuery.extend({ 8150 valHooks: { 8151 option: { 8152 get: function( elem ) { 8153 var val = jQuery.find.attr( elem, "value" ); 8154 return val != null ? 8155 val : 8156 // Support: IE10-11+ 8157 // option.text throws exceptions (#14686, #14858) 8158 jQuery.trim( jQuery.text( elem ) ); 8159 } 8160 }, 8161 select: { 8162 get: function( elem ) { 8163 var value, option, 8164 options = elem.options, 8165 index = elem.selectedIndex, 8166 one = elem.type === "select-one" || index < 0, 8167 values = one ? null : [], 8168 max = one ? index + 1 : options.length, 8169 i = index < 0 ? 8170 max : 8171 one ? index : 0; 8172 8173 // Loop through all the selected options 8174 for ( ; i < max; i++ ) { 8175 option = options[ i ]; 8176 8177 // oldIE doesn't update selected after form reset (#2551) 8178 if ( ( option.selected || i === index ) && 8179 // Don't return options that are disabled or in a disabled optgroup 8180 ( support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) && 8181 ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { 8182 8183 // Get the specific value for the option 8184 value = jQuery( option ).val(); 8185 8186 // We don't need an array for one selects 8187 if ( one ) { 8188 return value; 8189 } 8190 8191 // Multi-Selects return an array 8192 values.push( value ); 8193 } 8194 } 8195 8196 return values; 8197 }, 8198 8199 set: function( elem, value ) { 8200 var optionSet, option, 8201 options = elem.options, 8202 values = jQuery.makeArray( value ), 8203 i = options.length; 8204 8205 while ( i-- ) { 8206 option = options[ i ]; 8207 8208 if ( jQuery.inArray( jQuery.valHooks.option.get( option ), values ) >= 0 ) { 8209 8210 // Support: IE6 8211 // When new option element is added to select box we need to 8212 // force reflow of newly added node in order to workaround delay 8213 // of initialization properties 8214 try { 8215 option.selected = optionSet = true; 8216 8217 } catch ( _ ) { 8218 8219 // Will be executed only in IE6 8220 option.scrollHeight; 8221 } 8222 8223 } else { 8224 option.selected = false; 8225 } 8226 } 8227 8228 // Force browsers to behave consistently when non-matching value is set 8229 if ( !optionSet ) { 8230 elem.selectedIndex = -1; 8231 } 8232 8233 return options; 8234 } 8235 } 8236 } 8237}); 8238 8239// Radios and checkboxes getter/setter 8240jQuery.each([ "radio", "checkbox" ], function() { 8241 jQuery.valHooks[ this ] = { 8242 set: function( elem, value ) { 8243 if ( jQuery.isArray( value ) ) { 8244 return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); 8245 } 8246 } 8247 }; 8248 if ( !support.checkOn ) { 8249 jQuery.valHooks[ this ].get = function( elem ) { 8250 // Support: Webkit 8251 // "" is returned instead of "on" if a value isn't specified 8252 return elem.getAttribute("value") === null ? "on" : elem.value; 8253 }; 8254 } 8255}); 8256 8257var nodeHook, boolHook, 8258 attrHandle = jQuery.expr.attrHandle, 8259 ruseDefault = /^(?:checked|selected)$/i, 8260 getSetAttribute = support.getSetAttribute, 8261 getSetInput = support.input; 8262 8263jQuery.fn.extend({ 8264 attr: function( name, value ) { 8265 return access( this, jQuery.attr, name, value, arguments.length > 1 ); 8266 }, 8267 8268 removeAttr: function( name ) { 8269 return this.each(function() { 8270 jQuery.removeAttr( this, name ); 8271 }); 8272 } 8273}); 8274 8275jQuery.extend({ 8276 attr: function( elem, name, value ) { 8277 var hooks, ret, 8278 nType = elem.nodeType; 8279 8280 // don't get/set attributes on text, comment and attribute nodes 8281 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { 8282 return; 8283 } 8284 8285 // Fallback to prop when attributes are not supported 8286 if ( typeof elem.getAttribute === strundefined ) { 8287 return jQuery.prop( elem, name, value ); 8288 } 8289 8290 // All attributes are lowercase 8291 // Grab necessary hook if one is defined 8292 if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { 8293 name = name.toLowerCase(); 8294 hooks = jQuery.attrHooks[ name ] || 8295 ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook ); 8296 } 8297 8298 if ( value !== undefined ) { 8299 8300 if ( value === null ) { 8301 jQuery.removeAttr( elem, name ); 8302 8303 } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { 8304 return ret; 8305 8306 } else { 8307 elem.setAttribute( name, value + "" ); 8308 return value; 8309 } 8310 8311 } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { 8312 return ret; 8313 8314 } else { 8315 ret = jQuery.find.attr( elem, name ); 8316 8317 // Non-existent attributes return null, we normalize to undefined 8318 return ret == null ? 8319 undefined : 8320 ret; 8321 } 8322 }, 8323 8324 removeAttr: function( elem, value ) { 8325 var name, propName, 8326 i = 0, 8327 attrNames = value && value.match( rnotwhite ); 8328 8329 if ( attrNames && elem.nodeType === 1 ) { 8330 while ( (name = attrNames[i++]) ) { 8331 propName = jQuery.propFix[ name ] || name; 8332 8333 // Boolean attributes get special treatment (#10870) 8334 if ( jQuery.expr.match.bool.test( name ) ) { 8335 // Set corresponding property to false 8336 if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) { 8337 elem[ propName ] = false; 8338 // Support: IE<9 8339 // Also clear defaultChecked/defaultSelected (if appropriate) 8340 } else { 8341 elem[ jQuery.camelCase( "default-" + name ) ] = 8342 elem[ propName ] = false; 8343 } 8344 8345 // See #9699 for explanation of this approach (setting first, then removal) 8346 } else { 8347 jQuery.attr( elem, name, "" ); 8348 } 8349 8350 elem.removeAttribute( getSetAttribute ? name : propName ); 8351 } 8352 } 8353 }, 8354 8355 attrHooks: { 8356 type: { 8357 set: function( elem, value ) { 8358 if ( !support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { 8359 // Setting the type on a radio button after the value resets the value in IE6-9 8360 // Reset value to default in case type is set after value during creation 8361 var val = elem.value; 8362 elem.setAttribute( "type", value ); 8363 if ( val ) { 8364 elem.value = val; 8365 } 8366 return value; 8367 } 8368 } 8369 } 8370 } 8371}); 8372 8373// Hook for boolean attributes 8374boolHook = { 8375 set: function( elem, value, name ) { 8376 if ( value === false ) { 8377 // Remove boolean attributes when set to false 8378 jQuery.removeAttr( elem, name ); 8379 } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) { 8380 // IE<8 needs the *property* name 8381 elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name ); 8382 8383 // Use defaultChecked and defaultSelected for oldIE 8384 } else { 8385 elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true; 8386 } 8387 8388 return name; 8389 } 8390}; 8391 8392// Retrieve booleans specially 8393jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { 8394 8395 var getter = attrHandle[ name ] || jQuery.find.attr; 8396 8397 attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ? 8398 function( elem, name, isXML ) { 8399 var ret, handle; 8400 if ( !isXML ) { 8401 // Avoid an infinite loop by temporarily removing this function from the getter 8402 handle = attrHandle[ name ]; 8403 attrHandle[ name ] = ret; 8404 ret = getter( elem, name, isXML ) != null ? 8405 name.toLowerCase() : 8406 null; 8407 attrHandle[ name ] = handle; 8408 } 8409 return ret; 8410 } : 8411 function( elem, name, isXML ) { 8412 if ( !isXML ) { 8413 return elem[ jQuery.camelCase( "default-" + name ) ] ? 8414 name.toLowerCase() : 8415 null; 8416 } 8417 }; 8418}); 8419 8420// fix oldIE attroperties 8421if ( !getSetInput || !getSetAttribute ) { 8422 jQuery.attrHooks.value = { 8423 set: function( elem, value, name ) { 8424 if ( jQuery.nodeName( elem, "input" ) ) { 8425 // Does not return so that setAttribute is also used 8426 elem.defaultValue = value; 8427 } else { 8428 // Use nodeHook if defined (#1954); otherwise setAttribute is fine 8429 return nodeHook && nodeHook.set( elem, value, name ); 8430 } 8431 } 8432 }; 8433} 8434 8435// IE6/7 do not support getting/setting some attributes with get/setAttribute 8436if ( !getSetAttribute ) { 8437 8438 // Use this for any attribute in IE6/7 8439 // This fixes almost every IE6/7 issue 8440 nodeHook = { 8441 set: function( elem, value, name ) { 8442 // Set the existing or create a new attribute node 8443 var ret = elem.getAttributeNode( name ); 8444 if ( !ret ) { 8445 elem.setAttributeNode( 8446 (ret = elem.ownerDocument.createAttribute( name )) 8447 ); 8448 } 8449 8450 ret.value = value += ""; 8451 8452 // Break association with cloned elements by also using setAttribute (#9646) 8453 if ( name === "value" || value === elem.getAttribute( name ) ) { 8454 return value; 8455 } 8456 } 8457 }; 8458 8459 // Some attributes are constructed with empty-string values when not defined 8460 attrHandle.id = attrHandle.name = attrHandle.coords = 8461 function( elem, name, isXML ) { 8462 var ret; 8463 if ( !isXML ) { 8464 return (ret = elem.getAttributeNode( name )) && ret.value !== "" ? 8465 ret.value : 8466 null; 8467 } 8468 }; 8469 8470 // Fixing value retrieval on a button requires this module 8471 jQuery.valHooks.button = { 8472 get: function( elem, name ) { 8473 var ret = elem.getAttributeNode( name ); 8474 if ( ret && ret.specified ) { 8475 return ret.value; 8476 } 8477 }, 8478 set: nodeHook.set 8479 }; 8480 8481 // Set contenteditable to false on removals(#10429) 8482 // Setting to empty string throws an error as an invalid value 8483 jQuery.attrHooks.contenteditable = { 8484 set: function( elem, value, name ) { 8485 nodeHook.set( elem, value === "" ? false : value, name ); 8486 } 8487 }; 8488 8489 // Set width and height to auto instead of 0 on empty string( Bug #8150 ) 8490 // This is for removals 8491 jQuery.each([ "width", "height" ], function( i, name ) { 8492 jQuery.attrHooks[ name ] = { 8493 set: function( elem, value ) { 8494 if ( value === "" ) { 8495 elem.setAttribute( name, "auto" ); 8496 return value; 8497 } 8498 } 8499 }; 8500 }); 8501} 8502 8503if ( !support.style ) { 8504 jQuery.attrHooks.style = { 8505 get: function( elem ) { 8506 // Return undefined in the case of empty string 8507 // Note: IE uppercases css property names, but if we were to .toLowerCase() 8508 // .cssText, that would destroy case senstitivity in URL's, like in "background" 8509 return elem.style.cssText || undefined; 8510 }, 8511 set: function( elem, value ) { 8512 return ( elem.style.cssText = value + "" ); 8513 } 8514 }; 8515} 8516 8517var rfocusable = /^(?:input|select|textarea|button|object)$/i, 8518 rclickable = /^(?:a|area)$/i; 8519 8520jQuery.fn.extend({ 8521 prop: function( name, value ) { 8522 return access( this, jQuery.prop, name, value, arguments.length > 1 ); 8523 }, 8524 8525 removeProp: function( name ) { 8526 name = jQuery.propFix[ name ] || name; 8527 return this.each(function() { 8528 // try/catch handles cases where IE balks (such as removing a property on window) 8529 try { 8530 this[ name ] = undefined; 8531 delete this[ name ]; 8532 } catch( e ) {} 8533 }); 8534 } 8535}); 8536 8537jQuery.extend({ 8538 propFix: { 8539 "for": "htmlFor", 8540 "class": "className" 8541 }, 8542 8543 prop: function( elem, name, value ) { 8544 var ret, hooks, notxml, 8545 nType = elem.nodeType; 8546 8547 // don't get/set properties on text, comment and attribute nodes 8548 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { 8549 return; 8550 } 8551 8552 notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); 8553 8554 if ( notxml ) { 8555 // Fix name and attach hooks 8556 name = jQuery.propFix[ name ] || name; 8557 hooks = jQuery.propHooks[ name ]; 8558 } 8559 8560 if ( value !== undefined ) { 8561 return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ? 8562 ret : 8563 ( elem[ name ] = value ); 8564 8565 } else { 8566 return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ? 8567 ret : 8568 elem[ name ]; 8569 } 8570 }, 8571 8572 propHooks: { 8573 tabIndex: { 8574 get: function( elem ) { 8575 // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set 8576 // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ 8577 // Use proper attribute retrieval(#12072) 8578 var tabindex = jQuery.find.attr( elem, "tabindex" ); 8579 8580 return tabindex ? 8581 parseInt( tabindex, 10 ) : 8582 rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? 8583 0 : 8584 -1; 8585 } 8586 } 8587 } 8588}); 8589 8590// Some attributes require a special call on IE 8591// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx 8592if ( !support.hrefNormalized ) { 8593 // href/src property should get the full normalized URL (#10299/#12915) 8594 jQuery.each([ "href", "src" ], function( i, name ) { 8595 jQuery.propHooks[ name ] = { 8596 get: function( elem ) { 8597 return elem.getAttribute( name, 4 ); 8598 } 8599 }; 8600 }); 8601} 8602 8603// Support: Safari, IE9+ 8604// mis-reports the default selected property of an option 8605// Accessing the parent's selectedIndex property fixes it 8606if ( !support.optSelected ) { 8607 jQuery.propHooks.selected = { 8608 get: function( elem ) { 8609 var parent = elem.parentNode; 8610 8611 if ( parent ) { 8612 parent.selectedIndex; 8613 8614 // Make sure that it also works with optgroups, see #5701 8615 if ( parent.parentNode ) { 8616 parent.parentNode.selectedIndex; 8617 } 8618 } 8619 return null; 8620 } 8621 }; 8622} 8623 8624jQuery.each([ 8625 "tabIndex", 8626 "readOnly", 8627 "maxLength", 8628 "cellSpacing", 8629 "cellPadding", 8630 "rowSpan", 8631 "colSpan", 8632 "useMap", 8633 "frameBorder", 8634 "contentEditable" 8635], function() { 8636 jQuery.propFix[ this.toLowerCase() ] = this; 8637}); 8638 8639// IE6/7 call enctype encoding 8640if ( !support.enctype ) { 8641 jQuery.propFix.enctype = "encoding"; 8642} 8643 8644var rclass = /[\t\r\n\f]/g; 8645 8646jQuery.fn.extend({ 8647 addClass: function( value ) { 8648 var classes, elem, cur, clazz, j, finalValue, 8649 i = 0, 8650 len = this.length, 8651 proceed = typeof value === "string" && value; 8652 8653 if ( jQuery.isFunction( value ) ) { 8654 return this.each(function( j ) { 8655 jQuery( this ).addClass( value.call( this, j, this.className ) ); 8656 }); 8657 } 8658 8659 if ( proceed ) { 8660 // The disjunction here is for better compressibility (see removeClass) 8661 classes = ( value || "" ).match( rnotwhite ) || []; 8662 8663 for ( ; i < len; i++ ) { 8664 elem = this[ i ]; 8665 cur = elem.nodeType === 1 && ( elem.className ? 8666 ( " " + elem.className + " " ).replace( rclass, " " ) : 8667 " " 8668 ); 8669 8670 if ( cur ) { 8671 j = 0; 8672 while ( (clazz = classes[j++]) ) { 8673 if ( cur.indexOf( " " + clazz + " " ) < 0 ) { 8674 cur += clazz + " "; 8675 } 8676 } 8677 8678 // only assign if different to avoid unneeded rendering. 8679 finalValue = jQuery.trim( cur ); 8680 if ( elem.className !== finalValue ) { 8681 elem.className = finalValue; 8682 } 8683 } 8684 } 8685 } 8686 8687 return this; 8688 }, 8689 8690 removeClass: function( value ) { 8691 var classes, elem, cur, clazz, j, finalValue, 8692 i = 0, 8693 len = this.length, 8694 proceed = arguments.length === 0 || typeof value === "string" && value; 8695 8696 if ( jQuery.isFunction( value ) ) { 8697 return this.each(function( j ) { 8698 jQuery( this ).removeClass( value.call( this, j, this.className ) ); 8699 }); 8700 } 8701 if ( proceed ) { 8702 classes = ( value || "" ).match( rnotwhite ) || []; 8703 8704 for ( ; i < len; i++ ) { 8705 elem = this[ i ]; 8706 // This expression is here for better compressibility (see addClass) 8707 cur = elem.nodeType === 1 && ( elem.className ? 8708 ( " " + elem.className + " " ).replace( rclass, " " ) : 8709 "" 8710 ); 8711 8712 if ( cur ) { 8713 j = 0; 8714 while ( (clazz = classes[j++]) ) { 8715 // Remove *all* instances 8716 while ( cur.indexOf( " " + clazz + " " ) >= 0 ) { 8717 cur = cur.replace( " " + clazz + " ", " " ); 8718 } 8719 } 8720 8721 // only assign if different to avoid unneeded rendering. 8722 finalValue = value ? jQuery.trim( cur ) : ""; 8723 if ( elem.className !== finalValue ) { 8724 elem.className = finalValue; 8725 } 8726 } 8727 } 8728 } 8729 8730 return this; 8731 }, 8732 8733 toggleClass: function( value, stateVal ) { 8734 var type = typeof value; 8735 8736 if ( typeof stateVal === "boolean" && type === "string" ) { 8737 return stateVal ? this.addClass( value ) : this.removeClass( value ); 8738 } 8739 8740 if ( jQuery.isFunction( value ) ) { 8741 return this.each(function( i ) { 8742 jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); 8743 }); 8744 } 8745 8746 return this.each(function() { 8747 if ( type === "string" ) { 8748 // toggle individual class names 8749 var className, 8750 i = 0, 8751 self = jQuery( this ), 8752 classNames = value.match( rnotwhite ) || []; 8753 8754 while ( (className = classNames[ i++ ]) ) { 8755 // check each className given, space separated list 8756 if ( self.hasClass( className ) ) { 8757 self.removeClass( className ); 8758 } else { 8759 self.addClass( className ); 8760 } 8761 } 8762 8763 // Toggle whole class name 8764 } else if ( type === strundefined || type === "boolean" ) { 8765 if ( this.className ) { 8766 // store className if set 8767 jQuery._data( this, "__className__", this.className ); 8768 } 8769 8770 // If the element has a class name or if we're passed "false", 8771 // then remove the whole classname (if there was one, the above saved it). 8772 // Otherwise bring back whatever was previously saved (if anything), 8773 // falling back to the empty string if nothing was stored. 8774 this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; 8775 } 8776 }); 8777 }, 8778 8779 hasClass: function( selector ) { 8780 var className = " " + selector + " ", 8781 i = 0, 8782 l = this.length; 8783 for ( ; i < l; i++ ) { 8784 if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) { 8785 return true; 8786 } 8787 } 8788 8789 return false; 8790 } 8791}); 8792 8793// Return jQuery for attributes-only inclusion 8794 8795jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + 8796 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + 8797 "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { 8798 8799 // Handle event binding 8800 jQuery.fn[ name ] = function( data, fn ) { 8801 return arguments.length > 0 ? 8802 this.on( name, null, data, fn ) : 8803 this.trigger( name ); 8804 }; 8805}); 8806 8807jQuery.fn.extend({ 8808 hover: function( fnOver, fnOut ) { 8809 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); 8810 }, 8811 8812 bind: function( types, data, fn ) { 8813 return this.on( types, null, data, fn ); 8814 }, 8815 unbind: function( types, fn ) { 8816 return this.off( types, null, fn ); 8817 }, 8818 8819 delegate: function( selector, types, data, fn ) { 8820 return this.on( types, selector, data, fn ); 8821 }, 8822 undelegate: function( selector, types, fn ) { 8823 // ( namespace ) or ( selector, types [, fn] ) 8824 return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); 8825 } 8826}); 8827 8828var nonce = jQuery.now(); 8829 8830var rquery = (/\?/); 8831 8832var rvalidtokens = /(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g; 8833 8834jQuery.parseJSON = function( data ) { 8835 // Attempt to parse using the native JSON parser first 8836 if ( window.JSON && window.JSON.parse ) { 8837 // Support: Android 2.3 8838 // Workaround failure to string-cast null input 8839 return window.JSON.parse( data + "" ); 8840 } 8841 8842 var requireNonComma, 8843 depth = null, 8844 str = jQuery.trim( data + "" ); 8845 8846 // Guard against invalid (and possibly dangerous) input by ensuring that nothing remains 8847 // after removing valid tokens 8848 return str && !jQuery.trim( str.replace( rvalidtokens, function( token, comma, open, close ) { 8849 8850 // Force termination if we see a misplaced comma 8851 if ( requireNonComma && comma ) { 8852 depth = 0; 8853 } 8854 8855 // Perform no more replacements after returning to outermost depth 8856 if ( depth === 0 ) { 8857 return token; 8858 } 8859 8860 // Commas must not follow "[", "{", or "," 8861 requireNonComma = open || comma; 8862 8863 // Determine new depth 8864 // array/object open ("[" or "{"): depth += true - false (increment) 8865 // array/object close ("]" or "}"): depth += false - true (decrement) 8866 // other cases ("," or primitive): depth += true - true (numeric cast) 8867 depth += !close - !open; 8868 8869 // Remove this token 8870 return ""; 8871 }) ) ? 8872 ( Function( "return " + str ) )() : 8873 jQuery.error( "Invalid JSON: " + data ); 8874}; 8875 8876// Cross-browser xml parsing 8877jQuery.parseXML = function( data ) { 8878 var xml, tmp; 8879 if ( !data || typeof data !== "string" ) { 8880 return null; 8881 } 8882 try { 8883 if ( window.DOMParser ) { // Standard 8884 tmp = new DOMParser(); 8885 xml = tmp.parseFromString( data, "text/xml" ); 8886 } else { // IE 8887 xml = new ActiveXObject( "Microsoft.XMLDOM" ); 8888 xml.async = "false"; 8889 xml.loadXML( data ); 8890 } 8891 } catch( e ) { 8892 xml = undefined; 8893 } 8894 if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { 8895 jQuery.error( "Invalid XML: " + data ); 8896 } 8897 return xml; 8898}; 8899 8900var 8901 // Document location 8902 ajaxLocParts, 8903 ajaxLocation, 8904 8905 rhash = /#.*$/, 8906 rts = /([?&])_=[^&]*/, 8907 rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL 8908 // #7653, #8125, #8152: local protocol detection 8909 rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, 8910 rnoContent = /^(?:GET|HEAD)$/, 8911 rprotocol = /^\/\//, 8912 rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/, 8913 8914 /* Prefilters 8915 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) 8916 * 2) These are called: 8917 * - BEFORE asking for a transport 8918 * - AFTER param serialization (s.data is a string if s.processData is true) 8919 * 3) key is the dataType 8920 * 4) the catchall symbol "*" can be used 8921 * 5) execution will start with transport dataType and THEN continue down to "*" if needed 8922 */ 8923 prefilters = {}, 8924 8925 /* Transports bindings 8926 * 1) key is the dataType 8927 * 2) the catchall symbol "*" can be used 8928 * 3) selection will start with transport dataType and THEN go to "*" if needed 8929 */ 8930 transports = {}, 8931 8932 // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression 8933 allTypes = "*/".concat("*"); 8934 8935// #8138, IE may throw an exception when accessing 8936// a field from window.location if document.domain has been set 8937try { 8938 ajaxLocation = location.href; 8939} catch( e ) { 8940 // Use the href attribute of an A element 8941 // since IE will modify it given document.location 8942 ajaxLocation = document.createElement( "a" ); 8943 ajaxLocation.href = ""; 8944 ajaxLocation = ajaxLocation.href; 8945} 8946 8947// Segment location into parts 8948ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; 8949 8950// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport 8951function addToPrefiltersOrTransports( structure ) { 8952 8953 // dataTypeExpression is optional and defaults to "*" 8954 return function( dataTypeExpression, func ) { 8955 8956 if ( typeof dataTypeExpression !== "string" ) { 8957 func = dataTypeExpression; 8958 dataTypeExpression = "*"; 8959 } 8960 8961 var dataType, 8962 i = 0, 8963 dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || []; 8964 8965 if ( jQuery.isFunction( func ) ) { 8966 // For each dataType in the dataTypeExpression 8967 while ( (dataType = dataTypes[i++]) ) { 8968 // Prepend if requested 8969 if ( dataType.charAt( 0 ) === "+" ) { 8970 dataType = dataType.slice( 1 ) || "*"; 8971 (structure[ dataType ] = structure[ dataType ] || []).unshift( func ); 8972 8973 // Otherwise append 8974 } else { 8975 (structure[ dataType ] = structure[ dataType ] || []).push( func ); 8976 } 8977 } 8978 } 8979 }; 8980} 8981 8982// Base inspection function for prefilters and transports 8983function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { 8984 8985 var inspected = {}, 8986 seekingTransport = ( structure === transports ); 8987 8988 function inspect( dataType ) { 8989 var selected; 8990 inspected[ dataType ] = true; 8991 jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { 8992 var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); 8993 if ( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) { 8994 options.dataTypes.unshift( dataTypeOrTransport ); 8995 inspect( dataTypeOrTransport ); 8996 return false; 8997 } else if ( seekingTransport ) { 8998 return !( selected = dataTypeOrTransport ); 8999 } 9000 }); 9001 return selected; 9002 } 9003 9004 return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); 9005} 9006 9007// A special extend for ajax options 9008// that takes "flat" options (not to be deep extended) 9009// Fixes #9887 9010function ajaxExtend( target, src ) { 9011 var deep, key, 9012 flatOptions = jQuery.ajaxSettings.flatOptions || {}; 9013 9014 for ( key in src ) { 9015 if ( src[ key ] !== undefined ) { 9016 ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ]; 9017 } 9018 } 9019 if ( deep ) { 9020 jQuery.extend( true, target, deep ); 9021 } 9022 9023 return target; 9024} 9025 9026/* Handles responses to an ajax request: 9027 * - finds the right dataType (mediates between content-type and expected dataType) 9028 * - returns the corresponding response 9029 */ 9030function ajaxHandleResponses( s, jqXHR, responses ) { 9031 var firstDataType, ct, finalDataType, type, 9032 contents = s.contents, 9033 dataTypes = s.dataTypes; 9034 9035 // Remove auto dataType and get content-type in the process 9036 while ( dataTypes[ 0 ] === "*" ) { 9037 dataTypes.shift(); 9038 if ( ct === undefined ) { 9039 ct = s.mimeType || jqXHR.getResponseHeader("Content-Type"); 9040 } 9041 } 9042 9043 // Check if we're dealing with a known content-type 9044 if ( ct ) { 9045 for ( type in contents ) { 9046 if ( contents[ type ] && contents[ type ].test( ct ) ) { 9047 dataTypes.unshift( type ); 9048 break; 9049 } 9050 } 9051 } 9052 9053 // Check to see if we have a response for the expected dataType 9054 if ( dataTypes[ 0 ] in responses ) { 9055 finalDataType = dataTypes[ 0 ]; 9056 } else { 9057 // Try convertible dataTypes 9058 for ( type in responses ) { 9059 if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) { 9060 finalDataType = type; 9061 break; 9062 } 9063 if ( !firstDataType ) { 9064 firstDataType = type; 9065 } 9066 } 9067 // Or just use first one 9068 finalDataType = finalDataType || firstDataType; 9069 } 9070 9071 // If we found a dataType 9072 // We add the dataType to the list if needed 9073 // and return the corresponding response 9074 if ( finalDataType ) { 9075 if ( finalDataType !== dataTypes[ 0 ] ) { 9076 dataTypes.unshift( finalDataType ); 9077 } 9078 return responses[ finalDataType ]; 9079 } 9080} 9081 9082/* Chain conversions given the request and the original response 9083 * Also sets the responseXXX fields on the jqXHR instance 9084 */ 9085function ajaxConvert( s, response, jqXHR, isSuccess ) { 9086 var conv2, current, conv, tmp, prev, 9087 converters = {}, 9088 // Work with a copy of dataTypes in case we need to modify it for conversion 9089 dataTypes = s.dataTypes.slice(); 9090 9091 // Create converters map with lowercased keys 9092 if ( dataTypes[ 1 ] ) { 9093 for ( conv in s.converters ) { 9094 converters[ conv.toLowerCase() ] = s.converters[ conv ]; 9095 } 9096 } 9097 9098 current = dataTypes.shift(); 9099 9100 // Convert to each sequential dataType 9101 while ( current ) { 9102 9103 if ( s.responseFields[ current ] ) { 9104 jqXHR[ s.responseFields[ current ] ] = response; 9105 } 9106 9107 // Apply the dataFilter if provided 9108 if ( !prev && isSuccess && s.dataFilter ) { 9109 response = s.dataFilter( response, s.dataType ); 9110 } 9111 9112 prev = current; 9113 current = dataTypes.shift(); 9114 9115 if ( current ) { 9116 9117 // There's only work to do if current dataType is non-auto 9118 if ( current === "*" ) { 9119 9120 current = prev; 9121 9122 // Convert response if prev dataType is non-auto and differs from current 9123 } else if ( prev !== "*" && prev !== current ) { 9124 9125 // Seek a direct converter 9126 conv = converters[ prev + " " + current ] || converters[ "* " + current ]; 9127 9128 // If none found, seek a pair 9129 if ( !conv ) { 9130 for ( conv2 in converters ) { 9131 9132 // If conv2 outputs current 9133 tmp = conv2.split( " " ); 9134 if ( tmp[ 1 ] === current ) { 9135 9136 // If prev can be converted to accepted input 9137 conv = converters[ prev + " " + tmp[ 0 ] ] || 9138 converters[ "* " + tmp[ 0 ] ]; 9139 if ( conv ) { 9140 // Condense equivalence converters 9141 if ( conv === true ) { 9142 conv = converters[ conv2 ]; 9143 9144 // Otherwise, insert the intermediate dataType 9145 } else if ( converters[ conv2 ] !== true ) { 9146 current = tmp[ 0 ]; 9147 dataTypes.unshift( tmp[ 1 ] ); 9148 } 9149 break; 9150 } 9151 } 9152 } 9153 } 9154 9155 // Apply converter (if not an equivalence) 9156 if ( conv !== true ) { 9157 9158 // Unless errors are allowed to bubble, catch and return them 9159 if ( conv && s[ "throws" ] ) { 9160 response = conv( response ); 9161 } else { 9162 try { 9163 response = conv( response ); 9164 } catch ( e ) { 9165 return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current }; 9166 } 9167 } 9168 } 9169 } 9170 } 9171 } 9172 9173 return { state: "success", data: response }; 9174} 9175 9176jQuery.extend({ 9177 9178 // Counter for holding the number of active queries 9179 active: 0, 9180 9181 // Last-Modified header cache for next request 9182 lastModified: {}, 9183 etag: {}, 9184 9185 ajaxSettings: { 9186 url: ajaxLocation, 9187 type: "GET", 9188 isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ), 9189 global: true, 9190 processData: true, 9191 async: true, 9192 contentType: "application/x-www-form-urlencoded; charset=UTF-8", 9193 /* 9194 timeout: 0, 9195 data: null, 9196 dataType: null, 9197 username: null, 9198 password: null, 9199 cache: null, 9200 throws: false, 9201 traditional: false, 9202 headers: {}, 9203 */ 9204 9205 accepts: { 9206 "*": allTypes, 9207 text: "text/plain", 9208 html: "text/html", 9209 xml: "application/xml, text/xml", 9210 json: "application/json, text/javascript" 9211 }, 9212 9213 contents: { 9214 xml: /xml/, 9215 html: /html/, 9216 json: /json/ 9217 }, 9218 9219 responseFields: { 9220 xml: "responseXML", 9221 text: "responseText", 9222 json: "responseJSON" 9223 }, 9224 9225 // Data converters 9226 // Keys separate source (or catchall "*") and destination types with a single space 9227 converters: { 9228 9229 // Convert anything to text 9230 "* text": String, 9231 9232 // Text to html (true = no transformation) 9233 "text html": true, 9234 9235 // Evaluate text as a json expression 9236 "text json": jQuery.parseJSON, 9237 9238 // Parse text as xml 9239 "text xml": jQuery.parseXML 9240 }, 9241 9242 // For options that shouldn't be deep extended: 9243 // you can add your own custom options here if 9244 // and when you create one that shouldn't be 9245 // deep extended (see ajaxExtend) 9246 flatOptions: { 9247 url: true, 9248 context: true 9249 } 9250 }, 9251 9252 // Creates a full fledged settings object into target 9253 // with both ajaxSettings and settings fields. 9254 // If target is omitted, writes into ajaxSettings. 9255 ajaxSetup: function( target, settings ) { 9256 return settings ? 9257 9258 // Building a settings object 9259 ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : 9260 9261 // Extending ajaxSettings 9262 ajaxExtend( jQuery.ajaxSettings, target ); 9263 }, 9264 9265 ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), 9266 ajaxTransport: addToPrefiltersOrTransports( transports ), 9267 9268 // Main method 9269 ajax: function( url, options ) { 9270 9271 // If url is an object, simulate pre-1.5 signature 9272 if ( typeof url === "object" ) { 9273 options = url; 9274 url = undefined; 9275 } 9276 9277 // Force options to be an object 9278 options = options || {}; 9279 9280 var // Cross-domain detection vars 9281 parts, 9282 // Loop variable 9283 i, 9284 // URL without anti-cache param 9285 cacheURL, 9286 // Response headers as string 9287 responseHeadersString, 9288 // timeout handle 9289 timeoutTimer, 9290 9291 // To know if global events are to be dispatched 9292 fireGlobals, 9293 9294 transport, 9295 // Response headers 9296 responseHeaders, 9297 // Create the final options object 9298 s = jQuery.ajaxSetup( {}, options ), 9299 // Callbacks context 9300 callbackContext = s.context || s, 9301 // Context for global events is callbackContext if it is a DOM node or jQuery collection 9302 globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ? 9303 jQuery( callbackContext ) : 9304 jQuery.event, 9305 // Deferreds 9306 deferred = jQuery.Deferred(), 9307 completeDeferred = jQuery.Callbacks("once memory"), 9308 // Status-dependent callbacks 9309 statusCode = s.statusCode || {}, 9310 // Headers (they are sent all at once) 9311 requestHeaders = {}, 9312 requestHeadersNames = {}, 9313 // The jqXHR state 9314 state = 0, 9315 // Default abort message 9316 strAbort = "canceled", 9317 // Fake xhr 9318 jqXHR = { 9319 readyState: 0, 9320 9321 // Builds headers hashtable if needed 9322 getResponseHeader: function( key ) { 9323 var match; 9324 if ( state === 2 ) { 9325 if ( !responseHeaders ) { 9326 responseHeaders = {}; 9327 while ( (match = rheaders.exec( responseHeadersString )) ) { 9328 responseHeaders[ match[1].toLowerCase() ] = match[ 2 ]; 9329 } 9330 } 9331 match = responseHeaders[ key.toLowerCase() ]; 9332 } 9333 return match == null ? null : match; 9334 }, 9335 9336 // Raw string 9337 getAllResponseHeaders: function() { 9338 return state === 2 ? responseHeadersString : null; 9339 }, 9340 9341 // Caches the header 9342 setRequestHeader: function( name, value ) { 9343 var lname = name.toLowerCase(); 9344 if ( !state ) { 9345 name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; 9346 requestHeaders[ name ] = value; 9347 } 9348 return this; 9349 }, 9350 9351 // Overrides response content-type header 9352 overrideMimeType: function( type ) { 9353 if ( !state ) { 9354 s.mimeType = type; 9355 } 9356 return this; 9357 }, 9358 9359 // Status-dependent callbacks 9360 statusCode: function( map ) { 9361 var code; 9362 if ( map ) { 9363 if ( state < 2 ) { 9364 for ( code in map ) { 9365 // Lazy-add the new callback in a way that preserves old ones 9366 statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; 9367 } 9368 } else { 9369 // Execute the appropriate callbacks 9370 jqXHR.always( map[ jqXHR.status ] ); 9371 } 9372 } 9373 return this; 9374 }, 9375 9376 // Cancel the request 9377 abort: function( statusText ) { 9378 var finalText = statusText || strAbort; 9379 if ( transport ) { 9380 transport.abort( finalText ); 9381 } 9382 done( 0, finalText ); 9383 return this; 9384 } 9385 }; 9386 9387 // Attach deferreds 9388 deferred.promise( jqXHR ).complete = completeDeferred.add; 9389 jqXHR.success = jqXHR.done; 9390 jqXHR.error = jqXHR.fail; 9391 9392 // Remove hash character (#7531: and string promotion) 9393 // Add protocol if not provided (#5866: IE7 issue with protocol-less urls) 9394 // Handle falsy url in the settings object (#10093: consistency with old signature) 9395 // We also use the url parameter if available 9396 s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" ); 9397 9398 // Alias method option to type as per ticket #12004 9399 s.type = options.method || options.type || s.method || s.type; 9400 9401 // Extract dataTypes list 9402 s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ]; 9403 9404 // A cross-domain request is in order when we have a protocol:host:port mismatch 9405 if ( s.crossDomain == null ) { 9406 parts = rurl.exec( s.url.toLowerCase() ); 9407 s.crossDomain = !!( parts && 9408 ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] || 9409 ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !== 9410 ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) ) 9411 ); 9412 } 9413 9414 // Convert data if not already a string 9415 if ( s.data && s.processData && typeof s.data !== "string" ) { 9416 s.data = jQuery.param( s.data, s.traditional ); 9417 } 9418 9419 // Apply prefilters 9420 inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); 9421 9422 // If request was aborted inside a prefilter, stop there 9423 if ( state === 2 ) { 9424 return jqXHR; 9425 } 9426 9427 // We can fire global events as of now if asked to 9428 fireGlobals = s.global; 9429 9430 // Watch for a new set of requests 9431 if ( fireGlobals && jQuery.active++ === 0 ) { 9432 jQuery.event.trigger("ajaxStart"); 9433 } 9434 9435 // Uppercase the type 9436 s.type = s.type.toUpperCase(); 9437 9438 // Determine if request has content 9439 s.hasContent = !rnoContent.test( s.type ); 9440 9441 // Save the URL in case we're toying with the If-Modified-Since 9442 // and/or If-None-Match header later on 9443 cacheURL = s.url; 9444 9445 // More options handling for requests with no content 9446 if ( !s.hasContent ) { 9447 9448 // If data is available, append data to url 9449 if ( s.data ) { 9450 cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data ); 9451 // #9682: remove data so that it's not used in an eventual retry 9452 delete s.data; 9453 } 9454 9455 // Add anti-cache in url if needed 9456 if ( s.cache === false ) { 9457 s.url = rts.test( cacheURL ) ? 9458 9459 // If there is already a '_' parameter, set its value 9460 cacheURL.replace( rts, "$1_=" + nonce++ ) : 9461 9462 // Otherwise add one to the end 9463 cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++; 9464 } 9465 } 9466 9467 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. 9468 if ( s.ifModified ) { 9469 if ( jQuery.lastModified[ cacheURL ] ) { 9470 jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); 9471 } 9472 if ( jQuery.etag[ cacheURL ] ) { 9473 jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); 9474 } 9475 } 9476 9477 // Set the correct header, if data is being sent 9478 if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { 9479 jqXHR.setRequestHeader( "Content-Type", s.contentType ); 9480 } 9481 9482 // Set the Accepts header for the server, depending on the dataType 9483 jqXHR.setRequestHeader( 9484 "Accept", 9485 s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? 9486 s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : 9487 s.accepts[ "*" ] 9488 ); 9489 9490 // Check for headers option 9491 for ( i in s.headers ) { 9492 jqXHR.setRequestHeader( i, s.headers[ i ] ); 9493 } 9494 9495 // Allow custom headers/mimetypes and early abort 9496 if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) { 9497 // Abort if not done already and return 9498 return jqXHR.abort(); 9499 } 9500 9501 // aborting is no longer a cancellation 9502 strAbort = "abort"; 9503 9504 // Install callbacks on deferreds 9505 for ( i in { success: 1, error: 1, complete: 1 } ) { 9506 jqXHR[ i ]( s[ i ] ); 9507 } 9508 9509 // Get transport 9510 transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); 9511 9512 // If no transport, we auto-abort 9513 if ( !transport ) { 9514 done( -1, "No Transport" ); 9515 } else { 9516 jqXHR.readyState = 1; 9517 9518 // Send global event 9519 if ( fireGlobals ) { 9520 globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); 9521 } 9522 // Timeout 9523 if ( s.async && s.timeout > 0 ) { 9524 timeoutTimer = setTimeout(function() { 9525 jqXHR.abort("timeout"); 9526 }, s.timeout ); 9527 } 9528 9529 try { 9530 state = 1; 9531 transport.send( requestHeaders, done ); 9532 } catch ( e ) { 9533 // Propagate exception as error if not done 9534 if ( state < 2 ) { 9535 done( -1, e ); 9536 // Simply rethrow otherwise 9537 } else { 9538 throw e; 9539 } 9540 } 9541 } 9542 9543 // Callback for when everything is done 9544 function done( status, nativeStatusText, responses, headers ) { 9545 var isSuccess, success, error, response, modified, 9546 statusText = nativeStatusText; 9547 9548 // Called once 9549 if ( state === 2 ) { 9550 return; 9551 } 9552 9553 // State is "done" now 9554 state = 2; 9555 9556 // Clear timeout if it exists 9557 if ( timeoutTimer ) { 9558 clearTimeout( timeoutTimer ); 9559 } 9560 9561 // Dereference transport for early garbage collection 9562 // (no matter how long the jqXHR object will be used) 9563 transport = undefined; 9564 9565 // Cache response headers 9566 responseHeadersString = headers || ""; 9567 9568 // Set readyState 9569 jqXHR.readyState = status > 0 ? 4 : 0; 9570 9571 // Determine if successful 9572 isSuccess = status >= 200 && status < 300 || status === 304; 9573 9574 // Get response data 9575 if ( responses ) { 9576 response = ajaxHandleResponses( s, jqXHR, responses ); 9577 } 9578 9579 // Convert no matter what (that way responseXXX fields are always set) 9580 response = ajaxConvert( s, response, jqXHR, isSuccess ); 9581 9582 // If successful, handle type chaining 9583 if ( isSuccess ) { 9584 9585 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. 9586 if ( s.ifModified ) { 9587 modified = jqXHR.getResponseHeader("Last-Modified"); 9588 if ( modified ) { 9589 jQuery.lastModified[ cacheURL ] = modified; 9590 } 9591 modified = jqXHR.getResponseHeader("etag"); 9592 if ( modified ) { 9593 jQuery.etag[ cacheURL ] = modified; 9594 } 9595 } 9596 9597 // if no content 9598 if ( status === 204 || s.type === "HEAD" ) { 9599 statusText = "nocontent"; 9600 9601 // if not modified 9602 } else if ( status === 304 ) { 9603 statusText = "notmodified"; 9604 9605 // If we have data, let's convert it 9606 } else { 9607 statusText = response.state; 9608 success = response.data; 9609 error = response.error; 9610 isSuccess = !error; 9611 } 9612 } else { 9613 // We extract error from statusText 9614 // then normalize statusText and status for non-aborts 9615 error = statusText; 9616 if ( status || !statusText ) { 9617 statusText = "error"; 9618 if ( status < 0 ) { 9619 status = 0; 9620 } 9621 } 9622 } 9623 9624 // Set data for the fake xhr object 9625 jqXHR.status = status; 9626 jqXHR.statusText = ( nativeStatusText || statusText ) + ""; 9627 9628 // Success/Error 9629 if ( isSuccess ) { 9630 deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); 9631 } else { 9632 deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); 9633 } 9634 9635 // Status-dependent callbacks 9636 jqXHR.statusCode( statusCode ); 9637 statusCode = undefined; 9638 9639 if ( fireGlobals ) { 9640 globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", 9641 [ jqXHR, s, isSuccess ? success : error ] ); 9642 } 9643 9644 // Complete 9645 completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); 9646 9647 if ( fireGlobals ) { 9648 globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); 9649 // Handle the global AJAX counter 9650 if ( !( --jQuery.active ) ) { 9651 jQuery.event.trigger("ajaxStop"); 9652 } 9653 } 9654 } 9655 9656 return jqXHR; 9657 }, 9658 9659 getJSON: function( url, data, callback ) { 9660 return jQuery.get( url, data, callback, "json" ); 9661 }, 9662 9663 getScript: function( url, callback ) { 9664 return jQuery.get( url, undefined, callback, "script" ); 9665 } 9666}); 9667 9668jQuery.each( [ "get", "post" ], function( i, method ) { 9669 jQuery[ method ] = function( url, data, callback, type ) { 9670 // shift arguments if data argument was omitted 9671 if ( jQuery.isFunction( data ) ) { 9672 type = type || callback; 9673 callback = data; 9674 data = undefined; 9675 } 9676 9677 return jQuery.ajax({ 9678 url: url, 9679 type: method, 9680 dataType: type, 9681 data: data, 9682 success: callback 9683 }); 9684 }; 9685}); 9686 9687// Attach a bunch of functions for handling common AJAX events 9688jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) { 9689 jQuery.fn[ type ] = function( fn ) { 9690 return this.on( type, fn ); 9691 }; 9692}); 9693 9694jQuery._evalUrl = function( url ) { 9695 return jQuery.ajax({ 9696 url: url, 9697 type: "GET", 9698 dataType: "script", 9699 async: false, 9700 global: false, 9701 "throws": true 9702 }); 9703}; 9704 9705jQuery.fn.extend({ 9706 wrapAll: function( html ) { 9707 if ( jQuery.isFunction( html ) ) { 9708 return this.each(function(i) { 9709 jQuery(this).wrapAll( html.call(this, i) ); 9710 }); 9711 } 9712 9713 if ( this[0] ) { 9714 // The elements to wrap the target around 9715 var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); 9716 9717 if ( this[0].parentNode ) { 9718 wrap.insertBefore( this[0] ); 9719 } 9720 9721 wrap.map(function() { 9722 var elem = this; 9723 9724 while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { 9725 elem = elem.firstChild; 9726 } 9727 9728 return elem; 9729 }).append( this ); 9730 } 9731 9732 return this; 9733 }, 9734 9735 wrapInner: function( html ) { 9736 if ( jQuery.isFunction( html ) ) { 9737 return this.each(function(i) { 9738 jQuery(this).wrapInner( html.call(this, i) ); 9739 }); 9740 } 9741 9742 return this.each(function() { 9743 var self = jQuery( this ), 9744 contents = self.contents(); 9745 9746 if ( contents.length ) { 9747 contents.wrapAll( html ); 9748 9749 } else { 9750 self.append( html ); 9751 } 9752 }); 9753 }, 9754 9755 wrap: function( html ) { 9756 var isFunction = jQuery.isFunction( html ); 9757 9758 return this.each(function(i) { 9759 jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); 9760 }); 9761 }, 9762 9763 unwrap: function() { 9764 return this.parent().each(function() { 9765 if ( !jQuery.nodeName( this, "body" ) ) { 9766 jQuery( this ).replaceWith( this.childNodes ); 9767 } 9768 }).end(); 9769 } 9770}); 9771 9772jQuery.expr.filters.hidden = function( elem ) { 9773 // Support: Opera <= 12.12 9774 // Opera reports offsetWidths and offsetHeights less than zero on some elements 9775 return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 || 9776 (!support.reliableHiddenOffsets() && 9777 ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none"); 9778}; 9779 9780jQuery.expr.filters.visible = function( elem ) { 9781 return !jQuery.expr.filters.hidden( elem ); 9782}; 9783 9784var r20 = /%20/g, 9785 rbracket = /\[\]$/, 9786 rCRLF = /\r?\n/g, 9787 rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, 9788 rsubmittable = /^(?:input|select|textarea|keygen)/i; 9789 9790function buildParams( prefix, obj, traditional, add ) { 9791 var name; 9792 9793 if ( jQuery.isArray( obj ) ) { 9794 // Serialize array item. 9795 jQuery.each( obj, function( i, v ) { 9796 if ( traditional || rbracket.test( prefix ) ) { 9797 // Treat each array item as a scalar. 9798 add( prefix, v ); 9799 9800 } else { 9801 // Item is non-scalar (array or object), encode its numeric index. 9802 buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); 9803 } 9804 }); 9805 9806 } else if ( !traditional && jQuery.type( obj ) === "object" ) { 9807 // Serialize object item. 9808 for ( name in obj ) { 9809 buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); 9810 } 9811 9812 } else { 9813 // Serialize scalar item. 9814 add( prefix, obj ); 9815 } 9816} 9817 9818// Serialize an array of form elements or a set of 9819// key/values into a query string 9820jQuery.param = function( a, traditional ) { 9821 var prefix, 9822 s = [], 9823 add = function( key, value ) { 9824 // If value is a function, invoke it and return its value 9825 value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); 9826 s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); 9827 }; 9828 9829 // Set traditional to true for jQuery <= 1.3.2 behavior. 9830 if ( traditional === undefined ) { 9831 traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; 9832 } 9833 9834 // If an array was passed in, assume that it is an array of form elements. 9835 if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { 9836 // Serialize the form elements 9837 jQuery.each( a, function() { 9838 add( this.name, this.value ); 9839 }); 9840 9841 } else { 9842 // If traditional, encode the "old" way (the way 1.3.2 or older 9843 // did it), otherwise encode params recursively. 9844 for ( prefix in a ) { 9845 buildParams( prefix, a[ prefix ], traditional, add ); 9846 } 9847 } 9848 9849 // Return the resulting serialization 9850 return s.join( "&" ).replace( r20, "+" ); 9851}; 9852 9853jQuery.fn.extend({ 9854 serialize: function() { 9855 return jQuery.param( this.serializeArray() ); 9856 }, 9857 serializeArray: function() { 9858 return this.map(function() { 9859 // Can add propHook for "elements" to filter or add form elements 9860 var elements = jQuery.prop( this, "elements" ); 9861 return elements ? jQuery.makeArray( elements ) : this; 9862 }) 9863 .filter(function() { 9864 var type = this.type; 9865 // Use .is(":disabled") so that fieldset[disabled] works 9866 return this.name && !jQuery( this ).is( ":disabled" ) && 9867 rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && 9868 ( this.checked || !rcheckableType.test( type ) ); 9869 }) 9870 .map(function( i, elem ) { 9871 var val = jQuery( this ).val(); 9872 9873 return val == null ? 9874 null : 9875 jQuery.isArray( val ) ? 9876 jQuery.map( val, function( val ) { 9877 return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; 9878 }) : 9879 { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; 9880 }).get(); 9881 } 9882}); 9883 9884// Create the request object 9885// (This is still attached to ajaxSettings for backward compatibility) 9886jQuery.ajaxSettings.xhr = window.ActiveXObject !== undefined ? 9887 // Support: IE6+ 9888 function() { 9889 9890 // XHR cannot access local files, always use ActiveX for that case 9891 return !this.isLocal && 9892 9893 // Support: IE7-8 9894 // oldIE XHR does not support non-RFC2616 methods (#13240) 9895 // See http://msdn.microsoft.com/en-us/library/ie/ms536648(v=vs.85).aspx 9896 // and http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9 9897 // Although this check for six methods instead of eight 9898 // since IE also does not support "trace" and "connect" 9899 /^(get|post|head|put|delete|options)$/i.test( this.type ) && 9900 9901 createStandardXHR() || createActiveXHR(); 9902 } : 9903 // For all other browsers, use the standard XMLHttpRequest object 9904 createStandardXHR; 9905 9906var xhrId = 0, 9907 xhrCallbacks = {}, 9908 xhrSupported = jQuery.ajaxSettings.xhr(); 9909 9910// Support: IE<10 9911// Open requests must be manually aborted on unload (#5280) 9912if ( window.ActiveXObject ) { 9913 jQuery( window ).on( "unload", function() { 9914 for ( var key in xhrCallbacks ) { 9915 xhrCallbacks[ key ]( undefined, true ); 9916 } 9917 }); 9918} 9919 9920// Determine support properties 9921support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); 9922xhrSupported = support.ajax = !!xhrSupported; 9923 9924// Create transport if the browser can provide an xhr 9925if ( xhrSupported ) { 9926 9927 jQuery.ajaxTransport(function( options ) { 9928 // Cross domain only allowed if supported through XMLHttpRequest 9929 if ( !options.crossDomain || support.cors ) { 9930 9931 var callback; 9932 9933 return { 9934 send: function( headers, complete ) { 9935 var i, 9936 xhr = options.xhr(), 9937 id = ++xhrId; 9938 9939 // Open the socket 9940 xhr.open( options.type, options.url, options.async, options.username, options.password ); 9941 9942 // Apply custom fields if provided 9943 if ( options.xhrFields ) { 9944 for ( i in options.xhrFields ) { 9945 xhr[ i ] = options.xhrFields[ i ]; 9946 } 9947 } 9948 9949 // Override mime type if needed 9950 if ( options.mimeType && xhr.overrideMimeType ) { 9951 xhr.overrideMimeType( options.mimeType ); 9952 } 9953 9954 // X-Requested-With header 9955 // For cross-domain requests, seeing as conditions for a preflight are 9956 // akin to a jigsaw puzzle, we simply never set it to be sure. 9957 // (it can always be set on a per-request basis or even using ajaxSetup) 9958 // For same-domain requests, won't change header if already provided. 9959 if ( !options.crossDomain && !headers["X-Requested-With"] ) { 9960 headers["X-Requested-With"] = "XMLHttpRequest"; 9961 } 9962 9963 // Set headers 9964 for ( i in headers ) { 9965 // Support: IE<9 9966 // IE's ActiveXObject throws a 'Type Mismatch' exception when setting 9967 // request header to a null-value. 9968 // 9969 // To keep consistent with other XHR implementations, cast the value 9970 // to string and ignore `undefined`. 9971 if ( headers[ i ] !== undefined ) { 9972 xhr.setRequestHeader( i, headers[ i ] + "" ); 9973 } 9974 } 9975 9976 // Do send the request 9977 // This may raise an exception which is actually 9978 // handled in jQuery.ajax (so no try/catch here) 9979 xhr.send( ( options.hasContent && options.data ) || null ); 9980 9981 // Listener 9982 callback = function( _, isAbort ) { 9983 var status, statusText, responses; 9984 9985 // Was never called and is aborted or complete 9986 if ( callback && ( isAbort || xhr.readyState === 4 ) ) { 9987 // Clean up 9988 delete xhrCallbacks[ id ]; 9989 callback = undefined; 9990 xhr.onreadystatechange = jQuery.noop; 9991 9992 // Abort manually if needed 9993 if ( isAbort ) { 9994 if ( xhr.readyState !== 4 ) { 9995 xhr.abort(); 9996 } 9997 } else { 9998 responses = {}; 9999 status = xhr.status; 10000 10001 // Support: IE<10 10002 // Accessing binary-data responseText throws an exception 10003 // (#11426) 10004 if ( typeof xhr.responseText === "string" ) { 10005 responses.text = xhr.responseText; 10006 } 10007 10008 // Firefox throws an exception when accessing 10009 // statusText for faulty cross-domain requests 10010 try { 10011 statusText = xhr.statusText; 10012 } catch( e ) { 10013 // We normalize with Webkit giving an empty statusText 10014 statusText = ""; 10015 } 10016 10017 // Filter status for non standard behaviors 10018 10019 // If the request is local and we have data: assume a success 10020 // (success with no data won't get notified, that's the best we 10021 // can do given current implementations) 10022 if ( !status && options.isLocal && !options.crossDomain ) { 10023 status = responses.text ? 200 : 404; 10024 // IE - #1450: sometimes returns 1223 when it should be 204 10025 } else if ( status === 1223 ) { 10026 status = 204; 10027 } 10028 } 10029 } 10030 10031 // Call complete if needed 10032 if ( responses ) { 10033 complete( status, statusText, responses, xhr.getAllResponseHeaders() ); 10034 } 10035 }; 10036 10037 if ( !options.async ) { 10038 // if we're in sync mode we fire the callback 10039 callback(); 10040 } else if ( xhr.readyState === 4 ) { 10041 // (IE6 & IE7) if it's in cache and has been 10042 // retrieved directly we need to fire the callback 10043 setTimeout( callback ); 10044 } else { 10045 // Add to the list of active xhr callbacks 10046 xhr.onreadystatechange = xhrCallbacks[ id ] = callback; 10047 } 10048 }, 10049 10050 abort: function() { 10051 if ( callback ) { 10052 callback( undefined, true ); 10053 } 10054 } 10055 }; 10056 } 10057 }); 10058} 10059 10060// Functions to create xhrs 10061function createStandardXHR() { 10062 try { 10063 return new window.XMLHttpRequest(); 10064 } catch( e ) {} 10065} 10066 10067function createActiveXHR() { 10068 try { 10069 return new window.ActiveXObject( "Microsoft.XMLHTTP" ); 10070 } catch( e ) {} 10071} 10072 10073// Install script dataType 10074jQuery.ajaxSetup({ 10075 accepts: { 10076 script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" 10077 }, 10078 contents: { 10079 script: /(?:java|ecma)script/ 10080 }, 10081 converters: { 10082 "text script": function( text ) { 10083 jQuery.globalEval( text ); 10084 return text; 10085 } 10086 } 10087}); 10088 10089// Handle cache's special case and global 10090jQuery.ajaxPrefilter( "script", function( s ) { 10091 if ( s.cache === undefined ) { 10092 s.cache = false; 10093 } 10094 if ( s.crossDomain ) { 10095 s.type = "GET"; 10096 s.global = false; 10097 } 10098}); 10099 10100// Bind script tag hack transport 10101jQuery.ajaxTransport( "script", function(s) { 10102 10103 // This transport only deals with cross domain requests 10104 if ( s.crossDomain ) { 10105 10106 var script, 10107 head = document.head || jQuery("head")[0] || document.documentElement; 10108 10109 return { 10110 10111 send: function( _, callback ) { 10112 10113 script = document.createElement("script"); 10114 10115 script.async = true; 10116 10117 if ( s.scriptCharset ) { 10118 script.charset = s.scriptCharset; 10119 } 10120 10121 script.src = s.url; 10122 10123 // Attach handlers for all browsers 10124 script.onload = script.onreadystatechange = function( _, isAbort ) { 10125 10126 if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { 10127 10128 // Handle memory leak in IE 10129 script.onload = script.onreadystatechange = null; 10130 10131 // Remove the script 10132 if ( script.parentNode ) { 10133 script.parentNode.removeChild( script ); 10134 } 10135 10136 // Dereference the script 10137 script = null; 10138 10139 // Callback if not abort 10140 if ( !isAbort ) { 10141 callback( 200, "success" ); 10142 } 10143 } 10144 }; 10145 10146 // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending 10147 // Use native DOM manipulation to avoid our domManip AJAX trickery 10148 head.insertBefore( script, head.firstChild ); 10149 }, 10150 10151 abort: function() { 10152 if ( script ) { 10153 script.onload( undefined, true ); 10154 } 10155 } 10156 }; 10157 } 10158}); 10159 10160var oldCallbacks = [], 10161 rjsonp = /(=)\?(?=&|$)|\?\?/; 10162 10163// Default jsonp settings 10164jQuery.ajaxSetup({ 10165 jsonp: "callback", 10166 jsonpCallback: function() { 10167 var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); 10168 this[ callback ] = true; 10169 return callback; 10170 } 10171}); 10172 10173// Detect, normalize options and install callbacks for jsonp requests 10174jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { 10175 10176 var callbackName, overwritten, responseContainer, 10177 jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ? 10178 "url" : 10179 typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data" 10180 ); 10181 10182 // Handle iff the expected data type is "jsonp" or we have a parameter to set 10183 if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) { 10184 10185 // Get callback name, remembering preexisting value associated with it 10186 callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? 10187 s.jsonpCallback() : 10188 s.jsonpCallback; 10189 10190 // Insert callback into url or form data 10191 if ( jsonProp ) { 10192 s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName ); 10193 } else if ( s.jsonp !== false ) { 10194 s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; 10195 } 10196 10197 // Use data converter to retrieve json after script execution 10198 s.converters["script json"] = function() { 10199 if ( !responseContainer ) { 10200 jQuery.error( callbackName + " was not called" ); 10201 } 10202 return responseContainer[ 0 ]; 10203 }; 10204 10205 // force json dataType 10206 s.dataTypes[ 0 ] = "json"; 10207 10208 // Install callback 10209 overwritten = window[ callbackName ]; 10210 window[ callbackName ] = function() { 10211 responseContainer = arguments; 10212 }; 10213 10214 // Clean-up function (fires after converters) 10215 jqXHR.always(function() { 10216 // Restore preexisting value 10217 window[ callbackName ] = overwritten; 10218 10219 // Save back as free 10220 if ( s[ callbackName ] ) { 10221 // make sure that re-using the options doesn't screw things around 10222 s.jsonpCallback = originalSettings.jsonpCallback; 10223 10224 // save the callback name for future use 10225 oldCallbacks.push( callbackName ); 10226 } 10227 10228 // Call if it was a function and we have a response 10229 if ( responseContainer && jQuery.isFunction( overwritten ) ) { 10230 overwritten( responseContainer[ 0 ] ); 10231 } 10232 10233 responseContainer = overwritten = undefined; 10234 }); 10235 10236 // Delegate to script 10237 return "script"; 10238 } 10239}); 10240 10241// data: string of html 10242// context (optional): If specified, the fragment will be created in this context, defaults to document 10243// keepScripts (optional): If true, will include scripts passed in the html string 10244jQuery.parseHTML = function( data, context, keepScripts ) { 10245 if ( !data || typeof data !== "string" ) { 10246 return null; 10247 } 10248 if ( typeof context === "boolean" ) { 10249 keepScripts = context; 10250 context = false; 10251 } 10252 context = context || document; 10253 10254 var parsed = rsingleTag.exec( data ), 10255 scripts = !keepScripts && []; 10256 10257 // Single tag 10258 if ( parsed ) { 10259 return [ context.createElement( parsed[1] ) ]; 10260 } 10261 10262 parsed = jQuery.buildFragment( [ data ], context, scripts ); 10263 10264 if ( scripts && scripts.length ) { 10265 jQuery( scripts ).remove(); 10266 } 10267 10268 return jQuery.merge( [], parsed.childNodes ); 10269}; 10270 10271// Keep a copy of the old load method 10272var _load = jQuery.fn.load; 10273 10274/** 10275 * Load a url into a page 10276 */ 10277jQuery.fn.load = function( url, params, callback ) { 10278 if ( typeof url !== "string" && _load ) { 10279 return _load.apply( this, arguments ); 10280 } 10281 10282 var selector, response, type, 10283 self = this, 10284 off = url.indexOf(" "); 10285 10286 if ( off >= 0 ) { 10287 selector = jQuery.trim( url.slice( off, url.length ) ); 10288 url = url.slice( 0, off ); 10289 } 10290 10291 // If it's a function 10292 if ( jQuery.isFunction( params ) ) { 10293 10294 // We assume that it's the callback 10295 callback = params; 10296 params = undefined; 10297 10298 // Otherwise, build a param string 10299 } else if ( params && typeof params === "object" ) { 10300 type = "POST"; 10301 } 10302 10303 // If we have elements to modify, make the request 10304 if ( self.length > 0 ) { 10305 jQuery.ajax({ 10306 url: url, 10307 10308 // if "type" variable is undefined, then "GET" method will be used 10309 type: type, 10310 dataType: "html", 10311 data: params 10312 }).done(function( responseText ) { 10313 10314 // Save response for use in complete callback 10315 response = arguments; 10316 10317 self.html( selector ? 10318 10319 // If a selector was specified, locate the right elements in a dummy div 10320 // Exclude scripts to avoid IE 'Permission Denied' errors 10321 jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) : 10322 10323 // Otherwise use the full result 10324 responseText ); 10325 10326 }).complete( callback && function( jqXHR, status ) { 10327 self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] ); 10328 }); 10329 } 10330 10331 return this; 10332}; 10333 10334jQuery.expr.filters.animated = function( elem ) { 10335 return jQuery.grep(jQuery.timers, function( fn ) { 10336 return elem === fn.elem; 10337 }).length; 10338}; 10339 10340var docElem = window.document.documentElement; 10341 10342/** 10343 * Gets a window from an element 10344 */ 10345function getWindow( elem ) { 10346 return jQuery.isWindow( elem ) ? 10347 elem : 10348 elem.nodeType === 9 ? 10349 elem.defaultView || elem.parentWindow : 10350 false; 10351} 10352 10353jQuery.offset = { 10354 setOffset: function( elem, options, i ) { 10355 var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition, 10356 position = jQuery.css( elem, "position" ), 10357 curElem = jQuery( elem ), 10358 props = {}; 10359 10360 // set position first, in-case top/left are set even on static elem 10361 if ( position === "static" ) { 10362 elem.style.position = "relative"; 10363 } 10364 10365 curOffset = curElem.offset(); 10366 curCSSTop = jQuery.css( elem, "top" ); 10367 curCSSLeft = jQuery.css( elem, "left" ); 10368 calculatePosition = ( position === "absolute" || position === "fixed" ) && 10369 jQuery.inArray("auto", [ curCSSTop, curCSSLeft ] ) > -1; 10370 10371 // need to be able to calculate position if either top or left is auto and position is either absolute or fixed 10372 if ( calculatePosition ) { 10373 curPosition = curElem.position(); 10374 curTop = curPosition.top; 10375 curLeft = curPosition.left; 10376 } else { 10377 curTop = parseFloat( curCSSTop ) || 0; 10378 curLeft = parseFloat( curCSSLeft ) || 0; 10379 } 10380 10381 if ( jQuery.isFunction( options ) ) { 10382 options = options.call( elem, i, curOffset ); 10383 } 10384 10385 if ( options.top != null ) { 10386 props.top = ( options.top - curOffset.top ) + curTop; 10387 } 10388 if ( options.left != null ) { 10389 props.left = ( options.left - curOffset.left ) + curLeft; 10390 } 10391 10392 if ( "using" in options ) { 10393 options.using.call( elem, props ); 10394 } else { 10395 curElem.css( props ); 10396 } 10397 } 10398}; 10399 10400jQuery.fn.extend({ 10401 offset: function( options ) { 10402 if ( arguments.length ) { 10403 return options === undefined ? 10404 this : 10405 this.each(function( i ) { 10406 jQuery.offset.setOffset( this, options, i ); 10407 }); 10408 } 10409 10410 var docElem, win, 10411 box = { top: 0, left: 0 }, 10412 elem = this[ 0 ], 10413 doc = elem && elem.ownerDocument; 10414 10415 if ( !doc ) { 10416 return; 10417 } 10418 10419 docElem = doc.documentElement; 10420 10421 // Make sure it's not a disconnected DOM node 10422 if ( !jQuery.contains( docElem, elem ) ) { 10423 return box; 10424 } 10425 10426 // If we don't have gBCR, just use 0,0 rather than error 10427 // BlackBerry 5, iOS 3 (original iPhone) 10428 if ( typeof elem.getBoundingClientRect !== strundefined ) { 10429 box = elem.getBoundingClientRect(); 10430 } 10431 win = getWindow( doc ); 10432 return { 10433 top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ), 10434 left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 ) 10435 }; 10436 }, 10437 10438 position: function() { 10439 if ( !this[ 0 ] ) { 10440 return; 10441 } 10442 10443 var offsetParent, offset, 10444 parentOffset = { top: 0, left: 0 }, 10445 elem = this[ 0 ]; 10446 10447 // fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent 10448 if ( jQuery.css( elem, "position" ) === "fixed" ) { 10449 // we assume that getBoundingClientRect is available when computed position is fixed 10450 offset = elem.getBoundingClientRect(); 10451 } else { 10452 // Get *real* offsetParent 10453 offsetParent = this.offsetParent(); 10454 10455 // Get correct offsets 10456 offset = this.offset(); 10457 if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) { 10458 parentOffset = offsetParent.offset(); 10459 } 10460 10461 // Add offsetParent borders 10462 parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true ); 10463 parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true ); 10464 } 10465 10466 // Subtract parent offsets and element margins 10467 // note: when an element has margin: auto the offsetLeft and marginLeft 10468 // are the same in Safari causing offset.left to incorrectly be 0 10469 return { 10470 top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ), 10471 left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true) 10472 }; 10473 }, 10474 10475 offsetParent: function() { 10476 return this.map(function() { 10477 var offsetParent = this.offsetParent || docElem; 10478 10479 while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) ) { 10480 offsetParent = offsetParent.offsetParent; 10481 } 10482 return offsetParent || docElem; 10483 }); 10484 } 10485}); 10486 10487// Create scrollLeft and scrollTop methods 10488jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) { 10489 var top = /Y/.test( prop ); 10490 10491 jQuery.fn[ method ] = function( val ) { 10492 return access( this, function( elem, method, val ) { 10493 var win = getWindow( elem ); 10494 10495 if ( val === undefined ) { 10496 return win ? (prop in win) ? win[ prop ] : 10497 win.document.documentElement[ method ] : 10498 elem[ method ]; 10499 } 10500 10501 if ( win ) { 10502 win.scrollTo( 10503 !top ? val : jQuery( win ).scrollLeft(), 10504 top ? val : jQuery( win ).scrollTop() 10505 ); 10506 10507 } else { 10508 elem[ method ] = val; 10509 } 10510 }, method, val, arguments.length, null ); 10511 }; 10512}); 10513 10514// Add the top/left cssHooks using jQuery.fn.position 10515// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 10516// getComputedStyle returns percent when specified for top/left/bottom/right 10517// rather than make the css module depend on the offset module, we just check for it here 10518jQuery.each( [ "top", "left" ], function( i, prop ) { 10519 jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition, 10520 function( elem, computed ) { 10521 if ( computed ) { 10522 computed = curCSS( elem, prop ); 10523 // if curCSS returns percentage, fallback to offset 10524 return rnumnonpx.test( computed ) ? 10525 jQuery( elem ).position()[ prop ] + "px" : 10526 computed; 10527 } 10528 } 10529 ); 10530}); 10531 10532// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods 10533jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { 10534 jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) { 10535 // margin is only for outerHeight, outerWidth 10536 jQuery.fn[ funcName ] = function( margin, value ) { 10537 var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), 10538 extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); 10539 10540 return access( this, function( elem, type, value ) { 10541 var doc; 10542 10543 if ( jQuery.isWindow( elem ) ) { 10544 // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there 10545 // isn't a whole lot we can do. See pull request at this URL for discussion: 10546 // https://github.com/jquery/jquery/pull/764 10547 return elem.document.documentElement[ "client" + name ]; 10548 } 10549 10550 // Get document width or height 10551 if ( elem.nodeType === 9 ) { 10552 doc = elem.documentElement; 10553 10554 // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest 10555 // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it. 10556 return Math.max( 10557 elem.body[ "scroll" + name ], doc[ "scroll" + name ], 10558 elem.body[ "offset" + name ], doc[ "offset" + name ], 10559 doc[ "client" + name ] 10560 ); 10561 } 10562 10563 return value === undefined ? 10564 // Get width or height on the element, requesting but not forcing parseFloat 10565 jQuery.css( elem, type, extra ) : 10566 10567 // Set width or height on the element 10568 jQuery.style( elem, type, value, extra ); 10569 }, type, chainable ? margin : undefined, chainable, null ); 10570 }; 10571 }); 10572}); 10573 10574// The number of elements contained in the matched element set 10575jQuery.fn.size = function() { 10576 return this.length; 10577}; 10578 10579jQuery.fn.andSelf = jQuery.fn.addBack; 10580 10581// Register as a named AMD module, since jQuery can be concatenated with other 10582// files that may use define, but not via a proper concatenation script that 10583// understands anonymous AMD modules. A named AMD is safest and most robust 10584// way to register. Lowercase jquery is used because AMD module names are 10585// derived from file names, and jQuery is normally delivered in a lowercase 10586// file name. Do this after creating the global so that if an AMD module wants 10587// to call noConflict to hide this version of jQuery, it will work. 10588 10589// Note that for maximum portability, libraries that are not jQuery should 10590// declare themselves as anonymous modules, and avoid setting a global if an 10591// AMD loader is present. jQuery is a special case. For more information, see
10592// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon 10593 10594if ( typeof define === "function" && define.amd ) { 10595 define( "jquery", [], function() { 10596 return jQuery; 10597 }); 10598} 10599 10600var 10601 // Map over jQuery in case of overwrite 10602 _jQuery = window.jQuery, 10603 10604 // Map over the $ in case of overwrite 10605 _$ = window.$; 10606 10607jQuery.noConflict = function( deep ) { 10608 if ( window.$ === jQuery ) { 10609 window.$ = _$; 10610 } 10611 10612 if ( deep && window.jQuery === jQuery ) { 10613 window.jQuery = _jQuery; 10614 } 10615 10616 return jQuery; 10617}; 10618 10619// Expose jQuery and $ identifiers, even in 10620// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557) 10621// and CommonJS for browser emulators (#13566) 10622if ( typeof noGlobal === strundefined ) { 10623 window.jQuery = window.$ = jQuery; 10624} 10625 10626return jQuery; 10627 10628})); 10629 /* Ende jquery */ 10630 /* Start gsb_makeGSBModule */ 10631 /*! 10632 @author rkrusenb 10633 @license MIT 10634*/ 10635var gsb; 10636gsb = gsb || {}; 10637(function($, gsb){ 10638 10639 /* @example 10640 * function module(){} 10641 * var $; 10642 * set($, ['gsb', 'foo', 'bar'], module); 10643 * $.gsb && $.gsb.foo && $.gsb.foo.bar === module //true 10644 */ 10645 function set(object, namespace, value){ 10646 var i, l = namespace.length - 1, 10647 property, last = namespace[l]; 10648 for(i = 0; i < l; i++){ 10649 property = namespace[i]; 10650 object[property] = object[property] || {}; 10651 object = object[property]; 10652 } 10653 object[last] = value; 10654 } 10655 /* @example 10656 * var $ = { 10657 * gsb: { 10658 * foo: { 10659 * bar: function(x){ 10660 * return x; 10661 * } 10662 * } 10663 * } 10664 * }; 10665 * apply($, ['gsb', 'foo', 'bar'], ['baz']) === 'baz' //true 10666 */ 10667 function apply(object, namespace, args){ 10668 var i, l = namespace.length - 1, 10669 property, last = namespace[l]; 10670 for(i = 0; i < l; i++){ 10671 property = namespace[i]; 10672 object = object && object[property]; 10673 } 10674 if(typeof object[last] === "function") { 10675 object[last].apply(object, args); 10676 } 10677 } 10678 function enhance(fullName, namespace, template){ //returns an "enhanced" copy of a template 10679 return $.extend({ 10680 eventName: namespace.slice().reverse().join('.'), 10681 moduleName: fullName 10682 }, template); 10683 } 10684 gsb.makeGSBModule = function makeGSBModule(fullName, template){ 10685 var namespace = fullName.split('.'); 10686 10687 function module(el, userOptions, ...additionalParameters){ 10688 var base = $.extend({}, template); 10689 base.el = el; 10690 base.$el = $(el); 10691 base.options = $.extend(true, {}, template.defaultOptions, userOptions); 10692 base.$el.data(namespace.join('.'), base); 10693 base.init(el, userOptions, ...additionalParameters); 10694 } 10695 10696 template = enhance(fullName, namespace, template); 10697 10698 module.defaultOptions = template.defaultOptions || {}; 10699 10700 set($, namespace, module); 10701 10702 $.fn[namespace.join('_')] = function(userOptions, ...additionalParameters){ 10703 $(this).each(function(i, el){ 10704 if(!$(el).data( namespace.join('.') ) || (userOptions && userOptions.force)) { 10705 apply($, namespace, [el, userOptions, ...additionalParameters]); 10706 } 10707 }); 10708 return this; 10709 }; 10710 }; 10711})(jQuery, gsb); 10712 /* Ende gsb_makeGSBModule */ 10713 /* Start gsb_requireGSBComponent */ 10714 var gsb; 10715gsb = gsb || {}; 10716(function ($, gsb) { 10717 const state = { 10718 instanceCount: 0, 10719 promises: {} 10720 }; 10721 10722 function requireGenericGSBComponent(componentName, instanceName) { 10723 const promiseArray = createScriptTags(gsb.jsComponents.definitions[componentName].scriptList, instanceName); 10724 return Promise.all(promiseArray); 10725 } 10726 10727 function createScriptTags(scriptList, instanceName) { 10728 const promiseArray = []; 10729 scriptList.forEach((scriptPath) => { 10730 promiseArray.push(createScriptTag(scriptPath)); 10731 }); 10732 return promiseArray; 10733 } 10734 10735 /** 10736 * Creates a Script Tag, appends and executes it. 10737 * While creating a new Promise or waiting for a previou Promise the Script has already been requested. 10738 * 10739 * @param scriptPath the Path of the script used for the src Attribute 10740 * @param instanceName the name of this instance used for logging 10741 * @returns {Promise<unknown>} a promise that ensures that the Script is ready to use when resolved 10742 */ 10743 function createScriptTag(scriptPath, instanceName) { 10744 let promise; 10745 if (state.promises[scriptPath]) { 10746 promise = state.promises[scriptPath]; 10747 } else { 10748 promise = new Promise(function (resolve, reject) { 10749 const $script = $('<script></script>').attr('src', scriptPath).attr('charSet', 'UTF-8'); 10750 $script 10751 .prop('async', false) 10752 .on('load', function () { 10753 resolve({scriptPath, action: 'DOM load'}); 10754 }); 10755 document.body.appendChild($script[0]); 10756 10757 }); 10758 state.promises[scriptPath] = promise; 10759 } 10760 return promise; 10761 } 10762 10763 gsb.requireGSBComponent = function (componentName, $el) { 10764 const instanceName = 'gsb.requireGSBComponent-' + state.instanceCount++; 10765 const deferred = $.Deferred(); 10766 let error; 10767 10768 if (gsb.jsComponents.definitions[componentName]) { 10769 if (!$el || !$el.length) { 10770 error = new Error('Elemente nicht im DOM gefunden. GSB-Komponente wird nicht geladen'); 10771 deferred.reject(error); 10772 } else { 10773 requireGenericGSBComponent(componentName, instanceName) 10774 .then(() => deferred.resolve($el)) 10775 .catch((err) => { 10776 deferred.reject(err); 10777 console.error(instanceName, `GSB-Komponente ${componentName} für Elemente`, $el, 10778 'konnte nicht eingebunden werden, es gab folgenden Fehler', err); 10779 }); 10780 } 10781 } else { 10782 console.error(instanceName, `GSB-Komponente ${componentName} ist nicht definiert, und kann daher nicht eingebunden werden`); 10783 } 10784 10785 return deferred; 10786 }; 10787 10788})(jQuery, gsb); 10789 /* Ende gsb_requireGSBComponent */ 10790 /* Start jquery.datatables */ 10791 /*! DataTables 1.10.12 10792 * ©2008-2015 SpryMedia Ltd - datatables.net/license 10793 */ 10794/** 10795 * @summary DataTables 10796 * @description Paginate, search and order HTML tables 10797 * @version 1.10.12 10798 * @file jquery.dataTables.js 10799 * @author SpryMedia Ltd (www.sprymedia.co.uk) 10800 * @contact www.sprymedia.co.uk/contact 10801 * @copyright Copyright 2008-2015 SpryMedia Ltd. 10802 * 10803 * This source file is free software, available under the following license: 10804 * MIT license - http://datatables.net/license 10805 * 10806 * This source file is distributed in the hope that it will be useful, but 10807 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 10808 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. 10809 * 10810 * For details please refer to: http://www.datatables.net 10811 */ 10812/*jslint evil: true, undef: true, browser: true */ 10813/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_plu
10813ck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/ 10814(function( factory ) { 10815 "use strict"; 10816 if ( typeof define === 'function' && define.amd ) { 10817 // AMD 10818 define( ['jquery'], function ( $ ) { 10819 return factory( $, window, document ); 10820 } ); 10821 } 10822 else if ( typeof exports === 'object' ) { 10823 // CommonJS 10824 module.exports = function (root, $) { 10825 if ( ! root ) { 10826 // CommonJS environments without a window global must pass a 10827 // root. This will give an error otherwise 10828 root = window; 10829 } 10830 if ( ! $ ) { 10831 $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window 10832 require('jquery') : 10833 require('jquery')( root ); 10834 } 10835 return factory( $, root, root.document ); 10836 }; 10837 } 10838 else { 10839 // Browser 10840 factory( jQuery, window, document ); 10841 } 10842} 10843(function( $, window, document, undefined ) { 10844 "use strict"; 10845 /** 10846 * DataTables is a plug-in for the jQuery Javascript library. It is a highly 10847 * flexible tool, based upon the foundations of progressive enhancement, 10848 * which will add advanced interaction controls to any HTML table. For a 10849 * full list of features please refer to 10850 * [DataTables.net](href="http://datatables.net). 10851 * 10852 * Note that the `DataTable` object is not a global variable but is aliased 10853 * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may 10854 * be accessed. 10855 * 10856 * @class 10857 * @param {object} [init={}] Configuration object for DataTables. Options 10858 * are defined by {@link DataTable.defaults} 10859 * @requires jQuery 1.7+ 10860 * 10861 * @example 10862 * // Basic initialisation 10863 * $(document).ready( function { 10864 * $('#example').dataTable(); 10865 * } ); 10866 * 10867 * @example 10868 * // Initialisation with configuration options - in this case, disable 10869 * // pagination and sorting. 10870 * $(document).ready( function { 10871 * $('#example').dataTable( { 10872 * "paginate": false, 10873 * "sort": false 10874 * } ); 10875 * } ); 10876 */ 10877 var DataTable = function ( options ) 10878 { 10879 /** 10880 * Perform a jQuery selector action on the table's TR elements (from the tbody) and 10881 * return the resulting jQuery object. 10882 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on 10883 * @param {object} [oOpts] Optional parameters for modifying the rows to be included 10884 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter 10885 * criterion ("applied") or all TR elements (i.e. no filter). 10886 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array. 10887 * Can be either 'current', whereby the current sorting of the table is used, or 10888 * 'original' whereby the original order the data was read into the table is used. 10889 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page 10890 * ("current") or not ("all"). If 'current' is given, then order is assumed to be 10891 * 'current' and filter is 'applied', regardless of what they might be given as. 10892 * @returns {object} jQuery object, filtered by the given selector. 10893 * @dtopt API 10894 * @deprecated Since v1.10 10895 * 10896 * @example 10897 * $(document).ready(function() { 10898 * var oTable = $('#example').dataTable(); 10899 * 10900 * // Highlight every second row 10901 * oTable.$('tr:odd').css('backgroundColor', 'blue'); 10902 * } ); 10903 * 10904 * @example 10905 * $(document).ready(function() { 10906 * var oTable = $('#example').dataTable(); 10907 * 10908 * // Filter to rows with 'Webkit' in them, add a background colour and then 10909 * // remove the filter, thus highlighting the 'Webkit' rows only. 10910 * oTable.fnFilter('Webkit'); 10911 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue'); 10912 * oTable.fnFilter(''); 10913 * } ); 10914 */ 10915 this.$ = function ( sSelector, oOpts ) 10916 { 10917 return this.api(true).$( sSelector, oOpts ); 10918 }; 10919 10920 10921 /** 10922 * Almost identical to $ in operation, but in this case returns the data for the matched
10923 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes 10924 * rather than any descendants, so the data can be obtained for the row/cell. If matching 10925 * rows are found, the data returned is the original data array/object that was used to 10926 * create the row (or a generated array if from a DOM source). 10927 * 10928 * This method is often useful in-combination with $ where both functions are given the 10929 * same parameters and the array indexes will match identically. 10930 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on 10931 * @param {object} [oOpts] Optional parameters for modifying the rows to be included 10932 * @param {string} [oOpts.filter=none] Select elements that meet the current filter 10933 * criterion ("applied") or all elements (i.e. no filter). 10934 * @param {string} [oOpts.order=current] Order of the data in the processed array. 10935 * Can be either 'current', whereby the current sorting of the table is used, or 10936 * 'original' whereby the original order the data was read into the table is used. 10937 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page 10938 * ("current") or not ("all"). If 'current' is given, then order is assumed to be 10939 * 'current' and filter is 'applied', regardless of what they might be given as. 10940 * @returns {array} Data for the matched elements. If any elements, as a result of the 10941 * selector, were not TR, TD or TH elements in the DataTable, they will have a null 10942 * entry in the array. 10943 * @dtopt API 10944 * @deprecated Since v1.10 10945 * 10946 * @example 10947 * $(document).ready(function() { 10948 * var oTable = $('#example').dataTable(); 10949 * 10950 * // Get the data from the first row in the table 10951 * var data = oTable._('tr:first'); 10952 * 10953 * // Do something useful with the data 10954 * alert( "First cell is: "+data[0] ); 10955 * } ); 10956 * 10957 * @example 10958 * $(document).ready(function() { 10959 * var oTable = $('#example').dataTable(); 10960 * 10961 * // Filter to 'Webkit' and get all data for 10962 * oTable.fnFilter('Webkit'); 10963 * var data = oTable._('tr', {"search": "applied"}); 10964 * 10965 * // Do something with the data 10966 * alert( data.length+" rows matched the search" ); 10967 * } ); 10968 */ 10969 this._ = function ( sSelector, oOpts ) 10970 { 10971 return this.api(true).rows( sSelector, oOpts ).data(); 10972 }; 10973 10974 10975 /** 10976 * Create a DataTables Api instance, with the currently selected tables for 10977 * the Api's context. 10978 * @param {boolean} [traditional=false] Set the API instance's context to be 10979 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was 10980 * used in the API presented by DataTables 1.9- (i.e. the traditional mode), 10981 * or if all tables captured in the jQuery object should be used. 10982 * @return {DataTables.Api} 10983 */ 10984 this.api = function ( traditional ) 10985 { 10986 return traditional ? 10987 new _Api( 10988 _fnSettingsFromNode( this[ _ext.iApiIndex ] ) 10989 ) : 10990 new _Api( this ); 10991 }; 10992 10993 10994 /** 10995 * Add a single new row or multiple rows of data to the table. Please note 10996 * that this is suitable for client-side processing only - if you are using 10997 * server-side processing (i.e. "bServerSide": true), then to add data, you 10998 * must add it to the data source, i.e. the server-side, through an Ajax call. 10999 * @param {array|object} data The data to be added to the table. This can be: 11000 * <ul> 11001 * <li>1D array of data - add a single row with the data provided</li> 11002 * <li>2D array of arrays - add multiple rows in a single call</li> 11003 * <li>object - data object when using <i>mData</i></li> 11004 * <li>array of objects - multiple data objects when using <i>mData</i></li> 11005 * </ul> 11006 * @param {bool} [redraw=true] redraw the table or not 11007 * @returns {array} An array of integers, representing the list of indexes in 11008 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to 11009 * the table. 11010 * @dtopt API 11011 * @deprecated Since v1.10 11012 * 11013 * @example 11014 * // Global var for counter 11015 * var giCount = 2; 11016 * 11017 * $(document).ready(function() { 11018 * $('#example').dataTable(); 11019 * } ); 11020 * 11021 * function fnClickAddRow() { 11022 * $('#example').dataTable().fnAddData( [ 11023 * giCount+".1", 11024 * giCount+".2", 11025 * giCount+".3", 11026 * giCount+".4" ] 11027 * ); 11028 * 11029 * giCount++; 11030 * } 11031 */ 11032 this.fnAddData = function( data, redraw ) 11033 { 11034 var api = this.api( true ); 11035 11036 /* Check if we want to add multiple rows or not */ 11037 var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ? 11038 api.rows.add( data ) : 11039 api.row.add( data ); 11040 11041 if ( redraw === undefined || redraw ) { 11042 api.draw(); 11043 } 11044 11045 return rows.flatten().toArray(); 11046 }; 11047 11048 11049 /** 11050 * This function will make DataTables recalculate the column sizes, based on the data 11051 * contained in the table and the sizes applied to the columns (in the DOM, CSS or 11052 * through the sWidth parameter). This can be useful when the width of the table's
11053 * parent element changes (for example a window resize). 11054 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to 11055 * @dtopt API 11056 * @deprecated Since v1.10 11057 * 11058 * @example 11059 * $(document).ready(function() { 11060 * var oTable = $('#example').dataTable( { 11061 * "sScrollY": "200px", 11062 * "bPaginate": false 11063 * } ); 11064 * 11065 * $(window).bind('resize', function () { 11066 * oTable.fnAdjustColumnSizing(); 11067 * } ); 11068 * } ); 11069 */ 11070 this.fnAdjustColumnSizing = function ( bRedraw ) 11071 { 11072 var api = this.api( true ).columns.adjust(); 11073 var settings = api.settings()[0]; 11074 var scroll = settings.oScroll; 11075 11076 if ( bRedraw === undefined || bRedraw ) { 11077 api.draw( false ); 11078 } 11079 else if ( scroll.sX !== "" || scroll.sY !== "" ) { 11080 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */ 11081 _fnScrollDraw( settings ); 11082 } 11083 }; 11084 11085 11086 /** 11087 * Quickly and simply clear a table 11088 * @param {bool} [bRedraw=true] redraw the table or not 11089 * @dtopt API 11090 * @deprecated Since v1.10 11091 * 11092 * @example 11093 * $(document).ready(function() { 11094 * var oTable = $('#example').dataTable(); 11095 * 11096 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...) 11097 * oTable.fnClearTable(); 11098 * } ); 11099 */ 11100 this.fnClearTable = function( bRedraw ) 11101 { 11102 var api = this.api( true ).clear(); 11103 11104 if ( bRedraw === undefined || bRedraw ) { 11105 api.draw(); 11106 } 11107 }; 11108 11109 11110 /** 11111 * The exact opposite of 'opening' a row, this function will close any rows which 11112 * are currently 'open'. 11113 * @param {node} nTr the table row to 'close' 11114 * @returns {int} 0 on success, or 1 if failed (can't find the row) 11115 * @dtopt API 11116 * @deprecated Since v1.10 11117 * 11118 * @example 11119 * $(document).ready(function() { 11120 * var oTable; 11121 * 11122 * // 'open' an information row when a row is clicked on 11123 * $('#example tbody tr').click( function () { 11124 * if ( oTable.fnIsOpen(this) ) { 11125 * oTable.fnClose( this ); 11126 * } else { 11127 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 11128 * } 11129 * } ); 11130 * 11131 * oTable = $('#example').dataTable(); 11132 * } ); 11133 */ 11134 this.fnClose = function( nTr ) 11135 { 11136 this.api( true ).row( nTr ).child.hide(); 11137 }; 11138 11139 11140 /** 11141 * Remove a row for the table 11142 * @param {mixed} target The index of the row from aoData to be deleted, or 11143 * the TR element you want to delete 11144 * @param {function|null} [callBack] Callback function 11145 * @param {bool} [redraw=true] Redraw the table or not 11146 * @returns {array} The row that was deleted 11147 * @dtopt API 11148 * @deprecated Since v1.10 11149 * 11150 * @example 11151 * $(document).ready(function() { 11152 * var oTable = $('#example').dataTable(); 11153 * 11154 * // Immediately remove the first row 11155 * oTable.fnDeleteRow( 0 ); 11156 * } ); 11157 */ 11158 this.fnDeleteRow = function( target, callback, redraw ) 11159 { 11160 var api = this.api( true ); 11161 var rows = api.rows( target ); 11162 var settings = rows.settings()[0]; 11163 var data = settings.aoData[ rows[0][0] ]; 11164 11165 rows.remove(); 11166 11167 if ( callback ) { 11168 callback.call( this, settings, data ); 11169 } 11170 11171 if ( redraw === undefined || redraw ) { 11172 api.draw(); 11173 } 11174 11175 return data; 11176 }; 11177 11178 11179 /** 11180 * Restore the table to it's original state in the DOM by removing all of DataTables 11181 * enhancements, alterations to the DOM structure of the table and event listeners. 11182 * @param {boolean} [remove=false] Completely remove the table from the DOM 11183 * @dtopt API 11184 * @deprecated Since v1.10 11185 * 11186 * @example 11187 * $(document).ready(function() { 11188 * // This example is fairly pointless in reality, but shows how fnDestroy can be used 11189 * var oTable = $('#example').dataTable(); 11190 * oTable.fnDestroy(); 11191 * } ); 11192 */ 11193 this.fnDestroy = function ( remove ) 11194 { 11195 this.api( true ).destroy( remove ); 11196 }; 11197 11198 11199 /** 11200 * Redraw the table 11201 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw. 11202 * @dtopt API 11203 * @deprecated Since v1.10 11204 * 11205 * @example 11206 * $(document).ready(function() { 11207 * var oTable = $('#example').dataTable(); 11208 * 11209 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-) 11210 * oTable.fnDraw(); 11211 * } ); 11212 */ 11213 this.fnDraw = function( complete ) 11214 { 11215 // Note that this isn't an exact match to the old call to _fnDraw - it takes 11216 // into account the new data, but can hold position. 11217 this.api( true ).draw( complete ); 11218 }; 11219 11220 11221 /** 11222 * Filter the input based on data 11223 * @param {string} sInput String to filter the table on 11224 * @param {int|null} [iColumn] Column to limit filtering to 11225 * @param {bool} [bRegex=false] Treat as regular expression or not 11226 * @param {bool} [bSmart=true] Perform smart filtering or not 11227 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es) 11228 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false) 11229 * @dtopt API 11230 * @deprecated Since v1.10 11231 * 11232 * @example 11233 * $(document).ready(function() { 11234 * var oTable = $('#example').dataTable(); 11235 * 11236 * // Sometime later - filter... 11237 * oTable.fnFilter( 'test string' ); 11238 * } ); 11239 */ 11240 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive ) 11241 { 11242 var api = this.api( true ); 11243 11244 if ( iColumn === null || iColumn === undefined ) { 11245 api.search( sInput, bRegex, bSmart, bCaseInsensitive ); 11246 } 11247 else { 11248 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive ); 11249 } 11250 11251 api.draw(); 11252 }; 11253 11254 11255 /** 11256 * Get the data for the whole table, an individual row or an individual cell based on the 11257 * provided parameters. 11258 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as 11259 * a TR node then the data source for the whole row will be returned. If given as a 11260 * TD/TH cell node then iCol will be automatically calculated and the data for the 11261 * cell returned. If given as an integer, then this is treated as the aoData internal 11262 * data index for the row (see fnGetPosition) and the data for that row used. 11263 * @param {int} [col] Optional column index that you want the data of. 11264 * @returns {array|object|string} If mRow is undefined, then the data for all rows is 11265 * returned. If mRow is defined, just data for that row, and is iCol is 11266 * defined, only data for the designated cell is returned. 11267 * @dtopt API 11268 * @deprecated Since v1.10 11269 * 11270 * @example 11271 * // Row data 11272 * $(document).ready(function() { 11273 * oTable = $('#example').dataTable(); 11274 * 11275 * oTable.$('tr').click( function () { 11276 * var data = oTable.fnGetData( this ); 11277 * // ... do something with the array / object of data for the row 11278 * } ); 11279 * } ); 11280 * 11281 * @example 11282 * // Individual cell data 11283 * $(document).ready(function() { 11284 * oTable = $('#example').dataTable(); 11285 * 11286 * oTable.$('td').click( function () { 11287 * var sData = oTable.fnGetData( this ); 11288 * alert( 'The cell clicked on had the value of '+sData ); 11289 * } ); 11290 * } ); 11291 */ 11292 this.fnGetData = function( src, col ) 11293 { 11294 var api = this.api( true ); 11295 11296 if ( src !== undefined ) { 11297 var type = src.nodeName ? src.nodeName.toLowerCase() : ''; 11298
vendor: 15,635 bytes, lines 11299-11809
11299 return col !== undefined || type == 'td' || type == 'th' ? 11300 api.cell( src, col ).data() : 11301 api.row( src ).data() || null; 11302 } 11303 11304 return api.data().toArray(); 11305 }; 11306 11307 11308 /** 11309 * Get an array of the TR nodes that are used in the table's body. Note that you will 11310 * typically want to use the '$' API method in preference to this as it is more 11311 * flexible. 11312 * @param {int} [iRow] Optional row index for the TR element you want 11313 * @returns {array|node} If iRow is undefined, returns an array of all TR elements 11314 * in the table's body, or iRow is defined, just the TR element requested. 11315 * @dtopt API 11316 * @deprecated Since v1.10 11317 * 11318 * @example 11319 * $(document).ready(function() { 11320 * var oTable = $('#example').dataTable(); 11321 * 11322 * // Get the nodes from the table 11323 * var nNodes = oTable.fnGetNodes( ); 11324 * } ); 11325 */ 11326 this.fnGetNodes = function( iRow ) 11327 { 11328 var api = this.api( true ); 11329 11330 return iRow !== undefined ? 11331 api.row( iRow ).node() : 11332 api.rows().nodes().flatten().toArray(); 11333 }; 11334 11335 11336 /** 11337 * Get the array indexes of a particular cell from it's DOM element 11338 * and column index including hidden columns 11339 * @param {node} node this can either be a TR, TD or TH in the table's body 11340 * @returns {int} If nNode is given as a TR, then a single index is returned, or 11341 * if given as a cell, an array of [row index, column index (visible), 11342 * column index (all)] is given. 11343 * @dtopt API 11344 * @deprecated Since v1.10 11345 * 11346 * @example 11347 * $(document).ready(function() { 11348 * $('#example tbody td').click( function () { 11349 * // Get the position of the current data from the node 11350 * var aPos = oTable.fnGetPosition( this ); 11351 * 11352 * // Get the data array for this row 11353 * var aData = oTable.fnGetData( aPos[0] ); 11354 * 11355 * // Update the data array and return the value 11356 * aData[ aPos[1] ] = 'clicked'; 11357 * this.innerHTML = 'clicked'; 11358 * } ); 11359 * 11360 * // Init DataTables 11361 * oTable = $('#example').dataTable(); 11362 * } ); 11363 */ 11364 this.fnGetPosition = function( node ) 11365 { 11366 var api = this.api( true ); 11367 var nodeName = node.nodeName.toUpperCase(); 11368 11369 if ( nodeName == 'TR' ) { 11370 return api.row( node ).index(); 11371 } 11372 else if ( nodeName == 'TD' || nodeName == 'TH' ) { 11373 var cell = api.cell( node ).index(); 11374 11375 return [ 11376 cell.row, 11377 cell.columnVisible, 11378 cell.column 11379 ]; 11380 } 11381 return null; 11382 }; 11383 11384 11385 /** 11386 * Check to see if a row is 'open' or not. 11387 * @param {node} nTr the table row to check 11388 * @returns {boolean} true if the row is currently open, false otherwise 11389 * @dtopt API 11390 * @deprecated Since v1.10 11391 * 11392 * @example 11393 * $(document).ready(function() { 11394 * var oTable; 11395 * 11396 * // 'open' an information row when a row is clicked on 11397 * $('#example tbody tr').click( function () { 11398 * if ( oTable.fnIsOpen(this) ) { 11399 * oTable.fnClose( this ); 11400 * } else { 11401 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 11402 * } 11403 * } ); 11404 * 11405 * oTable = $('#example').dataTable(); 11406 * } ); 11407 */ 11408 this.fnIsOpen = function( nTr ) 11409 { 11410 return this.api( true ).row( nTr ).child.isShown(); 11411 }; 11412 11413 11414 /** 11415 * This function will place a new row directly after a row which is currently 11416 * on display on the page, with the HTML contents that is passed into the 11417 * function. This can be used, for example, to ask for confirmation that a 11418 * particular record should be deleted. 11419 * @param {node} nTr The table row to 'open' 11420 * @param {string|node|jQuery} mHtml The HTML to put into the row 11421 * @param {string} sClass Class to give the new TD cell 11422 * @returns {node} The row opened. Note that if the table row passed in as the 11423 * first parameter, is not found in the table, this method will silently 11424 * return. 11425 * @dtopt API 11426 * @deprecated Since v1.10 11427 * 11428 * @example 11429 * $(document).ready(function() { 11430 * var oTable; 11431 * 11432 * // 'open' an information row when a row is clicked on 11433 * $('#example tbody tr').click( function () { 11434 * if ( oTable.fnIsOpen(this) ) { 11435 * oTable.fnClose( this ); 11436 * } else { 11437 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 11438 * } 11439 * } ); 11440 * 11441 * oTable = $('#example').dataTable(); 11442 * } ); 11443 */ 11444 this.fnOpen = function( nTr, mHtml, sClass ) 11445 { 11446 return this.api( true ) 11447 .row( nTr ) 11448 .child( mHtml, sClass ) 11449 .show() 11450 .child()[0]; 11451 }; 11452 11453 11454 /** 11455 * Change the pagination - provides the internal logic for pagination in a simple API 11456 * function. With this function you can have a DataTables table go to the next, 11457 * previous, first or last pages. 11458 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last" 11459 * or page number to jump to (integer), note that page 0 is the first page. 11460 * @param {bool} [bRedraw=true] Redraw the table or not 11461 * @dtopt API 11462 * @deprecated Since v1.10 11463 * 11464 * @example 11465 * $(document).ready(function() { 11466 * var oTable = $('#example').dataTable(); 11467 * oTable.fnPageChange( 'next' ); 11468 * } ); 11469 */ 11470 this.fnPageChange = function ( mAction, bRedraw ) 11471 { 11472 var api = this.api( true ).page( mAction ); 11473 11474 if ( bRedraw === undefined || bRedraw ) { 11475 api.draw(false); 11476 } 11477 }; 11478 11479 11480 /** 11481 * Show a particular column 11482 * @param {int} iCol The column whose display should be changed 11483 * @param {bool} bShow Show (true) or hide (false) the column 11484 * @param {bool} [bRedraw=true] Redraw the table or not 11485 * @dtopt API 11486 * @deprecated Since v1.10 11487 * 11488 * @example 11489 * $(document).ready(function() { 11490 * var oTable = $('#example').dataTable(); 11491 * 11492 * // Hide the second column after initialisation 11493 * oTable.fnSetColumnVis( 1, false ); 11494 * } ); 11495 */ 11496 this.fnSetColumnVis = function ( iCol, bShow, bRedraw ) 11497 { 11498 var api = this.api( true ).column( iCol ).visible( bShow ); 11499 11500 if ( bRedraw === undefined || bRedraw ) { 11501 api.columns.adjust().draw(); 11502 } 11503 }; 11504 11505 11506 /** 11507 * Get the settings for a particular table for external manipulation 11508 * @returns {object} DataTables settings object. See 11509 * {@link DataTable.models.oSettings} 11510 * @dtopt API 11511 * @deprecated Since v1.10 11512 * 11513 * @example 11514 * $(document).ready(function() { 11515 * var oTable = $('#example').dataTable(); 11516 * var oSettings = oTable.fnSettings(); 11517 * 11518 * // Show an example parameter from the settings 11519 * alert( oSettings._iDisplayStart ); 11520 * } ); 11521 */ 11522 this.fnSettings = function() 11523 { 11524 return _fnSettingsFromNode( this[_ext.iApiIndex] ); 11525 }; 11526 11527 11528 /** 11529 * Sort the table by a particular column 11530 * @param {int} iCol the data index to sort on. Note that this will not match the 11531 * 'display index' if you have hidden data entries 11532 * @dtopt API 11533 * @deprecated Since v1.10 11534 * 11535 * @example 11536 * $(document).ready(function() { 11537 * var oTable = $('#example').dataTable(); 11538 * 11539 * // Sort immediately with columns 0 and 1 11540 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] ); 11541 * } ); 11542 */ 11543 this.fnSort = function( aaSort ) 11544 { 11545 this.api( true ).order( aaSort ).draw(); 11546 }; 11547 11548 11549 /** 11550 * Attach a sort listener to an element for a given column 11551 * @param {node} nNode the element to attach the sort listener to 11552 * @param {int} iColumn the column that a click on this node will sort on 11553 * @param {function} [fnCallback] callback function when sort is run 11554 * @dtopt API 11555 * @deprecated Since v1.10 11556 * 11557 * @example 11558 * $(document).ready(function() { 11559 * var oTable = $('#example').dataTable(); 11560 * 11561 * // Sort on column 1, when 'sorter' is clicked on 11562 * oTable.fnSortListener( document.getElementById('sorter'), 1 ); 11563 * } ); 11564 */ 11565 this.fnSortListener = function( nNode, iColumn, fnCallback ) 11566 { 11567 this.api( true ).order.listener( nNode, iColumn, fnCallback ); 11568 }; 11569 11570 11571 /** 11572 * Update a table cell or row - this method will accept either a single value to 11573 * update the cell with, an array of values with one element for each column or 11574 * an object in the same format as the original data source. The function is 11575 * self-referencing in order to make the multi column updates easier. 11576 * @param {object|array|string} mData Data to update the cell/row with 11577 * @param {node|int} mRow TR element you want to update or the aoData index 11578 * @param {int} [iColumn] The column to update, give as null or undefined to 11579 * update a whole row. 11580 * @param {bool} [bRedraw=true] Redraw the table or not 11581 * @param {bool} [bAction=true] Perform pre-draw actions or not 11582 * @returns {int} 0 on success, 1 on error 11583 * @dtopt API 11584 * @deprecated Since v1.10 11585 * 11586 * @example 11587 * $(document).ready(function() { 11588 * var oTable = $('#example').dataTable(); 11589 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell 11590 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row 11591 * } ); 11592 */ 11593 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction ) 11594 { 11595 var api = this.api( true ); 11596 11597 if ( iColumn === undefined || iColumn === null ) { 11598 api.row( mRow ).data( mData ); 11599 } 11600 else { 11601 api.cell( mRow, iColumn ).data( mData ); 11602 } 11603 11604 if ( bAction === undefined || bAction ) { 11605 api.columns.adjust(); 11606 } 11607 11608 if ( bRedraw === undefined || bRedraw ) { 11609 api.draw(); 11610 } 11611 return 0; 11612 }; 11613 11614 11615 /** 11616 * Provide a common method for plug-ins to check the version of DataTables being used, in order 11617 * to ensure compatibility. 11618 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the 11619 * formats "X" and "X.Y" are also acceptable. 11620 * @returns {boolean} true if this version of DataTables is greater or equal to the required 11621 * version, or false if this version of DataTales is not suitable 11622 * @method 11623 * @dtopt API 11624 * @deprecated Since v1.10 11625 * 11626 * @example 11627 * $(document).ready(function() { 11628 * var oTable = $('#example').dataTable(); 11629 * alert( oTable.fnVersionCheck( '1.9.0' ) ); 11630 * } ); 11631 */ 11632 this.fnVersionCheck = _ext.fnVersionCheck; 11633 11634 var _that = this; 11635 var emptyInit = options === undefined; 11636 var len = this.length; 11637 if ( emptyInit ) { 11638 options = {}; 11639 } 11640 this.oApi = this.internal = _ext.internal; 11641 // Extend with old style plug-in API methods 11642 for ( var fn in DataTable.ext.internal ) { 11643 if ( fn ) { 11644 this[fn] = _fnExternApiFunc(fn); 11645 } 11646 } 11647 this.each(function() { 11648 // For each initialisation we want to give it a clean initialisation 11649 // object that can be bashed around 11650 var o = {}; 11651 var oInit = len > 1 ? // optimisation for single table case 11652 _fnExtend( o, options, true ) : 11653 options; 11654 /*global oInit,_that,emptyInit*/ 11655 var i=0, iLen, j, jLen, k, kLen; 11656 var sId = this.getAttribute( 'id' ); 11657 var bInitHandedOff = false; 11658 var defaults = DataTable.defaults; 11659 var $this = $(this); 11660 11661 11662 /* Sanity check */ 11663 if ( this.nodeName.toLowerCase() != 'table' ) 11664 { 11665 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 ); 11666 return; 11667 } 11668 11669 /* Backwards compatibility for the defaults */ 11670 _fnCompatOpts( defaults ); 11671 _fnCompatCols( defaults.column ); 11672 11673 /* Convert the camel-case defaults to Hungarian */ 11674 _fnCamelToHungarian( defaults, defaults, true ); 11675 _fnCamelToHungarian( defaults.column, defaults.column, true ); 11676 11677 /* Setting up the initialisation object */ 11678 _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) ); 11679 11680 11681 11682 /* Check to see if we are re-initialising a table */ 11683 var allSettings = DataTable.settings; 11684 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ ) 11685 { 11686 var s = allSettings[i]; 11687 11688 /* Base check on table node */ 11689 if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) ) 11690 { 11691 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve; 11692 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy; 11693 11694 if ( emptyInit || bRetrieve ) 11695 { 11696 return s.oInstance; 11697 } 11698 else if ( bDestroy ) 11699 { 11700 s.oInstance.fnDestroy(); 11701 break; 11702 } 11703 else 11704 { 11705 _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 ); 11706 return; 11707 } 11708 } 11709 11710 /* If the element we are initialising has the same ID as a table which was previously 11711 * initialised, but the table nodes don't match (from before) then we destroy the old 11712 * instance by simply deleting it. This is under the assumption that the table has been 11713 * destroyed by other methods. Anyone using non-id selectors will need to do this manually 11714 */ 11715 if ( s.sTableId == this.id ) 11716 { 11717 allSettings.splice( i, 1 ); 11718 break; 11719 } 11720 } 11721 11722 /* Ensure the table has an ID - required for accessibility */ 11723 if ( sId === null || sId === "" ) 11724 { 11725 sId = "DataTables_Table_"+(DataTable.ext._unique++); 11726 this.id = sId; 11727 } 11728 11729 /* Create the settings object for this table and set some of the default parameters */ 11730 var oSettings = $.extend( true, {}, DataTable.models.oSettings, { 11731 "sDestroyWidth": $this[0].style.width, 11732 "sInstance": sId, 11733 "sTableId": sId 11734 } ); 11735 oSettings.nTable = this; 11736 oSettings.oApi = _that.internal; 11737 oSettings.oInit = oInit; 11738 11739 allSettings.push( oSettings ); 11740 11741 // Need to add the instance after the instance after the settings object has been added 11742 // to the settings array, so we can self reference the table instance if more than one 11743 oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable(); 11744 11745 // Backwards compatibility, before we apply all the defaults 11746 _fnCompatOpts( oInit ); 11747 11748 if ( oInit.oLanguage ) 11749 { 11750 _fnLanguageCompat( oInit.oLanguage ); 11751 } 11752 11753 // If the length menu is given, but the init display length is not, use the length menu 11754 if ( oInit.aLengthMenu && ! oInit.iDisplayLength ) 11755 { 11756 oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ? 11757 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0]; 11758 } 11759 11760 // Apply the defaults and init options to make a single init object will all 11761 // options defined from defaults and instance options. 11762 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit ); 11763 11764 11765 // Map the initialisation options onto the settings object 11766 _fnMap( oSettings.oFeatures, oInit, [ 11767 "bPaginate", 11768 "bLengthChange", 11769 "bFilter", 11770 "bSort", 11771 "bSortMulti", 11772 "bInfo", 11773 "bProcessing", 11774 "bAutoWidth", 11775 "bSortClasses", 11776 "bServerSide", 11777 "bDeferRender" 11778 ] ); 11779 _fnMap( oSettings, oInit, [ 11780 "asStripeClasses", 11781 "ajax", 11782 "fnServerData", 11783 "fnFormatNumber", 11784 "sServerMethod", 11785 "aaSorting", 11786 "aaSortingFixed", 11787 "aLengthMenu", 11788 "sPaginationType", 11789 "sAjaxSource", 11790 "sAjaxDataProp", 11791 "iStateDuration", 11792 "sDom", 11793 "bSortCellsTop", 11794 "iTabIndex", 11795 "fnStateLoadCallback", 11796 "fnStateSaveCallback", 11797 "renderer", 11798 "searchDelay", 11799 "rowId", 11800 [ "iCookieDuration", "iStateDuration" ], // backwards compat 11801 [ "oSearch", "oPreviousSearch" ], 11802 [ "aoSearchCols", "aoPreSearchCols" ], 11803 [ "iDisplayLength", "_iDisplayLength" ], 11804 [ "bJQueryUI", "bJUI" ] 11805 ] ); 11806 _fnMap( oSettings.oScroll, oInit, [ 11807 [ "sScrollX", "sX" ], 11808 [ "sScrollXInner", "sXInner" ], 11809 [ "sScrollY", "sY" ],
11810 [ "bScrollCollapse", "bCollapse" ] 11811 ] ); 11812 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" ); 11813 11814 /* Callback functions which are array driven */ 11815 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' ); 11816 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' ); 11817 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' ); 11818 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' ); 11819 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' ); 11820 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' ); 11821 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' ); 11822 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' ); 11823 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' ); 11824 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' ); 11825 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' ); 11826 11827 oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId ); 11828 11829 /* Browser support detection */ 11830 _fnBrowserDetect( oSettings ); 11831 11832 var oClasses = oSettings.oClasses; 11833 11834 // @todo Remove in 1.11 11835 if ( oInit.bJQueryUI ) 11836 { 11837 /* Use the JUI classes object for display. You could clone the oStdClasses object if 11838 * you want to have multiple tables with multiple independent classes 11839 */ 11840 $.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses ); 11841 11842 if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" ) 11843 { 11844 /* Set the DOM to use a layout suitable for jQuery UI's theming */ 11845 oSettings.sDom = '<"H"lfr>t<"F"ip>'; 11846 } 11847 11848 if ( ! oSettings.renderer ) { 11849 oSettings.renderer = 'jqueryui'; 11850 } 11851 else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) { 11852 oSettings.renderer.header = 'jqueryui'; 11853 } 11854 } 11855 else 11856 { 11857 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses ); 11858 } 11859 $this.addClass( oClasses.sTable ); 11860 11861 11862 if ( oSettings.iInitDisplayStart === undefined ) 11863 { 11864 /* Display start point, taking into account the save saving */ 11865 oSettings.iInitDisplayStart = oInit.iDisplayStart; 11866 oSettings._iDisplayStart = oInit.iDisplayStart; 11867 } 11868 11869 if ( oInit.iDeferLoading !== null ) 11870 { 11871 oSettings.bDeferLoading = true; 11872 var tmp = $.isArray( oInit.iDeferLoading ); 11873 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading; 11874 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading; 11875 } 11876 11877 /* Language definitions */ 11878 var oLanguage = oSettings.oLanguage; 11879 $.extend( true, oLanguage, oInit.oLanguage ); 11880 11881 if ( oLanguage.sUrl !== "" ) 11882 { 11883 /* Get the language definitions from a file - because this Ajax call makes the language 11884 * get async to the remainder of this function we use bInitHandedOff to indicate that 11885 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor 11886 */ 11887 $.ajax( { 11888 dataType: 'json', 11889 url: oLanguage.sUrl, 11890 success: function ( json ) { 11891 _fnLanguageCompat( json ); 11892 _fnCamelToHungarian( defaults.oLanguage, json ); 11893 $.extend( true, oLanguage, json ); 11894 _fnInitialise( oSettings ); 11895 }, 11896 error: function () { 11897 // Error occurred loading language file, continue on as best we can 11898 _fnInitialise( oSettings ); 11899 } 11900 } ); 11901 bInitHandedOff = true; 11902 } 11903 11904 /* 11905 * Stripes 11906 */ 11907 if ( oInit.asStripeClasses === null ) 11908 { 11909 oSettings.asStripeClasses =[ 11910 oClasses.sStripeOdd, 11911 oClasses.sStripeEven 11912 ]; 11913 } 11914 11915 /* Remove row stripe classes if they are already on the table row */ 11916 var stripeClasses = oSettings.asStripeClasses; 11917 var rowOne = $this.children('tbody').find('tr').eq(0); 11918 if ( $.inArray( true, $.map( stripeClasses, function(el, i) { 11919 return rowOne.hasClass(el); 11920 } ) ) !== -1 ) { 11921 $('tbody tr', this).removeClass( stripeClasses.join(' ') ); 11922 oSettings.asDestroyStripes = stripeClasses.slice(); 11923 } 11924 11925 /* 11926 * Columns 11927 * See if we should load columns automatically or use defined ones 11928 */ 11929 var anThs = []; 11930 var aoColumnsInit; 11931 var nThead = this.getElementsByTagName('thead'); 11932 if ( nThead.length !== 0 ) 11933 { 11934 _fnDetectHeader( oSettings.aoHeader, nThead[0] ); 11935 anThs = _fnGetUniqueThs( oSettings ); 11936 } 11937 11938 /* If not given a column array, generate one with nulls */ 11939 if ( oInit.aoColumns === null ) 11940 { 11941 aoColumnsInit = []; 11942 for ( i=0, iLen=anThs.length ; i<iLen ; i++ ) 11943 { 11944 aoColumnsInit.push( null ); 11945 } 11946 } 11947 else 11948 { 11949 aoColumnsInit = oInit.aoColumns; 11950 } 11951 11952 /* Add the columns */ 11953 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ ) 11954 { 11955 _fnAddColumn( oSettings, anThs ? anThs[i] : null ); 11956 } 11957 11958 /* Apply the column definitions */ 11959 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) { 11960 _fnColumnOptions( oSettings, iCol, oDef ); 11961 } ); 11962 11963 /* HTML5 attribute detection - build an mData object automatically if the 11964 * attributes are found 11965 */ 11966 if ( rowOne.length ) { 11967 var a = function ( cell, name ) { 11968 return cell.getAttribute( 'data-'+name ) !== null ? name : null; 11969 }; 11970 11971 $( rowOne[0] ).children('th, td').each( function (i, cell) { 11972 var col = oSettings.aoColumns[i]; 11973 11974 if ( col.mData === i ) { 11975 var sort = a( cell, 'sort' ) || a( cell, 'order' ); 11976 var filter = a( cell, 'filter' ) || a( cell, 'search' ); 11977 11978 if ( sort !== null || filter !== null ) { 11979 col.mData = { 11980 _: i+'.display', 11981 sort: sort !== null ? i+'.@data-'+sort : undefined, 11982 type: sort !== null ? i+'.@data-'+sort : undefined, 11983 filter: filter !== null ? i+'.@data-'+filter : undefined 11984 }; 11985 11986 _fnColumnOptions( oSettings, i ); 11987 } 11988 } 11989 } ); 11990 } 11991 11992 var features = oSettings.oFeatures; 11993 11994 /* Must be done after everything which can be overridden by the state saving! */ 11995 if ( oInit.bStateSave ) 11996 { 11997 features.bStateSave = true; 11998 _fnLoadState( oSettings, oInit ); 11999 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' ); 12000 } 12001 12002 12003 /* 12004 * Sorting 12005 * @todo For modularisation (1.11) this needs to do into a sort start up handler 12006 */ 12007 12008 // If aaSorting is not defined, then we use the first indicator in asSorting 12009 // in case that has been altered, so the default sort reflects that option 12010 if ( oInit.aaSorting === undefined ) 12011 { 12012 var sorting = oSettings.aaSorting; 12013 for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) 12014 { 12015 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0]; 12016 } 12017 } 12018 12019 /* Do a first pass on the sorting classes (allows any size changes to be taken into 12020 * account, and also will apply sorting disabled classes if disabled 12021 */ 12022 _fnSortingClasses( oSettings ); 12023 12024 if ( features.bSort ) 12025 { 12026 _fnCallbackReg( oSettings, 'aoDrawCallback', function () { 12027 if ( oSettings.bSorted ) { 12028 var aSort = _fnSortFlatten( oSettings ); 12029 var sortedColumns = {}; 12030 12031 $.each( aSort, function (i, val) { 12032 sortedColumns[ val.src ] = val.dir; 12033 } ); 12034 12035 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] ); 12036 _fnSortAria( oSettings ); 12037 } 12038 } ); 12039 } 12040 12041 _fnCallbackReg( oSettings, 'aoDrawCallback', function () { 12042 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) { 12043 _fnSortingClasses( oSettings ); 12044 } 12045 }, 'sc' ); 12046 12047 12048 /* 12049 * Final init 12050 * Cache the header, body and footer as required, creating them if needed 12051 */ 12052 12053 // Work around for Webkit bug 83867 - store the caption-side before removing from doc 12054 var captions = $this.children('caption').each( function () { 12055 this._captionSide = $this.css('caption-side'); 12056 } ); 12057 12058 var thead = $this.children('thead'); 12059 if ( thead.length === 0 ) 12060 { 12061 thead = $('<thead/>').appendTo(this); 12062 } 12063 oSettings.nTHead = thead[0]; 12064 12065 var tbody = $this.children('tbody'); 12066 if ( tbody.length === 0 ) 12067 { 12068 tbody = $('<tbody/>').appendTo(this); 12069 } 12070 oSettings.nTBody = tbody[0]; 12071 12072 var tfoot = $this.children('tfoot'); 12073 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) 12074 { 12075 // If we are a scrolling table, and no footer has been given, then we need to create 12076 // a tfoot element for the caption element to be appended to 12077 tfoot = $('<tfoot/>').appendTo(this); 12078 } 12079 12080 if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
vendor: 1,188 bytes, lines 12081-12123
12081 $this.addClass( oClasses.sNoFooter ); 12082 } 12083 else if ( tfoot.length > 0 ) { 12084 oSettings.nTFoot = tfoot[0]; 12085 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot ); 12086 } 12087 12088 /* Check if there is data passing into the constructor */ 12089 if ( oInit.aaData ) 12090 { 12091 for ( i=0 ; i<oInit.aaData.length ; i++ ) 12092 { 12093 _fnAddData( oSettings, oInit.aaData[ i ] ); 12094 } 12095 } 12096 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) 12097 { 12098 /* Grab the data from the page - only do this when deferred loading or no Ajax 12099 * source since there is no point in reading the DOM data if we are then going 12100 * to replace it with Ajax data 12101 */ 12102 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') ); 12103 } 12104 12105 /* Copy the data index array */ 12106 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); 12107 12108 /* Initialisation complete - table can be drawn */ 12109 oSettings.bInitialised = true; 12110 12111 /* Check if we need to initialise the table (it might not have been handed off to the 12112 * language processor) 12113 */ 12114 if ( bInitHandedOff === false ) 12115 { 12116 _fnInitialise( oSettings ); 12117 } 12118 } ); 12119 _that = null; 12120 return this; 12121 }; 12122 12123 /*
12124 * It is useful to have variables which are scoped locally so only the 12125 * DataTables functions can access them and they don't leak into global space. 12126 * At the same time these functions are often useful over multiple files in the 12127 * core and API, so we list, or at least document, all variables which are used 12128 * by DataTables as private variables here. This also ensures that there is no 12129 * clashing of variable names and that they can easily referenced for reuse. 12130 */ 12131 12132 12133 // Defined else where 12134 // _selector_run 12135 // _selector_opts 12136 // _selector_first 12137 // _selector_row_indexes 12138 12139 var _ext; // DataTable.ext 12140 var _Api; // DataTable.Api 12141 var _api_register; // DataTable.Api.register 12142 var _api_registerPlural; // DataTable.Api.registerPlural 12143 12144 var _re_dic = {}; 12145 var _re_new_lines = /[\r\n]/g; 12146 var _re_html = /<.*?>/g; 12147 var _re_date_start = /^[\w\+\-]/; 12148 var _re_date_end = /[\w\+\-]$/; 12149 12150 // Escape regular expression special characters 12151 var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' ); 12152 12153 // http://en.wikipedia.org/wiki/Foreign_exchange_market 12154 // - \u20BD - Russian ruble. 12155 // - \u20a9 - South Korean Won 12156 // - \u20BA - Turkish Lira 12157 // - \u20B9 - Indian Rupee 12158 // - R - Brazil (R$) and South Africa 12159 // - fr - Swiss Franc 12160 // - kr - Swedish krona, Norwegian krone and Danish krone 12161 // - \u2009 is thin space and \u202F is narrow no-break space, both used in many 12162 // standards as thousands separators. 12163 var _re_formatted_numeric = /[',$£â¬Â¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi; 12164 12165 12166 var _empty = function ( d ) { 12167 return !d || d === true || d === '-' ? true : false; 12168 }; 12169 12170 12171 var _intVal = function ( s ) { 12172 var integer = parseInt( s, 10 ); 12173 return !isNaN(integer) && isFinite(s) ? integer : null; 12174 }; 12175 12176 // Convert from a formatted number with characters other than `.` as the 12177 // decimal place, to a Javascript number 12178 var _numToDecimal = function ( num, decimalPoint ) { 12179 // Cache created regular expressions for speed as this function is called often 12180 if ( ! _re_dic[ decimalPoint ] ) { 12181 _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' ); 12182 } 12183 return typeof num === 'string' && decimalPoint !== '.' ? 12184 num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) : 12185 num; 12186 }; 12187 12188 12189 var _isNumber = function ( d, decimalPoint, formatted ) { 12190 var strType = typeof d === 'string'; 12191 12192 // If empty return immediately so there must be a number if it is a 12193 // formatted string (this stops the string "k", or "kr", etc being detected 12194 // as a formatted number for currency 12195 if ( _empty( d ) ) { 12196 return true; 12197 } 12198 12199 if ( decimalPoint && strType ) { 12200 d = _numToDecimal( d, decimalPoint ); 12201 } 12202 12203 if ( formatted && strType ) { 12204 d = d.replace( _re_formatted_numeric, '' ); 12205 } 12206 12207 return !isNaN( parseFloat(d) ) && isFinite( d ); 12208 }; 12209 12210 12211 // A string without HTML in it can be considered to be HTML still 12212 var _isHtml = function ( d ) { 12213 return _empty( d ) || typeof d === 'string'; 12214 }; 12215 12216 12217 var _htmlNumeric = function ( d, decimalPoint, formatted ) { 12218 if ( _empty( d ) ) { 12219 return true; 12220 } 12221 12222 var html = _isHtml( d ); 12223 return ! html ? 12224 null : 12225 _isNumber( _stripHtml( d ), decimalPoint, formatted ) ? 12226 true : 12227 null; 12228 }; 12229 12230 12231 var _pluck = function ( a, prop, prop2 ) { 12232 var out = []; 12233 var i=0, ien=a.length; 12234 12235 // Could have the test in the loop for slightly smaller code, but speed 12236 // is essential here 12237 if ( prop2 !== undefined ) { 12238 for ( ; i<ien ; i++ ) { 12239 if ( a[i] && a[i][ prop ] ) { 12240 out.push( a[i][ prop ][ prop2 ] ); 12241 } 12242 } 12243 } 12244 else { 12245 for ( ; i<ien ; i++ ) { 12246 if ( a[i] ) { 12247 out.push( a[i][ prop ] ); 12248 } 12249 } 12250 } 12251 12252 return out; 12253 }; 12254 12255 12256 // Basically the same as _pluck, but rather than looping over `a` we use `order` 12257 // as the indexes to pick from `a` 12258 var _pluck_order = function ( a, order, prop, prop2 ) 12259 { 12260 var out = []; 12261 var i=0, ien=order.length; 12262 12263 // Could have the test in the loop for slightly smaller code, but speed 12264 // is essential here 12265 if ( prop2 !== undefined ) { 12266 for ( ; i<ien ; i++ ) { 12267 if ( a[ order[i] ][ prop ] ) { 12268 out.push( a[ order[i] ][ prop ][ prop2 ] ); 12269 } 12270 } 12271 } 12272 else { 12273 for ( ; i<ien ; i++ ) { 12274 out.push( a[ order[i] ][ prop ] ); 12275 } 12276 } 12277 12278 return out; 12279 }; 12280 12281 12282 var _range = function ( len, start ) 12283 { 12284 var out = []; 12285 var end; 12286 12287 if ( start === undefined ) { 12288 start = 0; 12289 end = len; 12290 } 12291 else { 12292 end = start; 12293 start = len; 12294 } 12295 12296 for ( var i=start ; i<end ; i++ ) { 12297 out.push( i ); 12298 } 12299 12300 return out; 12301 }; 12302 12303 12304 var _removeEmpty = function ( a ) 12305 { 12306 var out = []; 12307 12308 for ( var i=0, ien=a.length ; i<ien ; i++ ) { 12309 if ( a[i] ) { // careful - will remove all falsy values! 12310 out.push( a[i] ); 12311 } 12312 } 12313 12314 return out; 12315 }; 12316 12317 12318 var _stripHtml = function ( d ) { 12319 return d.replace( _re_html, '' ); 12320 }; 12321 12322 12323 /** 12324 * Find the unique elements in a source array. 12325 * 12326 * @param {array} src Source array 12327 * @return {array} Array of unique items 12328 * @ignore 12329 */ 12330 var _unique = function ( src ) 12331 {
vendor: 25,648 bytes, lines 12332-13241
12332 // A faster unique method is to use object keys to identify used values, 12333 // but this doesn't work with arrays or objects, which we must also 12334 // consider. See jsperf.com/compare-array-unique-versions/4 for more 12335 // information. 12336 var 12337 out = [], 12338 val, 12339 i, ien=src.length, 12340 j, k=0; 12341 12342 again: for ( i=0 ; i<ien ; i++ ) { 12343 val = src[i]; 12344 12345 for ( j=0 ; j<k ; j++ ) { 12346 if ( out[j] === val ) { 12347 continue again; 12348 } 12349 } 12350 12351 out.push( val ); 12352 k++; 12353 } 12354 12355 return out; 12356 }; 12357 12358 12359 /** 12360 * DataTables utility methods 12361 * 12362 * This namespace provides helper methods that DataTables uses internally to 12363 * create a DataTable, but which are not exclusively used only for DataTables. 12364 * These methods can be used by extension authors to save the duplication of 12365 * code. 12366 * 12367 * @namespace 12368 */ 12369 DataTable.util = { 12370 /** 12371 * Throttle the calls to a function. Arguments and context are maintained 12372 * for the throttled function. 12373 * 12374 * @param {function} fn Function to be called 12375 * @param {integer} freq Call frequency in mS 12376 * @return {function} Wrapped function 12377 */ 12378 throttle: function ( fn, freq ) { 12379 var 12380 frequency = freq !== undefined ? freq : 200, 12381 last, 12382 timer; 12383 12384 return function () { 12385 var 12386 that = this, 12387 now = +new Date(), 12388 args = arguments; 12389 12390 if ( last && now < last + frequency ) { 12391 clearTimeout( timer ); 12392 12393 timer = setTimeout( function () { 12394 last = undefined; 12395 fn.apply( that, args ); 12396 }, frequency ); 12397 } 12398 else { 12399 last = now; 12400 fn.apply( that, args ); 12401 } 12402 }; 12403 }, 12404 12405 12406 /** 12407 * Escape a string such that it can be used in a regular expression 12408 * 12409 * @param {string} val string to escape 12410 * @returns {string} escaped string 12411 */ 12412 escapeRegex: function ( val ) { 12413 return val.replace( _re_escape_regex, '\\$1' ); 12414 } 12415 }; 12416 12417 12418 12419 /** 12420 * Create a mapping object that allows camel case parameters to be looked up 12421 * for their Hungarian counterparts. The mapping is stored in a private 12422 * parameter called `_hungarianMap` which can be accessed on the source object. 12423 * @param {object} o 12424 * @memberof DataTable#oApi 12425 */ 12426 function _fnHungarianMap ( o ) 12427 { 12428 var 12429 hungarian = 'a aa ai ao as b fn i m o s ', 12430 match, 12431 newKey, 12432 map = {}; 12433 12434 $.each( o, function (key, val) { 12435 match = key.match(/^([^A-Z]+?)([A-Z])/); 12436 12437 if ( match && hungarian.indexOf(match[1]+' ') !== -1 ) 12438 { 12439 newKey = key.replace( match[0], match[2].toLowerCase() ); 12440 map[ newKey ] = key; 12441 12442 if ( match[1] === 'o' ) 12443 { 12444 _fnHungarianMap( o[key] ); 12445 } 12446 } 12447 } ); 12448 12449 o._hungarianMap = map; 12450 } 12451 12452 12453 /** 12454 * Convert from camel case parameters to Hungarian, based on a Hungarian map 12455 * created by _fnHungarianMap. 12456 * @param {object} src The model object which holds all parameters that can be 12457 * mapped. 12458 * @param {object} user The object to convert from camel case to Hungarian. 12459 * @param {boolean} force When set to `true`, properties which already have a 12460 * Hungarian value in the `user` object will be overwritten. Otherwise they 12461 * won't be. 12462 * @memberof DataTable#oApi 12463 */ 12464 function _fnCamelToHungarian ( src, user, force ) 12465 { 12466 if ( ! src._hungarianMap ) { 12467 _fnHungarianMap( src ); 12468 } 12469 12470 var hungarianKey; 12471 12472 $.each( user, function (key, val) { 12473 hungarianKey = src._hungarianMap[ key ]; 12474 12475 if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) ) 12476 { 12477 // For objects, we need to buzz down into the object to copy parameters 12478 if ( hungarianKey.charAt(0) === 'o' ) 12479 { 12480 // Copy the camelCase options over to the hungarian 12481 if ( ! user[ hungarianKey ] ) { 12482 user[ hungarianKey ] = {}; 12483 } 12484 $.extend( true, user[hungarianKey], user[key] ); 12485 12486 _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force ); 12487 } 12488 else { 12489 user[hungarianKey] = user[ key ]; 12490 } 12491 } 12492 } ); 12493 } 12494 12495 12496 /** 12497 * Language compatibility - when certain options are given, and others aren't, we 12498 * need to duplicate the values over, in order to provide backwards compatibility 12499 * with older language files. 12500 * @param {object} oSettings dataTables settings object 12501 * @memberof DataTable#oApi 12502 */ 12503 function _fnLanguageCompat( lang ) 12504 { 12505 var defaults = DataTable.defaults.oLanguage; 12506 var zeroRecords = lang.sZeroRecords; 12507 12508 /* Backwards compatibility - if there is no sEmptyTable given, then use the same as 12509 * sZeroRecords - assuming that is given. 12510 */ 12511 if ( ! lang.sEmptyTable && zeroRecords && 12512 defaults.sEmptyTable === "No data available in table" ) 12513 { 12514 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' ); 12515 } 12516 12517 /* Likewise with loading records */ 12518 if ( ! lang.sLoadingRecords && zeroRecords && 12519 defaults.sLoadingRecords === "Loading..." ) 12520 { 12521 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' ); 12522 } 12523 12524 // Old parameter name of the thousands separator mapped onto the new 12525 if ( lang.sInfoThousands ) { 12526 lang.sThousands = lang.sInfoThousands; 12527 } 12528 12529 var decimal = lang.sDecimal; 12530 if ( decimal ) { 12531 _addNumericSort( decimal ); 12532 } 12533 } 12534 12535 12536 /** 12537 * Map one parameter onto another 12538 * @param {object} o Object to map 12539 * @param {*} knew The new parameter name 12540 * @param {*} old The old parameter name 12541 */ 12542 var _fnCompatMap = function ( o, knew, old ) { 12543 if ( o[ knew ] !== undefined ) { 12544 o[ old ] = o[ knew ]; 12545 } 12546 }; 12547 12548 12549 /** 12550 * Provide backwards compatibility for the main DT options. Note that the new 12551 * options are mapped onto the old parameters, so this is an external interface 12552 * change only. 12553 * @param {object} init Object to map 12554 */ 12555 function _fnCompatOpts ( init ) 12556 { 12557 _fnCompatMap( init, 'ordering', 'bSort' ); 12558 _fnCompatMap( init, 'orderMulti', 'bSortMulti' ); 12559 _fnCompatMap( init, 'orderClasses', 'bSortClasses' ); 12560 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' ); 12561 _fnCompatMap( init, 'order', 'aaSorting' ); 12562 _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' ); 12563 _fnCompatMap( init, 'paging', 'bPaginate' ); 12564 _fnCompatMap( init, 'pagingType', 'sPaginationType' ); 12565 _fnCompatMap( init, 'pageLength', 'iDisplayLength' ); 12566 _fnCompatMap( init, 'searching', 'bFilter' ); 12567 12568 // Boolean initialisation of x-scrolling 12569 if ( typeof init.sScrollX === 'boolean' ) { 12570 init.sScrollX = init.sScrollX ? '100%' : ''; 12571 } 12572 if ( typeof init.scrollX === 'boolean' ) { 12573 init.scrollX = init.scrollX ? '100%' : ''; 12574 } 12575 12576 // Column search objects are in an array, so it needs to be converted 12577 // element by element 12578 var searchCols = init.aoSearchCols; 12579 12580 if ( searchCols ) { 12581 for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) { 12582 if ( searchCols[i] ) { 12583 _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] ); 12584 } 12585 } 12586 } 12587 } 12588 12589 12590 /** 12591 * Provide backwards compatibility for column options. Note that the new options 12592 * are mapped onto the old parameters, so this is an external interface change 12593 * only. 12594 * @param {object} init Object to map 12595 */ 12596 function _fnCompatCols ( init ) 12597 { 12598 _fnCompatMap( init, 'orderable', 'bSortable' ); 12599 _fnCompatMap( init, 'orderData', 'aDataSort' ); 12600 _fnCompatMap( init, 'orderSequence', 'asSorting' ); 12601 _fnCompatMap( init, 'orderDataType', 'sortDataType' ); 12602 12603 // orderData can be given as an integer 12604 var dataSort = init.aDataSort; 12605 if ( dataSort && ! $.isArray( dataSort ) ) { 12606 init.aDataSort = [ dataSort ]; 12607 } 12608 } 12609 12610 12611 /** 12612 * Browser feature detection for capabilities, quirks 12613 * @param {object} settings dataTables settings object 12614 * @memberof DataTable#oApi 12615 */ 12616 function _fnBrowserDetect( settings ) 12617 { 12618 // We don't need to do this every time DataTables is constructed, the values 12619 // calculated are specific to the browser and OS configuration which we 12620 // don't expect to change between initialisations 12621 if ( ! DataTable.__browser ) { 12622 var browser = {}; 12623 DataTable.__browser = browser; 12624 12625 // Scrolling feature / quirks detection 12626 var n = $('<div/>') 12627 .css( { 12628 position: 'fixed', 12629 top: 0, 12630 left: 0, 12631 height: 1, 12632 width: 1, 12633 overflow: 'hidden' 12634 } ) 12635 .append( 12636 $('<div/>') 12637 .css( { 12638 position: 'absolute', 12639 top: 1, 12640 left: 1, 12641 width: 100, 12642 overflow: 'scroll' 12643 } ) 12644 .append( 12645 $('<div/>') 12646 .css( { 12647 width: '100%', 12648 height: 10 12649 } ) 12650 ) 12651 ) 12652 .appendTo( 'body' ); 12653 12654 var outer = n.children(); 12655 var inner = outer.children(); 12656 12657 // Numbers below, in order, are: 12658 // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth 12659 // 12660 // IE6 XP: 100 100 100 83 12661 // IE7 Vista: 100 100 100 83 12662 // IE 8+ Windows: 83 83 100 83 12663 // Evergreen Windows: 83 83 100 83 12664 // Evergreen Mac with scrollbars: 85 85 100 85 12665 // Evergreen Mac without scrollbars: 100 100 100 100 12666 12667 // Get scrollbar width 12668 browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth; 12669 12670 // IE6/7 will oversize a width 100% element inside a scrolling element, to 12671 // include the width of the scrollbar, while other browsers ensure the inner 12672 // element is contained without forcing scrolling 12673 browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100; 12674 12675 // In rtl text layout, some browsers (most, but not all) will place the 12676 // scrollbar on the left, rather than the right. 12677 browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1; 12678 12679 // IE8- don't provide height and width for getBoundingClientRect 12680 browser.bBounding = n[0].getBoundingClientRect().width ? true : false; 12681 12682 n.remove(); 12683 } 12684 12685 $.extend( settings.oBrowser, DataTable.__browser ); 12686 settings.oScroll.iBarWidth = DataTable.__browser.barWidth; 12687 } 12688 12689 12690 /** 12691 * Array.prototype reduce[Right] method, used for browsers which don't support 12692 * JS 1.6. Done this way to reduce code size, since we iterate either way 12693 * @param {object} settings dataTables settings object 12694 * @memberof DataTable#oApi 12695 */ 12696 function _fnReduce ( that, fn, init, start, end, inc ) 12697 { 12698 var 12699 i = start, 12700 value, 12701 isSet = false; 12702 12703 if ( init !== undefined ) { 12704 value = init; 12705 isSet = true; 12706 } 12707 12708 while ( i !== end ) { 12709 if ( ! that.hasOwnProperty(i) ) { 12710 continue; 12711 } 12712 12713 value = isSet ? 12714 fn( value, that[i], i, that ) : 12715 that[i]; 12716 12717 isSet = true; 12718 i += inc; 12719 } 12720 12721 return value; 12722 } 12723 12724 /** 12725 * Add a column to the list used for the table with default values 12726 * @param {object} oSettings dataTables settings object 12727 * @param {node} nTh The th element for this column 12728 * @memberof DataTable#oApi 12729 */ 12730 function _fnAddColumn( oSettings, nTh ) 12731 { 12732 // Add column to aoColumns array 12733 var oDefaults = DataTable.defaults.column; 12734 var iCol = oSettings.aoColumns.length; 12735 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, { 12736 "nTh": nTh ? nTh : document.createElement('th'), 12737 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '', 12738 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol], 12739 "mData": oDefaults.mData ? oDefaults.mData : iCol, 12740 idx: iCol 12741 } ); 12742 oSettings.aoColumns.push( oCol ); 12743 12744 // Add search object for column specific search. Note that the `searchCols[ iCol ]` 12745 // passed into extend can be undefined. This allows the user to give a default 12746 // with only some of the parameters defined, and also not give a default 12747 var searchCols = oSettings.aoPreSearchCols; 12748 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] ); 12749 12750 // Use the default column options function to initialise classes etc 12751 _fnColumnOptions( oSettings, iCol, $(nTh).data() ); 12752 } 12753 12754 12755 /** 12756 * Apply options for a column 12757 * @param {object} oSettings dataTables settings object 12758 * @param {int} iCol column index to consider 12759 * @param {object} oOptions object with sType, bVisible and bSearchable etc 12760 * @memberof DataTable#oApi 12761 */ 12762 function _fnColumnOptions( oSettings, iCol, oOptions ) 12763 { 12764 var oCol = oSettings.aoColumns[ iCol ]; 12765 var oClasses = oSettings.oClasses; 12766 var th = $(oCol.nTh); 12767 12768 // Try to get width information from the DOM. We can't get it from CSS 12769 // as we'd need to parse the CSS stylesheet. `width` option can override 12770 if ( ! oCol.sWidthOrig ) { 12771 // Width attribute 12772 oCol.sWidthOrig = th.attr('width') || null; 12773 12774 // Style attribute 12775 var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/); 12776 if ( t ) { 12777 oCol.sWidthOrig = t[1]; 12778 } 12779 } 12780 12781 /* User specified column options */ 12782 if ( oOptions !== undefined && oOptions !== null ) 12783 { 12784 // Backwards compatibility 12785 _fnCompatCols( oOptions ); 12786 12787 // Map camel case parameters to their Hungarian counterparts 12788 _fnCamelToHungarian( DataTable.defaults.column, oOptions ); 12789 12790 /* Backwards compatibility for mDataProp */ 12791 if ( oOptions.mDataProp !== undefined && !oOptions.mData ) 12792 { 12793 oOptions.mData = oOptions.mDataProp; 12794 } 12795 12796 if ( oOptions.sType ) 12797 { 12798 oCol._sManualType = oOptions.sType; 12799 } 12800 12801 // `class` is a reserved word in Javascript, so we need to provide 12802 // the ability to use a valid name for the camel case input 12803 if ( oOptions.className && ! oOptions.sClass ) 12804 { 12805 oOptions.sClass = oOptions.className; 12806 } 12807 12808 $.extend( oCol, oOptions ); 12809 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" ); 12810 12811 /* iDataSort to be applied (backwards compatibility), but aDataSort will take 12812 * priority if defined 12813 */ 12814 if ( oOptions.iDataSort !== undefined ) 12815 { 12816 oCol.aDataSort = [ oOptions.iDataSort ]; 12817 } 12818 _fnMap( oCol, oOptions, "aDataSort" ); 12819 } 12820 12821 /* Cache the data get and set functions for speed */ 12822 var mDataSrc = oCol.mData; 12823 var mData = _fnGetObjectDataFn( mDataSrc ); 12824 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null; 12825 12826 var attrTest = function( src ) { 12827 return typeof src === 'string' && src.indexOf('@') !== -1; 12828 }; 12829 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && ( 12830 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter) 12831 ); 12832 oCol._setter = null; 12833 12834 oCol.fnGetData = function (rowData, type, meta) { 12835 var innerData = mData( rowData, type, undefined, meta ); 12836 12837 return mRender && type ? 12838 mRender( innerData, type, rowData, meta ) : 12839 innerData; 12840 }; 12841 oCol.fnSetData = function ( rowData, val, meta ) { 12842 return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta ); 12843 }; 12844 12845 // Indicate if DataTables should read DOM data as an object or array 12846 // Used in _fnGetRowElements 12847 if ( typeof mDataSrc !== 'number' ) { 12848 oSettings._rowReadObject = true; 12849 } 12850 12851 /* Feature sorting overrides column specific when off */ 12852 if ( !oSettings.oFeatures.bSort ) 12853 { 12854 oCol.bSortable = false; 12855 th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called 12856 } 12857 12858 /* Check that the class assignment is correct for sorting */ 12859 var bAsc = $.inArray('asc', oCol.asSorting) !== -1; 12860 var bDesc = $.inArray('desc', oCol.asSorting) !== -1; 12861 if ( !oCol.bSortable || (!bAsc && !bDesc) ) 12862 { 12863 oCol.sSortingClass = oClasses.sSortableNone; 12864 oCol.sSortingClassJUI = ""; 12865 } 12866 else if ( bAsc && !bDesc ) 12867 { 12868 oCol.sSortingClass = oClasses.sSortableAsc; 12869 oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed; 12870 } 12871 else if ( !bAsc && bDesc ) 12872 { 12873 oCol.sSortingClass = oClasses.sSortableDesc; 12874 oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed; 12875 } 12876 else 12877 { 12878 oCol.sSortingClass = oClasses.sSortable; 12879 oCol.sSortingClassJUI = oClasses.sSortJUI; 12880 } 12881 } 12882 12883 12884 /** 12885 * Adjust the table column widths for new data. Note: you would probably want to 12886 * do a redraw after calling this function! 12887 * @param {object} settings dataTables settings object 12888 * @memberof DataTable#oApi 12889 */ 12890 function _fnAdjustColumnSizing ( settings ) 12891 { 12892 /* Not interested in doing column width calculation if auto-width is disabled */ 12893 if ( settings.oFeatures.bAutoWidth !== false ) 12894 { 12895 var columns = settings.aoColumns; 12896 12897 _fnCalculateColumnWidths( settings ); 12898 for ( var i=0 , iLen=columns.length ; i<iLen ; i++ ) 12899 { 12900 columns[i].nTh.style.width = columns[i].sWidth; 12901 } 12902 } 12903 12904 var scroll = settings.oScroll; 12905 if ( scroll.sY !== '' || scroll.sX !== '') 12906 { 12907 _fnScrollDraw( settings ); 12908 } 12909 12910 _fnCallbackFire( settings, null, 'column-sizing', [settings] ); 12911 } 12912 12913 12914 /** 12915 * Covert the index of a visible column to the index in the data array (take account 12916 * of hidden columns) 12917 * @param {object} oSettings dataTables settings object 12918 * @param {int} iMatch Visible column index to lookup 12919 * @returns {int} i the data index 12920 * @memberof DataTable#oApi 12921 */ 12922 function _fnVisibleToColumnIndex( oSettings, iMatch ) 12923 { 12924 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); 12925 12926 return typeof aiVis[iMatch] === 'number' ? 12927 aiVis[iMatch] : 12928 null; 12929 } 12930 12931 12932 /** 12933 * Covert the index of an index in the data array and convert it to the visible 12934 * column index (take account of hidden columns) 12935 * @param {int} iMatch Column index to lookup 12936 * @param {object} oSettings dataTables settings object 12937 * @returns {int} i the data index 12938 * @memberof DataTable#oApi 12939 */ 12940 function _fnColumnIndexToVisible( oSettings, iMatch ) 12941 { 12942 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); 12943 var iPos = $.inArray( iMatch, aiVis ); 12944 12945 return iPos !== -1 ? iPos : null; 12946 } 12947 12948 12949 /** 12950 * Get the number of visible columns 12951 * @param {object} oSettings dataTables settings object 12952 * @returns {int} i the number of visible columns 12953 * @memberof DataTable#oApi 12954 */ 12955 function _fnVisbleColumns( oSettings ) 12956 { 12957 var vis = 0; 12958 12959 // No reduce in IE8, use a loop for now 12960 $.each( oSettings.aoColumns, function ( i, col ) { 12961 if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) { 12962 vis++; 12963 } 12964 } ); 12965 12966 return vis; 12967 } 12968 12969 12970 /** 12971 * Get an array of column indexes that match a given property 12972 * @param {object} oSettings dataTables settings object 12973 * @param {string} sParam Parameter in aoColumns to look for - typically 12974 * bVisible or bSearchable 12975 * @returns {array} Array of indexes with matched properties 12976 * @memberof DataTable#oApi 12977 */ 12978 function _fnGetColumns( oSettings, sParam ) 12979 { 12980 var a = []; 12981 12982 $.map( oSettings.aoColumns, function(val, i) { 12983 if ( val[sParam] ) { 12984 a.push( i ); 12985 } 12986 } ); 12987 12988 return a; 12989 } 12990 12991 12992 /** 12993 * Calculate the 'type' of a column 12994 * @param {object} settings dataTables settings object 12995 * @memberof DataTable#oApi 12996 */ 12997 function _fnColumnTypes ( settings ) 12998 { 12999 var columns = settings.aoColumns; 13000 var data = settings.aoData; 13001 var types = DataTable.ext.type.detect; 13002 var i, ien, j, jen, k, ken; 13003 var col, cell, detectedType, cache; 13004 13005 // For each column, spin over the 13006 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 13007 col = columns[i]; 13008 cache = []; 13009 13010 if ( ! col.sType && col._sManualType ) { 13011 col.sType = col._sManualType; 13012 } 13013 else if ( ! col.sType ) { 13014 for ( j=0, jen=types.length ; j<jen ; j++ ) { 13015 for ( k=0, ken=data.length ; k<ken ; k++ ) { 13016 // Use a cache array so we only need to get the type data 13017 // from the formatter once (when using multiple detectors) 13018 if ( cache[k] === undefined ) { 13019 cache[k] = _fnGetCellData( settings, k, i, 'type' ); 13020 } 13021 13022 detectedType = types[j]( cache[k], settings ); 13023 13024 // If null, then this type can't apply to this column, so 13025 // rather than testing all cells, break out. There is an 13026 // exception for the last type which is `html`. We need to 13027 // scan all rows since it is possible to mix string and HTML 13028 // types 13029 if ( ! detectedType && j !== types.length-1 ) { 13030 break; 13031 } 13032 13033 // Only a single match is needed for html type since it is 13034 // bottom of the pile and very similar to string 13035 if ( detectedType === 'html' ) { 13036 break; 13037 } 13038 } 13039 13040 // Type is valid for all data points in the column - use this 13041 // type 13042 if ( detectedType ) { 13043 col.sType = detectedType; 13044 break; 13045 } 13046 } 13047 13048 // Fall back - if no type was detected, always use string 13049 if ( ! col.sType ) { 13050 col.sType = 'string'; 13051 } 13052 } 13053 } 13054 } 13055 13056 13057 /** 13058 * Take the column definitions and static columns arrays and calculate how 13059 * they relate to column indexes. The callback function will then apply the 13060 * definition found for a column to a suitable configuration object. 13061 * @param {object} oSettings dataTables settings object 13062 * @param {array} aoColDefs The aoColumnDefs array that is to be applied 13063 * @param {array} aoCols The aoColumns array that defines columns individually 13064 * @param {function} fn Callback function - takes two parameters, the calculated 13065 * column index and the definition for that column. 13066 * @memberof DataTable#oApi 13067 */ 13068 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn ) 13069 { 13070 var i, iLen, j, jLen, k, kLen, def; 13071 var columns = oSettings.aoColumns; 13072 13073 // Column definitions with aTargets 13074 if ( aoColDefs ) 13075 { 13076 /* Loop over the definitions array - loop in reverse so first instance has priority */ 13077 for ( i=aoColDefs.length-1 ; i>=0 ; i-- ) 13078 { 13079 def = aoColDefs[i]; 13080 13081 /* Each definition can target multiple columns, as it is an array */ 13082 var aTargets = def.targets !== undefined ? 13083 def.targets : 13084 def.aTargets; 13085 13086 if ( ! $.isArray( aTargets ) ) 13087 { 13088 aTargets = [ aTargets ]; 13089 } 13090 13091 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ ) 13092 { 13093 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 ) 13094 { 13095 /* Add columns that we don't yet know about */ 13096 while( columns.length <= aTargets[j] ) 13097 { 13098 _fnAddColumn( oSettings ); 13099 } 13100 13101 /* Integer, basic index */ 13102 fn( aTargets[j], def ); 13103 } 13104 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 ) 13105 { 13106 /* Negative integer, right to left column counting */ 13107 fn( columns.length+aTargets[j], def ); 13108 } 13109 else if ( typeof aTargets[j] === 'string' ) 13110 { 13111 /* Class name matching on TH element */ 13112 for ( k=0, kLen=columns.length ; k<kLen ; k++ ) 13113 { 13114 if ( aTargets[j] == "_all" || 13115 $(columns[k].nTh).hasClass( aTargets[j] ) ) 13116 { 13117 fn( k, def ); 13118 } 13119 } 13120 } 13121 } 13122 } 13123 } 13124 13125 // Statically defined columns array 13126 if ( aoCols ) 13127 { 13128 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) 13129 { 13130 fn( i, aoCols[i] ); 13131 } 13132 } 13133 } 13134 13135 /** 13136 * Add a data array to the table, creating DOM node etc. This is the parallel to 13137 * _fnGatherData, but for adding rows from a Javascript source, rather than a 13138 * DOM source. 13139 * @param {object} oSettings dataTables settings object 13140 * @param {array} aData data array to be added 13141 * @param {node} [nTr] TR element to add to the table - optional. If not given, 13142 * DataTables will create a row automatically 13143 * @param {array} [anTds] Array of TD|TH elements for the row - must be given 13144 * if nTr is. 13145 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed 13146 * @memberof DataTable#oApi 13147 */ 13148 function _fnAddData ( oSettings, aDataIn, nTr, anTds ) 13149 { 13150 /* Create the object for storing information about this new row */ 13151 var iRow = oSettings.aoData.length; 13152 var oData = $.extend( true, {}, DataTable.models.oRow, { 13153 src: nTr ? 'dom' : 'data', 13154 idx: iRow 13155 } ); 13156 13157 oData._aData = aDataIn; 13158 oSettings.aoData.push( oData ); 13159 13160 /* Create the cells */ 13161 var nTd, sThisType; 13162 var columns = oSettings.aoColumns; 13163 13164 // Invalidate the column types as the new data needs to be revalidated 13165 for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) 13166 { 13167 columns[i].sType = null; 13168 } 13169 13170 /* Add to the display array */ 13171 oSettings.aiDisplayMaster.push( iRow ); 13172 13173 var id = oSettings.rowIdFn( aDataIn ); 13174 if ( id !== undefined ) { 13175 oSettings.aIds[ id ] = oData; 13176 } 13177 13178 /* Create the DOM information, or register it if already present */ 13179 if ( nTr || ! oSettings.oFeatures.bDeferRender ) 13180 { 13181 _fnCreateTr( oSettings, iRow, nTr, anTds ); 13182 } 13183 13184 return iRow; 13185 } 13186 13187 13188 /** 13189 * Add one or more TR elements to the table. Generally we'd expect to 13190 * use this for reading data from a DOM sourced table, but it could be 13191 * used for an TR element. Note that if a TR is given, it is used (i.e. 13192 * it is not cloned). 13193 * @param {object} settings dataTables settings object 13194 * @param {array|node|jQuery} trs The TR element(s) to add to the table 13195 * @returns {array} Array of indexes for the added rows 13196 * @memberof DataTable#oApi 13197 */ 13198 function _fnAddTr( settings, trs ) 13199 { 13200 var row; 13201 13202 // Allow an individual node to be passed in 13203 if ( ! (trs instanceof $) ) { 13204 trs = $(trs); 13205 } 13206 13207 return trs.map( function (i, el) { 13208 row = _fnGetRowElements( settings, el ); 13209 return _fnAddData( settings, row.data, el, row.cells ); 13210 } ); 13211 } 13212 13213 13214 /** 13215 * Take a TR element and convert it to an index in aoData 13216 * @param {object} oSettings dataTables settings object 13217 * @param {node} n the TR element to find 13218 * @returns {int} index if the node is found, null if not 13219 * @memberof DataTable#oApi 13220 */ 13221 function _fnNodeToDataIndex( oSettings, n ) 13222 { 13223 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null; 13224 } 13225 13226 13227 /** 13228 * Take a TD element and convert it into a column data index (not the visible index) 13229 * @param {object} oSettings dataTables settings object 13230 * @param {int} iRow The row number the TD/TH can be found in 13231 * @param {node} n The TD/TH element to find 13232 * @returns {int} index if the node is found, -1 if not 13233 * @memberof DataTable#oApi 13234 */ 13235 function _fnNodeToColumnIndex( oSettings, iRow, n ) 13236 { 13237 return $.inArray( n, oSettings.aoData[ iRow ].anCells ); 13238 } 13239 13240 13241 /**
13242 * Get the data for a given cell from the internal cache, taking into account data mapping 13243 * @param {object} settings dataTables settings object 13244 * @param {int} rowIdx aoData row id 13245 * @param {int} colIdx Column index 13246 * @param {string} type data get type ('display', 'type' 'filter' 'sort') 13247 * @returns {*} Cell data 13248 * @memberof DataTable#oApi 13249 */ 13250 function _fnGetCellData( settings, rowIdx, colIdx, type ) 13251 { 13252 var draw = settings.iDraw; 13253 var col = settings.aoColumns[colIdx]; 13254 var rowData = settings.aoData[rowIdx]._aData; 13255 var defaultContent = col.sDefaultContent; 13256 var cellData = col.fnGetData( rowData, type, { 13257 settings: settings, 13258 row: rowIdx, 13259 col: colIdx 13260 } ); 13261 13262 if ( cellData === undefined ) { 13263 if ( settings.iDrawError != draw && defaultContent === null ) { 13264 _fnLog( settings, 0, "Requested unknown parameter "+ 13265 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+ 13266 " for row "+rowIdx+", column "+colIdx, 4 ); 13267 settings.iDrawError = draw; 13268 } 13269 return defaultContent; 13270 } 13271 13272 // When the data source is null and a specific data type is requested (i.e. 13273 // not the original data), we can use default column data 13274 if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) { 13275 cellData = defaultContent; 13276 } 13277 else if ( typeof cellData === 'function' ) { 13278 // If the data source is a function, then we run it and use the return, 13279 // executing in the scope of the data object (for instances) 13280 return cellData.call( rowData ); 13281 } 13282 13283 if ( cellData === null && type == 'display' ) { 13284 return ''; 13285 } 13286 return cellData; 13287 } 13288 13289 13290 /** 13291 * Set the value for a specific cell, into the internal data cache 13292 * @param {object} settings dataTables settings object 13293 * @param {int} rowIdx aoData row id 13294 * @param {int} colIdx Column index 13295 * @param {*} val Value to set 13296 * @memberof DataTable#oApi 13297 */ 13298 function _fnSetCellData( settings, rowIdx, colIdx, val ) 13299 { 13300 var col = settings.aoColumns[colIdx]; 13301 var rowData = settings.aoData[rowIdx]._aData; 13302 13303 col.fnSetData( rowData, val, { 13304 settings: settings, 13305 row: rowIdx, 13306 col: colIdx 13307 } ); 13308 } 13309 13310 13311 // Private variable that is used to match action syntax in the data property object 13312 var __reArray = /\[.*?\]$/; 13313 var __reFn = /\(\)$/; 13314 13315 /** 13316 * Split string on periods, taking into account escaped periods 13317 * @param {string} str String to split 13318 * @return {array} Split string 13319 */ 13320 function _fnSplitObjNotation( str ) 13321 { 13322 return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) { 13323 return s.replace(/\\./g, '.'); 13324 } ); 13325 } 13326 13327 13328 /** 13329 * Return a function that can be used to get data from a source object, taking 13330 * into account the ability to use nested objects as a source 13331 * @param {string|int|function} mSource The data source for the object 13332 * @returns {function} Data get function 13333 * @memberof DataTable#oApi 13334 */ 13335 function _fnGetObjectDataFn( mSource ) 13336 { 13337 if ( $.isPlainObject( mSource ) ) 13338 { 13339 /* Build an object of get functions, and wrap them in a single call */ 13340 var o = {}; 13341 $.each( mSource, function (key, val) { 13342 if ( val ) { 13343 o[key] = _fnGetObjectDataFn( val ); 13344 } 13345 } ); 13346 13347 return function (data, type, row, meta) { 13348 var t = o[type] || o._; 13349 return t !== undefined ? 13350 t(data, type, row, meta) : 13351 data; 13352 }; 13353 } 13354 else if ( mSource === null ) 13355 { 13356 /* Give an empty string for rendering / sorting etc */ 13357 return function (data) { // type, row and meta also passed, but not used 13358 return data; 13359 }; 13360 } 13361 else if ( typeof mSource === 'function' ) 13362 { 13363 return function (data, type, row, meta) { 13364 return mSource( data, type, row, meta ); 13365 }; 13366 } 13367 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || 13368 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) ) 13369 { 13370 /* If there is a . in the source string then the data source is in a 13371 * nested object so we loop over the data for each level to get the next 13372 * level down. On each loop we test for undefined, and if found immediately 13373 * return. This allows entire objects to be missing and sDefaultContent to 13374 * be used if defined, rather than throwing an error 13375 */
vendor: 6,769 bytes, lines 13376-13629
13376 var fetchData = function (data, type, src) { 13377 var arrayNotation, funcNotation, out, innerSrc; 13378 13379 if ( src !== "" ) 13380 { 13381 var a = _fnSplitObjNotation( src ); 13382 13383 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) 13384 { 13385 // Check if we are dealing with special notation 13386 arrayNotation = a[i].match(__reArray); 13387 funcNotation = a[i].match(__reFn); 13388 13389 if ( arrayNotation ) 13390 { 13391 // Array notation 13392 a[i] = a[i].replace(__reArray, ''); 13393 13394 // Condition allows simply [] to be passed in 13395 if ( a[i] !== "" ) { 13396 data = data[ a[i] ]; 13397 } 13398 out = []; 13399 13400 // Get the remainder of the nested object to get 13401 a.splice( 0, i+1 ); 13402 innerSrc = a.join('.'); 13403 13404 // Traverse each entry in the array getting the properties requested 13405 if ( $.isArray( data ) ) { 13406 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) { 13407 out.push( fetchData( data[j], type, innerSrc ) ); 13408 } 13409 } 13410 13411 // If a string is given in between the array notation indicators, that 13412 // is used to join the strings together, otherwise an array is returned 13413 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1); 13414 data = (join==="") ? out : out.join(join); 13415 13416 // The inner call to fetchData has already traversed through the remainder 13417 // of the source requested, so we exit from the loop 13418 break; 13419 } 13420 else if ( funcNotation ) 13421 { 13422 // Function call 13423 a[i] = a[i].replace(__reFn, ''); 13424 data = data[ a[i] ](); 13425 continue; 13426 } 13427 13428 if ( data === null || data[ a[i] ] === undefined ) 13429 { 13430 return undefined; 13431 } 13432 data = data[ a[i] ]; 13433 } 13434 } 13435 13436 return data; 13437 }; 13438 13439 return function (data, type) { // row and meta also passed, but not used 13440 return fetchData( data, type, mSource ); 13441 }; 13442 } 13443 else 13444 { 13445 /* Array or flat object mapping */ 13446 return function (data, type) { // row and meta also passed, but not used 13447 return data[mSource]; 13448 }; 13449 } 13450 } 13451 13452 13453 /** 13454 * Return a function that can be used to set data from a source object, taking 13455 * into account the ability to use nested objects as a source 13456 * @param {string|int|function} mSource The data source for the object 13457 * @returns {function} Data set function 13458 * @memberof DataTable#oApi 13459 */ 13460 function _fnSetObjectDataFn( mSource ) 13461 { 13462 if ( $.isPlainObject( mSource ) ) 13463 { 13464 /* Unlike get, only the underscore (global) option is used for for 13465 * setting data since we don't know the type here. This is why an object 13466 * option is not documented for `mData` (which is read/write), but it is 13467 * for `mRender` which is read only. 13468 */ 13469 return _fnSetObjectDataFn( mSource._ ); 13470 } 13471 else if ( mSource === null ) 13472 { 13473 /* Nothing to do when the data source is null */ 13474 return function () {}; 13475 } 13476 else if ( typeof mSource === 'function' ) 13477 { 13478 return function (data, val, meta) { 13479 mSource( data, 'set', val, meta ); 13480 }; 13481 } 13482 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || 13483 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) ) 13484 { 13485 /* Like the get, we need to get data from a nested object */ 13486 var setData = function (data, val, src) { 13487 var a = _fnSplitObjNotation( src ), b; 13488 var aLast = a[a.length-1]; 13489 var arrayNotation, funcNotation, o, innerSrc; 13490 13491 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) 13492 { 13493 // Check if we are dealing with an array notation request 13494 arrayNotation = a[i].match(__reArray); 13495 funcNotation = a[i].match(__reFn); 13496 13497 if ( arrayNotation ) 13498 { 13499 a[i] = a[i].replace(__reArray, ''); 13500 data[ a[i] ] = []; 13501 13502 // Get the remainder of the nested object to set so we can recurse 13503 b = a.slice(); 13504 b.splice( 0, i+1 ); 13505 innerSrc = b.join('.'); 13506 13507 // Traverse each entry in the array setting the properties requested 13508 if ( $.isArray( val ) ) 13509 { 13510 for ( var j=0, jLen=val.length ; j<jLen ; j++ ) 13511 { 13512 o = {}; 13513 setData( o, val[j], innerSrc ); 13514 data[ a[i] ].push( o ); 13515 } 13516 } 13517 else 13518 { 13519 // We've been asked to save data to an array, but it 13520 // isn't array data to be saved. Best that can be done 13521 // is to just save the value. 13522 data[ a[i] ] = val; 13523 } 13524 13525 // The inner call to setData has already traversed through the remainder 13526 // of the source and has set the data, thus we can exit here 13527 return; 13528 } 13529 else if ( funcNotation ) 13530 { 13531 // Function call 13532 a[i] = a[i].replace(__reFn, ''); 13533 data = data[ a[i] ]( val ); 13534 } 13535 13536 // If the nested object doesn't currently exist - since we are 13537 // trying to set the value - create it 13538 if ( data[ a[i] ] === null || data[ a[i] ] === undefined ) 13539 { 13540 data[ a[i] ] = {}; 13541 } 13542 data = data[ a[i] ]; 13543 } 13544 13545 // Last item in the input - i.e, the actual set 13546 if ( aLast.match(__reFn ) ) 13547 { 13548 // Function call 13549 data = data[ aLast.replace(__reFn, '') ]( val ); 13550 } 13551 else 13552 { 13553 // If array notation is used, we just want to strip it and use the property name 13554 // and assign the value. If it isn't used, then we get the result we want anyway 13555 data[ aLast.replace(__reArray, '') ] = val; 13556 } 13557 }; 13558 13559 return function (data, val) { // meta is also passed in, but not used 13560 return setData( data, val, mSource ); 13561 }; 13562 } 13563 else 13564 { 13565 /* Array or flat object mapping */ 13566 return function (data, val) { // meta is also passed in, but not used 13567 data[mSource] = val; 13568 }; 13569 } 13570 } 13571 13572 13573 /** 13574 * Return an array with the full table data 13575 * @param {object} oSettings dataTables settings object 13576 * @returns array {array} aData Master data array 13577 * @memberof DataTable#oApi 13578 */ 13579 function _fnGetDataMaster ( settings ) 13580 { 13581 return _pluck( settings.aoData, '_aData' ); 13582 } 13583 13584 13585 /** 13586 * Nuke the table 13587 * @param {object} oSettings dataTables settings object 13588 * @memberof DataTable#oApi 13589 */ 13590 function _fnClearTable( settings ) 13591 { 13592 settings.aoData.length = 0; 13593 settings.aiDisplayMaster.length = 0; 13594 settings.aiDisplay.length = 0; 13595 settings.aIds = {}; 13596 } 13597 13598 13599 /** 13600 * Take an array of integers (index array) and remove a target integer (value - not 13601 * the key!) 13602 * @param {array} a Index array to target 13603 * @param {int} iTarget value to find 13604 * @memberof DataTable#oApi 13605 */ 13606 function _fnDeleteIndex( a, iTarget, splice ) 13607 { 13608 var iTargetIndex = -1; 13609 13610 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) 13611 { 13612 if ( a[i] == iTarget ) 13613 { 13614 iTargetIndex = i; 13615 } 13616 else if ( a[i] > iTarget ) 13617 { 13618 a[i]--; 13619 } 13620 } 13621 13622 if ( iTargetIndex != -1 && splice === undefined ) 13623 { 13624 a.splice( iTargetIndex, 1 ); 13625 } 13626 } 13627 13628 13629 /**
13630 * Mark cached data as invalid such that a re-read of the data will occur when 13631 * the cached data is next requested. Also update from the data source object. 13632 * 13633 * @param {object} settings DataTables settings object 13634 * @param {int} rowIdx Row index to invalidate 13635 * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom' 13636 * or 'data' 13637 * @param {int} [colIdx] Column index to invalidate. If undefined the whole 13638 * row will be invalidated 13639 * @memberof DataTable#oApi 13640 * 13641 * @todo For the modularisation of v1.11 this will need to become a callback, so 13642 * the sort and filter methods can subscribe to it. That will required 13643 * initialisation options for sorting, which is why it is not already baked in 13644 */ 13645 function _fnInvalidate( settings, rowIdx, src, colIdx ) 13646 { 13647 var row = settings.aoData[ rowIdx ]; 13648 var i, ien; 13649 var cellWrite = function ( cell, col ) { 13650 // This is very frustrating, but in IE if you just write directly 13651 // to innerHTML, and elements that are overwritten are GC'ed, 13652 // even if there is a reference to them elsewhere 13653 while ( cell.childNodes.length ) { 13654 cell.removeChild( cell.firstChild ); 13655 } 13656 13657 cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' ); 13658 }; 13659 13660 // Are we reading last data from DOM or the data object? 13661 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) { 13662 // Read the data from the DOM 13663 row._aData = _fnGetRowElements( 13664 settings, row, colIdx, colIdx === undefined ? undefined : row._aData 13665 ) 13666 .data; 13667 } 13668 else { 13669 // Reading from data object, update the DOM 13670 var cells = row.anCells; 13671 13672 if ( cells ) { 13673 if ( colIdx !== undefined ) { 13674 cellWrite( cells[colIdx], colIdx ); 13675 } 13676 else { 13677 for ( i=0, ien=cells.length ; i<ien ; i++ ) { 13678 cellWrite( cells[i], i ); 13679 } 13680 } 13681 } 13682 } 13683 13684 // For both row and cell invalidation, the cached data for sorting and 13685 // filtering is nulled out 13686 row._aSortData = null; 13687 row._aFilterData = null; 13688 13689 // Invalidate the type for a specific column (if given) or all columns since 13690 // the data might have changed 13691 var cols = settings.aoColumns; 13692 if ( colIdx !== undefined ) { 13693 cols[ colIdx ].sType = null; 13694 } 13695 else { 13696 for ( i=0, ien=cols.length ; i<ien ; i++ ) { 13697 cols[i].sType = null; 13698 } 13699 13700 // Update DataTables special `DT_*` attributes for the row 13701 _fnRowAttributes( settings, row ); 13702 } 13703 } 13704 13705 13706 /** 13707 * Build a data source object from an HTML row, reading the contents of the 13708 * cells that are in the row. 13709 * 13710 * @param {object} settings DataTables settings object 13711 * @param {node|object} TR element from which to read data or existing row 13712 * object from which to re-read the data from the cells 13713 * @param {int} [colIdx] Optional column index 13714 * @param {array|object} [d] Data source object. If `colIdx` is given then this 13715 * parameter should also be given and will be used to write the data into. 13716 * Only the column in question will be written 13717 * @returns {object} Object with two parameters: `data` the data read, in 13718 * document order, and `cells` and array of nodes (they can be useful to the 13719 * caller, so rather than needing a second traversal to get them, just return 13720 * them from here). 13721 * @memberof DataTable#oApi 13722 */ 13723 function _fnGetRowElements( settings, row, colIdx, d ) 13724 { 13725 var 13726 tds = [], 13727 td = row.firstChild, 13728 name, col, o, i=0, contents, 13729 columns = settings.aoColumns, 13730 objectRead = settings._rowReadObject; 13731 13732 // Allow the data object to be passed in, or construct 13733 d = d !== undefined ? 13734 d : 13735 objectRead ? 13736 {} : 13737 []; 13738 13739 var attr = function ( str, td ) { 13740 if ( typeof str === 'string' ) { 13741 var idx = str.indexOf('@'); 13742 13743 if ( idx !== -1 ) { 13744 var attr = str.substring( idx+1 ); 13745 var setter = _fnSetObjectDataFn( str ); 13746 setter( d, td.getAttribute( attr ) ); 13747 } 13748 } 13749 }; 13750 13751 // Read data from a cell and store into the data object 13752 var cellProcess = function ( cell ) { 13753 if ( colIdx === undefined || colIdx === i ) { 13754 col = columns[i]; 13755 contents = $.trim(cell.innerHTML); 13756 13757 if ( col && col._bAttrSrc ) { 13758 var setter = _fnSetObjectDataFn( col.mData._ ); 13759 setter( d, contents ); 13760 13761 attr( col.mData.sort, cell ); 13762 attr( col.mData.type, cell ); 13763 attr( col.mData.filter, cell ); 13764 } 13765 else { 13766 // Depending on the `data` option for the columns the data can 13767 // be read to either an object or an array.
vendor: 36,444 bytes, lines 13768-15084
13768 if ( objectRead ) { 13769 if ( ! col._setter ) { 13770 // Cache the setter function 13771 col._setter = _fnSetObjectDataFn( col.mData ); 13772 } 13773 col._setter( d, contents ); 13774 } 13775 else { 13776 d[i] = contents; 13777 } 13778 } 13779 } 13780 13781 i++; 13782 }; 13783 13784 if ( td ) { 13785 // `tr` element was passed in 13786 while ( td ) { 13787 name = td.nodeName.toUpperCase(); 13788 13789 if ( name == "TD" || name == "TH" ) { 13790 cellProcess( td ); 13791 tds.push( td ); 13792 } 13793 13794 td = td.nextSibling; 13795 } 13796 } 13797 else { 13798 // Existing row object passed in 13799 tds = row.anCells; 13800 13801 for ( var j=0, jen=tds.length ; j<jen ; j++ ) { 13802 cellProcess( tds[j] ); 13803 } 13804 } 13805 13806 // Read the ID from the DOM if present 13807 var rowNode = row.firstChild ? row : row.nTr; 13808 13809 if ( rowNode ) { 13810 var id = rowNode.getAttribute( 'id' ); 13811 13812 if ( id ) { 13813 _fnSetObjectDataFn( settings.rowId )( d, id ); 13814 } 13815 } 13816 13817 return { 13818 data: d, 13819 cells: tds 13820 }; 13821 } 13822 /** 13823 * Create a new TR element (and it's TD children) for a row 13824 * @param {object} oSettings dataTables settings object 13825 * @param {int} iRow Row to consider 13826 * @param {node} [nTrIn] TR element to add to the table - optional. If not given, 13827 * DataTables will create a row automatically 13828 * @param {array} [anTds] Array of TD|TH elements for the row - must be given 13829 * if nTr is. 13830 * @memberof DataTable#oApi 13831 */ 13832 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds ) 13833 { 13834 var 13835 row = oSettings.aoData[iRow], 13836 rowData = row._aData, 13837 cells = [], 13838 nTr, nTd, oCol, 13839 i, iLen; 13840 13841 if ( row.nTr === null ) 13842 { 13843 nTr = nTrIn || document.createElement('tr'); 13844 13845 row.nTr = nTr; 13846 row.anCells = cells; 13847 13848 /* Use a private property on the node to allow reserve mapping from the node 13849 * to the aoData array for fast look up 13850 */ 13851 nTr._DT_RowIndex = iRow; 13852 13853 /* Special parameters can be given by the data source to be used on the row */ 13854 _fnRowAttributes( oSettings, row ); 13855 13856 /* Process each column */ 13857 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 13858 { 13859 oCol = oSettings.aoColumns[i]; 13860 13861 nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType ); 13862 nTd._DT_CellIndex = { 13863 row: iRow, 13864 column: i 13865 }; 13866 13867 cells.push( nTd ); 13868 13869 // Need to create the HTML if new, or if a rendering function is defined 13870 if ( (!nTrIn || oCol.mRender || oCol.mData !== i) && 13871 (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display') 13872 ) { 13873 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' ); 13874 } 13875 13876 /* Add user defined class */ 13877 if ( oCol.sClass ) 13878 { 13879 nTd.className += ' '+oCol.sClass; 13880 } 13881 13882 // Visibility - add or remove as required 13883 if ( oCol.bVisible && ! nTrIn ) 13884 { 13885 nTr.appendChild( nTd ); 13886 } 13887 else if ( ! oCol.bVisible && nTrIn ) 13888 { 13889 nTd.parentNode.removeChild( nTd ); 13890 } 13891 13892 if ( oCol.fnCreatedCell ) 13893 { 13894 oCol.fnCreatedCell.call( oSettings.oInstance, 13895 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i 13896 ); 13897 } 13898 } 13899 13900 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] ); 13901 } 13902 13903 // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved 13904 // and deployed 13905 row.nTr.setAttribute( 'role', 'row' ); 13906 } 13907 13908 13909 /** 13910 * Add attributes to a row based on the special `DT_*` parameters in a data 13911 * source object. 13912 * @param {object} settings DataTables settings object 13913 * @param {object} DataTables row object for the row to be modified 13914 * @memberof DataTable#oApi 13915 */ 13916 function _fnRowAttributes( settings, row ) 13917 { 13918 var tr = row.nTr; 13919 var data = row._aData; 13920 13921 if ( tr ) { 13922 var id = settings.rowIdFn( data ); 13923 13924 if ( id ) { 13925 tr.id = id; 13926 } 13927 13928 if ( data.DT_RowClass ) { 13929 // Remove any classes added by DT_RowClass before 13930 var a = data.DT_RowClass.split(' '); 13931 row.__rowc = row.__rowc ? 13932 _unique( row.__rowc.concat( a ) ) : 13933 a; 13934 13935 $(tr) 13936 .removeClass( row.__rowc.join(' ') ) 13937 .addClass( data.DT_RowClass ); 13938 } 13939 13940 if ( data.DT_RowAttr ) { 13941 $(tr).attr( data.DT_RowAttr ); 13942 } 13943 13944 if ( data.DT_RowData ) { 13945 $(tr).data( data.DT_RowData ); 13946 } 13947 } 13948 } 13949 13950 13951 /** 13952 * Create the HTML header for the table 13953 * @param {object} oSettings dataTables settings object 13954 * @memberof DataTable#oApi 13955 */ 13956 function _fnBuildHead( oSettings ) 13957 { 13958 var i, ien, cell, row, column; 13959 var thead = oSettings.nTHead; 13960 var tfoot = oSettings.nTFoot; 13961 var createHeader = $('th, td', thead).length === 0; 13962 var classes = oSettings.oClasses; 13963 var columns = oSettings.aoColumns; 13964 13965 if ( createHeader ) { 13966 row = $('<tr/>').appendTo( thead ); 13967 } 13968 13969 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 13970 column = columns[i]; 13971 cell = $( column.nTh ).addClass( column.sClass ); 13972 13973 if ( createHeader ) { 13974 cell.appendTo( row ); 13975 } 13976 13977 // 1.11 move into sorting 13978 if ( oSettings.oFeatures.bSort ) { 13979 cell.addClass( column.sSortingClass ); 13980 13981 if ( column.bSortable !== false ) { 13982 cell 13983 .attr( 'tabindex', oSettings.iTabIndex ) 13984 .attr( 'aria-controls', oSettings.sTableId ); 13985 13986 _fnSortAttachListener( oSettings, column.nTh, i ); 13987 } 13988 } 13989 13990 if ( column.sTitle != cell[0].innerHTML ) { 13991 cell.html( column.sTitle ); 13992 } 13993 13994 _fnRenderer( oSettings, 'header' )( 13995 oSettings, cell, column, classes 13996 ); 13997 } 13998 13999 if ( createHeader ) { 14000 _fnDetectHeader( oSettings.aoHeader, thead ); 14001 } 14002 14003 /* ARIA role for the rows */ 14004 $(thead).find('>tr').attr('role', 'row'); 14005 14006 /* Deal with the footer - add classes if required */ 14007 $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH ); 14008 $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH ); 14009 14010 // Cache the footer cells. Note that we only take the cells from the first 14011 // row in the footer. If there is more than one row the user wants to 14012 // interact with, they need to use the table().foot() method. Note also this 14013 // allows cells to be used for multiple columns using colspan 14014 if ( tfoot !== null ) { 14015 var cells = oSettings.aoFooter[0]; 14016 14017 for ( i=0, ien=cells.length ; i<ien ; i++ ) { 14018 column = columns[i]; 14019 column.nTf = cells[i].cell; 14020 14021 if ( column.sClass ) { 14022 $(column.nTf).addClass( column.sClass ); 14023 } 14024 } 14025 } 14026 } 14027 14028 14029 /** 14030 * Draw the header (or footer) element based on the column visibility states. The 14031 * methodology here is to use the layout array from _fnDetectHeader, modified for 14032 * the instantaneous column visibility, to construct the new layout. The grid is 14033 * traversed over cell at a time in a rows x columns grid fashion, although each 14034 * cell insert can cover multiple elements in the grid - which is tracks using the 14035 * aApplied array. Cell inserts in the grid will only occur where there isn't 14036 * already a cell in that position. 14037 * @param {object} oSettings dataTables settings object 14038 * @param array {objects} aoSource Layout array from _fnDetectHeader 14039 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc, 14040 * @memberof DataTable#oApi 14041 */ 14042 function _fnDrawHead( oSettings, aoSource, bIncludeHidden ) 14043 { 14044 var i, iLen, j, jLen, k, kLen, n, nLocalTr; 14045 var aoLocal = []; 14046 var aApplied = []; 14047 var iColumns = oSettings.aoColumns.length; 14048 var iRowspan, iColspan; 14049 14050 if ( ! aoSource ) 14051 { 14052 return; 14053 } 14054 14055 if ( bIncludeHidden === undefined ) 14056 { 14057 bIncludeHidden = false; 14058 } 14059 14060 /* Make a copy of the master layout array, but without the visible columns in it */ 14061 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ ) 14062 { 14063 aoLocal[i] = aoSource[i].slice(); 14064 aoLocal[i].nTr = aoSource[i].nTr; 14065 14066 /* Remove any columns which are currently hidden */ 14067 for ( j=iColumns-1 ; j>=0 ; j-- ) 14068 { 14069 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden ) 14070 { 14071 aoLocal[i].splice( j, 1 ); 14072 } 14073 } 14074 14075 /* Prep the applied array - it needs an element for each row */ 14076 aApplied.push( [] ); 14077 } 14078 14079 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ ) 14080 { 14081 nLocalTr = aoLocal[i].nTr; 14082 14083 /* All cells are going to be replaced, so empty out the row */ 14084 if ( nLocalTr ) 14085 { 14086 while( (n = nLocalTr.firstChild) ) 14087 { 14088 nLocalTr.removeChild( n ); 14089 } 14090 } 14091 14092 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ ) 14093 { 14094 iRowspan = 1; 14095 iColspan = 1; 14096 14097 /* Check to see if there is already a cell (row/colspan) covering our target 14098 * insert point. If there is, then there is nothing to do. 14099 */ 14100 if ( aApplied[i][j] === undefined ) 14101 { 14102 nLocalTr.appendChild( aoLocal[i][j].cell ); 14103 aApplied[i][j] = 1; 14104 14105 /* Expand the cell to cover as many rows as needed */ 14106 while ( aoLocal[i+iRowspan] !== undefined && 14107 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell ) 14108 { 14109 aApplied[i+iRowspan][j] = 1; 14110 iRowspan++; 14111 } 14112 14113 /* Expand the cell to cover as many columns as needed */ 14114 while ( aoLocal[i][j+iColspan] !== undefined && 14115 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell ) 14116 { 14117 /* Must update the applied array over the rows for the columns */ 14118 for ( k=0 ; k<iRowspan ; k++ ) 14119 { 14120 aApplied[i+k][j+iColspan] = 1; 14121 } 14122 iColspan++; 14123 } 14124 14125 /* Do the actual expansion in the DOM */ 14126 $(aoLocal[i][j].cell) 14127 .attr('rowspan', iRowspan) 14128 .attr('colspan', iColspan); 14129 } 14130 } 14131 } 14132 } 14133 14134 14135 /** 14136 * Insert the required TR nodes into the table for display 14137 * @param {object} oSettings dataTables settings object 14138 * @memberof DataTable#oApi 14139 */ 14140 function _fnDraw( oSettings ) 14141 { 14142 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */ 14143 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] ); 14144 if ( $.inArray( false, aPreDraw ) !== -1 ) 14145 { 14146 _fnProcessingDisplay( oSettings, false ); 14147 return; 14148 } 14149 14150 var i, iLen, n; 14151 var anRows = []; 14152 var iRowCount = 0; 14153 var asStripeClasses = oSettings.asStripeClasses; 14154 var iStripes = asStripeClasses.length; 14155 var iOpenRows = oSettings.aoOpenRows.length; 14156 var oLang = oSettings.oLanguage; 14157 var iInitDisplayStart = oSettings.iInitDisplayStart; 14158 var bServerSide = _fnDataSource( oSettings ) == 'ssp'; 14159 var aiDisplay = oSettings.aiDisplay; 14160 14161 oSettings.bDrawing = true; 14162 14163 /* Check and see if we have an initial draw position from state saving */ 14164 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 ) 14165 { 14166 oSettings._iDisplayStart = bServerSide ? 14167 iInitDisplayStart : 14168 iInitDisplayStart >= oSettings.fnRecordsDisplay() ? 14169 0 : 14170 iInitDisplayStart; 14171 14172 oSettings.iInitDisplayStart = -1; 14173 } 14174 14175 var iDisplayStart = oSettings._iDisplayStart; 14176 var iDisplayEnd = oSettings.fnDisplayEnd(); 14177 14178 /* Server-side processing draw intercept */ 14179 if ( oSettings.bDeferLoading ) 14180 { 14181 oSettings.bDeferLoading = false; 14182 oSettings.iDraw++; 14183 _fnProcessingDisplay( oSettings, false ); 14184 } 14185 else if ( !bServerSide ) 14186 { 14187 oSettings.iDraw++; 14188 } 14189 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) ) 14190 { 14191 return; 14192 } 14193 14194 if ( aiDisplay.length !== 0 ) 14195 { 14196 var iStart = bServerSide ? 0 : iDisplayStart; 14197 var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd; 14198 14199 for ( var j=iStart ; j<iEnd ; j++ ) 14200 { 14201 var iDataIndex = aiDisplay[j]; 14202 var aoData = oSettings.aoData[ iDataIndex ]; 14203 if ( aoData.nTr === null ) 14204 { 14205 _fnCreateTr( oSettings, iDataIndex ); 14206 } 14207 14208 var nRow = aoData.nTr; 14209 14210 /* Remove the old striping classes and then add the new one */ 14211 if ( iStripes !== 0 ) 14212 { 14213 var sStripe = asStripeClasses[ iRowCount % iStripes ]; 14214 if ( aoData._sRowStripe != sStripe ) 14215 { 14216 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe ); 14217 aoData._sRowStripe = sStripe; 14218 } 14219 } 14220 14221 // Row callback functions - might want to manipulate the row 14222 // iRowCount and j are not currently documented. Are they at all 14223 // useful? 14224 _fnCallbackFire( oSettings, 'aoRowCallback', null, 14225 [nRow, aoData._aData, iRowCount, j] ); 14226 14227 anRows.push( nRow ); 14228 iRowCount++; 14229 } 14230 } 14231 else 14232 { 14233 /* Table is empty - create a row with an empty message in it */ 14234 var sZero = oLang.sZeroRecords; 14235 if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' ) 14236 { 14237 sZero = oLang.sLoadingRecords; 14238 } 14239 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 ) 14240 { 14241 sZero = oLang.sEmptyTable; 14242 } 14243 14244 anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } ) 14245 .append( $('<td />', { 14246 'valign': 'top', 14247 'colSpan': _fnVisbleColumns( oSettings ), 14248 'class': oSettings.oClasses.sRowEmpty 14249 } ).html( sZero ) )[0]; 14250 } 14251 14252 /* Header and footer callbacks */ 14253 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], 14254 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); 14255 14256 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], 14257 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); 14258 14259 var body = $(oSettings.nTBody); 14260 14261 body.children().detach(); 14262 body.append( $(anRows) ); 14263 14264 /* Call all required callback functions for the end of a draw */ 14265 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] ); 14266 14267 /* Draw is complete, sorting and filtering must be as well */ 14268 oSettings.bSorted = false; 14269 oSettings.bFiltered = false; 14270 oSettings.bDrawing = false; 14271 } 14272 14273 14274 /** 14275 * Redraw the table - taking account of the various features which are enabled 14276 * @param {object} oSettings dataTables settings object 14277 * @param {boolean} [holdPosition] Keep the current paging position. By default 14278 * the paging is reset to the first page 14279 * @memberof DataTable#oApi 14280 */ 14281 function _fnReDraw( settings, holdPosition ) 14282 { 14283 var 14284 features = settings.oFeatures, 14285 sort = features.bSort, 14286 filter = features.bFilter; 14287 14288 if ( sort ) { 14289 _fnSort( settings ); 14290 } 14291 14292 if ( filter ) { 14293 _fnFilterComplete( settings, settings.oPreviousSearch ); 14294 } 14295 else { 14296 // No filtering, so we want to just use the display master 14297 settings.aiDisplay = settings.aiDisplayMaster.slice(); 14298 } 14299 14300 if ( holdPosition !== true ) { 14301 settings._iDisplayStart = 0; 14302 } 14303 14304 // Let any modules know about the draw hold position state (used by 14305 // scrolling internally) 14306 settings._drawHold = holdPosition; 14307 14308 _fnDraw( settings ); 14309 14310 settings._drawHold = false; 14311 } 14312 14313 14314 /** 14315 * Add the options to the page HTML for the table 14316 * @param {object} oSettings dataTables settings object 14317 * @memberof DataTable#oApi 14318 */ 14319 function _fnAddOptionsHtml ( oSettings ) 14320 { 14321 var classes = oSettings.oClasses; 14322 var table = $(oSettings.nTable); 14323 var holding = $('<div/>').insertBefore( table ); // Holding element for speed 14324 var features = oSettings.oFeatures; 14325 14326 // All DataTables are wrapped in a div 14327 var insert = $('<div/>', { 14328 id: oSettings.sTableId+'_wrapper', 14329 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter) 14330 } ); 14331 14332 oSettings.nHolding = holding[0]; 14333 oSettings.nTableWrapper = insert[0]; 14334 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling; 14335 14336 /* Loop over the user set positioning and place the elements as needed */ 14337 var aDom = oSettings.sDom.split(''); 14338 var featureNode, cOption, nNewNode, cNext, sAttr, j; 14339 for ( var i=0 ; i<aDom.length ; i++ ) 14340 { 14341 featureNode = null; 14342 cOption = aDom[i]; 14343 14344 if ( cOption == '<' ) 14345 { 14346 /* New container div */ 14347 nNewNode = $('<div/>')[0]; 14348 14349 /* Check to see if we should append an id and/or a class name to the container */ 14350 cNext = aDom[i+1]; 14351 if ( cNext == "'" || cNext == '"' ) 14352 { 14353 sAttr = ""; 14354 j = 2; 14355 while ( aDom[i+j] != cNext ) 14356 { 14357 sAttr += aDom[i+j]; 14358 j++; 14359 } 14360 14361 /* Replace jQuery UI constants @todo depreciated */ 14362 if ( sAttr == "H" ) 14363 { 14364 sAttr = classes.sJUIHeader; 14365 } 14366 else if ( sAttr == "F" ) 14367 { 14368 sAttr = classes.sJUIFooter; 14369 } 14370 14371 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic 14372 * breaks the string into parts and applies them as needed 14373 */ 14374 if ( sAttr.indexOf('.') != -1 ) 14375 { 14376 var aSplit = sAttr.split('.'); 14377 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1); 14378 nNewNode.className = aSplit[1]; 14379 } 14380 else if ( sAttr.charAt(0) == "#" ) 14381 { 14382 nNewNode.id = sAttr.substr(1, sAttr.length-1); 14383 } 14384 else 14385 { 14386 nNewNode.className = sAttr; 14387 } 14388 14389 i += j; /* Move along the position array */ 14390 } 14391 14392 insert.append( nNewNode ); 14393 insert = $(nNewNode); 14394 } 14395 else if ( cOption == '>' ) 14396 { 14397 /* End container div */ 14398 insert = insert.parent(); 14399 } 14400 // @todo Move options into their own plugins? 14401 else if ( cOption == 'l' && features.bPaginate && features.bLengthChange ) 14402 { 14403 /* Length */ 14404 featureNode = _fnFeatureHtmlLength( oSettings ); 14405 } 14406 else if ( cOption == 'f' && features.bFilter ) 14407 { 14408 /* Filter */ 14409 featureNode = _fnFeatureHtmlFilter( oSettings ); 14410 } 14411 else if ( cOption == 'r' && features.bProcessing ) 14412 { 14413 /* pRocessing */ 14414 featureNode = _fnFeatureHtmlProcessing( oSettings ); 14415 } 14416 else if ( cOption == 't' ) 14417 { 14418 /* Table */ 14419 featureNode = _fnFeatureHtmlTable( oSettings ); 14420 } 14421 else if ( cOption == 'i' && features.bInfo ) 14422 { 14423 /* Info */ 14424 featureNode = _fnFeatureHtmlInfo( oSettings ); 14425 } 14426 else if ( cOption == 'p' && features.bPaginate ) 14427 { 14428 /* Pagination */ 14429 featureNode = _fnFeatureHtmlPaginate( oSettings ); 14430 } 14431 else if ( DataTable.ext.feature.length !== 0 ) 14432 { 14433 /* Plug-in features */ 14434 var aoFeatures = DataTable.ext.feature; 14435 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ ) 14436 { 14437 if ( cOption == aoFeatures[k].cFeature ) 14438 { 14439 featureNode = aoFeatures[k].fnInit( oSettings ); 14440 break; 14441 } 14442 } 14443 } 14444 14445 /* Add to the 2D features array */ 14446 if ( featureNode ) 14447 { 14448 var aanFeatures = oSettings.aanFeatures; 14449 14450 if ( ! aanFeatures[cOption] ) 14451 { 14452 aanFeatures[cOption] = []; 14453 } 14454 14455 aanFeatures[cOption].push( featureNode ); 14456 insert.append( featureNode ); 14457 } 14458 } 14459 14460 /* Built our DOM structure - replace the holding div with what we want */ 14461 holding.replaceWith( insert ); 14462 oSettings.nHolding = null; 14463 } 14464 14465 14466 /** 14467 * Use the DOM source to create up an array of header cells. The idea here is to 14468 * create a layout grid (array) of rows x columns, which contains a reference 14469 * to the cell that that point in the grid (regardless of col/rowspan), such that 14470 * any column / row could be removed and the new grid constructed 14471 * @param array {object} aLayout Array to store the calculated layout in 14472 * @param {node} nThead The header/footer element for the table 14473 * @memberof DataTable#oApi 14474 */ 14475 function _fnDetectHeader ( aLayout, nThead ) 14476 { 14477 var nTrs = $(nThead).children('tr'); 14478 var nTr, nCell; 14479 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan; 14480 var bUnique; 14481 var fnShiftCol = function ( a, i, j ) { 14482 var k = a[i]; 14483 while ( k[j] ) { 14484 j++; 14485 } 14486 return j; 14487 }; 14488 14489 aLayout.splice( 0, aLayout.length ); 14490 14491 /* We know how many rows there are in the layout - so prep it */ 14492 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 14493 { 14494 aLayout.push( [] ); 14495 } 14496 14497 /* Calculate a layout array */ 14498 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 14499 { 14500 nTr = nTrs[i]; 14501 iColumn = 0; 14502 14503 /* For every cell in the row... */ 14504 nCell = nTr.firstChild; 14505 while ( nCell ) { 14506 if ( nCell.nodeName.toUpperCase() == "TD" || 14507 nCell.nodeName.toUpperCase() == "TH" ) 14508 { 14509 /* Get the col and rowspan attributes from the DOM and sanitise them */ 14510 iColspan = nCell.getAttribute('colspan') * 1; 14511 iRowspan = nCell.getAttribute('rowspan') * 1; 14512 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan; 14513 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan; 14514 14515 /* There might be colspan cells already in this row, so shift our target 14516 * accordingly 14517 */ 14518 iColShifted = fnShiftCol( aLayout, i, iColumn ); 14519 14520 /* Cache calculation for unique columns */ 14521 bUnique = iColspan === 1 ? true : false; 14522 14523 /* If there is col / rowspan, copy the information into the layout grid */ 14524 for ( l=0 ; l<iColspan ; l++ ) 14525 { 14526 for ( k=0 ; k<iRowspan ; k++ ) 14527 { 14528 aLayout[i+k][iColShifted+l] = { 14529 "cell": nCell, 14530 "unique": bUnique 14531 }; 14532 aLayout[i+k].nTr = nTr; 14533 } 14534 } 14535 } 14536 nCell = nCell.nextSibling; 14537 } 14538 } 14539 } 14540 14541 14542 /** 14543 * Get an array of unique th elements, one for each column 14544 * @param {object} oSettings dataTables settings object 14545 * @param {node} nHeader automatically detect the layout from this node - optional 14546 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional 14547 * @returns array {node} aReturn list of unique th's 14548 * @memberof DataTable#oApi 14549 */ 14550 function _fnGetUniqueThs ( oSettings, nHeader, aLayout ) 14551 { 14552 var aReturn = []; 14553 if ( !aLayout ) 14554 { 14555 aLayout = oSettings.aoHeader; 14556 if ( nHeader ) 14557 { 14558 aLayout = []; 14559 _fnDetectHeader( aLayout, nHeader ); 14560 } 14561 } 14562 14563 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ ) 14564 { 14565 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ ) 14566 { 14567 if ( aLayout[i][j].unique && 14568 (!aReturn[j] || !oSettings.bSortCellsTop) ) 14569 { 14570 aReturn[j] = aLayout[i][j].cell; 14571 } 14572 } 14573 } 14574 14575 return aReturn; 14576 } 14577 14578 /** 14579 * Create an Ajax call based on the table's settings, taking into account that 14580 * parameters can have multiple forms, and backwards compatibility. 14581 * 14582 * @param {object} oSettings dataTables settings object 14583 * @param {array} data Data to send to the server, required by 14584 * DataTables - may be augmented by developer callbacks 14585 * @param {function} fn Callback function to run when data is obtained 14586 */ 14587 function _fnBuildAjax( oSettings, data, fn ) 14588 { 14589 // Compatibility with 1.9-, allow fnServerData and event to manipulate 14590 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] ); 14591 14592 // Convert to object based for 1.10+ if using the old array scheme which can 14593 // come from server-side processing or serverParams 14594 if ( data && $.isArray(data) ) { 14595 var tmp = {}; 14596 var rbracket = /(.*?)\[\]$/; 14597 14598 $.each( data, function (key, val) { 14599 var match = val.name.match(rbracket); 14600 14601 if ( match ) { 14602 // Support for arrays 14603 var name = match[0]; 14604 14605 if ( ! tmp[ name ] ) { 14606 tmp[ name ] = []; 14607 } 14608 tmp[ name ].push( val.value ); 14609 } 14610 else { 14611 tmp[val.name] = val.value; 14612 } 14613 } ); 14614 data = tmp; 14615 } 14616 14617 var ajaxData; 14618 var ajax = oSettings.ajax; 14619 var instance = oSettings.oInstance; 14620 var callback = function ( json ) { 14621 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] ); 14622 fn( json ); 14623 }; 14624 14625 if ( $.isPlainObject( ajax ) && ajax.data ) 14626 { 14627 ajaxData = ajax.data; 14628 14629 var newData = $.isFunction( ajaxData ) ? 14630 ajaxData( data, oSettings ) : // fn can manipulate data or return 14631 ajaxData; // an object object or array to merge 14632 14633 // If the function returned something, use that alone 14634 data = $.isFunction( ajaxData ) && newData ? 14635 newData : 14636 $.extend( true, data, newData ); 14637 14638 // Remove the data property as we've resolved it already and don't want 14639 // jQuery to do it again (it is restored at the end of the function) 14640 delete ajax.data; 14641 } 14642 14643 var baseAjax = { 14644 "data": data, 14645 "success": function (json) { 14646 var error = json.error || json.sError; 14647 if ( error ) { 14648 _fnLog( oSettings, 0, error ); 14649 } 14650 14651 oSettings.json = json; 14652 callback( json ); 14653 }, 14654 "dataType": "json", 14655 "cache": false, 14656 "type": oSettings.sServerMethod, 14657 "error": function (xhr, error, thrown) { 14658 var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] ); 14659 14660 if ( $.inArray( true, ret ) === -1 ) { 14661 if ( error == "parsererror" ) { 14662 _fnLog( oSettings, 0, 'Invalid JSON response', 1 ); 14663 } 14664 else if ( xhr.readyState === 4 ) { 14665 _fnLog( oSettings, 0, 'Ajax error', 7 ); 14666 } 14667 } 14668 14669 _fnProcessingDisplay( oSettings, false ); 14670 } 14671 }; 14672 14673 // Store the data submitted for the API 14674 oSettings.oAjaxData = data; 14675 14676 // Allow plug-ins and external processes to modify the data 14677 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] ); 14678 14679 if ( oSettings.fnServerData ) 14680 { 14681 // DataTables 1.9- compatibility 14682 oSettings.fnServerData.call( instance, 14683 oSettings.sAjaxSource, 14684 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format 14685 return { name: key, value: val }; 14686 } ), 14687 callback, 14688 oSettings 14689 ); 14690 } 14691 else if ( oSettings.sAjaxSource || typeof ajax === 'string' ) 14692 { 14693 // DataTables 1.9- compatibility 14694 oSettings.jqXHR = $.ajax( $.extend( baseAjax, { 14695 url: ajax || oSettings.sAjaxSource 14696 } ) ); 14697 } 14698 else if ( $.isFunction( ajax ) ) 14699 { 14700 // Is a function - let the caller define what needs to be done 14701 oSettings.jqXHR = ajax.call( instance, data, callback, oSettings ); 14702 } 14703 else 14704 { 14705 // Object to extend the base settings 14706 oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) ); 14707 14708 // Restore for next time around 14709 ajax.data = ajaxData; 14710 } 14711 } 14712 14713 14714 /** 14715 * Update the table using an Ajax call 14716 * @param {object} settings dataTables settings object 14717 * @returns {boolean} Block the table drawing or not 14718 * @memberof DataTable#oApi 14719 */ 14720 function _fnAjaxUpdate( settings ) 14721 { 14722 if ( settings.bAjaxDataGet ) { 14723 settings.iDraw++; 14724 _fnProcessingDisplay( settings, true ); 14725 14726 _fnBuildAjax( 14727 settings, 14728 _fnAjaxParameters( settings ), 14729 function(json) { 14730 _fnAjaxUpdateDraw( settings, json ); 14731 } 14732 ); 14733 14734 return false; 14735 } 14736 return true; 14737 } 14738 14739 14740 /** 14741 * Build up the parameters in an object needed for a server-side processing 14742 * request. Note that this is basically done twice, is different ways - a modern 14743 * method which is used by default in DataTables 1.10 which uses objects and 14744 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if 14745 * the sAjaxSource option is used in the initialisation, or the legacyAjax 14746 * option is set. 14747 * @param {object} oSettings dataTables settings object 14748 * @returns {bool} block the table drawing or not 14749 * @memberof DataTable#oApi 14750 */ 14751 function _fnAjaxParameters( settings ) 14752 { 14753 var 14754 columns = settings.aoColumns, 14755 columnCount = columns.length, 14756 features = settings.oFeatures, 14757 preSearch = settings.oPreviousSearch, 14758 preColSearch = settings.aoPreSearchCols, 14759 i, data = [], dataProp, column, columnSearch, 14760 sort = _fnSortFlatten( settings ), 14761 displayStart = settings._iDisplayStart, 14762 displayLength = features.bPaginate !== false ? 14763 settings._iDisplayLength : 14764 -1; 14765 14766 var param = function ( name, value ) { 14767 data.push( { 'name': name, 'value': value } ); 14768 }; 14769 14770 // DataTables 1.9- compatible method 14771 param( 'sEcho', settings.iDraw ); 14772 param( 'iColumns', columnCount ); 14773 param( 'sColumns', _pluck( columns, 'sName' ).join(',') ); 14774 param( 'iDisplayStart', displayStart ); 14775 param( 'iDisplayLength', displayLength ); 14776 14777 // DataTables 1.10+ method 14778 var d = { 14779 draw: settings.iDraw, 14780 columns: [], 14781 order: [], 14782 start: displayStart, 14783 length: displayLength, 14784 search: { 14785 value: preSearch.sSearch, 14786 regex: preSearch.bRegex 14787 } 14788 }; 14789 14790 for ( i=0 ; i<columnCount ; i++ ) { 14791 column = columns[i]; 14792 columnSearch = preColSearch[i]; 14793 dataProp = typeof column.mData=="function" ? 'function' : column.mData ; 14794 14795 d.columns.push( { 14796 data: dataProp, 14797 name: column.sName, 14798 searchable: column.bSearchable, 14799 orderable: column.bSortable, 14800 search: { 14801 value: columnSearch.sSearch, 14802 regex: columnSearch.bRegex 14803 } 14804 } ); 14805 14806 param( "mDataProp_"+i, dataProp ); 14807 14808 if ( features.bFilter ) { 14809 param( 'sSearch_'+i, columnSearch.sSearch ); 14810 param( 'bRegex_'+i, columnSearch.bRegex ); 14811 param( 'bSearchable_'+i, column.bSearchable ); 14812 } 14813 14814 if ( features.bSort ) { 14815 param( 'bSortable_'+i, column.bSortable ); 14816 } 14817 } 14818 14819 if ( features.bFilter ) { 14820 param( 'sSearch', preSearch.sSearch ); 14821 param( 'bRegex', preSearch.bRegex ); 14822 } 14823 14824 if ( features.bSort ) { 14825 $.each( sort, function ( i, val ) { 14826 d.order.push( { column: val.col, dir: val.dir } ); 14827 14828 param( 'iSortCol_'+i, val.col ); 14829 param( 'sSortDir_'+i, val.dir ); 14830 } ); 14831 14832 param( 'iSortingCols', sort.length ); 14833 } 14834 14835 // If the legacy.ajax parameter is null, then we automatically decide which 14836 // form to use, based on sAjaxSource 14837 var legacy = DataTable.ext.legacy.ajax; 14838 if ( legacy === null ) { 14839 return settings.sAjaxSource ? data : d; 14840 } 14841 14842 // Otherwise, if legacy has been specified then we use that to decide on the 14843 // form 14844 return legacy ? data : d; 14845 } 14846 14847 14848 /** 14849 * Data the data from the server (nuking the old) and redraw the table 14850 * @param {object} oSettings dataTables settings object 14851 * @param {object} json json data return from the server. 14852 * @param {string} json.sEcho Tracking flag for DataTables to match requests 14853 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering 14854 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering 14855 * @param {array} json.aaData The data to display on this page 14856 * @param {string} [json.sColumns] Column ordering (sName, comma separated) 14857 * @memberof DataTable#oApi 14858 */ 14859 function _fnAjaxUpdateDraw ( settings, json ) 14860 { 14861 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation. 14862 // Support both 14863 var compat = function ( old, modern ) { 14864 return json[old] !== undefined ? json[old] : json[modern]; 14865 }; 14866 14867 var data = _fnAjaxDataSrc( settings, json ); 14868 var draw = compat( 'sEcho', 'draw' ); 14869 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' ); 14870 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' ); 14871 14872 if ( draw ) { 14873 // Protect against out of sequence returns 14874 if ( draw*1 < settings.iDraw ) { 14875 return; 14876 } 14877 settings.iDraw = draw * 1; 14878 } 14879 14880 _fnClearTable( settings ); 14881 settings._iRecordsTotal = parseInt(recordsTotal, 10); 14882 settings._iRecordsDisplay = parseInt(recordsFiltered, 10); 14883 14884 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 14885 _fnAddData( settings, data[i] ); 14886 } 14887 settings.aiDisplay = settings.aiDisplayMaster.slice(); 14888 14889 settings.bAjaxDataGet = false; 14890 _fnDraw( settings ); 14891 14892 if ( ! settings._bInitComplete ) { 14893 _fnInitComplete( settings, json ); 14894 } 14895 14896 settings.bAjaxDataGet = true; 14897 _fnProcessingDisplay( settings, false ); 14898 } 14899 14900 14901 /** 14902 * Get the data from the JSON data source to use for drawing a table. Using 14903 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the 14904 * source object, or from a processing function. 14905 * @param {object} oSettings dataTables settings object 14906 * @param {object} json Data source object / array from the server 14907 * @return {array} Array of data to use 14908 */ 14909 function _fnAjaxDataSrc ( oSettings, json ) 14910 { 14911 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ? 14912 oSettings.ajax.dataSrc : 14913 oSettings.sAjaxDataProp; // Compatibility with 1.9-. 14914 14915 // Compatibility with 1.9-. In order to read from aaData, check if the 14916 // default has been changed, if not, check for aaData 14917 if ( dataSrc === 'data' ) { 14918 return json.aaData || json[dataSrc]; 14919 } 14920 14921 return dataSrc !== "" ? 14922 _fnGetObjectDataFn( dataSrc )( json ) : 14923 json; 14924 } 14925 14926 /** 14927 * Generate the node required for filtering text 14928 * @returns {node} Filter control element 14929 * @param {object} oSettings dataTables settings object 14930 * @memberof DataTable#oApi 14931 */ 14932 function _fnFeatureHtmlFilter ( settings ) 14933 { 14934 var classes = settings.oClasses; 14935 var tableId = settings.sTableId; 14936 var language = settings.oLanguage; 14937 var previousSearch = settings.oPreviousSearch; 14938 var features = settings.aanFeatures; 14939 var input = '<input type="search" class="'+classes.sFilterInput+'"/>'; 14940 14941 var str = language.sSearch; 14942 str = str.match(/_INPUT_/) ? 14943 str.replace('_INPUT_', input) : 14944 str+input; 14945 14946 var filter = $('<div/>', { 14947 'id': ! features.f ? tableId+'_filter' : null, 14948 'class': classes.sFilter 14949 } ) 14950 .append( $('<label/>' ).append( str ) ); 14951 14952 var searchFn = function() { 14953 /* Update all other filter input elements for the new display */ 14954 var n = features.f; 14955 var val = !this.value ? "" : this.value; // mental IE8 fix :-( 14956 14957 /* Now do the filter */ 14958 if ( val != previousSearch.sSearch ) { 14959 _fnFilterComplete( settings, { 14960 "sSearch": val, 14961 "bRegex": previousSearch.bRegex, 14962 "bSmart": previousSearch.bSmart , 14963 "bCaseInsensitive": previousSearch.bCaseInsensitive 14964 } ); 14965 14966 // Need to redraw, without resorting 14967 settings._iDisplayStart = 0; 14968 _fnDraw( settings ); 14969 } 14970 }; 14971 14972 var searchDelay = settings.searchDelay !== null ? 14973 settings.searchDelay : 14974 _fnDataSource( settings ) === 'ssp' ? 14975 400 : 14976 0; 14977 14978 var jqFilter = $('input', filter) 14979 .val( previousSearch.sSearch ) 14980 .attr( 'placeholder', language.sSearchPlaceholder ) 14981 .bind( 14982 'keyup.DT search.DT input.DT paste.DT cut.DT', 14983 searchDelay ? 14984 _fnThrottle( searchFn, searchDelay ) : 14985 searchFn 14986 ) 14987 .bind( 'keypress.DT', function(e) { 14988 /* Prevent form submission */ 14989 if ( e.keyCode == 13 ) { 14990 return false; 14991 } 14992 } ) 14993 .attr('aria-controls', tableId); 14994 14995 // Update the input elements whenever the table is filtered 14996 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) { 14997 if ( settings === s ) { 14998 // IE9 throws an 'unknown error' if document.activeElement is used 14999 // inside an iframe or frame... 15000 try { 15001 if ( jqFilter[0] !== document.activeElement ) { 15002 jqFilter.val( previousSearch.sSearch ); 15003 } 15004 } 15005 catch ( e ) {} 15006 } 15007 } ); 15008 15009 return filter[0]; 15010 } 15011 15012 15013 /** 15014 * Filter the table using both the global filter and column based filtering 15015 * @param {object} oSettings dataTables settings object 15016 * @param {object} oSearch search information 15017 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0) 15018 * @memberof DataTable#oApi 15019 */ 15020 function _fnFilterComplete ( oSettings, oInput, iForce ) 15021 { 15022 var oPrevSearch = oSettings.oPreviousSearch; 15023 var aoPrevSearch = oSettings.aoPreSearchCols; 15024 var fnSaveFilter = function ( oFilter ) { 15025 /* Save the filtering values */ 15026 oPrevSearch.sSearch = oFilter.sSearch; 15027 oPrevSearch.bRegex = oFilter.bRegex; 15028 oPrevSearch.bSmart = oFilter.bSmart; 15029 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive; 15030 }; 15031 var fnRegex = function ( o ) { 15032 // Backwards compatibility with the bEscapeRegex option 15033 return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex; 15034 }; 15035 15036 // Resolve any column types that are unknown due to addition or invalidation 15037 // @todo As per sort - can this be moved into an event handler? 15038 _fnColumnTypes( oSettings ); 15039 15040 /* In server-side processing all filtering is done by the server, so no point hanging around here */ 15041 if ( _fnDataSource( oSettings ) != 'ssp' ) 15042 { 15043 /* Global filter */ 15044 _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive ); 15045 fnSaveFilter( oInput ); 15046 15047 /* Now do the individual column filter */ 15048 for ( var i=0 ; i<aoPrevSearch.length ; i++ ) 15049 { 15050 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]), 15051 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive ); 15052 } 15053 15054 /* Custom filtering */ 15055 _fnFilterCustom( oSettings ); 15056 } 15057 else 15058 { 15059 fnSaveFilter( oInput ); 15060 } 15061 15062 /* Tell the draw function we have been filtering */ 15063 oSettings.bFiltered = true; 15064 _fnCallbackFire( oSettings, null, 'search', [oSettings] ); 15065 } 15066 15067 15068 /** 15069 * Apply custom filtering functions 15070 * @param {object} oSettings dataTables settings object 15071 * @memberof DataTable#oApi 15072 */ 15073 function _fnFilterCustom( settings ) 15074 { 15075 var filters = DataTable.ext.search; 15076 var displayRows = settings.aiDisplay; 15077 var row, rowIdx; 15078 15079 for ( var i=0, ien=filters.length ; i<ien ; i++ ) { 15080 var rows = []; 15081 15082 // Loop over each row and see if it should be included 15083 for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) { 15084 rowIdx = displayRows[ j ];
15085 row = settings.aoData[ rowIdx ]; 15086 15087 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) { 15088 rows.push( rowIdx ); 15089 } 15090 } 15091 15092 // So the array reference doesn't break set the results into the 15093 // existing array 15094 displayRows.length = 0; 15095 $.merge( displayRows, rows ); 15096 } 15097 } 15098 15099 15100 /** 15101 * Filter the table on a per-column basis 15102 * @param {object} oSettings dataTables settings object 15103 * @param {string} sInput string to filter on 15104 * @param {int} iColumn column to filter 15105 * @param {bool} bRegex treat search string as a regular expression or not 15106 * @param {bool} bSmart use smart filtering or not 15107 * @param {bool} bCaseInsensitive Do case insenstive matching or not 15108 * @memberof DataTable#oApi 15109 */ 15110 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive ) 15111 { 15112 if ( searchStr === '' ) { 15113 return; 15114 } 15115 15116 var data; 15117 var display = settings.aiDisplay; 15118 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive ); 15119 15120 for ( var i=display.length-1 ; i>=0 ; i-- ) { 15121 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ]; 15122 15123 if ( ! rpSearch.test( data ) ) { 15124 display.splice( i, 1 ); 15125 } 15126 } 15127 } 15128 15129 15130 /** 15131 * Filter the data table based on user input and draw the table 15132 * @param {object} settings dataTables settings object 15133 * @param {string} input string to filter on 15134 * @param {int} force optional - force a research of the master array (1) or not (undefined or 0) 15135 * @param {bool} regex treat as a regular expression or not 15136 * @param {bool} smart perform smart filtering or not 15137 * @param {bool} caseInsensitive Do case insenstive matching or not 15138 * @memberof DataTable#oApi 15139 */ 15140 function _fnFilter( settings, input, force, regex, smart, caseInsensitive ) 15141 { 15142 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive ); 15143 var prevSearch = settings.oPreviousSearch.sSearch; 15144 var displayMaster = settings.aiDisplayMaster; 15145 var display, invalidated, i; 15146 15147 // Need to take account of custom filtering functions - always filter 15148 if ( DataTable.ext.search.length !== 0 ) { 15149 force = true; 15150 } 15151 15152 // Check if any of the rows were invalidated 15153 invalidated = _fnFilterData( settings ); 15154 15155 // If the input is blank - we just want the full data set 15156 if ( input.length <= 0 ) { 15157 settings.aiDisplay = displayMaster.slice(); 15158 } 15159 else { 15160 // New search - start from the master array 15161 if ( invalidated || 15162 force || 15163 prevSearch.length > input.length || 15164 input.indexOf(prevSearch) !== 0 || 15165 settings.bSorted // On resort, the display master needs to be 15166 // re-filtered since indexes will have changed 15167 ) { 15168 settings.aiDisplay = displayMaster.slice(); 15169 } 15170 15171 // Search the display array 15172 display = settings.aiDisplay; 15173 15174 for ( i=display.length-1 ; i>=0 ; i-- ) { 15175 if ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) { 15176 display.splice( i, 1 ); 15177 } 15178 } 15179 } 15180 } 15181 15182 15183 /** 15184 * Build a regular expression object suitable for searching a table 15185 * @param {string} sSearch string to search for 15186 * @param {bool} bRegex treat as a regular expression or not 15187 * @param {bool} bSmart perform smart filtering or not 15188 * @param {bool} bCaseInsensitive Do case insensitive matching or not 15189 * @returns {RegExp} constructed object 15190 * @memberof DataTable#oApi 15191 */ 15192 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive ) 15193 { 15194 search = regex ? 15195 search : 15196 _fnEscapeRegex( search ); 15197 15198 if ( smart ) { 15199 /* For smart filtering we want to allow the search to work regardless of 15200 * word order. We also want double quoted text to be preserved, so word 15201 * order is important - a la google. So this is what we want to 15202 * generate: 15203 * 15204 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$ 15205 */ 15206 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) { 15207 if ( word.charAt(0) === '"' ) { 15208 var m = word.match( /^"(.*)"$/ ); 15209 word = m ? m[1] : word; 15210 } 15211 15212 return word.replace('"', ''); 15213 } ); 15214 15215 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$'; 15216 } 15217 15218 return new RegExp( search, caseInsensitive ? 'i' : '' ); 15219 } 15220 15221 15222 /** 15223 * Escape a string such that it can be used in a regular expression 15224 * @param {string} sVal string to escape 15225 * @returns {string} escaped string 15226 * @memberof DataTable#oApi 15227 */ 15228 var _fnEscapeRegex = DataTable.util.escapeRegex; 15229
vendor: 66,580 bytes, lines 15230-17568
15230 var __filter_div = $('<div>')[0]; 15231 var __filter_div_textContent = __filter_div.textContent !== undefined; 15232 15233 // Update the filtering data for each row if needed (by invalidation or first run) 15234 function _fnFilterData ( settings ) 15235 { 15236 var columns = settings.aoColumns; 15237 var column; 15238 var i, j, ien, jen, filterData, cellData, row; 15239 var fomatters = DataTable.ext.type.search; 15240 var wasInvalidated = false; 15241 15242 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 15243 row = settings.aoData[i]; 15244 15245 if ( ! row._aFilterData ) { 15246 filterData = []; 15247 15248 for ( j=0, jen=columns.length ; j<jen ; j++ ) { 15249 column = columns[j]; 15250 15251 if ( column.bSearchable ) { 15252 cellData = _fnGetCellData( settings, i, j, 'filter' ); 15253 15254 if ( fomatters[ column.sType ] ) { 15255 cellData = fomatters[ column.sType ]( cellData ); 15256 } 15257 15258 // Search in DataTables 1.10 is string based. In 1.11 this 15259 // should be altered to also allow strict type checking. 15260 if ( cellData === null ) { 15261 cellData = ''; 15262 } 15263 15264 if ( typeof cellData !== 'string' && cellData.toString ) { 15265 cellData = cellData.toString(); 15266 } 15267 } 15268 else { 15269 cellData = ''; 15270 } 15271 15272 // If it looks like there is an HTML entity in the string, 15273 // attempt to decode it so sorting works as expected. Note that 15274 // we could use a single line of jQuery to do this, but the DOM 15275 // method used here is much faster http://jsperf.com/html-decode 15276 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) { 15277 __filter_div.innerHTML = cellData; 15278 cellData = __filter_div_textContent ? 15279 __filter_div.textContent : 15280 __filter_div.innerText; 15281 } 15282 15283 if ( cellData.replace ) { 15284 cellData = cellData.replace(/[\r\n]/g, ''); 15285 } 15286 15287 filterData.push( cellData ); 15288 } 15289 15290 row._aFilterData = filterData; 15291 row._sFilterRow = filterData.join(' '); 15292 wasInvalidated = true; 15293 } 15294 } 15295 15296 return wasInvalidated; 15297 } 15298 15299 15300 /** 15301 * Convert from the internal Hungarian notation to camelCase for external 15302 * interaction 15303 * @param {object} obj Object to convert 15304 * @returns {object} Inverted object 15305 * @memberof DataTable#oApi 15306 */ 15307 function _fnSearchToCamel ( obj ) 15308 { 15309 return { 15310 search: obj.sSearch, 15311 smart: obj.bSmart, 15312 regex: obj.bRegex, 15313 caseInsensitive: obj.bCaseInsensitive 15314 }; 15315 } 15316 15317 15318 15319 /** 15320 * Convert from camelCase notation to the internal Hungarian. We could use the 15321 * Hungarian convert function here, but this is cleaner 15322 * @param {object} obj Object to convert 15323 * @returns {object} Inverted object 15324 * @memberof DataTable#oApi 15325 */ 15326 function _fnSearchToHung ( obj ) 15327 { 15328 return { 15329 sSearch: obj.search, 15330 bSmart: obj.smart, 15331 bRegex: obj.regex, 15332 bCaseInsensitive: obj.caseInsensitive 15333 }; 15334 } 15335 15336 /** 15337 * Generate the node required for the info display 15338 * @param {object} oSettings dataTables settings object 15339 * @returns {node} Information element 15340 * @memberof DataTable#oApi 15341 */ 15342 function _fnFeatureHtmlInfo ( settings ) 15343 { 15344 var 15345 tid = settings.sTableId, 15346 nodes = settings.aanFeatures.i, 15347 n = $('<div/>', { 15348 'class': settings.oClasses.sInfo, 15349 'id': ! nodes ? tid+'_info' : null 15350 } ); 15351 15352 if ( ! nodes ) { 15353 // Update display on each draw 15354 settings.aoDrawCallback.push( { 15355 "fn": _fnUpdateInfo, 15356 "sName": "information" 15357 } ); 15358 15359 n 15360 .attr( 'role', 'status' ) 15361 .attr( 'aria-live', 'polite' ); 15362 15363 // Table is described by our info div 15364 $(settings.nTable).attr( 'aria-describedby', tid+'_info' ); 15365 } 15366 15367 return n[0]; 15368 } 15369 15370 15371 /** 15372 * Update the information elements in the display 15373 * @param {object} settings dataTables settings object 15374 * @memberof DataTable#oApi 15375 */ 15376 function _fnUpdateInfo ( settings ) 15377 { 15378 /* Show information about the table */ 15379 var nodes = settings.aanFeatures.i; 15380 if ( nodes.length === 0 ) { 15381 return; 15382 } 15383 15384 var 15385 lang = settings.oLanguage, 15386 start = settings._iDisplayStart+1, 15387 end = settings.fnDisplayEnd(), 15388 max = settings.fnRecordsTotal(), 15389 total = settings.fnRecordsDisplay(), 15390 out = total ? 15391 lang.sInfo : 15392 lang.sInfoEmpty; 15393 15394 if ( total !== max ) { 15395 /* Record set after filtering */ 15396 out += ' ' + lang.sInfoFiltered; 15397 } 15398 15399 // Convert the macros 15400 out += lang.sInfoPostFix; 15401 out = _fnInfoMacros( settings, out ); 15402 15403 var callback = lang.fnInfoCallback; 15404 if ( callback !== null ) { 15405 out = callback.call( settings.oInstance, 15406 settings, start, end, max, total, out 15407 ); 15408 } 15409 15410 $(nodes).html( out ); 15411 } 15412 15413 15414 function _fnInfoMacros ( settings, str ) 15415 { 15416 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only 15417 // internally 15418 var 15419 formatter = settings.fnFormatNumber, 15420 start = settings._iDisplayStart+1, 15421 len = settings._iDisplayLength, 15422 vis = settings.fnRecordsDisplay(), 15423 all = len === -1; 15424 15425 return str. 15426 replace(/_START_/g, formatter.call( settings, start ) ). 15427 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ). 15428 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ). 15429 replace(/_TOTAL_/g, formatter.call( settings, vis ) ). 15430 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ). 15431 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ); 15432 } 15433 15434 15435 15436 /** 15437 * Draw the table for the first time, adding all required features 15438 * @param {object} settings dataTables settings object 15439 * @memberof DataTable#oApi 15440 */ 15441 function _fnInitialise ( settings ) 15442 { 15443 var i, iLen, iAjaxStart=settings.iInitDisplayStart; 15444 var columns = settings.aoColumns, column; 15445 var features = settings.oFeatures; 15446 var deferLoading = settings.bDeferLoading; // value modified by the draw 15447 15448 /* Ensure that the table data is fully initialised */ 15449 if ( ! settings.bInitialised ) { 15450 setTimeout( function(){ _fnInitialise( settings ); }, 200 ); 15451 return; 15452 } 15453 15454 /* Show the display HTML options */ 15455 _fnAddOptionsHtml( settings ); 15456 15457 /* Build and draw the header / footer for the table */ 15458 _fnBuildHead( settings ); 15459 _fnDrawHead( settings, settings.aoHeader ); 15460 _fnDrawHead( settings, settings.aoFooter ); 15461 15462 /* Okay to show that something is going on now */ 15463 _fnProcessingDisplay( settings, true ); 15464 15465 /* Calculate sizes for columns */ 15466 if ( features.bAutoWidth ) { 15467 _fnCalculateColumnWidths( settings ); 15468 } 15469 15470 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) { 15471 column = columns[i]; 15472 15473 if ( column.sWidth ) { 15474 column.nTh.style.width = _fnStringToCss( column.sWidth ); 15475 } 15476 } 15477 15478 _fnCallbackFire( settings, null, 'preInit', [settings] ); 15479 15480 // If there is default sorting required - let's do it. The sort function 15481 // will do the drawing for us. Otherwise we draw the table regardless of the 15482 // Ajax source - this allows the table to look initialised for Ajax sourcing 15483 // data (show 'loading' message possibly) 15484 _fnReDraw( settings ); 15485 15486 // Server-side processing init complete is done by _fnAjaxUpdateDraw 15487 var dataSrc = _fnDataSource( settings ); 15488 if ( dataSrc != 'ssp' || deferLoading ) { 15489 // if there is an ajax source load the data 15490 if ( dataSrc == 'ajax' ) { 15491 _fnBuildAjax( settings, [], function(json) { 15492 var aData = _fnAjaxDataSrc( settings, json ); 15493 15494 // Got the data - add it to the table 15495 for ( i=0 ; i<aData.length ; i++ ) { 15496 _fnAddData( settings, aData[i] ); 15497 } 15498 15499 // Reset the init display for cookie saving. We've already done 15500 // a filter, and therefore cleared it before. So we need to make 15501 // it appear 'fresh' 15502 settings.iInitDisplayStart = iAjaxStart; 15503 15504 _fnReDraw( settings ); 15505 15506 _fnProcessingDisplay( settings, false ); 15507 _fnInitComplete( settings, json ); 15508 }, settings ); 15509 } 15510 else { 15511 _fnProcessingDisplay( settings, false ); 15512 _fnInitComplete( settings ); 15513 } 15514 } 15515 } 15516 15517 15518 /** 15519 * Draw the table for the first time, adding all required features 15520 * @param {object} oSettings dataTables settings object 15521 * @param {object} [json] JSON from the server that completed the table, if using Ajax source 15522 * with client-side processing (optional) 15523 * @memberof DataTable#oApi 15524 */ 15525 function _fnInitComplete ( settings, json ) 15526 { 15527 settings._bInitComplete = true; 15528 15529 // When data was added after the initialisation (data or Ajax) we need to 15530 // calculate the column sizing 15531 if ( json || settings.oInit.aaData ) { 15532 _fnAdjustColumnSizing( settings ); 15533 } 15534 15535 _fnCallbackFire( settings, null, 'plugin-init', [settings, json] ); 15536 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] ); 15537 } 15538 15539 15540 function _fnLengthChange ( settings, val ) 15541 { 15542 var len = parseInt( val, 10 ); 15543 settings._iDisplayLength = len; 15544 15545 _fnLengthOverflow( settings ); 15546 15547 // Fire length change event 15548 _fnCallbackFire( settings, null, 'length', [settings, len] ); 15549 } 15550 15551 15552 /** 15553 * Generate the node required for user display length changing 15554 * @param {object} settings dataTables settings object 15555 * @returns {node} Display length feature node 15556 * @memberof DataTable#oApi 15557 */ 15558 function _fnFeatureHtmlLength ( settings ) 15559 { 15560 var 15561 classes = settings.oClasses, 15562 tableId = settings.sTableId, 15563 menu = settings.aLengthMenu, 15564 d2 = $.isArray( menu[0] ), 15565 lengths = d2 ? menu[0] : menu, 15566 language = d2 ? menu[1] : menu; 15567 15568 var select = $('<select/>', { 15569 'name': tableId+'_length', 15570 'aria-controls': tableId, 15571 'class': classes.sLengthSelect 15572 } ); 15573 15574 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) { 15575 select[0][ i ] = new Option( language[i], lengths[i] ); 15576 } 15577 15578 var div = $('<div><label/></div>').addClass( classes.sLength ); 15579 if ( ! settings.aanFeatures.l ) { 15580 div[0].id = tableId+'_length'; 15581 } 15582 15583 div.children().append( 15584 settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML ) 15585 ); 15586 15587 // Can't use `select` variable as user might provide their own and the 15588 // reference is broken by the use of outerHTML 15589 $('select', div) 15590 .val( settings._iDisplayLength ) 15591 .bind( 'change.DT', function(e) { 15592 _fnLengthChange( settings, $(this).val() ); 15593 _fnDraw( settings ); 15594 } ); 15595 15596 // Update node value whenever anything changes the table's length 15597 $(settings.nTable).bind( 'length.dt.DT', function (e, s, len) { 15598 if ( settings === s ) { 15599 $('select', div).val( len ); 15600 } 15601 } ); 15602 15603 return div[0]; 15604 } 15605 15606 15607 15608 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 15609 * Note that most of the paging logic is done in 15610 * DataTable.ext.pager 15611 */ 15612 15613 /** 15614 * Generate the node required for default pagination 15615 * @param {object} oSettings dataTables settings object 15616 * @returns {node} Pagination feature node 15617 * @memberof DataTable#oApi 15618 */ 15619 function _fnFeatureHtmlPaginate ( settings ) 15620 { 15621 var 15622 type = settings.sPaginationType, 15623 plugin = DataTable.ext.pager[ type ], 15624 modern = typeof plugin === 'function', 15625 redraw = function( settings ) { 15626 _fnDraw( settings ); 15627 }, 15628 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0], 15629 features = settings.aanFeatures; 15630 15631 if ( ! modern ) { 15632 plugin.fnInit( settings, node, redraw ); 15633 } 15634 15635 /* Add a draw callback for the pagination on first instance, to update the paging display */ 15636 if ( ! features.p ) 15637 { 15638 node.id = settings.sTableId+'_paginate'; 15639 15640 settings.aoDrawCallback.push( { 15641 "fn": function( settings ) { 15642 if ( modern ) { 15643 var 15644 start = settings._iDisplayStart, 15645 len = settings._iDisplayLength, 15646 visRecords = settings.fnRecordsDisplay(), 15647 all = len === -1, 15648 page = all ? 0 : Math.ceil( start / len ), 15649 pages = all ? 1 : Math.ceil( visRecords / len ), 15650 buttons = plugin(page, pages), 15651 i, ien; 15652 15653 for ( i=0, ien=features.p.length ; i<ien ; i++ ) { 15654 _fnRenderer( settings, 'pageButton' )( 15655 settings, features.p[i], i, buttons, page, pages 15656 ); 15657 } 15658 } 15659 else { 15660 plugin.fnUpdate( settings, redraw ); 15661 } 15662 }, 15663 "sName": "pagination" 15664 } ); 15665 } 15666 15667 return node; 15668 } 15669 15670 15671 /** 15672 * Alter the display settings to change the page 15673 * @param {object} settings DataTables settings object 15674 * @param {string|int} action Paging action to take: "first", "previous", 15675 * "next" or "last" or page number to jump to (integer) 15676 * @param [bool] redraw Automatically draw the update or not 15677 * @returns {bool} true page has changed, false - no change 15678 * @memberof DataTable#oApi 15679 */ 15680 function _fnPageChange ( settings, action, redraw ) 15681 { 15682 var 15683 start = settings._iDisplayStart, 15684 len = settings._iDisplayLength, 15685 records = settings.fnRecordsDisplay(); 15686 15687 if ( records === 0 || len === -1 ) 15688 { 15689 start = 0; 15690 } 15691 else if ( typeof action === "number" ) 15692 { 15693 start = action * len; 15694 15695 if ( start > records ) 15696 { 15697 start = 0; 15698 } 15699 } 15700 else if ( action == "first" ) 15701 { 15702 start = 0; 15703 } 15704 else if ( action == "previous" ) 15705 { 15706 start = len >= 0 ? 15707 start - len : 15708 0; 15709 15710 if ( start < 0 ) 15711 { 15712 start = 0; 15713 } 15714 } 15715 else if ( action == "next" ) 15716 { 15717 if ( start + len < records ) 15718 { 15719 start += len; 15720 } 15721 } 15722 else if ( action == "last" ) 15723 { 15724 start = Math.floor( (records-1) / len) * len; 15725 } 15726 else 15727 { 15728 _fnLog( settings, 0, "Unknown paging action: "+action, 5 ); 15729 } 15730 15731 var changed = settings._iDisplayStart !== start; 15732 settings._iDisplayStart = start; 15733 15734 if ( changed ) { 15735 _fnCallbackFire( settings, null, 'page', [settings] ); 15736 15737 if ( redraw ) { 15738 _fnDraw( settings ); 15739 } 15740 } 15741 15742 return changed; 15743 } 15744 15745 15746 15747 /** 15748 * Generate the node required for the processing node 15749 * @param {object} settings dataTables settings object 15750 * @returns {node} Processing element 15751 * @memberof DataTable#oApi 15752 */ 15753 function _fnFeatureHtmlProcessing ( settings ) 15754 { 15755 return $('<div/>', { 15756 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null, 15757 'class': settings.oClasses.sProcessing 15758 } ) 15759 .html( settings.oLanguage.sProcessing ) 15760 .insertBefore( settings.nTable )[0]; 15761 } 15762 15763 15764 /** 15765 * Display or hide the processing indicator 15766 * @param {object} settings dataTables settings object 15767 * @param {bool} show Show the processing indicator (true) or not (false) 15768 * @memberof DataTable#oApi 15769 */ 15770 function _fnProcessingDisplay ( settings, show ) 15771 { 15772 if ( settings.oFeatures.bProcessing ) { 15773 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' ); 15774 } 15775 15776 _fnCallbackFire( settings, null, 'processing', [settings, show] ); 15777 } 15778 15779 /** 15780 * Add any control elements for the table - specifically scrolling 15781 * @param {object} settings dataTables settings object 15782 * @returns {node} Node to add to the DOM 15783 * @memberof DataTable#oApi 15784 */ 15785 function _fnFeatureHtmlTable ( settings ) 15786 { 15787 var table = $(settings.nTable); 15788 15789 // Add the ARIA grid role to the table 15790 table.attr( 'role', 'grid' ); 15791 15792 // Scrolling from here on in 15793 var scroll = settings.oScroll; 15794 15795 if ( scroll.sX === '' && scroll.sY === '' ) { 15796 return settings.nTable; 15797 } 15798 15799 var scrollX = scroll.sX; 15800 var scrollY = scroll.sY; 15801 var classes = settings.oClasses; 15802 var caption = table.children('caption'); 15803 var captionSide = caption.length ? caption[0]._captionSide : null; 15804 var headerClone = $( table[0].cloneNode(false) ); 15805 var footerClone = $( table[0].cloneNode(false) ); 15806 var footer = table.children('tfoot'); 15807 var _div = '<div/>'; 15808 var size = function ( s ) { 15809 return !s ? null : _fnStringToCss( s ); 15810 }; 15811 15812 if ( ! footer.length ) { 15813 footer = null; 15814 } 15815 15816 /* 15817 * The HTML structure that we want to generate in this function is: 15818 * div - scroller 15819 * div - scroll head 15820 * div - scroll head inner 15821 * table - scroll head table 15822 * thead - thead 15823 * div - scroll body 15824 * table - table (master table) 15825 * thead - thead clone for sizing 15826 * tbody - tbody 15827 * div - scroll foot 15828 * div - scroll foot inner 15829 * table - scroll foot table 15830 * tfoot - tfoot 15831 */ 15832 var scroller = $( _div, { 'class': classes.sScrollWrapper } ) 15833 .append( 15834 $(_div, { 'class': classes.sScrollHead } ) 15835 .css( { 15836 overflow: 'hidden', 15837 position: 'relative', 15838 border: 0, 15839 width: scrollX ? size(scrollX) : '100%' 15840 } ) 15841 .append( 15842 $(_div, { 'class': classes.sScrollHeadInner } ) 15843 .css( { 15844 'box-sizing': 'content-box', 15845 width: scroll.sXInner || '100%' 15846 } ) 15847 .append( 15848 headerClone 15849 .removeAttr('id') 15850 .css( 'margin-left', 0 ) 15851 .append( captionSide === 'top' ? caption : null ) 15852 .append( 15853 table.children('thead') 15854 ) 15855 ) 15856 ) 15857 ) 15858 .append( 15859 $(_div, { 'class': classes.sScrollBody } ) 15860 .css( { 15861 position: 'relative', 15862 overflow: 'auto', 15863 width: size( scrollX ) 15864 } ) 15865 .append( table ) 15866 ); 15867 15868 if ( footer ) { 15869 scroller.append( 15870 $(_div, { 'class': classes.sScrollFoot } ) 15871 .css( { 15872 overflow: 'hidden', 15873 border: 0, 15874 width: scrollX ? size(scrollX) : '100%' 15875 } ) 15876 .append( 15877 $(_div, { 'class': classes.sScrollFootInner } ) 15878 .append( 15879 footerClone 15880 .removeAttr('id') 15881 .css( 'margin-left', 0 ) 15882 .append( captionSide === 'bottom' ? caption : null ) 15883 .append( 15884 table.children('tfoot') 15885 ) 15886 ) 15887 ) 15888 ); 15889 } 15890 15891 var children = scroller.children(); 15892 var scrollHead = children[0]; 15893 var scrollBody = children[1]; 15894 var scrollFoot = footer ? children[2] : null; 15895 15896 // When the body is scrolled, then we also want to scroll the headers 15897 if ( scrollX ) { 15898 $(scrollBody).on( 'scroll.DT', function (e) { 15899 var scrollLeft = this.scrollLeft; 15900 15901 scrollHead.scrollLeft = scrollLeft; 15902 15903 if ( footer ) { 15904 scrollFoot.scrollLeft = scrollLeft; 15905 } 15906 } ); 15907 } 15908 15909 $(scrollBody).css( 15910 scrollY && scroll.bCollapse ? 'max-height' : 'height', 15911 scrollY 15912 ); 15913 15914 settings.nScrollHead = scrollHead; 15915 settings.nScrollBody = scrollBody; 15916 settings.nScrollFoot = scrollFoot; 15917 15918 // On redraw - align columns 15919 settings.aoDrawCallback.push( { 15920 "fn": _fnScrollDraw, 15921 "sName": "scrolling" 15922 } ); 15923 15924 return scroller[0]; 15925 } 15926 15927 15928 15929 /** 15930 * Update the header, footer and body tables for resizing - i.e. column 15931 * alignment. 15932 * 15933 * Welcome to the most horrible function DataTables. The process that this 15934 * function follows is basically: 15935 * 1. Re-create the table inside the scrolling div 15936 * 2. Take live measurements from the DOM 15937 * 3. Apply the measurements to align the columns 15938 * 4. Clean up 15939 * 15940 * @param {object} settings dataTables settings object 15941 * @memberof DataTable#oApi 15942 */ 15943 function _fnScrollDraw ( settings ) 15944 { 15945 // Given that this is such a monster function, a lot of variables are use 15946 // to try and keep the minimised size as small as possible 15947 var 15948 scroll = settings.oScroll, 15949 scrollX = scroll.sX, 15950 scrollXInner = scroll.sXInner, 15951 scrollY = scroll.sY, 15952 barWidth = scroll.iBarWidth, 15953 divHeader = $(settings.nScrollHead), 15954 divHeaderStyle = divHeader[0].style, 15955 divHeaderInner = divHeader.children('div'), 15956 divHeaderInnerStyle = divHeaderInner[0].style, 15957 divHeaderTable = divHeaderInner.children('table'), 15958 divBodyEl = settings.nScrollBody, 15959 divBody = $(divBodyEl), 15960 divBodyStyle = divBodyEl.style, 15961 divFooter = $(settings.nScrollFoot), 15962 divFooterInner = divFooter.children('div'), 15963 divFooterTable = divFooterInner.children('table'), 15964 header = $(settings.nTHead), 15965 table = $(settings.nTable), 15966 tableEl = table[0], 15967 tableStyle = tableEl.style, 15968 footer = settings.nTFoot ? $(settings.nTFoot) : null, 15969 browser = settings.oBrowser, 15970 ie67 = browser.bScrollOversize, 15971 dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ), 15972 headerTrgEls, footerTrgEls, 15973 headerSrcEls, footerSrcEls, 15974 headerCopy, footerCopy, 15975 headerWidths=[], footerWidths=[], 15976 headerContent=[], footerContent=[], 15977 idx, correction, sanityWidth, 15978 zeroOut = function(nSizer) { 15979 var style = nSizer.style; 15980 style.paddingTop = "0"; 15981 style.paddingBottom = "0"; 15982 style.borderTopWidth = "0"; 15983 style.borderBottomWidth = "0"; 15984 style.height = 0; 15985 }; 15986 15987 // If the scrollbar visibility has changed from the last draw, we need to 15988 // adjust the column sizes as the table width will have changed to account 15989 // for the scrollbar 15990 var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight; 15991 15992 if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) { 15993 settings.scrollBarVis = scrollBarVis; 15994 _fnAdjustColumnSizing( settings ); 15995 return; // adjust column sizing will call this function again 15996 } 15997 else { 15998 settings.scrollBarVis = scrollBarVis; 15999 } 16000 16001 /* 16002 * 1. Re-create the table inside the scrolling div 16003 */ 16004 16005 // Remove the old minimised thead and tfoot elements in the inner table 16006 table.children('thead, tfoot').remove(); 16007 16008 if ( footer ) { 16009 footerCopy = footer.clone().prependTo( table ); 16010 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized 16011 footerSrcEls = footerCopy.find('tr'); 16012 } 16013 16014 // Clone the current header and footer elements and then place it into the inner table 16015 headerCopy = header.clone().prependTo( table ); 16016 headerTrgEls = header.find('tr'); // original header is in its own table 16017 headerSrcEls = headerCopy.find('tr'); 16018 headerCopy.find('th, td').removeAttr('tabindex'); 16019 16020 16021 /* 16022 * 2. Take live measurements from the DOM - do not alter the DOM itself! 16023 */ 16024 16025 // Remove old sizing and apply the calculated column widths 16026 // Get the unique column headers in the newly created (cloned) header. We want to apply the 16027 // calculated sizes to this header 16028 if ( ! scrollX ) 16029 { 16030 divBodyStyle.width = '100%'; 16031 divHeader[0].style.width = '100%'; 16032 } 16033 16034 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) { 16035 idx = _fnVisibleToColumnIndex( settings, i ); 16036 el.style.width = settings.aoColumns[idx].sWidth; 16037 } ); 16038 16039 if ( footer ) { 16040 _fnApplyToChildren( function(n) { 16041 n.style.width = ""; 16042 }, footerSrcEls ); 16043 } 16044 16045 // Size the table as a whole 16046 sanityWidth = table.outerWidth(); 16047 if ( scrollX === "" ) { 16048 // No x scrolling 16049 tableStyle.width = "100%"; 16050 16051 // IE7 will make the width of the table when 100% include the scrollbar 16052 // - which is shouldn't. When there is a scrollbar we need to take this 16053 // into account. 16054 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight || 16055 divBody.css('overflow-y') == "scroll") 16056 ) { 16057 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth); 16058 } 16059 16060 // Recalculate the sanity width 16061 sanityWidth = table.outerWidth(); 16062 } 16063 else if ( scrollXInner !== "" ) { 16064 // legacy x scroll inner has been given - use it 16065 tableStyle.width = _fnStringToCss(scrollXInner); 16066 16067 // Recalculate the sanity width 16068 sanityWidth = table.outerWidth(); 16069 } 16070 16071 // Hidden header should have zero height, so remove padding and borders. Then 16072 // set the width based on the real headers 16073 16074 // Apply all styles in one pass 16075 _fnApplyToChildren( zeroOut, headerSrcEls ); 16076 16077 // Read all widths in next pass 16078 _fnApplyToChildren( function(nSizer) { 16079 headerContent.push( nSizer.innerHTML ); 16080 headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); 16081 }, headerSrcEls ); 16082 16083 // Apply all widths in final pass 16084 _fnApplyToChildren( function(nToSize, i) { 16085 // Only apply widths to the DataTables detected header cells - this 16086 // prevents complex headers from having contradictory sizes applied 16087 if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) { 16088 nToSize.style.width = headerWidths[i]; 16089 } 16090 }, headerTrgEls ); 16091 16092 $(headerSrcEls).height(0); 16093 16094 /* Same again with the footer if we have one */ 16095 if ( footer ) 16096 { 16097 _fnApplyToChildren( zeroOut, footerSrcEls ); 16098 16099 _fnApplyToChildren( function(nSizer) { 16100 footerContent.push( nSizer.innerHTML ); 16101 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); 16102 }, footerSrcEls ); 16103 16104 _fnApplyToChildren( function(nToSize, i) { 16105 nToSize.style.width = footerWidths[i]; 16106 }, footerTrgEls ); 16107 16108 $(footerSrcEls).height(0); 16109 } 16110 16111 16112 /* 16113 * 3. Apply the measurements 16114 */ 16115 16116 // "Hide" the header and footer that we used for the sizing. We need to keep 16117 // the content of the cell so that the width applied to the header and body 16118 // both match, but we want to hide it completely. We want to also fix their 16119 // width to what they currently are 16120 _fnApplyToChildren( function(nSizer, i) { 16121 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>'; 16122 nSizer.style.width = headerWidths[i]; 16123 }, headerSrcEls ); 16124 16125 if ( footer ) 16126 { 16127 _fnApplyToChildren( function(nSizer, i) { 16128 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+footerContent[i]+'</div>'; 16129 nSizer.style.width = footerWidths[i]; 16130 }, footerSrcEls ); 16131 } 16132 16133 // Sanity check that the table is of a sensible width. If not then we are going to get 16134 // misalignment - try to prevent this by not allowing the table to shrink below its min width 16135 if ( table.outerWidth() < sanityWidth ) 16136 { 16137 // The min width depends upon if we have a vertical scrollbar visible or not */ 16138 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight || 16139 divBody.css('overflow-y') == "scroll")) ? 16140 sanityWidth+barWidth : 16141 sanityWidth; 16142 16143 // IE6/7 are a law unto themselves... 16144 if ( ie67 && (divBodyEl.scrollHeight > 16145 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll") 16146 ) { 16147 tableStyle.width = _fnStringToCss( correction-barWidth ); 16148 } 16149 16150 // And give the user a warning that we've stopped the table getting too small 16151 if ( scrollX === "" || scrollXInner !== "" ) { 16152 _fnLog( settings, 1, 'Possible column misalignment', 6 ); 16153 } 16154 } 16155 else 16156 { 16157 correction = '100%'; 16158 } 16159 16160 // Apply to the container elements 16161 divBodyStyle.width = _fnStringToCss( correction ); 16162 divHeaderStyle.width = _fnStringToCss( correction ); 16163 16164 if ( footer ) { 16165 settings.nScrollFoot.style.width = _fnStringToCss( correction ); 16166 } 16167 16168 16169 /* 16170 * 4. Clean up 16171 */ 16172 if ( ! scrollY ) { 16173 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting 16174 * the scrollbar height from the visible display, rather than adding it on. We need to 16175 * set the height in order to sort this. Don't want to do it in any other browsers. 16176 */ 16177 if ( ie67 ) { 16178 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth ); 16179 } 16180 } 16181 16182 /* Finally set the width's of the header and footer tables */ 16183 var iOuterWidth = table.outerWidth(); 16184 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth ); 16185 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth ); 16186 16187 // Figure out if there are scrollbar present - if so then we need a the header and footer to 16188 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) 16189 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll"; 16190 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' ); 16191 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px"; 16192 16193 if ( footer ) { 16194 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth ); 16195 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth ); 16196 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px"; 16197 } 16198 16199 // Correct DOM ordering for colgroup - comes before the thead 16200 table.children('colgroup').insertBefore( table.children('thead') ); 16201 16202 /* Adjust the position of the header in case we loose the y-scrollbar */ 16203 divBody.scroll(); 16204 16205 // If sorting or filtering has occurred, jump the scrolling back to the top 16206 // only if we aren't holding the position 16207 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) { 16208 divBodyEl.scrollTop = 0; 16209 } 16210 } 16211 16212 16213 16214 /** 16215 * Apply a given function to the display child nodes of an element array (typically 16216 * TD children of TR rows 16217 * @param {function} fn Method to apply to the objects 16218 * @param array {nodes} an1 List of elements to look through for display children 16219 * @param array {nodes} an2 Another list (identical structure to the first) - optional 16220 * @memberof DataTable#oApi 16221 */ 16222 function _fnApplyToChildren( fn, an1, an2 ) 16223 { 16224 var index=0, i=0, iLen=an1.length; 16225 var nNode1, nNode2; 16226 16227 while ( i < iLen ) { 16228 nNode1 = an1[i].firstChild; 16229 nNode2 = an2 ? an2[i].firstChild : null; 16230 16231 while ( nNode1 ) { 16232 if ( nNode1.nodeType === 1 ) { 16233 if ( an2 ) { 16234 fn( nNode1, nNode2, index ); 16235 } 16236 else { 16237 fn( nNode1, index ); 16238 } 16239 16240 index++; 16241 } 16242 16243 nNode1 = nNode1.nextSibling; 16244 nNode2 = an2 ? nNode2.nextSibling : null; 16245 } 16246 16247 i++; 16248 } 16249 } 16250 16251 16252 16253 var __re_html_remove = /<.*?>/g; 16254 16255 16256 /** 16257 * Calculate the width of columns for the table 16258 * @param {object} oSettings dataTables settings object 16259 * @memberof DataTable#oApi 16260 */ 16261 function _fnCalculateColumnWidths ( oSettings ) 16262 { 16263 var 16264 table = oSettings.nTable, 16265 columns = oSettings.aoColumns, 16266 scroll = oSettings.oScroll, 16267 scrollY = scroll.sY, 16268 scrollX = scroll.sX, 16269 scrollXInner = scroll.sXInner, 16270 columnCount = columns.length, 16271 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ), 16272 headerCells = $('th', oSettings.nTHead), 16273 tableWidthAttr = table.getAttribute('width'), // from DOM element 16274 tableContainer = table.parentNode, 16275 userInputs = false, 16276 i, column, columnIdx, width, outerWidth, 16277 browser = oSettings.oBrowser, 16278 ie67 = browser.bScrollOversize; 16279 16280 var styleWidth = table.style.width; 16281 if ( styleWidth && styleWidth.indexOf('%') !== -1 ) { 16282 tableWidthAttr = styleWidth; 16283 } 16284 16285 /* Convert any user input sizes into pixel sizes */ 16286 for ( i=0 ; i<visibleColumns.length ; i++ ) { 16287 column = columns[ visibleColumns[i] ]; 16288 16289 if ( column.sWidth !== null ) { 16290 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer ); 16291 16292 userInputs = true; 16293 } 16294 } 16295 16296 /* If the number of columns in the DOM equals the number that we have to 16297 * process in DataTables, then we can use the offsets that are created by 16298 * the web- browser. No custom sizes can be set in order for this to happen, 16299 * nor scrolling used 16300 */ 16301 if ( ie67 || ! userInputs && ! scrollX && ! scrollY && 16302 columnCount == _fnVisbleColumns( oSettings ) && 16303 columnCount == headerCells.length 16304 ) { 16305 for ( i=0 ; i<columnCount ; i++ ) { 16306 var colIdx = _fnVisibleToColumnIndex( oSettings, i ); 16307 16308 if ( colIdx !== null ) { 16309 columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() ); 16310 } 16311 } 16312 } 16313 else 16314 { 16315 // Otherwise construct a single row, worst case, table with the widest 16316 // node in the data, assign any user defined widths, then insert it into 16317 // the DOM and allow the browser to do all the hard work of calculating 16318 // table widths 16319 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table 16320 .css( 'visibility', 'hidden' ) 16321 .removeAttr( 'id' ); 16322 16323 // Clean up the table body 16324 tmpTable.find('tbody tr').remove(); 16325 var tr = $('<tr/>').appendTo( tmpTable.find('tbody') ); 16326 16327 // Clone the table header and footer - we can't use the header / footer 16328 // from the cloned table, since if scrolling is active, the table's 16329 // real header and footer are contained in different table tags 16330 tmpTable.find('thead, tfoot').remove(); 16331 tmpTable 16332 .append( $(oSettings.nTHead).clone() ) 16333 .append( $(oSettings.nTFoot).clone() ); 16334 16335 // Remove any assigned widths from the footer (from scrolling) 16336 tmpTable.find('tfoot th, tfoot td').css('width', ''); 16337 16338 // Apply custom sizing to the cloned header 16339 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] ); 16340 16341 for ( i=0 ; i<visibleColumns.length ; i++ ) { 16342 column = columns[ visibleColumns[i] ]; 16343 16344 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ? 16345 _fnStringToCss( column.sWidthOrig ) : 16346 ''; 16347 16348 // For scrollX we need to force the column width otherwise the 16349 // browser will collapse it. If this width is smaller than the 16350 // width the column requires, then it will have no effect 16351 if ( column.sWidthOrig && scrollX ) { 16352 $( headerCells[i] ).append( $('<div/>').css( { 16353 width: column.sWidthOrig, 16354 margin: 0, 16355 padding: 0, 16356 border: 0, 16357 height: 1 16358 } ) ); 16359 } 16360 } 16361 16362 // Find the widest cell for each column and put it into the table 16363 if ( oSettings.aoData.length ) { 16364 for ( i=0 ; i<visibleColumns.length ; i++ ) { 16365 columnIdx = visibleColumns[i]; 16366 column = columns[ columnIdx ]; 16367 16368 $( _fnGetWidestNode( oSettings, columnIdx ) ) 16369 .clone( false ) 16370 .append( column.sContentPadding ) 16371 .appendTo( tr ); 16372 } 16373 } 16374 16375 // Tidy the temporary table - remove name attributes so there aren't 16376 // duplicated in the dom (radio elements for example) 16377 $('[name]', tmpTable).removeAttr('name'); 16378 16379 // Table has been built, attach to the document so we can work with it. 16380 // A holding element is used, positioned at the top of the container 16381 // with minimal height, so it has no effect on if the container scrolls 16382 // or not. Otherwise it might trigger scrolling when it actually isn't 16383 // needed 16384 var holder = $('<div/>').css( scrollX || scrollY ? 16385 { 16386 position: 'absolute', 16387 top: 0, 16388 left: 0, 16389 height: 1, 16390 right: 0, 16391 overflow: 'hidden' 16392 } : 16393 {} 16394 ) 16395 .append( tmpTable ) 16396 .appendTo( tableContainer ); 16397 16398 // When scrolling (X or Y) we want to set the width of the table as 16399 // appropriate. However, when not scrolling leave the table width as it 16400 // is. This results in slightly different, but I think correct behaviour 16401 if ( scrollX && scrollXInner ) { 16402 tmpTable.width( scrollXInner ); 16403 } 16404 else if ( scrollX ) { 16405 tmpTable.css( 'width', 'auto' ); 16406 tmpTable.removeAttr('width'); 16407 16408 // If there is no width attribute or style, then allow the table to 16409 // collapse 16410 if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) { 16411 tmpTable.width( tableContainer.clientWidth ); 16412 } 16413 } 16414 else if ( scrollY ) { 16415 tmpTable.width( tableContainer.clientWidth ); 16416 } 16417 else if ( tableWidthAttr ) { 16418 tmpTable.width( tableWidthAttr ); 16419 } 16420 16421 // Get the width of each column in the constructed table - we need to 16422 // know the inner width (so it can be assigned to the other table's 16423 // cells) and the outer width so we can calculate the full width of the 16424 // table. This is safe since DataTables requires a unique cell for each 16425 // column, but if ever a header can span multiple columns, this will 16426 // need to be modified. 16427 var total = 0; 16428 for ( i=0 ; i<visibleColumns.length ; i++ ) { 16429 var cell = $(headerCells[i]); 16430 var border = cell.outerWidth() - cell.width(); 16431 16432 // Use getBounding... where possible (not IE8-) because it can give 16433 // sub-pixel accuracy, which we then want to round up! 16434 var bounding = browser.bBounding ? 16435 Math.ceil( headerCells[i].getBoundingClientRect().width ) : 16436 cell.outerWidth(); 16437 16438 // Total is tracked to remove any sub-pixel errors as the outerWidth 16439 // of the table might not equal the total given here (IE!). 16440 total += bounding; 16441 16442 // Width for each column to use 16443 columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border ); 16444 } 16445 16446 table.style.width = _fnStringToCss( total ); 16447 16448 // Finished with the table - ditch it 16449 holder.remove(); 16450 } 16451 16452 // If there is a width attr, we want to attach an event listener which 16453 // allows the table sizing to automatically adjust when the window is 16454 // resized. Use the width attr rather than CSS, since we can't know if the 16455 // CSS is a relative value or absolute - DOM read is always px. 16456 if ( tableWidthAttr ) { 16457 table.style.width = _fnStringToCss( tableWidthAttr ); 16458 } 16459 16460 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) { 16461 var bindResize = function () { 16462 $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () { 16463 _fnAdjustColumnSizing( oSettings ); 16464 } ) ); 16465 }; 16466 16467 // IE6/7 will crash if we bind a resize event handler on page load. 16468 // To be removed in 1.11 which drops IE6/7 support 16469 if ( ie67 ) { 16470 setTimeout( bindResize, 1000 ); 16471 } 16472 else { 16473 bindResize(); 16474 } 16475 16476 oSettings._reszEvt = true; 16477 } 16478 } 16479 16480 16481 /** 16482 * Throttle the calls to a function. Arguments and context are maintained for 16483 * the throttled function 16484 * @param {function} fn Function to be called 16485 * @param {int} [freq=200] call frequency in mS 16486 * @returns {function} wrapped function 16487 * @memberof DataTable#oApi 16488 */ 16489 var _fnThrottle = DataTable.util.throttle; 16490 16491 16492 /** 16493 * Convert a CSS unit width to pixels (e.g. 2em) 16494 * @param {string} width width to be converted 16495 * @param {node} parent parent to get the with for (required for relative widths) - optional 16496 * @returns {int} width in pixels 16497 * @memberof DataTable#oApi 16498 */ 16499 function _fnConvertToWidth ( width, parent ) 16500 { 16501 if ( ! width ) { 16502 return 0; 16503 } 16504 16505 var n = $('<div/>') 16506 .css( 'width', _fnStringToCss( width ) ) 16507 .appendTo( parent || document.body ); 16508 16509 var val = n[0].offsetWidth; 16510 n.remove(); 16511 16512 return val; 16513 } 16514 16515 16516 /** 16517 * Get the widest node 16518 * @param {object} settings dataTables settings object 16519 * @param {int} colIdx column of interest 16520 * @returns {node} widest table node 16521 * @memberof DataTable#oApi 16522 */ 16523 function _fnGetWidestNode( settings, colIdx ) 16524 { 16525 var idx = _fnGetMaxLenString( settings, colIdx ); 16526 if ( idx < 0 ) { 16527 return null; 16528 } 16529 16530 var data = settings.aoData[ idx ]; 16531 return ! data.nTr ? // Might not have been created when deferred rendering 16532 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] : 16533 data.anCells[ colIdx ]; 16534 } 16535 16536 16537 /** 16538 * Get the maximum strlen for each data column 16539 * @param {object} settings dataTables settings object 16540 * @param {int} colIdx column of interest 16541 * @returns {string} max string length for each column 16542 * @memberof DataTable#oApi 16543 */ 16544 function _fnGetMaxLenString( settings, colIdx ) 16545 { 16546 var s, max=-1, maxIdx = -1; 16547 16548 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 16549 s = _fnGetCellData( settings, i, colIdx, 'display' )+''; 16550 s = s.replace( __re_html_remove, '' ); 16551 s = s.replace( / /g, ' ' ); 16552 16553 if ( s.length > max ) { 16554 max = s.length; 16555 maxIdx = i; 16556 } 16557 } 16558 16559 return maxIdx; 16560 } 16561 16562 16563 /** 16564 * Append a CSS unit (only if required) to a string 16565 * @param {string} value to css-ify 16566 * @returns {string} value with css unit 16567 * @memberof DataTable#oApi 16568 */ 16569 function _fnStringToCss( s ) 16570 { 16571 if ( s === null ) { 16572 return '0px'; 16573 } 16574 16575 if ( typeof s == 'number' ) { 16576 return s < 0 ? 16577 '0px' : 16578 s+'px'; 16579 } 16580 16581 // Check it has a unit character already 16582 return s.match(/\d$/) ? 16583 s+'px' : 16584 s; 16585 } 16586 16587 16588 16589 function _fnSortFlatten ( settings ) 16590 { 16591 var 16592 i, iLen, k, kLen, 16593 aSort = [], 16594 aiOrig = [], 16595 aoColumns = settings.aoColumns, 16596 aDataSort, iCol, sType, srcCol, 16597 fixed = settings.aaSortingFixed, 16598 fixedObj = $.isPlainObject( fixed ), 16599 nestedSort = [], 16600 add = function ( a ) { 16601 if ( a.length && ! $.isArray( a[0] ) ) { 16602 // 1D array 16603 nestedSort.push( a ); 16604 } 16605 else { 16606 // 2D array 16607 $.merge( nestedSort, a ); 16608 } 16609 }; 16610 16611 // Build the sort array, with pre-fix and post-fix options if they have been 16612 // specified 16613 if ( $.isArray( fixed ) ) { 16614 add( fixed ); 16615 } 16616 16617 if ( fixedObj && fixed.pre ) { 16618 add( fixed.pre ); 16619 } 16620 16621 add( settings.aaSorting ); 16622 16623 if (fixedObj && fixed.post ) { 16624 add( fixed.post ); 16625 } 16626 16627 for ( i=0 ; i<nestedSort.length ; i++ ) 16628 { 16629 srcCol = nestedSort[i][0]; 16630 aDataSort = aoColumns[ srcCol ].aDataSort; 16631 16632 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ ) 16633 { 16634 iCol = aDataSort[k]; 16635 sType = aoColumns[ iCol ].sType || 'string'; 16636 16637 if ( nestedSort[i]._idx === undefined ) { 16638 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting ); 16639 } 16640 16641 aSort.push( { 16642 src: srcCol, 16643 col: iCol, 16644 dir: nestedSort[i][1], 16645 index: nestedSort[i]._idx, 16646 type: sType, 16647 formatter: DataTable.ext.type.order[ sType+"-pre" ] 16648 } ); 16649 } 16650 } 16651 16652 return aSort; 16653 } 16654 16655 /** 16656 * Change the order of the table 16657 * @param {object} oSettings dataTables settings object 16658 * @memberof DataTable#oApi 16659 * @todo This really needs split up! 16660 */ 16661 function _fnSort ( oSettings ) 16662 { 16663 var 16664 i, ien, iLen, j, jLen, k, kLen, 16665 sDataType, nTh, 16666 aiOrig = [], 16667 oExtSort = DataTable.ext.type.order, 16668 aoData = oSettings.aoData, 16669 aoColumns = oSettings.aoColumns, 16670 aDataSort, data, iCol, sType, oSort, 16671 formatters = 0, 16672 sortCol, 16673 displayMaster = oSettings.aiDisplayMaster, 16674 aSort; 16675 16676 // Resolve any column types that are unknown due to addition or invalidation 16677 // @todo Can this be moved into a 'data-ready' handler which is called when 16678 // data is going to be used in the table? 16679 _fnColumnTypes( oSettings ); 16680 16681 aSort = _fnSortFlatten( oSettings ); 16682 16683 for ( i=0, ien=aSort.length ; i<ien ; i++ ) { 16684 sortCol = aSort[i]; 16685 16686 // Track if we can use the fast sort algorithm 16687 if ( sortCol.formatter ) { 16688 formatters++; 16689 } 16690 16691 // Load the data needed for the sort, for each cell 16692 _fnSortData( oSettings, sortCol.col ); 16693 } 16694 16695 /* No sorting required if server-side or no sorting array */ 16696 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 ) 16697 { 16698 // Create a value - key array of the current row positions such that we can use their 16699 // current position during the sort, if values match, in order to perform stable sorting 16700 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) { 16701 aiOrig[ displayMaster[i] ] = i; 16702 } 16703 16704 /* Do the sort - here we want multi-column sorting based on a given data source (column) 16705 * and sorting function (from oSort) in a certain direction. It's reasonably complex to 16706 * follow on it's own, but this is what we want (example two column sorting): 16707 * fnLocalSorting = function(a,b){ 16708 * var iTest; 16709 * iTest = oSort['string-asc']('data11', 'data12'); 16710 * if (iTest !== 0) 16711 * return iTest; 16712 * iTest = oSort['numeric-desc']('data21', 'data22'); 16713 * if (iTest !== 0) 16714 * return iTest; 16715 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] ); 16716 * } 16717 * Basically we have a test for each sorting column, if the data in that column is equal, 16718 * test the next column. If all columns match, then we use a numeric sort on the row 16719 * positions in the original data array to provide a stable sort. 16720 * 16721 * Note - I know it seems excessive to have two sorting methods, but the first is around 16722 * 15% faster, so the second is only maintained for backwards compatibility with sorting 16723 * methods which do not have a pre-sort formatting function. 16724 */ 16725 if ( formatters === aSort.length ) { 16726 // All sort types have formatting functions 16727 displayMaster.sort( function ( a, b ) { 16728 var 16729 x, y, k, test, sort, 16730 len=aSort.length, 16731 dataA = aoData[a]._aSortData, 16732 dataB = aoData[b]._aSortData; 16733 16734 for ( k=0 ; k<len ; k++ ) { 16735 sort = aSort[k]; 16736 16737 x = dataA[ sort.col ]; 16738 y = dataB[ sort.col ]; 16739 16740 test = x<y ? -1 : x>y ? 1 : 0; 16741 if ( test !== 0 ) { 16742 return sort.dir === 'asc' ? test : -test; 16743 } 16744 } 16745 16746 x = aiOrig[a]; 16747 y = aiOrig[b]; 16748 return x<y ? -1 : x>y ? 1 : 0; 16749 } ); 16750 } 16751 else { 16752 // Depreciated - remove in 1.11 (providing a plug-in option) 16753 // Not all sort types have formatting methods, so we have to call their sorting 16754 // methods. 16755 displayMaster.sort( function ( a, b ) { 16756 var 16757 x, y, k, l, test, sort, fn, 16758 len=aSort.length, 16759 dataA = aoData[a]._aSortData, 16760 dataB = aoData[b]._aSortData; 16761 16762 for ( k=0 ; k<len ; k++ ) { 16763 sort = aSort[k]; 16764 16765 x = dataA[ sort.col ]; 16766 y = dataB[ sort.col ]; 16767 16768 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ]; 16769 test = fn( x, y ); 16770 if ( test !== 0 ) { 16771 return test; 16772 } 16773 } 16774 16775 x = aiOrig[a]; 16776 y = aiOrig[b]; 16777 return x<y ? -1 : x>y ? 1 : 0; 16778 } ); 16779 } 16780 } 16781 16782 /* Tell the draw function that we have sorted the data */ 16783 oSettings.bSorted = true; 16784 } 16785 16786 16787 function _fnSortAria ( settings ) 16788 { 16789 var label; 16790 var nextSort; 16791 var columns = settings.aoColumns; 16792 var aSort = _fnSortFlatten( settings ); 16793 var oAria = settings.oLanguage.oAria; 16794 16795 // ARIA attributes - need to loop all columns, to update all (removing old 16796 // attributes as needed) 16797 for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) 16798 { 16799 var col = columns[i]; 16800 var asSorting = col.asSorting; 16801 var sTitle = col.sTitle.replace( /<.*?>/g, "" ); 16802 var th = col.nTh; 16803 16804 // IE7 is throwing an error when setting these properties with jQuery's 16805 // attr() and removeAttr() methods... 16806 th.removeAttribute('aria-sort'); 16807 16808 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */ 16809 if ( col.bSortable ) { 16810 if ( aSort.length > 0 && aSort[0].col == i ) { 16811 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" ); 16812 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0]; 16813 } 16814 else { 16815 nextSort = asSorting[0]; 16816 } 16817 16818 label = sTitle + ( nextSort === "asc" ? 16819 oAria.sSortAscending : 16820 oAria.sSortDescending 16821 ); 16822 } 16823 else { 16824 label = sTitle; 16825 } 16826 16827 th.setAttribute('aria-label', label); 16828 } 16829 } 16830 16831 16832 /** 16833 * Function to run on user sort request 16834 * @param {object} settings dataTables settings object 16835 * @param {node} attachTo node to attach the handler to 16836 * @param {int} colIdx column sorting index 16837 * @param {boolean} [append=false] Append the requested sort to the existing 16838 * sort if true (i.e. multi-column sort) 16839 * @param {function} [callback] callback function 16840 * @memberof DataTable#oApi 16841 */ 16842 function _fnSortListener ( settings, colIdx, append, callback ) 16843 { 16844 var col = settings.aoColumns[ colIdx ]; 16845 var sorting = settings.aaSorting; 16846 var asSorting = col.asSorting; 16847 var nextSortIdx; 16848 var next = function ( a, overflow ) { 16849 var idx = a._idx; 16850 if ( idx === undefined ) { 16851 idx = $.inArray( a[1], asSorting ); 16852 } 16853 16854 return idx+1 < asSorting.length ? 16855 idx+1 : 16856 overflow ? 16857 null : 16858 0; 16859 }; 16860 16861 // Convert to 2D array if needed 16862 if ( typeof sorting[0] === 'number' ) { 16863 sorting = settings.aaSorting = [ sorting ]; 16864 } 16865 16866 // If appending the sort then we are multi-column sorting 16867 if ( append && settings.oFeatures.bSortMulti ) { 16868 // Are we already doing some kind of sort on this column? 16869 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') ); 16870 16871 if ( sortIdx !== -1 ) { 16872 // Yes, modify the sort 16873 nextSortIdx = next( sorting[sortIdx], true ); 16874 16875 if ( nextSortIdx === null && sorting.length === 1 ) { 16876 nextSortIdx = 0; // can't remove sorting completely 16877 } 16878 16879 if ( nextSortIdx === null ) { 16880 sorting.splice( sortIdx, 1 ); 16881 } 16882 else { 16883 sorting[sortIdx][1] = asSorting[ nextSortIdx ]; 16884 sorting[sortIdx]._idx = nextSortIdx; 16885 } 16886 } 16887 else { 16888 // No sort on this column yet 16889 sorting.push( [ colIdx, asSorting[0], 0 ] ); 16890 sorting[sorting.length-1]._idx = 0; 16891 } 16892 } 16893 else if ( sorting.length && sorting[0][0] == colIdx ) { 16894 // Single column - already sorting on this column, modify the sort 16895 nextSortIdx = next( sorting[0] ); 16896 16897 sorting.length = 1; 16898 sorting[0][1] = asSorting[ nextSortIdx ]; 16899 sorting[0]._idx = nextSortIdx; 16900 } 16901 else { 16902 // Single column - sort only on this column 16903 sorting.length = 0; 16904 sorting.push( [ colIdx, asSorting[0] ] ); 16905 sorting[0]._idx = 0; 16906 } 16907 16908 // Run the sort by calling a full redraw 16909 _fnReDraw( settings ); 16910 16911 // callback used for async user interaction 16912 if ( typeof callback == 'function' ) { 16913 callback( settings ); 16914 } 16915 } 16916 16917 16918 /** 16919 * Attach a sort handler (click) to a node 16920 * @param {object} settings dataTables settings object 16921 * @param {node} attachTo node to attach the handler to 16922 * @param {int} colIdx column sorting index 16923 * @param {function} [callback] callback function 16924 * @memberof DataTable#oApi 16925 */ 16926 function _fnSortAttachListener ( settings, attachTo, colIdx, callback ) 16927 { 16928 var col = settings.aoColumns[ colIdx ]; 16929 16930 _fnBindAction( attachTo, {}, function (e) { 16931 /* If the column is not sortable - don't to anything */ 16932 if ( col.bSortable === false ) { 16933 return; 16934 } 16935 16936 // If processing is enabled use a timeout to allow the processing 16937 // display to be shown - otherwise to it synchronously 16938 if ( settings.oFeatures.bProcessing ) { 16939 _fnProcessingDisplay( settings, true ); 16940 16941 setTimeout( function() { 16942 _fnSortListener( settings, colIdx, e.shiftKey, callback ); 16943 16944 // In server-side processing, the draw callback will remove the 16945 // processing display 16946 if ( _fnDataSource( settings ) !== 'ssp' ) { 16947 _fnProcessingDisplay( settings, false ); 16948 } 16949 }, 0 ); 16950 } 16951 else { 16952 _fnSortListener( settings, colIdx, e.shiftKey, callback ); 16953 } 16954 } ); 16955 } 16956 16957 16958 /** 16959 * Set the sorting classes on table's body, Note: it is safe to call this function 16960 * when bSort and bSortClasses are false 16961 * @param {object} oSettings dataTables settings object 16962 * @memberof DataTable#oApi 16963 */ 16964 function _fnSortingClasses( settings ) 16965 { 16966 var oldSort = settings.aLastSort; 16967 var sortClass = settings.oClasses.sSortColumn; 16968 var sort = _fnSortFlatten( settings ); 16969 var features = settings.oFeatures; 16970 var i, ien, colIdx; 16971 16972 if ( features.bSort && features.bSortClasses ) { 16973 // Remove old sorting classes 16974 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) { 16975 colIdx = oldSort[i].src; 16976 16977 // Remove column sorting 16978 $( _pluck( settings.aoData, 'anCells', colIdx ) ) 16979 .removeClass( sortClass + (i<2 ? i+1 : 3) ); 16980 } 16981 16982 // Add new column sorting 16983 for ( i=0, ien=sort.length ; i<ien ; i++ ) { 16984 colIdx = sort[i].src; 16985 16986 $( _pluck( settings.aoData, 'anCells', colIdx ) ) 16987 .addClass( sortClass + (i<2 ? i+1 : 3) ); 16988 } 16989 } 16990 16991 settings.aLastSort = sort; 16992 } 16993 16994 16995 // Get the data to sort a column, be it from cache, fresh (populating the 16996 // cache), or from a sort formatter 16997 function _fnSortData( settings, idx ) 16998 { 16999 // Custom sorting function - provided by the sort data type 17000 var column = settings.aoColumns[ idx ]; 17001 var customSort = DataTable.ext.order[ column.sSortDataType ]; 17002 var customData; 17003 17004 if ( customSort ) { 17005 customData = customSort.call( settings.oInstance, settings, idx, 17006 _fnColumnIndexToVisible( settings, idx ) 17007 ); 17008 } 17009 17010 // Use / populate cache 17011 var row, cellData; 17012 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ]; 17013 17014 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 17015 row = settings.aoData[i]; 17016 17017 if ( ! row._aSortData ) { 17018 row._aSortData = []; 17019 } 17020 17021 if ( ! row._aSortData[idx] || customSort ) { 17022 cellData = customSort ? 17023 customData[i] : // If there was a custom sort function, use data from there 17024 _fnGetCellData( settings, i, idx, 'sort' ); 17025 17026 row._aSortData[ idx ] = formatter ? 17027 formatter( cellData ) : 17028 cellData; 17029 } 17030 } 17031 } 17032 17033 17034 17035 /** 17036 * Save the state of a table 17037 * @param {object} oSettings dataTables settings object 17038 * @memberof DataTable#oApi 17039 */ 17040 function _fnSaveState ( settings ) 17041 { 17042 if ( !settings.oFeatures.bStateSave || settings.bDestroying ) 17043 { 17044 return; 17045 } 17046 17047 /* Store the interesting variables */ 17048 var state = { 17049 time: +new Date(), 17050 start: settings._iDisplayStart, 17051 length: settings._iDisplayLength, 17052 order: $.extend( true, [], settings.aaSorting ), 17053 search: _fnSearchToCamel( settings.oPreviousSearch ), 17054 columns: $.map( settings.aoColumns, function ( col, i ) { 17055 return { 17056 visible: col.bVisible, 17057 search: _fnSearchToCamel( settings.aoPreSearchCols[i] ) 17058 }; 17059 } ) 17060 }; 17061 17062 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] ); 17063 17064 settings.oSavedState = state; 17065 settings.fnStateSaveCallback.call( settings.oInstance, settings, state ); 17066 } 17067 17068 17069 /** 17070 * Attempt to load a saved table state 17071 * @param {object} oSettings dataTables settings object 17072 * @param {object} oInit DataTables init object so we can override settings 17073 * @memberof DataTable#oApi 17074 */ 17075 function _fnLoadState ( settings, oInit ) 17076 { 17077 var i, ien; 17078 var columns = settings.aoColumns; 17079 17080 if ( ! settings.oFeatures.bStateSave ) { 17081 return; 17082 } 17083 17084 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings ); 17085 if ( ! state || ! state.time ) { 17086 return; 17087 } 17088 17089 /* Allow custom and plug-in manipulation functions to alter the saved data set and 17090 * cancelling of loading by returning false 17091 */ 17092 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] ); 17093 if ( $.inArray( false, abStateLoad ) !== -1 ) { 17094 return; 17095 } 17096 17097 /* Reject old data */ 17098 var duration = settings.iStateDuration; 17099 if ( duration > 0 && state.time < +new Date() - (duration*1000) ) { 17100 return; 17101 } 17102 17103 // Number of columns have changed - all bets are off, no restore of settings 17104 if ( columns.length !== state.columns.length ) { 17105 return; 17106 } 17107 17108 // Store the saved state so it might be accessed at any time 17109 settings.oLoadedState = $.extend( true, {}, state ); 17110 17111 // Restore key features - todo - for 1.11 this needs to be done by 17112 // subscribed events 17113 if ( state.start !== undefined ) { 17114 settings._iDisplayStart = state.start; 17115 settings.iInitDisplayStart = state.start; 17116 } 17117 if ( state.length !== undefined ) { 17118 settings._iDisplayLength = state.length; 17119 } 17120 17121 // Order 17122 if ( state.order !== undefined ) { 17123 settings.aaSorting = []; 17124 $.each( state.order, function ( i, col ) { 17125 settings.aaSorting.push( col[0] >= columns.length ? 17126 [ 0, col[1] ] : 17127 col 17128 ); 17129 } ); 17130 } 17131 17132 // Search 17133 if ( state.search !== undefined ) { 17134 $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) ); 17135 } 17136 17137 // Columns 17138 for ( i=0, ien=state.columns.length ; i<ien ; i++ ) { 17139 var col = state.columns[i]; 17140 17141 // Visibility 17142 if ( col.visible !== undefined ) { 17143 columns[i].bVisible = col.visible; 17144 } 17145 17146 // Search 17147 if ( col.search !== undefined ) { 17148 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) ); 17149 } 17150 } 17151 17152 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] ); 17153 } 17154 17155 17156 /** 17157 * Return the settings object for a particular table 17158 * @param {node} table table we are using as a dataTable 17159 * @returns {object} Settings object - or null if not found 17160 * @memberof DataTable#oApi 17161 */ 17162 function _fnSettingsFromNode ( table ) 17163 { 17164 var settings = DataTable.settings; 17165 var idx = $.inArray( table, _pluck( settings, 'nTable' ) ); 17166 17167 return idx !== -1 ? 17168 settings[ idx ] : 17169 null; 17170 } 17171 17172 17173 /** 17174 * Log an error message 17175 * @param {object} settings dataTables settings object 17176 * @param {int} level log error messages, or display them to the user 17177 * @param {string} msg error message 17178 * @param {int} tn Technical note id to get more information about the error. 17179 * @memberof DataTable#oApi 17180 */ 17181 function _fnLog( settings, level, msg, tn ) 17182 { 17183 msg = 'DataTables warning: '+ 17184 (settings ? 'table id='+settings.sTableId+' - ' : '')+msg; 17185 17186 if ( tn ) { 17187 msg += '. For more information about this error, please see '+ 17188 'http://datatables.net/tn/'+tn; 17189 } 17190 17191 if ( ! level ) { 17192 // Backwards compatibility pre 1.10 17193 var ext = DataTable.ext; 17194 var type = ext.sErrMode || ext.errMode; 17195 17196 if ( settings ) { 17197 _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] ); 17198 } 17199 17200 if ( type == 'alert' ) { 17201 alert( msg ); 17202 } 17203 else if ( type == 'throw' ) { 17204 throw new Error(msg); 17205 } 17206 else if ( typeof type == 'function' ) { 17207 type( settings, tn, msg ); 17208 } 17209 } 17210 else if ( window.console && console.log ) { 17211 console.log( msg ); 17212 } 17213 } 17214 17215 17216 /** 17217 * See if a property is defined on one object, if so assign it to the other object 17218 * @param {object} ret target object 17219 * @param {object} src source object 17220 * @param {string} name property 17221 * @param {string} [mappedName] name to map too - optional, name used if not given 17222 * @memberof DataTable#oApi 17223 */ 17224 function _fnMap( ret, src, name, mappedName ) 17225 { 17226 if ( $.isArray( name ) ) { 17227 $.each( name, function (i, val) { 17228 if ( $.isArray( val ) ) { 17229 _fnMap( ret, src, val[0], val[1] ); 17230 } 17231 else { 17232 _fnMap( ret, src, val ); 17233 } 17234 } ); 17235 17236 return; 17237 } 17238 17239 if ( mappedName === undefined ) { 17240 mappedName = name; 17241 } 17242 17243 if ( src[name] !== undefined ) { 17244 ret[mappedName] = src[name]; 17245 } 17246 } 17247 17248 17249 /** 17250 * Extend objects - very similar to jQuery.extend, but deep copy objects, and 17251 * shallow copy arrays. The reason we need to do this, is that we don't want to 17252 * deep copy array init values (such as aaSorting) since the dev wouldn't be 17253 * able to override them, but we do want to deep copy arrays. 17254 * @param {object} out Object to extend 17255 * @param {object} extender Object from which the properties will be applied to 17256 * out 17257 * @param {boolean} breakRefs If true, then arrays will be sliced to take an 17258 * independent copy with the exception of the `data` or `aaData` parameters 17259 * if they are present. This is so you can pass in a collection to 17260 * DataTables and have that used as your data source without breaking the 17261 * references 17262 * @returns {object} out Reference, just for convenience - out === the return. 17263 * @memberof DataTable#oApi 17264 * @todo This doesn't take account of arrays inside the deep copied objects. 17265 */ 17266 function _fnExtend( out, extender, breakRefs ) 17267 { 17268 var val; 17269 17270 for ( var prop in extender ) { 17271 if ( extender.hasOwnProperty(prop) ) { 17272 val = extender[prop]; 17273 17274 if ( $.isPlainObject( val ) ) { 17275 if ( ! $.isPlainObject( out[prop] ) ) { 17276 out[prop] = {}; 17277 } 17278 $.extend( true, out[prop], val ); 17279 } 17280 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) { 17281 out[prop] = val.slice(); 17282 } 17283 else { 17284 out[prop] = val; 17285 } 17286 } 17287 } 17288 17289 return out; 17290 } 17291 17292 17293 /** 17294 * Bind an event handers to allow a click or return key to activate the callback. 17295 * This is good for accessibility since a return on the keyboard will have the 17296 * same effect as a click, if the element has focus. 17297 * @param {element} n Element to bind the action to 17298 * @param {object} oData Data object to pass to the triggered function 17299 * @param {function} fn Callback function for when the event is triggered 17300 * @memberof DataTable#oApi 17301 */ 17302 function _fnBindAction( n, oData, fn ) 17303 { 17304 $(n) 17305 .bind( 'click.DT', oData, function (e) { 17306 n.blur(); // Remove focus outline for mouse users 17307 fn(e); 17308 } ) 17309 .bind( 'keypress.DT', oData, function (e){ 17310 if ( e.which === 13 ) { 17311 e.preventDefault(); 17312 fn(e); 17313 } 17314 } ) 17315 .bind( 'selectstart.DT', function () { 17316 /* Take the brutal approach to cancelling text selection */ 17317 return false; 17318 } ); 17319 } 17320 17321 17322 /** 17323 * Register a callback function. Easily allows a callback function to be added to 17324 * an array store of callback functions that can then all be called together. 17325 * @param {object} oSettings dataTables settings object 17326 * @param {string} sStore Name of the array storage for the callbacks in oSettings 17327 * @param {function} fn Function to be called back 17328 * @param {string} sName Identifying name for the callback (i.e. a label) 17329 * @memberof DataTable#oApi 17330 */ 17331 function _fnCallbackReg( oSettings, sStore, fn, sName ) 17332 { 17333 if ( fn ) 17334 { 17335 oSettings[sStore].push( { 17336 "fn": fn, 17337 "sName": sName 17338 } ); 17339 } 17340 } 17341 17342 17343 /** 17344 * Fire callback functions and trigger events. Note that the loop over the 17345 * callback array store is done backwards! Further note that you do not want to 17346 * fire off triggers in time sensitive applications (for example cell creation) 17347 * as its slow. 17348 * @param {object} settings dataTables settings object 17349 * @param {string} callbackArr Name of the array storage for the callbacks in 17350 * oSettings 17351 * @param {string} eventName Name of the jQuery custom event to trigger. If 17352 * null no trigger is fired 17353 * @param {array} args Array of arguments to pass to the callback function / 17354 * trigger 17355 * @memberof DataTable#oApi 17356 */ 17357 function _fnCallbackFire( settings, callbackArr, eventName, args ) 17358 { 17359 var ret = []; 17360 17361 if ( callbackArr ) { 17362 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) { 17363 return val.fn.apply( settings.oInstance, args ); 17364 } ); 17365 } 17366 17367 if ( eventName !== null ) { 17368 var e = $.Event( eventName+'.dt' ); 17369 17370 $(settings.nTable).trigger( e, args ); 17371 17372 ret.push( e.result ); 17373 } 17374 17375 return ret; 17376 } 17377 17378 17379 function _fnLengthOverflow ( settings ) 17380 { 17381 var 17382 start = settings._iDisplayStart, 17383 end = settings.fnDisplayEnd(), 17384 len = settings._iDisplayLength; 17385 17386 /* If we have space to show extra rows (backing up from the end point - then do so */ 17387 if ( start >= end ) 17388 { 17389 start = end - len; 17390 } 17391 17392 // Keep the start record on the current page 17393 start -= (start % len); 17394 17395 if ( len === -1 || start < 0 ) 17396 { 17397 start = 0; 17398 } 17399 17400 settings._iDisplayStart = start; 17401 } 17402 17403 17404 function _fnRenderer( settings, type ) 17405 { 17406 var renderer = settings.renderer; 17407 var host = DataTable.ext.renderer[type]; 17408 17409 if ( $.isPlainObject( renderer ) && renderer[type] ) { 17410 // Specific renderer for this type. If available use it, otherwise use 17411 // the default. 17412 return host[renderer[type]] || host._; 17413 } 17414 else if ( typeof renderer === 'string' ) { 17415 // Common renderer - if there is one available for this type use it, 17416 // otherwise use the default 17417 return host[renderer] || host._; 17418 } 17419 17420 // Use the default 17421 return host._; 17422 } 17423 17424 17425 /** 17426 * Detect the data source being used for the table. Used to simplify the code 17427 * a little (ajax) and to make it compress a little smaller. 17428 * 17429 * @param {object} settings dataTables settings object 17430 * @returns {string} Data source 17431 * @memberof DataTable#oApi 17432 */ 17433 function _fnDataSource ( settings ) 17434 { 17435 if ( settings.oFeatures.bServerSide ) { 17436 return 'ssp'; 17437 } 17438 else if ( settings.ajax || settings.sAjaxSource ) { 17439 return 'ajax'; 17440 } 17441 return 'dom'; 17442 } 17443 17444 17445 17446 /** 17447 * Computed structure of the DataTables API, defined by the options passed to 17448 * `DataTable.Api.register()` when building the API. 17449 * 17450 * The structure is built in order to speed creation and extension of the Api 17451 * objects since the extensions are effectively pre-parsed. 17452 * 17453 * The array is an array of objects with the following structure, where this 17454 * base array represents the Api prototype base: 17455 * 17456 * [ 17457 * { 17458 * name: 'data' -- string - Property name 17459 * val: function () {}, -- function - Api method (or undefined if just an object 17460 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result 17461 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property 17462 * }, 17463 * { 17464 * name: 'row' 17465 * val: {}, 17466 * methodExt: [ ... ], 17467 * propExt: [ 17468 * { 17469 * name: 'data' 17470 * val: function () {}, 17471 * methodExt: [ ... ], 17472 * propExt: [ ... ] 17473 * }, 17474 * ... 17475 * ] 17476 * } 17477 * ] 17478 * 17479 * @type {Array} 17480 * @ignore 17481 */ 17482 var __apiStruct = []; 17483 17484 17485 /** 17486 * `Array.prototype` reference. 17487 * 17488 * @type object 17489 * @ignore 17490 */ 17491 var __arrayProto = Array.prototype; 17492 17493 17494 /** 17495 * Abstraction for `context` parameter of the `Api` constructor to allow it to 17496 * take several different forms for ease of use. 17497 * 17498 * Each of the input parameter types will be converted to a DataTables settings 17499 * object where possible. 17500 * 17501 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one 17502 * of: 17503 * 17504 * * `string` - jQuery selector. Any DataTables' matching the given selector 17505 * with be found and used. 17506 * * `node` - `TABLE` node which has already been formed into a DataTable. 17507 * * `jQuery` - A jQuery object of `TABLE` nodes. 17508 * * `object` - DataTables settings object 17509 * * `DataTables.Api` - API instance 17510 * @return {array|null} Matching DataTables settings objects. `null` or 17511 * `undefined` is returned if no matching DataTable is found. 17512 * @ignore 17513 */ 17514 var _toSettings = function ( mixed ) 17515 { 17516 var idx, jq; 17517 var settings = DataTable.settings; 17518 var tables = $.map( settings, function (el, i) { 17519 return el.nTable; 17520 } ); 17521 17522 if ( ! mixed ) { 17523 return []; 17524 } 17525 else if ( mixed.nTable && mixed.oApi ) { 17526 // DataTables settings object 17527 return [ mixed ]; 17528 } 17529 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) { 17530 // Table node 17531 idx = $.inArray( mixed, tables ); 17532 return idx !== -1 ? [ settings[idx] ] : null; 17533 } 17534 else if ( mixed && typeof mixed.settings === 'function' ) { 17535 return mixed.settings().toArray(); 17536 } 17537 else if ( typeof mixed === 'string' ) { 17538 // jQuery selector 17539 jq = $(mixed); 17540 } 17541 else if ( mixed instanceof $ ) { 17542 // jQuery object (also DataTables instance) 17543 jq = mixed; 17544 } 17545 17546 if ( jq ) { 17547 return jq.map( function(i) { 17548 idx = $.inArray( this, tables ); 17549 return idx !== -1 ? settings[idx] : null; 17550 } ).toArray(); 17551 } 17552 }; 17553 17554 17555 /** 17556 * DataTables API class - used to control and interface with one or more 17557 * DataTables enhanced tables. 17558 * 17559 * The API class is heavily based on jQuery, presenting a chainable interface 17560 * that you can use to interact with tables. Each instance of the API class has 17561 * a "context" - i.e. the tables that it will operate on. This could be a single 17562 * table, all tables on a page or a sub-set thereof. 17563 * 17564 * Additionally the API is designed to allow you to easily work with the data in 17565 * the tables, retrieving and manipulating it as required. This is done by 17566 * presenting the API class as an array like interface. The contents of the 17567 * array depend upon the actions requested by each method (for example 17568 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
17569 * return an array of objects or arrays depending upon your table's 17570 * configuration). The API object has a number of array like methods (`push`, 17571 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`, 17572 * `unique` etc) to assist your working with the data held in a table. 17573 * 17574 * Most methods (those which return an Api instance) are chainable, which means 17575 * the return from a method call also has all of the methods available that the 17576 * top level object had. For example, these two calls are equivalent: 17577 * 17578 * // Not chained 17579 * api.row.add( {...} ); 17580 * api.draw(); 17581 * 17582 * // Chained 17583 * api.row.add( {...} ).draw(); 17584 * 17585 * @class DataTable.Api 17586 * @param {array|object|string|jQuery} context DataTable identifier. This is 17587 * used to define which DataTables enhanced tables this API will operate on. 17588 * Can be one of: 17589 * 17590 * * `string` - jQuery selector. Any DataTables' matching the given selector 17591 * with be found and used. 17592 * * `node` - `TABLE` node which has already been formed into a DataTable. 17593 * * `jQuery` - A jQuery object of `TABLE` nodes. 17594 * * `object` - DataTables settings object 17595 * @param {array} [data] Data to initialise the Api instance with. 17596 * 17597 * @example 17598 * // Direct initialisation during DataTables construction 17599 * var api = $('#example').DataTable(); 17600 * 17601 * @example 17602 * // Initialisation using a DataTables jQuery object 17603 * var api = $('#example').dataTable().api(); 17604 * 17605 * @example 17606 * // Initialisation as a constructor 17607 * var api = new $.fn.DataTable.Api( 'table.dataTable' ); 17608 */ 17609 _Api = function ( context, data ) 17610 { 17611 if ( ! (this instanceof _Api) ) { 17612 return new _Api( context, data ); 17613 } 17614 17615 var settings = []; 17616 var ctxSettings = function ( o ) { 17617 var a = _toSettings( o ); 17618 if ( a ) { 17619 settings = settings.concat( a ); 17620 } 17621 }; 17622 17623 if ( $.isArray( context ) ) { 17624 for ( var i=0, ien=context.length ; i<ien ; i++ ) { 17625 ctxSettings( context[i] ); 17626 } 17627 } 17628 else { 17629 ctxSettings( context ); 17630 } 17631 17632 // Remove duplicates 17633 this.context = _unique( settings ); 17634 17635 // Initial data 17636 if ( data ) { 17637 $.merge( this, data ); 17638 } 17639 17640 // selector 17641 this.selector = { 17642 rows: null, 17643 cols: null, 17644 opts: null 17645 }; 17646 17647 _Api.extend( this, this, __apiStruct ); 17648 }; 17649 17650 DataTable.Api = _Api; 17651 17652 // Don't destroy the existing prototype, just extend it. Required for jQuery 2's 17653 // isPlainObject. 17654 $.extend( _Api.prototype, { 17655 any: function () 17656 { 17657 return this.count() !== 0; 17658 }, 17659 17660 17661 concat: __arrayProto.concat, 17662 17663 17664 context: [], // array of table settings objects 17665 17666 17667 count: function () 17668 { 17669 return this.flatten().length; 17670 }, 17671 17672 17673 each: function ( fn ) 17674 { 17675 for ( var i=0, ien=this.length ; i<ien; i++ ) { 17676 fn.call( this, this[i], i, this ); 17677 } 17678 17679 return this; 17680 }, 17681 17682 17683 eq: function ( idx ) 17684 { 17685 var ctx = this.context; 17686 17687 return ctx.length > idx ? 17688 new _Api( ctx[idx], this[idx] ) : 17689 null; 17690 }, 17691 17692 17693 filter: function ( fn ) 17694 { 17695 var a = []; 17696 17697 if ( __arrayProto.filter ) { 17698 a = __arrayProto.filter.call( this, fn, this ); 17699 } 17700 else { 17701 // Compatibility for browsers without EMCA-252-5 (JS 1.6) 17702 for ( var i=0, ien=this.length ; i<ien ; i++ ) { 17703 if ( fn.call( this, this[i], i, this ) ) { 17704 a.push( this[i] ); 17705 } 17706 } 17707 } 17708 17709 return new _Api( this.context, a ); 17710 }, 17711 17712 17713 flatten: function () 17714 { 17715 var a = []; 17716 return new _Api( this.context, a.concat.apply( a, this.toArray() ) ); 17717 }, 17718 17719 17720 join: __arrayProto.join, 17721 17722 17723 indexOf: __arrayProto.indexOf || function (obj, start) 17724 { 17725 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) { 17726 if ( this[i] === obj ) { 17727 return i; 17728 } 17729 } 17730 return -1; 17731 }, 17732 17733 iterator: function ( flatten, type, fn, alwaysNew ) { 17734 var 17735 a = [], ret, 17736 i, ien, j, jen, 17737 context = this.context, 17738 rows, items, item, 17739 selector = this.selector; 17740 17741 // Argument shifting 17742 if ( typeof flatten === 'string' ) { 17743 alwaysNew = fn; 17744 fn = type; 17745 type = flatten; 17746 flatten = false; 17747 } 17748 17749 for ( i=0, ien=context.length ; i<ien ; i++ ) { 17750 var apiInst = new _Api( context[i] ); 17751 17752 if ( type === 'table' ) { 17753 ret = fn.call( apiInst, context[i], i ); 17754 17755 if ( ret !== undefined ) { 17756 a.push( ret ); 17757 } 17758 } 17759 else if ( type === 'columns' || type === 'rows' ) { 17760 // this has same length as context - one entry for each table 17761 ret = fn.call( apiInst, context[i], this[i], i ); 17762 17763 if ( ret !== undefined ) { 17764 a.push( ret ); 17765 } 17766 } 17767 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) { 17768 // columns and rows share the same structure. 17769 // 'this' is an array of column indexes for each context 17770 items = this[i]; 17771 17772 if ( type === 'column-rows' ) { 17773 rows = _selector_row_indexes( context[i], selector.opts ); 17774 } 17775 17776 for ( j=0, jen=items.length ; j<jen ; j++ ) { 17777 item = items[j]; 17778 17779 if ( type === 'cell' ) { 17780 ret = fn.call( apiInst, context[i], item.row, item.column, i, j ); 17781 } 17782 else { 17783 ret = fn.call( apiInst, context[i], item, i, j, rows ); 17784 } 17785 17786 if ( ret !== undefined ) { 17787 a.push( ret ); 17788 } 17789 } 17790 } 17791 } 17792 17793 if ( a.length || alwaysNew ) { 17794 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a ); 17795 var apiSelector = api.selector; 17796 apiSelector.rows = selector.rows; 17797 apiSelector.cols = selector.cols; 17798 apiSelector.opts = selector.opts; 17799 return api; 17800 } 17801 return this; 17802 }, 17803 17804 17805 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start) 17806 { 17807 // Bit cheeky... 17808 return this.indexOf.apply( this.toArray.reverse(), arguments ); 17809 }, 17810 17811 17812 length: 0, 17813 17814 17815 map: function ( fn ) 17816 { 17817 var a = []; 17818 17819 if ( __arrayProto.map ) { 17820 a = __arrayProto.map.call( this, fn, this ); 17821 } 17822 else { 17823 // Compatibility for browsers without EMCA-252-5 (JS 1.6) 17824 for ( var i=0, ien=this.length ; i<ien ; i++ ) { 17825 a.push( fn.call( this, this[i], i ) ); 17826 } 17827 } 17828 17829 return new _Api( this.context, a ); 17830 }, 17831 17832 17833 pluck: function ( prop ) 17834 { 17835 return this.map( function ( el ) { 17836 return el[ prop ]; 17837 } ); 17838 }, 17839 17840 pop: __arrayProto.pop, 17841 17842 17843 push: __arrayProto.push, 17844 17845 17846 // Does not return an API instance 17847 reduce: __arrayProto.reduce || function ( fn, init ) 17848 { 17849 return _fnReduce( this, fn, init, 0, this.length, 1 ); 17850 }, 17851 17852 17853 reduceRight: __arrayProto.reduceRight || function ( fn, init ) 17854 { 17855 return _fnReduce( this, fn, init, this.length-1, -1, -1 ); 17856 }, 17857 17858 17859 reverse: __arrayProto.reverse, 17860 17861 17862 // Object with rows, columns and opts 17863 selector: null, 17864 17865 17866 shift: __arrayProto.shift, 17867 17868 17869 sort: __arrayProto.sort, // ? name - order? 17870 17871 17872 splice: __arrayProto.splice, 17873 17874 17875 toArray: function () 17876 { 17877 return __arrayProto.slice.call( this ); 17878 }, 17879 17880 17881 to$: function () 17882 { 17883 return $( this ); 17884 }, 17885 17886 17887 toJQuery: function () 17888 { 17889 return $( this ); 17890 }, 17891 17892 17893 unique: function () 17894 { 17895 return new _Api( this.context, _unique(this) ); 17896 }, 17897 17898 17899 unshift: __arrayProto.unshift 17900 } ); 17901 17902 17903 _Api.extend = function ( scope, obj, ext ) 17904 { 17905 // Only extend API instances and static properties of the API 17906 if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) { 17907 return; 17908 } 17909 17910 var 17911 i, ien, 17912 j, jen, 17913 struct, inner, 17914 methodScoping = function ( scope, fn, struc ) { 17915 return function () { 17916 var ret = fn.apply( scope, arguments ); 17917 17918 // Method extension 17919 _Api.extend( ret, ret, struc.methodExt ); 17920 return ret; 17921 }; 17922 }; 17923 17924 for ( i=0, ien=ext.length ; i<ien ; i++ ) { 17925 struct = ext[i]; 17926 17927 // Value 17928 obj[ struct.name ] = typeof struct.val === 'function' ? 17929 methodScoping( scope, struct.val, struct ) : 17930 $.isPlainObject( struct.val ) ? 17931 {} : 17932 struct.val; 17933 17934 obj[ struct.name ].__dt_wrapper = true; 17935 17936 // Property extension 17937 _Api.extend( scope, obj[ struct.name ], struct.propExt ); 17938 } 17939 }; 17940 17941 17942 // @todo - Is there need for an augment function? 17943 // _Api.augment = function ( inst, name ) 17944 // { 17945 // // Find src object in the structure from the name 17946 // var parts = name.split('.'); 17947 17948 // _Api.extend( inst, obj ); 17949 // }; 17950 17951 17952 // [ 17953 // { 17954 // name: 'data' -- string - Property name 17955 // val: function () {}, -- function - Api method (or undefined if just an object 17956 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result 17957 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property 17958 // }, 17959 // { 17960 // name: 'row' 17961 // val: {}, 17962 // methodExt: [ ... ], 17963 // propExt: [ 17964 // { 17965 // name: 'data' 17966 // val: function () {}, 17967 // methodExt: [ ... ], 17968 // propExt: [ ... ] 17969 // }, 17970 // ... 17971 // ] 17972 // } 17973 // ] 17974 17975 _Api.register = _api_register = function ( name, val ) 17976 { 17977 if ( $.isArray( name ) ) { 17978 for ( var j=0, jen=name.length ; j<jen ; j++ ) { 17979 _Api.register( name[j], val ); 17980 } 17981 return; 17982 } 17983 17984 var 17985 i, ien, 17986 heir = name.split('.'), 17987 struct = __apiStruct, 17988 key, method; 17989 17990 var find = function ( src, name ) { 17991 for ( var i=0, ien=src.length ; i<ien ; i++ ) { 17992 if ( src[i].name === name ) { 17993 return src[i]; 17994 } 17995 } 17996 return null; 17997 }; 17998 17999 for ( i=0, ien=heir.length ; i<ien ; i++ ) { 18000 method = heir[i].indexOf('()') !== -1; 18001 key = method ?
vendor: 42,517 bytes, lines 18002-19612
18002 heir[i].replace('()', '') : 18003 heir[i]; 18004 18005 var src = find( struct, key ); 18006 if ( ! src ) { 18007 src = { 18008 name: key, 18009 val: {}, 18010 methodExt: [], 18011 propExt: [] 18012 }; 18013 struct.push( src ); 18014 } 18015 18016 if ( i === ien-1 ) { 18017 src.val = val; 18018 } 18019 else { 18020 struct = method ? 18021 src.methodExt : 18022 src.propExt; 18023 } 18024 } 18025 }; 18026 18027 18028 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) { 18029 _Api.register( pluralName, val ); 18030 18031 _Api.register( singularName, function () { 18032 var ret = val.apply( this, arguments ); 18033 18034 if ( ret === this ) { 18035 // Returned item is the API instance that was passed in, return it 18036 return this; 18037 } 18038 else if ( ret instanceof _Api ) { 18039 // New API instance returned, want the value from the first item 18040 // in the returned array for the singular result. 18041 return ret.length ? 18042 $.isArray( ret[0] ) ? 18043 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced' 18044 ret[0] : 18045 undefined; 18046 } 18047 18048 // Non-API return - just fire it back 18049 return ret; 18050 } ); 18051 }; 18052 18053 18054 /** 18055 * Selector for HTML tables. Apply the given selector to the give array of 18056 * DataTables settings objects. 18057 * 18058 * @param {string|integer} [selector] jQuery selector string or integer 18059 * @param {array} Array of DataTables settings objects to be filtered 18060 * @return {array} 18061 * @ignore 18062 */ 18063 var __table_selector = function ( selector, a ) 18064 { 18065 // Integer is used to pick out a table by index 18066 if ( typeof selector === 'number' ) { 18067 return [ a[ selector ] ]; 18068 } 18069 18070 // Perform a jQuery selector on the table nodes 18071 var nodes = $.map( a, function (el, i) { 18072 return el.nTable; 18073 } ); 18074 18075 return $(nodes) 18076 .filter( selector ) 18077 .map( function (i) { 18078 // Need to translate back from the table node to the settings 18079 var idx = $.inArray( this, nodes ); 18080 return a[ idx ]; 18081 } ) 18082 .toArray(); 18083 }; 18084 18085 18086 18087 /** 18088 * Context selector for the API's context (i.e. the tables the API instance 18089 * refers to. 18090 * 18091 * @name DataTable.Api#tables 18092 * @param {string|integer} [selector] Selector to pick which tables the iterator 18093 * should operate on. If not given, all tables in the current context are 18094 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to 18095 * select multiple tables or as an integer to select a single table. 18096 * @returns {DataTable.Api} Returns a new API instance if a selector is given. 18097 */ 18098 _api_register( 'tables()', function ( selector ) { 18099 // A new instance is created if there was a selector specified 18100 return selector ? 18101 new _Api( __table_selector( selector, this.context ) ) : 18102 this; 18103 } ); 18104 18105 18106 _api_register( 'table()', function ( selector ) { 18107 var tables = this.tables( selector ); 18108 var ctx = tables.context; 18109 18110 // Truncate to the first matched table 18111 return ctx.length ? 18112 new _Api( ctx[0] ) : 18113 tables; 18114 } ); 18115 18116 18117 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () { 18118 return this.iterator( 'table', function ( ctx ) { 18119 return ctx.nTable; 18120 }, 1 ); 18121 } ); 18122 18123 18124 _api_registerPlural( 'tables().body()', 'table().body()' , function () { 18125 return this.iterator( 'table', function ( ctx ) { 18126 return ctx.nTBody; 18127 }, 1 ); 18128 } ); 18129 18130 18131 _api_registerPlural( 'tables().header()', 'table().header()' , function () { 18132 return this.iterator( 'table', function ( ctx ) { 18133 return ctx.nTHead; 18134 }, 1 ); 18135 } ); 18136 18137 18138 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () { 18139 return this.iterator( 'table', function ( ctx ) { 18140 return ctx.nTFoot; 18141 }, 1 ); 18142 } ); 18143 18144 18145 _api_registerPlural( 'tables().containers()', 'table().container()' , function () { 18146 return this.iterator( 'table', function ( ctx ) { 18147 return ctx.nTableWrapper; 18148 }, 1 ); 18149 } ); 18150 18151 18152 18153 /** 18154 * Redraw the tables in the current context. 18155 */ 18156 _api_register( 'draw()', function ( paging ) { 18157 return this.iterator( 'table', function ( settings ) { 18158 if ( paging === 'page' ) { 18159 _fnDraw( settings ); 18160 } 18161 else { 18162 if ( typeof paging === 'string' ) { 18163 paging = paging === 'full-hold' ? 18164 false : 18165 true; 18166 } 18167 18168 _fnReDraw( settings, paging===false ); 18169 } 18170 } ); 18171 } ); 18172 18173 18174 18175 /** 18176 * Get the current page index. 18177 * 18178 * @return {integer} Current page index (zero based) 18179 *//** 18180 * Set the current page. 18181 * 18182 * Note that if you attempt to show a page which does not exist, DataTables will 18183 * not throw an error, but rather reset the paging. 18184 * 18185 * @param {integer|string} action The paging action to take. This can be one of: 18186 * * `integer` - The page index to jump to 18187 * * `string` - An action to take: 18188 * * `first` - Jump to first page. 18189 * * `next` - Jump to the next page 18190 * * `previous` - Jump to previous page 18191 * * `last` - Jump to the last page. 18192 * @returns {DataTables.Api} this 18193 */ 18194 _api_register( 'page()', function ( action ) { 18195 if ( action === undefined ) { 18196 return this.page.info().page; // not an expensive call 18197 } 18198 18199 // else, have an action to take on all tables 18200 return this.iterator( 'table', function ( settings ) { 18201 _fnPageChange( settings, action ); 18202 } ); 18203 } ); 18204 18205 18206 /** 18207 * Paging information for the first table in the current context. 18208 * 18209 * If you require paging information for another table, use the `table()` method 18210 * with a suitable selector. 18211 * 18212 * @return {object} Object with the following properties set: 18213 * * `page` - Current page index (zero based - i.e. the first page is `0`) 18214 * * `pages` - Total number of pages 18215 * * `start` - Display index for the first record shown on the current page 18216 * * `end` - Display index for the last record shown on the current page 18217 * * `length` - Display length (number of records). Note that generally `start 18218 * + length = end`, but this is not always true, for example if there are 18219 * only 2 records to show on the final page, with a length of 10. 18220 * * `recordsTotal` - Full data set length 18221 * * `recordsDisplay` - Data set length once the current filtering criterion 18222 * are applied. 18223 */ 18224 _api_register( 'page.info()', function ( action ) { 18225 if ( this.context.length === 0 ) { 18226 return undefined; 18227 } 18228 18229 var 18230 settings = this.context[0], 18231 start = settings._iDisplayStart, 18232 len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1, 18233 visRecords = settings.fnRecordsDisplay(), 18234 all = len === -1; 18235 18236 return { 18237 "page": all ? 0 : Math.floor( start / len ), 18238 "pages": all ? 1 : Math.ceil( visRecords / len ), 18239 "start": start, 18240 "end": settings.fnDisplayEnd(), 18241 "length": len, 18242 "recordsTotal": settings.fnRecordsTotal(), 18243 "recordsDisplay": visRecords, 18244 "serverSide": _fnDataSource( settings ) === 'ssp' 18245 }; 18246 } ); 18247 18248 18249 /** 18250 * Get the current page length. 18251 * 18252 * @return {integer} Current page length. Note `-1` indicates that all records 18253 * are to be shown. 18254 *//** 18255 * Set the current page length. 18256 * 18257 * @param {integer} Page length to set. Use `-1` to show all records. 18258 * @returns {DataTables.Api} this 18259 */ 18260 _api_register( 'page.len()', function ( len ) { 18261 // Note that we can't call this function 'length()' because `length` 18262 // is a Javascript property of functions which defines how many arguments 18263 // the function expects. 18264 if ( len === undefined ) { 18265 return this.context.length !== 0 ? 18266 this.context[0]._iDisplayLength : 18267 undefined; 18268 } 18269 18270 // else, set the page length 18271 return this.iterator( 'table', function ( settings ) { 18272 _fnLengthChange( settings, len ); 18273 } ); 18274 } ); 18275 18276 18277 18278 var __reload = function ( settings, holdPosition, callback ) { 18279 // Use the draw event to trigger a callback 18280 if ( callback ) { 18281 var api = new _Api( settings ); 18282 18283 api.one( 'draw', function () { 18284 callback( api.ajax.json() ); 18285 } ); 18286 } 18287 18288 if ( _fnDataSource( settings ) == 'ssp' ) { 18289 _fnReDraw( settings, holdPosition ); 18290 } 18291 else { 18292 _fnProcessingDisplay( settings, true ); 18293 18294 // Cancel an existing request 18295 var xhr = settings.jqXHR; 18296 if ( xhr && xhr.readyState !== 4 ) { 18297 xhr.abort(); 18298 } 18299 18300 // Trigger xhr 18301 _fnBuildAjax( settings, [], function( json ) { 18302 _fnClearTable( settings ); 18303 18304 var data = _fnAjaxDataSrc( settings, json ); 18305 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 18306 _fnAddData( settings, data[i] ); 18307 } 18308 18309 _fnReDraw( settings, holdPosition ); 18310 _fnProcessingDisplay( settings, false ); 18311 } ); 18312 } 18313 }; 18314 18315 18316 /** 18317 * Get the JSON response from the last Ajax request that DataTables made to the 18318 * server. Note that this returns the JSON from the first table in the current 18319 * context. 18320 * 18321 * @return {object} JSON received from the server. 18322 */ 18323 _api_register( 'ajax.json()', function () { 18324 var ctx = this.context; 18325 18326 if ( ctx.length > 0 ) { 18327 return ctx[0].json; 18328 } 18329 18330 // else return undefined; 18331 } ); 18332 18333 18334 /** 18335 * Get the data submitted in the last Ajax request 18336 */ 18337 _api_register( 'ajax.params()', function () { 18338 var ctx = this.context; 18339 18340 if ( ctx.length > 0 ) { 18341 return ctx[0].oAjaxData; 18342 } 18343 18344 // else return undefined; 18345 } ); 18346 18347 18348 /** 18349 * Reload tables from the Ajax data source. Note that this function will 18350 * automatically re-draw the table when the remote data has been loaded. 18351 * 18352 * @param {boolean} [reset=true] Reset (default) or hold the current paging 18353 * position. A full re-sort and re-filter is performed when this method is 18354 * called, which is why the pagination reset is the default action. 18355 * @returns {DataTables.Api} this 18356 */ 18357 _api_register( 'ajax.reload()', function ( callback, resetPaging ) { 18358 return this.iterator( 'table', function (settings) { 18359 __reload( settings, resetPaging===false, callback ); 18360 } ); 18361 } ); 18362 18363 18364 /** 18365 * Get the current Ajax URL. Note that this returns the URL from the first 18366 * table in the current context. 18367 * 18368 * @return {string} Current Ajax source URL 18369 *//** 18370 * Set the Ajax URL. Note that this will set the URL for all tables in the 18371 * current context. 18372 * 18373 * @param {string} url URL to set. 18374 * @returns {DataTables.Api} this 18375 */ 18376 _api_register( 'ajax.url()', function ( url ) { 18377 var ctx = this.context; 18378 18379 if ( url === undefined ) { 18380 // get 18381 if ( ctx.length === 0 ) { 18382 return undefined; 18383 } 18384 ctx = ctx[0]; 18385 18386 return ctx.ajax ? 18387 $.isPlainObject( ctx.ajax ) ? 18388 ctx.ajax.url : 18389 ctx.ajax : 18390 ctx.sAjaxSource; 18391 } 18392 18393 // set 18394 return this.iterator( 'table', function ( settings ) { 18395 if ( $.isPlainObject( settings.ajax ) ) { 18396 settings.ajax.url = url; 18397 } 18398 else { 18399 settings.ajax = url; 18400 } 18401 // No need to consider sAjaxSource here since DataTables gives priority 18402 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any 18403 // value of `sAjaxSource` redundant. 18404 } ); 18405 } ); 18406 18407 18408 /** 18409 * Load data from the newly set Ajax URL. Note that this method is only 18410 * available when `ajax.url()` is used to set a URL. Additionally, this method 18411 * has the same effect as calling `ajax.reload()` but is provided for 18412 * convenience when setting a new URL. Like `ajax.reload()` it will 18413 * automatically redraw the table once the remote data has been loaded. 18414 * 18415 * @returns {DataTables.Api} this 18416 */ 18417 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) { 18418 // Same as a reload, but makes sense to present it for easy access after a 18419 // url change 18420 return this.iterator( 'table', function ( ctx ) { 18421 __reload( ctx, resetPaging===false, callback ); 18422 } ); 18423 } ); 18424 18425 18426 18427 18428 var _selector_run = function ( type, selector, selectFn, settings, opts ) 18429 { 18430 var 18431 out = [], res, 18432 a, i, ien, j, jen, 18433 selectorType = typeof selector; 18434 18435 // Can't just check for isArray here, as an API or jQuery instance might be 18436 // given with their array like look 18437 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) { 18438 selector = [ selector ]; 18439 } 18440 18441 for ( i=0, ien=selector.length ; i<ien ; i++ ) { 18442 a = selector[i] && selector[i].split ? 18443 selector[i].split(',') : 18444 [ selector[i] ]; 18445 18446 for ( j=0, jen=a.length ; j<jen ; j++ ) { 18447 res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] ); 18448 18449 if ( res && res.length ) { 18450 out = out.concat( res ); 18451 } 18452 } 18453 } 18454 18455 // selector extensions 18456 var ext = _ext.selector[ type ]; 18457 if ( ext.length ) { 18458 for ( i=0, ien=ext.length ; i<ien ; i++ ) { 18459 out = ext[i]( settings, opts, out ); 18460 } 18461 } 18462 18463 return _unique( out ); 18464 }; 18465 18466 18467 var _selector_opts = function ( opts ) 18468 { 18469 if ( ! opts ) { 18470 opts = {}; 18471 } 18472 18473 // Backwards compatibility for 1.9- which used the terminology filter rather 18474 // than search 18475 if ( opts.filter && opts.search === undefined ) { 18476 opts.search = opts.filter; 18477 } 18478 18479 return $.extend( { 18480 search: 'none', 18481 order: 'current', 18482 page: 'all' 18483 }, opts ); 18484 }; 18485 18486 18487 var _selector_first = function ( inst ) 18488 { 18489 // Reduce the API instance to the first item found 18490 for ( var i=0, ien=inst.length ; i<ien ; i++ ) { 18491 if ( inst[i].length > 0 ) { 18492 // Assign the first element to the first item in the instance 18493 // and truncate the instance and context 18494 inst[0] = inst[i]; 18495 inst[0].length = 1; 18496 inst.length = 1; 18497 inst.context = [ inst.context[i] ]; 18498 18499 return inst; 18500 } 18501 } 18502 18503 // Not found - return an empty instance 18504 inst.length = 0; 18505 return inst; 18506 }; 18507 18508 18509 var _selector_row_indexes = function ( settings, opts ) 18510 { 18511 var 18512 i, ien, tmp, a=[], 18513 displayFiltered = settings.aiDisplay, 18514 displayMaster = settings.aiDisplayMaster; 18515 18516 var 18517 search = opts.search, // none, applied, removed 18518 order = opts.order, // applied, current, index (original - compatibility with 1.9) 18519 page = opts.page; // all, current 18520 18521 if ( _fnDataSource( settings ) == 'ssp' ) { 18522 // In server-side processing mode, most options are irrelevant since 18523 // rows not shown don't exist and the index order is the applied order 18524 // Removed is a special case - for consistency just return an empty 18525 // array 18526 return search === 'removed' ? 18527 [] : 18528 _range( 0, displayMaster.length ); 18529 } 18530 else if ( page == 'current' ) { 18531 // Current page implies that order=current and fitler=applied, since it is 18532 // fairly senseless otherwise, regardless of what order and search actually 18533 // are 18534 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) { 18535 a.push( displayFiltered[i] ); 18536 } 18537 } 18538 else if ( order == 'current' || order == 'applied' ) { 18539 a = search == 'none' ? 18540 displayMaster.slice() : // no search 18541 search == 'applied' ? 18542 displayFiltered.slice() : // applied search 18543 $.map( displayMaster, function (el, i) { // removed search 18544 return $.inArray( el, displayFiltered ) === -1 ? el : null; 18545 } ); 18546 } 18547 else if ( order == 'index' || order == 'original' ) { 18548 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 18549 if ( search == 'none' ) { 18550 a.push( i ); 18551 } 18552 else { // applied | removed 18553 tmp = $.inArray( i, displayFiltered ); 18554 18555 if ((tmp === -1 && search == 'removed') || 18556 (tmp >= 0 && search == 'applied') ) 18557 { 18558 a.push( i ); 18559 } 18560 } 18561 } 18562 } 18563 18564 return a; 18565 }; 18566 18567 18568 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 18569 * Rows 18570 * 18571 * {} - no selector - use all available rows 18572 * {integer} - row aoData index 18573 * {node} - TR node 18574 * {string} - jQuery selector to apply to the TR elements 18575 * {array} - jQuery array of nodes, or simply an array of TR nodes 18576 * 18577 */ 18578 18579 18580 var __row_selector = function ( settings, selector, opts ) 18581 { 18582 var run = function ( sel ) { 18583 var selInt = _intVal( sel ); 18584 var i, ien; 18585 18586 // Short cut - selector is a number and no options provided (default is 18587 // all records, so no need to check if the index is in there, since it 18588 // must be - dev error if the index doesn't exist). 18589 if ( selInt !== null && ! opts ) { 18590 return [ selInt ]; 18591 } 18592 18593 var rows = _selector_row_indexes( settings, opts ); 18594 18595 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) { 18596 // Selector - integer 18597 return [ selInt ]; 18598 } 18599 else if ( ! sel ) { 18600 // Selector - none 18601 return rows; 18602 } 18603 18604 // Selector - function 18605 if ( typeof sel === 'function' ) { 18606 return $.map( rows, function (idx) { 18607 var row = settings.aoData[ idx ]; 18608 return sel( idx, row._aData, row.nTr ) ? idx : null; 18609 } ); 18610 } 18611 18612 // Get nodes in the order from the `rows` array with null values removed 18613 var nodes = _removeEmpty( 18614 _pluck_order( settings.aoData, rows, 'nTr' ) 18615 ); 18616 18617 // Selector - node 18618 if ( sel.nodeName ) { 18619 if ( sel._DT_RowIndex !== undefined ) { 18620 return [ sel._DT_RowIndex ]; // Property added by DT for fast lookup 18621 } 18622 else if ( sel._DT_CellIndex ) { 18623 return [ sel._DT_CellIndex.row ]; 18624 } 18625 else { 18626 var host = $(sel).closest('*[data-dt-row]'); 18627 return host.length ? 18628 [ host.data('dt-row') ] : 18629 []; 18630 } 18631 } 18632 18633 // ID selector. Want to always be able to select rows by id, regardless 18634 // of if the tr element has been created or not, so can't rely upon 18635 // jQuery here - hence a custom implementation. This does not match 18636 // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything, 18637 // but to select it using a CSS selector engine (like Sizzle or 18638 // querySelect) it would need to need to be escaped for some characters. 18639 // DataTables simplifies this for row selectors since you can select 18640 // only a row. A # indicates an id any anything that follows is the id - 18641 // unescaped. 18642 if ( typeof sel === 'string' && sel.charAt(0) === '#' ) { 18643 // get row index from id 18644 var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ]; 18645 if ( rowObj !== undefined ) { 18646 return [ rowObj.idx ]; 18647 } 18648 18649 // need to fall through to jQuery in case there is DOM id that 18650 // matches 18651 } 18652 18653 // Selector - jQuery selector string, array of nodes or jQuery object/ 18654 // As jQuery's .filter() allows jQuery objects to be passed in filter, 18655 // it also allows arrays, so this will cope with all three options 18656 return $(nodes) 18657 .filter( sel ) 18658 .map( function () { 18659 return this._DT_RowIndex; 18660 } ) 18661 .toArray(); 18662 }; 18663 18664 return _selector_run( 'row', selector, run, settings, opts ); 18665 }; 18666 18667 18668 _api_register( 'rows()', function ( selector, opts ) { 18669 // argument shifting 18670 if ( selector === undefined ) { 18671 selector = ''; 18672 } 18673 else if ( $.isPlainObject( selector ) ) { 18674 opts = selector; 18675 selector = ''; 18676 } 18677 18678 opts = _selector_opts( opts ); 18679 18680 var inst = this.iterator( 'table', function ( settings ) { 18681 return __row_selector( settings, selector, opts ); 18682 }, 1 ); 18683 18684 // Want argument shifting here and in __row_selector? 18685 inst.selector.rows = selector; 18686 inst.selector.opts = opts; 18687 18688 return inst; 18689 } ); 18690 18691 _api_register( 'rows().nodes()', function () { 18692 return this.iterator( 'row', function ( settings, row ) { 18693 return settings.aoData[ row ].nTr || undefined; 18694 }, 1 ); 18695 } ); 18696 18697 _api_register( 'rows().data()', function () { 18698 return this.iterator( true, 'rows', function ( settings, rows ) { 18699 return _pluck_order( settings.aoData, rows, '_aData' ); 18700 }, 1 ); 18701 } ); 18702 18703 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) { 18704 return this.iterator( 'row', function ( settings, row ) { 18705 var r = settings.aoData[ row ]; 18706 return type === 'search' ? r._aFilterData : r._aSortData; 18707 }, 1 ); 18708 } ); 18709 18710 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) { 18711 return this.iterator( 'row', function ( settings, row ) { 18712 _fnInvalidate( settings, row, src ); 18713 } ); 18714 } ); 18715 18716 _api_registerPlural( 'rows().indexes()', 'row().index()', function () { 18717 return this.iterator( 'row', function ( settings, row ) { 18718 return row; 18719 }, 1 ); 18720 } ); 18721 18722 _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) { 18723 var a = []; 18724 var context = this.context; 18725 18726 // `iterator` will drop undefined values, but in this case we want them 18727 for ( var i=0, ien=context.length ; i<ien ; i++ ) { 18728 for ( var j=0, jen=this[i].length ; j<jen ; j++ ) { 18729 var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData ); 18730 a.push( (hash === true ? '#' : '' )+ id ); 18731 } 18732 } 18733 18734 return new _Api( context, a ); 18735 } ); 18736 18737 _api_registerPlural( 'rows().remove()', 'row().remove()', function () { 18738 var that = this; 18739 18740 this.iterator( 'row', function ( settings, row, thatIdx ) { 18741 var data = settings.aoData; 18742 var rowData = data[ row ]; 18743 var i, ien, j, jen; 18744 var loopRow, loopCells; 18745 18746 data.splice( row, 1 ); 18747 18748 // Update the cached indexes 18749 for ( i=0, ien=data.length ; i<ien ; i++ ) { 18750 loopRow = data[i]; 18751 loopCells = loopRow.anCells; 18752 18753 // Rows 18754 if ( loopRow.nTr !== null ) { 18755 loopRow.nTr._DT_RowIndex = i; 18756 } 18757 18758 // Cells 18759 if ( loopCells !== null ) { 18760 for ( j=0, jen=loopCells.length ; j<jen ; j++ ) { 18761 loopCells[j]._DT_CellIndex.row = i; 18762 } 18763 } 18764 } 18765 18766 // Delete from the display arrays 18767 _fnDeleteIndex( settings.aiDisplayMaster, row ); 18768 _fnDeleteIndex( settings.aiDisplay, row ); 18769 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes 18770 18771 // Check for an 'overflow' they case for displaying the table 18772 _fnLengthOverflow( settings ); 18773 18774 // Remove the row's ID reference if there is one 18775 var id = settings.rowIdFn( rowData._aData ); 18776 if ( id !== undefined ) { 18777 delete settings.aIds[ id ]; 18778 } 18779 } ); 18780 18781 this.iterator( 'table', function ( settings ) { 18782 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 18783 settings.aoData[i].idx = i; 18784 } 18785 } ); 18786 18787 return this; 18788 } ); 18789 18790 18791 _api_register( 'rows.add()', function ( rows ) { 18792 var newRows = this.iterator( 'table', function ( settings ) { 18793 var row, i, ien; 18794 var out = []; 18795 18796 for ( i=0, ien=rows.length ; i<ien ; i++ ) { 18797 row = rows[i]; 18798 18799 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { 18800 out.push( _fnAddTr( settings, row )[0] ); 18801 } 18802 else { 18803 out.push( _fnAddData( settings, row ) ); 18804 } 18805 } 18806 18807 return out; 18808 }, 1 ); 18809 18810 // Return an Api.rows() extended instance, so rows().nodes() etc can be used 18811 var modRows = this.rows( -1 ); 18812 modRows.pop(); 18813 $.merge( modRows, newRows ); 18814 18815 return modRows; 18816 } ); 18817 18818 18819 18820 18821 18822 /** 18823 * 18824 */ 18825 _api_register( 'row()', function ( selector, opts ) { 18826 return _selector_first( this.rows( selector, opts ) ); 18827 } ); 18828 18829 18830 _api_register( 'row().data()', function ( data ) { 18831 var ctx = this.context; 18832 18833 if ( data === undefined ) { 18834 // Get 18835 return ctx.length && this.length ? 18836 ctx[0].aoData[ this[0] ]._aData : 18837 undefined; 18838 } 18839 18840 // Set 18841 ctx[0].aoData[ this[0] ]._aData = data; 18842 18843 // Automatically invalidate 18844 _fnInvalidate( ctx[0], this[0], 'data' ); 18845 18846 return this; 18847 } ); 18848 18849 18850 _api_register( 'row().node()', function () { 18851 var ctx = this.context; 18852 18853 return ctx.length && this.length ? 18854 ctx[0].aoData[ this[0] ].nTr || null : 18855 null; 18856 } ); 18857 18858 18859 _api_register( 'row.add()', function ( row ) { 18860 // Allow a jQuery object to be passed in - only a single row is added from 18861 // it though - the first element in the set 18862 if ( row instanceof $ && row.length ) { 18863 row = row[0]; 18864 } 18865 18866 var rows = this.iterator( 'table', function ( settings ) { 18867 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { 18868 return _fnAddTr( settings, row )[0]; 18869 } 18870 return _fnAddData( settings, row ); 18871 } ); 18872 18873 // Return an Api.rows() extended instance, with the newly added row selected 18874 return this.row( rows[0] ); 18875 } ); 18876 18877 18878 18879 var __details_add = function ( ctx, row, data, klass ) 18880 { 18881 // Convert to array of TR elements 18882 var rows = []; 18883 var addRow = function ( r, k ) { 18884 // Recursion to allow for arrays of jQuery objects 18885 if ( $.isArray( r ) || r instanceof $ ) { 18886 for ( var i=0, ien=r.length ; i<ien ; i++ ) { 18887 addRow( r[i], k ); 18888 } 18889 return; 18890 } 18891 18892 // If we get a TR element, then just add it directly - up to the dev 18893 // to add the correct number of columns etc 18894 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) { 18895 rows.push( r ); 18896 } 18897 else { 18898 // Otherwise create a row with a wrapper 18899 var created = $('<tr><td/></tr>').addClass( k ); 18900 $('td', created) 18901 .addClass( k ) 18902 .html( r ) 18903 [0].colSpan = _fnVisbleColumns( ctx ); 18904 18905 rows.push( created[0] ); 18906 } 18907 }; 18908 18909 addRow( data, klass ); 18910 18911 if ( row._details ) { 18912 row._details.remove(); 18913 } 18914 18915 row._details = $(rows); 18916 18917 // If the children were already shown, that state should be retained 18918 if ( row._detailsShow ) { 18919 row._details.insertAfter( row.nTr ); 18920 } 18921 }; 18922 18923 18924 var __details_remove = function ( api, idx ) 18925 { 18926 var ctx = api.context; 18927 18928 if ( ctx.length ) { 18929 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ]; 18930 18931 if ( row && row._details ) { 18932 row._details.remove(); 18933 18934 row._detailsShow = undefined; 18935 row._details = undefined; 18936 } 18937 } 18938 }; 18939 18940 18941 var __details_display = function ( api, show ) { 18942 var ctx = api.context; 18943 18944 if ( ctx.length && api.length ) { 18945 var row = ctx[0].aoData[ api[0] ]; 18946 18947 if ( row._details ) { 18948 row._detailsShow = show; 18949 18950 if ( show ) { 18951 row._details.insertAfter( row.nTr ); 18952 } 18953 else { 18954 row._details.detach(); 18955 } 18956 18957 __details_events( ctx[0] ); 18958 } 18959 } 18960 }; 18961 18962 18963 var __details_events = function ( settings ) 18964 { 18965 var api = new _Api( settings ); 18966 var namespace = '.dt.DT_details'; 18967 var drawEvent = 'draw'+namespace; 18968 var colvisEvent = 'column-visibility'+namespace; 18969 var destroyEvent = 'destroy'+namespace; 18970 var data = settings.aoData; 18971 18972 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent ); 18973 18974 if ( _pluck( data, '_details' ).length > 0 ) { 18975 // On each draw, insert the required elements into the document 18976 api.on( drawEvent, function ( e, ctx ) { 18977 if ( settings !== ctx ) { 18978 return; 18979 } 18980 18981 api.rows( {page:'current'} ).eq(0).each( function (idx) { 18982 // Internal data grab 18983 var row = data[ idx ]; 18984 18985 if ( row._detailsShow ) { 18986 row._details.insertAfter( row.nTr ); 18987 } 18988 } ); 18989 } ); 18990 18991 // Column visibility change - update the colspan 18992 api.on( colvisEvent, function ( e, ctx, idx, vis ) { 18993 if ( settings !== ctx ) { 18994 return; 18995 } 18996 18997 // Update the colspan for the details rows (note, only if it already has 18998 // a colspan) 18999 var row, visible = _fnVisbleColumns( ctx ); 19000 19001 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 19002 row = data[i]; 19003 19004 if ( row._details ) { 19005 row._details.children('td[colspan]').attr('colspan', visible ); 19006 } 19007 } 19008 } ); 19009 19010 // Table destroyed - nuke any child rows 19011 api.on( destroyEvent, function ( e, ctx ) { 19012 if ( settings !== ctx ) { 19013 return; 19014 } 19015 19016 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 19017 if ( data[i]._details ) { 19018 __details_remove( api, i ); 19019 } 19020 } 19021 } ); 19022 } 19023 }; 19024 19025 // Strings for the method names to help minification 19026 var _emp = ''; 19027 var _child_obj = _emp+'row().child'; 19028 var _child_mth = _child_obj+'()'; 19029 19030 // data can be: 19031 // tr 19032 // string 19033 // jQuery or array of any of the above 19034 _api_register( _child_mth, function ( data, klass ) { 19035 var ctx = this.context; 19036 19037 if ( data === undefined ) { 19038 // get 19039 return ctx.length && this.length ? 19040 ctx[0].aoData[ this[0] ]._details : 19041 undefined; 19042 } 19043 else if ( data === true ) { 19044 // show 19045 this.child.show(); 19046 } 19047 else if ( data === false ) { 19048 // remove 19049 __details_remove( this ); 19050 } 19051 else if ( ctx.length && this.length ) { 19052 // set 19053 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass ); 19054 } 19055 19056 return this; 19057 } ); 19058 19059 19060 _api_register( [ 19061 _child_obj+'.show()', 19062 _child_mth+'.show()' // only when `child()` was called with parameters (without 19063 ], function ( show ) { // it returns an object and this method is not executed) 19064 __details_display( this, true ); 19065 return this; 19066 } ); 19067 19068 19069 _api_register( [ 19070 _child_obj+'.hide()', 19071 _child_mth+'.hide()' // only when `child()` was called with parameters (without 19072 ], function () { // it returns an object and this method is not executed) 19073 __details_display( this, false ); 19074 return this; 19075 } ); 19076 19077 19078 _api_register( [ 19079 _child_obj+'.remove()', 19080 _child_mth+'.remove()' // only when `child()` was called with parameters (without 19081 ], function () { // it returns an object and this method is not executed) 19082 __details_remove( this ); 19083 return this; 19084 } ); 19085 19086 19087 _api_register( _child_obj+'.isShown()', function () { 19088 var ctx = this.context; 19089 19090 if ( ctx.length && this.length ) { 19091 // _detailsShown as false or undefined will fall through to return false 19092 return ctx[0].aoData[ this[0] ]._detailsShow || false; 19093 } 19094 return false; 19095 } ); 19096 19097 19098 19099 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 19100 * Columns 19101 * 19102 * {integer} - column index (>=0 count from left, <0 count from right) 19103 * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right) 19104 * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right) 19105 * "{string}:name" - column name 19106 * "{string}" - jQuery selector on column header nodes 19107 * 19108 */ 19109 19110 // can be an array of these items, comma separated list, or an array of comma 19111 // separated lists 19112 19113 var __re_column_selector = /^(.+):(name|visIdx|visible)$/; 19114 19115 19116 // r1 and r2 are redundant - but it means that the parameters match for the 19117 // iterator callback in columns().data() 19118 var __columnData = function ( settings, column, r1, r2, rows ) { 19119 var a = []; 19120 for ( var row=0, ien=rows.length ; row<ien ; row++ ) { 19121 a.push( _fnGetCellData( settings, rows[row], column ) ); 19122 } 19123 return a; 19124 }; 19125 19126 19127 var __column_selector = function ( settings, selector, opts ) 19128 { 19129 var 19130 columns = settings.aoColumns, 19131 names = _pluck( columns, 'sName' ), 19132 nodes = _pluck( columns, 'nTh' ); 19133 19134 var run = function ( s ) { 19135 var selInt = _intVal( s ); 19136 19137 // Selector - all 19138 if ( s === '' ) { 19139 return _range( columns.length ); 19140 } 19141 19142 // Selector - index 19143 if ( selInt !== null ) { 19144 return [ selInt >= 0 ? 19145 selInt : // Count from left 19146 columns.length + selInt // Count from right (+ because its a negative value) 19147 ]; 19148 } 19149 19150 // Selector = function 19151 if ( typeof s === 'function' ) { 19152 var rows = _selector_row_indexes( settings, opts ); 19153 19154 return $.map( columns, function (col, idx) { 19155 return s( 19156 idx, 19157 __columnData( settings, idx, 0, 0, rows ), 19158 nodes[ idx ] 19159 ) ? idx : null; 19160 } ); 19161 } 19162 19163 // jQuery or string selector 19164 var match = typeof s === 'string' ? 19165 s.match( __re_column_selector ) : 19166 ''; 19167 19168 if ( match ) { 19169 switch( match[2] ) { 19170 case 'visIdx': 19171 case 'visible': 19172 var idx = parseInt( match[1], 10 ); 19173 // Visible index given, convert to column index 19174 if ( idx < 0 ) { 19175 // Counting from the right 19176 var visColumns = $.map( columns, function (col,i) { 19177 return col.bVisible ? i : null; 19178 } ); 19179 return [ visColumns[ visColumns.length + idx ] ]; 19180 } 19181 // Counting from the left 19182 return [ _fnVisibleToColumnIndex( settings, idx ) ]; 19183 19184 case 'name': 19185 // match by name. `names` is column index complete and in order 19186 return $.map( names, function (name, i) { 19187 return name === match[1] ? i : null; 19188 } ); 19189 19190 default: 19191 return []; 19192 } 19193 } 19194 19195 // Cell in the table body 19196 if ( s.nodeName && s._DT_CellIndex ) { 19197 return [ s._DT_CellIndex.column ]; 19198 } 19199 19200 // jQuery selector on the TH elements for the columns 19201 var jqResult = $( nodes ) 19202 .filter( s ) 19203 .map( function () { 19204 return $.inArray( this, nodes ); // `nodes` is column index complete and in order 19205 } ) 19206 .toArray(); 19207 19208 if ( jqResult.length || ! s.nodeName ) { 19209 return jqResult; 19210 } 19211 19212 // Otherwise a node which might have a `dt-column` data attribute, or be 19213 // a child or such an element 19214 var host = $(s).closest('*[data-dt-column]'); 19215 return host.length ? 19216 [ host.data('dt-column') ] : 19217 []; 19218 }; 19219 19220 return _selector_run( 'column', selector, run, settings, opts ); 19221 }; 19222 19223 19224 var __setColumnVis = function ( settings, column, vis ) { 19225 var 19226 cols = settings.aoColumns, 19227 col = cols[ column ], 19228 data = settings.aoData, 19229 row, cells, i, ien, tr; 19230 19231 // Get 19232 if ( vis === undefined ) { 19233 return col.bVisible; 19234 } 19235 19236 // Set 19237 // No change 19238 if ( col.bVisible === vis ) { 19239 return; 19240 } 19241 19242 if ( vis ) { 19243 // Insert column 19244 // Need to decide if we should use appendChild or insertBefore 19245 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 ); 19246 19247 for ( i=0, ien=data.length ; i<ien ; i++ ) { 19248 tr = data[i].nTr; 19249 cells = data[i].anCells; 19250 19251 if ( tr ) { 19252 // insertBefore can act like appendChild if 2nd arg is null 19253 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null ); 19254 } 19255 } 19256 } 19257 else { 19258 // Remove column 19259 $( _pluck( settings.aoData, 'anCells', column ) ).detach(); 19260 } 19261 19262 // Common actions 19263 col.bVisible = vis; 19264 _fnDrawHead( settings, settings.aoHeader ); 19265 _fnDrawHead( settings, settings.aoFooter ); 19266 19267 _fnSaveState( settings ); 19268 }; 19269 19270 19271 _api_register( 'columns()', function ( selector, opts ) { 19272 // argument shifting 19273 if ( selector === undefined ) { 19274 selector = ''; 19275 } 19276 else if ( $.isPlainObject( selector ) ) { 19277 opts = selector; 19278 selector = ''; 19279 } 19280 19281 opts = _selector_opts( opts ); 19282 19283 var inst = this.iterator( 'table', function ( settings ) { 19284 return __column_selector( settings, selector, opts ); 19285 }, 1 ); 19286 19287 // Want argument shifting here and in _row_selector? 19288 inst.selector.cols = selector; 19289 inst.selector.opts = opts; 19290 19291 return inst; 19292 } ); 19293 19294 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) { 19295 return this.iterator( 'column', function ( settings, column ) { 19296 return settings.aoColumns[column].nTh; 19297 }, 1 ); 19298 } ); 19299 19300 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) { 19301 return this.iterator( 'column', function ( settings, column ) { 19302 return settings.aoColumns[column].nTf; 19303 }, 1 ); 19304 } ); 19305 19306 _api_registerPlural( 'columns().data()', 'column().data()', function () { 19307 return this.iterator( 'column-rows', __columnData, 1 ); 19308 } ); 19309 19310 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () { 19311 return this.iterator( 'column', function ( settings, column ) { 19312 return settings.aoColumns[column].mData; 19313 }, 1 ); 19314 } ); 19315 19316 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) { 19317 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { 19318 return _pluck_order( settings.aoData, rows, 19319 type === 'search' ? '_aFilterData' : '_aSortData', column 19320 ); 19321 }, 1 ); 19322 } ); 19323 19324 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () { 19325 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { 19326 return _pluck_order( settings.aoData, rows, 'anCells', column ) ; 19327 }, 1 ); 19328 } ); 19329 19330 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) { 19331 var ret = this.iterator( 'column', function ( settings, column ) { 19332 if ( vis === undefined ) { 19333 return settings.aoColumns[ column ].bVisible; 19334 } // else 19335 __setColumnVis( settings, column, vis ); 19336 } ); 19337 19338 // Group the column visibility changes 19339 if ( vis !== undefined ) { 19340 // Second loop once the first is done for events 19341 this.iterator( 'column', function ( settings, column ) { 19342 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] ); 19343 } ); 19344 19345 if ( calc === undefined || calc ) { 19346 this.columns.adjust(); 19347 } 19348 } 19349 19350 return ret; 19351 } ); 19352 19353 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) { 19354 return this.iterator( 'column', function ( settings, column ) { 19355 return type === 'visible' ? 19356 _fnColumnIndexToVisible( settings, column ) : 19357 column; 19358 }, 1 ); 19359 } ); 19360 19361 _api_register( 'columns.adjust()', function () { 19362 return this.iterator( 'table', function ( settings ) { 19363 _fnAdjustColumnSizing( settings ); 19364 }, 1 ); 19365 } ); 19366 19367 _api_register( 'column.index()', function ( type, idx ) { 19368 if ( this.context.length !== 0 ) { 19369 var ctx = this.context[0]; 19370 19371 if ( type === 'fromVisible' || type === 'toData' ) { 19372 return _fnVisibleToColumnIndex( ctx, idx ); 19373 } 19374 else if ( type === 'fromData' || type === 'toVisible' ) { 19375 return _fnColumnIndexToVisible( ctx, idx ); 19376 } 19377 } 19378 } ); 19379 19380 _api_register( 'column()', function ( selector, opts ) { 19381 return _selector_first( this.columns( selector, opts ) ); 19382 } ); 19383 19384 19385 19386 var __cell_selector = function ( settings, selector, opts ) 19387 { 19388 var data = settings.aoData; 19389 var rows = _selector_row_indexes( settings, opts ); 19390 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) ); 19391 var allCells = $( [].concat.apply([], cells) ); 19392 var row; 19393 var columns = settings.aoColumns.length; 19394 var a, i, ien, j, o, host; 19395 19396 var run = function ( s ) { 19397 var fnSelector = typeof s === 'function'; 19398 19399 if ( s === null || s === undefined || fnSelector ) { 19400 // All cells and function selectors 19401 a = []; 19402 19403 for ( i=0, ien=rows.length ; i<ien ; i++ ) { 19404 row = rows[i]; 19405 19406 for ( j=0 ; j<columns ; j++ ) { 19407 o = { 19408 row: row, 19409 column: j 19410 }; 19411 19412 if ( fnSelector ) { 19413 // Selector - function 19414 host = data[ row ]; 19415 19416 if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) { 19417 a.push( o ); 19418 } 19419 } 19420 else { 19421 // Selector - all 19422 a.push( o ); 19423 } 19424 } 19425 } 19426 19427 return a; 19428 } 19429 19430 // Selector - index 19431 if ( $.isPlainObject( s ) ) { 19432 return [s]; 19433 } 19434 19435 // Selector - jQuery filtered cells 19436 var jqResult = allCells 19437 .filter( s ) 19438 .map( function (i, el) { 19439 return { // use a new object, in case someone changes the values 19440 row: el._DT_CellIndex.row, 19441 column: el._DT_CellIndex.column 19442 }; 19443 } ) 19444 .toArray(); 19445 19446 if ( jqResult.length || ! s.nodeName ) { 19447 return jqResult; 19448 } 19449 19450 // Otherwise the selector is a node, and there is one last option - the 19451 // element might be a child of an element which has dt-row and dt-column 19452 // data attributes 19453 host = $(s).closest('*[data-dt-row]'); 19454 return host.length ? 19455 [ { 19456 row: host.data('dt-row'), 19457 column: host.data('dt-column') 19458 } ] : 19459 []; 19460 }; 19461 19462 return _selector_run( 'cell', selector, run, settings, opts ); 19463 }; 19464 19465 19466 19467 19468 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) { 19469 // Argument shifting 19470 if ( $.isPlainObject( rowSelector ) ) { 19471 // Indexes 19472 if ( rowSelector.row === undefined ) { 19473 // Selector options in first parameter 19474 opts = rowSelector; 19475 rowSelector = null; 19476 } 19477 else { 19478 // Cell index objects in first parameter 19479 opts = columnSelector; 19480 columnSelector = null; 19481 } 19482 } 19483 if ( $.isPlainObject( columnSelector ) ) { 19484 opts = columnSelector; 19485 columnSelector = null; 19486 } 19487 19488 // Cell selector 19489 if ( columnSelector === null || columnSelector === undefined ) { 19490 return this.iterator( 'table', function ( settings ) { 19491 return __cell_selector( settings, rowSelector, _selector_opts( opts ) ); 19492 } ); 19493 } 19494 19495 // Row + column selector 19496 var columns = this.columns( columnSelector, opts ); 19497 var rows = this.rows( rowSelector, opts ); 19498 var a, i, ien, j, jen; 19499 19500 var cells = this.iterator( 'table', function ( settings, idx ) { 19501 a = []; 19502 19503 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) { 19504 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) { 19505 a.push( { 19506 row: rows[idx][i], 19507 column: columns[idx][j] 19508 } ); 19509 } 19510 } 19511 19512 return a; 19513 }, 1 ); 19514 19515 $.extend( cells.selector, { 19516 cols: columnSelector, 19517 rows: rowSelector, 19518 opts: opts 19519 } ); 19520 19521 return cells; 19522 } ); 19523 19524 19525 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () { 19526 return this.iterator( 'cell', function ( settings, row, column ) { 19527 var data = settings.aoData[ row ]; 19528 19529 return data && data.anCells ? 19530 data.anCells[ column ] : 19531 undefined; 19532 }, 1 ); 19533 } ); 19534 19535 19536 _api_register( 'cells().data()', function () { 19537 return this.iterator( 'cell', function ( settings, row, column ) { 19538 return _fnGetCellData( settings, row, column ); 19539 }, 1 ); 19540 } ); 19541 19542 19543 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) { 19544 type = type === 'search' ? '_aFilterData' : '_aSortData'; 19545 19546 return this.iterator( 'cell', function ( settings, row, column ) { 19547 return settings.aoData[ row ][ type ][ column ]; 19548 }, 1 ); 19549 } ); 19550 19551 19552 _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) { 19553 return this.iterator( 'cell', function ( settings, row, column ) { 19554 return _fnGetCellData( settings, row, column, type ); 19555 }, 1 ); 19556 } ); 19557 19558 19559 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () { 19560 return this.iterator( 'cell', function ( settings, row, column ) { 19561 return { 19562 row: row, 19563 column: column, 19564 columnVisible: _fnColumnIndexToVisible( settings, column ) 19565 }; 19566 }, 1 ); 19567 } ); 19568 19569 19570 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) { 19571 return this.iterator( 'cell', function ( settings, row, column ) { 19572 _fnInvalidate( settings, row, src, column ); 19573 } ); 19574 } ); 19575 19576 19577 19578 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) { 19579 return _selector_first( this.cells( rowSelector, columnSelector, opts ) ); 19580 } ); 19581 19582 19583 _api_register( 'cell().data()', function ( data ) { 19584 var ctx = this.context; 19585 var cell = this[0]; 19586 19587 if ( data === undefined ) { 19588 // Get 19589 return ctx.length && cell.length ? 19590 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) : 19591 undefined; 19592 } 19593 19594 // Set 19595 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data ); 19596 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column ); 19597 19598 return this; 19599 } ); 19600 19601 19602 19603 /** 19604 * Get current ordering (sorting) that has been applied to the table. 19605 * 19606 * @returns {array} 2D array containing the sorting information for the first 19607 * table in the current context. Each element in the parent array represents 19608 * a column being sorted upon (i.e. multi-sorting with two columns would have 19609 * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is 19610 * the column index that the sorting condition applies to, the second is the 19611 * direction of the sort (`desc` or `asc`) and, optionally, the third is the 19612 * index of the sorting order from the `column.sorting` initialisation array.
19613 *//** 19614 * Set the ordering for the table. 19615 * 19616 * @param {integer} order Column index to sort upon. 19617 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`) 19618 * @returns {DataTables.Api} this 19619 *//** 19620 * Set the ordering for the table. 19621 * 19622 * @param {array} order 1D array of sorting information to be applied. 19623 * @param {array} [...] Optional additional sorting conditions 19624 * @returns {DataTables.Api} this 19625 *//** 19626 * Set the ordering for the table. 19627 * 19628 * @param {array} order 2D array of sorting information to be applied. 19629 * @returns {DataTables.Api} this 19630 */ 19631 _api_register( 'order()', function ( order, dir ) { 19632 var ctx = this.context; 19633 19634 if ( order === undefined ) { 19635 // get 19636 return ctx.length !== 0 ? 19637 ctx[0].aaSorting : 19638 undefined; 19639 } 19640 19641 // set 19642 if ( typeof order === 'number' ) { 19643 // Simple column / direction passed in 19644 order = [ [ order, dir ] ]; 19645 } 19646 else if ( order.length && ! $.isArray( order[0] ) ) { 19647 // Arguments passed in (list of 1D arrays) 19648 order = Array.prototype.slice.call( arguments ); 19649 } 19650 // otherwise a 2D array was passed in 19651 19652 return this.iterator( 'table', function ( settings ) { 19653 settings.aaSorting = order.slice(); 19654 } ); 19655 } ); 19656 19657 19658 /** 19659 * Attach a sort listener to an element for a given column 19660 * 19661 * @param {node|jQuery|string} node Identifier for the element(s) to attach the 19662 * listener to. This can take the form of a single DOM node, a jQuery
vendor: 9,293 bytes, lines 19663-20015
19663 * collection of nodes or a jQuery selector which will identify the node(s). 19664 * @param {integer} column the column that a click on this node will sort on 19665 * @param {function} [callback] callback function when sort is run 19666 * @returns {DataTables.Api} this 19667 */ 19668 _api_register( 'order.listener()', function ( node, column, callback ) { 19669 return this.iterator( 'table', function ( settings ) { 19670 _fnSortAttachListener( settings, node, column, callback ); 19671 } ); 19672 } ); 19673 19674 19675 _api_register( 'order.fixed()', function ( set ) { 19676 if ( ! set ) { 19677 var ctx = this.context; 19678 var fixed = ctx.length ? 19679 ctx[0].aaSortingFixed : 19680 undefined; 19681 19682 return $.isArray( fixed ) ? 19683 { pre: fixed } : 19684 fixed; 19685 } 19686 19687 return this.iterator( 'table', function ( settings ) { 19688 settings.aaSortingFixed = $.extend( true, {}, set ); 19689 } ); 19690 } ); 19691 19692 19693 // Order by the selected column(s) 19694 _api_register( [ 19695 'columns().order()', 19696 'column().order()' 19697 ], function ( dir ) { 19698 var that = this; 19699 19700 return this.iterator( 'table', function ( settings, i ) { 19701 var sort = []; 19702 19703 $.each( that[i], function (j, col) { 19704 sort.push( [ col, dir ] ); 19705 } ); 19706 19707 settings.aaSorting = sort; 19708 } ); 19709 } ); 19710 19711 19712 19713 _api_register( 'search()', function ( input, regex, smart, caseInsen ) { 19714 var ctx = this.context; 19715 19716 if ( input === undefined ) { 19717 // get 19718 return ctx.length !== 0 ? 19719 ctx[0].oPreviousSearch.sSearch : 19720 undefined; 19721 } 19722 19723 // set 19724 return this.iterator( 'table', function ( settings ) { 19725 if ( ! settings.oFeatures.bFilter ) { 19726 return; 19727 } 19728 19729 _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, { 19730 "sSearch": input+"", 19731 "bRegex": regex === null ? false : regex, 19732 "bSmart": smart === null ? true : smart, 19733 "bCaseInsensitive": caseInsen === null ? true : caseInsen 19734 } ), 1 ); 19735 } ); 19736 } ); 19737 19738 19739 _api_registerPlural( 19740 'columns().search()', 19741 'column().search()', 19742 function ( input, regex, smart, caseInsen ) { 19743 return this.iterator( 'column', function ( settings, column ) { 19744 var preSearch = settings.aoPreSearchCols; 19745 19746 if ( input === undefined ) { 19747 // get 19748 return preSearch[ column ].sSearch; 19749 } 19750 19751 // set 19752 if ( ! settings.oFeatures.bFilter ) { 19753 return; 19754 } 19755 19756 $.extend( preSearch[ column ], { 19757 "sSearch": input+"", 19758 "bRegex": regex === null ? false : regex, 19759 "bSmart": smart === null ? true : smart, 19760 "bCaseInsensitive": caseInsen === null ? true : caseInsen 19761 } ); 19762 19763 _fnFilterComplete( settings, settings.oPreviousSearch, 1 ); 19764 } ); 19765 } 19766 ); 19767 19768 /* 19769 * State API methods 19770 */ 19771 19772 _api_register( 'state()', function () { 19773 return this.context.length ? 19774 this.context[0].oSavedState : 19775 null; 19776 } ); 19777 19778 19779 _api_register( 'state.clear()', function () { 19780 return this.iterator( 'table', function ( settings ) { 19781 // Save an empty object 19782 settings.fnStateSaveCallback.call( settings.oInstance, settings, {} ); 19783 } ); 19784 } ); 19785 19786 19787 _api_register( 'state.loaded()', function () { 19788 return this.context.length ? 19789 this.context[0].oLoadedState : 19790 null; 19791 } ); 19792 19793 19794 _api_register( 'state.save()', function () { 19795 return this.iterator( 'table', function ( settings ) { 19796 _fnSaveState( settings ); 19797 } ); 19798 } ); 19799 19800 19801 19802 /** 19803 * Provide a common method for plug-ins to check the version of DataTables being 19804 * used, in order to ensure compatibility. 19805 * 19806 * @param {string} version Version string to check for, in the format "X.Y.Z". 19807 * Note that the formats "X" and "X.Y" are also acceptable. 19808 * @returns {boolean} true if this version of DataTables is greater or equal to 19809 * the required version, or false if this version of DataTales is not 19810 * suitable 19811 * @static 19812 * @dtopt API-Static 19813 * 19814 * @example 19815 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) ); 19816 */ 19817 DataTable.versionCheck = DataTable.fnVersionCheck = function( version ) 19818 { 19819 var aThis = DataTable.version.split('.'); 19820 var aThat = version.split('.'); 19821 var iThis, iThat; 19822 19823 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) { 19824 iThis = parseInt( aThis[i], 10 ) || 0; 19825 iThat = parseInt( aThat[i], 10 ) || 0; 19826 19827 // Parts are the same, keep comparing 19828 if (iThis === iThat) { 19829 continue; 19830 } 19831 19832 // Parts are different, return immediately 19833 return iThis > iThat; 19834 } 19835 19836 return true; 19837 }; 19838 19839 19840 /** 19841 * Check if a `<table>` node is a DataTable table already or not. 19842 * 19843 * @param {node|jquery|string} table Table node, jQuery object or jQuery 19844 * selector for the table to test. Note that if more than more than one 19845 * table is passed on, only the first will be checked 19846 * @returns {boolean} true the table given is a DataTable, or false otherwise 19847 * @static 19848 * @dtopt API-Static 19849 * 19850 * @example 19851 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) { 19852 * $('#example').dataTable(); 19853 * } 19854 */ 19855 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table ) 19856 { 19857 var t = $(table).get(0); 19858 var is = false; 19859 19860 $.each( DataTable.settings, function (i, o) { 19861 var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null; 19862 var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null; 19863 19864 if ( o.nTable === t || head === t || foot === t ) { 19865 is = true; 19866 } 19867 } ); 19868 19869 return is; 19870 }; 19871 19872 19873 /** 19874 * Get all DataTable tables that have been initialised - optionally you can 19875 * select to get only currently visible tables. 19876 * 19877 * @param {boolean} [visible=false] Flag to indicate if you want all (default) 19878 * or visible tables only. 19879 * @returns {array} Array of `table` nodes (not DataTable instances) which are 19880 * DataTables 19881 * @static 19882 * @dtopt API-Static 19883 * 19884 * @example 19885 * $.each( $.fn.dataTable.tables(true), function () { 19886 * $(table).DataTable().columns.adjust(); 19887 * } ); 19888 */ 19889 DataTable.tables = DataTable.fnTables = function ( visible ) 19890 { 19891 var api = false; 19892 19893 if ( $.isPlainObject( visible ) ) { 19894 api = visible.api; 19895 visible = visible.visible; 19896 } 19897 19898 var a = $.map( DataTable.settings, function (o) { 19899 if ( !visible || (visible && $(o.nTable).is(':visible')) ) { 19900 return o.nTable; 19901 } 19902 } ); 19903 19904 return api ? 19905 new _Api( a ) : 19906 a; 19907 }; 19908 19909 19910 /** 19911 * Convert from camel case parameters to Hungarian notation. This is made public 19912 * for the extensions to provide the same ability as DataTables core to accept 19913 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase 19914 * parameters. 19915 * 19916 * @param {object} src The model object which holds all parameters that can be 19917 * mapped. 19918 * @param {object} user The object to convert from camel case to Hungarian. 19919 * @param {boolean} force When set to `true`, properties which already have a 19920 * Hungarian value in the `user` object will be overwritten. Otherwise they 19921 * won't be. 19922 */ 19923 DataTable.camelToHungarian = _fnCamelToHungarian; 19924 19925 19926 19927 /** 19928 * 19929 */ 19930 _api_register( '$()', function ( selector, opts ) { 19931 var 19932 rows = this.rows( opts ).nodes(), // Get all rows 19933 jqRows = $(rows); 19934 19935 return $( [].concat( 19936 jqRows.filter( selector ).toArray(), 19937 jqRows.find( selector ).toArray() 19938 ) ); 19939 } ); 19940 19941 19942 // jQuery functions to operate on the tables 19943 $.each( [ 'on', 'one', 'off' ], function (i, key) { 19944 _api_register( key+'()', function ( /* event, handler */ ) { 19945 var args = Array.prototype.slice.call(arguments); 19946 19947 // Add the `dt` namespace automatically if it isn't already present 19948 if ( ! args[0].match(/\.dt\b/) ) { 19949 args[0] += '.dt'; 19950 } 19951 19952 var inst = $( this.tables().nodes() ); 19953 inst[key].apply( inst, args ); 19954 return this; 19955 } ); 19956 } ); 19957 19958 19959 _api_register( 'clear()', function () { 19960 return this.iterator( 'table', function ( settings ) { 19961 _fnClearTable( settings ); 19962 } ); 19963 } ); 19964 19965 19966 _api_register( 'settings()', function () { 19967 return new _Api( this.context, this.context ); 19968 } ); 19969 19970 19971 _api_register( 'init()', function () { 19972 var ctx = this.context; 19973 return ctx.length ? ctx[0].oInit : null; 19974 } ); 19975 19976 19977 _api_register( 'data()', function () { 19978 return this.iterator( 'table', function ( settings ) { 19979 return _pluck( settings.aoData, '_aData' ); 19980 } ).flatten(); 19981 } ); 19982 19983 19984 _api_register( 'destroy()', function ( remove ) { 19985 remove = remove || false; 19986 19987 return this.iterator( 'table', function ( settings ) { 19988 var orig = settings.nTableWrapper.parentNode; 19989 var classes = settings.oClasses; 19990 var table = settings.nTable; 19991 var tbody = settings.nTBody; 19992 var thead = settings.nTHead; 19993 var tfoot = settings.nTFoot; 19994 var jqTable = $(table); 19995 var jqTbody = $(tbody); 19996 var jqWrapper = $(settings.nTableWrapper); 19997 var rows = $.map( settings.aoData, function (r) { return r.nTr; } ); 19998 var i, ien; 19999 20000 // Flag to note that the table is currently being destroyed - no action 20001 // should be taken 20002 settings.bDestroying = true; 20003 20004 // Fire off the destroy callbacks for plug-ins etc 20005 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] ); 20006 20007 // If not being removed from the document, make all columns visible 20008 if ( ! remove ) { 20009 new _Api( settings ).columns().visible( true ); 20010 } 20011 20012 // Blitz all `DT` namespaced events (these are internal events, the 20013 // lowercase, `dt` events are user subscribed and they are responsible 20014 // for removing them 20015 jqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT');
20016 $(window).unbind('.DT-'+settings.sInstance); 20017 20018 // When scrolling we had to break the table up - restore it 20019 if ( table != thead.parentNode ) { 20020 jqTable.children('thead').detach(); 20021 jqTable.append( thead ); 20022 } 20023 20024 if ( tfoot && table != tfoot.parentNode ) { 20025 jqTable.children('tfoot').detach(); 20026 jqTable.append( tfoot ); 20027 } 20028 20029 settings.aaSorting = []; 20030 settings.aaSortingFixed = []; 20031 _fnSortingClasses( settings ); 20032 20033 $( rows ).removeClass( settings.asStripeClasses.join(' ') ); 20034 20035 $('th, td', thead).removeClass( classes.sSortable+' '+ 20036 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone 20037 ); 20038 20039 if ( settings.bJUI ) { 20040 $('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach(); 20041 $('th, td', thead).each( function () { 20042 var wrapper = $('div.'+classes.sSortJUIWrapper, this); 20043 $(this).append( wrapper.contents() ); 20044 wrapper.detach(); 20045 } ); 20046 } 20047 20048 // Add the TR elements back into the table in their original order 20049 jqTbody.children().detach(); 20050 jqTbody.append( rows ); 20051 20052 // Remove the DataTables generated nodes, events and classes 20053 var removedMethod = remove ? 'remove' : 'detach'; 20054 jqTable[ removedMethod ](); 20055 jqWrapper[ removedMethod ](); 20056 20057 // If we need to reattach the table to the document 20058 if ( ! remove && orig ) { 20059 // insertBefore acts like appendChild if !arg[1] 20060 orig.insertBefore( table, settings.nTableReinsertBefore ); 20061 20062 // Restore the width of the original table - was read from the style property, 20063 // so we can restore directly to that 20064 jqTable 20065 .css( 'width', settings.sDestroyWidth ) 20066 .removeClass( classes.sTable ); 20067 20068 // If the were originally stripe classes - then we add them back here. 20069 // Note this is not fool proof (for example if not all rows had stripe 20070 // classes - but it's a good effort without getting carried away 20071 ien = settings.asDestroyStripes.length; 20072 20073 if ( ien ) { 20074 jqTbody.children().each( function (i) { 20075 $(this).addClass( settings.asDestroyStripes[i % ien] ); 20076 } ); 20077 } 20078 } 20079 20080 /* Remove the settings object from the settings array */ 20081 var idx = $.inArray( settings, DataTable.settings ); 20082 if ( idx !== -1 ) { 20083 DataTable.settings.splice( idx, 1 ); 20084 } 20085 } ); 20086 } ); 20087 20088 20089 // Add the `every()` method for rows, columns and cells in a compact form 20090 $.each( [ 'column', 'row', 'cell' ], function ( i, type ) { 20091 _api_register( type+'s().every()', function ( fn ) { 20092 var opts = this.selector.opts; 20093 var api = this; 20094 20095 return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) { 20096 // Rows and columns: 20097 // arg1 - index 20098 // arg2 - table counter 20099 // arg3 - loop counter 20100 // arg4 - undefined 20101 // Cells: 20102 // arg1 - row index 20103 // arg2 - column index 20104 // arg3 - table counter 20105 // arg4 - loop counter 20106 fn.call( 20107 api[ type ]( 20108 arg1, 20109 type==='cell' ? arg2 : opts, 20110 type==='cell' ? opts : undefined 20111 ), 20112 arg1, arg2, arg3, arg4 20113 ); 20114 } ); 20115 } ); 20116 } ); 20117 20118 20119 // i18n method for extensions to be able to use the language object from the 20120 // DataTable 20121 _api_register( 'i18n()', function ( token, def, plural ) { 20122 var ctx = this.context[0]; 20123 var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage ); 20124 20125 if ( resolved === undefined ) { 20126 resolved = def; 20127 } 20128 20129 if ( plural !== undefined && $.isPlainObject( resolved ) ) { 20130 resolved = resolved[ plural ] !== undefined ? 20131 resolved[ plural ] : 20132 resolved._; 20133 } 20134 20135 return resolved.replace( '%d', plural ); // nb: plural might be undefined, 20136 } ); 20137 /** 20138 * Version string for plug-ins to check compatibility. Allowed format is 20139 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used 20140 * only for non-release builds. See http://semver.org/ for more information. 20141 * @member 20142 * @type string 20143 * @default Version number 20144 */ 20145 DataTable.version = "1.10.12"; 20146 /** 20147 * Private data store, containing all of the settings objects that are 20148 * created for the tables on a given page. 20149 * 20150 * Note that the `DataTable.settings` object is aliased to 20151 * `jQuery.fn.dataTableExt` through which it may be accessed and 20152 * manipulated, or `jQuery.fn.dataTable.settings`. 20153 * @member 20154 * @type array 20155 * @default [] 20156 * @private 20157 */ 20158 DataTable.settings = []; 20159 /** 20160 * Object models container, for the various models that DataTables has 20161 * available to it. These models define the objects that are used to hold 20162 * the active state and configuration of the table. 20163 * @namespace 20164 */ 20165 DataTable.models = {}; 20166 20167 20168 20169 /** 20170 * Template object for the way in which DataTables holds information about 20171 * search information for the global filter and individual column filters. 20172 * @namespace 20173 */ 20174 DataTable.models.oSearch = { 20175 /** 20176 * Flag to indicate if the filtering should be case insensitive or not 20177 * @type boolean 20178 * @default true 20179 */ 20180 "bCaseInsensitive": true, 20181 20182 /** 20183 * Applied search term 20184 * @type string 20185 * @default <i>Empty string</i> 20186 */ 20187 "sSearch": "", 20188 20189 /** 20190 * Flag to indicate if the search term should be interpreted as a 20191 * regular expression (true) or not (false) and therefore and special 20192 * regex characters escaped. 20193 * @type boolean 20194 * @default false 20195 */ 20196 "bRegex": false, 20197 20198 /** 20199 * Flag to indicate if DataTables is to use its smart filtering or not. 20200 * @type boolean 20201 * @default true 20202 */ 20203 "bSmart": true 20204 }; 20205 20206 20207 20208 20209 /** 20210 * Template object for the way in which DataTables holds information about 20211 * each individual row. This is the object format used for the settings 20212 * aoData array.
20213 * @namespace 20214 */ 20215 DataTable.models.oRow = { 20216 /** 20217 * TR element for the row 20218 * @type node 20219 * @default null 20220 */ 20221 "nTr": null, 20222 20223 /** 20224 * Array of TD elements for each row. This is null until the row has been 20225 * created. 20226 * @type array nodes 20227 * @default [] 20228 */ 20229 "anCells": null, 20230 20231 /** 20232 * Data object from the original data source for the row. This is either 20233 * an array if using the traditional form of DataTables, or an object if 20234 * using mData options. The exact type will depend on the passed in 20235 * data from the data source, or will be an array if using DOM a data 20236 * source. 20237 * @type array|object 20238 * @default [] 20239 */ 20240 "_aData": [], 20241 20242 /** 20243 * Sorting data cache - this array is ostensibly the same length as the 20244 * number of columns (although each index is generated only as it is 20245 * needed), and holds the data that is used for sorting each column in the 20246 * row. We do this cache generation at the start of the sort in order that 20247 * the formatting of the sort data need be done only once for each cell 20248 * per sort. This array should not be read from or written to by anything 20249 * other than the master sorting methods. 20250 * @type array 20251 * @default null 20252 * @private 20253 */ 20254 "_aSortData": null, 20255 20256 /** 20257 * Per cell filtering data cache. As per the sort data cache, used to 20258 * increase the performance of the filtering in DataTables 20259 * @type array 20260 * @default null 20261 * @private 20262 */ 20263 "_aFilterData": null, 20264 20265 /** 20266 * Filtering data cache. This is the same as the cell filtering cache, but 20267 * in this case a string rather than an array. This is easily computed with 20268 * a join on `_aFilterData`, but is provided as a cache so the join isn't 20269 * needed on every search (memory traded for performance) 20270 * @type array 20271 * @default null 20272 * @private 20273 */ 20274 "_sFilterRow": null, 20275 20276 /** 20277 * Cache of the class name that DataTables has applied to the row, so we 20278 * can quickly look at this variable rather than needing to do a DOM check 20279 * on className for the nTr property. 20280 * @type string 20281 * @default <i>Empty string</i> 20282 * @private 20283 */ 20284 "_sRowStripe": "", 20285 20286 /** 20287 * Denote if the original data source was from the DOM, or the data source 20288 * object. This is used for invalidating data, so DataTables can 20289 * automatically read data from the original source, unless uninstructed 20290 * otherwise. 20291 * @type string 20292 * @default null 20293 * @private 20294 */ 20295 "src": null, 20296 20297 /** 20298 * Index in the aoData array. This saves an indexOf lookup when we have the 20299 * object, but want to know the index 20300 * @type integer 20301 * @default -1 20302 * @private 20303 */ 20304 "idx": -1 20305 }; 20306 20307 20308 /** 20309 * Template object for the column information object in DataTables. This object 20310 * is held in the settings aoColumns array and contains all the information that 20311 * DataTables needs about each individual column. 20312 * 20313 * Note that this object is related to {@link DataTable.defaults.column} 20314 * but this one is the internal data store for DataTables's cache of columns. 20315 * It should NOT be manipulated outside of DataTables. Any configuration should 20316 * be done through the initialisation options. 20317 * @namespace 20318 */ 20319 DataTable.models.oColumn = { 20320 /** 20321 * Column index. This could be worked out on-the-fly with $.inArray, but it 20322 * is faster to just hold it as a variable 20323 * @type integer 20324 * @default null 20325 */ 20326 "idx": null, 20327 20328 /** 20329 * A list of the columns that sorting should occur on when this column 20330 * is sorted. That this property is an array allows multi-column sorting 20331 * to be defined for a column (for example first name / last name columns 20332 * would benefit from this). The values are integers pointing to the 20333 * columns to be sorted on (typically it will be a single integer pointing 20334 * at itself, but that doesn't need to be the case). 20335 * @type array 20336 */ 20337 "aDataSort": null, 20338 20339 /** 20340 * Define the sorting directions that are applied to the column, in sequence 20341 * as the column is repeatedly sorted upon - i.e. the first value is used 20342 * as the sorting direction when the column if first sorted (clicked on). 20343 * Sort it again (click again) and it will move on to the next index. 20344 * Repeat until loop. 20345 * @type array 20346 */ 20347 "asSorting": null, 20348 20349 /** 20350 * Flag to indicate if the column is searchable, and thus should be included 20351 * in the filtering or not. 20352 * @type boolean 20353 */ 20354 "bSearchable": null, 20355 20356 /** 20357 * Flag to indicate if the column is sortable or not. 20358 * @type boolean 20359 */ 20360 "bSortable": null, 20361 20362 /** 20363 * Flag to indicate if the column is currently visible in the table or not 20364 * @type boolean 20365 */ 20366 "bVisible": null, 20367 20368 /** 20369 * Store for manual type assignment using the `column.type` option. This 20370 * is held in store so we can manipulate the column's `sType` property. 20371 * @type string 20372 * @default null 20373 * @private 20374 */ 20375 "_sManualType": null, 20376 20377 /** 20378 * Flag to indicate if HTML5 data attributes should be used as the data 20379 * source for filtering or sorting. True is either are. 20380 * @type boolean 20381 * @default false 20382 * @private 20383 */ 20384 "_bAttrSrc": false, 20385 20386 /** 20387 * Developer definable function that is called whenever a cell is created (Ajax source, 20388 * etc) or processed for input (DOM source). This can be used as a compliment to mRender 20389 * allowing you to modify the DOM element (add background colour for example) when the 20390 * element is available. 20391 * @type function 20392 * @param {element} nTd The TD node that has been created 20393 * @param {*} sData The Data for the cell 20394 * @param {array|object} oData The data for the whole row 20395 * @param {int} iRow The row index for the aoData data store 20396 * @default null 20397 */ 20398 "fnCreatedCell": null, 20399 20400 /** 20401 * Function to get data from a cell in a column. You should <b>never</b> 20402 * access data directly through _aData internally in DataTables - always use 20403 * the method attached to this property. It allows mData to function as 20404 * required. This function is automatically assigned by the column 20405 * initialisation method 20406 * @type function 20407 * @param {array|object} oData The data array/object for the array 20408 * (i.e. aoData[]._aData) 20409 * @param {string} sSpecific The specific data type you want to get - 20410 * 'display', 'type' 'filter' 'sort' 20411 * @returns {*} The data for the cell from the given row's data 20412 * @default null 20413 */ 20414 "fnGetData": null, 20415 20416 /** 20417 * Function to set data for a cell in the column. You should <b>never</b> 20418 * set the data directly to _aData internally in DataTables - always use 20419 * this method. It allows mData to function as required. This function 20420 * is automatically assigned by the column initialisation method 20421 * @type function 20422 * @param {array|object} oData The data array/object for the array 20423 * (i.e. aoData[]._aData) 20424 * @param {*} sValue Value to set 20425 * @default null 20426 */ 20427 "fnSetData": null, 20428 20429 /** 20430 * Property to read the value for the cells in the column from the data 20431 * source array / object. If null, then the default content is used, if a 20432 * function is given then the return from the function is used. 20433 * @type function|int|string|null 20434 * @default null 20435 */ 20436 "mData": null, 20437 20438 /** 20439 * Partner property to mData which is used (only when defined) to get 20440 * the data - i.e. it is basically the same as mData, but without the 20441 * 'set' option, and also the data fed to it is the result from mData. 20442 * This is the rendering method to match the data method of mData. 20443 * @type function|int|string|null 20444 * @default null 20445 */
20446 "mRender": null, 20447 20448 /** 20449 * Unique header TH/TD element for this column - this is what the sorting 20450 * listener is attached to (if sorting is enabled.) 20451 * @type node 20452 * @default null 20453 */ 20454 "nTh": null, 20455 20456 /** 20457 * Unique footer TH/TD element for this column (if there is one). Not used 20458 * in DataTables as such, but can be used for plug-ins to reference the 20459 * footer for each column. 20460 * @type node 20461 * @default null 20462 */ 20463 "nTf": null, 20464 20465 /** 20466 * The class to apply to all TD elements in the table's TBODY for the column 20467 * @type string 20468 * @default null 20469 */ 20470 "sClass": null, 20471 20472 /** 20473 * When DataTables calculates the column widths to assign to each column, 20474 * it finds the longest string in each column and then constructs a 20475 * temporary table and reads the widths from that. The problem with this 20476 * is that "mmm" is much wider then "iiii", but the latter is a longer 20477 * string - thus the calculation can go wrong (doing it properly and putting 20478 * it into an DOM object and measuring that is horribly(!) slow). Thus as 20479 * a "work around" we provide this option. It will append its value to the 20480 * text that is found to be the longest string for the column - i.e. padding. 20481 * @type string 20482 */ 20483 "sContentPadding": null, 20484 20485 /** 20486 * Allows a default value to be given for a column's data, and will be used 20487 * whenever a null data source is encountered (this can be because mData 20488 * is set to null, or because the data source itself is null). 20489 * @type string 20490 * @default null 20491 */ 20492 "sDefaultContent": null, 20493 20494 /** 20495 * Name for the column, allowing reference to the column by name as well as 20496 * by index (needs a lookup to work by name). 20497 * @type string 20498 */ 20499 "sName": null, 20500 20501 /** 20502 * Custom sorting data type - defines which of the available plug-ins in 20503 * afnSortData the custom sorting will use - if any is defined. 20504 * @type string 20505 * @default std 20506 */ 20507 "sSortDataType": 'std', 20508 20509 /** 20510 * Class to be applied to the header element when sorting on this column 20511 * @type string 20512 * @default null 20513 */ 20514 "sSortingClass": null, 20515 20516 /** 20517 * Class to be applied to the header element when sorting on this column - 20518 * when jQuery UI theming is used. 20519 * @type string 20520 * @default null 20521 */ 20522 "sSortingClassJUI": null, 20523 20524 /** 20525 * Title of the column - what is seen in the TH element (nTh). 20526 * @type string 20527 */ 20528 "sTitle": null, 20529 20530 /** 20531 * Column sorting and filtering type 20532 * @type string 20533 * @default null 20534 */ 20535 "sType": null, 20536 20537 /** 20538 * Width of the column 20539 * @type string 20540 * @default null 20541 */ 20542 "sWidth": null, 20543 20544 /** 20545 * Width of the column when it was first "encountered" 20546 * @type string 20547 * @default null 20548 */ 20549 "sWidthOrig": null 20550 }; 20551 20552 20553 /* 20554 * Developer note: The properties of the object below are given in Hungarian 20555 * notation, that was used as the interface for DataTables prior to v1.10, however 20556 * from v1.10 onwards the primary interface is camel case. In order to avoid 20557 * breaking backwards compatibility utterly with this change, the Hungarian
20558 * version is still, internally the primary interface, but is is not documented 20559 * - hence the @name tags in each doc comment. This allows a Javascript function 20560 * to create a map from Hungarian notation to camel case (going the other direction 20561 * would require each property to be listed, which would at around 3K to the size 20562 * of DataTables, while this method is about a 0.5K hit. 20563 * 20564 * Ultimately this does pave the way for Hungarian notation to be dropped 20565 * completely, but that is a massive amount of work and will break current 20566 * installs (therefore is on-hold until v2). 20567 */ 20568 20569 /** 20570 * Initialisation options that can be given to DataTables at initialisation 20571 * time. 20572 * @namespace 20573 */ 20574 DataTable.defaults = { 20575 /** 20576 * An array of data to use for the table, passed in at initialisation which 20577 * will be used in preference to any data which is already in the DOM. This is 20578 * particularly useful for constructing tables purely in Javascript, for 20579 * example with a custom Ajax call. 20580 * @type array 20581 * @default null 20582 * 20583 * @dtopt Option 20584 * @name DataTable.defaults.data 20585 * 20586 * @example 20587 * // Using a 2D array data source 20588 * $(document).ready( function () { 20589 * $('#example').dataTable( { 20590 * "data": [ 20591 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'], 20592 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'], 20593 * ], 20594 * "columns": [ 20595 * { "title": "Engine" }, 20596 * { "title": "Browser" }, 20597 * { "title": "Platform" }, 20598 * { "title": "Version" }, 20599 * { "title": "Grade" } 20600 * ] 20601 * } ); 20602 * } ); 20603 * 20604 * @example 20605 * // Using an array of objects as a data source (`data`) 20606 * $(document).ready( function () { 20607 * $('#example').dataTable( { 20608 * "data": [ 20609 * { 20610 * "engine": "Trident", 20611 * "browser": "Internet Explorer 4.0", 20612 * "platform": "Win 95+", 20613 * "version": 4, 20614 * "grade": "X" 20615 * }, 20616 * { 20617 * "engine": "Trident", 20618 * "browser": "Internet Explorer 5.0", 20619 * "platform": "Win 95+", 20620 * "version": 5, 20621 * "grade": "C" 20622 * } 20623 * ], 20624 * "columns": [ 20625 * { "title": "Engine", "data": "engine" }, 20626 * { "title": "Browser", "data": "browser" }, 20627 * { "title": "Platform", "data": "platform" }, 20628 * { "title": "Version", "data": "version" }, 20629 * { "title": "Grade", "data": "grade" } 20630 * ] 20631 * } ); 20632 * } ); 20633 */ 20634 "aaData": null, 20635 20636 20637 /** 20638 * If ordering is enabled, then DataTables will perform a first pass sort on 20639 * initialisation. You can define which column(s) the sort is performed 20640 * upon, and the sorting direction, with this variable. The `sorting` array 20641 * should contain an array for each column to be sorted initially containing 20642 * the column's index and a direction string ('asc' or 'desc'). 20643 * @type array 20644 * @default [[0,'asc']] 20645 * 20646 * @dtopt Option 20647 * @name DataTable.defaults.order 20648 * 20649 * @example 20650 * // Sort by 3rd column first, and then 4th column 20651 * $(document).ready( function() { 20652 * $('#example').dataTable( { 20653 * "order": [[2,'asc'], [3,'desc']] 20654 * } ); 20655 * } ); 20656 * 20657 * // No initial sorting 20658 * $(document).ready( function() { 20659 * $('#example').dataTable( { 20660 * "order": [] 20661 * } ); 20662 * } ); 20663 */ 20664 "aaSorting": [[0,'asc']], 20665 20666 20667 /** 20668 * This parameter is basically identical to the `sorting` parameter, but 20669 * cannot be overridden by user interaction with the table. What this means 20670 * is that you could have a column (visible or hidden) which the sorting 20671 * will always be forced on first - any sorting after that (from the user) 20672 * will then be performed as required. This can be useful for grouping rows 20673 * together. 20674 * @type array 20675 * @default null 20676 * 20677 * @dtopt Option 20678 * @name DataTable.defaults.orderFixed 20679 * 20680 * @example 20681 * $(document).ready( function() { 20682 * $('#example').dataTable( { 20683 * "orderFixed": [[0,'asc']] 20684 * } ); 20685 * } ) 20686 */ 20687 "aaSortingFixed": [], 20688 20689 20690 /** 20691 * DataTables can be instructed to load data to display in the table from a 20692 * Ajax source. This option defines how that Ajax call is made and where to. 20693 * 20694 * The `ajax` property has three different modes of operation, depending on 20695 * how it is defined. These are: 20696 * 20697 * * `string` - Set the URL from where the data should be loaded from. 20698 * * `object` - Define properties for `jQuery.ajax`. 20699 * * `function` - Custom data get function 20700 * 20701 * `string` 20702 * -------- 20703 * 20704 * As a string, the `ajax` property simply defines the URL from which 20705 * DataTables will load data. 20706 * 20707 * `object` 20708 * -------- 20709 * 20710 * As an object, the parameters in the object are passed to 20711 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
20712 * of the Ajax request. DataTables has a number of default parameters which 20713 * you can override using this option. Please refer to the jQuery 20714 * documentation for a full description of the options available, although 20715 * the following parameters provide additional options in DataTables or 20716 * require special consideration: 20717 * 20718 * * `data` - As with jQuery, `data` can be provided as an object, but it 20719 * can also be used as a function to manipulate the data DataTables sends 20720 * to the server. The function takes a single parameter, an object of 20721 * parameters with the values that DataTables has readied for sending. An 20722 * object may be returned which will be merged into the DataTables 20723 * defaults, or you can add the items to the object that was passed in and 20724 * not return anything from the function. This supersedes `fnServerParams` 20725 * from DataTables 1.9-. 20726 * 20727 * * `dataSrc` - By default DataTables will look for the property `data` (or 20728 * `aaData` for compatibility with DataTables 1.9-) when obtaining data 20729 * from an Ajax source or for server-side processing - this parameter 20730 * allows that property to be changed. You can use Javascript dotted 20731 * object notation to get a data source for multiple levels of nesting, or 20732 * it my be used as a function. As a function it takes a single parameter, 20733 * the JSON returned from the server, which can be manipulated as 20734 * required, with the returned value being that used by DataTables as the 20735 * data source for the table. This supersedes `sAjaxDataProp` from 20736 * DataTables 1.9-. 20737 * 20738 * * `success` - Should not be overridden it is used internally in 20739 * DataTables. To manipulate / transform the data returned by the server 20740 * use `ajax.dataSrc`, or use `ajax` as a function (see below). 20741 * 20742 * `function` 20743 * ---------- 20744 * 20745 * As a function, making the Ajax call is left up to yourself allowing 20746 * complete control of the Ajax request. Indeed, if desired, a method other 20747 * than Ajax could be used to obtain the required data, such as Web storage 20748 * or an AIR database. 20749 * 20750 * The function is given four parameters and no return is required. The 20751 * parameters are: 20752 * 20753 * 1. _object_ - Data to send to the server 20754 * 2. _function_ - Callback function that must be executed when the required 20755 * data has been obtained. That data should be passed into the callback 20756 * as the only parameter 20757 * 3. _object_ - DataTables settings object for the table 20758 * 20759 * Note that this supersedes `fnServerData` from DataTables 1.9-. 20760 * 20761 * @type string|object|function 20762 * @default null 20763 * 20764 * @dtopt Option 20765 * @name DataTable.defaults.ajax 20766 * @since 1.10.0 20767 * 20768 * @example 20769 * // Get JSON data from a file via Ajax. 20770 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default). 20771 * $('#example').dataTable( { 20772 * "ajax": "data.json" 20773 * } ); 20774 * 20775 * @example 20776 * // Get JSON data from a file via Ajax, using `dataSrc` to change 20777 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`) 20778 * $('#example').dataTable( { 20779 * "ajax": { 20780 * "url": "data.json", 20781 * "dataSrc": "tableData" 20782 * } 20783 * } ); 20784 * 20785 * @example 20786 * // Get JSON data from a file via Ajax, using `dataSrc` to read data 20787 * // from a plain array rather than an array in an object 20788 * $('#example').dataTable( { 20789 * "ajax": { 20790 * "url": "data.json", 20791 * "dataSrc": "" 20792 * } 20793 * } ); 20794 * 20795 * @example 20796 * // Manipulate the data returned from the server - add a link to data 20797 * // (note this can, should, be done using `render` for the column - this 20798 * // is just a simple example of how the data can be manipulated). 20799 * $('#example').dataTable( { 20800 * "ajax": { 20801 * "url": "data.json", 20802 * "dataSrc": function ( json ) { 20803 * for ( var i=0, ien=json.length ; i<ien ; i++ ) { 20804 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>'; 20805 * } 20806 * return json; 20807 * } 20808 * } 20809 * } ); 20810 * 20811 * @example 20812 * // Add data to the request 20813 * $('#example').dataTable( { 20814 * "ajax": { 20815 * "url": "data.json", 20816 * "data": function ( d ) { 20817 * return { 20818 * "extra_search": $('#extra').val() 20819 * }; 20820 * } 20821 * } 20822 * } ); 20823 * 20824 * @example 20825 * // Send request as POST 20826 * $('#example').dataTable( { 20827 * "ajax": { 20828 * "url": "data.json", 20829 * "type": "POST" 20830 * } 20831 * } ); 20832 * 20833 * @example 20834 * // Get the data from localStorage (could interface with a form for 20835 * // adding, editing and removing rows). 20836 * $('#example').dataTable( { 20837 * "ajax": function (data, callback, settings) { 20838 * callback( 20839 * JSON.parse( localStorage.getItem('dataTablesData') ) 20840 * ); 20841 * } 20842 * } ); 20843 */ 20844 "ajax": null, 20845 20846 20847 /** 20848 * This parameter allows you to readily specify the entries in the length drop 20849 * down menu that DataTables shows when pagination is enabled. It can be 20850 * either a 1D array of options which will be used for both the displayed 20851 * option and the value, or a 2D array which will use the array in the first 20852 * position as the value, and the array in the second position as the 20853 * displayed options (useful for language strings such as 'All'). 20854 * 20855 * Note that the `pageLength` property will be automatically set to the 20856 * first value given in this array, unless `pageLength` is also provided. 20857 * @type array 20858 * @default [ 10, 25, 50, 100 ] 20859 * 20860 * @dtopt Option 20861 * @name DataTable.defaults.lengthMenu 20862 * 20863 * @example 20864 * $(document).ready( function() { 20865 * $('#example').dataTable( { 20866 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]] 20867 * } ); 20868 * } ); 20869 */
20870 "aLengthMenu": [ 10, 25, 50, 100 ], 20871 20872 20873 /** 20874 * The `columns` option in the initialisation parameter allows you to define 20875 * details about the way individual columns behave. For a full list of 20876 * column options that can be set, please see 20877 * {@link DataTable.defaults.column}. Note that if you use `columns` to 20878 * define your columns, you must have an entry in the array for every single 20879 * column that you have in your table (these can be null if you don't which 20880 * to specify any options). 20881 * @member 20882 * 20883 * @name DataTable.defaults.column 20884 */ 20885 "aoColumns": null, 20886 20887 /** 20888 * Very similar to `columns`, `columnDefs` allows you to target a specific 20889 * column, multiple columns, or all columns, using the `targets` property of 20890 * each object in the array. This allows great flexibility when creating 20891 * tables, as the `columnDefs` arrays can be of any length, targeting the 20892 * columns you specifically want. `columnDefs` may use any of the column 20893 * options available: {@link DataTable.defaults.column}, but it _must_ 20894 * have `targets` defined in each object in the array. Values in the `targets` 20895 * array may be: 20896 * <ul> 20897 * <li>a string - class name will be matched on the TH for the column</li> 20898 * <li>0 or a positive integer - column index counting from the left</li> 20899 * <li>a negative integer - column index counting from the right</li> 20900 * <li>the string "_all" - all columns (i.e. assign a default)</li> 20901 * </ul> 20902 * @member 20903 * 20904 * @name DataTable.defaults.columnDefs 20905 */ 20906 "aoColumnDefs": null, 20907 20908 20909 /** 20910 * Basically the same as `search`, this parameter defines the individual column 20911 * filtering state at initialisation time. The array must be of the same size 20912 * as the number of columns, and each element be an object with the parameters 20913 * `search` and `escapeRegex` (the latter is optional). 'null' is also 20914 * accepted and the default will be used. 20915 * @type array 20916 * @default [] 20917 * 20918 * @dtopt Option 20919 * @name DataTable.defaults.searchCols 20920 * 20921 * @example 20922 * $(document).ready( function() { 20923 * $('#example').dataTable( { 20924 * "searchCols": [ 20925 * null, 20926 * { "search": "My filter" }, 20927 * null, 20928 * { "search": "^[0-9]", "escapeRegex": false } 20929 * ] 20930 * } ); 20931 * } ) 20932 */ 20933 "aoSearchCols": [], 20934 20935 20936 /** 20937 * An array of CSS classes that should be applied to displayed rows. This 20938 * array may be of any length, and DataTables will apply each class 20939 * sequentially, looping when required. 20940 * @type array 20941 * @default null <i>
20941Will take the values determined by the `oClasses.stripe*` 20942 * options</i> 20943 * 20944 * @dtopt Option 20945 * @name DataTable.defaults.stripeClasses 20946 * 20947 * @example 20948 * $(document).ready( function() { 20949 * $('#example').dataTable( { 20950 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ] 20951 * } ); 20952 * } ) 20953 */ 20954 "asStripeClasses": null, 20955 20956 20957 /** 20958 * Enable or disable automatic column width calculation. This can be disabled 20959 * as an optimisation (it takes some time to calculate the widths) if the 20960 * tables widths are passed in using `columns`. 20961 * @type boolean 20962 * @default true 20963 * 20964 * @dtopt Features 20965 * @name DataTable.defaults.autoWidth 20966 * 20967 * @example 20968 * $(document).ready( function () { 20969 * $('#example').dataTable( { 20970 * "autoWidth": false 20971 * } ); 20972 * } ); 20973 */ 20974 "bAutoWidth": true, 20975 20976 20977 /** 20978 * Deferred rendering can provide DataTables with a huge speed boost when you 20979 * are using an Ajax or JS data source for the table. This option, when set to 20980 * true, will cause DataTables to defer the creation of the table elements for 20981 * each row until they are needed for a draw - saving a significant amount of 20982 * time. 20983 * @type boolean 20984 * @default false 20985 * 20986 * @dtopt Features 20987 * @name DataTable.defaults.deferRender 20988 * 20989 * @example 20990 * $(document).ready( function() { 20991 * $('#example').dataTable( { 20992 * "ajax": "sources/arrays.txt", 20993 * "deferRender": true 20994 * } ); 20995 * } ); 20996 */ 20997 "bDeferRender": false, 20998 20999 21000 /** 21001 * Replace a DataTable which matches the given selector and replace it with 21002 * one which has the properties of the new initialisation object passed. If no 21003 * table matches the selector, then the new DataTable will be constructed as 21004 * per normal. 21005 * @type boolean 21006 * @default false 21007 * 21008 * @dtopt Options 21009 * @name DataTable.defaults.destroy 21010 * 21011 * @example 21012 * $(document).ready( function() { 21013 * $('#example').dataTable( { 21014 * "srollY": "200px", 21015 * "paginate": false 21016 * } ); 21017 * 21018 * // Some time later.... 21019 * $('#example').dataTable( { 21020 * "filter": false, 21021 * "destroy": true 21022 * } ); 21023 * } ); 21024 */ 21025 "bDestroy": false, 21026 21027 21028 /** 21029 * Enable or disable filtering of data. Filtering in DataTables is "smart" in 21030 * that it allows the end user to input multiple words (space separated) and 21031 * will match a row containing those words, even if not in the order that was 21032 * specified (this allow matching across multiple columns). Note that if you 21033 * wish to use filtering in DataTables this must remain 'true' - to remove the 21034 * default filtering input box and retain filtering abilities, please use 21035 * {@link DataTable.defaults.dom}. 21036 * @type boolean 21037 * @default true 21038 * 21039 * @dtopt Features 21040 * @name DataTable.defaults.searching 21041 * 21042 * @example 21043 * $(document).ready( function () { 21044 * $('#example').dataTable( { 21045 * "searching": false 21046 * } ); 21047 * } ); 21048 */ 21049 "bFilter": true, 21050 21051 21052 /** 21053 * Enable or disable the table information display. This shows information 21054 * about the data that is currently visible on the page, including information 21055 * about filtered data if that action is being performed. 21056 * @type boolean 21057 * @default true 21058 * 21059 * @dtopt Features 21060 * @name DataTable.defaults.info 21061 * 21062 * @example 21063 * $(document).ready( function () { 21064 * $('#example').dataTable( { 21065 * "info": false 21066 * } ); 21067 * } ); 21068 */ 21069 "bInfo": true, 21070 21071 21072 /** 21073 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some 21074 * slightly different and additional mark-up from what DataTables has 21075 * traditionally used). 21076 * @type boolean 21077 * @default false 21078 * 21079 * @dtopt Features 21080 * @name DataTable.defaults.jQueryUI 21081 * 21082 * @example 21083 * $(document).ready( function() { 21084 * $('#example').dataTable( { 21085 * "jQueryUI": true 21086 * } ); 21087 * } ); 21088 */ 21089 "bJQueryUI": false, 21090 21091 21092 /** 21093 * Allows the end user to select the size of a formatted page from a select 21094 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`). 21095 * @type boolean 21096 * @default true 21097 * 21098 * @dtopt Features 21099 * @name DataTable.defaults.lengthChange 21100 * 21101 * @example 21102 * $(document).ready( function () { 21103 * $('#example').dataTable( { 21104 * "lengthChange": false 21105 * } ); 21106 * } ); 21107 */ 21108 "bLengthChange": true, 21109 21110 21111 /** 21112 * Enable or disable pagination. 21113 * @type boolean 21114 * @default true 21115 * 21116 * @dtopt Features 21117 * @name DataTable.defaults.paging 21118 * 21119 * @example 21120 * $(document).ready( function () { 21121 * $('#example').dataTable( { 21122 * "paging": false 21123 * } ); 21124 * } ); 21125 */ 21126 "bPaginate": true, 21127 21128 21129 /** 21130 * Enable or disable the display of a 'processing' indicator when the table is 21131 * being processed (e.g. a sort). This is particularly useful for tables with 21132 * large amounts of data where it can take a noticeable amount of time to sort 21133 * the entries. 21134 * @type boolean 21135 * @default false 21136 * 21137 * @dtopt Features 21138 * @name DataTable.defaults.processing 21139 * 21140 * @example 21141 * $(document).ready( function () { 21142 * $('#example').dataTable( { 21143 * "processing": true 21144 * } ); 21145 * } ); 21146 */ 21147 "bProcessing": false, 21148 21149 21150 /** 21151 * Retrieve the DataTables object for the given selector. Note that if the 21152 * table has already been initialised, this parameter will cause DataTables 21153 * to simply return the object that has already been set up - it will not take 21154 * account of any changes you might have made to the initialisation object 21155 * passed to DataTables (setting this parameter to true is an acknowledgement 21156 * that you understand this). `destroy` can be used to reinitialise a table if 21157 * you need. 21158 * @type boolean 21159 * @default false 21160 * 21161 * @dtopt Options 21162 * @name DataTable.defaults.retrieve 21163 * 21164 * @example 21165 * $(document).ready( function() { 21166 * initTable(); 21167 * tableActions(); 21168 * } ); 21169 * 21170 * function initTable () 21171 * { 21172 * return $('#example').dataTable( { 21173 * "scrollY": "200px", 21174 * "paginate": false, 21175 * "retrieve": true 21176 * } ); 21177 * } 21178 * 21179 * function tableActions () 21180 * { 21181 * var table = initTable(); 21182 * // perform API operations with oTable 21183 * } 21184 */ 21185 "bRetrieve": false, 21186 21187 21188 /** 21189 * When vertical (y) scrolling is enabled, DataTables will force the height of
21190 * the table's viewport to the given height at all times (useful for layout). 21191 * However, this can look odd when filtering data down to a small data set, 21192 * and the footer is left "floating" further down. This parameter (when 21193 * enabled) will cause DataTables to collapse the table's viewport down when 21194 * the result set will fit within the given Y height. 21195 * @type boolean 21196 * @default false 21197 * 21198 * @dtopt Options 21199 * @name DataTable.defaults.scrollCollapse 21200 * 21201 * @example 21202 * $(document).ready( function() { 21203 * $('#example').dataTable( { 21204 * "scrollY": "200", 21205 * "scrollCollapse": true 21206 * } ); 21207 * } ); 21208 */ 21209 "bScrollCollapse": false, 21210 21211 21212 /** 21213 * Configure DataTables to use server-side processing. Note that the 21214 * `ajax` parameter must also be given in order to give DataTables a 21215 * source to obtain the required data for each draw. 21216 * @type boolean 21217 * @default false 21218 * 21219 * @dtopt Features 21220 * @dtopt Server-side 21221 * @name DataTable.defaults.serverSide 21222 * 21223 * @example 21224 * $(document).ready( function () { 21225 * $('#example').dataTable( { 21226 * "serverSide": true, 21227 * "ajax": "xhr.php" 21228 * } ); 21229 * } ); 21230 */ 21231 "bServerSide": false, 21232 21233 21234 /** 21235 * Enable or disable sorting of columns. Sorting of individual columns can be 21236 * disabled by the `sortable` option for each column. 21237 * @type boolean 21238 * @default true 21239 * 21240 * @dtopt Features 21241 * @name DataTable.defaults.ordering 21242 * 21243 * @example 21244 * $(document).ready( function () { 21245 * $('#example').dataTable( { 21246 * "ordering": false 21247 * } ); 21248 * } ); 21249 */ 21250 "bSort": true, 21251 21252 21253 /** 21254 * Enable or display DataTables' ability to sort multiple columns at the 21255 * same time (activated by shift-click by the user). 21256 * @type boolean 21257 * @default true 21258 * 21259 * @dtopt Options 21260 * @name DataTable.defaults.orderMulti 21261 * 21262 * @example 21263 * // Disable multiple column sorting ability 21264 * $(document).ready( function () { 21265 * $('#example').dataTable( { 21266 * "orderMulti": false 21267 * } ); 21268 * } ); 21269 */ 21270 "bSortMulti": true, 21271 21272 21273 /** 21274 * Allows control over whether DataTables should use the top (true) unique 21275 * cell that is found for a single column, or the bottom (false - default). 21276 * This is useful when using complex headers. 21277 * @type boolean 21278 * @default false 21279 * 21280 * @dtopt Options 21281 * @name DataTable.defaults.orderCellsTop 21282 * 21283 * @example 21284 * $(document).ready( function() { 21285 * $('#example').dataTable( { 21286 * "orderCellsTop": true 21287 * } ); 21288 * } ); 21289 */ 21290 "bSortCellsTop": false, 21291 21292 21293 /** 21294 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and 21295 * `sorting\_3` to the columns which are currently being sorted on. This is 21296 * presented as a feature switch as it can increase processing time (while 21297 * classes are removed and added) so for large data sets you might want to 21298 * turn this off. 21299 * @type boolean 21300 * @default true 21301 * 21302 * @dtopt Features 21303 * @name DataTable.defaults.orderClasses 21304 * 21305 * @example 21306 * $(document).ready( function () { 21307 * $('#example').dataTable( { 21308 * "orderClasses": false 21309 * } ); 21310 * } ); 21311 */ 21312 "bSortClasses": true, 21313 21314 21315 /** 21316 * Enable or disable state saving. When enabled HTML5 `localStorage` will be 21317 * used to save table display information such as pagination information, 21318 * display length, filtering and sorting. As such when the end user reloads 21319 * the page the display display will match what thy had previously set up. 21320 * 21321 * Due to the use of `localStorage` the default state saving is not supported 21322 * in IE6 or 7. If state saving is required in those browsers, use 21323 * `stateSaveCallback` to provide a storage solution such as cookies. 21324 * @type boolean 21325 * @default false 21326 * 21327 * @dtopt Features 21328 * @name DataTable.defaults.stateSave 21329 * 21330 * @example 21331 * $(document).ready( function () { 21332 * $('#example').dataTable( { 21333 * "stateSave": true 21334 * } ); 21335 * } ); 21336 */ 21337 "bStateSave": false, 21338 21339 21340 /** 21341 * This function is called when a TR element is created (and all TD child 21342 * elements have been inserted), or registered if using a DOM source, allowing 21343 * manipulation of the TR element (adding classes etc). 21344 * @type function 21345 * @param {node} row "TR" element for the current row 21346 * @param {array} data Raw data array for this row 21347 * @param {int} dataIndex The index of this row in the internal aoData array 21348 * 21349 * @dtopt Callbacks 21350 * @name DataTable.defaults.createdRow 21351 * 21352 * @example 21353 * $(document).ready( function() { 21354 * $('#example').dataTable( { 21355 * "createdRow": function( row, data, dataIndex ) { 21356 * // Bold the grade for all 'A' grade browsers 21357 * if ( data[4] == "A" ) 21358 * { 21359 * $('td:eq(4)', row).html( '<b>A</b>' ); 21360 * } 21361 * } 21362 * } ); 21363 * } ); 21364 */ 21365 "fnCreatedRow": null, 21366 21367 21368 /** 21369 * This function is called on every 'draw' event, and allows you to 21370 * dynamically modify any aspect you want about the created DOM. 21371 * @type function 21372 * @param {object} settings DataTables settings object 21373 * 21374 * @dtopt Callbacks 21375 * @name DataTable.defaults.drawCallback 21376 * 21377 * @example 21378 * $(document).ready( function() { 21379 * $('#example').dataTable( { 21380 * "drawCallback": function( settings ) { 21381 * alert( 'DataTables has redrawn the table' ); 21382 * } 21383 * } ); 21384 * } ); 21385 */ 21386 "fnDrawCallback": null, 21387 21388 21389 /** 21390 * Identical to fnHeaderCallback() but for the table footer this function 21391 * allows you to modify the table footer on every 'draw' event. 21392 * @type function 21393 * @param {node} foot "TR" element for the footer 21394 * @param {array} data Full table data (as derived from the original HTML) 21395 * @param {int} start Index for the current display starting point in the 21396 * display array 21397 * @param {int} end Index for the current display ending point in the 21398 * display array 21399 * @param {array int} display Index array to translate the visual position 21400 * to the full data array 21401 * 21402 * @dtopt Callbacks 21403 * @name DataTable.defaults.footerCallback 21404 * 21405 * @example 21406 * $(document).ready( function() { 21407 * $('#example').dataTable( { 21408 * "footerCallback": function( tfoot, data, start, end, display ) { 21409 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start; 21410 * } 21411 * } ); 21412 * } ) 21413 */ 21414 "fnFooterCallback": null, 21415 21416 21417 /** 21418 * When rendering large numbers in the information element for the table 21419 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers 21420 * to have a comma separator for the 'thousands' units (e.g. 1 million is 21421 * rendered as "1,000,000") to help readability for the end user. This 21422 * function will override the default method DataTables uses. 21423 * @type function 21424 * @member 21425 * @param {int} toFormat number to be formatted 21426 * @returns {string} formatted string for DataTables to show the number 21427 * 21428 * @dtopt Callbacks 21429 * @name DataTable.defaults.formatNumber 21430 * 21431 * @example 21432 * // Format a number using a single quote for the separator (note that
21433 * // this can also be done with the language.thousands option) 21434 * $(document).ready( function() { 21435 * $('#example').dataTable( { 21436 * "formatNumber": function ( toFormat ) { 21437 * return toFormat.toString().replace( 21438 * /\B(?=(\d{3})+(?!\d))/g, "'" 21439 * ); 21440 * }; 21441 * } ); 21442 * } ); 21443 */ 21444 "fnFormatNumber": function ( toFormat ) { 21445 return toFormat.toString().replace( 21446 /\B(?=(\d{3})+(?!\d))/g, 21447 this.oLanguage.sThousands 21448 ); 21449 }, 21450 21451 21452 /** 21453 * This function is called on every 'draw' event, and allows you to 21454 * dynamically modify the header row. This can be used to calculate and 21455 * display useful information about the table. 21456 * @type function 21457 * @param {node} head "TR" element for the header 21458 * @param {array} data Full table data (as derived from the original HTML) 21459 * @param {int} start Index for the current display starting point in the 21460 * display array 21461 * @param {int} end Index for the current display ending point in the 21462 * display array 21463 * @param {array int} display Index array to translate the visual position 21464 * to the full data array 21465 * 21466 * @dtopt Callbacks 21467 * @name DataTable.defaults.headerCallback 21468 * 21469 * @example 21470 * $(document).ready( function() { 21471 * $('#example').dataTable( { 21472 * "fheaderCallback": function( head, data, start, end, display ) { 21473 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records"; 21474 * } 21475 * } ); 21476 * } ) 21477 */ 21478 "fnHeaderCallback": null, 21479 21480 21481 /** 21482 * The information element can be used to convey information about the current 21483 * state of the table. Although the internationalisation options presented by 21484 * DataTables are quite capable of dealing with most customisations, there may 21485 * be times where you wish to customise the string further. This callback 21486 * allows you to do exactly that. 21487 * @type function 21488 * @param {object} oSettings DataTables settings object 21489 * @param {int} start Starting position in data for the draw 21490 * @param {int} end End position in data for the draw 21491 * @param {int} max Total number of rows in the table (regardless of 21492 * filtering) 21493 * @param {int} total Total number of rows in the data set, after filtering 21494 * @param {string} pre The string that DataTables has formatted using it's 21495 * own rules 21496 * @returns {string} The string to be displayed in the information element. 21497 * 21498 * @dtopt Callbacks 21499 * @name DataTable.defaults.infoCallback 21500 * 21501 * @example 21502 * $('#example').dataTable( { 21503 * "infoCallback": function( settings, start, end, max, total, pre ) { 21504 * return start +" to "+ end; 21505 * } 21506 * } ); 21507 */ 21508 "fnInfoCallback": null, 21509 21510 21511 /** 21512 * Called when the table has been initialised. Normally DataTables will 21513 * initialise sequentially and there will be no need for this function, 21514 * however, this does not hold true when using external language information 21515 * since that is obtained using an async XHR call. 21516 * @type function 21517 * @param {object} settings DataTables settings object 21518 * @param {object} json The JSON object request from the server - only 21519 * present if client-side Ajax sourced data is used 21520 * 21521 * @dtopt Callbacks 21522 * @name DataTable.defaults.initComplete 21523 * 21524 * @example 21525 * $(document).ready( function() { 21526 * $('#example').dataTable( { 21527 * "initComplete": function(settings, json) { 21528 * alert( 'DataTables has finished its initialisation.' ); 21529 * } 21530 * } ); 21531 * } ) 21532 */ 21533 "fnInitComplete": null, 21534 21535 21536 /** 21537 * Called at the very start of each table draw and can be used to cancel the 21538 * draw by returning false, any other return (including undefined) results in 21539 * the full draw occurring). 21540 * @type function 21541 * @param {object} settings DataTables settings object 21542 * @returns {boolean} False will cancel the draw, anything else (including no 21543 * return) will allow it to complete. 21544 * 21545 * @dtopt Callbacks 21546 * @name DataTable.defaults.preDrawCallback 21547 * 21548 * @example 21549 * $(document).ready( function() { 21550 * $('#example').dataTable( { 21551 * "preDrawCallback": function( settings ) { 21552 * if ( $('#test').val() == 1 ) { 21553 * return false;
21554 * } 21555 * } 21556 * } ); 21557 * } ); 21558 */ 21559 "fnPreDrawCallback": null, 21560 21561 21562 /** 21563 * This function allows you to 'post process' each row after it have been 21564 * generated for each table draw, but before it is rendered on screen. This 21565 * function might be used for setting the row class name etc. 21566 * @type function 21567 * @param {node} row "TR" element for the current row 21568 * @param {array} data Raw data array for this row 21569 * @param {int} displayIndex The display index for the current table draw 21570 * @param {int} displayIndexFull The index of the data in the full list of 21571 * rows (after filtering) 21572 * 21573 * @dtopt Callbacks 21574 * @name DataTable.defaults.rowCallback 21575 * 21576 * @example 21577 * $(document).ready( function() { 21578 * $('#example').dataTable( { 21579 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) { 21580 * // Bold the grade for all 'A' grade browsers 21581 * if ( data[4] == "A" ) { 21582 * $('td:eq(4)', row).html( '<b>A</b>' ); 21583 * } 21584 * } 21585 * } ); 21586 * } ); 21587 */ 21588 "fnRowCallback": null, 21589 21590 21591 /** 21592 * __Deprecated__ The functionality provided by this parameter has now been 21593 * superseded by that provided through `ajax`, which should be used instead. 21594 * 21595 * This parameter allows you to override the default function which obtains 21596 * the data from the server so something more suitable for your application. 21597 * For example you could use POST data, or pull information from a Gears or 21598 * AIR database. 21599 * @type function 21600 * @member 21601 * @param {string} source HTTP source to obtain the data from (`ajax`) 21602 * @param {array} data A key/value pair object containing the data to send 21603 * to the server 21604 * @param {function} callback to be called on completion of the data get 21605 * process that will draw the data on the page. 21606 * @param {object} settings DataTables settings object 21607 * 21608 * @dtopt Callbacks 21609 * @dtopt Server-side 21610 * @name DataTable.defaults.serverData 21611 * 21612 * @deprecated 1.10. Please use `ajax` for this functionality now. 21613 */ 21614 "fnServerData": null, 21615 21616 21617 /** 21618 * __Deprecated__ The functionality provided by this parameter has now been 21619 * superseded by that provided through `ajax`, which should be used instead. 21620 * 21621 * It is often useful to send extra data to the server when making an Ajax 21622 * request - for example custom filtering information, and this callback 21623 * function makes it trivial to send extra information to the server. The 21624 * passed in parameter is the data set that has been constructed by 21625 * DataTables, and you can add to this or modify it as you require. 21626 * @type function 21627 * @param {array} data Data array (array of objects which are name/value 21628 * pairs) that has been constructed by DataTables and will be sent to the 21629 * server. In the case of Ajax sourced data with server-side processing 21630 * this will be an empty array, for server-side processing there will be a 21631 * significant number of parameters! 21632 * @returns {undefined} Ensure that you modify the data array passed in, 21633 * as this is passed by reference. 21634 * 21635 * @dtopt Callbacks 21636 * @dtopt Server-side 21637 * @name DataTable.defaults.serverParams 21638 * 21639 * @deprecated 1.10. Please use `ajax` for this functionality now. 21640 */ 21641 "fnServerParams": null, 21642 21643 21644 /** 21645 * Load the table state. With this function you can define from where, and how, the 21646 * state of a table is loaded. By default DataTables will load from `localStorage` 21647 * but you might wish to use a server-side database or cookies. 21648 * @type function 21649 * @member 21650 * @param {object} settings DataTables settings object 21651 * @return {object} The DataTables state object to be loaded 21652 * 21653 * @dtopt Callbacks 21654 * @name DataTable.defaults.stateLoadCallback 21655 * 21656 * @example 21657 * $(document).ready( function() { 21658 * $('#example').dataTable( { 21659 * "stateSave": true, 21660 * "stateLoadCallback": function (settings) { 21661 * var o; 21662 * 21663 * // Send an Ajax request to the server to get the data. Note that 21664 * // this is a synchronous request. 21665 * $.ajax( { 21666 * "url": "/state_load", 21667 * "async": false, 21668 * "dataType": "json", 21669 * "success": function (json) { 21670 * o = json; 21671 * } 21672 * } ); 21673 * 21674 * return o; 21675 * } 21676 * } ); 21677 * } ); 21678 */ 21679 "fnStateLoadCallback": function ( settings ) { 21680 try { 21681 return JSON.parse(
21682 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem( 21683 'DataTables_'+settings.sInstance+'_'+location.pathname 21684 ) 21685 ); 21686 } catch (e) {} 21687 }, 21688 21689 21690 /** 21691 * Callback which allows modification of the saved state prior to loading that state. 21692 * This callback is called when the table is loading state from the stored data, but 21693 * prior to the settings object being modified by the saved state. Note that for 21694 * plug-in authors, you should use the `stateLoadParams` event to load parameters for 21695 * a plug-in. 21696 * @type function 21697 * @param {object} settings DataTables settings object 21698 * @param {object} data The state object that is to be loaded 21699 * 21700 * @dtopt Callbacks 21701 * @name DataTable.defaults.stateLoadParams 21702 * 21703 * @example 21704 * // Remove a saved filter, so filtering is never loaded 21705 * $(document).ready( function() { 21706 * $('#example').dataTable( { 21707 * "stateSave": true, 21708 * "stateLoadParams": function (settings, data) { 21709 * data.oSearch.sSearch = ""; 21710 * } 21711 * } ); 21712 * } ); 21713 * 21714 * @example 21715 * // Disallow state loading by returning false 21716 * $(document).ready( function() { 21717 * $('#example').dataTable( { 21718 * "stateSave": true, 21719 * "stateLoadParams": function (settings, data) { 21720 * return false; 21721 * } 21722 * } ); 21723 * } ); 21724 */ 21725 "fnStateLoadParams": null, 21726 21727 21728 /** 21729 * Callback that is called when the state has been loaded from the state saving method 21730 * and the DataTables settings object has been modified as a result of the loaded state. 21731 * @type function 21732 * @param {object} settings DataTables settings object 21733 * @param {object} data The state object that was loaded 21734 * 21735 * @dtopt Callbacks 21736 * @name DataTable.defaults.stateLoaded 21737 * 21738 * @example 21739 * // Show an alert with the filtering value that was saved 21740 * $(document).ready( function() { 21741 * $('#example').dataTable( { 21742 * "stateSave": true, 21743 * "stateLoaded": function (settings, data) { 21744 * alert( 'Saved filter was: '+data.oSearch.sSearch ); 21745 * } 21746 * } ); 21747 * } ); 21748 */ 21749 "fnStateLoaded": null, 21750 21751 21752 /** 21753 * Save the table state. This function allows you to define where and how the state 21754 * information for the table is stored By default DataTables will use `localStorage` 21755 * but you might wish to use a server-side database or cookies. 21756 * @type function 21757 * @member 21758 * @param {object} settings DataTables settings object 21759 * @param {object} data The state object to be saved 21760 * 21761 * @dtopt Callbacks 21762 * @name DataTable.defaults.stateSaveCallback 21763 * 21764 * @example 21765 * $(document).ready( function() { 21766 * $('#example').dataTable( { 21767 * "stateSave": true, 21768 * "stateSaveCallback": function (settings, data) { 21769 * // Send an Ajax request to the server with the state object 21770 * $.ajax( { 21771 * "url": "/state_save", 21772 * "data": data, 21773 * "dataType": "json", 21774 * "method": "POST" 21775 * "success": function () {} 21776 * } ); 21777 * } 21778 * } ); 21779 * } ); 21780 */ 21781 "fnStateSaveCallback": function ( settings, data ) { 21782 try { 21783 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem( 21784 'DataTables_'+settings.sInstance+'_'+location.pathname, 21785 JSON.stringify( data ) 21786 ); 21787 } catch (e) {} 21788 }, 21789 21790 21791 /** 21792 * Callback which allows modification of the state to be saved. Called when the table 21793 * has changed state a new state save is required. This method allows modification of 21794 * the state saving object prior to actually doing the save, including addition or 21795 * other state properties or modification. Note that for plug-in authors, you should 21796 * use the `stateSaveParams` event to save parameters for a plug-in. 21797 * @type function 21798 * @param {object} settings DataTables settings object 21799 * @param {object} data The state object to be saved 21800 * 21801 * @dtopt Callbacks 21802 * @name DataTable.defaults.stateSaveParams 21803 * 21804 * @example 21805 * // Remove a saved filter, so filtering is never saved 21806 * $(document).ready( function() { 21807 * $('#example').dataTable( { 21808 * "stateSave": true, 21809 * "stateSaveParams": function (settings, data) { 21810 * data.oSearch.sSearch = ""; 21811 * } 21812 * } ); 21813 * } ); 21814 */ 21815 "fnStateSaveParams": null, 21816 21817 21818 /** 21819 * Duration for which the saved state information is considered valid. After this period 21820 * has elapsed the state will be returned to the default. 21821 * Value is given in seconds. 21822 * @type int 21823 * @default 7200 <i>(2 hours)</i> 21824 * 21825 * @dtopt Options 21826 * @name DataTable.defaults.stateDuration 21827 * 21828 * @example 21829 * $(document).ready( function() { 21830 * $('#example').dataTable( { 21831 * "stateDuration": 60*60*24; // 1 day 21832 * } ); 21833 * } ) 21834 */ 21835 "iStateDuration": 7200, 21836 21837 21838 /** 21839 * When enabled DataTables will not make a request to the server for the first 21840 * page draw - rather it will use the data already on the page (no sorting etc 21841 * will be applied to it), thus saving on an XHR at load time. `deferLoading` 21842 * is used to indicate that deferred loading is required, but it is also used
21843 * to tell DataTables how many records there are in the full table (allowing 21844 * the information element and pagination to be displayed correctly). In the case 21845 * where a filtering is applied to the table on initial load, this can be 21846 * indicated by giving the parameter as an array, where the first element is 21847 * the number of records available after filtering and the second element is the 21848 * number of records without filtering (allowing the table information element 21849 * to be shown correctly). 21850 * @type int | array 21851 * @default null 21852 * 21853 * @dtopt Options 21854 * @name DataTable.defaults.deferLoading 21855 * 21856 * @example 21857 * // 57 records available in the table, no filtering applied 21858 * $(document).ready( function() { 21859 * $('#example').dataTable( { 21860 * "serverSide": true, 21861 * "ajax": "scripts/server_processing.php", 21862 * "deferLoading": 57 21863 * } ); 21864 * } ); 21865 * 21866 * @example 21867 * // 57 records after filtering, 100 without filtering (an initial filter applied) 21868 * $(document).ready( function() { 21869 * $('#example').dataTable( { 21870 * "serverSide": true, 21871 * "ajax": "scripts/server_processing.php", 21872 * "deferLoading": [ 57, 100 ], 21873 * "search": { 21874 * "search": "my_filter" 21875 * } 21876 * } ); 21877 * } ); 21878 */ 21879 "iDeferLoading": null, 21880 21881 21882 /** 21883 * Number of rows to display on a single page when using pagination. If 21884 * feature enabled (`lengthChange`) then the end user will be able to override 21885 * this to a custom setting using a pop-up menu. 21886 * @type int 21887 * @default 10 21888 * 21889 * @dtopt Options 21890 * @name DataTable.defaults.pageLength 21891 * 21892 * @example 21893 * $(document).ready( function() { 21894 * $('#example').dataTable( { 21895 * "pageLength": 50 21896 * } ); 21897 * } ) 21898 */ 21899 "iDisplayLength": 10, 21900 21901 21902 /** 21903 * Define the starting point for data display when using DataTables with 21904 * pagination. Note that this parameter is the number of records, rather than 21905 * the page number, so if you have 10 records per page and want to start on 21906 * the third page, it should be "20". 21907 * @type int 21908 * @default 0 21909 * 21910 * @dtopt Options 21911 * @name DataTable.defaults.displayStart 21912 * 21913 * @example 21914 * $(document).ready( function() { 21915 * $('#example').dataTable( { 21916 * "displayStart": 20 21917 * } ); 21918 * } ) 21919 */ 21920 "iDisplayStart": 0, 21921 21922 21923 /** 21924 * By default DataTables allows keyboard navigation of the table (sorting, paging, 21925 * and filtering) by adding a `tabindex` attribute to the required elements. This 21926 * allows you to tab through the controls and press the enter key to activate them. 21927 * The tabindex is default 0, meaning that the tab follows the flow of the document. 21928 * You can overrule this using this parameter if you wish. Use a value of -1 to 21929 * disable built-in keyboard navigation. 21930 * @type int 21931 * @default 0 21932 * 21933 * @dtopt Options 21934 * @name DataTable.defaults.tabIndex 21935 * 21936 * @example 21937 * $(document).ready( function() { 21938 * $('#example').dataTable( { 21939 * "tabIndex": 1 21940 * } ); 21941 * } ); 21942 */ 21943 "iTabIndex": 0, 21944 21945 21946 /** 21947 * Classes that DataTables assigns to the various components and features 21948 * that it adds to the HTML table. This allows classes to be configured 21949 * during initialisation in addition to through the static 21950 * {@link DataTable.ext.oStdClasses} object). 21951 * @namespace 21952 * @name DataTable.defaults.classes 21953 */ 21954 "oClasses": {}, 21955 21956 21957 /** 21958 * All strings that DataTables uses in the user interface that it creates 21959 * are defined in this object, allowing you to modified them individually or 21960 * completely replace them all as required. 21961 * @namespace 21962 * @name DataTable.defaults.language 21963 */ 21964 "oLanguage": { 21965 /** 21966 * Strings that are used for WAI-ARIA labels and controls only (these are not 21967 * actually visible on the page, but will be read by screenreaders, and thus 21968 * must be internationalised as well). 21969 * @namespace 21970 * @name DataTable.defaults.language.aria 21971 */ 21972 "oAria": { 21973 /** 21974 * ARIA label that is added to the table headers when the column may be 21975 * sorted ascending by activing the column (click or return when focu
21975sed). 21976 * Note that the column header is prefixed to this string. 21977 * @type string 21978 * @default : activate to sort column ascending 21979 * 21980 * @dtopt Language 21981 * @name DataTable.defaults.language.aria.sortAscending 21982 * 21983 * @example 21984 * $(document).ready( function() { 21985 * $('#example').dataTable( { 21986 * "language": { 21987 * "aria": { 21988 * "sortAscending": " - click/return to sort ascending" 21989 * } 21990 * } 21991 * } ); 21992 * } ); 21993 */ 21994 "sSortAscending": ": activate to sort column ascending", 21995 21996 /** 21997 * ARIA label that is added to the table headers when the column may be 21998 * sorted descending by activing the column (click or return when focused). 21999 * Note that the column header is prefixed to this string. 22000 * @type string 22001 * @default : activate to sort column ascending 22002 * 22003 * @dtopt Language 22004 * @name DataTable.defaults.language.aria.sortDescending 22005 * 22006 * @example 22007 * $(document).ready( function() { 22008 * $('#example').dataTable( { 22009 * "language": { 22010 * "aria": { 22011 * "sortDescending": " - click/return to sort descending" 22012 * } 22013 * } 22014 * } ); 22015 * } ); 22016 */ 22017 "sSortDescending": ": activate to sort column descending" 22018 }, 22019 22020 /** 22021 * Pagination string used by DataTables for the built-in pagination 22022 * control types. 22023 * @namespace 22024 * @name DataTable.defaults.language.paginate 22025 */ 22026 "oPaginate": { 22027 /** 22028 * Text to use when using the 'full_numbers' type of pagination for the 22029 * button to take the user to the first page. 22030 * @type string 22031 * @default First 22032 * 22033 * @dtopt Language 22034 * @name DataTable.defaults.language.paginate.first 22035 * 22036 * @example 22037 * $(document).ready( function() { 22038 * $('#example').dataTable( { 22039 * "language": { 22040 * "paginate": { 22041 * "first": "First page" 22042 * } 22043 * } 22044 * } ); 22045 * } ); 22046 */ 22047 "sFirst": "First", 22048 22049 22050 /** 22051 * Text to use when using the 'full_numbers' type of pagination for the 22052 * button to take the user to the last page. 22053 * @type string 22054 * @default Last 22055 * 22056 * @dtopt Language 22057 * @name DataTable.defaults.language.paginate.last 22058 * 22059 * @example 22060 * $(document).ready( function() { 22061 * $('#example').dataTable( { 22062 * "language": { 22063 * "paginate": { 22064 * "last": "Last page" 22065 * } 22066 * } 22067 * } ); 22068 * } ); 22069 */ 22070 "sLast": "Last", 22071 22072 22073 /** 22074 * Text to use for the 'next' pagination button (to take the user to the 22075 * next page). 22076 * @type string 22077 * @default Next 22078 * 22079 * @dtopt Language 22080 * @name DataTable.defaults.language.paginate.next 22081 * 22082 * @example 22083 * $(document).ready( function() { 22084 * $('#example').dataTable( { 22085 * "language": { 22086 * "paginate": { 22087 * "next": "Next page" 22088 * } 22089 * } 22090 * } ); 22091 * } ); 22092 */ 22093 "sNext": "Next", 22094 22095 22096 /** 22097 * Text to use for the 'previous' pagination button (to take the user to 22098 * the previous page). 22099 * @type string 22100 * @default Previous 22101 * 22102 * @dtopt Language 22103 * @name DataTable.defaults.language.paginate.previous 22104 * 22105 * @example 22106 * $(document).ready( function() { 22107 * $('#example').dataTable( { 22108 * "language": { 22109 * "paginate": { 22110 * "previous": "Previous page" 22111 * } 22112 * } 22113 * } ); 22114 * } ); 22115 */ 22116 "sPrevious": "Previous" 22117 }, 22118 22119 /** 22120 * This string is shown in preference to `zeroRecords` when the table is 22121 * empty of data (regardless of filtering). Note that this is an optional 22122 * parameter - if it is not given, the value of `zeroRecords` will be used 22123 * instead (either the default or given value). 22124 * @type string 22125 * @default No data available in table 22126 * 22127 * @dtopt Language 22128 * @name DataTable.defaults.language.emptyTable 22129 * 22130 * @example 22131 * $(document).ready( function() { 22132 * $('#example').dataTable( { 22133 * "language": { 22134 * "emptyTable": "No data available in table" 22135 * } 22136 * } ); 22137 * } ); 22138 */ 22139 "sEmptyTable": "No data available in table", 22140 22141 22142 /** 22143 * This string gives information to the end user about the information 22144 * that is current on display on the page. The following tokens can be 22145 * used in the string and will be dynamically replaced as the table 22146 * display updates. This tokens can be placed anywhere in the string, or 22147 * removed as needed by the language requires: 22148 * 22149 * * `\_START\_` - Display index of the first record on the current page 22150 * * `\_END\_` - Display index of the last record on the current page 22151 * * `\_TOTAL\_` - Number of records in the table after filtering 22152 * * `\_MAX\_` - Number of records in the table without filtering 22153 * * `\_PAGE\_` - Current page number 22154 * * `\_PAGES\_` - Total number of pages of data in the table 22155 * 22156 * @type string 22157 * @default Showing _START_ to _END_ of _TOTAL_ entries 22158 * 22159 * @dtopt Language 22160 * @name DataTable.defaults.language.info 22161 * 22162 * @example 22163 * $(document).ready( function() { 22164 * $('#example').dataTable( { 22165 * "language": { 22166 * "info": "Showing page _PAGE_ of _PAGES_" 22167 * } 22168 * } ); 22169 * } ); 22170 */ 22171 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries", 22172 22173 22174 /**
22175 * Display information string for when the table is empty. Typically the 22176 * format of this string should match `info`. 22177 * @type string 22178 * @default Showing 0 to 0 of 0 entries 22179 * 22180 * @dtopt Language 22181 * @name DataTable.defaults.language.infoEmpty 22182 * 22183 * @example 22184 * $(document).ready( function() { 22185 * $('#example').dataTable( { 22186 * "language": { 22187 * "infoEmpty": "No entries to show" 22188 * } 22189 * } ); 22190 * } ); 22191 */ 22192 "sInfoEmpty": "Showing 0 to 0 of 0 entries", 22193 22194 22195 /** 22196 * When a user filters the information in a table, this string is appended 22197 * to the information (`info`) to give an idea of how strong the filtering 22198 * is. The variable _MAX_ is dynamically updated. 22199 * @type string 22200 * @default (filtered from _MAX_ total entries) 22201 * 22202 * @dtopt Language 22203 * @name DataTable.defaults.language.infoFiltered 22204 * 22205 * @example 22206 * $(document).ready( function() { 22207 * $('#example').dataTable( { 22208 * "language": { 22209 * "infoFiltered": " - filtering from _MAX_ records" 22210 * } 22211 * } ); 22212 * } ); 22213 */ 22214 "sInfoFiltered": "(filtered from _MAX_ total entries)", 22215 22216 22217 /** 22218 * If can be useful to append extra information to the info string at times, 22219 * and this variable does exactly that. This information will be appended to 22220 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are 22221 * being used) at all times. 22222 * @type string 22223 * @default <i>Empty string</i> 22224 * 22225 * @dtopt Language 22226 * @name DataTable.defaults.language.infoPostFix 22227 * 22228 * @example 22229 * $(document).ready( function() { 22230 * $('#example').dataTable( { 22231 * "language": { 22232 * "infoPostFix": "All records shown are derived from real information." 22233 * } 22234 * } ); 22235 * } ); 22236 */ 22237 "sInfoPostFix": "", 22238 22239 22240 /** 22241 * This decimal place operator is a little different from the other 22242 * language options since DataTables doesn't output floating point 22243 * numbers, so it won't ever use this for display of a number. Rather, 22244 * what this parameter does is modify the sort methods of the table so 22245 * that numbers which are in a format which has a character other than 22246 * a period (`.`) as a decimal place will be sorted numerically. 22247 * 22248 * Note that numbers with different decimal places cannot be shown in 22249 * the same table and still be sortable, the table must be consistent. 22250 * However, multiple different tables on the page can use different 22251 * decimal place characters. 22252 * @type string 22253 * @default 22254 * 22255 * @dtopt Language 22256 * @name DataTable.defaults.language.decimal 22257 * 22258 * @example 22259 * $(document).ready( function() { 22260 * $('#example').dataTable( { 22261 * "language": { 22262 * "decimal": "," 22263 * "thousands": "." 22264 * } 22265 * } ); 22266 * } ); 22267 */ 22268 "sDecimal": "", 22269 22270 22271 /** 22272 * DataTables has a build in number formatter (`formatNumber`) which is 22273 * used to format large numbers that are used in the table information. 22274 * By default a comma is used, but this can be trivially changed to any 22275 * character you wish with this parameter. 22276 * @type string 22277 * @default , 22278 * 22279 * @dtopt Language 22280 * @name DataTable.defaults.language.thousands 22281 * 22282 * @example 22283 * $(document).ready( function() { 22284 * $('#example').dataTable( { 22285 * "language": { 22286 * "thousands": "'" 22287 * } 22288 * } ); 22289 * } ); 22290 */ 22291 "sThousands": ",", 22292 22293 22294 /** 22295 * Detail the action that will be taken when the drop down menu for the 22296 * pagination length option is changed. The '_MENU_' variable is replaced 22297 * with a default select list of 10, 25, 50 and 100, and can be replaced 22298 * with a custom select box if required. 22299 * @type string 22300 * @default Show _MENU_ entries 22301 * 22302 * @dtopt Language 22303 * @name DataTable.defaults.language.lengthMenu 22304 * 22305 * @example 22306 * // Language change only 22307 * $(document).ready( function() { 22308 * $('#example').dataTable( { 22309 * "language": {
22310 * "lengthMenu": "Display _MENU_ records" 22311 * } 22312 * } ); 22313 * } ); 22314 * 22315 * @example 22316 * // Language and options change 22317 * $(document).ready( function() { 22318 * $('#example').dataTable( { 22319 * "language": { 22320 * "lengthMenu": 'Display <select>'+ 22321 * '<option value="10">10</option>'+ 22322 * '<option value="20">20</option>'+ 22323 * '<option value="30">30</option>'+ 22324 * '<option value="40">40</option>'+ 22325 * '<option value="50">50</option>'+ 22326 * '<option value="-1">All</option>'+ 22327 * '</select> records' 22328 * } 22329 * } ); 22330 * } ); 22331 */ 22332 "sLengthMenu": "Show _MENU_ entries", 22333 22334 22335 /** 22336 * When using Ajax sourced data and during the first draw when DataTables is 22337 * gathering the data, this message is shown in an empty row in the table to 22338 * indicate to the end user the the data is being loaded. Note that this 22339 * parameter is not used when loading data by server-side processing, just 22340 * Ajax sourced data with client-side processing. 22341 * @type string 22342 * @default Loading... 22343 * 22344 * @dtopt Language 22345 * @name DataTable.defaults.language.loadingRecords 22346 * 22347 * @example 22348 * $(document).ready( function() { 22349 * $('#example').dataTable( { 22350 * "language": { 22351 * "loadingRecords": "Please wait - loading..." 22352 * } 22353 * } ); 22354 * } ); 22355 */ 22356 "sLoadingRecords": "Loading...", 22357 22358 22359 /** 22360 * Text which is displayed when the table is processing a user action 22361 * (usually a sort command or similar). 22362 * @type string 22363 * @default Processing... 22364 * 22365 * @dtopt Language 22366 * @name DataTable.defaults.language.processing 22367 * 22368 * @example 22369 * $(document).ready( function() { 22370 * $('#example').dataTable( { 22371 * "language": { 22372 * "processing": "DataTables is currently busy" 22373 * } 22374 * } ); 22375 * } ); 22376 */ 22377 "sProcessing": "Processing...", 22378 22379 22380 /** 22381 * Details the actions that will be taken when the user types into the 22382 * filtering input text box. The variable "_INPUT_", if used in the string, 22383 * is replaced with the HTML text box for the filtering input allowing 22384 * control over where it appears in the string. If "_INPUT_" is not given 22385 * then the input box is appended to the string automatically. 22386 * @type string 22387 * @default Search: 22388 * 22389 * @dtopt Language 22390 * @name DataTable.defaults.language.search 22391 * 22392 * @example 22393 * // Input text box will be appended at the end automatically 22394 * $(document).ready( function() { 22395 * $('#example').dataTable( { 22396 * "language": { 22397 * "search": "Filter records:" 22398 * } 22399 * } ); 22400 * } ); 22401 * 22402 * @example 22403 * // Specify where the filter should appear 22404 * $(document).ready( function() { 22405 * $('#example').dataTable( { 22406 * "language": { 22407 * "search": "Apply filter _INPUT_ to table" 22408 * } 22409 * } ); 22410 * } ); 22411 */ 22412 "sSearch": "Search:", 22413 22414 22415 /** 22416 * Assign a `placeholder` attribute to the search `input` element 22417 * @type string 22418 * @default 22419 * 22420 * @dtopt Language 22421 * @name DataTable.defaults.language.searchPlaceholder 22422 */ 22423 "sSearchPlaceholder": "", 22424 22425 22426 /** 22427 * All of the language information can be stored in a file on the 22428 * server-side, which DataTables will look up if this parameter is passed. 22429 * It must store the URL of the language file, which is in a JSON format, 22430 * and the object has the same properties as the oLanguage object in the 22431 * initialiser object (i.e. the above parameters). Please refer to one of 22432 * the example language files to see how this works in action. 22433 * @type string 22434 * @default <i>Empty string - i.e. disabled</i> 22435 * 22436 * @dtopt Language 22437 * @name DataTable.defaults.language.url 22438 * 22439 * @example 22440 * $(document).ready( function() { 22441 * $('#example').dataTable( { 22442 * "language": { 22443 * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt" 22444 * } 22445 * } ); 22446 * } ); 22447 */ 22448 "sUrl": "", 22449 22450 22451 /** 22452 * Text shown inside the table records when the is no information to be 22453 * displayed after filtering. `emptyTable` is shown when there is simply no 22454 * information in the table at all (regardless of filtering). 22455 * @type string
22456 * @default No matching records found 22457 * 22458 * @dtopt Language 22459 * @name DataTable.defaults.language.zeroRecords 22460 * 22461 * @example 22462 * $(document).ready( function() { 22463 * $('#example').dataTable( { 22464 * "language": { 22465 * "zeroRecords": "No records to display" 22466 * } 22467 * } ); 22468 * } ); 22469 */ 22470 "sZeroRecords": "No matching records found" 22471 }, 22472 22473 22474 /** 22475 * This parameter allows you to have define the global filtering state at 22476 * initialisation time. As an object the `search` parameter must be 22477 * defined, but all other parameters are optional. When `regex` is true, 22478 * the search string will be treated as a regular expression, when false 22479 * (default) it will be treated as a straight string. When `smart` 22480 * DataTables will use it's smart filtering methods (to word match at 22481 * any point in the data), when false this will not be done. 22482 * @namespace 22483 * @extends DataTable.models.oSearch 22484 * 22485 * @dtopt Options 22486 * @name DataTable.defaults.search 22487 * 22488 * @example 22489 * $(document).ready( function() { 22490 * $('#example').dataTable( { 22491 * "search": {"search": "Initial search"} 22492 * } ); 22493 * } ) 22494 */ 22495 "oSearch": $.extend( {}, DataTable.models.oSearch ), 22496 22497 22498 /** 22499 * __Deprecated__ The functionality provided by this parameter has now been 22500 * superseded by that provided through `ajax`, which should be used instead. 22501 * 22502 * By default DataTables will look for the property `data` (or `aaData` for 22503 * compatibility with DataTables 1.9-) when obtaining data from an Ajax 22504 * source or for server-side processing - this parameter allows that 22505 * property to be changed. You can use Javascript dotted object notation to 22506 * get a data source for multiple levels of nesting. 22507 * @type string 22508 * @default data 22509 * 22510 * @dtopt Options 22511 * @dtopt Server-side 22512 * @name DataTable.defaults.ajaxDataProp 22513 * 22514 * @deprecated 1.10. Please use `ajax` for this functionality now. 22515 */ 22516 "sAjaxDataProp": "data", 22517 22518 22519 /** 22520 * __Deprecated__ The functionality provided by this parameter has now been 22521 * superseded by that provided through `ajax`, which should be used instead. 22522 * 22523 * You can instruct DataTables to load data from an external 22524 * source using this parameter (use aData if you want to pass data in you 22525 * already have). Simply provide a url a JSON object can be obtained from. 22526 * @type string 22527 * @default null 22528 * 22529 * @dtopt Options 22530 * @dtopt Server-side 22531 * @name DataTable.defaults.ajaxSource 22532 * 22533 * @deprecated 1.10. Please use `ajax` for this functionality now. 22534 */ 22535 "sAjaxSource": null, 22536 22537 22538 /** 22539 * This initialisation variable allows you to specify exactly where in the 22540 * DOM you want DataTables to inject the various controls it adds to the page 22541 * (for example you might want the pagination controls at the top of the 22542 * table). DIV elements (with or without a custom class) can also be added to 22543 * aid styling. The follow syntax is used: 22544 * <ul> 22545 * <li>The following options are allowed: 22546 * <ul> 22547 * <li>'l' - Length changing</li> 22548 * <li>'f' - Filtering input</li> 22549 * <li>'t' - The table!</li> 22550 * <li>'i' - Information</li> 22551 * <li>'p' - Pagination</li> 22552 * <li>'r' - pRocessing</li> 22553 * </ul> 22554 * </li> 22555 * <li>The following constants are allowed: 22556 * <ul> 22557 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li> 22558 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li> 22559 * </ul> 22560 * </li> 22561 * <li>The following syntax is expected: 22562 * <ul> 22563 * <li>'<' and '>' - div elements</li> 22564 * <li>'<"class" and '>' - div with a class</li> 22565 * <li>'<"#id" and '>' - div with an ID</li> 22566 * </ul> 22567 * </li> 22568 * <li>Examples: 22569 * <ul> 22570 * <li>'<"wrapper"flipt>'</li> 22571 * <li>'<lf<t>ip>'</li> 22572 * </ul> 22573 * </li> 22574 * </ul> 22575 * @type string 22576 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b> 22577 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i> 22578 * 22579 * @dtopt Options 22580 * @name DataTable.defaults.dom 22581 * 22582 * @example 22583 * $(document).ready( function() { 22584 * $('#example').dataTable( { 22585 * "dom": '<"top"i>rt<"bottom"flp><"clear">' 22586 * } ); 22587 * } ); 22588 */ 22589 "sDom": "lfrtip", 22590 22591 22592 /** 22593 * Search delay option. This will throttle full table searches that use the 22594 * DataTables provided search input element (it does not effect calls to 22595 * `dt-api search()`, providing a delay before the search is made. 22596 * @type integer 22597 * @default 0 22598 * 22599 * @dtopt Options 22600 * @name DataTable.defaults.searchDelay 22601 * 22602 * @example 22603 * $(document).ready( function() { 22604 * $('#example').dataTable( { 22605 * "searchDelay": 200 22606 * } ); 22607 * } ) 22608 */ 22609 "searchDelay": null, 22610 22611 22612 /** 22613 * DataTables features four different built-in options for the buttons to 22614 * display for pagination control: 22615 * 22616 * * `simple` - 'Previous' and 'Next' buttons only 22617 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers 22618 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons 22619 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus 22620 * page numbers 22621 * 22622 * Further methods can be added using {@link DataTable.ext.oPagination}. 22623 * @type string 22624 * @default simple_numbers 22625 * 22626 * @dtopt Options 22627 * @name DataTable.defaults.pagingType 22628 * 22629 * @example 22630 * $(document).ready( function() { 22631 * $('#example').dataTable( { 22632 * "pagingType": "full_numbers" 22633 * } ); 22634 * } ) 22635 */ 22636 "sPaginationType": "simple_numbers", 22637 22638 22639 /** 22640 * Enable horizontal scrolling. When a table is too wide to fit into a 22641 * certain layout, or you have a large number of columns in the table, you 22642 * can enable x-scrolling to show the table in a viewport, which can be 22643 * scrolled. This property can be `true` which will allow the table to 22644 * scroll horizontally when needed, or any CSS unit, or a number (in which 22645 * case it will be treated as a pixel measurement). Setting as simply `true` 22646 * is recommended.
22647 * @type boolean|string 22648 * @default <i>blank string - i.e. disabled</i> 22649 * 22650 * @dtopt Features 22651 * @name DataTable.defaults.scrollX 22652 * 22653 * @example 22654 * $(document).ready( function() { 22655 * $('#example').dataTable( { 22656 * "scrollX": true, 22657 * "scrollCollapse": true 22658 * } ); 22659 * } ); 22660 */ 22661 "sScrollX": "", 22662 22663 22664 /** 22665 * This property can be used to force a DataTable to use more width than it 22666 * might otherwise do when x-scrolling is enabled. For example if you have a 22667 * table which requires to be well spaced, this parameter is useful for 22668 * "over-sizing" the table, and thus forcing scrolling. This property can by 22669 * any CSS unit, or a number (in which case it will be treated as a pixel 22670 * measurement). 22671 * @type string 22672 * @default <i>blank string - i.e. disabled</i> 22673 * 22674 * @dtopt Options 22675 * @name DataTable.defaults.scrollXInner 22676 * 22677 * @example 22678 * $(document).ready( function() { 22679 * $('#example').dataTable( { 22680 * "scrollX": "100%", 22681 * "scrollXInner": "110%" 22682 * } ); 22683 * } ); 22684 */ 22685 "sScrollXInner": "", 22686 22687 22688 /** 22689 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable 22690 * to the given height, and enable scrolling for any data which overflows the 22691 * current viewport. This can be used as an alternative to paging to display 22692 * a lot of data in a small area (although paging and scrolling can both be 22693 * enabled at the same time). This property can be any CSS unit, or a number 22694 * (in which case it will be treated as a pixel measurement). 22695 * @type string 22696 * @default <i>blank string - i.e. disabled</i> 22697 * 22698 * @dtopt Features 22699 * @name DataTable.defaults.scrollY 22700 * 22701 * @example 22702 * $(document).ready( function() { 22703 * $('#example').dataTable( { 22704 * "scrollY": "200px", 22705 * "paginate": false 22706 * } ); 22707 * } ); 22708 */ 22709 "sScrollY": "", 22710 22711 22712 /** 22713 * __Deprecated__ The functionality provided by this parameter has now been 22714 * superseded by that provided through `ajax`, which should be used instead. 22715 * 22716 * Set the HTTP method that is used to make the Ajax call for server-side 22717 * processing or Ajax sourced data. 22718 * @type string 22719 * @default GET 22720 * 22721 * @dtopt Options 22722 * @dtopt Server-side 22723 * @name DataTable.defaults.serverMethod 22724 * 22725 * @deprecated 1.10. Please use `ajax` for this functionality now. 22726 */ 22727 "sServerMethod": "GET", 22728 22729 22730 /** 22731 * DataTables makes use of renderers when displaying HTML elements for 22732 * a table. These renderers can be added or modified by plug-ins to 22733 * generate suitable mark-up for a site. For example the Bootstrap 22734 * integration plug-in for DataTables uses a paging button renderer to 22735 * display pagination buttons in the mark-up required by Bootstrap. 22736 * 22737 * For further information about the renderers available see 22738 * DataTable.ext.renderer 22739 * @type string|object 22740 * @default null 22741 * 22742 * @name DataTable.defaults.renderer 22743 * 22744 */ 22745 "renderer": null, 22746 22747 22748 /** 22749 * Set the data property name that DataTables should use to get a row's id 22750 * to set as the `id` property in the node. 22751 * @type string 22752 * @default DT_RowId 22753 * 22754 * @name DataTable.defaults.rowId 22755 */ 22756 "rowId": "DT_RowId" 22757 }; 22758 22759 _fnHungarianMap( DataTable.defaults ); 22760 22761 22762 22763 /* 22764 * Developer note - See note in model.defaults.js about the use of Hungarian 22765 * notation and camel case. 22766 */ 22767 22768 /** 22769 * Column options that can be given to DataTables at initialisation time. 22770 * @namespace 22771 */ 22772 DataTable.defaults.column = { 22773 /** 22774 * Define which column(s) an order will occur on for this column. This 22775 * allows a column's ordering to take multiple columns into account when 22776 * doing a sort or use the data from a different column. For example first 22777 * name / last name columns make sense to do a multi-column sort over the 22778 * two columns. 22779 * @type array|int 22780 * @default null <i>Takes the value of the column index automatically</i> 22781 * 22782 * @name DataTable.defaults.column.orderData 22783 * @dtopt Columns 22784 * 22785 * @example 22786 * // Using `columnDefs` 22787 * $(document).ready( function() { 22788 * $('#example').dataTable( { 22789 * "columnDefs": [ 22790 * { "orderData": [ 0, 1 ], "targets": [ 0 ] }, 22791 * { "orderData": [ 1, 0 ], "targets": [ 1 ] }, 22792 * { "orderData": 2, "targets": [ 2 ] } 22793 * ] 22794 * } ); 22795 * } ); 22796 * 22797 * @example 22798 * // Using `columns` 22799 * $(document).ready( function() { 22800 * $('#example').dataTable( { 22801 * "columns": [ 22802 * { "orderData": [ 0, 1 ] }, 22803 * { "orderData": [ 1, 0 ] }, 22804 * { "orderData": 2 }, 22805 * null, 22806 * null 22807 * ] 22808 * } ); 22809 * } ); 22810 */ 22811 "aDataSort": null, 22812 "iDataSort": -1, 22813 22814 22815 /** 22816 * You can control the default ordering direction, and even alter the 22817 * behaviour of the sort handler (i.e. only allow ascending ordering etc) 22818 * using this parameter. 22819 * @type array 22820 * @default [ 'asc', 'desc' ] 22821 * 22822 * @name DataTable.defaults.column.orderSequence 22823 * @dtopt Columns 22824 * 22825 * @example 22826 * // Using `columnDefs` 22827 * $(document).ready( function() { 22828 * $('#example').dataTable( { 22829 * "columnDefs": [ 22830 * { "orderSequence": [ "asc" ], "targets": [ 1 ] }, 22831 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] }, 22832 * { "orderSequence": [ "desc" ], "targets": [ 3 ] } 22833 * ] 22834 * } ); 22835 * } ); 22836 * 22837 * @example 22838 * // Using `columns` 22839 * $(document).ready( function() { 22840 * $('#example').dataTable( { 22841 * "columns": [ 22842 * null, 22843 * { "orderSequence": [ "asc" ] }, 22844 * { "orderSequence": [ "desc", "asc", "asc" ] }, 22845 * { "orderSequence": [ "desc" ] }, 22846 * null 22847 * ] 22848 * } ); 22849 * } ); 22850 */ 22851 "asSorting": [ 'asc', 'desc' ], 22852 22853 22854 /** 22855 * Enable or disable filtering on the data in this column. 22856 * @type boolean 22857 * @default true 22858 * 22859 * @name DataTable.defaults.column.searchable 22860 * @dtopt Columns 22861 * 22862 * @example 22863 * // Using `columnDefs` 22864 * $(document).ready( function() { 22865 * $('#example').dataTable( { 22866 * "columnDefs": [ 22867 * { "searchable": false, "targets": [ 0 ] } 22868 * ] } ); 22869 * } ); 22870 * 22871 * @example 22872 * // Using `columns` 22873 * $(document).ready( function() { 22874 * $('#example').dataTable( { 22875 * "columns": [ 22876 * { "searchable": false }, 22877 * null, 22878 * null, 22879 * null, 22880 * null 22881 * ] } ); 22882 * } ); 22883 */ 22884 "bSearchable": true, 22885 22886 22887 /** 22888 * Enable or disable ordering on this column. 22889 * @type boolean 22890 * @default true 22891 * 22892 * @name DataTable.defaults.column.orderable 22893 * @dtopt Columns 22894 * 22895 * @example 22896 * // Using `columnDefs` 22897 * $(document).ready( function() { 22898 * $('#example').dataTable( { 22899 * "columnDefs": [ 22900 * { "orderable": false, "targets": [ 0 ] } 22901 * ] } ); 22902 * } ); 22903 * 22904 * @example 22905 * // Using `columns` 22906 * $(document).ready( function() { 22907 * $('#example').dataTable( { 22908 * "columns": [ 22909 * { "orderable": false }, 22910 * null, 22911 * null, 22912 * null, 22913 * null 22914 * ] } ); 22915 * } ); 22916 */ 22917 "bSortable": true, 22918 22919 22920 /** 22921 * Enable or disable the display of this column. 22922 * @type boolean 22923 * @default true 22924 * 22925 * @name DataTable.defaults.column.visible 22926 * @dtopt Columns 22927 * 22928 * @example 22929 * // Using `columnDefs` 22930 * $(document).ready( function() { 22931 * $('#example').dataTable( { 22932 * "columnDefs": [ 22933 * { "visible": false, "targets": [ 0 ] } 22934 * ] } ); 22935 * } ); 22936 * 22937 * @example 22938 * // Using `columns` 22939 * $(document).ready( function() { 22940 * $('#example').dataTable( { 22941 * "columns": [ 22942 * { "visible": false }, 22943 * null, 22944 * null, 22945 * null, 22946 * null 22947 * ] } ); 22948 * } ); 22949 */ 22950 "bVisible": true, 22951 22952 22953 /** 22954 * Developer definable function that is called whenever a cell is created (Ajax source, 22955 * etc) or processed for input (DOM source). This can be used as a compliment to mRender 22956 * allowing you to modify the DOM element (add background colour for example) when the 22957 * element is available. 22958 * @type function 22959 * @param {element} td The TD node that has been created 22960 * @param {*} cellData The Data for the cell 22961 * @param {array|object} rowData The data for the whole row 22962 * @param {int} row The row index for the aoData data store 22963 * @param {int} col The column index for aoColumns 22964 * 22965 * @name DataTable.defaults.column.createdCell 22966 * @dtopt Columns 22967 * 22968 * @example 22969 * $(document).ready( function() { 22970 * $('#example').dataTable( { 22971 * "columnDefs": [ { 22972 * "targets": [3], 22973 * "createdCell": function (td, cellData, rowData, row, c
22973ol) { 22974 * if ( cellData == "1.7" ) { 22975 * $(td).css('color', 'blue') 22976 * } 22977 * } 22978 * } ] 22979 * }); 22980 * } ); 22981 */ 22982 "fnCreatedCell": null, 22983 22984 22985 /** 22986 * This parameter has been replaced by `data` in DataTables to ensure naming 22987 * consistency. `dataProp` can still be used, as there is backwards 22988 * compatibility in DataTables for this option, but it is strongly 22989 * recommended that you use `data` in preference to `dataProp`. 22990 * @name DataTable.defaults.column.dataProp 22991 */ 22992 22993 22994 /** 22995 * This property can be used to read data from any data source property, 22996 * including deeply nested objects / properties. `data` can be given in a 22997 * number of different ways which effect its behaviour: 22998 * 22999 * * `integer` - treated as an array index for the data source. This is the 23000 * default that DataTables uses (incrementally increased for each column). 23001 * * `string` - read an object property from the data source. There are 23002 * three 'special' options that can be used in the string to alter how 23003 * DataTables reads the data from the source object: 23004 * * `.` - Dotted Javascript notation. Just as you use a `.` in 23005 * Javascript to read from nested objects, so to can the options 23006 * specified in `data`. For example: `browser.version` or 23007 * `browser.name`. If your object parameter name contains a period, use 23008 * `\\` to escape it - i.e. `first\\.name`. 23009 * * `[]` - Array notation. DataTables can automatically combine data 23010 * from and array source, joining the data with the characters provided 23011 * between the two brackets. For example: `name[, ]` would provide a 23012 * comma-space separated list from the source array. If no characters 23013 * are provided between the brackets, the original array source is 23014 * returned. 23015 * * `()` - Function notation. Adding `()` to the end of a parameter will 23016 * execute a function of the name given. For example: `browser()` for a 23017 * simple function on the data source, `browser.version()` for a 23018 * function in a nested property or even `browser().version` to get an 23019 * object property if the function called returns an object. Note that 23020 * function notation is recommended for use in `render` rather than 23021 * `data` as it is much simpler to use as a renderer. 23022 * * `null` - use the original data source for the row rather than plucking 23023 * data directly from it. This action has effects on two other 23024 * initialisation options: 23025 * * `defaultContent` - When null is given as the `data` option and 23026 * `defaultContent` is specified for the column, the value defined by 23027 * `defaultContent` will be used for the cell. 23028 * * `render` - When null is used for the `data` option and the `render` 23029 * option is specified for the column, the whole data source for the 23030 * row is used for the renderer. 23031 * * `function` - the function given will be executed whenever DataTables 23032 * needs to set or get the data for a cell in the column. The function 23033 * takes three parameters: 23034 * * Parameters: 23035 * * `{array|object}` The data source for the row 23036 * * `{string}` The type call data requested - this will be 'set' when 23037 * setting data or 'filter', 'display', 'type', 'sort' or undefined 23038 * when gathering data. Note that when `undefined` is given for the 23039 * type DataTables expects to get the raw data for the object back< 23040 * * `{*}` Data to set when the second parameter is 'set'. 23041 * * Return: 23042 * * The return value from the function is not required when 'set' is 23043 * the type of call, but otherwise the return is what will be used 23044 * for the data requested. 23045 * 23046 * Note that `data` is a getter and setter option. If you just require 23047 * formatting of data for output, you will likely want to use `render` which 23048 * is simply a getter and thus simpler to use. 23049 * 23050 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The 23051 * name change reflects the flexibility of this property and is consistent 23052 * with the naming of mRender. If 'mDataProp' is given, then it will still 23053 * be used by DataTables, as it automatically maps the old name to the new 23054 * if required. 23055 * 23056 * @type string|int|function|null 23057 * @default null <i>Use automatically calculated column index</i> 23058 * 23059 * @name DataTable.defaults.column.data 23060 * @dtopt Columns 23061 * 23062 * @example 23063 * // Read table data from objects 23064 * // JSON structure for each row: 23065 * // { 23066 * // "engine": {value}, 23067 * // "browser": {value}, 23068 * // "platform": {value}, 23069 * // "version": {value}, 23070 * // "grade": {value} 23071 * // } 23072 * $(document).ready( function() { 23073 * $('#example').dataTable( { 23074 * "ajaxSource": "sources/objects.txt", 23075 * "columns": [ 23076 * { "data": "engine" }, 23077 * { "data": "browser" }, 23078 * { "data": "platform" }, 23079 * { "data": "version" }, 23080 * { "data": "grade" } 23081 * ] 23082 * } ); 23083 * } ); 23084 * 23085 * @example 23086 * // Read information from deeply nested objects 23087 * // JSON structure for each row: 23088 * // { 23089 * // "engine": {value}, 23090 * // "browser": {value}, 23091 * // "platform": { 23092 * // "inner": {value} 23093 * // }, 23094 * // "details": [ 23095 * // {value}, {value} 23096 * // ] 23097 * // } 23098 * $(document).ready( function() { 23099 * $('#example').dataTable( { 23100 * "ajaxSource": "sources/deep.txt", 23101 * "columns": [ 23102 * { "data": "engine" }, 23103 * { "data": "browser" }, 23104 * { "data": "platform.inner" }, 23105 * { "data": "platform.details.0" }, 23106 * { "data": "platform.details.1" } 23107 * ] 23108 * } ); 23109 * } ); 23110 * 23111 * @example 23112 * // Using `data` as a function to provide different information for 23113 * // sorting, filtering and display. In this case, currency (price) 23114 * $(document).ready( function() { 23115 * $('#example').dataTable( { 23116 * "columnDefs": [ { 23117 * "targets": [ 0 ], 23118 * "data": function ( source, type, val ) { 23119 * if (type === 'set') { 23120 * source.price = val; 23121 * // Store the computed dislay and filter values for efficiency 23122 * source.price_display = val=="" ? "" : "$"+numberFormat(val); 23123 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val; 23124 * return; 23125 * } 23126 * else if (type === 'display') { 23127 * return source.price_display; 23128 * } 23129 * else if (type === 'filter') { 23130 * return source.price_filter; 23131 * } 23132 * // 'sort', 'type' and undefined all just use the integer 23133 * return source.price; 23134 * } 23135 * } ] 23136 * } ); 23137 * } ); 23138 * 23139 * @example 23140 * // Using default content 23141 * $(document).ready( function() { 23142 * $('#example').dataTable( { 23143 * "columnDefs": [ { 23144 * "targets": [ 0 ], 23145 * "data": null, 23146 * "defaultContent": "Click to edit" 23147 * } ] 23148 * } ); 23149 * } ); 23150 * 23151 * @example 23152 * // Using array notation - outputting a list from an array 23153 * $(document).ready( function() { 23154 * $('#example').dataTable( { 23155 * "columnDefs": [ { 23156 * "targets": [ 0 ], 23157 * "data": "name[, ]" 23158 * } ] 23159 * } ); 23160 * } ); 23161 * 23162 */ 23163 "mData": null, 23164 23165 23166 /** 23167 * This property is the rendering partner to `data` and it is suggested that 23168 * when you want to manipulate data for display (including filtering, 23169 * sorting etc) without altering the underlying data for the table, use this 23170 * property. `render` can be considered to be the the read only companion to 23171 * `data` which is read / write (then as such more complex). Like `data` 23172 * this option can be given in a number of different ways to effect its 23173 * behaviour: 23174 * 23175 * * `integer` - treated as an array index for the data source. This is the 23176 * default that DataTables uses (incrementally increased for each column). 23177 * * `string` - read an object property from the data source. There are 23178 * three 'special' options that can be used in the string to alter how 23179 * DataTables reads the data from the source object: 23180 * * `.` - Dotted Javascript notation. Just as you use a `.` in 23181 * Javascript to read from nested objects, so to can the options 23182 * specified in `data`. For example: `browser.version` or 23183 * `browser.name`. If your object parameter name contains a period, use 23184 * `\\` to escape it - i.e. `first\\.name`. 23185 * * `[]` - Array notation. DataTables can automatically combine data 23186 * from and array source, joining the data with the characters provided 23187 * between the two brackets. For example: `name[, ]` would provide a 23188 * comma-space separated list from the source array. If no characters 23189 * are provided between the brackets, the original array source is 23190 * returned. 23191 * * `()` - Function notation. Adding `()` to the end of a parameter will 23192 * execute a function of the name given. For example: `browser()` for a 23193 * simple function on the data source, `browser.version()` for a 23194 * function in a nested property or even `browser().version` to get an 23195 * object property if the function called returns an object. 23196 * * `object` - use different data for the different data types requested by 23197 * DataTables ('filter', 'display', 'type' or 'sort'). The property names 23198 * of the object is the data type the property refers to and the value can 23199 * defined using an integer, string or function using the same rules as 23200 * `render` normally does. Note that an `_` option _must_ be specified. 23201 * This is the default value to use if you haven't specified a value for 23202 * the data type requested by DataTables. 23203 * * `function` - the function given will be executed whenever DataTables 23204 * needs to set or get the data for a cell in the column. The function 23205 * takes three parameters: 23206 * * Parameters: 23207 * * {array|object} The data source for the row (based on `data`) 23208 * * {string} The type call data requested - this will be 'filter', 23209 * 'display', 'type' or 'sort'. 23210 * * {array|object} The full data source for the row (not based on 23211 * `data`) 23212 * * Return: 23213 * * The return value from the function is what will be used for the 23214 * data requested. 23215 * 23216 * @type string|int|function|object|null 23217 * @default null Use the data source value. 23218 * 23219 * @name DataTable.defaults.column.render 23220 * @dtopt Columns 23221 * 23222 * @example 23223 * // Create a comma separated list from an array of objects 23224 * $(document).ready( function() { 23225 * $('#example').dataTable( { 23226 * "ajaxSource": "sources/deep.txt", 23227 * "columns": [ 23228 * { "data": "engine" }, 23229 * { "data": "browser" }, 23230 * { 23231 * "data": "platform", 23232 * "render": "[, ].name" 23233 * } 23234 * ] 23235 * } ); 23236 * } ); 23237 * 23238 * @example 23239 * // Execute a function to obtain data 23240 * $(document).ready( function() { 23241 * $('#example').dataTable( { 23242 * "columnDefs": [ { 23243 * "targets": [ 0 ], 23244 * "data": null, // Use the full data source object for the renderer's source 23245 * "render": "browserName()" 23246 * } ] 23247 * } ); 23248 * } ); 23249 * 23250 * @example 23251 * // As an object, extracting different data for the different types 23252 * // This would be used with a data source such as: 23253 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" } 23254 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter` 23255 * // (which has both forms) is used for filtering for if a user inputs either format, while 23256 * // the formatted phone number is the one that is shown in the table. 23257 * $(document).ready( function() { 23258 * $('#example').dataTable( { 23259 * "columnDefs": [ { 23260 * "targets": [ 0 ], 23261 * "data": null, // Use the full data source object for the renderer's source 23262 * "render": { 23263 * "_": "phone", 23264 * "filter": "phone_filter", 23265 * "display": "phone_display" 23266 * } 23267 * } ] 23268 * } ); 23269 * } ); 23270 * 23271 * @example 23272 * // Use as a function to create a link from the data source 23273 * $(document).ready( function() { 23274 * $('#example').dataTable( { 23275 * "columnDefs": [ { 23276 * "targets": [ 0 ], 23277 * "data": "download_link", 23278 * "render": function ( data, type, full ) { 23279 * return '<a href="'+data+'">Download</a>'; 23280 * } 23281 * } ] 23282 * } ); 23283 * } ); 23284 */
23285 "mRender": null, 23286 23287 23288 /** 23289 * Change the cell type created for the column - either TD cells or TH cells. This 23290 * can be useful as TH cells have semantic meaning in the table body, allowing them 23291 * to act as a header for a row (you may wish to add scope='row' to the TH elements). 23292 * @type string 23293 * @default td 23294 * 23295 * @name DataTable.defaults.column.cellType 23296 * @dtopt Columns 23297 * 23298 * @example 23299 * // Make the first column use TH cells 23300 * $(document).ready( function() { 23301 * $('#example').dataTable( { 23302 * "columnDefs": [ { 23303 * "targets": [ 0 ], 23304 * "cellType": "th" 23305 * } ] 23306 * } ); 23307 * } ); 23308 */ 23309 "sCellType": "td", 23310 23311 23312 /** 23313 * Class to give to each cell in this column. 23314 * @type string 23315 * @default <i>Empty string</i> 23316 * 23317 * @name DataTable.defaults.column.class 23318 * @dtopt Columns 23319 * 23320 * @example 23321 * // Using `columnDefs` 23322 * $(document).ready( function() { 23323 * $('#example').dataTable( { 23324 * "columnDefs": [ 23325 * { "class": "my_class", "targets": [ 0 ] } 23326 * ] 23327 * } ); 23328 * } ); 23329 * 23330 * @example 23331 * // Using `columns` 23332 * $(document).ready( function() { 23333 * $('#example').dataTable( { 23334 * "columns": [ 23335 * { "class": "my_class" }, 23336 * null, 23337 * null, 23338 * null, 23339 * null 23340 * ] 23341 * } ); 23342 * } ); 23343 */ 23344 "sClass": "", 23345 23346 /** 23347 * When DataTables calculates the column widths to assign to each column, 23348 * it finds the longest string in each column and then constructs a 23349 * temporary table and reads the widths from that. The problem with this 23350 * is that "mmm" is much wider then "iiii", but the latter is a longer 23351 * string - thus the calculation can go wrong (doing it properly and putting 23352 * it into an DOM object and measuring that is horribly(!) slow). Thus as 23353 * a "work around" we provide this option. It will append its value to the 23354 * text that is found to be the longest string for the column - i.e. padding. 23355 * Generally you shouldn't need this! 23356 * @type string 23357 * @default <i>Empty string<i> 23358 * 23359 * @name DataTable.defaults.column.contentPadding 23360 * @dtopt Columns 23361 * 23362 * @example 23363 * // Using `columns` 23364 * $(document).ready( function() { 23365 * $('#example').dataTable( { 23366 * "columns": [ 23367 * null, 23368 * null, 23369 * null, 23370 * { 23371 * "contentPadding": "mmm" 23372 * } 23373 * ] 23374 * } ); 23375 * } ); 23376 */ 23377 "sContentPadding": "", 23378 23379 23380 /** 23381 * Allows a default value to be given for a column's data, and will be used 23382 * whenever a null data source is encountered (this can be because `data` 23383 * is set to null, or because the data source itself is null). 23384 * @type string 23385 * @default null 23386 * 23387 * @name DataTable.defaults.column.defaultContent 23388 * @dtopt Columns 23389 * 23390 * @example 23391 * // Using `columnDefs` 23392 * $(document).ready( function() { 23393 * $('#example').dataTable( { 23394 * "columnDefs": [ 23395 * { 23396 * "data": null, 23397 * "defaultContent": "Edit", 23398 * "targets": [ -1 ] 23399 * } 23400 * ] 23401 * } ); 23402 * } ); 23403 * 23404 * @example 23405 * // Using `columns` 23406 * $(document).ready( function() { 23407 * $('#example').dataTable( { 23408 * "columns": [ 23409 * null, 23410 * null, 23411 * null, 23412 * { 23413 * "data": null, 23414 * "defaultContent": "Edit" 23415 * } 23416 * ] 23417 * } ); 23418 * } ); 23419 */ 23420 "sDefaultContent": null, 23421 23422 23423 /** 23424 * This parameter is only used in DataTables' server-side processing. It can 23425 * be exceptionally useful to know what columns are being displayed on the 23426 * client side, and to map these to database fields. When defined, the names 23427 * also allow DataTables to reorder information from the server if it comes 23428 * back in an unexpected order (i.e. if you switch your columns around on the 23429 * client-side, your server-side code does not also need updating). 23430 * @type string 23431 * @default <i>Empty string</i> 23432 * 23433 * @name DataTable.defaults.column.name 23434 * @dtopt Columns 23435 * 23436 * @example 23437 * // Using `columnDefs` 23438 * $(document).ready( function() { 23439 * $('#example').dataTable( { 23440 * "columnDefs": [ 23441 * { "name": "engine", "targets": [ 0 ] }, 23442 * { "name": "browser", "targets": [ 1 ] }, 23443 * { "name": "platform", "targets": [ 2 ] }, 23444 * { "name": "version", "targets": [ 3 ] }, 23445 * { "name": "grade", "targets": [ 4 ] } 23446 * ] 23447 * } ); 23448 * } ); 23449 * 23450 * @example 23451 * // Using `columns` 23452 * $(document).ready( function() { 23453 * $('#example').dataTable( { 23454 * "columns": [ 23455 * { "name": "engine" }, 23456 * { "name": "browser" }, 23457 * { "name": "platform" }, 23458 * { "name": "version" }, 23459 * { "name": "grade" } 23460 * ] 23461 * } ); 23462 * } ); 23463 */ 23464 "sName": "", 23465 23466 23467 /** 23468 * Defines a data source type for the ordering which can be used to read 23469 * real-time information from the table (updating the internally cached 23470 * version) prior to ordering. This allows ordering to occur on user 23471 * editable elements such as form inputs. 23472 * @type string 23473 * @default std 23474 * 23475 * @name DataTable.defaults.column.orderDataType 23476 * @dtopt Columns 23477 * 23478 * @example 23479 * // Using `columnDefs` 23480 * $(document).ready( function() { 23481 * $('#example').dataTable( { 23482 * "columnDefs": [ 23483 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] }, 23484 * { "type": "numeric", "targets": [ 3 ] }, 23485 * { "orderDataType": "dom-select", "targets": [ 4 ] }, 23486 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] } 23487 * ] 23488 * } ); 23489 * } ); 23490 * 23491 * @example 23492 * // Using `columns` 23493 * $(document).ready( function() { 23494 * $('#example').dataTable( { 23495 * "columns": [ 23496 * null, 23497 * null, 23498 * { "orderDataType": "dom-text" }, 23499 * { "orderDataType": "dom-text", "type": "numeric" }, 23500 * { "orderDataType": "dom-select" }, 23501 * { "orderDataType": "dom-checkbox" } 23502 * ] 23503 * } ); 23504 * } ); 23505 */ 23506 "sSortDataType": "std", 23507 23508 23509 /** 23510 * The title of this column. 23511 * @type string 23512 * @default null <i>Derived from the 'TH' value for this column in the 23513 * original HTML table.</i> 23514 * 23515 * @name DataTable.defaults.column.title 23516 * @dtopt Columns 23517 * 23518 * @example 23519 * // Using `columnDefs` 23520 * $(document).ready( function() { 23521 * $('#example').dataTable( { 23522 * "columnDefs": [ 23523 * { "title": "My column title", "targets": [ 0 ] } 23524 * ] 23525 * } ); 23526 * } ); 23527 * 23528 * @example 23529 * // Using `columns` 23530 * $(document).ready( function() { 23531 * $('#example').dataTable( { 23532 * "columns": [ 23533 * { "title": "My column title" }, 23534 * null, 23535 * null, 23536 * null, 23537 * null 23538 * ] 23539 * } ); 23540 * } ); 23541 */ 23542 "sTitle": null, 23543 23544 23545 /** 23546 * The type allows you to specify how the data for this column will be
23547 * ordered. Four types (string, numeric, date and html (which will strip 23548 * HTML tags before ordering)) are currently available. Note that only date 23549 * formats understood by Javascript's Date() object will be accepted as type 23550 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 23551 * 'numeric', 'date' or 'html' (by default). Further types can be adding 23552 * through plug-ins. 23553 * @type string 23554 * @default null <i>Auto-detected from raw data</i> 23555 * 23556 * @name DataTable.defaults.column.type 23557 * @dtopt Columns 23558 * 23559 * @example 23560 * // Using `columnDefs` 23561 * $(document).ready( function() { 23562 * $('#example').dataTable( { 23563 * "columnDefs": [ 23564 * { "type": "html", "targets": [ 0 ] } 23565 * ] 23566 * } ); 23567 * } ); 23568 * 23569 * @example 23570 * // Using `columns` 23571 * $(document).ready( function() { 23572 * $('#example').dataTable( { 23573 * "columns": [ 23574 * { "type": "html" }, 23575 * null, 23576 * null, 23577 * null, 23578 * null 23579 * ] 23580 * } ); 23581 * } ); 23582 */ 23583 "sType": null, 23584 23585 23586 /** 23587 * Defining the width of the column, this parameter may take any CSS value 23588 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not 23589 * been given a specific width through this interface ensuring that the table 23590 * remains readable. 23591 * @type string 23592 * @default null <i>Automatic</i> 23593 * 23594 * @name DataTable.defaults.column.width 23595 * @dtopt Columns 23596 * 23597 * @example 23598 * // Using `columnDefs` 23599 * $(document).ready( function() { 23600 * $('#example').dataTable( { 23601 * "columnDefs": [ 23602 * { "width": "20%", "targets": [ 0 ] } 23603 * ] 23604 * } ); 23605 * } ); 23606 * 23607 * @example 23608 * // Using `columns` 23609 * $(document).ready( function() { 23610 * $('#example').dataTable( { 23611 * "columns": [ 23612 * { "width": "20%" }, 23613 * null, 23614 * null, 23615 * null, 23616 * null 23617 * ] 23618 * } ); 23619 * } ); 23620 */ 23621 "sWidth": null 23622 }; 23623 23624 _fnHungarianMap( DataTable.defaults.column ); 23625 23626 23627 23628 /** 23629 * DataTables settings object - this holds all the information needed for a 23630 * given table, including configuration, data and current application of the 23631 * table options. DataTables does not have a single instance for each DataTable 23632 * with the settings attached to that instance, but rather instances of the 23633 * DataTable "class" are created on-the-fly as needed (typically by a 23634 * $().dataTable() call) and the settings object is then applied to that 23635 * instance. 23636 * 23637 * Note that this object is related to {@link DataTable.defaults} but this 23638 * one is the internal data store for DataTables's cache of columns. It should 23639 * NOT be manipulated outside of DataTables. Any configuration should be done 23640 * through the initialisation options. 23641 * @namespace 23642 * @todo Really should attach the settings object to individual instances so we 23643 * don't need to create new instances on each $().dataTable() call (if the 23644 * table already exists). It would also save passing oSettings around and 23645 * into every single function. However, this is a very significant 23646 * architecture change for DataTables and will almost certainly break 23647 * backwards compatibility with older installations. This is something that 23648 * will be done in 2.0. 23649 */ 23650 DataTable.models.oSettings = { 23651 /** 23652 * Primary features of DataTables and their enablement state. 23653 * @namespace 23654 */ 23655 "oFeatures": { 23656 23657 /** 23658 * Flag to say if DataTables should automatically try to calculate the 23659 * optimum table and columns widths (true) or not (false). 23660 * Note that this parameter will be set by the initialisation routine. To 23661 * set a default use {@link DataTable.defaults}. 23662 * @type boolean 23663 */ 23664 "bAutoWidth": null, 23665 23666 /** 23667 * Delay the creation of TR and TD elements until they are actually 23668 * needed by a driven page draw. This can give a significant speed 23669 * increase for Ajax source and Javascript source data, but makes no 23670 * difference at all fro DOM and server-side processing tables. 23671 * Note that this parameter will be set by the initialisation routine. To 23672 * set a default use {@link DataTable.defaults}. 23673 * @type boolean 23674 */ 23675 "bDeferRender": null, 23676 23677 /** 23678 * Enable filtering on the table or not. Note that if this is disabled 23679 * then there is no filtering at all on the table, including fnFilter. 23680 * To just remove the filtering input use sDom and remove the 'f' option. 23681 * Note that this parameter will be set by the initialisation routine. To 23682 * set a default use {@link DataTable.defaults}. 23683 * @type boolean 23684 */ 23685 "bFilter": null, 23686 23687 /** 23688 * Table information element (the 'Showing x of y records' div) enable 23689 * flag. 23690 * Note that this parameter will be set by the initialisation routine. To 23691 * set a default use {@link DataTable.defaults}. 23692 * @type boolean 23693 */ 23694 "bInfo": null, 23695 23696 /** 23697 * Present a user control allowing the end user to change the page size 23698 * when pagination is enabled. 23699 * Note that this parameter will be set by the initialisation routine. To 23700 * set a default use {@link DataTable.defaults}. 23701 * @type boolean 23702 */ 23703 "bLengthChange": null, 23704 23705 /** 23706 * Pagination enabled or not. Note that if this is disabled then length 23707 * changing must also be disabled. 23708 * Note that this parameter will be set by the initialisation routine. To 23709 * set a default use {@link DataTable.defaults}. 23710 * @type boolean 23711 */ 23712 "bPaginate": null, 23713 23714 /** 23715 * Processing indicator enable flag whenever DataTables is enacting a 23716 * user request - typically an Ajax request for server-side processing. 23717 * Note that this parameter will be set by the initialisation routine. To 23718 * set a default use {@link DataTable.defaults}. 23719 * @type boolean 23720 */ 23721 "bProcessing": null, 23722 23723 /** 23724 * Server-side processing enabled flag - when enabled DataTables will 23725 * get all data from the server for every draw - there is no filtering, 23726 * sorting or paging done on the client-side. 23727 * Note that this parameter will be set by the initialisation routine. To 23728 * set a default use {@link DataTable.defaults}. 23729 * @type boolean 23730 */ 23731 "bServerSide": null, 23732 23733 /** 23734 * Sorting enablement flag. 23735 * Note that this parameter will be set by the initialisation routine. To 23736 * set a default use {@link DataTable.defaults}. 23737 * @type boolean 23738 */ 23739 "bSort": null, 23740 23741 /**
23742 * Multi-column sorting 23743 * Note that this parameter will be set by the initialisation routine. To 23744 * set a default use {@link DataTable.defaults}. 23745 * @type boolean 23746 */ 23747 "bSortMulti": null, 23748 23749 /** 23750 * Apply a class to the columns which are being sorted to provide a 23751 * visual highlight or not. This can slow things down when enabled since 23752 * there is a lot of DOM interaction. 23753 * Note that this parameter will be set by the initialisation routine. To 23754 * set a default use {@link DataTable.defaults}. 23755 * @type boolean 23756 */ 23757 "bSortClasses": null, 23758 23759 /** 23760 * State saving enablement flag. 23761 * Note that this parameter will be set by the initialisation routine. To 23762 * set a default use {@link DataTable.defaults}. 23763 * @type boolean 23764 */ 23765 "bStateSave": null 23766 }, 23767 23768 23769 /** 23770 * Scrolling settings for a table. 23771 * @namespace 23772 */ 23773 "oScroll": { 23774 /** 23775 * When the table is shorter in height than sScrollY, collapse the 23776 * table container down to the height of the table (when true). 23777 * Note that this parameter will be set by the initialisation routine. To 23778 * set a default use {@link DataTable.defaults}. 23779 * @type boolean 23780 */ 23781 "bCollapse": null, 23782 23783 /** 23784 * Width of the scrollbar for the web-browser's platform. Calculated 23785 * during table initialisation. 23786 * @type int 23787 * @default 0 23788 */ 23789 "iBarWidth": 0, 23790 23791 /** 23792 * Viewport width for horizontal scrolling. Horizontal scrolling is 23793 * disabled if an empty string. 23794 * Note that this parameter will be set by the initialisation routine. To 23795 * set a default use {@link DataTable.defaults}. 23796 * @type string 23797 */ 23798 "sX": null, 23799 23800 /** 23801 * Width to expand the table to when using x-scrolling. Typically you 23802 * should not need to use this. 23803 * Note that this parameter will be set by the initialisation routine. To 23804 * set a default use {@link DataTable.defaults}. 23805 * @type string 23806 * @deprecated 23807 */ 23808 "sXInner": null, 23809 23810 /** 23811 * Viewport height for vertical scrolling. Vertical scrolling is disabled 23812 * if an empty string. 23813 * Note that this parameter will be set by the initialisation routine. To 23814 * set a default use {@link DataTable.defaults}. 23815 * @type string 23816 */ 23817 "sY": null 23818 }, 23819 23820 /** 23821 * Language information for the table. 23822 * @namespace 23823 * @extends DataTable.defaults.oLanguage 23824 */ 23825 "oLanguage": { 23826 /** 23827 * Information callback function. See 23828 * {@link DataTable.defaults.fnInfoCallback} 23829 * @type function 23830 * @default null 23831 */ 23832 "fnInfoCallback": null 23833 }, 23834 23835 /** 23836 * Browser support parameters 23837 * @namespace 23838 */ 23839 "oBrowser": { 23840 /** 23841 * Indicate if the browser incorrectly calculates width:100% inside a 23842 * scrolling element (IE6/7) 23843 * @type boolean 23844 * @default false 23845 */ 23846 "bScrollOversize": false, 23847 23848 /** 23849 * Determine if the vertical scrollbar is on the right or left of the 23850 * scrolling container - needed for rtl language layout, although not 23851 * all browsers move the scrollbar (Safari). 23852 * @type boolean 23853 * @default false 23854 */ 23855 "bScrollbarLeft": false, 23856 23857 /** 23858 * Flag for if `getBoundingClientRect` is fully supported or not 23859 * @type boolean 23860 * @default false 23861 */ 23862 "bBounding": false, 23863 23864 /** 23865 * Browser scrollbar width 23866 * @type integer 23867 * @default 0 23868 */ 23869 "barWidth": 0 23870 }, 23871 23872 23873 "ajax": null, 23874 23875 23876 /** 23877 * Array referencing the nodes which are used for the features. The 23878 * parameters of this object match what is allowed by sDom - i.e. 23879 * <ul> 23880 * <li>'l' - Length changing</li> 23881 * <li>'f' - Filtering input</li> 23882 * <li>'t' - The table!</li> 23883 * <li>'i' - Information</li> 23884 * <li>'p' - Pagination</li> 23885 * <li>'r' - pRocessing</li> 23886 * </ul> 23887 * @type array 23888 * @default [] 23889 */ 23890 "aanFeatures": [], 23891 23892 /** 23893 * Store data information - see {@link DataTable.models.oRow} for detailed 23894 * information. 23895 * @type array 23896 * @default [] 23897 */ 23898 "aoData": [], 23899 23900 /** 23901 * Array of indexes which are in the current display (after filtering etc) 23902 * @type array 23903 * @default [] 23904 */ 23905 "aiDisplay": [], 23906 23907 /** 23908 * Array of indexes for display - no filtering 23909 * @type array 23910 * @default [] 23911 */ 23912 "aiDisplayMaster": [], 23913 23914 /** 23915 * Map of row ids to data indexes 23916 * @type object 23917 * @default {} 23918 */ 23919 "aIds": {}, 23920 23921 /** 23922 * Store information about each column that is in use 23923 * @type array 23924 * @default [] 23925 */ 23926 "aoColumns": [], 23927 23928 /** 23929 * Store information about the table's header 23930 * @type array 23931 * @default [] 23932 */ 23933 "aoHeader": [], 23934 23935 /** 23936 * Store information about the table's footer 23937 * @type array 23938 * @default [] 23939 */ 23940 "aoFooter": [], 23941 23942 /** 23943 * Store the applied global search information in case we want to force a 23944 * research or compare the old search to a new one. 23945 * Note that this parameter will be set by the initialisation routine. To 23946 * set a default use {@link DataTable.defaults}. 23947 * @namespace 23948 * @extends DataTable.models.oSearch 23949 */ 23950 "oPreviousSearch": {}, 23951 23952 /** 23953 * Store the applied search for each column - see 23954 * {@link DataTable.models.oSearch} for the format that is used for the 23955 * filtering information for each column. 23956 * @type array 23957 * @default [] 23958 */ 23959 "aoPreSearchCols": [], 23960 23961 /** 23962 * Sorting that is applied to the table. Note that the inner arrays are 23963 * used in the following manner: 23964 * <ul> 23965 * <li>Index 0 - column number</li> 23966 * <li>Index 1 - current sorting direction</li> 23967 * </ul> 23968 * Note that this parameter will be set by the initialisation routine. To 23969 * set a default use {@link DataTable.defaults}. 23970 * @type array 23971 * @todo These inner arrays should really be objects 23972 */ 23973 "aaSorting": null, 23974 23975 /** 23976 * Sorting that is always applied to the table (i.e. prefixed in front of 23977 * aaSorting). 23978 * Note that this parameter will be set by the initialisation routine. To 23979 * set a default use {@link DataTable.defaults}. 23980 * @type array 23981 * @default [] 23982 */ 23983 "aaSortingFixed": [], 23984 23985 /** 23986 * Classes to use for the striping of a table. 23987 * Note that this parameter will be set by the initialisation routine. To 23988 * set a default use {@link DataTable.defaults}. 23989 * @type array 23990 * @default [] 23991 */ 23992 "asStripeClasses": null, 23993 23994 /** 23995 * If restoring a table - we should restore its striping classes as well 23996 * @type array 23997 * @default [] 23998 */ 23999 "asDestroyStripes": [], 24000 24001 /** 24002 * If restoring a table - we should restore its width 24003 * @type int 24004 * @default 0 24005 */ 24006 "sDestroyWidth": 0, 24007 24008 /** 24009 * Callback functions array for every time a row is inserted (i.e. on a draw). 24010 * @type array 24011 * @default [] 24012 */ 24013 "aoRowCallback": [], 24014 24015 /** 24016 * Callback functions for the header on each draw. 24017 * @type array 24018 * @default [] 24019 */ 24020 "aoHeaderCallback": [], 24021 24022 /** 24023 * Callback function for the footer on each draw. 24024 * @type array 24025 * @default [] 24026 */ 24027 "aoFooterCallback": [], 24028 24029 /** 24030 * Array of callback functions for draw callback functions 24031 * @type array 24032 * @default [] 24033 */ 24034 "aoDrawCallback": [], 24035 24036 /** 24037 * Array of callback functions for row created function 24038 * @type array 24039 * @default [] 24040 */ 24041 "aoRowCreatedCallback": [], 24042 24043 /** 24044 * Callback functions for just before the table is redrawn. A return of 24045 * false will be used to cancel the draw. 24046 * @type array 24047 * @default [] 24048 */ 24049 "aoPreDrawCallback": [], 24050 24051 /** 24052 * Callback functions for when the table has been initialised. 24053 * @type array 24054 * @default [] 24055 */ 24056 "aoInitComplete": [], 24057 24058 24059 /** 24060 * Callbacks for modifying the settings to be stored for state saving, prior to 24061 * saving state. 24062 * @type array 24063 * @default [] 24064 */ 24065 "aoStateSaveParams": [], 24066 24067 /** 24068 * Callbacks for modifying the settings that have been stored for state saving 24069 * prior to using the stored values to restore the state. 24070 * @type array 24071 * @default [] 24072 */ 24073 "aoStateLoadParams": [], 24074 24075 /** 24076 * Callbacks for operating on the settings object once the saved state has been 24077 * loaded 24078 * @type array 24079 * @default [] 24080 */ 24081 "aoStateLoaded": [], 24082 24083 /** 24084 * Cache the table ID for quick access 24085 * @type string 24086 * @default <i>Empty string</i> 24087 */ 24088 "sTableId": "", 24089 24090 /** 24091 * The TABLE node for the main table 24092 * @type node 24093 * @default null 24094 */ 24095 "nTable": null, 24096 24097 /** 24098 * Permanent ref to the thead element 24099 * @type node 24100 * @default null 24101 */ 24102 "nTHead": null, 24103 24104 /** 24105 * Permanent ref to the tfoot element - if it exists 24106 * @type node 24107 * @default null 24108 */ 24109 "nTFoot": null, 24110 24111 /** 24112 * Permanent ref to the tbody element 24113 * @type node 24114 * @default null 24115 */ 24116 "nTBody": null, 24117 24118 /** 24119 * Cache the wrapper node (contains all DataTables controlled elements) 24120 * @type node 24121 * @default null 24122 */ 24123 "nTableWrapper": null, 24124 24125 /** 24126 * Indicate if when using server-side processing the loading of data 24127 * should be deferred until the second draw. 24128 * Note that this parameter will be set by the initialisation routine. To 24129 * set a default use {@link DataTable.defaults}. 24130 * @type boolean 24131 * @default false 24132 */ 24133 "bDeferLoading": false, 24134 24135 /** 24136 * Indicate if all required information has been read in 24137 * @type boolean 24138 * @default false 24139 */ 24140 "bInitialised": false, 24141 24142 /** 24143 * Information about open rows. Each object in the array has the parameters 24144 * 'nTr' and 'nParent' 24145 * @type array 24146 * @default [] 24147 */ 24148 "aoOpenRows": [], 24149 24150 /**
24151 * Dictate the positioning of DataTables' control elements - see 24152 * {@link DataTable.model.oInit.sDom}. 24153 * Note that this parameter will be set by the initialisation routine. To 24154 * set a default use {@link DataTable.defaults}. 24155 * @type string 24156 * @default null 24157 */ 24158 "sDom": null, 24159 24160 /** 24161 * Search delay (in mS) 24162 * @type integer 24163 * @default null 24164 */ 24165 "searchDelay": null, 24166 24167 /** 24168 * Which type of pagination should be used. 24169 * Note that this parameter will be set by the initialisation routine. To 24170 * set a default use {@link DataTable.defaults}. 24171 * @type string 24172 * @default two_button 24173 */ 24174 "sPaginationType": "two_button", 24175 24176 /** 24177 * The state duration (for `stateSave`) in seconds. 24178 * Note that this parameter will be set by the initialisation routine. To 24179 * set a default use {@link DataTable.defaults}. 24180 * @type int 24181 * @default 0 24182 */ 24183 "iStateDuration": 0, 24184 24185 /** 24186 * Array of callback functions for state saving. Each array element is an 24187 * object with the following parameters: 24188 * <ul> 24189 * <li>function:fn - function to call. Takes two parameters, oSettings 24190 * and the JSON string to save that has been thus far created. Returns 24191 * a JSON string to be inserted into a json object 24192 * (i.e. '"param": [ 0, 1, 2]')</li> 24193 * <li>string:sName - name of callback</li> 24194 * </ul> 24195 * @type array 24196 * @default [] 24197 */ 24198 "aoStateSave": [], 24199 24200 /** 24201 * Array of callback functions for state loading. Each array element is an 24202 * object with the following parameters: 24203 * <ul> 24204 * <li>function:fn - function to call. Takes two parameters, oSettings 24205 * and the object stored. May return false to cancel state loading</li> 24206 * <li>string:sName - name of callback</li> 24207 * </ul> 24208 * @type array 24209 * @default [] 24210 */ 24211 "aoStateLoad": [], 24212 24213 /** 24214 * State that was saved. Useful for back reference 24215 * @type object 24216 * @default null 24217 */ 24218 "oSavedState": null, 24219 24220 /** 24221 * State that was loaded. Useful for back reference 24222 * @type object 24223 * @default null 24224 */ 24225 "oLoadedState": null, 24226 24227 /** 24228 * Source url for AJAX data for the table. 24229 * Note that this parameter will be set by the initialisation routine. To 24230 * set a default use {@link DataTable.defaults}. 24231 * @type string 24232 * @default null 24233 */ 24234 "sAjaxSource": null, 24235 24236 /** 24237 * Property from a given object from which to read the table data from. This 24238 * can be an empty string (when not server-side processing), in which case 24239 * it is assumed an an array is given directly. 24240 * Note that this parameter will be set by the initialisation routine. To 24241 * set a default use {@link DataTable.defaults}. 24242 * @type string 24243 */ 24244 "sAjaxDataProp": null, 24245 24246 /** 24247 * Note if draw should be blocked while getting data 24248 * @type boolean 24249 * @default true 24250 */ 24251 "bAjaxDataGet": true, 24252 24253 /** 24254 * The last jQuery XHR object that was used for server-side data gathering. 24255 * This can be used for working with the XHR information in one of the 24256 * callbacks 24257 * @type object 24258 * @default null 24259 */ 24260 "jqXHR": null, 24261 24262 /** 24263 * JSON returned from the server in the last Ajax request 24264 * @type object 24265 * @default undefined 24266 */ 24267 "json": undefined, 24268 24269 /** 24270 * Data submitted as part of the last Ajax request 24271 * @type object 24272 * @default undefined 24273 */ 24274 "oAjaxData": undefined, 24275 24276 /** 24277 * Function to get the server-side data. 24278 * Note that this parameter will be set by the initialisation routine. To 24279 * set a default use {@link DataTable.defaults}. 24280 * @type function 24281 */ 24282 "fnServerData": null, 24283 24284 /** 24285 * Functions which are called prior to sending an Ajax request so extra 24286 * parameters can easily be sent to the server 24287 * @type array 24288 * @default [] 24289 */ 24290 "aoServerParams": [], 24291 24292 /** 24293 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if 24294 * required). 24295 * Note that this parameter will be set by the initialisation routine. To 24296 * set a default use {@link DataTable.defaults}. 24297 * @type string 24298 */ 24299 "sServerMethod": null, 24300 24301 /** 24302 * Format numbers for display. 24303 * Note that this parameter will be set by the initialisation routine. To 24304 * set a default use {@link DataTable.defaults}. 24305 * @type function 24306 */ 24307 "fnFormatNumber": null, 24308 24309 /** 24310 * List of options that can be used for the user selectable length menu. 24311 * Note that this parameter will be set by the initialisation routine. To 24312 * set a default use {@link DataTable.defaults}. 24313 * @type array 24314 * @default [] 24315 */
24316 "aLengthMenu": null, 24317 24318 /** 24319 * Counter for the draws that the table does. Also used as a tracker for 24320 * server-side processing 24321 * @type int 24322 * @default 0 24323 */ 24324 "iDraw": 0, 24325 24326 /** 24327 * Indicate if a redraw is being done - useful for Ajax 24328 * @type boolean 24329 * @default false 24330 */ 24331 "bDrawing": false, 24332 24333 /** 24334 * Draw index (iDraw) of the last error when parsing the returned data 24335 * @type int 24336 * @default -1 24337 */ 24338 "iDrawError": -1, 24339 24340 /** 24341 * Paging display length 24342 * @type int 24343 * @default 10 24344 */ 24345 "_iDisplayLength": 10, 24346 24347 /** 24348 * Paging start point - aiDisplay index 24349 * @type int 24350 * @default 0 24351 */ 24352 "_iDisplayStart": 0, 24353 24354 /** 24355 * Server-side processing - number of records in the result set 24356 * (i.e. before filtering), Use fnRecordsTotal rather than 24357 * this property to get the value of the number of records, regardless of 24358 * the server-side processing setting. 24359 * @type int 24360 * @default 0 24361 * @private 24362 */ 24363 "_iRecordsTotal": 0, 24364 24365 /** 24366 * Server-side processing - number of records in the current display set 24367 * (i.e. after filtering). Use fnRecordsDisplay rather than 24368 * this property to get the value of the number of records, regardless of 24369 * the server-side processing setting. 24370 * @type boolean 24371 * @default 0 24372 * @private 24373 */ 24374 "_iRecordsDisplay": 0, 24375 24376 /** 24377 * Flag to indicate if jQuery UI marking and classes should be used. 24378 * Note that this parameter will be set by the initialisation routine. To 24379 * set a default use {@link DataTable.defaults}. 24380 * @type boolean 24381 */ 24382 "bJUI": null, 24383 24384 /** 24385 * The classes to use for the table 24386 * @type object 24387 * @default {} 24388 */ 24389 "oClasses": {}, 24390 24391 /** 24392 * Flag attached to the settings object so you can check in the draw 24393 * callback if filtering has been done in the draw. Deprecated
vendor: 4,896 bytes, lines 24393-24611
24393in favour of 24394 * events. 24395 * @type boolean 24396 * @default false 24397 * @deprecated 24398 */ 24399 "bFiltered": false, 24400 24401 /** 24402 * Flag attached to the settings object so you can check in the draw 24403 * callback if sorting has been done in the draw. Deprecated in favour of 24404 * events. 24405 * @type boolean 24406 * @default false 24407 * @deprecated 24408 */ 24409 "bSorted": false, 24410 24411 /** 24412 * Indicate that if multiple rows are in the header and there is more than 24413 * one unique cell per column, if the top one (true) or bottom one (false) 24414 * should be used for sorting / title by DataTables. 24415 * Note that this parameter will be set by the initialisation routine. To 24416 * set a default use {@link DataTable.defaults}. 24417 * @type boolean 24418 */ 24419 "bSortCellsTop": null, 24420 24421 /** 24422 * Initialisation object that is used for the table 24423 * @type object 24424 * @default null 24425 */ 24426 "oInit": null, 24427 24428 /** 24429 * Destroy callback functions - for plug-ins to attach themselves to the 24430 * destroy so they can clean up markup and events. 24431 * @type array 24432 * @default [] 24433 */ 24434 "aoDestroyCallback": [], 24435 24436 24437 /** 24438 * Get the number of records in the current record set, before filtering 24439 * @type function 24440 */ 24441 "fnRecordsTotal": function () 24442 { 24443 return _fnDataSource( this ) == 'ssp' ? 24444 this._iRecordsTotal * 1 : 24445 this.aiDisplayMaster.length; 24446 }, 24447 24448 /** 24449 * Get the number of records in the current record set, after filtering 24450 * @type function 24451 */ 24452 "fnRecordsDisplay": function () 24453 { 24454 return _fnDataSource( this ) == 'ssp' ? 24455 this._iRecordsDisplay * 1 : 24456 this.aiDisplay.length; 24457 }, 24458 24459 /** 24460 * Get the display end point - aiDisplay index 24461 * @type function 24462 */ 24463 "fnDisplayEnd": function () 24464 { 24465 var 24466 len = this._iDisplayLength, 24467 start = this._iDisplayStart, 24468 calc = start + len, 24469 records = this.aiDisplay.length, 24470 features = this.oFeatures, 24471 paginate = features.bPaginate; 24472 24473 if ( features.bServerSide ) { 24474 return paginate === false || len === -1 ? 24475 start + records : 24476 Math.min( start+len, this._iRecordsDisplay ); 24477 } 24478 else { 24479 return ! paginate || calc>records || len===-1 ? 24480 records : 24481 calc; 24482 } 24483 }, 24484 24485 /** 24486 * The DataTables object for this table 24487 * @type object 24488 * @default null 24489 */ 24490 "oInstance": null, 24491 24492 /** 24493 * Unique identifier for each instance of the DataTables object. If there 24494 * is an ID on the table node, then it takes that value, otherwise an 24495 * incrementing internal counter is used. 24496 * @type string 24497 * @default null 24498 */ 24499 "sInstance": null, 24500 24501 /** 24502 * tabindex attribute value that is added to DataTables control elements, allowing 24503 * keyboard navigation of the table and its controls. 24504 */ 24505 "iTabIndex": 0, 24506 24507 /** 24508 * DIV container for the footer scrolling table if scrolling 24509 */ 24510 "nScrollHead": null, 24511 24512 /** 24513 * DIV container for the footer scrolling table if scrolling 24514 */ 24515 "nScrollFoot": null, 24516 24517 /** 24518 * Last applied sort 24519 * @type array 24520 * @default [] 24521 */ 24522 "aLastSort": [], 24523 24524 /** 24525 * Stored plug-in instances 24526 * @type object 24527 * @default {} 24528 */ 24529 "oPlugins": {}, 24530 24531 /** 24532 * Function used to get a row's id from the row's data 24533 * @type function 24534 * @default null 24535 */ 24536 "rowIdFn": null, 24537 24538 /** 24539 * Data location where to store a row's id 24540 * @type string 24541 * @default null 24542 */ 24543 "rowId": null 24544 }; 24545 /** 24546 * Extension object for DataTables that is used to provide all extension 24547 * options. 24548 * 24549 * Note that the `DataTable.ext` object is available through 24550 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is 24551 * also aliased to `jQuery.fn.dataTableExt` for historic reasons. 24552 * @namespace 24553 * @extends DataTable.models.ext 24554 */ 24555 24556 24557 /** 24558 * DataTables extensions 24559 * 24560 * This namespace acts as a collection area for plug-ins that can be used to 24561 * extend DataTables capabilities. Indeed many of the build in methods 24562 * use this method to provide their own capabilities (sorting methods for 24563 * example). 24564 * 24565 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy 24566 * reasons 24567 * 24568 * @namespace 24569 */ 24570 DataTable.ext = _ext = { 24571 /** 24572 * Buttons. For use with the Buttons extension for DataTables. This is 24573 * defined here so other extensions can define buttons regardless of load 24574 * order. It is _not_ used by DataTables core. 24575 * 24576 * @type object 24577 * @default {} 24578 */ 24579 buttons: {}, 24580 24581 24582 /** 24583 * Element class names 24584 * 24585 * @type object 24586 * @default {} 24587 */ 24588 classes: {}, 24589 24590 24591 /** 24592 * DataTables build type (expanded by the download builder) 24593 * 24594 * @type string 24595 */ 24596 builder: "-source-", 24597 24598 24599 /** 24600 * Error reporting. 24601 * 24602 * How should DataTables report an error. Can take the value 'alert', 24603 * 'throw', 'none' or a function. 24604 * 24605 * @type string|function 24606 * @default alert 24607 */ 24608 errMode: "alert", 24609 24610 24611 /**
24612 * Feature plug-ins. 24613 * 24614 * This is an array of objects which describe the feature plug-ins that are 24615 * available to DataTables. These feature plug-ins are then available for 24616 * use through the `dom` initialisation option. 24617 * 24618 * Each feature plug-in is described by an object which must have the 24619 * following properties: 24620 * 24621 * * `fnInit` - function that is used to initialise the plug-in, 24622 * * `cFeature` - a character so the feature can be enabled by the `dom` 24623 * instillation option. This is case sensitive. 24624 * 24625 * The `fnInit` function has the following input parameters: 24626 * 24627 * 1. `{object}` DataTables settings object: see 24628 * {@link DataTable.models.oSettings} 24629 * 24630 * And the following return is expected: 24631 * 24632 * * {node|null} The element which contains your feature. Note that the 24633 * return may also be void if your plug-in does not require to inject any 24634 * DOM elements into DataTables control (`dom`) - for example this might 24635 * be useful when developing a plug-in which allows table control via 24636 * keyboard entry 24637 * 24638 * @type array 24639 * 24640 * @example 24641 * $.fn.dataTable.ext.features.push( { 24642 * "fnInit": function( oSettings ) { 24643 * return new TableTools( { "oDTSettings": oSettings } ); 24644 * }, 24645 * "cFeature": "T" 24646 * } ); 24647 */ 24648 feature: [], 24649 24650 24651 /** 24652 * Row searching. 24653 * 24654 * This method of searching is complimentary to the default type based 24655 * searching, and a lot more comprehensive as it allows you complete control 24656 * over the searching logic. Each element in this array is a function 24657 * (parameters described below) that is called for every row in the table, 24658 * and your logic decides if it should be included in the searching data set 24659 * or not. 24660 * 24661 * Searching functions have the following input parameters: 24662 * 24663 * 1. `{object}` DataTables settings object: see 24664 * {@link DataTable.models.oSettings} 24665 * 2. `{array|object}` Data for the row to be processed (same as the 24666 * original format that was passed in as the data source, or an array 24667 * from a DOM data source 24668 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which 24669 * can be useful to retrieve the `TR` element if you need DOM interaction. 24670 * 24671 * And the following return is expected: 24672 * 24673 * * {boolean} Include the row in the searched result set (true) or not 24674 * (false) 24675 * 24676 * Note that as with the main search ability in DataTables, technically this 24677 * is "filtering", since it is subtractive. However, for consistency in 24678 * naming we call it searching here. 24679 * 24680 * @type array 24681 * @default [] 24682 * 24683 * @example 24684 * // The following example shows custom search being applied to the 24685 * // fourth column (i.e. the data[3] index) based on two input values 24686 * // from the end-user, matching the data in a certain range. 24687 * $.fn.dataTable.ext.search.push( 24688 * function( settings, data, dataIndex ) { 24689 * var min = document.getElementById('min').value * 1; 24690 * var max = document.getElementById('max').value * 1; 24691 * var version = data[3] == "-" ? 0 : data[3]*1; 24692 * 24693 * if ( min == "" && max == "" ) { 24694 * return true; 24695 * } 24696 * else if ( min == "" && version < max ) { 24697 * return true; 24698 * } 24699 * else if ( min < version && "" == max ) { 24700 * return true; 24701 * } 24702 * else if ( min < version && version < max ) { 24703 * return true; 24704 * } 24705 * return false; 24706 * } 24707 * ); 24708 */ 24709 search: [], 24710 24711 24712 /** 24713 * Selector extensions 24714 * 24715 * The `selector` option can be used to extend the options available for the 24716 * selector modifier options (`selector-modifier` object data type) that 24717 * each of the three built in selector types offer (row, column and cell + 24718 * their plural counterparts). For example the Select extension uses this 24719 * mechanism to provide an option to select only rows, columns and cells 24720 * that have been marked as selected by the end user (`{selected: true}`), 24721 * which can be used in conjunction with the existing built in selector 24722 * options. 24723 * 24724 * Each property is an array to which functions can be pushed. The functions 24725 * take three attributes: 24726 * 24727 * * Settings object for the host table 24728 * * Options object (`selector-modifier` object type) 24729 * * Array of selected item indexes 24730 * 24731 * The return is an array of the resulting item indexes after the custom 24732 * selector has been applied. 24733 * 24734 * @type object 24735 */ 24736 selector: { 24737 cell: [], 24738 column: [], 24739 row: [] 24740 }, 24741 24742 24743 /** 24744 * Internal functions, exposed for used in plug-ins. 24745 * 24746 * Please note that you should not need to use the internal methods for 24747 * anything other than a plug-in (and even then, try to avoid if possible). 24748 * The internal function may change between releases. 24749 * 24750 * @type object 24751 * @default {} 24752 */ 24753 internal: {}, 24754 24755 24756 /** 24757 * Legacy configuration options. Enable and disable legacy options that 24758 * are available in DataTables. 24759 * 24760 * @type object 24761 */ 24762 legacy: { 24763 /** 24764 * Enable / disable DataTables 1.9 compatible server-side processing 24765 * requests 24766 * 24767 * @type boolean 24768 * @default null 24769 */ 24770 ajax: null 24771 }, 24772 24773 24774 /** 24775 * Pagination plug-in methods. 24776 * 24777 * Each entry in this object is a function and defines which buttons should 24778 * be shown by the pagination rendering method that is used for the table: 24779 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the 24780 * buttons are displayed in the document, while the functions here tell it 24781 * what buttons to display. This is done by returning an array of button 24782 * descriptions (what each button will do). 24783 * 24784 * Pagination types (the four built in options and any additional plug-in 24785 * options defined here) can be used through the `paginationType` 24786 * initialisation parameter. 24787 * 24788 * The functions defined take two parameters: 24789 * 24790 * 1. `{int} page` The current page index 24791 * 2. `{int} pages` The number of pages in the table 24792 * 24793 * Each function is expected to return an array where each element of the 24794 * array can be one of: 24795 * 24796 * * `first` - Jump to first page when activated 24797 * * `last` - Jump to last page when activated 24798 * * `previous` - Show previous page when activated 24799 * * `next` - Show next page when activated 24800 * * `{int}` - Show page of the index given 24801 * * `{array}` - A nested array containing the above elements to add a 24802 * containing 'DIV' element (might be useful for styling). 24803 * 24804 * Note that DataTables v1.9- used this object slightly differently whereby 24805 * an object with two functions would be defined for each plug-in. That 24806 * ability is still supported by DataTables 1.10+ to provide backwards 24807 * compatibility, but this option of use is now decremented and no longer 24808 * documented in DataTables 1.10+. 24809 * 24810 * @type object 24811 * @default {} 24812 * 24813 * @example 24814 * // Show previous, next and current page buttons only 24815 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) { 24816 * return [ 'previous', page, 'next' ]; 24817 * }; 24818 */ 24819 pager: {}, 24820 24821 24822 renderer: { 24823 pageButton: {}, 24824 header: {} 24825 }, 24826 24827 24828 /** 24829 * Ordering plug-ins - custom data source 24830 *
24831 * The extension options for ordering of data available here is complimentary 24832 * to the default type based ordering that DataTables typically uses. It 24833 * allows much greater control over the the data that is being used to 24834 * order a column, but is necessarily therefore more complex. 24835 * 24836 * This type of ordering is useful if you want to do ordering based on data 24837 * live from the DOM (for example the contents of an 'input' element) rather 24838 * than just the static string that DataTables knows of. 24839 * 24840 * The way these plug-ins work is that you create an array of the values you 24841 * wish to be ordering for the column in question and then return that 24842 * array. The data in the array much be in the index order of the rows in 24843 * the table (not the currently ordering order!). Which order data gathering 24844 * function is run here depends on the `dt-init columns.orderDataType` 24845 * parameter that is used for the column (if any). 24846 * 24847 * The functions defined take two parameters: 24848 * 24849 * 1. `{object}` DataTables settings object: see 24850 * {@link DataTable.models.oSettings} 24851 * 2. `{int}` Target column index 24852 * 24853 * Each function is expected to return an array: 24854 * 24855 * * `{array}` Data for the column to be ordering upon 24856 * 24857 * @type array 24858 * 24859 * @example 24860 * // Ordering using `input` node values 24861 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col ) 24862 * { 24863 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) { 24864 * return $('input', td).val(); 24865 * } ); 24866 * } 24867 */ 24868 order: {}, 24869 24870 24871 /** 24872 * Type based plug-ins. 24873 * 24874 * Each column in DataTables has a type assigned to it, either by automatic 24875 * detection or by direct assignment using the `type` option for the column. 24876 * The type of a column will effect how it is ordering and search (plug-ins 24877 * can also make use of the column type if required). 24878 * 24879 * @namespace 24880 */ 24881 type: { 24882 /** 24883 * Type detection functions. 24884 * 24885 * The functions defined in this object are used to automatically detect 24886 * a column's type, making initialisation of DataTables super easy, even 24887 * when complex data is in the table. 24888 * 24889 * The functions defined take two parameters: 24890 * 24891 * 1. `{*}` Data from the column cell to be analysed 24892 * 2. `{settings}` DataTables settings object. This can be used to 24893 * perform context specific type detection - for example detection 24894 * based on language settings such as using a comma for a decimal 24895 * place. Generally speaking the options from the settings will not 24896 * be required 24897 * 24898 * Each function is expected to return: 24899 * 24900 * * `{string|null}` Data type detected, or null if unknown (and thus 24901 * pass it on to the other type detection functions. 24902 * 24903 * @type array 24904 * 24905 * @example 24906 * // Currency type detection plug-in: 24907 * $.fn.dataTable.ext.type.detect.push( 24908 * function ( data, settings ) { 24909 * // Check the numeric part 24910 * if ( ! $.isNumeric( data.substring(1) ) ) { 24911 * return null; 24912 * } 24913 * 24914 * // Check prefixed by currency 24915 * if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) { 24916 * return 'currency'; 24917 * } 24918 * return null; 24919 * } 24920 * ); 24921 */ 24922 detect: [], 24923 24924 24925 /** 24926 * Type based search formatting. 24927 * 24928 * The type based searching functions can be used to pre-format the 24929 * data to be search on. For example, it can be used to strip HTML 24930 * tags or to de-format telephone numbers for numeric only searching. 24931 * 24932 * Note that is a search is not defined for a column of a given type, 24933 * no search formatting will be performed. 24934 * 24935 * Pre-processing of searching data plug-ins - When you assign the sType 24936 * for a column (or have it automatically detected for you by DataTables 24937 * or a type detection plug-in), you will typically be using this for 24938 * custom sorting, but it can also be used to provide custom searching 24939 * by allowing you to pre-processing the data and returning the data in 24940 * the format that should be searched upon. This is done by adding 24941 * functions this object with a parameter name which matches the sType 24942 * for that target column. This is the corollary of <i>afnSortData</i> 24943 * for searching data. 24944 * 24945 * The functions defined take a single parameter: 24946 * 24947 * 1. `{*}` Data from the column cell to be prepared for searching 24948 * 24949 * Each function is expected to return: 24950 * 24951 * * `{string|null}` Formatted string that will be used for the searching. 24952 * 24953 * @type object 24954 * @default {} 24955 * 24956 * @example 24957 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) { 24958 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" ); 24959 * } 24960 */ 24961 search: {}, 24962 24963 24964 /** 24965 * Type based ordering. 24966 * 24967 * The column type tells DataTables what ordering to apply to the table 24968 * when a column is sorted upon. The order for each type that is defined, 24969 * is defined by the functions available in this object. 24970 * 24971 * Each ordering option can be described by three properties added to 24972 * this object: 24973 * 24974 * * `{type}-pre` - Pre-formatting function 24975 * * `{type}-asc` - Ascending order function 24976 * * `{type}-desc` - Descending order function 24977 * 24978 * All three can be used together, only `{type}-pre` or only 24979 * `{type}-asc` and `{type}-desc` together. It is generally recommended 24980 * that only `{type}-pre` is used, as this provides the optimal 24981 * implementation in terms of speed, although the others are provided 24982 * for compatibility with existing Javascript sort functions. 24983 * 24984 * `{type}-pre`: Functions defined take a single parameter: 24985 * 24986 * 1. `{*}` Data from the column cell to be prepared for ordering 24987 * 24988 * And return: 24989 * 24990 * * `{*}` Data to be sorted upon 24991 * 24992 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort 24993 * functions, taking two parameters: 24994 * 24995 * 1. `{*}` Data to compare to the second parameter 24996 * 2. `{*}` Data to compare to the first parameter 24997 * 24998 * And returning: 24999 * 25000 * * `{*}` Ordering match: <0 if first parameter should be sorted lower 25001 * than the second parameter, ===0 if the two parameters are equal and 25002 * >0 if the first parameter should be sorted height than the second 25003 * parameter. 25004 * 25005 * @type object 25006 * @default {} 25007 * 25008 * @example 25009 * // Numeric ordering of formatted numbers with a pre-formatter 25010 * $.extend( $.fn.dataTable.ext.type.order, { 25011 * "string-pre": function(x) { 25012 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" ); 25013 * return parseFloat( a ); 25014 * } 25015 * } ); 25016 * 25017 * @example 25018 * // Case-sensitive string ordering, with no pre-formatting method 25019 * $.extend( $.fn.dataTable.ext.order, { 25020 * "string-case-asc": function(x,y) { 25021 * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 25022 * }, 25023 * "string-case-desc": function(x,y) { 25024 * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 25025 * } 25026 * } ); 25027 */ 25028 order: {} 25029 }, 25030 25031 /** 25032 * Unique DataTables instance counter 25033 * 25034 * @type int 25035 * @private 25036 */ 25037 _unique: 0, 25038 25039 25040 // 25041 // Depreciated 25042 // The following properties are retained for backwards compatiblity only. 25043 // The should not be used in new projects and will be removed in a future 25044 // version 25045 // 25046 25047 /** 25048 * Version check function. 25049 * @type function 25050 * @depreciated Since 1.10 25051 */ 25052 fnVersionCheck: DataTable.fnVersionCheck, 25053 25054 25055 /** 25056 * Index for what 'this' index API functions should use 25057 * @type int 25058 * @deprecated Since v1.10 25059 */ 25060 iApiIndex: 0, 25061 25062 25063 /** 25064 * jQuery UI class container 25065 * @type object 25066 * @deprecated Since v1.10 25067 */ 25068 oJUIClasses: {}, 25069 25070 25071 /** 25072 * Software version 25073 * @type string 25074 * @deprecated Since v1.10 25075 */
25076 sVersion: DataTable.version 25077 }; 25078 25079 25080 // 25081 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts 25082 // 25083 $.extend( _ext, { 25084 afnFiltering: _ext.search, 25085 aTypes: _ext.type.detect, 25086 ofnSearch: _ext.type.search, 25087 oSort: _ext.type.order, 25088 afnSortData: _ext.order, 25089 aoFeatures: _ext.feature, 25090 oApi: _ext.internal, 25091 oStdClasses: _ext.classes, 25092 oPagination: _ext.pager 25093 } ); 25094 25095 25096 $.extend( DataTable.ext.classes, { 25097 "sTable": "dataTable", 25098 "sNoFooter": "no-footer", 25099 25100 /* Paging buttons */ 25101 "sPageButton": "paginate_button", 25102 "sPageButtonActive": "current", 25103 "sPageButtonDisabled": "disabled", 25104 25105 /* Striping classes */ 25106 "sStripeOdd": "odd", 25107 "sStripeEven": "even", 25108 25109 /* Empty row */ 25110 "sRowEmpty": "dataTables_empty", 25111 25112 /* Features */ 25113 "sWrapper": "dataTables_wrapper", 25114 "sFilter": "dataTables_filter", 25115 "sInfo": "dataTables_info", 25116 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */ 25117 "sLength": "dataTables_length", 25118 "sProcessing": "dataTables_processing", 25119 25120 /* Sorting */ 25121 "sSortAsc": "sorting_asc", 25122 "sSortDesc": "sorting_desc", 25123 "sSortable": "sorting", /* Sortable in both directions */ 25124 "sSortableAsc": "sorting_asc_disabled", 25125 "sSortableDesc": "sorting_desc_disabled", 25126 "sSortableNone": "sorting_disabled", 25127 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */ 25128 25129 /* Filtering */ 25130 "sFilterInput": "", 25131 25132 /* Page length */ 25133 "sLengthSelect": "", 25134 25135 /* Scrolling */ 25136 "sScrollWrapper": "dataTables_scroll", 25137 "sScrollHead": "dataTables_scrollHead", 25138 "sScrollHeadInner": "dataTables_scrollHeadInner", 25139 "sScrollBody": "dataTables_scrollBody", 25140 "sScrollFoot": "dataTables_scrollFoot", 25141 "sScrollFootInner": "dataTables_scrollFootInner", 25142 25143 /* Misc */ 25144 "sHeaderTH": "", 25145 "sFooterTH": "", 25146 25147 // Deprecated 25148 "sSortJUIAsc": "", 25149 "sSortJUIDesc": "", 25150 "sSortJUI": "", 25151 "sSortJUIAscAllowed": "", 25152 "sSortJUIDescAllowed": "", 25153 "sSortJUIWrapper": "", 25154 "sSortIcon": "", 25155 "sJUIHeader": "", 25156 "sJUIFooter": "" 25157 } ); 25158 25159 25160 (function() { 25161 25162 // Reused strings for better compression. Closure compiler appears to have a 25163 // weird edge case where it is trying to expand strings rather than use the 25164 // variable version. This results in about 200 bytes being added, for very 25165 // little preference benefit since it this run on script load only. 25166 var _empty = ''; 25167 _empty = ''; 25168 25169 var _stateDefault = _empty + 'ui-state-default'; 25170 var _sortIcon = _empty + 'css_right ui-icon ui-icon-'; 25171 var _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix'; 25172 25173 $.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, { 25174 /* Full numbers paging buttons */ 25175 "sPageButton": "fg-button ui-button "+_stateDefault, 25176 "sPageButtonActive": "ui-state-disabled", 25177 "sPageButtonDisabled": "ui-state-disabled", 25178 25179 /* Features */ 25180 "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+ 25181 "ui-buttonset-multi paging_", /* Note that the type is postfixed */ 25182 25183 /* Sorting */ 25184 "sSortAsc": _stateDefault+" sorting_asc", 25185 "sSortDesc": _stateDefault+" sorting_desc", 25186 "sSortable": _stateDefault+" sorting", 25187 "sSortableAsc": _stateDefault+" sorting_asc_disabled", 25188 "sSortableDesc": _stateDefault+" sorting_desc_disabled", 25189 "sSortableNone": _stateDefault+" sorting_disabled", 25190 "sSortJUIAsc": _sortIcon+"triangle-1-n", 25191 "sSortJUIDesc": _sortIcon+"triangle-1-s", 25192 "sSortJUI": _sortIcon+"carat-2-n-s", 25193 "sSortJUIAscAllowed": _sortIcon+"carat-1-n", 25194 "sSortJUIDescAllowed": _sortIcon+"carat-1-s", 25195 "sSortJUIWrapper": "DataTables_sort_wrapper", 25196 "sSortIcon": "DataTables_sort_icon", 25197 25198 /* Scrolling */ 25199 "sScrollHead": "dataTables_scrollHead "+_stateDefault, 25200 "sScrollFoot": "dataTables_scrollFoot "+_stateDefault, 25201 25202 /* Misc */ 25203 "sHeaderTH": _stateDefault, 25204 "sFooterTH": _stateDefault, 25205 "sJUIHeader": _headerFooter+" ui-corner-tl ui-corner-tr", 25206 "sJUIFooter": _headerFooter+" ui-corner-bl ui-corner-br" 25207 } ); 25208 25209 }()); 25210 25211 25212 25213 var extPagination = DataTable.ext.pager; 25214 25215 function _numbers ( page, pages ) { 25216 var 25217 numbers = [], 25218 buttons = extPagination.numbers_length, 25219 half = Math.floor( buttons / 2 ), 25220 i = 1; 25221 25222 if ( pages <= buttons ) { 25223 numbers = _range( 0, pages ); 25224 } 25225 else if ( page <= half ) { 25226 numbers = _range( 0, buttons-2 ); 25227 numbers.push( 'ellipsis' ); 25228 numbers.push( pages-1 ); 25229 } 25230 else if ( page >= pages - 1 - half ) { 25231 numbers = _range( pages-(buttons-2), pages ); 25232 numbers.splice( 0, 0, 'ellipsis' );
25232 // no unshift in ie6 25233 numbers.splice( 0, 0, 0 ); 25234 } 25235 else { 25236 numbers = _range( page-half+2, page+half-1 ); 25237 numbers.push( 'ellipsis' ); 25238 numbers.push( pages-1 ); 25239 numbers.splice( 0, 0, 'ellipsis' ); 25240 numbers.splice( 0, 0, 0 ); 25241 } 25242 25243 numbers.DT_el = 'span'; 25244 return numbers; 25245 } 25246 25247 25248 $.extend( extPagination, { 25249 simple: function ( page, pages ) { 25250 return [ 'previous', 'next' ]; 25251 }, 25252 25253 full: function ( page, pages ) { 25254 return [ 'first', 'previous', 'next', 'last' ]; 25255 }, 25256 25257 numbers: function ( page, pages ) { 25258 return [ _numbers(page, pages) ]; 25259 }, 25260 25261 simple_numbers: function ( page, pages ) { 25262 return [ 'previous', _numbers(page, pages), 'next' ]; 25263 }, 25264 25265 full_numbers: function ( page, pages ) { 25266 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ]; 25267 }, 25268 25269 // For testing and plug-ins to use 25270 _numbers: _numbers, 25271 25272 // Number of number buttons (including ellipsis) to show. _Must be odd!_ 25273 numbers_length: 7 25274 } ); 25275 25276 25277 $.extend( true, DataTable.ext.renderer, { 25278 pageButton: { 25279 _: function ( settings, host, idx, buttons, page, pages ) { 25280 var classes = settings.oClasses; 25281 var lang = settings.oLanguage.oPaginate; 25282 var aria = settings.oLanguage.oAria.paginate || {}; 25283 var btnDisplay, btnClass, counter=0; 25284 25285 var attach = function( container, buttons ) { 25286 var i, ien, node, button; 25287 var clickHandler = function ( e ) { 25288 _fnPageChange( settings, e.data.action, true ); 25289 }; 25290 25291 for ( i=0, ien=buttons.length ; i<ien ; i++ ) { 25292 button = buttons[i]; 25293 25294 if ( $.isArray( button ) ) { 25295 var inner = $( '<'+(button.DT_el || 'div')+'/>' ) 25296 .appendTo( container ); 25297 attach( inner, button ); 25298 } 25299 else { 25300 btnDisplay = null; 25301 btnClass = ''; 25302 25303 switch ( button ) { 25304 case 'ellipsis': 25305 container.append('<span class="ellipsis">…</span>'); 25306 break; 25307 25308 case 'first': 25309 btnDisplay = lang.sFirst; 25310 btnClass = button + (page > 0 ? 25311 '' : ' '+classes.sPageButtonDisabled); 25312 break; 25313 25314 case 'previous': 25315 btnDisplay = lang.sPrevious; 25316 btnClass = button + (page > 0 ? 25317 '' : ' '+classes.sPageButtonDisabled); 25318 break; 25319 25320 case 'next': 25321 btnDisplay = lang.sNext; 25322 btnClass = button + (page < pages-1 ? 25323 '' : ' '+classes.sPageButtonDisabled); 25324 break; 25325 25326 case 'last': 25327 btnDisplay = lang.sLast; 25328 btnClass = button + (page < pages-1 ? 25329 '' : ' '+classes.sPageButtonDisabled); 25330 break; 25331 25332 default: 25333 btnDisplay = button + 1; 25334 btnClass = page === button ? 25335 classes.sPageButtonActive : ''; 25336 break; 25337 } 25338 25339 if ( btnDisplay !== null ) { 25340 node = $('<a>', { 25341 'class': classes.sPageButton+' '+btnClass, 25342 'aria-controls': settings.sTableId, 25343 'aria-label': aria[ button ], 25344 'data-dt-idx': counter, 25345 'tabindex': settings.iTabIndex, 25346 'id': idx === 0 && typeof button === 'string' ? 25347 settings.sTableId +'_'+ button : 25348 null 25349 } ) 25350 .html( btnDisplay ) 25351 .appendTo( container ); 25352 25353 _fnBindAction( 25354 node, {action: button}, clickHandler 25355 ); 25356 25357 counter++; 25358 } 25359 } 25360 } 25361 }; 25362 25363 // IE9 throws an 'unknown error' if document.activeElement is used 25364 // inside an iframe or frame. Try / catch the error. Not good for 25365 // accessibility, but neither are frames. 25366 var activeEl; 25367 25368 try { 25369 // Because this approach is destroying and recreating the paging 25370 // elements, focus is lost on the select button which is bad for 25371 // accessibility. So we want to restore focus once the draw has 25372 // completed 25373 activeEl = $(host).find(document.activeElement).data('dt-idx'); 25374 } 25375 catch (e) {} 25376 25377 attach( $(host).empty(), buttons ); 25378 25379 if ( activeEl ) { 25380 $(host).find( '[data-dt-idx='+activeEl+']' ).focus(); 25381 } 25382 } 25383 } 25384 } ); 25385 25386 25387 25388 // Built in type detection. See model.ext.aTypes for information about 25389 // what is required from this methods. 25390 $.extend( DataTable.ext.type.detect, [
vendor: 18,135 bytes, lines 25391-25968
25391 // Plain numbers - first since V8 detects some plain numbers as dates 25392 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...). 25393 function ( d, settings ) 25394 { 25395 var decimal = settings.oLanguage.sDecimal; 25396 return _isNumber( d, decimal ) ? 'num'+decimal : null; 25397 }, 25398 25399 // Dates (only those recognised by the browser's Date.parse) 25400 function ( d, settings ) 25401 { 25402 // V8 will remove any unknown characters at the start and end of the 25403 // expression, leading to false matches such as `$245.12` or `10%` being 25404 // a valid date. See forum thread 18941 for detail. 25405 if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) { 25406 return null; 25407 } 25408 var parsed = Date.parse(d); 25409 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null; 25410 }, 25411 25412 // Formatted numbers 25413 function ( d, settings ) 25414 { 25415 var decimal = settings.oLanguage.sDecimal; 25416 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null; 25417 }, 25418 25419 // HTML numeric 25420 function ( d, settings ) 25421 { 25422 var decimal = settings.oLanguage.sDecimal; 25423 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null; 25424 }, 25425 25426 // HTML numeric, formatted 25427 function ( d, settings ) 25428 { 25429 var decimal = settings.oLanguage.sDecimal; 25430 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null; 25431 }, 25432 25433 // HTML (this is strict checking - there must be html) 25434 function ( d, settings ) 25435 { 25436 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ? 25437 'html' : null; 25438 } 25439 ] ); 25440 25441 25442 25443 // Filter formatting functions. See model.ext.ofnSearch for information about 25444 // what is required from these methods. 25445 // 25446 // Note that additional search methods are added for the html numbers and 25447 // html formatted numbers by `_addNumericSort()` when we know what the decimal 25448 // place is 25449 25450 25451 $.extend( DataTable.ext.type.search, { 25452 html: function ( data ) { 25453 return _empty(data) ? 25454 data : 25455 typeof data === 'string' ? 25456 data 25457 .replace( _re_new_lines, " " ) 25458 .replace( _re_html, "" ) : 25459 ''; 25460 }, 25461 25462 string: function ( data ) { 25463 return _empty(data) ? 25464 data : 25465 typeof data === 'string' ? 25466 data.replace( _re_new_lines, " " ) : 25467 data; 25468 } 25469 } ); 25470 25471 25472 25473 var __numericReplace = function ( d, decimalPlace, re1, re2 ) { 25474 if ( d !== 0 && (!d || d === '-') ) { 25475 return -Infinity; 25476 } 25477 25478 // If a decimal place other than `.` is used, it needs to be given to the 25479 // function so we can detect it and replace with a `.` which is the only 25480 // decimal place Javascript recognises - it is not locale aware. 25481 if ( decimalPlace ) { 25482 d = _numToDecimal( d, decimalPlace ); 25483 } 25484 25485 if ( d.replace ) { 25486 if ( re1 ) { 25487 d = d.replace( re1, '' ); 25488 } 25489 25490 if ( re2 ) { 25491 d = d.replace( re2, '' ); 25492 } 25493 } 25494 25495 return d * 1; 25496 }; 25497 25498 25499 // Add the numeric 'deformatting' functions for sorting and search. This is done 25500 // in a function to provide an easy ability for the language options to add 25501 // additional methods if a non-period decimal place is used. 25502 function _addNumericSort ( decimalPlace ) { 25503 $.each( 25504 { 25505 // Plain numbers 25506 "num": function ( d ) { 25507 return __numericReplace( d, decimalPlace ); 25508 }, 25509 25510 // Formatted numbers 25511 "num-fmt": function ( d ) { 25512 return __numericReplace( d, decimalPlace, _re_formatted_numeric ); 25513 }, 25514 25515 // HTML numeric 25516 "html-num": function ( d ) { 25517 return __numericReplace( d, decimalPlace, _re_html ); 25518 }, 25519 25520 // HTML numeric, formatted 25521 "html-num-fmt": function ( d ) { 25522 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric ); 25523 } 25524 }, 25525 function ( key, fn ) { 25526 // Add the ordering method 25527 _ext.type.order[ key+decimalPlace+'-pre' ] = fn; 25528 25529 // For HTML types add a search formatter that will strip the HTML 25530 if ( key.match(/^html\-/) ) { 25531 _ext.type.search[ key+decimalPlace ] = _ext.type.search.html; 25532 } 25533 } 25534 ); 25535 } 25536 25537 25538 // Default sort methods 25539 $.extend( _ext.type.order, { 25540 // Dates 25541 "date-pre": function ( d ) { 25542 return Date.parse( d ) || 0; 25543 }, 25544 25545 // html 25546 "html-pre": function ( a ) { 25547 return _empty(a) ? 25548 '' : 25549 a.replace ? 25550 a.replace( /<.*?>/g, "" ).toLowerCase() : 25551 a+''; 25552 }, 25553 25554 // string 25555 "string-pre": function ( a ) { 25556 // This is a little complex, but faster than always calling toString, 25557 // http://jsperf.com/tostring-v-check 25558 return _empty(a) ? 25559 '' : 25560 typeof a === 'string' ? 25561 a.toLowerCase() : 25562 ! a.toString ? 25563 '' : 25564 a.toString(); 25565 }, 25566 25567 // string-asc and -desc are retained only for compatibility with the old 25568 // sort methods 25569 "string-asc": function ( x, y ) { 25570 return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 25571 }, 25572 25573 "string-desc": function ( x, y ) { 25574 return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 25575 } 25576 } ); 25577 25578 25579 // Numeric sorting types - order doesn't matter here 25580 _addNumericSort( '' ); 25581 25582 25583 $.extend( true, DataTable.ext.renderer, { 25584 header: { 25585 _: function ( settings, cell, column, classes ) { 25586 // No additional mark-up required 25587 // Attach a sort listener to update on sort - note that using the 25588 // `DT` namespace will allow the event to be removed automatically 25589 // on destroy, while the `dt` namespaced event is the one we are 25590 // listening for 25591 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { 25592 if ( settings !== ctx ) { // need to check this this is the host 25593 return; // table, not a nested one 25594 } 25595 25596 var colIdx = column.idx; 25597 25598 cell 25599 .removeClass( 25600 column.sSortingClass +' '+ 25601 classes.sSortAsc +' '+ 25602 classes.sSortDesc 25603 ) 25604 .addClass( columns[ colIdx ] == 'asc' ? 25605 classes.sSortAsc : columns[ colIdx ] == 'desc' ? 25606 classes.sSortDesc : 25607 column.sSortingClass 25608 ); 25609 } ); 25610 }, 25611 25612 jqueryui: function ( settings, cell, column, classes ) { 25613 $('<div/>') 25614 .addClass( classes.sSortJUIWrapper ) 25615 .append( cell.contents() ) 25616 .append( $('<span/>') 25617 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI ) 25618 ) 25619 .appendTo( cell ); 25620 25621 // Attach a sort listener to update on sort 25622 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { 25623 if ( settings !== ctx ) { 25624 return; 25625 } 25626 25627 var colIdx = column.idx; 25628 25629 cell 25630 .removeClass( classes.sSortAsc +" "+classes.sSortDesc ) 25631 .addClass( columns[ colIdx ] == 'asc' ? 25632 classes.sSortAsc : columns[ colIdx ] == 'desc' ? 25633 classes.sSortDesc : 25634 column.sSortingClass 25635 ); 25636 25637 cell 25638 .find( 'span.'+classes.sSortIcon ) 25639 .removeClass( 25640 classes.sSortJUIAsc +" "+ 25641 classes.sSortJUIDesc +" "+ 25642 classes.sSortJUI +" "+ 25643 classes.sSortJUIAscAllowed +" "+ 25644 classes.sSortJUIDescAllowed 25645 ) 25646 .addClass( columns[ colIdx ] == 'asc' ? 25647 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ? 25648 classes.sSortJUIDesc : 25649 column.sSortingClassJUI 25650 ); 25651 } ); 25652 } 25653 } 25654 } ); 25655 25656 /* 25657 * Public helper functions. These aren't used internally by DataTables, or 25658 * called by any of the options passed into DataTables, but they can be used 25659 * externally by developers working with DataTables. They are helper functions 25660 * to make working with DataTables a little bit easier. 25661 */ 25662 25663 var __htmlEscapeEntities = function ( d ) { 25664 return typeof d === 'string' ? 25665 d.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"') : 25666 d; 25667 }; 25668 25669 /** 25670 * Helpers for `columns.render`. 25671 * 25672 * The options defined here can be used with the `columns.render` initialisation 25673 * option to provide a display renderer. The following functions are defined: 25674 * 25675 * * `number` - Will format numeric data (defined by `columns.data`) for 25676 * display, retaining the original unformatted data for sorting and filtering. 25677 * It takes 5 parameters: 25678 * * `string` - Thousands grouping separator 25679 * * `string` - Decimal point indicator 25680 * * `integer` - Number of decimal points to show 25681 * * `string` (optional) - Prefix. 25682 * * `string` (optional) - Postfix (/suffix). 25683 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional 25684 * parameters. 25685 * 25686 * @example 25687 * // Column definition using the number renderer 25688 * { 25689 * data: "salary", 25690 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' ) 25691 * } 25692 * 25693 * @namespace 25694 */ 25695 DataTable.render = { 25696 number: function ( thousands, decimal, precision, prefix, postfix ) { 25697 return { 25698 display: function ( d ) { 25699 if ( typeof d !== 'number' && typeof d !== 'string' ) { 25700 return d; 25701 } 25702 25703 var negative = d < 0 ? '-' : ''; 25704 var flo = parseFloat( d ); 25705 25706 // If NaN then there isn't much formatting that we can do - just 25707 // return immediately, escaping any HTML (this was supposed to 25708 // be a number after all) 25709 if ( isNaN( flo ) ) { 25710 return __htmlEscapeEntities( d ); 25711 } 25712 25713 d = Math.abs( flo ); 25714 25715 var intPart = parseInt( d, 10 ); 25716 var floatPart = precision ? 25717 decimal+(d - intPart).toFixed( precision ).substring( 2 ): 25718 ''; 25719 25720 return negative + (prefix||'') + 25721 intPart.toString().replace( 25722 /\B(?=(\d{3})+(?!\d))/g, thousands 25723 ) + 25724 floatPart + 25725 (postfix||''); 25726 } 25727 }; 25728 }, 25729 25730 text: function () { 25731 return { 25732 display: __htmlEscapeEntities 25733 }; 25734 } 25735 }; 25736 25737 25738 /* 25739 * This is really a good bit rubbish this method of exposing the internal methods 25740 * publicly... - To be fixed in 2.0 using methods on the prototype 25741 */ 25742 25743 25744 /** 25745 * Create a wrapper function for exporting an internal functions to an external API. 25746 * @param {string} fn API function name 25747 * @returns {function} wrapped function 25748 * @memberof DataTable#internal 25749 */ 25750 function _fnExternApiFunc (fn) 25751 { 25752 return function() { 25753 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat( 25754 Array.prototype.slice.call(arguments) 25755 ); 25756 return DataTable.ext.internal[fn].apply( this, args ); 25757 }; 25758 } 25759 25760 25761 /** 25762 * Reference to internal functions for use by plug-in developers. Note that 25763 * these methods are references to internal functions and are considered to be 25764 * private. If you use these methods, be aware that they are liable to change 25765 * between versions. 25766 * @namespace 25767 */ 25768 $.extend( DataTable.ext.internal, { 25769 _fnExternApiFunc: _fnExternApiFunc, 25770 _fnBuildAjax: _fnBuildAjax, 25771 _fnAjaxUpdate: _fnAjaxUpdate, 25772 _fnAjaxParameters: _fnAjaxParameters, 25773 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw, 25774 _fnAjaxDataSrc: _fnAjaxDataSrc, 25775 _fnAddColumn: _fnAddColumn, 25776 _fnColumnOptions: _fnColumnOptions, 25777 _fnAdjustColumnSizing: _fnAdjustColumnSizing, 25778 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex, 25779 _fnColumnIndexToVisible: _fnColumnIndexToVisible, 25780 _fnVisbleColumns: _fnVisbleColumns, 25781 _fnGetColumns: _fnGetColumns, 25782 _fnColumnTypes: _fnColumnTypes, 25783 _fnApplyColumnDefs: _fnApplyColumnDefs, 25784 _fnHungarianMap: _fnHungarianMap, 25785 _fnCamelToHungarian: _fnCamelToHungarian, 25786 _fnLanguageCompat: _fnLanguageCompat, 25787 _fnBrowserDetect: _fnBrowserDetect, 25788 _fnAddData: _fnAddData, 25789 _fnAddTr: _fnAddTr, 25790 _fnNodeToDataIndex: _fnNodeToDataIndex, 25791 _fnNodeToColumnIndex: _fnNodeToColumnIndex, 25792 _fnGetCellData: _fnGetCellData, 25793 _fnSetCellData: _fnSetCellData, 25794 _fnSplitObjNotation: _fnSplitObjNotation, 25795 _fnGetObjectDataFn: _fnGetObjectDataFn, 25796 _fnSetObjectDataFn: _fnSetObjectDataFn, 25797 _fnGetDataMaster: _fnGetDataMaster, 25798 _fnClearTable: _fnClearTable, 25799 _fnDeleteIndex: _fnDeleteIndex, 25800 _fnInvalidate: _fnInvalidate, 25801 _fnGetRowElements: _fnGetRowElements, 25802 _fnCreateTr: _fnCreateTr, 25803 _fnBuildHead: _fnBuildHead, 25804 _fnDrawHead: _fnDrawHead, 25805 _fnDraw: _fnDraw, 25806 _fnReDraw: _fnReDraw, 25807 _fnAddOptionsHtml: _fnAddOptionsHtml, 25808 _fnDetectHeader: _fnDetectHeader, 25809 _fnGetUniqueThs: _fnGetUniqueThs, 25810 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter, 25811 _fnFilterComplete: _fnFilterComplete, 25812 _fnFilterCustom: _fnFilterCustom, 25813 _fnFilterColumn: _fnFilterColumn, 25814 _fnFilter: _fnFilter, 25815 _fnFilterCreateSearch: _fnFilterCreateSearch, 25816 _fnEscapeRegex: _fnEscapeRegex, 25817 _fnFilterData: _fnFilterData, 25818 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo, 25819 _fnUpdateInfo: _fnUpdateInfo, 25820 _fnInfoMacros: _fnInfoMacros, 25821 _fnInitialise: _fnInitialise, 25822 _fnInitComplete: _fnInitComplete, 25823 _fnLengthChange: _fnLengthChange, 25824 _fnFeatureHtmlLength: _fnFeatureHtmlLength, 25825 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate, 25826 _fnPageChange: _fnPageChange, 25827 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing, 25828 _fnProcessingDisplay: _fnProcessingDisplay, 25829 _fnFeatureHtmlTable: _fnFeatureHtmlTable, 25830 _fnScrollDraw: _fnScrollDraw, 25831 _fnApplyToChildren: _fnApplyToChildren, 25832 _fnCalculateColumnWidths: _fnCalculateColumnWidths, 25833 _fnThrottle: _fnThrottle, 25834 _fnConvertToWidth: _fnConvertToWidth, 25835 _fnGetWidestNode: _fnGetWidestNode, 25836 _fnGetMaxLenString: _fnGetMaxLenString, 25837 _fnStringToCss: _fnStringToCss, 25838 _fnSortFlatten: _fnSortFlatten, 25839 _fnSort: _fnSort, 25840 _fnSortAria: _fnSortAria, 25841 _fnSortListener: _fnSortListener, 25842 _fnSortAttachListener: _fnSortAttachListener, 25843 _fnSortingClasses: _fnSortingClasses, 25844 _fnSortData: _fnSortData, 25845 _fnSaveState: _fnSaveState, 25846 _fnLoadState: _fnLoadState, 25847 _fnSettingsFromNode: _fnSettingsFromNode, 25848 _fnLog: _fnLog, 25849 _fnMap: _fnMap, 25850 _fnBindAction: _fnBindAction, 25851 _fnCallbackReg: _fnCallbackReg, 25852 _fnCallbackFire: _fnCallbackFire, 25853 _fnLengthOverflow: _fnLengthOverflow, 25854 _fnRenderer: _fnRenderer, 25855 _fnDataSource: _fnDataSource, 25856 _fnRowAttributes: _fnRowAttributes, 25857 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant 25858 // in 1.10, so this dead-end function is 25859 // added to prevent errors 25860 } ); 25861 25862 // jQuery access 25863 $.fn.dataTable = DataTable; 25864 // Provide access to the host jQuery object (circular reference) 25865 DataTable.$ = $; 25866 // Legacy aliases 25867 $.fn.dataTableSettings = DataTable.settings; 25868 $.fn.dataTableExt = DataTable.ext; 25869 // With a capital `D` we return a DataTables API instance rather than a 25870 // jQuery object 25871 $.fn.DataTable = function ( opts ) { 25872 return $(this).dataTable( opts ).api(); 25873 }; 25874 // All properties that are available to $.fn.dataTable should also be 25875 // available on $.fn.DataTable 25876 $.each( DataTable, function ( prop, val ) { 25877 $.fn.DataTable[ prop ] = val; 25878 } ); 25879 // Information about events fired by DataTables - for documentation. 25880 /** 25881 * Draw event, fired whenever the table is redrawn on the page, at the same 25882 * point as fnDrawCallback. This may be useful for binding events or 25883 * performing calculations when the table is altered at all. 25884 * @name DataTable#draw.dt 25885 * @event 25886 * @param {event} e jQuery event object 25887 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 25888 */ 25889 /** 25890 * Search event, fired when the searching applied to the table (using the 25891 * built-in global search, or column filters) is altered. 25892 * @name DataTable#search.dt 25893 * @event 25894 * @param {event} e jQuery event object 25895 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 25896 */ 25897 /** 25898 * Page change event, fired when the paging of the table is altered. 25899 * @name DataTable#page.dt 25900 * @event 25901 * @param {event} e jQuery event object 25902 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 25903 */ 25904 /** 25905 * Order event, fired when the ordering applied to the table is altered. 25906 * @name DataTable#order.dt 25907 * @event 25908 * @param {event} e jQuery event object 25909 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 25910 */ 25911 /** 25912 * DataTables initialisation complete event, fired when the table is fully 25913 * drawn, including Ajax data loaded, if Ajax data is required. 25914 * @name DataTable#init.dt 25915 * @event 25916 * @param {event} e jQuery event object 25917 * @param {object} oSettings DataTables settings object 25918 * @param {object} json The JSON object request from the server - only 25919 * present if client-side Ajax sourced data is used</li></ol> 25920 */ 25921 /** 25922 * State save event, fired when the table has changed state a new state save 25923 * is required. This event allows modification of the state saving object 25924 * prior to actually doing the save, including addition or other state 25925 * properties (for plug-ins) or modification of a DataTables core property. 25926 * @name DataTable#stateSaveParams.dt 25927 * @event 25928 * @param {event} e jQuery event object 25929 * @param {object} oSettings DataTables settings object 25930 * @param {object} json The state information to be saved 25931 */ 25932 /** 25933 * State load event, fired when the table is loading state from the stored 25934 * data, but prior to the settings object being modified by the saved state 25935 * - allowing modification of the saved state is required or loading of 25936 * state for a plug-in. 25937 * @name DataTable#stateLoadParams.dt 25938 * @event 25939 * @param {event} e jQuery event object 25940 * @param {object} oSettings DataTables settings object 25941 * @param {object} json The saved state information 25942 */ 25943 /** 25944 * State loaded event, fired when state has been loaded from stored data and 25945 * the settings object has been modified by the loaded data. 25946 * @name DataTable#stateLoaded.dt 25947 * @event 25948 * @param {event} e jQuery event object 25949 * @param {object} oSettings DataTables settings object 25950 * @param {object} json The saved state information 25951 */ 25952 /** 25953 * Processing event, fired when DataTables is doing some kind of processing 25954 * (be it, order, searcg or anything else). It can be used to indicate to 25955 * the end user that there is something happening, or that something has 25956 * finished. 25957 * @name DataTable#processing.dt 25958 * @event 25959 * @param {event} e jQuery event object 25960 * @param {object} oSettings DataTables settings object 25961 * @param {boolean} bShow Flag for if DataTables is doing processing or not 25962 */ 25963 /** 25964 * Ajax (XHR) event, fired whenever an Ajax request is completed from a 25965 * request to made to the server for new data. This event is called before 25966 * DataTables processed the returned data, so it can also be used to pre- 25967 * process the data returned from the server, if needed. 25968 *
25969 * Note that this trigger is called in `fnServerData`, if you override 25970 * `fnServerData` and which to use this event, you need to trigger it in you 25971 * success function. 25972 * @name DataTable#xhr.dt 25973 * @event 25974 * @param {event} e jQuery event object 25975 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 25976 * @param {object} json JSON returned from the server 25977 * 25978 * @example 25979 * // Use a custom property returned from the server in another DOM element 25980 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) { 25981 * $('#status').html( json.status ); 25982 * } ); 25983 * 25984 * @example 25985 * // Pre-process the data returned from the server 25986 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) { 25987 * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) { 25988 * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two; 25989 * } 25990 * // Note no return - manipulate the data directly in the JSON object. 25991 * } ); 25992 */ 25993 /** 25994 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy 25995 * or passing the bDestroy:true parameter in the initialisation object. This 25996 * can be used to remove bound events, added DOM nodes, etc. 25997 * @name DataTable#destroy.dt 25998 * @event 25999 * @param {event} e jQuery event object 26000 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 26001 */ 26002 /** 26003 * Page length change event, fired when number of records to show on each 26004 * page (the length) is changed. 26005 * @name DataTable#length.dt 26006 * @event 26007 * @param {event} e jQuery event object 26008 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 26009 * @param {integer} len New length 26010 */ 26011 /** 26012 * Column sizing has changed. 26013 * @name DataTable#column-sizing.dt 26014 * @event 26015 * @param {event} e jQuery event object 26016 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 26017 */ 26018 /** 26019 * Column visibility has changed. 26020 * @name DataTable#column-visibility.dt 26021 * @event 26022 * @param {event} e jQuery event object 26023 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 26024 * @param {int} column Column index 26025 * @param {bool} vis `false` if column now hidden, or `true` if visible 26026 */ 26027 return $.fn.dataTable; 26028})); 26029 26030 /* Ende jquery.datatables */ 26031 /* Start jquery.cookie */ 26032 /*! 26033 * jQuery Cookie Plugin v1.4.1 26034 * https://github.com/carhartl/jquery-cookie 26035 * 26036 * Copyright 2013 Klaus Hartl 26037 * Released under the MIT license 26038 */ 26039(function (factory) { 26040 if (typeof define === 'function' && define.amd) { 26041 // AMD 26042 define(['jquery'], factory); 26043 } else if (typeof exports === 'object') { 26044 // CommonJS 26045 factory(require('jquery')); 26046 } else { 26047 // Browser globals 26048 factory(jQuery); 26049 } 26050}(function ($) { 26051 26052 var pluses = /\+/g; 26053 26054 function encode(s) { 26055 return config.raw ? s : encodeURIComponent(s); 26056 } 26057 26058 function decode(s) { 26059 return config.raw ? s : decodeURIComponent(s); 26060 } 26061 26062 function stringifyCookieValue(value) { 26063 return encode(config.json ? JSON.stringify(value) : String(value)); 26064 } 26065 26066 function parseCookieValue(s) { 26067 if (s.indexOf('"') === 0) { 26068 // This is a quoted cookie as according to RFC2068, unescape... 26069 s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); 26070 } 26071 26072 try { 26073 // Replace server-side written pluses with spaces. 26074 // If we can't decode the cookie, ignore it, it's unusable. 26075 // If we can't parse the cookie, ignore it, it's unusable. 26076 s = decodeURIComponent(s.replace(pluses, ' ')); 26077 return config.json ? JSON.parse(s) : s; 26078 } catch(e) {} 26079 } 26080 26081 function read(s, converter) { 26082 var value = config.raw ? s : parseCookieValue(s); 26083 return $.isFunction(converter) ? converter(value) : value; 26084 } 26085 26086 var config = $.cookie = function (key, value, options) { 26087 26088 // Write 26089 26090 if (value !== undefined && !$.isFunction(value)) { 26091 options = $.extend({}, config.defaults, options); 26092 26093 if (typeof options.expires === 'number') { 26094 var days = options.expires, t = options.expires = new Date(); 26095 t.setTime(+t + days * 864e+5); 26096 } 26097 26098 return (document.cookie = [ 26099 encode(key), '=', stringifyCookieValue(value), 26100 options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE 26101 options.path ? '; path=' + options.path : '', 26102 options.domain ? '; domain=' + options.domain : '', 26103 options.secure ? '; secure' : '' 26104 ].join('')); 26105 } 26106 26107 // Read 26108 26109 var result = key ? undefined : {}; 26110 26111 // To prevent the for loop in the first place assign an empty array 26112 // in case there are no cookies at all. Also prevents odd result when 26113 // calling $.cookie(). 26114 var cookies = document.cookie ? document.cookie.split('; ') : []; 26115 26116 for (var i = 0, l = cookies.length; i < l; i++) { 26117 var parts = cookies[i].split('='); 26118 var name = decode(parts.shift()); 26119 var cookie = parts.join('='); 26120 26121 if (key && key === name) { 26122 // If second argument (value) is a function it's a converter... 26123 result = read(cookie, value); 26124 break; 26125 } 26126 26127 // Prevent storing a cookie that we couldn't decode. 26128 if (!key && (cookie = read(cookie)) !== undefined) { 26129 result[name] = cookie; 26130 } 26131 } 26132 26133 return result; 26134 }; 26135 26136 config.defaults = {}; 26137 26138 $.removeCookie = function (key, options) { 26139 if ($.cookie(key) === undefined) { 26140 return false;
26141 } 26142 26143 // Must not alter options, thus extending a fresh object... 26144 $.cookie(key, '', $.extend({}, options, { expires: -1 })); 26145 return !$.cookie(key); 26146 }; 26147 26148})); 26149 /* Ende jquery.cookie */ 26150 /* Start gsb_responsiveListener */ 26151 /*! 26152 * @name responsiveListener 26153 * @author @anuebel/pespeloe 26154 * Licensed under the MIT license 26155 * 26156 * Callback function je Breakpoint 26157 * */ 26158; 26159(function ($) { 26160 if (!$.gsb) { 26161 $.gsb = {}; 26162 } 26163 ; 26164 26165 $.gsb.responsiveListener = function (pluginBase) { 26166 var base = this; 26167 this.base = base; 26168 this.pluginBase = pluginBase; 26169 26170 // Add a reverse reference to the DOM object 26171 this.base.breakpoints = []; 26172 this.base.breakpointSettings = []; 26173 this.base.activeBreakpoint = null; 26174 this.base.windowWidth = 0; 26175 26176 base.init = function () { 26177 //Da die Lib keine eigenen Options hat, Options vom Plugin holen 26178 base.options = pluginBase.options; 26179 base.originalOptions = base.options; 26180 this.base.options = base.options; 26181 this.base.originalOptions = base.originalOptions; 26182 base.initResponsive(); 26183 base.checkResponsive(); 26184 if (base.options.respondToEvents === true) { 26185 base.initEvents(); 26186 } 26187 }; 26188 26189 26190 /** 26191 * Initialisiert die Events. 26192 */ 26193 $.gsb.responsiveListener.prototype.initEvents = function () { 26194 var $window = $(window), 26195 onResize = function () { 26196 if ($(window).width() !== base.windowWidth) { 26197 clearTimeout(base.windowDelay); 26198 base.windowDelay = window.setTimeout(function () { 26199 base.windowWidth = $(window).width(); 26200 base.checkResponsive(); 26201 }, 100); 26202 } 26203 }; 26204 $window.on('resize', onResize); 26205 $window.on('orientationchange', function () { 26206 base.checkResponsive(); 26207 }); 26208 }; 26209 26210 // Run initializer 26211 base.init(); 26212 }; 26213 26214 26215 /** 26216 * Initialisiert die Datenstrukturen fuer die responsiven Ueberpruefungen. 26217 */ 26218 $.gsb.responsiveListener.prototype.initResponsive = function () { 26219 var breakpoint, 26220 responsiveSettings = this.base.options.responsive || null; 26221 26222 if (responsiveSettings && responsiveSettings.length > -1) { 26223 for (breakpoint in responsiveSettings) { 26224 if (responsiveSettings.hasOwnProperty(breakpoint)) { 26225 this.base.breakpoints.push(responsiveSettings[ 26226 breakpoint].breakpoint); 26227 this.base.breakpointSettings[responsiveSettings[ 26228 breakpoint].breakpoint] = 26229 responsiveSettings[breakpoint]; 26230 } 26231 } 26232 this.base.breakpoints.sort(function (a, b) { 26233 return b - a; 26234 }); 26235 } 26236 }; 26237 26238 26239 /** 26240 * Ueberprueft, ob eine Aenderung der Einstellungen durchgefuehrt werden muss. Dies ist dann der Fall, wenn 26241 * sich die Breite des Viewports(window-Objekt) geaendert hat und mindestens einen der angegebenen Breakpoints 26242 * unterschreitet. Ausschlaggebend fuer die Aenderungen ist der letzte konfigurierte Breakpoint, dessen Breite 26243 * unterschritten wird. 26244 * 26245 */ 26246 $.gsb.responsiveListener.prototype.checkResponsive = function () { 26247 var breakpoint, 26248 targetBreakpoint, 26249 respondToWidth = window.innerWidth || $(window).width(); 26250 26251 if (this.base.originalOptions.responsive && 26252 this.base.originalOptions.responsive.length > -1 && 26253 this.base.originalOptions.responsive !== null) { 26254 26255 targetBreakpoint = null; 26256 26257 if (this.base.activeBreakpoint !== null && respondToWidth >= this.base.breakpoints[0]) { 26258 this.base.activeBreakpoint = null; 26259 this.pluginBase.options = this.base.originalOptions; 26260 } 26261 26262 for (breakpoint in this.base.breakpoints) { 26263 if (this.base.breakpoints.hasOwnProperty(breakpoint)) { 26264 if (respondToWidth < this.base.breakpoints[breakpoint]) { 26265 targetBreakpoint = this.base.breakpoints[breakpoint]; 26266 this.base.highestResolution = false; 26267 } 26268 } 26269 } 26270 26271 if (this.base.highestResolution) { 26272 return; 26273 } 26274 26275 if (targetBreakpoint !== null) { 26276 if (this.base.activeBreakpoint !== null) { 26277 if (targetBreakpoint !== this.base.activeBreakpoint) {
26278 this.base.activeBreakpoint = targetBreakpoint; 26279 this.pluginBase.options = $.extend({}, 26280 this.base.originalOptions, 26281 this.base.breakpointSettings[targetBreakpoint]); 26282 this.base.triggerRefresh(); 26283 } 26284 } else { 26285 this.base.activeBreakpoint = targetBreakpoint; 26286 this.pluginBase.options = $.extend({}, 26287 this.base.originalOptions, 26288 this.base.breakpointSettings[targetBreakpoint]); 26289 this.base.triggerRefresh(); 26290 } 26291 } else { 26292 if (this.base.activeBreakpoint !== null) { 26293 this.base.activeBreakpoint = null; 26294 this.base.options = this.base.originalOptions; 26295 this.base.triggerRefresh(); 26296 } else { 26297 this.base.highestResolution = true; 26298 this.base.triggerRefresh(); 26299 } 26300 } 26301 } else if (this.base.originalOptions.onRefresh && 26302 this.base.originalOptions.onRefresh.length > -1 && 26303 this.base.originalOptions.onRefresh !== null) { 26304 if (this.base.highestResolution) { 26305 return; 26306 } 26307 this.base.triggerRefresh(); 26308 this.base.highestResolution = true; 26309 } 26310 }; 26311 26312 26313 /** 26314 * Loest die Aktualisierung des Scripts aus. 26315 */ 26316 $.gsb.responsiveListener.prototype.triggerRefresh = function () { 26317 if (typeof this.pluginBase.options.onRefresh === 'function') { 26318 this.pluginBase.options.onRefresh.call(this.pluginBase); 26319 } 26320 }; 26321 26322 $.fn.gsb_responsiveListener = function (pluginBase) { 26323 return this.each(function () { 26324 (new $.gsb.responsiveListener(pluginBase)); 26325 }); 26326 }; 26327})(jQuery); 26328 /* Ende gsb_responsiveListener */ 26329 /* Start gsb_ariaSupport */ 26330 /** 26331 * @module ariaSupport 26332 * @version 1.1.0 26333 * @see {@link http://semver.org|Semantic Versioning} 26334 * @author pespeloe 26335 * 26336 * @desc Diese Erweiterung fügt Aria-Support für gsb Plugins hinzu. 26337 * Falls eine Mobulvariante noch nicht verfügbar ist, muss diese als Option hinzugefügt werden (genaueres direkt im Quellcode Kommentar nachzulesen). 26338 * ACHTUNG: Es ist zwingend notwendig unser module-Pattern zu verwenden (ähnlich wie beim responsiveListener) 26339 * 26340 * Das Script wird direkt im Modul konfiguriert. Es müssen folgende Schritte gemacht werden: 26341 * 1. Die Option ariaType muss angegeben werden - also mobilemenu, tab, accordion, lightbox usw. 26342 * 2. Es müssen base.controlPanel und base.contentPanel gesetzt werden - hier direkt Panel (was geklickt wird) und Content (was angezeigt werden soll) 26343 * 3. Nach Aktion (click usw.) funktion base.aria.updateAria() aufrufen (zu übergebende Parameter unten aufgelistet) um Inhalt der WAI-ARIA Attribute zu tauschen 26344 * 26345 * @example 26346 * base.controlPanel = base.menu.find('.mm-vertical > .mm-next'); //Aufklapptpfeil im MMenu 26347 * base.contentPanel = base.menu.find('li > .mm-panel.mm-vertical > ul'); // Ul welches aufgeklappt wird 26348 * 26349 * Innerhalb des click-Events: 26350 * 26351 * //Menü öffnen 26352 * base.aria.updateAria(this, false, true); 26353 * 26354 * //Menu schlieÃen 26355 * base.aria.updateAria(this, true, true); 26356 * 26357 * */ 26358; 26359(function ($) { 26360 if (!$.gsb) { 26361 $.gsb = {}; 26362 } 26363 ; 26364 26365 $.gsb.ariaSupport = function (pluginBase) { 26366 this.base = this; 26367 this.pluginBase = pluginBase; 26368 26369 this.base.init = function () { 26370 //Da die Lib keine eigenen Options hat, Options vom Plugin holen 26371 this.base.options = pluginBase.options; 26372 26373 this.base.ariaOptions = $.extend({}, $.gsb.ariaSupport.defaultOptions, pluginBase.options.ariaSupport) 26374 26375 this.base.originalOptions = this.base.options; 26376 this.base.options = this.base.options; 26377 this.base.originalOptions = this.base.originalOptions; 26378 this.base.initializeAria(); 26379 }; 26380 26381 // Run initializer 26382 this.base.init(); 26383 26384 }; 26385 26386 //*************************************** Verschiedene Aria-Typen initialisieren ************************************/ 26387 /** 26388 * @method initialize 26389 * @desc Initialisierung des Scripts 26390 */ 26391 $.gsb.ariaSupport.prototype.initializeAria = function(){ 26392 var ariaType = this.base.options.ariaType, 26393 base = this.base, 26394 pluginBase= this.pluginBase, 26395 ariaOptions = this.base.ariaOptions; 26396 26397 base.moduleOptions = ariaOptions[ariaType.toUpperCase()]; 26398 base.attributesPanel = ariaOptions[ariaType.toUpperCase()]['panel']; 26399 base.attributesContent = ariaOptions[ariaType.toUpperCase()]['content']; 26400 26401 base.panelToggle = base.setToggleoptions(base.attributesPanel); 26402 base.contentToggle = base.setToggleoptions(base.attributesContent); 26403
26404 pluginBase.controlPanel.get().forEach(function(panel, index){ 26405 var firstOpen = ariaOptions[ariaType.toUpperCase()].firstOpen; 26406 var addAural = ariaOptions[ariaType.toUpperCase()].addAural; 26407 26408 if(firstOpen && index >0){ 26409 firstOpen = false 26410 } 26411 26412 //Attribute fuer Controlpanel setzen 26413 base.setAttributes(panel, base.attributesPanel, index, firstOpen); 26414 26415 //falls aural hinzugefuegt werden soll 26416 if(addAural){ 26417 if(firstOpen){ 26418 base.addAural(panel, true); 26419 }else{ 26420 base.addAural(panel, false); 26421 } 26422 } 26423 26424 //Atttribute fuert Contentpanel setzen, wenn contentPanel vorhanden ist 26425 if(pluginBase.contentPanel && pluginBase.contentPanel.get(index)){ 26426 base.setAttributes(pluginBase.contentPanel.get(index), base.attributesContent, index, firstOpen); 26427 } 26428 }); 26429 }; 26430 26431 //*********************************Ende Verschiedene Aria-Typen initialisieren **************************************/ 26432 26433 26434 //*********************************Aria-Typen Attribute Zuordnungen *************************************************/ 26435 26436 /* 26437 * Array : 1. Wert aktiver Zustand, 2. Wert inaktiver Zustand 26438 * Function: Es können alle Funktionen die sich in dieser Lib befinden, genutzt werden. An die Funktion innerhalb 26439 * der Option wird immer this, base und index übergeben 26440 * Listener: erste Array ist der Zustand in dem etwas aktiv gesetzt werden soll, der zweite für den wo alles wieder 26441 * zurückgesetzt werden soll 26442 */ 26443 $.gsb.ariaSupport.defaultOptions = { 26444 26445 TAB: { 26446 firstOpen: true, 26447 panel:{ 26448 id : function (base){ 26449 return base.generateID() 26450 }, 26451 role: "tab", 26452 aria_expanded: [ 26453 "true","false" 26454 ], 26455 aria_controls: function (base){ 26456 return base.generateID() 26457 } 26458 }, 26459 content:{ 26460 role: 'tabpanel', 26461 aria_hidden:[ 26462 "false","true" 26463 ], 26464 id: function(base, index){ 26465 return base.getPanelAttribute(index, "aria-controls") 26466 }, 26467 aria_labelledby: function (base, index){ 26468 return base.getPanelAttribute(index, "id") 26469 } 26470 } 26471 }, 26472 26473 ACCORDION:{ 26474 panel:{ 26475 role: 'tab', 26476 aria_expanded: [ 26477 "true", "false" 26478 ], 26479 aria_selected: [ 26480 "true","false" 26481 ], 26482 id : function (base){ 26483 return base.generateID() 26484 }, 26485 aria_controls: function (base){ 26486 return base.generateID() 26487 } 26488 }, 26489 content: { 26490 role: 'tabpanel', 26491 aria_hidden:[ 26492 "false","true" 26493 ], 26494 id: function(base, index){ 26495 return base.getPanelAttribute(index, "aria-controls") 26496 }, 26497 aria_labelledby: function (base, index){ 26498 return base.getPanelAttribute(index, "id") 26499 } 26500 } 26501 }, 26502 26503 LIGTHBOX: { 26504 panel:{ 26505 aria_haspopup : "true" 26506 } 26507 }, 26508 26509 MOBILEMENU:{ 26510 /*addAural: true, 26511 auralText:[ 26512 SHOW_LESS, SHOW_MORE 26513 ],*/ 26514 panel: { 26515 aria_controls: function (base){ 26516 return base.generateID() 26517 }, 26518 id : function (base){ 26519 return base.generateID() 26520 } 26521 }, 26522 content: { 26523 aria_labelledby: function (base, index){ 26524 return base.getPanelAttribute(index, "id") 26525 }, 26526 id: function(base, index){ 26527 return base.getPanelAttribute(index, "aria-controls") 26528 }, 26529 aria_hidden:[ 26530 "false","true" 26531 ], 26532 aria_expanded:[ 26533 "true","false" 26534 ] 26535 } 26536 } 26537 }; 26538 26539 //**************************** Ende Aria-Typen Attribute Zuordnungen ************************************************/ 26540 26541 //********************************* Helper **************************************************************************/ 26542 /** 26543 * @method generateID 26544 * @desc generiert eine ID aus einer Zufallszahl und dessen toString result mit der Basis 36 26545 */ 26546 $.gsb.ariaSupport.prototype.generateID = function(){ 26547 26548 // Math.random should be unique because of its seeding algorithm. 26549 // Convert it to base 36 (numbers + letters), and grab the first 9 characters 26550 // after the decimal. 26551 return '_' + Math.random().toString(36).substr(2, 9); 26552 }; 26553 26554 26555 //********************************* Aural **************************************************************************/ 26556 /** 26557 * @method addAural 26558 * @desc fuegt ein span Aural mit dem "defaultText" hinzu 26559 * @param {elem} Element 26560 * @param {boolean} open: soll Text fuer geoeffnet oder geschlossen ausgegeben werden? 26561 */ 26562 $.gsb.ariaSupport.prototype.addAural = function(elem, open){ 26563 var base = this.base; 26564 26565 //Span erstellen und Class setzen 26566 var auralSpan = document.createElement("span"); 26567 auralSpan.classList.add('aural'); 26568 26569 //Angabe, welcher Text ausgegeben werden soll - 0 = geoeffnet, 1 = geschlossen 26570 var index = 1; 26571 if(open == true){ 26572 index = 0; 26573 } 26574 26575 //Auraltext hinzufuegen 26576 var auralText = document.createTextNode(base.moduleOptions.auralText[index]); 26577 auralSpan.appendChild(auralText); 26578 26579 elem.insertBefore(auralSpan, elem.firstChild); 26580 26581 } 26582 26583 /** 26584 * @method updateAural 26585 * @desc Tauscht den auraltext 26586 * @param {Object} clickedElem Element welches geklickt wurde 26587 * @param {boolean} open: wird das Element geoeffnet oder geschlossen 26588 */ 26589 $.gsb.ariaSupport.prototype.updateAural = function(clickedElem, open){ 26590 var base = this.base; 26591 var auralSpan = clickedElem.querySelector('.aural'); 26592 26593 //Angabe, welcher Text ausgegeben werden soll - 0 = geoeffnet, 1 = geschlossen 26594 var index = 1; 26595 if(open == true){ 26596 index = 0; 26597 } 26598 26599 auralSpan.removeChild(auralSpan.firstChild); 26600 26601 //Auraltext hinzufuegen 26602 var auralText = document.createTextNode(base.moduleOptions.auralText[index]); 26603 auralSpan.appendChild(auralText); 26604 26605 } 26606 26607 //********************************* Aria **************************************************************************/ 26608 /** 26609 * @method setAttributes
26610 * @desc setzt Attribute aus einem Array 26611 * @param {elem} Element 26612 * @param {Object} options: Options die als attribute gesetzt werden sollen 26613 * @param {int} index: Index des Elements welches aktualisiert werden soll 26614 * @param {boolean} open: Aria-Attribut für "geöffnet" setzen 26615 */ 26616 $.gsb.ariaSupport.prototype.setAttributes = function (elem, options, index, open){ 26617 var base = this.base; 26618 26619 for(var key in options){ 26620 //JSON keynames mit - nicht erlaubt, desswegen muss jetzt wieder von _ zu - umgewandelt werden 26621 var keyNameAsProperty = key.replace(/_/g,'-'); 26622 26623 if(typeof options[key] === 'function' ){ 26624 elem.setAttribute(keyNameAsProperty, options[key].call(this, base, index)) 26625 } else if(Array.isArray(options[key])){ 26626 if(options[key].length == 2){ 26627 if(open){ 26628 elem.setAttribute(keyNameAsProperty,options[key][0]); 26629 } else{ 26630 elem.setAttribute(keyNameAsProperty,options[key][1]); 26631 } 26632 } 26633 }else{ 26634 elem.setAttribute(keyNameAsProperty,options[key]); 26635 } 26636 } 26637 }; 26638 26639 26640 /** 26641 * @method setToggleoptions 26642 * @desc Setzt die übergebenen Optionen als Attribute für Content oder Panel - Keyname = Attributname, Valu = Value 26643 * @param {Array} Object mit Attributen 26644 */ 26645 $.gsb.ariaSupport.prototype.setToggleoptions = function(options){ 26646 var obj={}; 26647 26648 for(key in options){ 26649 if(Array.isArray(options[key])){ 26650 obj[key] = options[key]; 26651 } 26652 } 26653 26654 return obj; 26655 }; 26656 26657 /** 26658 * @method getPanelAttribute 26659 * @desc liefert den Wert des Attributes 26660 * getAttribute zu erzeugen) 26661 * @param {int} elementIdex: Index des Panelelements, von welchem die Attribute ausgelesen werden sollen 26662 * @param {String} Attribute: welches Attribute soll gelesen werden 26663 */ 26664 $.gsb.ariaSupport.prototype.getPanelAttribute = function(elementIndex, attribute){ 26665 return this.pluginBase.controlPanel.get(elementIndex).getAttribute(attribute); 26666 }; 26667 26668 26669 /** 26670 * @method getContentAttribute 26671 * @desc liefert den Wert des Attributes getAttribute zu erzeugen) 26672 * @param {int} elementIdex: Index des Panelelements, von welchem die Attribute ausgelesen werden sollen 26673 * @param {String} Attribute: welches Attribute soll gelesen werden 26674 */ 26675 $.gsb.ariaSupport.prototype.getContentAttribute = function(elementIndex, attribute){ 26676 return this.pluginBase.contentPanel.get(elementIndex).getAttribute(attribute); 26677 }; 26678 26679 /** 26680 * @method updateAria 26681 * @desc Tauscht den Value der ARI-Attribute 26682 * @param {Object} clickedElem Element welches geklickt wurde 26683 * @param {boolean} externalOpen: Aria Status für geöffnetes Element erzwingen 26684 * @param {boolean} singleOpen: Es soll nur ein Element geöffnet werden (also nicht wie bei einem Accordion - eins öffnen, andere SchlieÃen) 26685 */ 26686 $.gsb.ariaSupport.prototype.updateAria = function(clickedElem, externalOpen, singleOpen){ 26687 var base = this.base 26688 pluginBase = base.pluginBase; 26689 26690 if(typeof externalOpen != "boolean"){ 26691 externalOpen = null; 26692 } 26693 26694 base.pluginBase.controlPanel.get().forEach(function(elem, index){ 26695 var open = false; 26696 26697 if(externalOpen){ 26698 open = true 26699 } else if(externalOpen == null && elem == clickedElem){ 26700 open = true; 26701 } 26702 26703 if(singleOpen){ 26704 if(elem !== clickedElem){ 26705 // Wenn nur ein Element geöffnet werden soll und das geklickte nicht das aktuelle aus dem Schleifen 26706 // durchlauf ist, nächste Durchlauf 26707 return; 26708 } 26709 } 26710 26711 base.setAttributes(elem, base.panelToggle, index, open ); 26712 base.setAttributes(pluginBase.contentPanel.get(index), base.contentToggle, index, open ); 26713 }); 26714 }; 26715 26716 26717 $.fn.gsb_ariaSupport = function (pluginBase) { 26718 return (new $.gsb.ariaSupport(pluginBase)); 26719 }; 26720})(jQuery); 26721 /* Ende gsb_ariaSupport */ 26722 /* Start foundation */ 26723 /* 26724 * Foundation Responsive Library 26725 * http://foundation.zurb.com 26726 * Copyright 2014, ZURB 26727 * Free to use under the MIT license. 26728 * http://www.opensource.org/licenses/mit-license.php 26729*/ 26730(function ($, window, document, undefined) { 26731 'use strict'; 26732 var header_helpers = function (class_array) { 26733 var i = class_array.length; 26734 var head = $('head'); 26735 while (i--) { 26736 if(head.has('.' + class_array[i]).length === 0) { 26737 head.append('<meta class="' + class_array[i] + '" />'); 26738 } 26739 } 26740 }; 26741 header_helpers([ 26742 'foundation-mq-small', 26743 'foundation-mq-medium', 26744 'foundation-mq-large', 26745 'foundation-mq-xlarge', 26746 'foundation-mq-xxlarge', 26747 'foundation-data-attribute-namespace']); 26748 // Enable FastClick if present 26749 $(function() { 26750 if (typeof FastClick !== 'undefined') { 26751 // Don't attach to body if undefined 26752 if (typeof document.body !== 'undefined') { 26753 FastClick.attach(document.body); 26754 } 26755 } 26756 }); 26757 // private Fast Selector wrapper, 26758 // returns jQuery object. Only use where 26759 // getElementById is not available. 26760 var S = function (selector, context) { 26761 if (typeof selector === 'string') { 26762 if (context) { 26763 var cont; 26764 if (context.jquery) { 26765 cont = context[0]; 26766 if (!cont) return context; 26767 } else { 26768 cont = context; 26769 } 26770 return $(cont.querySelectorAll(selector)); 26771 } 26772 return $(document.querySelectorAll(selector)); 26773 } 26774 return $(selector, context); 26775 }; 26776 // Namespace functions. 26777 var attr_name = function (init) { 26778 var arr = []; 26779 if (!init) arr.push('data'); 26780 if (this.namespace.length > 0) arr.push(this.namespace); 26781 arr.push(this.name); 26782 return arr.join('-'); 26783 }; 26784 var add_namespace = function (str) { 26785 var parts = str.split('-'), 26786 i = parts.length, 26787 arr = []; 26788 while (i--) { 26789 if (i !== 0) { 26790 arr.push(parts[i]); 26791 } else { 26792 if (this.namespace.length > 0) { 26793 arr.push(this.namespace, parts[i]); 26794 } else { 26795 arr.push(parts[i]); 26796 } 26797 } 26798 } 26799 return arr.reverse().join('-'); 26800 }; 26801 // Event binding and data-options updating. 26802 var bindings = function (method, options) { 26803 var self = this, 26804 should_bind_events = !S(this).data(this.attr_name(true)); 26805 if (S(this.scope).is('[' + this.attr_name() +']')) { 26806 S(this.scope).data(this.attr_name(true) + '-init', $.extend({}, this.settings, (options || method), this.data_options(S(this.scope)))); 26807 if (should_bind_events) { 26808 this.events(this.scope); 26809 } 26810 } else { 26811 S('[' + this.attr_name() +']', this.scope).each(function () { 26812 var should_bind_events = !S(this).data(self.attr_name(true) + '-init'); 26813 S(this).data(self.attr_name(true) + '-init', $.extend({}, self.settings, (options || method), self.data_options(S(this)))); 26814 if (should_bind_events) { 26815 self.events(this); 26816 } 26817 }); 26818 } 26819 // # Patch to fix #5043 to move this *after* the if/else clause in order for Backbone and similar frameworks to have improved control over event binding and data-options updating. 26820 if (typeof method === 'string') { 26821 return this[method].call(this, options); 26822 } 26823 }; 26824 var single_image_loaded = function (image, callback) { 26825 function loaded () { 26826 callback(image[0]); 26827 } 26828 function bindLoad () { 26829 this.one('load', loaded); 26830 if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) { 26831 var src = this.attr( 'src' ), 26832 param = src.match( /\?/ ) ? '&' : '?'; 26833 param += 'random=' + (new Date()).getTime(); 26834 this.attr('src', src + param); 26835 } 26836 } 26837 if (!image.attr('src')) { 26838 loaded(); 26839 return; 26840 } 26841 if (image[0].complete || image[0].readyState === 4) { 26842 loaded(); 26843 } else { 26844 bindLoad.call(image); 26845 } 26846 }; 26847 /* 26848 https://github.com/paulirish/matchMedia.js 26849 */ 26850 window.matchMedia = window.matchMedia || (function( doc ) { 26851 "use strict"; 26852 var bool, 26853 docElem = doc.documentElement, 26854 refNode = docElem.firstElementChild || docElem.firstChild, 26855 // fakeBody required for <FF4 when executed in <head> 26856 fakeBody = doc.createElement( "body" ), 26857 div = doc.createElement( "div" ); 26858 div.id = "mq-test-1"; 26859 div.style.cssText = "position:absolute;top:-100em"; 26860 fakeBody.style.background = "none"; 26861 fakeBody.appendChild(div); 26862 return function (q) { 26863 div.innerHTML = "­<style media=\"" + q + "\"> #mq-test-1 { width: 42px; }</style>";
26864 docElem.insertBefore( fakeBody, refNode ); 26865 bool = div.offsetWidth === 42; 26866 docElem.removeChild( fakeBody ); 26867 return { 26868 matches: bool, 26869 media: q 26870 }; 26871 }; 26872 }( document )); 26873 /* 26874 * jquery.requestAnimationFrame 26875 * https://github.com/gnarf37/jquery-requestAnimationFrame 26876 * Requires jQuery 1.8+ 26877 * 26878 * Copyright (c) 2012 Corey Frang 26879 * Licensed under the MIT license. 26880 */ 26881 (function($) { 26882 // requestAnimationFrame polyfill adapted from Erik Möller 26883 // fixes from Paul Irish and Tino Zijdel 26884 // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ 26885 // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating 26886 var animating, 26887 lastTime = 0, 26888 vendors = ['webkit', 'moz'], 26889 requestAnimationFrame = window.requestAnimationFrame, 26890 cancelAnimationFrame = window.cancelAnimationFrame, 26891 jqueryFxAvailable = 'undefined' !== typeof jQuery.fx; 26892 for (; lastTime < vendors.length && !requestAnimationFrame; lastTime++) { 26893 requestAnimationFrame = window[ vendors[lastTime] + "RequestAnimationFrame" ]; 26894 cancelAnimationFrame = cancelAnimationFrame || 26895 window[ vendors[lastTime] + "CancelAnimationFrame" ] || 26896 window[ vendors[lastTime] + "CancelRequestAnimationFrame" ]; 26897 } 26898 function raf() { 26899 if (animating) { 26900 requestAnimationFrame(raf); 26901 if (jqueryFxAvailable) { 26902 jQuery.fx.tick(); 26903 } 26904 } 26905 } 26906 if (requestAnimationFrame) { 26907 // use rAF 26908 window.requestAnimationFrame = requestAnimationFrame; 26909 window.cancelAnimationFrame = cancelAnimationFrame; 26910 if (jqueryFxAvailable) { 26911 jQuery.fx.timer = function (timer) { 26912 if (timer() && jQuery.timers.push(timer) && !animating) { 26913 animating = true; 26914 raf(); 26915 } 26916 }; 26917 jQuery.fx.stop = function () { 26918 animating = false; 26919 }; 26920 } 26921 } else { 26922 // polyfill 26923 window.requestAnimationFrame = function (callback) { 26924 var currTime = new Date().getTime(), 26925 timeToCall = Math.max(0, 16 - (currTime - lastTime)), 26926 id = window.setTimeout(function () { 26927 callback(currTime + timeToCall); 26928 }, timeToCall); 26929 lastTime = currTime + timeToCall; 26930 return id; 26931 }; 26932 window.cancelAnimationFrame = function (id) { 26933 clearTimeout(id); 26934 }; 26935 } 26936 }( jQuery )); 26937 function removeQuotes (string) { 26938 if (typeof string === 'string' || string instanceof String) { 26939 string = string.replace(/^['\\/"]+|(;\s?})+|['\\/"]+$/g, ''); 26940 } 26941 return string; 26942 } 26943 window.Foundation = { 26944 name : 'Foundation', 26945 version : '{{VERSION}}', 26946 media_queries : { 26947 small : S('.foundation-mq-small').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''), 26948 medium : S('.foundation-mq-medium').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''),
26949 large : S('.foundation-mq-large').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''), 26950 xlarge: S('.foundation-mq-xlarge').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''), 26951 xxlarge: S('.foundation-mq-xxlarge').css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, '') 26952 }, 26953 stylesheet : $('<style></style>').appendTo('head')[0].sheet, 26954 global: { 26955 namespace: undefined 26956 }, 26957 init : function (scope, libraries, method, options, response) { 26958 var args = [scope, method, options, response], 26959 responses = []; 26960 // check RTL 26961 this.rtl = /rtl/i.test(S('html').attr('dir')); 26962 // set foundation global scope 26963 this.scope = scope || this.scope; 26964 this.set_namespace(); 26965 if (libraries && typeof libraries === 'string' && !/reflow/i.test(libraries)) { 26966 if (this.libs.hasOwnProperty(libraries)) { 26967 responses.push(this.init_lib(libraries, args)); 26968 } 26969 } else { 26970 for (var lib in this.libs) { 26971 responses.push(this.init_lib(lib, libraries)); 26972 } 26973 } 26974 S(window).load(function(){ 26975 S(window) 26976 .trigger('resize.fndtn.clearing') 26977 .trigger('resize.fndtn.dropdown') 26978 .trigger('resize.fndtn.equalizer') 26979 .trigger('resize.fndtn.interchange') 26980 .trigger('resize.fndtn.joyride') 26981 .trigger('resize.fndtn.magellan') 26982 .trigger('resize.fndtn.topbar') 26983 .trigger('resize.fndtn.slider'); 26984 }); 26985 return scope; 26986 }, 26987 init_lib : function (lib, args) { 26988 if (this.libs.hasOwnProperty(lib)) { 26989 this.patch(this.libs[lib]); 26990 if (args && args.hasOwnProperty(lib)) { 26991 if (typeof this.libs[lib].settings !== 'undefined') { 26992 $.extend(true, this.libs[lib].settings, args[lib]); 26993 } 26994 else if (typeof this.libs[lib].defaults !== 'undefined') { 26995 $.extend(true, this.libs[lib].defaults, args[lib]); 26996 } 26997 return this.libs[lib].init.apply(this.libs[lib], [this.scope, args[lib]]); 26998 } 26999 args = args instanceof Array ? args : new Array(args); // PATCH: added this line 27000 return this.libs[lib].init.apply(this.libs[lib], args); 27001 } 27002 return function () {}; 27003 }, 27004 patch : function (lib) { 27005 lib.scope = this.scope; 27006 lib.namespace = this.global.namespace; 27007 lib.rtl = this.rtl; 27008 lib['data_options'] = this.utils.data_options; 27009 lib['attr_name'] = attr_name; 27010 lib['add_namespace'] = add_namespace; 27011 lib['bindings'] = bindings; 27012 lib['S'] = this.utils.S; 27013 }, 27014 inherit : function (scope, methods) { 27015 var methods_arr = methods.split(' '), 27016 i = methods_arr.length; 27017 while (i--) { 27018 if (this.utils.hasOwnProperty(methods_arr[i])) { 27019 scope[methods_arr[i]] = this.utils[methods_arr[i]]; 27020 } 27021 } 27022 }, 27023 set_namespace: function () { 27024 // Description: 27025 // Don't bother reading the namespace out of the meta tag 27026 // if the namespace has been set globally in javascript 27027 // 27028 // Example: 27029 // Foundation.global.namespace = 'my-namespace'; 27030 // or make it an empty string: 27031 // Foundation.global.namespace = ''; 27032 // 27033 // 27034 // If the namespace has not been set (is undefined), try to read it out of the meta element. 27035 // Otherwise use the globally defined namespace, even if it's empty ('') 27036 var namespace = ( this.global.namespace === undefined ) ? $('.foundation-data-attribute-namespace').css('font-family') : this.global.namespace; 27037 // Finally, if the namsepace is either undefined or false, set it to an empty string. 27038 // Otherwise use the namespace value. 27039 this.global.namespace = ( namespace === undefined || /false/i.test(namespace) ) ? '' : namespace; 27040 }, 27041 libs : {}, 27042 // methods that can be inherited in libraries 27043 utils : { 27044 // Description: 27045 // Fast Selector wrapper returns jQuery object. Only use where getElementById 27046 // is not available. 27047 // 27048 // Arguments:
27049 // Selector (String): CSS selector describing the element(s) to be 27050 // returned as a jQuery object. 27051 // 27052 // Scope (String): CSS selector describing the area to be searched. Default 27053 // is document. 27054 // 27055 // Returns: 27056 // Element (jQuery Object): jQuery object containing elements matching the 27057 // selector within the scope. 27058 S : S, 27059 // Description: 27060 // Executes a function a max of once every n milliseconds 27061 // 27062 // Arguments: 27063 // Func (Function): Function to be throttled. 27064 // 27065 // Delay (Integer): Function execution threshold in milliseconds. 27066 // 27067 // Returns: 27068 // Lazy_function (Function): Function with throttling applied. 27069 throttle : function (func, delay) { 27070 var timer = null; 27071 return function () { 27072 var context = this, args = arguments; 27073 if (timer == null) { 27074 timer = setTimeout(function () { 27075 func.apply(context, args); 27076 timer = null; 27077 }, delay); 27078 } 27079 }; 27080 }, 27081 // Description: 27082 // Executes a function when it stops being invoked for n seconds 27083 // Modified version of _.debounce() http://underscorejs.org 27084 // 27085 // Arguments: 27086 // Func (Function): Function to be debounced. 27087 // 27088 // Delay (Integer): Function execution threshold in milliseconds. 27089 // 27090 // Immediate (Bool): Whether the function should be called at the beginning 27091 // of the delay instead of the end. Default is false. 27092 // 27093 // Returns: 27094 // Lazy_function (Function): Function with debouncing applied. 27095 debounce : function (func, delay, immediate) { 27096 var timeout, result; 27097 return function () { 27098 var context = this, args = arguments; 27099 var later = function () { 27100 timeout = null; 27101 if (!immediate) result = func.apply(context, args); 27102 }; 27103 var callNow = immediate && !timeout; 27104 clearTimeout(timeout); 27105 timeout = setTimeout(later, delay); 27106 if (callNow) result = func.apply(context, args); 27107 return result; 27108 }; 27109 }, 27110 // Description: 27111 // Parses data-options attribute 27112 // 27113 // Arguments: 27114 // El (jQuery Object): Element to be parsed. 27115 // 27116 // Returns: 27117 // Options (Javascript Object): Contents of the element's data-options 27118 // attribute. 27119 data_options : function (el, data_attr_name) { 27120 data_attr_name = data_attr_name || 'options'; 27121 var opts = {}, ii, p, opts_arr, 27122 data_options = function (el) { 27123 var namespace = Foundation.global.namespace; 27124 if (namespace.length > 0) { 27125 return el.data(namespace + '-' + data_attr_name); 27126 } 27127 return el.data(data_attr_name); 27128 }; 27129 var cached_options = data_options(el); 27130 if (typeof cached_options === 'object') { 27131 return cached_options; 27132 } 27133 opts_arr = (cached_options || ':').split(';'); 27134 ii = opts_arr.length; 27135 function isNumber (o) { 27136 return ! isNaN (o-0) && o !== null && o !== "" && o !== false && o !== true; 27137 } 27138 function trim (str) { 27139 if (typeof str === 'string') return $.trim(str); 27140 return str; 27141 } 27142 while (ii--) { 27143 p = opts_arr[ii].split(':'); 27144 p = [p[0], p.slice(1).join(':')]; 27145 if (/true/i.test(p[1])) p[1] = true; 27146 if (/false/i.test(p[1])) p[1] = false; 27147 if (isNumber(p[1])) { 27148 if (p[1].indexOf('.') === -1) { 27149 p[1] = parseInt(p[1], 10); 27150 } else { 27151 p[1] = parseFloat(p[1]); 27152 } 27153 } 27154 if (p.length === 2 && p[0].length > 0) { 27155 opts[trim(p[0])] = trim(p[1]); 27156 } 27157 } 27158 return opts; 27159 }, 27160 // Description: 27161 // Adds JS-recognizable media queries 27162 // 27163 // Arguments: 27164 // Media (String): Key string for the media query to be stored as in 27165 // Foundation.media_queries 27166 //
27167 // Class (String): Class name for the generated <meta> tag 27168 register_media : function (media, media_class) { 27169 if(Foundation.media_queries[media] === undefined) { 27170 $('head').append('<meta class="' + media_class + '"/>'); 27171 Foundation.media_queries[media] = removeQuotes($('.' + media_class).css('font-family')); 27172 } 27173 }, 27174 // Description: 27175 // Add custom CSS within a JS-defined media query 27176 // 27177 // Arguments: 27178 // Rule (String): CSS rule to be appended to the document. 27179 // 27180 // Media (String): Optional media query string for the CSS rule to be 27181 // nested under. 27182 add_custom_rule : function (rule, media) { 27183 if (media === undefined && Foundation.stylesheet) { 27184 Foundation.stylesheet.insertRule(rule, Foundation.stylesheet.cssRules.length); 27185 } else { 27186 var query = Foundation.media_queries[media]; 27187 if (query !== undefined) { 27188 Foundation.stylesheet.insertRule('@media ' + 27189 Foundation.media_queries[media] + '{ ' + rule + ' }'); 27190 } 27191 } 27192 }, 27193 // Description: 27194 // Performs a callback function when an image is fully loaded 27195 // 27196 // Arguments: 27197 // Image (jQuery Object): Image(s) to check if loaded. 27198 // 27199 // Callback (Function): Function to execute when image is fully loaded. 27200 image_loaded : function (images, callback) { 27201 var self = this, 27202 unloaded = images.length; 27203 if (unloaded === 0) { 27204 callback(images); 27205 } 27206 images.each(function () { 27207 single_image_loaded(self.S(this), function () { 27208 unloaded -= 1; 27209 if (unloaded === 0) { 27210 callback(images); 27211 } 27212 }); 27213 }); 27214 }, 27215 // Description: 27216 // Returns a random, alphanumeric string 27217 // 27218 // Arguments: 27219 // Length (Integer): Length of string to be generated. Defaults to random 27220 // integer. 27221 // 27222 // Returns: 27223 // Rand (String): Pseudo-random, alphanumeric string. 27224 random_str : function () { 27225 if (!this.fidx) this.fidx = 0; 27226 this.prefix = this.prefix || [(this.name || 'F'), (+new Date).toString(36)].join('-'); 27227 return this.prefix + (this.fidx++).toString(36); 27228 } 27229 } 27230 }; 27231 $.fn.foundation = function () { 27232 var args = Array.prototype.slice.call(arguments, 0); 27233 return this.each(function () { 27234 Foundation.init.apply(Foundation, [this].concat(args)); 27235 return this; 27236 }); 27237 }; 27238}(jQuery, window, window.document)); 27239 27240 /* Ende foundation */ 27241 /* Start foundation.tooltip */ 27242 ;(function ($, window, document, undefined) { 27243 'use strict'; 27244 27245 Foundation.libs.tooltip = { 27246 name : 'tooltip', 27247 27248 version : '{{VERSION}}', 27249 27250 settings : { 27251 additional_inheritable_classes : [], 27252 tooltip_class : '.tooltip', 27253 append_to: 'body', 27254 touch_close_text: 'Tap To Close', 27255 disable_for_touch: false, 27256 hover_delay: 200, 27257 show_on : 'all', 27258 tip_template : function (selector, content) { 27259 return '<span data-selector="' + selector + '" id="' + selector + '" class="' 27260 + Foundation.libs.tooltip.settings.tooltip_class.substring(1) 27261 + '" role="tooltip">' + content + '<span class="nub"></span></span>'; 27262 } 27263 }, 27264 27265 cache : {}, 27266 27267 init : function (scope, method, options) { 27268 Foundation.inherit(this, 'random_str'); 27269 this.bindings(method, options); 27270 }, 27271 27272 should_show: function (target, tip) { 27273 var settings = $.extend({}, this.settings, this.data_options(target)); 27274 27275 if (settings.show_on === 'all') { 27276 return true; 27277 } else if (this.small() && settings.show_on === 'small') { 27278 return true; 27279 } else if (this.medium() && settings.show_on === 'medium') { 27280 return true; 27281 } else if (this.large() && settings.show_on === 'large') { 27282 return true; 27283 } 27284 return false; 27285 }, 27286 27287 medium : function () { 27288 return matchMedia(Foundation.media_queries['medium']).matches; 27289 }, 27290 27291 large : function () { 27292 return matchMedia(Foundation.media_queries['large']).matches; 27293 }, 27294 27295 events : function (instance) { 27296 var self = this, 27297 S = self.S; 27298 27299 self.create(this.S(instance)); 27300 27301 $(this.scope) 27302 .off('.tooltip') 27303 .on('mouseenter.fndtn.tooltip mouseleave.fndtn.tooltip touchstart.fndtn.tooltip MSPointerDown.fndtn.tooltip', 27304 '[' + this.attr_name() + ']', function (e) { 27305 var $this = S(this), 27306 settings = $.extend({}, self.settings, self.data_options($this)), 27307 is_touch = false;
27308 27309 if (Modernizr.touch && /touchstart|MSPointerDown/i.test(e.type) && S(e.target).is('a')) { 27310 return false; 27311 } 27312 27313 if (/mouse/i.test(e.type) && self.ie_touch(e)) return false; 27314 27315 if ($this.hasClass('open')) { 27316 if (Modernizr.touch && /touchstart|MSPointerDown/i.test(e.type)) e.preventDefault(); 27317 self.hide($this); 27318 } else { 27319 if (settings.disable_for_touch && Modernizr.touch && /touchstart|MSPointerDown/i.test(e.type)) { 27320 return; 27321 } else if(!settings.disable_for_touch && Modernizr.touch && /touchstart|MSPointerDown/i.test(e.type)) { 27322 e.preventDefault(); 27323 S(settings.tooltip_class + '.open').hide(); 27324 is_touch = true; 27325 } 27326 27327 if (/enter|over/i.test(e.type)) { 27328 this.timer = setTimeout(function () { 27329 var tip = self.showTip($this); 27330 }.bind(this), self.settings.hover_delay); 27331 } else if (e.type === 'mouseout' || e.type === 'mouseleave') { 27332 clearTimeout(this.timer); 27333 self.hide($this); 27334 } else { 27335 self.showTip($this); 27336 } 27337 } 27338 }) 27339 .on('mouseleave.fndtn.tooltip touchstart.fndtn.tooltip MSPointerDown.fndtn.tooltip', '[' + this.attr_name() + '].open', function (e) { 27340 if (/mouse/i.test(e.type) && self.ie_touch(e)) return false; 27341 27342 if($(this).data('tooltip-open-event-type') == 'touch' && e.type == 'mouseleave') { 27343 return; 27344 } 27345 else if($(this).data('tooltip-open-event-type') == 'mouse' && /MSPointerDown|touchstart/i.test(e.type)) { 27346 self.convert_to_touch($(this)); 27347 } else { 27348 self.hide($(this)); 27349 } 27350 }) 27351 // .on('DOMNodeRemoved DOMAttrModified', '[' + this.attr_name() + ']:not(a)', function (e) { 27352 // self.hide(S(this)); 27353 // }); 27354 }, 27355 27356 ie_touch : function (e) { 27357 // How do I distinguish between IE11 and Windows Phone 8????? 27358 return false; 27359 }, 27360 27361 showTip : function ($target) { 27362 var $tip = this.getTip($target); 27363 if (this.should_show($target, $tip)){ 27364 return this.show($target); 27365 } 27366 return; 27367 }, 27368 27369 getTip : function ($target) { 27370 var selector = this.selector($target), 27371 settings = $.extend({}, this.settings, this.data_options($target)), 27372 tip = null; 27373 27374 if (selector) { 27375 tip = this.S('span[data-selector="' + selector + '"]' + settings.tooltip_class); 27376 } 27377 27378 return (typeof tip === 'object') ? tip : false; 27379 }, 27380 27381 selector : function ($target) { 27382 var id = $target.attr('id'), 27383 dataSelector = $target.attr(this.attr_name()) || $target.attr('data-selector'); 27384 27385 if ((id && id.length < 1 || !id) && typeof dataSelector != 'string') { 27386 dataSelector = this.random_str(6); 27387 $target 27388 .attr('data-selector', dataSelector) 27389 .attr('aria-describedby', dataSelector); 27390 } 27391 27392 return (id && id.length > 0) ? id : dataSelector; 27393 }, 27394 27395 create : function ($target) { 27396 var self = this, 27397 settings = $.extend({}, this.settings, this.data_options($target)), 27398 tip_template = this.settings.tip_template; 27399 27400 if (typeof settings.tip_template === 'string' && window.hasOwnProperty(settings.tip_template)) { 27401 tip_template = window[settings.tip_template]; 27402 } 27403 27404 var $tip = $(tip_template(this.selector($target), $('<div></div>').html($target.attr('title')).html())), 27405 classes = this.inheritable_classes($target); 27406
27407 $tip.addClass(classes).appendTo(settings.append_to); 27408 27409 if (Modernizr.touch) { 27410 $tip.append('<span class="tap-to-close">'+settings.touch_close_text+'</span>'); 27411 $tip.on('touchstart.fndtn.tooltip MSPointerDown.fndtn.tooltip', function(e) { 27412 self.hide($target); 27413 }); 27414 } 27415 27416 $target.removeAttr('title').attr('title',''); 27417 }, 27418 27419 reposition : function (target, tip, classes) { 27420 var width, nub, nubHeight, nubWidth, column, objPos; 27421 27422 tip.css('visibility', 'hidden').show(); 27423 27424 width = target.data('width'); 27425 nub = tip.children('.nub'); 27426 nubHeight = nub.outerHeight(); 27427 nubWidth = nub.outerHeight(); 27428 27429 if (this.small()) { 27430 tip.css({'width' : '100%' }); 27431 } else { 27432 tip.css({'width' : (width) ? width : 'auto'}); 27433 } 27434 27435 objPos = function (obj, top, right, bottom, left, width) { 27436 return obj.css({ 27437 'top' : (top) ? top : 'auto', 27438 'bottom' : (bottom) ? bottom : 'auto', 27439 'left' : (left) ? left : 'auto', 27440 'right' : (right) ? right : 'auto' 27441 }).end(); 27442 }; 27443 27444 objPos(tip, (target.offset().top + target.outerHeight() + 10), 'auto', 'auto', target.offset().left); 27445 27446 if (this.small()) { 27447 objPos(tip, (target.offset().top + target.outerHeight() + 10), 'auto', 'auto', 12.5, $(this.scope).width()); 27448 tip.addClass('tip-override'); 27449 objPos(nub, -nubHeight, 'auto', 'auto', target.offset().left); 27450 } else { 27451 var left = target.offset().left; 27452 if (Foundation.rtl) { 27453 nub.addClass('rtl'); 27454 left = target.offset().left + target.outerWidth() - tip.outerWidth(); 27455 } 27456 objPos(tip, (target.offset().top + target.outerHeight() + 10), 'auto', 'auto', left); 27457 tip.removeClass('tip-override'); 27458 if (classes && classes.indexOf('tip-top') > -1) { 27459 if (Foundation.rtl) nub.addClass('rtl'); 27460 objPos(tip, (target.offset().top - tip.outerHeight()), 'auto', 'auto', left) 27461 .removeClass('tip-override'); 27462 } else if (classes && classes.indexOf('tip-left') > -1) { 27463 objPos(tip, (target.offset().top + (target.outerHeight() / 2) - (tip.outerHeight() / 2)), 'auto', 'auto', (target.offset().left - tip.outerWidth() - nubHeight)) 27464 .removeClass('tip-override'); 27465 nub.removeClass('rtl'); 27466 } else if (classes && classes.indexOf('tip-right') > -1) { 27467 objPos(tip, (target.offset().top + (target.outerHeight() / 2) - (tip.outerHeight() / 2)), 'auto', 'auto', (target.offset().left + target.outerWidth() + nubHeight)) 27468 .removeClass('tip-override'); 27469 nub.removeClass('rtl'); 27470 } 27471 } 27472 27473 tip.css('visibility', 'visible').hide(); 27474 }, 27475 27476 small : function () { 27477 return matchMedia(Foundation.media_queries.small).matches && 27478 !matchMedia(Foundation.media_queries.medium).matches; 27479 }, 27480 27481 inheritable_classes : function ($target) { 27482 var settings = $.extend({}, this.settings, this.data_options($target)), 27483 inheritables = ['tip-top', 'tip-left', 'tip-bottom', 'tip-right', 'radius', 'round'].concat(settings.additional_inheritable_classes), 27484 classes = $target.attr('class'), 27485 filtered = classes ? $.map(classes.split(' '), function (el, i) { 27486 if ($.inArray(el, inheritables) !== -1) { 27487 return el; 27488 } 27489 }).join(' ') : ''; 27490 27491 return $.trim(filtered); 27492 }, 27493 27494 convert_to_touch : function($target) { 27495 var self = this, 27496 $tip = self.getTip($target), 27497 settings = $.extend({}, self.settings, self.data_options($target)); 27498 27499 if ($tip.find('.tap-to-close').length === 0) { 27500 $tip.append('<span class="tap-to-close">'+settings.touch_close_text+'</span>'); 27501 $tip.on('click.fndtn.tooltip.tapclose touchstart.fndtn.tooltip.tapclose MSPointerDown.fndtn.tooltip.tapclose', function(e) { 27502 self.hide($target); 27503 }); 27504 } 27505 27506 $target.data('tooltip-open-event-type', 'touch'); 27507 }, 27508 27509 show : function ($target) { 27510 var $tip = this.getTip($target); 27511 27512 if ($target.data('tooltip-open-event-type') == 'touch') { 27513 this.convert_to_touch($target); 27514 } 27515 27516 this.reposition($target, $tip, $target.attr('class')); 27517 $target.addClass('open'); 27518 $tip.fadeIn(150); 27519 }, 27520 27521 hide : function ($target) { 27522 var $tip = this.getTip($target); 27523 27524 $tip.fadeOut(150, function() { 27525 $tip.find('.tap-to-close').remove(); 27526 $tip.off('click.fndtn.tooltip.tapclose MSPointerDown.fndtn.tapclose'); 27527 $target.removeClass('open'); 27528 }); 27529 }, 27530 27531 off : function () { 27532 var self = this; 27533 this.S(this.scope).off('.fndtn.tooltip'); 27534 this.S(this.settings.tooltip_class).each(function (i) { 27535 $('[' + self.attr_name() + ']').eq(i).attr('title', $(this).text()); 27536 }).remove(); 27537 }, 27538 27539 reflow : function () {} 27540 }; 27541}(jQuery, window, window.document)); 27542 /* Ende foundation.tooltip */ 27543 /* Start hammer */ 27544 /*! Hammer.JS - v2.0.2 - 2014-07-28 * http://hammerjs.github.io/ * * Copyright (c) 2014 Jorik Tangelder <[email protected]>; * Licensed under the MIT license */ ! function(a, b, c, d) { 27545 function e(a, b, c) { 27546 return setTimeout(k(a, c), b); 27547 } 27548 27549 function f(a, b, c) { 27550 return Array.isArray(a) ? (g(a, c[b], c), !0) : !1; 27551 } 27552 27553 function g(a, b, c) { 27554 var e, f; 27555 if (a) {
27556 if (a.forEach) { 27557 a.forEach(b, c); 27558 } else { 27559 if (a.length !== d) { 27560 for (e = 0, f = a.length; f > e; e++) { 27561 b.call(c, a[e], e, a); 27562 } 27563 } else { 27564 for (e in a) { 27565 a.hasOwnProperty(e) && b.call(c, a[e], e, a); 27566 } 27567 } 27568 } 27569 } 27570 } 27571 27572 function h(a, b, c) { 27573 for (var e = Object.keys(b), f = 0, g = e.length; g > f; f++) { 27574 (!c || c && a[e[f]] === d) && (a[e[f]] = b[e[f]]); 27575 } 27576 return a; 27577 } 27578 27579 function i(a, b) { 27580 return h(a, b, !0); 27581 } 27582 27583 function j(a, b, c) { 27584 var d, e = b.prototype; 27585 d = a.prototype = Object.create(e), d.constructor = a, d._super = e, c && h(d, c); 27586 } 27587 27588 function k(a, b) { 27589 return function() { 27590 return a.apply(b, arguments); 27591 }; 27592 } 27593 27594 function l(a, b) { 27595 return typeof a == hb ? a.apply(b ? b[0] || d : d, b) : a; 27596 } 27597 27598 function m(a, b) { 27599 return a === d ? b : a; 27600 } 27601 27602 function n(a, b, c) { 27603 g(r(b), function(b) { 27604 a.addEventListener(b, c, !1); 27605 }); 27606 } 27607 27608 function o(a, b, c) { 27609 g(r(b), function(b) { 27610 a.removeEventListener(b, c, !1); 27611 }); 27612 } 27613 27614 function p(a, b) { 27615 for (; a;) { 27616 if (a == b) { 27617 return !0; 27618 } 27619 a = a.parentNode; 27620 } 27621 return !1; 27622 } 27623 27624 function q(a, b) { 27625 return a.indexOf(b) > -1; 27626 } 27627 27628 function r(a) { 27629 return a.trim().split(/\s+/g); 27630 } 27631 27632 function s(a, b, c) { 27633 if (a.indexOf && !c) { 27634 return a.indexOf(b); 27635 } 27636 for (var d = 0, e = a.length; e > d; d++) { 27637 if (c && a[d][c] == b || !c && a[d] === b) { 27638 return d; 27639 } 27640 } 27641 return -1; 27642 } 27643 27644 function t(a) { 27645 return Array.prototype.slice.call(a, 0); 27646 } 27647 27648 function u(a, b, c) { 27649 for (var d = [], e = [], f = 0, g = a.length; g > f; f++) { 27650 var h = b ? a[f][b] : a[f]; 27651 s(e, h) < 0 && d.push(a[f]), e[f] = h; 27652 } 27653 return c && (d = b ? d.sort(function(a, c) { 27654 return a[b] > c[b]; 27655 }) : d.sort()), d; 27656 } 27657 27658 function v(a, b) { 27659 for (var c, e, f = b[0].toUpperCase() + b.slice(1), g = 0, h = fb.length; h > g; g++) { 27660 if (c = fb[g], e = c ? c + f : b, e in a) { 27661 return e; 27662 } 27663 } 27664 return d; 27665 } 27666 27667 function w() { 27668 return lb++; 27669 } 27670 27671 function x(b, c) { 27672 var d = this; 27673 this.manager = b, this.callback = c, this.element = b.element, this.target = b.options.inputTarget, this.domHandler = function(a) { 27674 l(b.options.enable, [b]) && d.handler(a); 27675 }, this.evEl && n(this.element, this.evEl, this.domHandler), this.evTarget && n(this.target, this.evTarget, this.domHandler), this.evWin && n(a, this.evWin, this.domHandler); 27676 } 27677 27678 function y(a) { 27679 var b; 27680 return new(b = ob ? M : pb ? N : nb ? P : L)(a, z); 27681 } 27682 27683 function z(a, b, c) { 27684 var d = c.pointers.length, 27685 e = c.changedPointers.length, 27686 f = b & vb && d - e === 0, 27687 g = b & (xb | yb) && d - e === 0; 27688 c.isFirst = !!f, c.isFinal = !!g, f && (a.session = {}), c.eventType = b, A(a, c), a.emit("hammer.input", c), a.recognize(c), a.session.prevInput = c; 27689 } 27690 27691 function A(a, b) { 27692 var c = a.session, 27693 d = b.pointers, 27694 e = d.length; 27695 c.firstInput || (c.firstInput = D(b)), e > 1 && !c.firstMultiple ? c.firstMultiple = D(b) : 1 === e && (c.firstMultiple = !1); 27696 var f = c.firstInput, 27697 g = c.firstMultiple, 27698 h = g ? g.center : f.center, 27699 i = b.center = E(d); 27700 b.timeStamp = kb(), b.deltaTime = b.timeStamp - f.timeStamp, b.angle = I(h, i), b.distance = H(h, i), B(c, b), b.offsetDirection = G(b.deltaX, b.deltaY), b.scale = g ? K(g.pointers, d) : 1, b.rotation = g ? J(g.pointers, d) : 0, C(c, b); 27701 var j = a.element; 27702 p(b.srcEvent.target, j) && (j = b.srcEvent.target), b.target = j; 27703 } 27704 27705 function B(a, b) { 27706 var c = b.center, 27707 d = a.offsetDelta || {}, 27708 e = a.prevDelta || {}, 27709 f = a.prevInput || {}; 27710 (b.eventType === vb || f.eventType === xb) && (e = a.prevDelta = { 27711 x: f.deltaX || 0, 27712 y: f.deltaY || 0 27713 }, d = a.offsetDelta = { 27714 x: c.x, 27715 y: c.y 27716 }), b.deltaX = e.x + (c.x - d.x), b.deltaY = e.y + (c.y - d.y); 27717 } 27718 27719 function C(a, b) { 27720 var c, e, f, g, h = a.lastInterval || b, 27721 i = b.timeStamp - h.timeStamp; 27722 if (b.eventType != yb && (i > ub || h.velocity === d)) { 27723 var j = h.deltaX - b.deltaX, 27724 k = h.deltaY - b.deltaY, 27725 l = F(i, j, k); 27726 e = l.x, f = l.y, c = jb(l.x) > jb(l.y) ? l.x : l.y, g = G(j, k), a.lastInterval = b; 27727 } else { 27728 c = h.velocity, e = h.velocityX, f = h.velocityY, g = h.direction; 27729 } 27730 b.velocity = c, b.velocityX = e, b.velocityY = f, b.direction = g; 27731 } 27732 27733 function D(a) { 27734 for (var b = [], c = 0; c < a.pointers.length; c++) { 27735 b[c] = { 27736 clientX: ib(a.pointers[c].clientX), 27737 clientY: ib(a.pointers[c].clientY) 27738 }; 27739 } 27740 return { 27741 timeStamp: kb(), 27742 pointers: b, 27743 center: E(b), 27744 deltaX: a.deltaX,
27745 deltaY: a.deltaY 27746 }; 27747 } 27748 27749 function E(a) { 27750 var b = a.length; 27751 if (1 === b) { 27752 return { 27753 x: ib(a[0].clientX), 27754 y: ib(a[0].clientY) 27755 }; 27756 } 27757 for (var c = 0, d = 0, e = 0; b > e; e++) { 27758 c += a[e].clientX, d += a[e].clientY; 27759 } 27760 return { 27761 x: ib(c / b), 27762 y: ib(d / b) 27763 }; 27764 } 27765 27766 function F(a, b, c) { 27767 return { 27768 x: b / a || 0, 27769 y: c / a || 0 27770 }; 27771 } 27772 27773 function G(a, b) { 27774 return a === b ? zb : jb(a) >= jb(b) ? a > 0 ? Ab : Bb : b > 0 ? Cb : Db; 27775 } 27776 27777 function H(a, b, c) { 27778 c || (c = Hb); 27779 var d = b[c[0]] - a[c[0]], 27780 e = b[c[1]] - a[c[1]]; 27781 return Math.sqrt(d * d + e * e); 27782 } 27783 27784 function I(a, b, c) { 27785 c || (c = Hb); 27786 var d = b[c[0]] - a[c[0]], 27787 e = b[c[1]] - a[c[1]]; 27788 return 180 * Math.atan2(e, d) / Math.PI; 27789 } 27790 27791 function J(a, b) { 27792 return I(b[1], b[0], Ib) - I(a[1], a[0], Ib); 27793 } 27794 27795 function K(a, b) { 27796 return H(b[0], b[1], Ib) / H(a[0], a[1], Ib); 27797 } 27798 27799 function L() { 27800 this.evEl = Kb, this.evWin = Lb, this.allow = !0, this.pressed = !1, x.apply(this, arguments); 27801 } 27802 27803 function M() { 27804 this.evEl = Ob, this.evWin = Pb, x.apply(this, arguments), this.store = this.manager.session.pointerEvents = []; 27805 } 27806 27807 function N() { 27808 this.evTarget = Rb, this.targetIds = {}, x.apply(this, arguments); 27809 } 27810 27811 function O(a, b) { 27812 var c = t(a.touches), 27813 d = this.targetIds; 27814 if (b & (vb | wb) && 1 === c.length) { 27815 return d[c[0].identifier] = !0, [c, c]; 27816 } 27817 var e, f, g = t(a.targetTouches), 27818 h = t(a.changedTouches), 27819 i = []; 27820 if (b === vb) { 27821 for (e = 0, f = g.length; f > e; e++) { 27822 d[g[e].identifier] = !0; 27823 } 27824 } 27825 for (e = 0, f = h.length; f > e; e++) { 27826 d[h[e].identifier] && i.push(h[e]), b & (xb | yb) && delete d[h[e].identifier]; 27827 } 27828 return i.length ? [u(g.concat(i), "identifier", !0), i] : void 0; 27829 } 27830 27831 function P() { 27832 x.apply(this, arguments); 27833 var a = k(this.handler, this); 27834 this.touch = new N(this.manager, a), this.mouse = new L(this.manager, a); 27835 } 27836 27837 function Q(a, b) { 27838 this.manager = a, this.set(b); 27839 } 27840 27841 function R(a) { 27842 if (q(a, Xb)) { 27843 return Xb; 27844 } 27845 var b = q(a, Yb), 27846 c = q(a, Zb); 27847 return b && c ? Yb + " " + Zb : b || c ? b ? Yb : Zb : q(a, Wb) ? Wb : Vb; 27848 } 27849 27850 function S(a) { 27851 this.id = w(), this.manager = null, this.options = i(a || {}, this.defaults), this.options.enable = m(this.options.enable, !0), this.state = $b, this.simultaneous = {}, this.requireFail = []; 27852 } 27853 27854 function T(a) { 27855 return a & dc ? "cancel" : a & bc ? "end" : a & ac ? "move" : a & _b ? "start" : ""; 27856 } 27857 27858 function U(a) { 27859 return a == Db ? "down" : a == Cb ? "up" : a == Ab ? "left" : a == Bb ? "right" : ""; 27860 } 27861 27862 function V(a, b) { 27863 var c = b.manager; 27864 return c ? c.get(a) : a; 27865 } 27866 27867 function W() { 27868 S.apply(this, arguments); 27869 } 27870 27871 function X() { 27872 W.apply(this, arguments), this.pX = null, this.pY = null; 27873 } 27874 27875 function Y() { 27876 W.apply(this, arguments); 27877 } 27878 27879 function Z() { 27880 S.apply(this, arguments), this._timer = null, this._input = null; 27881 } 27882 27883 function $() { 27884 W.apply(this, arguments); 27885 } 27886 27887 function _() { 27888 W.apply(this, arguments); 27889 } 27890 27891 function ab() { 27892 S.apply(this, arguments), this.pTime = !1, this.pCenter = !1, this._timer = null, this._input = null, this.count = 0; 27893 } 27894 27895 function bb(a, b) { 27896 return b = b || {}, b.recognizers = m(b.recognizers, bb.defaults.preset), new cb(a, b); 27897 } 27898 27899 function cb(a, b) { 27900 b = b || {}, this.options = i(b, bb.defaults), this.options.inputTarget = this.options.inputTarget || a, this.handlers = {}, this.session = {}, this.recognizers = [], this.element = a, this.input = y(this), this.touchAction = new Q(this, this.options.touchAction), db(this, !0), g(b.recognizers, function(a) { 27901 var b = this.add(new a[0](a[1])); 27902 a[2] && b.recognizeWith(a[2]), a[3] && b.requireFailure(a[2]); 27903 }, this); 27904 } 27905 27906 function db(a, b) { 27907 var c = a.element; 27908 g(a.options.cssProps, function(a, d) { 27909 c.style[v(c.style, d)] = b ? a : ""; 27910 }); 27911 } 27912 27913 function eb(a, c) { 27914 var d = b.createEvent("Event"); 27915 d.initEvent(a, !0, !0), d.gesture = c, c.target.dispatchEvent(d); 27916 } 27917 var fb = ["", "webkit", "moz", "MS", "ms", "o"], 27918 gb = b.createElement("div"), 27919 hb = "function", 27920 ib = Math.round, 27921 jb = Math.abs, 27922 kb = Date.now, 27923 lb = 1, 27924 mb = /mobile|tablet|ip(ad|hone|od)|android/i, 27925 nb = "ontouchstart" in a, 27926 ob = v(a, "PointerEvent") !== d, 27927 pb = nb && mb.test(navigator.userAgent), 27928 qb = "touch", 27929 rb = "pen", 27930 sb = "mouse", 27931 tb = "kinect", 27932 ub = 25, 27933 vb = 1, 27934 wb = 2, 27935 xb = 4, 27936 yb = 8, 27937 zb = 1, 27938 Ab = 2, 27939 Bb = 4, 27940 Cb = 8, 27941 Db = 16, 27942 Eb = Ab | Bb, 27943 Fb = Cb | Db, 27944 Gb = Eb | Fb, 27945 Hb = ["x", "y"], 27946 Ib = ["clientX", "clientY"]; 27947 x.prototype = { 27948 handler: function() {}, 27949 destroy: function() { 27950 this.evEl && o(this.element, this.evEl, this.domHandler), this.evTarget && o(this.target, this.evTarget, this.domHandler), this.evWin && o(a, this.evWin, this.domHandler); 27951 } 27952 }; 27953 var Jb = { 27954 mousedown: vb, 27955 mousemove: wb, 27956 mouseup: xb 27957 }, 27958 Kb = "mousedown", 27959 Lb = "mousemove mouseup"; 27960 j(L, x, { 27961 handler: function(a) { 27962 var b = Jb[a.type]; 27963 b & vb && 0 === a.button && (this.pressed = !0), b & wb && 1 !== a.which && (b = xb), this.pressed && this.allow && (b & xb && (this.pressed = !1), this.callback(this.manager, b, { 27964 pointers: [a], 27965 changedPointers: [a], 27966 pointerType: sb, 27967 srcEvent: a 27968 })); 27969 } 27970 }); 27971 var Mb = { 27972 pointerdown: vb, 27973 pointermove: wb, 27974 pointerup: xb, 27975 pointercancel: yb, 27976 pointerout: yb 27977 }, 27978 Nb = { 27979 2: qb, 27980 3: rb, 27981 4: sb, 27982 5: tb 27983 }, 27984 Ob = "pointerdown", 27985 Pb = "pointermove pointerup pointercancel"; 27986 a.MSPointerEvent && (Ob = "MSPointerDown", Pb = "MSPointerMove MSPointerUp MSPointerCancel"), j(M, x, { 27987 handler: function(a) { 27988 var b = this.store, 27989 c = !1, 27990 d = a.type.toLowerCase().replace("ms", ""), 27991 e = Mb[d], 27992 f = Nb[a.pointerType] || a.pointerType, 27993 g = f == qb; 27994 e & vb && (0 === a.button || g) ? b.push(a) : e & (xb | yb) && (c = !0); 27995 var h = s(b, a.pointerId, "pointerId"); 27996 0 > h || (b[h] = a, this.callback(this.manager, e, { 27997 pointers: b, 27998 changedPointers: [a], 27999 pointerType: f, 28000 srcEvent: a 28001 }
28001), c && b.splice(h, 1)); 28002 } 28003 }); 28004 var Qb = { 28005 touchstart: vb, 28006 touchmove: wb, 28007 touchend: xb, 28008 touchcancel: yb 28009 }, 28010 Rb = "touchstart touchmove touchend touchcancel"; 28011 j(N, x, { 28012 handler: function(a) { 28013 var b = Qb[a.type], 28014 c = O.call(this, a, b); 28015 c && this.callback(this.manager, b, { 28016 pointers: c[0], 28017 changedPointers: c[1], 28018 pointerType: qb, 28019 srcEvent: a 28020 }); 28021 } 28022 }), j(P, x, { 28023 handler: function(a, b, c) { 28024 var d = c.pointerType == qb, 28025 e = c.pointerType == sb; 28026 if (d) { 28027 this.mouse.allow = !1; 28028 } else { 28029 if (e && !this.mouse.allow) { 28030 return; 28031 } 28032 } 28033 b & (xb | yb) && (this.mouse.allow = !0), this.callback(a, b, c); 28034 }, 28035 destroy: function() { 28036 this.touch.destroy(), this.mouse.destroy(); 28037 } 28038 }); 28039 var Sb = v(gb.style, "touchAction"), 28040 Tb = Sb !== d, 28041 Ub = "compute", 28042 Vb = "auto", 28043 Wb = "manipulation", 28044 Xb = "none", 28045 Yb = "pan-x", 28046 Zb = "pan-y"; 28047 Q.prototype = { 28048 set: function(a) { 28049 a == Ub && (a = this.compute()), Tb && (this.manager.element.style[Sb] = a), this.actions = a.toLowerCase().trim(); 28050 }, 28051 update: function() { 28052 this.set(this.manager.options.touchAction); 28053 }, 28054 compute: function() { 28055 var a = []; 28056 return g(this.manager.recognizers, function(b) { 28057 l(b.options.enable, [b]) && (a = a.concat(b.getTouchAction())); 28058 }), R(a.join(" ")); 28059 }, 28060 preventDefaults: function(a) { 28061 if (!Tb) { 28062 var b = a.srcEvent, 28063 c = a.offsetDirection; 28064 if (this.manager.session.prevented) { 28065 return void b.preventDefault(); 28066 } 28067 var d = this.actions, 28068 e = q(d, Xb), 28069 f = q(d, Zb), 28070 g = q(d, Yb); 28071 return e || f && g || f && c & Eb || g && c & Fb ? this.preventSrc(b) : void 0; 28072 } 28073 }, 28074 preventSrc: function(a) { 28075 this.manager.session.prevented = !0, a.preventDefault(); 28076 } 28077 }; 28078 var $b = 1, 28079 _b = 2, 28080 ac = 4, 28081 bc = 8, 28082 cc = bc, 28083 dc = 16, 28084 ec = 32; 28085 S.prototype = { 28086 defaults: {}, 28087 set: function(a) { 28088 return h(this.options, a), this.manager && this.manager.touchAction.update(), this; 28089 }, 28090 recognizeWith: function(a) { 28091 if (f(a, "recognizeWith", this)) { 28092 return this; 28093 } 28094 var b = this.simultaneous; 28095 return a = V(a, this), b[a.id] || (b[a.id] = a, a.recognizeWith(this)), this; 28096 }, 28097 dropRecognizeWith: function(a) { 28098 return f(a, "dropRecognizeWith", this) ? this : (a = V(a, this), delete this.simultaneous[a.id], this); 28099 }, 28100 requireFailure: function(a) { 28101 if (f(a, "requireFailure", this)) { 28102 return this; 28103 } 28104 var b = this.requireFail; 28105 return a = V(a, this), -1 === s(b, a) && (b.push(a), a.requireFailure(this)), this; 28106 }, 28107 dropRequireFailure: function(a) { 28108 if (f(a, "dropRequireFailure", this)) { 28109 return this; 28110 } 28111 a = V(a, this); 28112 var b = s(this.requireFail, a); 28113 return b > -1 && this.requireFail.splice(b, 1), this; 28114 }, 28115 hasRequireFailures: function() { 28116 return this.requireFail.length > 0; 28117 }, 28118 canRecognizeWith: function(a) { 28119 return !!this.simultaneous[a.id]; 28120 }, 28121 emit: function(a) { 28122 function b(b) { 28123 c.manager.emit(c.options.event + (b ? T(d) : ""), a); 28124 } 28125 var c = this, 28126 d = this.state; 28127 bc > d && b(!0), b(), d >= bc && b(!0); 28128 }, 28129 tryEmit: function(a) {
28130 return this.canEmit() ? this.emit(a) : void(this.state = ec); 28131 }, 28132 canEmit: function() { 28133 for (var a = 0; a < this.requireFail.length; a++) { 28134 if (!(this.requireFail[a].state & (ec | $b))) { 28135 return !1; 28136 } 28137 } 28138 return !0; 28139 }, 28140 recognize: function(a) { 28141 var b = h({}, a); 28142 return l(this.options.enable, [this, b]) ? (this.state & (cc | dc | ec) && (this.state = $b), this.state = this.process(b), void(this.state & (_b | ac | bc | dc) && this.tryEmit(b))) : (this.reset(), void(this.state = ec)); 28143 }, 28144 process: function() {}, 28145 getTouchAction: function() {}, 28146 reset: function() {} 28147 }, j(W, S, { 28148 defaults: { 28149 pointers: 1 28150 }, 28151 attrTest: function(a) { 28152 var b = this.options.pointers; 28153 return 0 === b || a.pointers.length === b; 28154 }, 28155 process: function(a) { 28156 var b = this.state, 28157 c = a.eventType, 28158 d = b & (_b | ac), 28159 e = this.attrTest(a); 28160 return d && (c & yb || !e) ? b | dc : d || e ? c & xb ? b | bc : b & _b ? b | ac : _b : ec; 28161 } 28162 }), j(X, W, { 28163 defaults: { 28164 event: "pan", 28165 threshold: 10, 28166 pointers: 1, 28167 direction: Gb 28168 }, 28169 getTouchAction: function() { 28170 var a = this.options.direction; 28171 if (a === Gb) { 28172 return [Xb]; 28173 } 28174 var b = []; 28175 return a & Eb && b.push(Zb), a & Fb && b.push(Yb), b; 28176 }, 28177 directionTest: function(a) { 28178 var b = this.options, 28179 c = !0, 28180 d = a.distance, 28181 e = a.direction, 28182 f = a.deltaX, 28183 g = a.deltaY; 28184 return e & b.direction || (b.direction & Eb ? (e = 0 === f ? zb : 0 > f ? Ab : Bb, c = f != this.pX, d = Math.abs(a.deltaX)) : (e = 0 === g ? zb : 0 > g ? Cb : Db, c = g != this.pY, d = Math.abs(a.deltaY))), a.direction = e, c && d > b.threshold && e & b.direction; 28185 }, 28186 attrTest: function(a) { 28187 return W.prototype.attrTest.call(this, a) && (this.state & _b || !(this.state & _b) && this.directionTest(a)); 28188 }, 28189 emit: function(a) { 28190 this.pX = a.deltaX, this.pY = a.deltaY; 28191 var b = U(a.direction); 28192 b && this.manager.emit(this.options.event + b, a), this._super.emit.call(this, a); 28193 } 28194 }), j(Y, W, { 28195 defaults: { 28196 event: "pinch", 28197 threshold: 0, 28198 pointers: 2 28199 }, 28200 getTouchAction: function() { 28201 return [Xb]; 28202 }, 28203 attrTest: function(a) { 28204 return this._super.attrTest.call(this, a) && (Math.abs(a.scale - 1) > this.options.threshold || this.state & _b); 28205 }, 28206 emit: function(a) { 28207 if (this._super.emit.call(this, a), 1 !== a.scale) { 28208 var b = a.scale < 1 ? "in" : "out"; 28209 this.manager.emit(this.options.event + b, a); 28210 } 28211 } 28212 }), j(Z, S, { 28213 defaults: { 28214 event: "press", 28215 pointers: 1, 28216 time: 500, 28217 threshold: 5 28218 }, 28219 getTouchAction: function() { 28220 return [Vb]; 28221 }, 28222 process: function(a) { 28223 var b = this.options, 28224 c = a.pointers.length === b.pointers, 28225 d = a.distance < b.threshold, 28226 f = a.deltaTime > b.time; 28227 if (this._input = a, !d || !c || a.eventType & (xb | yb) && !f) { 28228 this.reset(); 28229 } else { 28230 if (a.eventType & vb) { 28231 this.reset(), this._timer = e(function() { 28232 this.state = cc, this.tryEmit(); 28233 }, b.time, this); 28234 } else { 28235 if (a.eventType & xb) { 28236 return cc; 28237 } 28238 } 28239 } 28240 return ec; 28241 }, 28242 reset: function() { 28243 clearTimeout(this._timer); 28244 }, 28245 emit: function(a) { 28246 this.state === cc && (a && a.eventType & xb ? this.manager.emit(this.options.event + "up", a) : (this._input.timeStamp = kb(), this.manager.emit(this.options.event, this._input))); 28247 } 28248 }), j($, W, { 28249 defaults: { 28250 event: "rotate", 28251 threshold: 0, 28252 pointers: 2 28253 }, 28254 getTouchAction: function() { 28255 return [Xb]; 28256 }, 28257 attrTest: function(a) { 28258 return this._super.attrTest.call(this, a) && (Math.abs(a.rotation) > this.options.threshold || this.state & _b); 28259 } 28260 }), j(_, W, { 28261 defaults: { 28262 event: "swipe", 28263 threshold: 10, 28264 velocity: 0.65, 28265 direction: Eb | Fb, 28266 pointers: 1 28267 }, 28268 getTouchAction: function() { 28269 return X.prototype.getTouchAction.call(this); 28270 }, 28271 attrTest: function(a) { 28272 var b, c = this.options.direction; 28273 return c & (Eb | Fb) ? b = a.velocity : c & Eb ? b = a.velocityX : c & Fb && (b = a.velocityY), this._super.attrTest.call(this, a) && c & a.direction && jb(b) > this.options.velocity && a.eventType & xb; 28274 }, 28275 emit: function(a) { 28276 var b = U(a.direction); 28277 b && this.manager.emit(this.options.event + b, a), this.manager.emit(this.options.event, a); 28278 } 28279 }), j(ab, S, { 28280 defaults: { 28281 event: "tap", 28282 pointers: 1, 28283 taps: 1, 28284 interval: 300, 28285 time: 250, 28286 threshold: 2, 28287 posThreshold: 10 28288 }, 28289 getTouchAction: function() { 28290 return [Wb]; 28291 }, 28292 process: function(a) { 28293 var b = this.options, 28294 c = a.pointers.length === b.pointers, 28295 d = a.distance < b.threshold, 28296 f = a.deltaTime < b.time; 28297 if (this.reset(), a.eventType & vb && 0 === this.count) { 28298 return this.failTimeout(); 28299 } 28300 if (d && f && c) { 28301 if (a.eventType != xb) { 28302 return this.failTimeout(); 28303 } 28304 var g = this.pTime ? a.timeStamp - this.pTime < b.interval : !0, 28305 h = !this.pCenter || H(this.pCenter, a.center) < b.posThreshold;
28306 this.pTime = a.timeStamp, this.pCenter = a.center, h && g ? this.count += 1 : this.count = 1, this._input = a; 28307 var i = this.count % b.taps; 28308 if (0 === i) { 28309 return this.hasRequireFailures() ? (this._timer = e(function() { 28310 this.state = cc, this.tryEmit(); 28311 }, b.interval, this), _b) : cc; 28312 } 28313 } 28314 return ec; 28315 }, 28316 failTimeout: function() { 28317 return this._timer = e(function() { 28318 this.state = ec; 28319 }, this.options.interval, this), ec; 28320 }, 28321 reset: function() { 28322 clearTimeout(this._timer); 28323 }, 28324 emit: function() { 28325 this.state == cc && (this._input.tapCount = this.count, this.manager.emit(this.options.event, this._input)); 28326 } 28327 }), bb.VERSION = "2.0.2", bb.defaults = { 28328 domEvents: !1, 28329 touchAction: Ub, 28330 inputTarget: null, 28331 enable: !0, 28332 preset: [ 28333 [$, { 28334 enable: !1 28335 }], 28336 [Y, { 28337 enable: !1 28338 }, 28339 ["rotate"] 28340 ], 28341 [_, { 28342 direction: Eb 28343 }], 28344 [X, { 28345 direction: Eb 28346 }, 28347 ["swipe"] 28348 ], 28349 [ab], 28350 [ab, { 28351 event: "doubletap", 28352 taps: 2 28353 }, 28354 ["tap"] 28355 ], 28356 [Z] 28357 ], 28358 cssProps: { 28359 userSelect: "none", 28360 touchSelect: "none", 28361 touchCallout: "none", 28362 contentZooming: "none", 28363 userDrag: "none", 28364 tapHighlightColor: "rgba(0,0,0,0)" 28365 } 28366 }; 28367 var fc = 1, 28368 gc = 2; 28369 cb.prototype = { 28370 set: function(a) { 28371 return h(this.options, a), this; 28372 }, 28373 stop: function(a) { 28374 this.session.stopped = a ? gc : fc; 28375 }, 28376 recognize: function(a) { 28377 var b = this.session; 28378 if (!b.stopped) { 28379 this.touchAction.preventDefaults(a); 28380 var c, d = this.recognizers, 28381 e = b.curRecognizer; 28382 (!e || e && e.state & cc) && (e = b.curRecognizer = null); 28383 for (var f = 0, g = d.length; g > f; f++) { 28384 c = d[f], b.stopped === gc || e && c != e && !c.canRecognizeWith(e) ? c.reset() : c.recognize(a), !e && c.state & (_b | ac | bc) && (e = b.curRecognizer = c); 28385 } 28386 } 28387 }, 28388 get: function(a) { 28389 if (a instanceof S) { 28390 return a; 28391 } 28392 for (var b = this.recognizers, c = 0; c < b.length; c++) { 28393 if (b[c].options.event == a) { 28394 return b[c]; 28395 } 28396 } 28397 return null; 28398 }, 28399 add: function(a) { 28400 if (f(a, "add", this)) { 28401 return this; 28402 } 28403 var b = this.get(a.options.event); 28404 return b && this.remove(b), this.recognizers.push(a), a.manager = this, this.touchAction.update(), a; 28405 }, 28406 remove: function(a) { 28407 if (f(a, "remove", this)) { 28408 return this; 28409 } 28410 var b = this.recognizers; 28411 return a = this.get(a), b.splice(s(b, a), 1), this.touchAction.update(), this; 28412 }, 28413 on: function(a, b) { 28414 var c = this.handlers; 28415 return g(r(a), function(a) { 28416 c[a] = c[a] || [], c[a].push(b); 28417 }), this; 28418 }, 28419 off: function(a, b) { 28420 var c = this.handlers; 28421 return g(r(a), function(a) { 28422 b ? c[a].splice(s(c[a], b), 1) : delete c[a]; 28423 }), this; 28424 }, 28425 emit: function(a, b) { 28426 this.options.domEvents && eb(a, b); 28427 var c = this.handlers[a] && this.handlers[a].slice(); 28428 if (c && c.length) { 28429 b.type = a, b.preventDefault = function() { 28430 b.srcEvent.preventDefault(); 28431 }; 28432 for (var d = 0, e = c.length; e > d; d++) { 28433 c[d](b); 28434 } 28435 } 28436 }, 28437 destroy: function() { 28438 this.element && db(this, !1), this.handlers = {}, this.session = {}, this.input.destroy(), this.element = null; 28439 } 28440 }, h(bb, { 28441 INPUT_START: vb, 28442 INPUT_MOVE: wb, 28443 INPUT_END: xb, 28444 INPUT_CANCEL: yb, 28445 STATE_POSSIBLE: $b, 28446 STATE_BEGAN: _b, 28447 STATE_CHANGED: ac, 28448 STATE_ENDED: bc, 28449 STATE_RECOGNIZED: cc, 28450 STATE_CANCELLED: dc, 28451 STATE_FAILED: ec, 28452 DIRECTION_NONE: zb, 28453 DIRECTION_LEFT: Ab, 28454 DIRECTION_RIGHT: Bb, 28455 DIRECTION_UP: Cb, 28456 DIRECTION_DOWN: Db, 28457 DIRECTION_HORIZONTAL: Eb, 28458 DIRECTION_VERTICAL: Fb, 28459 DIRECTION_ALL: Gb, 28460 Manager: cb, 28461 Input: x, 28462 TouchAction: Q, 28463 Recognizer: S, 28464 AttrRecognizer: W, 28465 Tap: ab, 28466 Pan: X, 28467 Swipe: _, 28468 Pinch: Y, 28469 Rotate: $, 28470 Press: Z, 28471 on: n, 28472 off: o, 28473 each: g, 28474 merge: i, 28475 extend: h, 28476 inherit: j, 28477 bindFn: k, 28478 prefixed: v 28479 }), typeof define == hb && define.amd ? define(function() { 28480 return bb; 28481 }) : "undefined" != typeof module && module.exports ? module.exports = bb : a[c] = bb; 28482}(window, document, "Hammer"); 28483 /* Ende hammer */ 28484 /* Start jquery.hammer */ 28485 (function($, Hammer, dataAttr) { 28486 function hammerify(el, options) { 28487 var $el = $(el); 28488 if(!$el.data(dataAttr)) { 28489 $el.data(dataAttr, new Hammer($el[0], options)); 28490 } 28491 } 28492 28493 $.fn.hammer = function(options) { 28494 return this.each(function() { 28495 hammerify(this, options); 28496 }); 28497 }; 28498 28499 // extend the emit method to also trigger jQuery events 28500 Hammer.Manager.prototype.emit = (function(originalEmit) { 28501 return function(type, data) { 28502 originalEmit.call(this, type, data); 28503 jQuery(this.element).triggerHandler({ 28504 type: type, 28505 gesture: data 28506 }); 28507 }; 28508 })(Hammer.Manager.prototype.emit); 28509})(jQuery, Hammer, "hammer"); 28510 /* Ende jquery.hammer */ 28511 /* Start jquery.mmenu */ 28512 /* 28513 * jQuery mmenu v5.5.3 28514 * @requires jQuery 1.7.0 or later 28515 * 28516 * mmenu.frebsite.nl 28517 * 28518 * Copyright (c) Fred Heusschen 28519 * www.frebsite.nl 28520 * 28521 * Licensed under the MIT license: 28522 * http://en.wikipedia.org/wiki/MIT_License 28523 */ 28524 28525(function( $ ) { 28526 28527 var _PLUGIN_ = 'mmenu', 28528 _VERSION_ = '5.5.3'; 28529 28530 28531 // Plugin already excists 28532 if ( $[ _PLUGIN_ ] && $[ _PLUGIN_ ].version > _VERSION_ ) 28533 { 28534 return; 28535 } 28536 28537 28538 /* 28539 Class 28540 */ 28541 $[ _PLUGIN_ ] = function( $menu, opts, conf ) 28542 { 28543 this.$menu = $menu;
28544 this._api = [ 'bind', 'init', 'update', 'setSelected', 'getInstance', 'openPanel', 'closePanel', 'closeAllPanels' ]; 28545 this.opts = opts; 28546 this.conf = conf; 28547 this.vars = {}; 28548 this.cbck = {}; 28549 28550 28551 if ( typeof this.___deprecated == 'function' ) 28552 { 28553 this.___deprecated(); 28554 } 28555 28556 this._initMenu(); 28557 this._initAnchors(); 28558 28559 var $pnls = this.$pnls.children(); 28560 28561 this._initAddons(); 28562 this.init( $pnls ); 28563 28564 28565 if ( typeof this.___debug == 'function' ) 28566 { 28567 this.___debug(); 28568 } 28569 28570 return this; 28571 }; 28572 28573 $[ _PLUGIN_ ].version = _VERSION_; 28574 $[ _PLUGIN_ ].addons = {}; 28575 $[ _PLUGIN_ ].uniqueId = 0; 28576 28577 28578 $[ _PLUGIN_ ].defaults = { 28579 extensions : [], 28580 navbar : { 28581 add : true, 28582 title : 'Menu', 28583 titleLink : 'panel' 28584 }, 28585 onClick : { 28586// close : true, 28587// preventDefault : null, 28588 setSelected : true 28589 }, 28590 slidingSubmenus : true 28591 }; 28592 28593 $[ _PLUGIN_ ].configuration = { 28594 classNames : { 28595 divider : 'Divider', 28596 inset : 'Inset', 28597 panel : 'Panel', 28598 selected : 'Selected', 28599 spacer : 'Spacer', 28600 vertical : 'Vertical' 28601 }, 28602 clone : false, 28603 openingInterval : 25, 28604 panelNodetype : 'ul, ol, div', 28605 transitionDuration : 400 28606 }; 28607 28608 $[ _PLUGIN_ ].prototype = { 28609 28610 init: function( $panels ) 28611 { 28612 $panels = $panels.not( '.' + _c.nopanel ); 28613 $panels = this._initPanels( $panels ); 28614 28615 this.trigger( 'init', $panels ); 28616 this.trigger( 'update' ); 28617 }, 28618 28619 update: function() 28620 { 28621 this.trigger( 'update' ); 28622 }, 28623 28624 setSelected: function( $li ) 28625 { 28626 this.$menu.find( '.' + _c.listview ).children().removeClass( _c.selected ); 28627 $li.addClass( _c.selected ); 28628 this.trigger( 'setSelected', $li ); 28629 }, 28630 28631 openPanel: function( $panel ) 28632 { 28633 var $l = $panel.parent(); 28634 28635 // Vertical 28636 if ( $l.hasClass( _c.vertical ) ) 28637 { 28638 var $sub = $l.parents( '.' + _c.subopened ); 28639 if ( $sub.length ) 28640 { 28641 return this.openPanel( $sub.first() ); 28642 } 28643 $l.addClass( _c.opened ); 28644 } 28645 28646 // Horizontal 28647 else 28648 { 28649 if ( $panel.hasClass( _c.current ) ) 28650 { 28651 return; 28652 } 28653 28654 var $panels = this.$pnls.children( '.' + _c.panel ), 28655 $current = $panels.filter( '.' + _c.current ); 28656 28657 $panels
28658 .removeClass( _c.highest ) 28659 .removeClass( _c.current ) 28660 .not( $panel ) 28661 .not( $current ) 28662 .not( '.' + _c.vertical ) 28663 .addClass( _c.hidden ); 28664 28665 if ( !$[ _PLUGIN_ ].support.csstransitions ) 28666 { 28667 $current.addClass( _c.hidden ); 28668 } 28669 28670 if ( $panel.hasClass( _c.opened ) ) 28671 { 28672 $panel.nextAll( '.' + _c.opened ) 28673 .addClass( _c.highest ) 28674 .removeClass( _c.opened ) 28675 .removeClass( _c.subopened ); 28676 } 28677 else 28678 { 28679 $panel.addClass( _c.highest ); 28680 $current.addClass( _c.subopened ); 28681 } 28682 28683 $panel 28684 .removeClass( _c.hidden ) 28685 .addClass( _c.current ); 28686 28687 // Without the timeout, the animation won't work because the element had display: none; 28688 setTimeout( 28689 function() 28690 { 28691 $panel 28692 .removeClass( _c.subopened ) 28693 .addClass( _c.opened ); 28694 28695 }, this.conf.openingInterval 28696 ); 28697 } 28698 this.trigger( 'openPanel', $panel ); 28699 }, 28700 28701 closePanel: function( $panel ) 28702 { 28703 var $l = $panel.parent(); 28704 28705 // Vertical only 28706 if ( $l.hasClass( _c.vertical ) ) 28707 { 28708 $l.removeClass( _c.opened ); 28709 this.trigger( 'closePanel', $panel ); 28710 } 28711 }, 28712 28713 closeAllPanels: function() 28714 { 28715 // Vertical 28716 this.$menu.find( '.' + _c.listview ) 28717 .children() 28718 .removeClass( _c.selected ) 28719 .filter( '.' + _c.vertical ) 28720 .removeClass( _c.opened ); 28721 28722 // Horizontal 28723 var $pnls = this.$pnls.children( '.' + _c.panel ), 28724 $frst = $pnls.first(); 28725 28726 this.$pnls.children( '.' + _c.panel ) 28727 .not( $frst ) 28728 .removeClass( _c.subopened ) 28729 .removeClass( _c.opened ) 28730 .removeClass( _c.current )
28731 .removeClass( _c.highest ) 28732 .addClass( _c.hidden ); 28733 28734 this.openPanel( $frst ); 28735 }, 28736 28737 togglePanel: function( $panel ) 28738 { 28739 var $l = $panel.parent(); 28740 28741 // Vertical only 28742 if ( $l.hasClass( _c.vertical ) ) 28743 { 28744 this[ $l.hasClass( _c.opened ) ? 'closePanel' : 'openPanel' ]( $panel ); 28745 } 28746 }, 28747 28748 getInstance: function() 28749 { 28750 return this; 28751 }, 28752 28753 bind: function( event, fn ) 28754 { 28755 this.cbck[ event ] = this.cbck[ event ] || []; 28756 this.cbck[ event ].push( fn ); 28757 }, 28758 28759 trigger: function() 28760 { 28761 var that = this, 28762 args = Array.prototype.slice.call( arguments ), 28763 evnt = args.shift(); 28764 28765 if ( this.cbck[ evnt ] ) 28766 { 28767 for ( var e = 0, l = this.cbck[ evnt ].length; e < l; e++ ) 28768 { 28769 this.cbck[ evnt ][ e ].apply( that, args ); 28770 } 28771 } 28772 }, 28773 28774 _initMenu: function() 28775 { 28776 var that = this; 28777 28778 // Clone if needed 28779 if ( this.opts.offCanvas && this.conf.clone ) 28780 { 28781 this.$menu = this.$menu.clone( true ); 28782 this.$menu.add( this.$menu.find( '[id]' ) ) 28783 .filter( '[id]' ) 28784 .each( 28785 function() 28786 { 28787 $(this).attr( 'id', _c.mm( $(this).attr( 'id' ) ) ); 28788 } 28789 ); 28790 } 28791 28792 // Strip whitespace 28793 this.$menu.contents().each( 28794 function() 28795 { 28796 if ( $(this)[ 0 ].nodeType == 3 ) 28797 { 28798 $(this).remove(); 28799 } 28800 } 28801 ); 28802 28803 // Add markup 28804 this.$pnls = $( '<div class="' + _c.panels + '" />' ) 28805 .append( this.$menu.children( this.conf.panelNodetype ) ) 28806 .prependTo( this.$menu ); 28807 28808 // Add classes 28809 this.$menu 28810 .parent() 28811 .addClass( _c.wrapper ); 28812 28813 var clsn = [ _c.menu ]; 28814 28815 // Add direction class 28816 if ( !this.opts.slidingSubmenus ) 28817 { 28818 clsn.push( _c.vertical ); 28819 } 28820 28821 // Add extensions classes 28822 this.opts.extensions = ( this.opts.extensions.length ) 28823 ? 'mm-' + this.opts.extensions.join( ' mm-' ) 28824 : ''; 28825 28826 if ( this.opts.extensions ) 28827 { 28828 clsn.push( this.opts.extensions ); 28829 } 28830 28831 this.$menu.addClass( clsn.join( ' ' ) ); 28832 }, 28833 28834 _initPanels: function( $panels ) 28835 { 28836 var that = this; 28837 28838 // Add List class 28839 var $lists = this.__findAddBack( $panels, 'ul, ol' ); 28840 28841 this.__refactorClass( $lists, this.conf.classNames.inset, 'inset' ) 28842 .addClass( _c.nolistview + ' ' + _c.nopanel ); 28843 28844 $lists.not( '.' + _c.nolistview ) 28845 .addClass( _c.listview ); 28846 28847 var $lis = this.__findAddBack( $panels, '.' + _c.listview ).children(); 28848 28849 // Refactor Selected class 28850 this.__refactorClass( $lis, this.conf.classNames.selected, 'selected' ); 28851 28852 // Refactor divider class 28853 this.__refactorClass( $lis, this.conf.classNames.divider, 'divider' ); 28854 28855 // Refactor Spacer class 28856 this.__refactorClass( $lis, this.conf.classNames.spacer, 'spacer' ); 28857 28858 // Refactor Panel class 28859 this.__refactorClass( this.__findAddBack( $panels, '.' + this.conf.classNames.panel ), this.conf.classNames.panel, 'panel' ); 28860 28861 // Create panels 28862 var $curpanels = $(), 28863 $oldpanels = $panels 28864 .add( $panels.find( '.' + _c.panel ) ) 28865 .add( this.__findAddBack( $panels, '.' + _c.listview ).children().children( this.conf.panelNodetype ) ) 28866 .not( '.' + _c.nopanel ); 28867 28868 this.__refactorClass( $oldpanels, this.conf.classNames.vertical, 'vertical' ); 28869 28870 if ( !this.opts.slidingSubmenus ) 28871 { 28872 $oldpanels.addClass( _c.vertical ); 28873 } 28874 28875 $oldpanels 28876 .each( 28877 function() 28878 { 28879 var $t = $(this), 28880 $p = $t; 28881 28882 if ( $t.is( 'ul, ol' ) ) 28883 { 28884 $t.wrap( '<div class="' + _c.panel + '" />' ); 28885 $p = $t.parent(); 28886 } 28887 else 28888 { 28889 $p.addClass( _c.panel ); 28890 } 28891 28892 var id = $t.attr( 'id' ); 28893 $t.removeAttr( 'id' ); 28894 $p.attr( 'id', id || that.__getUniqueId() ); 28895 28896 if ( $t.hasClass( _c.vertical ) ) 28897 { 28898 $t.removeClass( that.conf.classNames.vertical ); 28899 $p.add( $p.parent() ).addClass( _c.vertical ); 28900 } 28901 28902 $curpanels = $curpanels.add( $p ); 28903 } 28904 ); 28905 28906 var $allpanels = $('.' + _c.panel, this.$menu); 28907 28908 // Add open and close links to menu items 28909 $curpanels 28910 .each( 28911 function( i ) 28912 { 28913 var $t = $(this), 28914 $p = $t.parent(), 28915 $a = $p.children( 'a, span' ).first(); 28916 28917 if ( !$p.is( '.' + _c.panels ) ) 28918 { 28919 $p.data( _d.sub, $t ); 28920 $t.data( _d.parent, $p ); 28921 } 28922 28923 // Open link 28924 if ( !$p.children( '.' + _c.next ).length ) 28925 { 28926 if ( $p.parent().is( '.' + _c.listview ) ) 28927 { 28928 var id = $t.attr( 'id' ),
28929 $b = $( '<a class="' + _c.next + '" href="#' + id + '" data-target="#' + id + '" />' ).insertBefore( $a ); 28930 28931 if ( $a.is( 'span' ) ) 28932 { 28933 $b.addClass( _c.fullsubopen ); 28934 } 28935 } 28936 } 28937 28938 // Navbar 28939 if ( !$t.children( '.' + _c.navbar ).length ) 28940 { 28941 if ( !$p.hasClass( _c.vertical ) ) 28942 { 28943 if ( $p.parent().is( '.' + _c.listview ) ) 28944 { 28945 // Listview, the panel wrapping this panel 28946 var $p = $p.closest( '.' + _c.panel ); 28947 } 28948 else 28949 { 28950 // Non-listview, the first panel that has an anchor that links to this panel 28951 var $a = $p.closest( '.' + _c.panel ).find( 'a[href="#' + $t.attr( 'id' ) + '"]' ).first(), 28952 $p = $a.closest( '.' + _c.panel ); 28953 } 28954 28955 var $navbar = $( '<div class="' + _c.navbar + '" />' ); 28956 28957 if ( $p.length ) 28958 { 28959 var id = $p.attr( 'id' ); 28960 switch ( that.opts.navbar.titleLink ) 28961 { 28962 case 'anchor': 28963 _url = $a.attr( 'href' ); 28964 break; 28965 28966 case 'panel': 28967 case 'parent': 28968 _url = '#' + id; 28969 break; 28970 28971 case 'none': 28972 default: 28973 _url = false; 28974 break; 28975 } 28976 28977 $navbar 28978 .append( '<a class="' + _c.btn + ' ' + _c.prev + '" href="#' + id + '" data-target="#' + id + '" />' ) 28979 .append( $('<a class="' + _c.title + '"' + ( _url ? ' href="' + _url + '"' : '' ) + ' />').text( $a.text() ) ) 28980 .prependTo( $t ); 28981 28982 if ( that.opts.navbar.add ) 28983 { 28984 $t.addClass( _c.hasnavbar ); 28985 } 28986 } 28987 else if ( that.opts.navbar.title ) 28988 { 28989 $navbar 28990 .append( '<a class="' + _c.title + '">' + that.opts.navbar.title + '</a>' ) 28991 .prependTo( $t ); 28992 28993 if ( that.opts.navbar.add ) 28994 { 28995 $t.addClass( _c.hasnavbar ); 28996 } 28997 } 28998 } 28999 } 29000 } 29001 ); 29002 29003 29004 // Add opened-classes to parents 29005 var $s = this.__findAddBack( $panels, '.' + _c.listview ) 29006 .children( '.' + _c.selected ) 29007 .removeClass( _c.selected ) 29008 .last() 29009 .addClass( _c.selected ); 29010 29011 $s.add( $s.parentsUntil( '.' + _c.menu, 'li' ) ) 29012 .filter( '.' + _c.vertical ) 29013 .addClass( _c.opened ) 29014 .end() 29015 .not( '.' + _c.vertical ) 29016 .each( 29017 function() 29018 { 29019 $(this).parentsUntil( '.' + _c.menu, '.' + _c.panel ) 29020 .not( '.' + _c.vertical ) 29021 .first() 29022 .addClass( _c.opened ) 29023 .parentsUntil( '.' + _c.menu, '.' + _c.panel ) 29024 .not( '.' + _c.vertical ) 29025 .first() 29026 .addClass( _c.opened ) 29027 .addClass( _c.subopened ); 29028 } 29029 ); 29030 29031 29032 // Add opened-classes to child 29033 $s.children( '.' + _c.panel ) 29034 .not( '.' + _c.vertical ) 29035 .addClass( _c.opened ) 29036 .parentsUntil( '.' + _c.menu, '.' + _c.panel ) 29037 .not( '.' + _c.vertical ) 29038 .first() 29039 .addClass( _c.opened ) 29040 .addClass( _c.subopened ); 29041 29042 29043 // Set current opened 29044 var $current = $allpanels.filter( '.' + _c.opened ); 29045 if ( !$current.length ) 29046 { 29047 $current = $curpanels.first(); 29048 } 29049 $current 29050 .addClass( _c.opened ) 29051 .last() 29052 .addClass( _c.current ); 29053 29054 29055 // Rearrange markup 29056 $curpanels 29057 .not( '.' + _c.vertical ) 29058 .not( $current.last() ) 29059 .addClass( _c.hidden ) 29060 .end() 29061 .appendTo( this.$pnls ); 29062 29063 return $curpanels; 29064 }, 29065 29066 _initAnchors: function() 29067 { 29068 var that = this; 29069 29070 glbl.$body 29071 .on( _e.click + '-oncanvas', 29072 'a[href]', 29073 function( e ) 29074 { 29075 var $t = $(this), 29076 fired = false, 29077 inMenu = that.$menu.find( $t ).length; 29078 29079 // Find behavior for addons 29080 for ( var a in $[ _PLUGIN_ ].addons ) 29081 { 29082 if ( fired = $[ _PLUGIN_ ].addons[ a ].clickAnchor.call( that, $t, inMenu ) ) 29083 { 29084 break; 29085 } 29086 } 29087 29088 // Open/Close panel 29089 if ( !fired && inMenu ) 29090 { 29091 var _h = $t.attr( 'href' ); 29092 if ( _h.length > 1 && _h.slice( 0, 1 ) == '#' ) 29093 { 29094 try 29095 { 29096 var $h = $(_h, that.$menu); 29097 if ( $h.is( '.' + _c.panel ) ) 29098 { 29099 fired = true; 29100 that[ $t.parent().hasClass( _c.vertical ) ? 'togglePanel' : 'openPanel' ]( $h ); 29101 } 29102 } 29103 catch( err ) {} 29104 } 29105 } 29106 29107 if ( fired ) 29108 { 29109 e.preventDefault(); 29110 } 29111 29112 29113 // All other anchors in lists 29114 if ( !fired && inMenu ) 29115 { 29116 if ( $t.is( '.' + _c.listview + ' > li > a' ) 29117 && !$t.is( '[rel="external"]' ) 29118 && !$t.is( '[target="_blank"]' ) ) 29119 { 29120 29121 // Set selected item 29122 if ( that.__valueOrFn( that.opts.onClick.setSelected, $t ) ) 29123 { 29124 that.setSelected( $(e.target).parent() ); 29125 } 29126 29127 // Prevent default / don't follow link. Default: false 29128 var preventDefault = that.__valueOrFn( that.opts.onClick.preventDefault, $t, _h.slice( 0, 1 ) == '#' ); 29129 if ( preventDefault ) 29130 { 29131 e.preventDefault(); 29132 } 29133 29134 // Close menu. Default: true if preventDefault, false otherwise 29135 if ( that.__valueOrFn( that.opts.onClick.close, $t, preventDefault ) ) 29136 { 29137 that.close(); 29138 } 29139 } 29140 } 29141 } 29142 ); 29143 }, 29144 29145 _initAddons: function() 29146 { 29147 // Add add-ons to plugin 29148 for ( var a in $[ _PLUGIN_ ].addons ) 29149 { 29150 $[ _PLUGIN_ ].addons[ a ].add.call( this ); 29151 $[ _PLUGIN_ ].addons[ a ].add = function() {}; 29152 } 29153 29154 // Setup adds-on for menu 29155 for ( var a in $[ _PLUGIN_ ].addons ) 29156 { 29157 $[ _PLUGIN_ ].addons[ a ].setup.call( this ); 29158 } 29159 }, 29160 29161 __api: function() 29162 { 29163 var that = this, 29164 api = {}; 29165 29166 $.each( this._api, 29167 function( i ) 29168 { 29169 var fn = this; 29170 api[ fn ] = function() 29171 { 29172 var re = that[ fn ].apply( that, arguments ); 29173 return ( typeof re == 'undefined' ) ? api : re; 29174 } 29175 } 29176 ); 29177 return api; 29178 }, 29179 29180 __valueOrFn: function( o, $e, d ) 29181 { 29182 if ( typeof o == 'function' ) 29183 { 29184 return o.call( $e[ 0 ] ); 29185 } 29186 if ( typeof o == 'undefined' && typeof d != 'undefined' ) 29187 { 29188 return d; 29189 } 29190 return o; 29191 }, 29192 29193 __refactorClass: function( $e, o, c ) 29194 { 29195 return $e.filter( '.' + o ).removeClass( o ).addClass( _c[ c ] ); 29196 }, 29197 29198 __findAddBack: function( $e, s ) 29199 { 29200 return $e.find( s ).add( $e.filter( s ) ); 29201 }, 29202 29203 __filterListItems: function( $i ) 29204 { 29205 return $i 29206 .not( '.' + _c.divider ) 29207 .not( '.' + _c.hidden ); 29208 }, 29209 29210 __transitionend: function( $e, fn, duration ) 29211 { 29212 var _ended = false, 29213 _fn = function() 29214 { 29215 if ( !_ended ) 29216 { 29217 fn.call( $e[ 0 ] ); 29218 } 29219 _ended = true; 29220 }; 29221 29222 $e.one( _e.transitionend, _fn ); 29223 $e.one( _e.webkitTransitionEnd, _fn ); 29224 setTimeout( _fn, duration * 1.1 ); 29225 }, 29226 29227 __getUniqueId: function() 29228 { 29229 return _c.mm( $[ _PLUGIN_ ].uniqueId++ ); 29230 } 29231 }; 29232 29233 29234 /* 29235 jQuery plugin 29236 */ 29237 $.fn[ _PLUGIN_ ] = function( opts, conf ) 29238 { 29239 // First time plugin is fired 29240 initPlugin(); 29241 29242 // Extend options 29243 opts = $.extend( true, {}, $[ _PLUGIN_ ].defaults, opts ); 29244 conf = $.extend( true, {}, $[ _PLUGIN_ ].configuration, conf ); 29245 29246 return this.each( 29247 function() 29248 { 29249 var $menu = $(this); 29250 if ( $menu.data( _PLUGIN_ ) ) 29251 { 29252 return; 29253 } 29254 var _menu = new $[ _PLUGIN_ ]( $menu, opts, conf ); 29255 $menu.data( _PLUGIN_, _menu.__api() ); 29256 } 29257 ); 29258 }; 29259 29260 29261 /* 29262 SUPPORT 29263 */ 29264 $[ _PLUGIN_ ].support = { 29265 touch: 'ontouchstart' in window || navigator.msMaxTouchPoints, 29266 csstransitions: (function() 29267 { 29268 // Use Modernizr test 29269 if ( typeof Modernizr !== 'undefined' && 29270 typeof Modernizr.csstransitions !== 'undefined' 29271 ) { 29272 return Modernizr.csstransitions; 29273 } 29274 29275 var b = document.body || document.documentElement, 29276 s = b.style, 29277 p = 'transition'; 29278 29279 // Default support 29280 if ( typeof s[ p ] == 'string' ) 29281 { 29282 return true; 29283 } 29284
29285 // Vendor specific support 29286 var v = [ 'Moz', 'webkit', 'Webkit', 'Khtml', 'O', 'ms' ]; 29287 p = p.charAt( 0 ).toUpperCase() + p.substr( 1 ); 29288 29289 for ( var i = 0; i < v.length; i++ ) 29290 { 29291 if ( typeof s[ v[ i ] + p ] == 'string' ) 29292 { 29293 return true; 29294 } 29295 } 29296 29297 // No support 29298 return false; 29299 })() 29300 }; 29301 29302 29303 // Global variables 29304 var _c, _d, _e, glbl; 29305 29306 function initPlugin() 29307 { 29308 if ( $[ _PLUGIN_ ].glbl ) 29309 { 29310 return; 29311 } 29312 29313 glbl = { 29314 $wndw : $(window), 29315 $html : $('html'), 29316 $body : $('body') 29317 }; 29318 29319 29320 // Classnames, Datanames, Eventnames 29321 _c = {}; 29322 _d = {}; 29323 _e = {}; 29324 $.each( [ _c, _d, _e ], 29325 function( i, o ) 29326 { 29327 o.add = function( a ) 29328 { 29329 a = a.split( ' ' ); 29330 for ( var b = 0, l = a.length; b < l; b++ ) 29331 { 29332 o[ a[ b ] ] = o.mm( a[ b ] ); 29333 } 29334 }; 29335 } 29336 ); 29337 29338 // Classnames 29339 _c.mm = function( c ) { return 'mm-' + c; }; 29340 _c.add( 'wrapper menu panels panel nopanel current highest opened subopened navbar hasnavbar title btn prev next listview nolistview inset vertical selected divider spacer hidden fullsubopen' ); 29341 _c.umm = function( c ) 29342 { 29343 if ( c.slice( 0, 3 ) == 'mm-' ) 29344 { 29345 c = c.slice( 3 ); 29346 } 29347 return c; 29348 }; 29349 29350 // Datanames 29351 _d.mm = function( d ) { return 'mm-' + d; }; 29352 _d.add( 'parent sub' ); 29353 29354 // Eventnames 29355 _e.mm = function( e ) { return e + '.mm'; }; 29356 _e.add( 'transitionend webkitTransitionEnd mousedown mouseup touchstart touchmove touchend click keydown' ); 29357 29358 $[ _PLUGIN_ ]._c = _c; 29359 $[ _PLUGIN_ ]._d = _d; 29360 $[ _PLUGIN_ ]._e = _e; 29361 29362 $[ _PLUGIN_ ].glbl = glbl; 29363 } 29364 29365 29366})( jQuery ); 29367 29368 29369/* 29370 * jQuery mmenu offCanvas addon 29371 * mmenu.frebsite.nl 29372 * 29373 * Copyright (c) Fred Heusschen 29374 */ 29375 29376(function( $ ) { 29377 29378 var _PLUGIN_ = 'mmenu', 29379 _ADDON_ = 'offCanvas'; 29380 29381 29382 $[ _PLUGIN_ ].addons[ _ADDON_ ] = { 29383 29384 // setup: fired once per menu 29385 setup: function() 29386 { 29387 if ( !this.opts[ _ADDON_ ] ) 29388 { 29389 return; 29390 } 29391 29392 var that = this, 29393 opts = this.opts[ _ADDON_ ], 29394 conf = this.conf[ _ADDON_ ]; 29395 29396 glbl = $[ _PLUGIN_ ].glbl; 29397 29398 29399 // Add methods to api 29400 this._api = $.merge( this._api, [ 'open', 'close', 'setPage' ] ); 29401 29402 29403 // Debug positioning 29404 if ( opts.position == 'top' || opts.position == 'bottom' ) 29405 { 29406 opts.zposition = 'front'; 29407 } 29408 29409 29410 // Extend configuration 29411 if ( typeof conf.pageSelector != 'string' ) 29412 { 29413 conf.pageSelector = '> ' + conf.pageNodetype; 29414 } 29415 29416 29417 glbl.$allMenus = ( glbl.$allMenus || $() ).add( this.$menu ); 29418 29419 29420 // Setup the menu 29421 this.vars.opened = false; 29422 29423 var clsn = [ _c.offcanvas ]; 29424 29425 if ( opts.position != 'left' ) 29426 { 29427 clsn.push( _c.mm( opts.position ) ); 29428 } 29429 if ( opts.zposition != 'back' ) 29430 { 29431 clsn.push( _c.mm( opts.zposition ) ); 29432 } 29433 29434 this.$menu 29435 .addClass( clsn.join( ' ' ) ) 29436 .parent() 29437 .removeClass( _c.wrapper ); 29438 29439 29440 // Setup the page 29441 this.setPage( glbl.$page ); 29442 29443 29444 // Setup the UI blocker and the window 29445 this._initBlocker(); 29446 this[ '_initWindow_' + _ADDON_ ](); 29447 29448 29449 // Append to the body 29450 this.$menu[ conf.menuInjectMethod + 'To' ]( conf.menuWrapperSelector ); 29451 }, 29452 29453 // add: fired once per page load 29454 add: function() 29455 { 29456 _c = $[ _PLUGIN_ ]._c; 29457 _d = $[ _PLUGIN_ ]._d; 29458 _e = $[ _PLUGIN_ ]._e; 29459 29460 _c.add( 'offcanvas slideout blocking modal background opening blocker page' ); 29461 _d.add( 'style' ); 29462 _e.add( 'resize' ); 29463 }, 29464 29465 // clickAnchor: prevents default behavior when clicking an anchor 29466 clickAnchor: function( $a, inMenu ) 29467 { 29468 if ( !this.opts[ _ADDON_ ] ) 29469 { 29470 return false; 29471 } 29472 29473 // Open menu 29474 var id = this.$menu.attr( 'id' ); 29475 if ( id && id.length ) 29476 { 29477 if ( this.conf.clone ) 29478 { 29479 id = _c.umm( id ); 29480 } 29481 if ( $a.is( '[href="#' + id + '"]' ) ) 29482 { 29483 this.open(); 29484 return true; 29485 } 29486 } 29487 29488 // Close menu 29489 if ( !glbl.$page ) 29490 { 29491 return; 29492 } 29493 var id = glbl.$page.first().attr( 'id' ); 29494 if ( id && id.length ) 29495 { 29496 if ( $a.is( '[href="#' + id + '"]' ) ) 29497 { 29498 this.close(); 29499 return true; 29500 } 29501 } 29502 29503 return false;
29504 } 29505 }; 29506 29507 29508 // Default options and configuration 29509 $[ _PLUGIN_ ].defaults[ _ADDON_ ] = { 29510 position : 'left', 29511 zposition : 'back', 29512 blockUI : true, // 'modal' 29513 moveBackground : true 29514 }; 29515 $[ _PLUGIN_ ].configuration[ _ADDON_ ] = { 29516 pageNodetype : 'div', 29517 pageSelector : null, 29518 noPageSelector : [], 29519 wrapPageIfNeeded : true, 29520 menuWrapperSelector : 'body', 29521 menuInjectMethod : 'prepend' 29522 }; 29523 29524 29525 // Methods 29526 $[ _PLUGIN_ ].prototype.open = function() 29527 { 29528 if ( this.vars.opened ) 29529 { 29530 return; 29531 } 29532 29533 var that = this; 29534 29535 this._openSetup(); 29536 29537 // Without the timeout, the animation won't work because the menu had display: none; 29538 setTimeout( 29539 function() 29540 { 29541 that._openFinish(); 29542 }, this.conf.openingInterval 29543 ); 29544 this.trigger( 'open' ); 29545 }; 29546 29547 $[ _PLUGIN_ ].prototype._openSetup = function() 29548 { 29549 var that = this, 29550 opts = this.opts[ _ADDON_ ]; 29551 29552 // Close other menus 29553 this.closeAllOthers(); 29554 29555 // Store style and position 29556 glbl.$page.each( 29557 function() 29558 { 29559 $(this).data( _d.style, $(this).attr( 'style' ) || '' ); 29560 } 29561 ); 29562 29563 // Trigger window-resize to measure height 29564 glbl.$wndw.trigger( _e.resize + '-' + _ADDON_, [ true ] ); 29565 29566 var clsn = [ _c.opened ]; 29567 29568 // Add options 29569 if ( opts.blockUI ) 29570 { 29571 clsn.push( _c.blocking ); 29572 } 29573 if ( opts.blockUI == 'modal' ) 29574 { 29575 clsn.push( _c.modal ); 29576 } 29577 if ( opts.moveBackground ) 29578 { 29579 clsn.push( _c.background ); 29580 } 29581 if ( opts.position != 'left' ) 29582 { 29583 clsn.push( _c.mm( this.opts[ _ADDON_ ].position ) ); 29584 } 29585 if ( opts.zposition != 'back' ) 29586 { 29587 clsn.push( _c.mm( this.opts[ _ADDON_ ].zposition ) ); 29588 } 29589 if ( this.opts.extensions ) 29590 { 29591 clsn.push( this.opts.extensions ); 29592 } 29593 glbl.$html.addClass( clsn.join( ' ' ) ); 29594 29595 // Open 29596 setTimeout(function(){ 29597 that.vars.opened = true; 29598 },this.conf.openingInterval); 29599 29600 this.$menu.addClass( _c.current + ' ' + _c.opened ); 29601 }; 29602 29603 $[ _PLUGIN_ ].prototype._openFinish = function() 29604 { 29605 var that = this; 29606 29607 // Callback 29608 this.__transitionend( glbl.$page.first(), 29609 function() 29610 { 29611 that.trigger( 'opened' ); 29612 }, this.conf.transitionDuration 29613 ); 29614 29615 // Opening 29616 glbl.$html.addClass( _c.opening ); 29617 this.trigger( 'opening' ); 29618 }; 29619 29620 $[ _PLUGIN_ ].prototype.close = function() 29621 { 29622 if ( !this.vars.opened ) 29623 { 29624 return; 29625 } 29626 29627 var that = this; 29628 29629 // Callback 29630 this.__transitionend( glbl.$page.first(), 29631 function() 29632 { 29633 that.$menu 29634 .removeClass( _c.current ) 29635 .removeClass( _c.opened ); 29636 29637 glbl.$html 29638 .removeClass( _c.opened ) 29639 .removeClass( _c.blocking ) 29640 .removeClass( _c.modal ) 29641 .removeClass( _c.background ) 29642 .removeClass( _c.mm( that.opts[ _ADDON_ ].position ) ) 29643 .removeClass( _c.mm( that.opts[ _ADDON_ ].zposition ) ); 29644 29645 if ( that.opts.extensions ) 29646 { 29647 glbl.$html.removeClass( that.opts.extensions ); 29648 } 29649 29650 // Restore style and position 29651 glbl.$page.each( 29652 function() 29653 { 29654 $(this).attr( 'style', $(this).data( _d.style ) ); 29655 } 29656 ); 29657 29658 that.vars.opened = false; 29659 that.trigger( 'closed' ); 29660 29661 }, this.conf.transitionDuration 29662 ); 29663 29664 // Closing 29665 glbl.$html.removeClass( _c.opening ); 29666 this.trigger( 'close' ); 29667 this.trigger( 'closing' ); 29668 }; 29669 29670 $[ _PLUGIN_ ].prototype.closeAllOthers = function() 29671 { 29672 glbl.$allMenus 29673 .not( this.$menu ) 29674 .each( 29675 function() 29676 { 29677 var api = $(this).data( _PLUGIN_ ); 29678 if ( api && api.close ) 29679 { 29680 api.close(); 29681 } 29682 } 29683 ); 29684 } 29685 29686 $[ _PLUGIN_ ].prototype.setPage = function( $page ) 29687 { 29688 var that = this, 29689 conf = this.conf[ _ADDON_ ]; 29690 29691 if ( !$page || !$page.length ) 29692 { 29693 $page = glbl.$body.find( conf.pageSelector ); 29694 29695 if ( conf.noPageSelector.length ) 29696 { 29697 $page = $page.not( conf.noPageSelector.join( ', ' ) ); 29698 } 29699 if ( $page.length > 1 && conf.wrapPageIfNeeded ) 29700 { 29701 $page = $page 29702 .wrapAll( '<' + this.conf[ _ADDON_ ].pageNodetype + ' />' ) 29703 .parent(); 29704 } 29705 } 29706 29707 $page.each( 29708 function() 29709 { 29710 $(this).attr( 'id', $(this).attr( 'id' ) || that.__getUniqueId() ); 29711 } 29712 ); 29713 $page.addClass( _c.page + ' ' + _c.slideout ); 29714 glbl.$page = $page; 29715 29716 this.trigger( 'setPage', $page ); 29717 }; 29718 29719 $[ _PLUGIN_ ].prototype[ '_initWindow_' + _ADDON_ ] = function() 29720 { 29721 // Prevent tabbing 29722 glbl.$wndw 29723 .off( _e.keydown + '-' + _ADDON_ ) 29724 .on( _e.keydown + '-' + _ADDON_, 29725 function( e ) 29726 { 29727 if ( glbl.$html.hasClass( _c.opened ) ) 29728 { 29729 if ( e.keyCode == 9 ) 29730 { 29731 e.preventDefault(); 29732 return false;
29733 } 29734 } 29735 } 29736 ); 29737 29738 // Set page min-height to window height 29739 var _h = 0; 29740 glbl.$wndw 29741 .off( _e.resize + '-' + _ADDON_ ) 29742 .on( _e.resize + '-' + _ADDON_, 29743 function( e, force ) 29744 { 29745 if ( glbl.$page.length == 1 ) 29746 { 29747 if ( force || glbl.$html.hasClass( _c.opened ) ) 29748 { 29749 var nh = glbl.$wndw.height(); 29750 if ( force || nh != _h ) 29751 { 29752 _h = nh; 29753 glbl.$page.css( 'minHeight', nh ); 29754 } 29755 } 29756 } 29757 } 29758 ); 29759 }; 29760 29761 $[ _PLUGIN_ ].prototype._initBlocker = function() 29762 { 29763 var that = this; 29764 29765 if ( !this.opts[ _ADDON_ ].blockUI ) 29766 { 29767 return; 29768 } 29769 29770 if ( !glbl.$blck ) 29771 { 29772 glbl.$blck = $( '<div id="' + _c.blocker + '" class="' + _c.slideout + '" />' ); 29773 } 29774 29775 glbl.$blck 29776 .appendTo( glbl.$body ) 29777 .off( _e.touchstart + '-' + _ADDON_ + ' ' + _e.touchmove + '-' + _ADDON_ ) 29778 .on( _e.touchstart + '-' + _ADDON_ + ' ' + _e.touchmove + '-' + _ADDON_, 29779 function( e ) 29780 { 29781 e.preventDefault(); 29782 e.stopPropagation(); 29783 glbl.$blck.trigger( _e.mousedown + '-' + _ADDON_ ); 29784 } 29785 ) 29786 .off( _e.mousedown + '-' + _ADDON_ ) 29787 .on( _e.mousedown + '-' + _ADDON_, 29788 function( e ) 29789 { 29790 e.preventDefault(); 29791 if ( !glbl.$html.hasClass( _c.modal ) ) 29792 { 29793 that.closeAllOthers(); 29794 that.close(); 29795 } 29796 } 29797 ); 29798 }; 29799 29800 29801 var _c, _d, _e, glbl; 29802 29803})( jQuery ); 29804 /* Ende jquery.mmenu */ 29805 /* Start jquery.mmenu.searchfield */ 29806 (function($){var _PLUGIN_="mmenu",_ADDON_="searchfield";$[_PLUGIN_].addons[_ADDON_]={setup:function(){var that=this,opts=this.opts[_ADDON_],conf=this.conf[_ADDON_];glbl=$[_PLUGIN_].glbl;if(typeof opts=="boolean"){opts={add:opts};}if(typeof opts!="object"){opts={};}opts=this.opts[_ADDON_]=$.extend(true,{},$[_PLUGIN_].defaults[_ADDON_],opts);this.bind("close",function(){this.$menu.find("."+_c.search).find("input").blur();});this.bind("init",function($panels){if(opts.add){switch(opts.addTo){case"panels":var $wrapper=$panels;break;default:var $wrapper=$(opts.addTo,this.$menu);break;}$wrapper.each(function(){var $panl=$(this);if($panl.is("."+_c.panel)&&$panl.is("."+_c.vertical)){return;}if(!$panl.children("."+_c.search).length){var _srch=(conf.form)?"form":"div";var $srch=$("<"+_srch+' class="'+_c.search+'" />');if(conf.form&&typeof conf.form=="object"){for(var f in conf.form){$srch.attr(f,conf.form[f]);}}$srch.append('<input placeholder="'+opts.placeholder+'" type="text" autocomplete="off" />');if($panl.hasClass(_c.search)){$panl.replaceWith($srch);}else{$panl.prepend($srch).addClass(_c.hassearch);}}if(opts.noResults){var inPanel=$panl.closest("."+_c.panel).length;if(!inPanel){$panl=that.$pnls.children("."+_c.panel).first();}if(!$panl.children("."+_c.noresultsmsg).length){var $lst=$panl.children("."+_c.listview).first();$('<div class="'+_c.noresultsmsg+'" />').append(opts.noResults)[$lst.length?"insertAfter":"prependTo"]($lst.length?$lst:$panl);}}});if(opts.search){$("."+_c.search,this.$menu).each(function(){var $srch=$(this),inPanel=$srch.closest("."+_c.panel).length;if(inPanel){var $pnls=$srch.closest("."+_c.panel),$panl=$pnls;}else{var $pnls=$("."+_c.panel,that.$menu),$panl=that.$menu;}var $inpt=$srch.children("input"),$itms=that.__findAddBack($pnls,"."+_c.listview).children("li"),$dvdr=$itms.filter("."+_c.divider),$rslt=that.__filterListItems($itms);var _anchor="> a",_both=_anchor+", > span";var search=function(){var query=$inpt.val().toLowerCase();$pnls.scrollTop(0);$rslt.add($dvdr).addClass(_c.hidden).find("."+_c.fullsubopensearch).removeClass(_c.fullsubopen).removeClass(_c.fullsubopensearch);$rslt.each(function(){var $item=$(this),_search=_anchor;if(opts.showTextItems||(opts.showSubPanels&&$item.find("."+_c.next))){_search=_both;}if($(_search,$item).text().toLowerCase().indexOf(query)>-1){$item.add($item.prevAll("."+_c.divider).first()).removeClass(_c.hidden);}});if(opts.showSubPanels){$pnls.each(function(i){var $panl=$(this);that.__filterListItems($panl.find("."+_c.listview).children()).each(function(){var $li=$(this),$su=$li.data(_d.sub);$li.removeClass(_c.nosubresults);if($su){$su.find("."+_c.listview).children().removeClass(_c.hidden);}});});}$($pnls.get().reverse()).each(function(i){var $panl=$(this),$prnt=$panl.data(_d.parent);if($prnt){if(that.__filterListItems($panl.find("."+_c.listview).children()).length){if($prnt.hasClass(_c.hidden)){$prnt.children("."+_c.next).not("."+_c.fullsubopen).addClass(_c.fullsubopen).addClass(_c.fullsubopensearch);}$prnt.removeClass(_c.hidden).removeClass(_c.nosubresults).prevAll("."+_c.divider).first().removeClass(_c.hidden);}else{if(!inPanel){if($panl.hasClass(_c.opened)){setTimeout(function(){that.openPanel
29806($prnt.closest("."+_c.panel));},(i+1)*(that.conf.openingInterval*1.5));}$prnt.addClass(_c.nosubresults);}}}});$panl[$rslt.not("."+_c.hidden).length?"removeClass":"addClass"](_c.noresults);this.update();};$inpt.off(_e.keyup+"-searchfield "+_e.change+"-searchfield").on(_e.keyup+"-searchfield",function(e){if(!preventKeypressSearch(e.keyCode)){search.call(that);}}).on(_e.change+"-searchfield",function(e){search.call(that);});});}}});},add:function(){_c=$[_PLUGIN_]._c;_d=$[_PLUGIN_]._d;_e=$[_PLUGIN_]._e;_c.add("search hassearch noresultsmsg noresults nosubresults fullsubopensearch");_e.add("change keyup");},clickAnchor:function($a,inMenu){}};$[_PLUGIN_].defaults[_ADDON_]={add:false,addTo:"panels",search:true,placeholder:"Search",noResults:"No results found.",showTextItems:false,showSubPanels:true};$[_PLUGIN_].configuration[_ADDON_]={form:false};var _c,_d,_e,glbl;function preventKeypressSearch(c){switch(c){case 9:case 16:case 17:case 18:case 37:case 38:case 39:case 40:return true;}return false;}})(jQuery); 29807 29808 /* Ende jquery.mmenu.searchfield */ 29809 /* Start jquery.mmenu.navbars */ 29810 /* 29811 * jQuery mmenu navbar addon 29812 * mmenu.frebsite.nl 29813 * 29814 * Copyright (c) Fred Heusschen 29815 */ 29816!function(n){var a="mmenu",t="navbars";n[a].addons[t]={setup:function(){var r=this,s=this.opts[t],c=this.conf[t];if(i=n[a].glbl,"undefined"!=typeof s){s instanceof Array||(s=[s]);var d={};n.each(s,function(i){var o=s[i];"boolean"==typeof o&&o&&(o={}),"object"!=typeof o&&(o={}),"undefined"==typeof o.content&&(o.content=["prev","title"]),o.content instanceof Array||(o.content=[o.content]),o=n.extend(!0,{},r.opts.navbar,o);var l=o.position,h=o.height;"number"!=typeof h&&(h=1),h=Math.min(4,Math.max(1,h)),"bottom"!=l&&(l="top"),d[l]||(d[l]=0),d[l]++;var f=n("<div />").addClass(e.navbar+" "+e.navbar+"-"+l+" "+e.navbar+"-"+l+"-"+d[l]+" "+e.navbar+"-size-"+h);d[l]+=h-1;for(var v=0,p=o.content.length;p>v;v++){var u=n[a].addons[t][o.content[v]]||!1;u?u.call(r,f,o,c):(u=o.content[v],u instanceof n||(u=n(o.content[v])),u.each(function(){f.append(n(this))}))}var b=Math.ceil(f.children().not("."+e.btn).length/h);b>1&&f.addClass(e.navbar+"-content-"+b),f.children("."+e.btn).length&&f.addClass(e.hasbtns),f.prependTo(r.$menu)});for(var o in d)r.$menu.addClass(e.hasnavbar+"-"+o+"-"+d[o])}},add:function(){e=n[a]._c,r=n[a]._d,s=n[a]._e,e.add("close hasbtns")},clickAnchor:function(){}},n[a].configuration[t]={breadcrumbSeparator:"/"},n[a].configuration.classNames[t]={panelTitle:"Title",panelNext:"Next",panelPrev:"Prev"};var e,r,s,i}(jQuery),/* 29817 * jQuery mmenu navbar addon breadcrumbs content 29818 * mmenu.frebsite.nl 29819 * 29820 * Copyright (c) Fred Heusschen 29821 */ 29822function(n){var a="mmenu",t="navbars",e="breadcrumbs";n[a].addons[t][e]=function(t,e,r){var s=n[a]._c,i=n[a]._d;s.add("breadcrumbs separator"),t.append('<span class="'+s.breadcrumbs+'"></span>'),this.bind("init",function(a){a.removeClass(s.hasnavbar).each(function(){for(var a=[],t=n(this),e=n('<span class="'+s.breadcrumbs+'"></span>'),c=n(this).children().first(),d=!0;c&&c.length;){c.is("."+s.panel)||(c=c.closest("."+s.panel));var o=c.children("."+s.navbar).children("."+s.title).text();a.unshift(d?"<span>"+o+"</span>":'<a href="#'+c.attr("id")+'">'+o+"</a>"),d=!1,c=c.data(i.parent)}e.append(a.join('<span class="'+s.separator+'">'+r.breadcrumbSeparator+"</span>")).appendTo(t.children("."+s.navbar))})});var c=function(){var n=this.$pnls.children("."+s.current),a=t.find("."+s.breadcrumbs),e=n.children("."+s.navbar).children("."+s.breadcrumbs);a.html(e.html())};this.bind("openPanel",c),this.bind("init",c)}}(jQuery),/* 29823 * jQuery mmenu navbar addon close content 29824 * mmenu.frebsite.nl 29825 * 29826 * Copyright (c) Fred Heusschen 29827 */ 29828function(n){var a="mmenu",t="navbars",e="close";n[a].addons[t][e]=function(t){var e=n[a]._c,r=n[a].glbl;t.append('<a class="'+e.close+" "+e.btn+'" href="#"></a>');var s=function(n){t.find("."+e.close).attr("href","#"+n.attr("id"))};s.call(this,r.$page),this.bind("setPage",s)}}(jQuery),/* 29829 * jQuery mmenu navbar addon next content 29830 * mmenu.frebsite.nl 29831 * 29832 * Copyright (c) Fred Heusschen 29833 */ 29834function(n){var a="mmenu",t="navbars",e="next";n[a].addons[t][e]=function(e){var r=n[a]._c;e.append('<a class="'+r.next+" "+r.btn+'" href="#"></a>');var s=function(n){n=n||this.$pnls.children("."+r.current);var a=e.find("."+r.next),s=n.find("."+this.conf.classNames[t].panelNext),i=s.attr("href"),c=s.html();a[i?"attr":"removeAttr"]("href",i),a[i||c?"removeClass":"addClass"](r.hidden),a.html(c)};
29834this.bind("openPanel",s),this.bind("init",function(){s.call(this)})}}(jQuery),/* 29835 * jQuery mmenu navbar addon prev content 29836 * mmenu.frebsite.nl 29837 * 29838 * Copyright (c) Fred Heusschen 29839 */ 29840function(n){var a="mmenu",t="navbars",e="prev";n[a].addons[t][e]=function(e){var r=n[a]._c;e.append('<a class="'+r.prev+" "+r.btn+'" href="#"></a>'),this.bind("init",function(n){n.removeClass(r.hasnavbar)});var s=function(){var n=this.$pnls.children("."+r.current),a=e.find("."+r.prev),s=n.find("."+this.conf.classNames[t].panelPrev);s.length||(s=n.children("."+r.navbar).children("."+r.prev));var i=s.attr("href"),c=s.html();a[i?"attr":"removeAttr"]("href",i),a[i||c?"removeClass":"addClass"](r.hidden),a.html(c)};this.bind("openPanel",s),this.bind("init",s)}}(jQuery),/* 29841 * jQuery mmenu navbar addon searchfield content 29842 * mmenu.frebsite.nl 29843 * 29844 * Copyright (c) Fred Heusschen 29845 */ 29846function(n){var a="mmenu",t="navbars",e="searchfield";n[a].addons[t][e]=function(t){var e=n[a]._c,r=n('<div class="'+e.search+'" />').appendTo(t);"object"!=typeof this.opts.searchfield&&(this.opts.searchfield={}),this.opts.searchfield.add=!0,this.opts.searchfield.addTo=r}}(jQuery),/* 29847 * jQuery mmenu navbar addon title content 29848 * mmenu.frebsite.nl 29849 * 29850 * Copyright (c) Fred Heusschen 29851 */ 29852function(n){var a="mmenu",t="navbars",e="title";n[a].addons[t][e]=function(e,r){var s=n[a]._c;e.append('<a class="'+s.title+'"></a>');var i=function(n){n=n||this.$pnls.children("."+s.current);var a=e.find("."+s.title),i=n.find("."+this.conf.classNames[t].panelTitle);i.length||(i=n.children("."+s.navbar).children("."+s.title));var c=i.attr("href"),d=i.html()||r.title;a[c?"attr":"removeAttr"]("href",c),a[c||d?"removeClass":"addClass"](s.hidden),a.html(d)};this.bind("openPanel",i),this.bind("init",function(){i.call(this)})}}(jQuery); 29853 29854 /* Ende jquery.mmenu.navbars */ 29855 /* Start jqueryUI */ 29856 /*! jQuery UI - v1.12.1 - 2017-05-16 29857* http://jqueryui.com 29858* Includes: widget.js, position.js, keycode.js, unique-id.js, widgets/autocomplete.js, widgets/datepicker.js, widgets/menu.js 29859* Copyright jQuery Foundation and other contributors; Licensed MIT */ 29860(function( factory ) { 29861 if ( typeof define === "function" && define.amd ) { 29862 // AMD. Register as an anonymous module. 29863 define([ "jquery" ], factory ); 29864 } else { 29865 // Browser globals 29866 factory( jQuery ); 29867 } 29868}(function( $ ) { 29869$.ui = $.ui || {}; 29870var version = $.ui.version = "1.12.1"; 29871/*! 29872 * jQuery UI Widget 1.12.1 29873 * http://jqueryui.com 29874 * 29875 * Copyright jQuery Foundation and other contributors 29876 * Released under the MIT license. 29877 * http://jquery.org/license 29878 */ 29879//>>label: Widget 29880//>>group: Core 29881//>>description: Provides a factory for creating stateful widgets with a common API. 29882//>>docs: http://api.jqueryui.com/jQuery.widget/ 29883//>>demos: http://jqueryui.com/widget/ 29884var widgetUuid = 0; 29885var widgetSlice = Array.prototype.slice; 29886$.cleanData = ( function( orig ) { 29887 return function( elems ) { 29888 var events, elem, i; 29889 for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) { 29890 try { 29891 // Only trigger remove when necessary to save time 29892 events = $._data( elem, "events" ); 29893 if ( events && events.remove ) { 29894 $( elem ).triggerHandler( "remove" ); 29895 } 29896 // Http://bugs.jquery.com/ticket/8235 29897 } catch ( e ) {} 29898 } 29899 orig( elems ); 29900 }; 29901} )( $.cleanData ); 29902$.widget = function( name, base, prototype ) { 29903 var existingConstructor, constructor, basePrototype; 29904 // ProxiedPrototype allows the provided prototype to remain unmodified 29905 // so that it can be used as a mixin for multiple widgets (#8876) 29906 var proxiedPrototype = {}; 29907 var namespace = name.split( "." )[ 0 ]; 29908 name = name.split( "." )[ 1 ]; 29909 var fullName = namespace + "-" + name; 29910 if ( !prototype ) { 29911 prototype = base; 29912 base = $.Widget; 29913 } 29914 if ( $.isArray( prototype ) ) { 29915 prototype = $.extend.apply( null, [ {} ].concat( prototype ) ); 29916 } 29917 // Create selector for plugin 29918 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { 29919 return !!$.data( elem, fullName ); 29920 }; 29921 $[ namespace ] = $[ namespace ] || {}; 29922 existingConstructor = $[ namespace ][ name ]; 29923 constructor = $[ namespace ][ name ] = function( options, element ) { 29924 // Allow instantiation without "new" keyword 29925 if ( !this._createWidget ) { 29926 return new constructor( options, element ); 29927 } 29928 // Allow instantiation without initializing for simple inheritance 29929 // must use "new" keyword (the code above always passes args) 29930 if ( arguments.length ) { 29931 this._createWidget( options, element ); 29932 } 29933 }; 29934 // Extend with the existing constructor to carry over any static properties 29935 $.extend( constructor, existingConstructor, { 29936 version: prototype.version, 29937 // Copy the object used to create the prototype in case we need to 29938 // redefine the widget later 29939 _proto: $.extend( {}, prototype ), 29940 // Track widgets that inherit from this widget in case this widget is 29941 // redefined after a widget inherits from it 29942 _childConstructors: [] 29943 } ); 29944 basePrototype = new base(); 29945 // We need to make the options hash a property directly on the new instance 29946 // otherwise we'll modify the options hash on the prototype that we're 29947 // inheriting from 29948 basePrototype.options = $.widget.extend( {}, basePrototype.options ); 29949 $.each( prototype, function( prop, value ) { 29950 if ( !$.isFunction( value ) ) { 29951 proxiedPrototype[ prop ] = value; 29952 return; 29953 } 29954 proxiedPrototype[ prop ] = ( function() { 29955 function _super() { 29956 return base.prototype[ prop ].apply( this, arguments ); 29957 } 29958 function _superApply( args ) { 29959 return base.prototype[ prop ].apply( this, args ); 29960 } 29961 return function() { 29962 var __super = this._super; 29963 var __superApply = this._superApply; 29964 var returnValue; 29965 this._super = _super; 29966 this._superApply = _superApply;
vendor: 15,799 bytes, lines 29967-30449
29967 returnValue = value.apply( this, arguments ); 29968 this._super = __super; 29969 this._superApply = __superApply; 29970 return returnValue; 29971 }; 29972 } )(); 29973 } ); 29974 constructor.prototype = $.widget.extend( basePrototype, { 29975 // TODO: remove support for widgetEventPrefix 29976 // always use the name + a colon as the prefix, e.g., draggable:start 29977 // don't prefix for widgets that aren't DOM-based 29978 widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name 29979 }, proxiedPrototype, { 29980 constructor: constructor, 29981 namespace: namespace, 29982 widgetName: name, 29983 widgetFullName: fullName 29984 } ); 29985 // If this widget is being redefined then we need to find all widgets that 29986 // are inheriting from it and redefine all of them so that they inherit from 29987 // the new version of this widget. We're essentially trying to replace one 29988 // level in the prototype chain. 29989 if ( existingConstructor ) { 29990 $.each( existingConstructor._childConstructors, function( i, child ) { 29991 var childPrototype = child.prototype; 29992 // Redefine the child widget using the same prototype that was 29993 // originally used, but inherit from the new version of the base 29994 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, 29995 child._proto ); 29996 } ); 29997 // Remove the list of existing child constructors from the old constructor 29998 // so the old child constructors can be garbage collected 29999 delete existingConstructor._childConstructors; 30000 } else { 30001 base._childConstructors.push( constructor ); 30002 } 30003 $.widget.bridge( name, constructor ); 30004 return constructor; 30005}; 30006$.widget.extend = function( target ) { 30007 var input = widgetSlice.call( arguments, 1 ); 30008 var inputIndex = 0; 30009 var inputLength = input.length; 30010 var key; 30011 var value; 30012 for ( ; inputIndex < inputLength; inputIndex++ ) { 30013 for ( key in input[ inputIndex ] ) { 30014 value = input[ inputIndex ][ key ]; 30015 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { 30016 // Clone objects 30017 if ( $.isPlainObject( value ) ) { 30018 target[ key ] = $.isPlainObject( target[ key ] ) ? 30019 $.widget.extend( {}, target[ key ], value ) : 30020 // Don't extend strings, arrays, etc. with objects 30021 $.widget.extend( {}, value ); 30022 // Copy everything else by reference 30023 } else { 30024 target[ key ] = value; 30025 } 30026 } 30027 } 30028 } 30029 return target; 30030}; 30031$.widget.bridge = function( name, object ) { 30032 var fullName = object.prototype.widgetFullName || name; 30033 $.fn[ name ] = function( options ) { 30034 var isMethodCall = typeof options === "string"; 30035 var args = widgetSlice.call( arguments, 1 ); 30036 var returnValue = this; 30037 if ( isMethodCall ) { 30038 // If this is an empty collection, we need to have the instance method 30039 // return undefined instead of the jQuery instance 30040 if ( !this.length && options === "instance" ) { 30041 returnValue = undefined; 30042 } else { 30043 this.each( function() { 30044 var methodValue; 30045 var instance = $.data( this, fullName ); 30046 if ( options === "instance" ) { 30047 returnValue = instance; 30048 return false; 30049 } 30050 if ( !instance ) { 30051 return $.error( "cannot call methods on " + name + 30052 " prior to initialization; " + 30053 "attempted to call method '" + options + "'" ); 30054 } 30055 if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) { 30056 return $.error( "no such method '" + options + "' for " + name + 30057 " widget instance" ); 30058 } 30059 methodValue = instance[ options ].apply( instance, args ); 30060 if ( methodValue !== instance && methodValue !== undefined ) { 30061 returnValue = methodValue && methodValue.jquery ? 30062 returnValue.pushStack( methodValue.get() ) : 30063 methodValue; 30064 return false; 30065 } 30066 } ); 30067 } 30068 } else { 30069 // Allow multiple hashes to be passed on init 30070 if ( args.length ) { 30071 options = $.widget.extend.apply( null, [ options ].concat( args ) ); 30072 } 30073 this.each( function() { 30074 var instance = $.data( this, fullName ); 30075 if ( instance ) { 30076 instance.option( options || {} ); 30077 if ( instance._init ) { 30078 instance._init(); 30079 } 30080 } else { 30081 $.data( this, fullName, new object( options, this ) ); 30082 } 30083 } ); 30084 } 30085 return returnValue; 30086 }; 30087}; 30088$.Widget = function( /* options, element */ ) {}; 30089$.Widget._childConstructors = []; 30090$.Widget.prototype = { 30091 widgetName: "widget", 30092 widgetEventPrefix: "", 30093 defaultElement: "<div>", 30094 options: { 30095 classes: {}, 30096 disabled: false, 30097 // Callbacks 30098 create: null 30099 }, 30100 _createWidget: function( options, element ) { 30101 element = $( element || this.defaultElement || this )[ 0 ]; 30102 this.element = $( element ); 30103 this.uuid = widgetUuid++; 30104 this.eventNamespace = "." + this.widgetName + this.uuid; 30105 this.bindings = $(); 30106 this.hoverable = $(); 30107 this.focusable = $(); 30108 this.classesElementLookup = {}; 30109 if ( element !== this ) { 30110 $.data( element, this.widgetFullName, this ); 30111 this._on( true, this.element, { 30112 remove: function( event ) { 30113 if ( event.target === element ) { 30114 this.destroy(); 30115 } 30116 } 30117 } ); 30118 this.document = $( element.style ? 30119 // Element within the document 30120 element.ownerDocument : 30121 // Element is window or document 30122 element.document || element ); 30123 this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow ); 30124 } 30125 this.options = $.widget.extend( {}, 30126 this.options, 30127 this._getCreateOptions(), 30128 options ); 30129 this._create(); 30130 if ( this.options.disabled ) { 30131 this._setOptionDisabled( this.options.disabled ); 30132 } 30133 this._trigger( "create", null, this._getCreateEventData() ); 30134 this._init(); 30135 }, 30136 _getCreateOptions: function() { 30137 return {}; 30138 }, 30139 _getCreateEventData: $.noop, 30140 _create: $.noop, 30141 _init: $.noop, 30142 destroy: function() { 30143 var that = this; 30144 this._destroy(); 30145 $.each( this.classesElementLookup, function( key, value ) { 30146 that._removeClass( value, key ); 30147 } ); 30148 // We can probably remove the unbind calls in 2.0 30149 // all event bindings should go through this._on() 30150 this.element 30151 .off( this.eventNamespace ) 30152 .removeData( this.widgetFullName ); 30153 this.widget() 30154 .off( this.eventNamespace ) 30155 .removeAttr( "aria-disabled" ); 30156 // Clean up events and states 30157 this.bindings.off( this.eventNamespace ); 30158 }, 30159 _destroy: $.noop, 30160 widget: function() { 30161 return this.element; 30162 }, 30163 option: function( key, value ) { 30164 var options = key; 30165 var parts; 30166 var curOption; 30167 var i; 30168 if ( arguments.length === 0 ) { 30169 // Don't return a reference to the internal hash 30170 return $.widget.extend( {}, this.options ); 30171 } 30172 if ( typeof key === "string" ) { 30173 // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } 30174 options = {}; 30175 parts = key.split( "." ); 30176 key = parts.shift(); 30177 if ( parts.length ) { 30178 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); 30179 for ( i = 0; i < parts.length - 1; i++ ) { 30180 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; 30181 curOption = curOption[ parts[ i ] ]; 30182 } 30183 key = parts.pop(); 30184 if ( arguments.length === 1 ) { 30185 return curOption[ key ] === undefined ? null : curOption[ key ]; 30186 } 30187 curOption[ key ] = value; 30188 } else { 30189 if ( arguments.length === 1 ) { 30190 return this.options[ key ] === undefined ? null : this.options[ key ]; 30191 } 30192 options[ key ] = value; 30193 } 30194 } 30195 this._setOptions( options ); 30196 return this; 30197 }, 30198 _setOptions: function( options ) { 30199 var key; 30200 for ( key in options ) { 30201 this._setOption( key, options[ key ] ); 30202 } 30203 return this; 30204 }, 30205 _setOption: function( key, value ) { 30206 if ( key === "classes" ) { 30207 this._setOptionClasses( value ); 30208 } 30209 this.options[ key ] = value; 30210 if ( key === "disabled" ) { 30211 this._setOptionDisabled( value ); 30212 } 30213 return this; 30214 }, 30215 _setOptionClasses: function( value ) { 30216 var classKey, elements, currentElements; 30217 for ( classKey in value ) { 30218 currentElements = this.classesElementLookup[ classKey ]; 30219 if ( value[ classKey ] === this.options.classes[ classKey ] || 30220 !currentElements || 30221 !currentElements.length ) { 30222 continue; 30223 } 30224 // We are doing this to create a new jQuery object because the _removeClass() call 30225 // on the next line is going to destroy the reference to the current elements being 30226 // tracked. We need to save a copy of this collection so that we can add the new classes 30227 // below. 30228 elements = $( currentElements.get() ); 30229 this._removeClass( currentElements, classKey ); 30230 // We don't use _addClass() here, because that uses this.options.classes 30231 // for generating the string of classes. We want to use the value passed in from 30232 // _setOption(), this is the new value of the classes option which was passed to 30233 // _setOption(). We pass this value directly to _classes(). 30234 elements.addClass( this._classes( { 30235 element: elements, 30236 keys: classKey, 30237 classes: value, 30238 add: true 30239 } ) ); 30240 } 30241 }, 30242 _setOptionDisabled: function( value ) { 30243 this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value ); 30244 // If the widget is becoming disabled, then nothing is interactive 30245 if ( value ) { 30246 this._removeClass( this.hoverable, null, "ui-state-hover" ); 30247 this._removeClass( this.focusable, null, "ui-state-focus" ); 30248 } 30249 }, 30250 enable: function() { 30251 return this._setOptions( { disabled: false } ); 30252 }, 30253 disable: function() { 30254 return this._setOptions( { disabled: true } ); 30255 }, 30256 _classes: function( options ) { 30257 var full = []; 30258 var that = this; 30259 options = $.extend( { 30260 element: this.element, 30261 classes: this.options.classes || {} 30262 }, options ); 30263 function processClassString( classes, checkOption ) { 30264 var current, i; 30265 for ( i = 0; i < classes.length; i++ ) { 30266 current = that.classesElementLookup[ classes[ i ] ] || $(); 30267 if ( options.add ) { 30268 current = $( $.unique( current.get().concat( options.element.get() ) ) ); 30269 } else { 30270 current = $( current.not( options.element ).get() ); 30271 } 30272 that.classesElementLookup[ classes[ i ] ] = current; 30273 full.push( classes[ i ] ); 30274 if ( checkOption && options.classes[ classes[ i ] ] ) { 30275 full.push( options.classes[ classes[ i ] ] ); 30276 } 30277 } 30278 } 30279 this._on( options.element, { 30280 "remove": "_untrackClassesElement" 30281 } ); 30282 if ( options.keys ) { 30283 processClassString( options.keys.match( /\S+/g ) || [], true ); 30284 } 30285 if ( options.extra ) { 30286 processClassString( options.extra.match( /\S+/g ) || [] ); 30287 } 30288 return full.join( " " ); 30289 }, 30290 _untrackClassesElement: function( event ) { 30291 var that = this; 30292 $.each( that.classesElementLookup, function( key, value ) { 30293 if ( $.inArray( event.target, value ) !== -1 ) { 30294 that.classesElementLookup[ key ] = $( value.not( event.target ).get() ); 30295 } 30296 } ); 30297 }, 30298 _removeClass: function( element, keys, extra ) { 30299 return this._toggleClass( element, keys, extra, false ); 30300 }, 30301 _addClass: function( element, keys, extra ) { 30302 return this._toggleClass( element, keys, extra, true ); 30303 }, 30304 _toggleClass: function( element, keys, extra, add ) { 30305 add = ( typeof add === "boolean" ) ? add : extra; 30306 var shift = ( typeof element === "string" || element === null ), 30307 options = { 30308 extra: shift ? keys : extra, 30309 keys: shift ? element : keys, 30310 element: shift ? this.element : element, 30311 add: add 30312 }; 30313 options.element.toggleClass( this._classes( options ), add ); 30314 return this; 30315 }, 30316 _on: function( suppressDisabledCheck, element, handlers ) { 30317 var delegateElement; 30318 var instance = this; 30319 // No suppressDisabledCheck flag, shuffle arguments 30320 if ( typeof suppressDisabledCheck !== "boolean" ) { 30321 handlers = element; 30322 element = suppressDisabledCheck; 30323 suppressDisabledCheck = false; 30324 } 30325 // No element argument, shuffle and use this.element 30326 if ( !handlers ) { 30327 handlers = element; 30328 element = this.element; 30329 delegateElement = this.widget(); 30330 } else { 30331 element = delegateElement = $( element ); 30332 this.bindings = this.bindings.add( element ); 30333 } 30334 $.each( handlers, function( event, handler ) { 30335 function handlerProxy() { 30336 // Allow widgets to customize the disabled handling 30337 // - disabled as an array instead of boolean 30338 // - disabled class as method for disabling individual parts 30339 if ( !suppressDisabledCheck && 30340 ( instance.options.disabled === true || 30341 $( this ).hasClass( "ui-state-disabled" ) ) ) { 30342 return; 30343 } 30344 return ( typeof handler === "string" ? instance[ handler ] : handler ) 30345 .apply( instance, arguments ); 30346 } 30347 // Copy the guid so direct unbinding works 30348 if ( typeof handler !== "string" ) { 30349 handlerProxy.guid = handler.guid = 30350 handler.guid || handlerProxy.guid || $.guid++; 30351 } 30352 var match = event.match( /^([\w:-]*)\s*(.*)$/ ); 30353 var eventName = match[ 1 ] + instance.eventNamespace; 30354 var selector = match[ 2 ]; 30355 if ( selector ) { 30356 delegateElement.on( eventName, selector, handlerProxy ); 30357 } else { 30358 element.on( eventName, handlerProxy ); 30359 } 30360 } ); 30361 }, 30362 _off: function( element, eventName ) { 30363 eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) + 30364 this.eventNamespace; 30365 element.off( eventName ).off( eventName ); 30366 // Clear the stack to avoid memory leaks (#10056) 30367 this.bindings = $( this.bindings.not( element ).get() ); 30368 this.focusable = $( this.focusable.not( element ).get() ); 30369 this.hoverable = $( this.hoverable.not( element ).get() ); 30370 }, 30371 _delay: function( handler, delay ) { 30372 function handlerProxy() { 30373 return ( typeof handler === "string" ? instance[ handler ] : handler ) 30374 .apply( instance, arguments ); 30375 } 30376 var instance = this; 30377 return setTimeout( handlerProxy, delay || 0 ); 30378 }, 30379 _hoverable: function( element ) { 30380 this.hoverable = this.hoverable.add( element ); 30381 this._on( element, { 30382 mouseenter: function( event ) { 30383 this._addClass( $( event.currentTarget ), null, "ui-state-hover" ); 30384 }, 30385 mouseleave: function( event ) { 30386 this._removeClass( $( event.currentTarget ), null, "ui-state-hover" ); 30387 } 30388 } ); 30389 }, 30390 _focusable: function( element ) { 30391 this.focusable = this.focusable.add( element ); 30392 this._on( element, { 30393 focusin: function( event ) { 30394 this._addClass( $( event.currentTarget ), null, "ui-state-focus" ); 30395 }, 30396 focusout: function( event ) { 30397 this._removeClass( $( event.currentTarget ), null, "ui-state-focus" ); 30398 } 30399 } ); 30400 }, 30401 _trigger: function( type, event, data ) { 30402 var prop, orig; 30403 var callback = this.options[ type ]; 30404 data = data || {}; 30405 event = $.Event( event ); 30406 event.type = ( type === this.widgetEventPrefix ? 30407 type : 30408 this.widgetEventPrefix + type ).toLowerCase(); 30409 // The original event may come from any element 30410 // so we need to reset the target on the new event 30411 event.target = this.element[ 0 ]; 30412 // Copy original event properties over to the new event 30413 orig = event.originalEvent; 30414 if ( orig ) { 30415 for ( prop in orig ) { 30416 if ( !( prop in event ) ) { 30417 event[ prop ] = orig[ prop ]; 30418 } 30419 } 30420 } 30421 this.element.trigger( event, data ); 30422 return !( $.isFunction( callback ) && 30423 callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false || 30424 event.isDefaultPrevented() ); 30425 } 30426}; 30427$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { 30428 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { 30429 if ( typeof options === "string" ) { 30430 options = { effect: options }; 30431 } 30432 var hasOptions; 30433 var effectName = !options ? 30434 method : 30435 options === true || typeof options === "number" ? 30436 defaultEffect : 30437 options.effect || defaultEffect; 30438 options = options || {}; 30439 if ( typeof options === "number" ) { 30440 options = { duration: options }; 30441 } 30442 hasOptions = !$.isEmptyObject( options ); 30443 options.complete = callback; 30444 if ( options.delay ) { 30445 element.delay( options.delay ); 30446 } 30447 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { 30448 element[ method ]( options ); 30449 } else if ( effectName !== method && element[ effectName ] ) {
vendor: 4,779 bytes, lines 30450-30606
30450 element[ effectName ]( options.duration, options.easing, callback ); 30451 } else { 30452 element.queue( function( next ) { 30453 $( this )[ method ](); 30454 if ( callback ) { 30455 callback.call( element[ 0 ] ); 30456 } 30457 next(); 30458 } ); 30459 } 30460 }; 30461} ); 30462var widget = $.widget; 30463/*! 30464 * jQuery UI Position 1.12.1 30465 * http://jqueryui.com 30466 * 30467 * Copyright jQuery Foundation and other contributors 30468 * Released under the MIT license. 30469 * http://jquery.org/license 30470 * 30471 * http://api.jqueryui.com/position/ 30472 */ 30473//>>label: Position 30474//>>group: Core 30475//>>description: Positions elements relative to other elements. 30476//>>docs: http://api.jqueryui.com/position/ 30477//>>demos: http://jqueryui.com/position/ 30478( function() { 30479var cachedScrollbarWidth, 30480 max = Math.max, 30481 abs = Math.abs, 30482 rhorizontal = /left|center|right/, 30483 rvertical = /top|center|bottom/, 30484 roffset = /[\+\-]\d+(\.[\d]+)?%?/, 30485 rposition = /^\w+/, 30486 rpercent = /%$/, 30487 _position = $.fn.position; 30488function getOffsets( offsets, width, height ) { 30489 return [ 30490 parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), 30491 parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) 30492 ]; 30493} 30494function parseCss( element, property ) { 30495 return parseInt( $.css( element, property ), 10 ) || 0; 30496} 30497function getDimensions( elem ) { 30498 var raw = elem[ 0 ]; 30499 if ( raw.nodeType === 9 ) { 30500 return { 30501 width: elem.width(), 30502 height: elem.height(), 30503 offset: { top: 0, left: 0 } 30504 }; 30505 } 30506 if ( $.isWindow( raw ) ) { 30507 return { 30508 width: elem.width(), 30509 height: elem.height(), 30510 offset: { top: elem.scrollTop(), left: elem.scrollLeft() } 30511 }; 30512 } 30513 if ( raw.preventDefault ) { 30514 return { 30515 width: 0, 30516 height: 0, 30517 offset: { top: raw.pageY, left: raw.pageX } 30518 }; 30519 } 30520 return { 30521 width: elem.outerWidth(), 30522 height: elem.outerHeight(), 30523 offset: elem.offset() 30524 }; 30525} 30526$.position = { 30527 scrollbarWidth: function() { 30528 if ( cachedScrollbarWidth !== undefined ) { 30529 return cachedScrollbarWidth; 30530 } 30531 var w1, w2, 30532 div = $( "<div " + 30533 "style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'>" + 30534 "<div style='height:100px;width:auto;'></div></div>" ), 30535 innerDiv = div.children()[ 0 ]; 30536 $( "body" ).append( div ); 30537 w1 = innerDiv.offsetWidth; 30538 div.css( "overflow", "scroll" ); 30539 w2 = innerDiv.offsetWidth; 30540 if ( w1 === w2 ) { 30541 w2 = div[ 0 ].clientWidth; 30542 } 30543 div.remove(); 30544 return ( cachedScrollbarWidth = w1 - w2 ); 30545 }, 30546 getScrollInfo: function( within ) { 30547 var overflowX = within.isWindow || within.isDocument ? "" : 30548 within.element.css( "overflow-x" ), 30549 overflowY = within.isWindow || within.isDocument ? "" : 30550 within.element.css( "overflow-y" ), 30551 hasOverflowX = overflowX === "scroll" || 30552 ( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ), 30553 hasOverflowY = overflowY === "scroll" || 30554 ( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight ); 30555 return { 30556 width: hasOverflowY ? $.position.scrollbarWidth() : 0, 30557 height: hasOverflowX ? $.position.scrollbarWidth() : 0 30558 }; 30559 }, 30560 getWithinInfo: function( element ) { 30561 var withinElement = $( element || window ), 30562 isWindow = $.isWindow( withinElement[ 0 ] ), 30563 isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9, 30564 hasOffset = !isWindow && !isDocument; 30565 return { 30566 element: withinElement, 30567 isWindow: isWindow, 30568 isDocument: isDocument, 30569 offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 }, 30570 scrollLeft: withinElement.scrollLeft(), 30571 scrollTop: withinElement.scrollTop(), 30572 width: withinElement.outerWidth(), 30573 height: withinElement.outerHeight() 30574 }; 30575 } 30576}; 30577$.fn.position = function( options ) { 30578 if ( !options || !options.of ) { 30579 return _position.apply( this, arguments ); 30580 } 30581 // Make a copy, we don't want to modify arguments 30582 options = $.extend( {}, options ); 30583 var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, 30584 target = $( options.of ), 30585 within = $.position.getWithinInfo( options.within ), 30586 scrollInfo = $.position.getScrollInfo( within ), 30587 collision = ( options.collision || "flip" ).split( " " ), 30588 offsets = {}; 30589 dimensions = getDimensions( target ); 30590 if ( target[ 0 ].preventDefault ) { 30591 // Force left top to allow flipping 30592 options.at = "left top"; 30593 } 30594 targetWidth = dimensions.width; 30595 targetHeight = dimensions.height; 30596 targetOffset = dimensions.offset; 30597 // Clone to reuse original targetOffset later 30598 basePosition = $.extend( {}, targetOffset ); 30599 // Force my and at to have valid horizontal and vertical positions 30600 // if a value is missing or invalid, it will be converted to center 30601 $.each( [ "my", "at" ], function() { 30602 var pos = ( options[ this ] || "" ).split( " " ), 30603 horizontalOffset, 30604 verticalOffset; 30605 if ( pos.length === 1 ) { 30606 pos = rhorizontal.test( pos[ 0 ] ) ?
vendor: 10,072 bytes, lines 30607-30896
30607 pos.concat( [ "center" ] ) : 30608 rvertical.test( pos[ 0 ] ) ? 30609 [ "center" ].concat( pos ) : 30610 [ "center", "center" ]; 30611 } 30612 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; 30613 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; 30614 // Calculate offsets 30615 horizontalOffset = roffset.exec( pos[ 0 ] ); 30616 verticalOffset = roffset.exec( pos[ 1 ] ); 30617 offsets[ this ] = [ 30618 horizontalOffset ? horizontalOffset[ 0 ] : 0, 30619 verticalOffset ? verticalOffset[ 0 ] : 0 30620 ]; 30621 // Reduce to just the positions without the offsets 30622 options[ this ] = [ 30623 rposition.exec( pos[ 0 ] )[ 0 ], 30624 rposition.exec( pos[ 1 ] )[ 0 ] 30625 ]; 30626 } ); 30627 // Normalize collision option 30628 if ( collision.length === 1 ) { 30629 collision[ 1 ] = collision[ 0 ]; 30630 } 30631 if ( options.at[ 0 ] === "right" ) { 30632 basePosition.left += targetWidth; 30633 } else if ( options.at[ 0 ] === "center" ) { 30634 basePosition.left += targetWidth / 2; 30635 } 30636 if ( options.at[ 1 ] === "bottom" ) { 30637 basePosition.top += targetHeight; 30638 } else if ( options.at[ 1 ] === "center" ) { 30639 basePosition.top += targetHeight / 2; 30640 } 30641 atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); 30642 basePosition.left += atOffset[ 0 ]; 30643 basePosition.top += atOffset[ 1 ]; 30644 return this.each( function() { 30645 var collisionPosition, using, 30646 elem = $( this ), 30647 elemWidth = elem.outerWidth(), 30648 elemHeight = elem.outerHeight(), 30649 marginLeft = parseCss( this, "marginLeft" ), 30650 marginTop = parseCss( this, "marginTop" ), 30651 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + 30652 scrollInfo.width, 30653 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + 30654 scrollInfo.height, 30655 position = $.extend( {}, basePosition ), 30656 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); 30657 if ( options.my[ 0 ] === "right" ) { 30658 position.left -= elemWidth; 30659 } else if ( options.my[ 0 ] === "center" ) { 30660 position.left -= elemWidth / 2; 30661 } 30662 if ( options.my[ 1 ] === "bottom" ) { 30663 position.top -= elemHeight; 30664 } else if ( options.my[ 1 ] === "center" ) { 30665 position.top -= elemHeight / 2; 30666 } 30667 position.left += myOffset[ 0 ]; 30668 position.top += myOffset[ 1 ]; 30669 collisionPosition = { 30670 marginLeft: marginLeft, 30671 marginTop: marginTop 30672 }; 30673 $.each( [ "left", "top" ], function( i, dir ) { 30674 if ( $.ui.position[ collision[ i ] ] ) { 30675 $.ui.position[ collision[ i ] ][ dir ]( position, { 30676 targetWidth: targetWidth, 30677 targetHeight: targetHeight, 30678 elemWidth: elemWidth, 30679 elemHeight: elemHeight, 30680 collisionPosition: collisionPosition, 30681 collisionWidth: collisionWidth, 30682 collisionHeight: collisionHeight, 30683 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], 30684 my: options.my, 30685 at: options.at, 30686 within: within, 30687 elem: elem 30688 } ); 30689 } 30690 } ); 30691 if ( options.using ) { 30692 // Adds feedback as second argument to using callback, if present 30693 using = function( props ) { 30694 var left = targetOffset.left - position.left, 30695 right = left + targetWidth - elemWidth, 30696 top = targetOffset.top - position.top, 30697 bottom = top + targetHeight - elemHeight, 30698 feedback = { 30699 target: { 30700 element: target, 30701 left: targetOffset.left, 30702 top: targetOffset.top, 30703 width: targetWidth, 30704 height: targetHeight 30705 }, 30706 element: { 30707 element: elem, 30708 left: position.left, 30709 top: position.top, 30710 width: elemWidth, 30711 height: elemHeight 30712 }, 30713 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", 30714 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" 30715 }; 30716 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { 30717 feedback.horizontal = "center"; 30718 } 30719 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { 30720 feedback.vertical = "middle"; 30721 } 30722 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { 30723 feedback.important = "horizontal"; 30724 } else { 30725 feedback.important = "vertical"; 30726 } 30727 options.using.call( this, props, feedback ); 30728 }; 30729 } 30730 elem.offset( $.extend( position, { using: using } ) ); 30731 } ); 30732}; 30733$.ui.position = { 30734 fit: { 30735 left: function( position, data ) { 30736 var within = data.within, 30737 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, 30738 outerWidth = within.width, 30739 collisionPosLeft = position.left - data.collisionPosition.marginLeft, 30740 overLeft = withinOffset - collisionPosLeft, 30741 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, 30742 newOverRight; 30743 // Element is wider than within 30744 if ( data.collisionWidth > outerWidth ) { 30745 // Element is initially over the left side of within 30746 if ( overLeft > 0 && overRight <= 0 ) { 30747 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - 30748 withinOffset; 30749 position.left += overLeft - newOverRight; 30750 // Element is initially over right side of within 30751 } else if ( overRight > 0 && overLeft <= 0 ) { 30752 position.left = withinOffset; 30753 // Element is initially over both left and right sides of within 30754 } else { 30755 if ( overLeft > overRight ) { 30756 position.left = withinOffset + outerWidth - data.collisionWidth; 30757 } else { 30758 position.left = withinOffset; 30759 } 30760 } 30761 // Too far left -> align with left edge 30762 } else if ( overLeft > 0 ) { 30763 position.left += overLeft; 30764 // Too far right -> align with right edge 30765 } else if ( overRight > 0 ) { 30766 position.left -= overRight; 30767 // Adjust based on position and margin 30768 } else { 30769 position.left = max( position.left - collisionPosLeft, position.left ); 30770 } 30771 }, 30772 top: function( position, data ) { 30773 var within = data.within, 30774 withinOffset = within.isWindow ? within.scrollTop : within.offset.top, 30775 outerHeight = data.within.height, 30776 collisionPosTop = position.top - data.collisionPosition.marginTop, 30777 overTop = withinOffset - collisionPosTop, 30778 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, 30779 newOverBottom; 30780 // Element is taller than within 30781 if ( data.collisionHeight > outerHeight ) { 30782 // Element is initially over the top of within 30783 if ( overTop > 0 && overBottom <= 0 ) { 30784 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - 30785 withinOffset; 30786 position.top += overTop - newOverBottom; 30787 // Element is initially over bottom of within 30788 } else if ( overBottom > 0 && overTop <= 0 ) { 30789 position.top = withinOffset; 30790 // Element is initially over both top and bottom of within 30791 } else { 30792 if ( overTop > overBottom ) { 30793 position.top = withinOffset + outerHeight - data.collisionHeight; 30794 } else { 30795 position.top = withinOffset; 30796 } 30797 } 30798 // Too far up -> align with top 30799 } else if ( overTop > 0 ) { 30800 position.top += overTop; 30801 // Too far down -> align with bottom edge 30802 } else if ( overBottom > 0 ) { 30803 position.top -= overBottom; 30804 // Adjust based on position and margin 30805 } else { 30806 position.top = max( position.top - collisionPosTop, position.top ); 30807 } 30808 } 30809 }, 30810 flip: { 30811 left: function( position, data ) { 30812 var within = data.within, 30813 withinOffset = within.offset.left + within.scrollLeft, 30814 outerWidth = within.width, 30815 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, 30816 collisionPosLeft = position.left - data.collisionPosition.marginLeft, 30817 overLeft = collisionPosLeft - offsetLeft, 30818 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, 30819 myOffset = data.my[ 0 ] === "left" ? 30820 -data.elemWidth : 30821 data.my[ 0 ] === "right" ? 30822 data.elemWidth : 30823 0, 30824 atOffset = data.at[ 0 ] === "left" ? 30825 data.targetWidth : 30826 data.at[ 0 ] === "right" ? 30827 -data.targetWidth : 30828 0, 30829 offset = -2 * data.offset[ 0 ], 30830 newOverRight, 30831 newOverLeft; 30832 if ( overLeft < 0 ) { 30833 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - 30834 outerWidth - withinOffset; 30835 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { 30836 position.left += myOffset + atOffset + offset; 30837 } 30838 } else if ( overRight > 0 ) { 30839 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + 30840 atOffset + offset - offsetLeft; 30841 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { 30842 position.left += myOffset + atOffset + offset; 30843 } 30844 } 30845 }, 30846 top: function( position, data ) { 30847 var within = data.within, 30848 withinOffset = within.offset.top + within.scrollTop, 30849 outerHeight = within.height, 30850 offsetTop = within.isWindow ? within.scrollTop : within.offset.top, 30851 collisionPosTop = position.top - data.collisionPosition.marginTop, 30852 overTop = collisionPosTop - offsetTop, 30853 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, 30854 top = data.my[ 1 ] === "top", 30855 myOffset = top ? 30856 -data.elemHeight : 30857 data.my[ 1 ] === "bottom" ? 30858 data.elemHeight : 30859 0, 30860 atOffset = data.at[ 1 ] === "top" ? 30861 data.targetHeight : 30862 data.at[ 1 ] === "bottom" ? 30863 -data.targetHeight : 30864 0, 30865 offset = -2 * data.offset[ 1 ], 30866 newOverTop, 30867 newOverBottom; 30868 if ( overTop < 0 ) { 30869 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - 30870 outerHeight - withinOffset; 30871 if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) { 30872 position.top += myOffset + atOffset + offset; 30873 } 30874 } else if ( overBottom > 0 ) { 30875 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + 30876 offset - offsetTop; 30877 if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) { 30878 position.top += myOffset + atOffset + offset; 30879 } 30880 } 30881 } 30882 }, 30883 flipfit: { 30884 left: function() { 30885 $.ui.position.flip.left.apply( this, arguments ); 30886 $.ui.position.fit.left.apply( this, arguments ); 30887 }, 30888 top: function() { 30889 $.ui.position.flip.top.apply( this, arguments ); 30890 $.ui.position.fit.top.apply( this, arguments ); 30891 } 30892 } 30893}; 30894} )(); 30895var position = $.ui.position; 30896/*!
vendor: 5,645 bytes, lines 30897-31090
30897 * jQuery UI Keycode 1.12.1 30898 * http://jqueryui.com 30899 * 30900 * Copyright jQuery Foundation and other contributors 30901 * Released under the MIT license. 30902 * http://jquery.org/license 30903 */ 30904//>>label: Keycode 30905//>>group: Core 30906//>>description: Provide keycodes as keynames 30907//>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/ 30908var keycode = $.ui.keyCode = { 30909 BACKSPACE: 8, 30910 COMMA: 188, 30911 DELETE: 46, 30912 DOWN: 40, 30913 END: 35, 30914 ENTER: 13, 30915 ESCAPE: 27, 30916 HOME: 36, 30917 LEFT: 37, 30918 PAGE_DOWN: 34, 30919 PAGE_UP: 33, 30920 PERIOD: 190, 30921 RIGHT: 39, 30922 SPACE: 32, 30923 TAB: 9, 30924 UP: 38 30925}; 30926/*! 30927 * jQuery UI Unique ID 1.12.1 30928 * http://jqueryui.com 30929 * 30930 * Copyright jQuery Foundation and other contributors 30931 * Released under the MIT license. 30932 * http://jquery.org/license 30933 */ 30934//>>label: uniqueId 30935//>>group: Core 30936//>>description: Functions to generate and remove uniqueId's 30937//>>docs: http://api.jqueryui.com/uniqueId/ 30938var uniqueId = $.fn.extend( { 30939 uniqueId: ( function() { 30940 var uuid = 0; 30941 return function() { 30942 return this.each( function() { 30943 if ( !this.id ) { 30944 this.id = "ui-id-" + ( ++uuid ); 30945 } 30946 } ); 30947 }; 30948 } )(), 30949 removeUniqueId: function() { 30950 return this.each( function() { 30951 if ( /^ui-id-\d+$/.test( this.id ) ) { 30952 $( this ).removeAttr( "id" ); 30953 } 30954 } ); 30955 } 30956} ); 30957var safeActiveElement = $.ui.safeActiveElement = function( document ) { 30958 var activeElement; 30959 // Support: IE 9 only 30960 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe> 30961 try { 30962 activeElement = document.activeElement; 30963 } catch ( error ) { 30964 activeElement = document.body; 30965 } 30966 // Support: IE 9 - 11 only 30967 // IE may return null instead of an element 30968 // Interestingly, this only seems to occur when NOT in an iframe 30969 if ( !activeElement ) { 30970 activeElement = document.body; 30971 } 30972 // Support: IE 11 only 30973 // IE11 returns a seemingly empty object in some cases when accessing 30974 // document.activeElement from an <iframe> 30975 if ( !activeElement.nodeName ) { 30976 activeElement = document.body; 30977 } 30978 return activeElement; 30979}; 30980/*! 30981 * jQuery UI Menu 1.12.1 30982 * http://jqueryui.com 30983 * 30984 * Copyright jQuery Foundation and other contributors 30985 * Released under the MIT license. 30986 * http://jquery.org/license 30987 */ 30988//>>label: Menu 30989//>>group: Widgets 30990//>>description: Creates nestable menus. 30991//>>docs: http://api.jqueryui.com/menu/ 30992//>>demos: http://jqueryui.com/menu/ 30993//>>css.structure: ../../themes/base/core.css 30994//>>css.structure: ../../themes/base/menu.css 30995//>>css.theme: ../../themes/base/theme.css 30996var widgetsMenu = $.widget( "ui.menu", { 30997 version: "1.12.1", 30998 defaultElement: "<ul>", 30999 delay: 300, 31000 options: { 31001 icons: { 31002 submenu: "ui-icon-caret-1-e" 31003 }, 31004 items: "> *", 31005 menus: "ul", 31006 position: { 31007 my: "left top", 31008 at: "right top" 31009 }, 31010 role: "menu", 31011 // Callbacks 31012 blur: null, 31013 focus: null, 31014 select: null 31015 }, 31016 _create: function() { 31017 this.activeMenu = this.element; 31018 // Flag used to prevent firing of the click handler 31019 // as the event bubbles up through nested menus 31020 this.mouseHandled = false; 31021 this.element 31022 .uniqueId() 31023 .attr( { 31024 role: this.options.role, 31025 tabIndex: 0 31026 } ); 31027 this._addClass( "ui-menu", "ui-widget ui-widget-content" ); 31028 this._on( { 31029 // Prevent focus from sticking to links inside menu after clicking 31030 // them (focus should always stay on UL during navigation). 31031 "mousedown .ui-menu-item": function( event ) { 31032 event.preventDefault(); 31033 }, 31034 "click .ui-menu-item": function( event ) { 31035 var target = $( event.target ); 31036 var active = $( $.ui.safeActiveElement( this.document[ 0 ] ) ); 31037 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) { 31038 this.select( event ); 31039 // Only set the mouseHandled flag if the event will bubble, see #9469. 31040 if ( !event.isPropagationStopped() ) { 31041 this.mouseHandled = true; 31042 } 31043 // Open submenu on click 31044 if ( target.has( ".ui-menu" ).length ) { 31045 this.expand( event ); 31046 } else if ( !this.element.is( ":focus" ) && 31047 active.closest( ".ui-menu" ).length ) { 31048 // Redirect focus to the menu 31049 this.element.trigger( "focus", [ true ] ); 31050 // If the active item is on the top level, let it stay active. 31051 // Otherwise, blur the active item since it is no longer visible. 31052 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) { 31053 clearTimeout( this.timer ); 31054 } 31055 } 31056 } 31057 }, 31058 "mouseenter .ui-menu-item": function( event ) { 31059 // Ignore mouse events while typeahead is active, see #10458. 31060 // Prevents focusing the wrong item when typeahead causes a scroll while the mouse 31061 // is over an item in the menu 31062 if ( this.previousFilter ) { 31063 return; 31064 } 31065 var actualTarget = $( event.target ).closest( ".ui-menu-item" ), 31066 target = $( event.currentTarget ); 31067 // Ignore bubbled events on parent items, see #11641 31068 if ( actualTarget[ 0 ] !== target[ 0 ] ) { 31069 return; 31070 } 31071 // Remove ui-state-active class from siblings of the newly focused menu item 31072 // to avoid a jump caused by adjacent elements both having a class with a border 31073 this._removeClass( target.siblings().children( ".ui-state-active" ), 31074 null, "ui-state-active" ); 31075 this.focus( event, target ); 31076 }, 31077 mouseleave: "collapseAll", 31078 "mouseleave .ui-menu": "collapseAll", 31079 focus: function( event, keepActiveItem ) { 31080 // If there's already an active item, keep it active 31081 // If not, activate the first item 31082 var item = this.active || this.element.find( this.options.items ).eq( 0 ); 31083 if ( !keepActiveItem ) { 31084 this.focus( event, item ); 31085 } 31086 }, 31087 blur: function( event ) { 31088 this._delay( function() { 31089 var notContained = !$.contains( 31090 this.element[ 0 ],
vendor: 2,041 bytes, lines 31091-31171
31091 $.ui.safeActiveElement( this.document[ 0 ] ) 31092 ); 31093 if ( notContained ) { 31094 this.collapseAll( event ); 31095 } 31096 } ); 31097 }, 31098 keydown: "_keydown" 31099 } ); 31100 this.refresh(); 31101 // Clicks outside of a menu collapse any open menus 31102 this._on( this.document, { 31103 click: function( event ) { 31104 if ( this._closeOnDocumentClick( event ) ) { 31105 this.collapseAll( event ); 31106 } 31107 // Reset the mouseHandled flag 31108 this.mouseHandled = false; 31109 } 31110 } ); 31111 }, 31112 _destroy: function() { 31113 var items = this.element.find( ".ui-menu-item" ) 31114 .removeAttr( "role aria-disabled" ), 31115 submenus = items.children( ".ui-menu-item-wrapper" ) 31116 .removeUniqueId() 31117 .removeAttr( "tabIndex role aria-haspopup" ); 31118 // Destroy (sub)menus 31119 this.element 31120 .removeAttr( "aria-activedescendant" ) 31121 .find( ".ui-menu" ).addBack() 31122 .removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " + 31123 "tabIndex" ) 31124 .removeUniqueId() 31125 .show(); 31126 submenus.children().each( function() { 31127 var elem = $( this ); 31128 if ( elem.data( "ui-menu-submenu-caret" ) ) { 31129 elem.remove(); 31130 } 31131 } ); 31132 }, 31133 _keydown: function( event ) { 31134 var match, prev, character, skip, 31135 preventDefault = true; 31136 switch ( event.keyCode ) { 31137 case $.ui.keyCode.PAGE_UP: 31138 this.previousPage( event ); 31139 break; 31140 case $.ui.keyCode.PAGE_DOWN: 31141 this.nextPage( event ); 31142 break; 31143 case $.ui.keyCode.HOME: 31144 this._move( "first", "first", event ); 31145 break; 31146 case $.ui.keyCode.END: 31147 this._move( "last", "last", event ); 31148 break; 31149 case $.ui.keyCode.UP: 31150 this.previous( event ); 31151 break; 31152 case $.ui.keyCode.DOWN: 31153 this.next( event ); 31154 break; 31155 case $.ui.keyCode.LEFT: 31156 this.collapse( event ); 31157 break; 31158 case $.ui.keyCode.RIGHT: 31159 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { 31160 this.expand( event ); 31161 } 31162 break; 31163 case $.ui.keyCode.ENTER: 31164 case $.ui.keyCode.SPACE: 31165 this._activate( event ); 31166 break; 31167 case $.ui.keyCode.ESCAPE: 31168 this.collapse( event ); 31169 break; 31170 default: 31171 preventDefault = false;
vendor: 6,885 bytes, lines 31172-31375
31172 prev = this.previousFilter || ""; 31173 skip = false; 31174 // Support number pad values 31175 character = event.keyCode >= 96 && event.keyCode <= 105 ? 31176 ( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode ); 31177 clearTimeout( this.filterTimer ); 31178 if ( character === prev ) { 31179 skip = true; 31180 } else { 31181 character = prev + character; 31182 } 31183 match = this._filterMenuItems( character ); 31184 match = skip && match.index( this.active.next() ) !== -1 ? 31185 this.active.nextAll( ".ui-menu-item" ) : 31186 match; 31187 // If no matches on the current filter, reset to the last character pressed 31188 // to move down the menu to the first item that starts with that character 31189 if ( !match.length ) { 31190 character = String.fromCharCode( event.keyCode ); 31191 match = this._filterMenuItems( character ); 31192 } 31193 if ( match.length ) { 31194 this.focus( event, match ); 31195 this.previousFilter = character; 31196 this.filterTimer = this._delay( function() { 31197 delete this.previousFilter; 31198 }, 1000 ); 31199 } else { 31200 delete this.previousFilter; 31201 } 31202 } 31203 if ( preventDefault ) { 31204 event.preventDefault(); 31205 } 31206 }, 31207 _activate: function( event ) { 31208 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { 31209 if ( this.active.children( "[aria-haspopup='true']" ).length ) { 31210 this.expand( event ); 31211 } else { 31212 this.select( event ); 31213 } 31214 } 31215 }, 31216 refresh: function() { 31217 var menus, items, newSubmenus, newItems, newWrappers, 31218 that = this, 31219 icon = this.options.icons.submenu, 31220 submenus = this.element.find( this.options.menus ); 31221 this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length ); 31222 // Initialize nested menus 31223 newSubmenus = submenus.filter( ":not(.ui-menu)" ) 31224 .hide() 31225 .attr( { 31226 role: this.options.role, 31227 "aria-hidden": "true", 31228 "aria-expanded": "false" 31229 } ) 31230 .each( function() { 31231 var menu = $( this ), 31232 item = menu.prev(), 31233 submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true ); 31234 that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon ); 31235 item 31236 .attr( "aria-haspopup", "true" ) 31237 .prepend( submenuCaret ); 31238 menu.attr( "aria-labelledby", item.attr( "id" ) ); 31239 } ); 31240 this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" ); 31241 menus = submenus.add( this.element ); 31242 items = menus.find( this.options.items ); 31243 // Initialize menu-items containing spaces and/or dashes only as dividers 31244 items.not( ".ui-menu-item" ).each( function() { 31245 var item = $( this ); 31246 if ( that._isDivider( item ) ) { 31247 that._addClass( item, "ui-menu-divider", "ui-widget-content" ); 31248 } 31249 } ); 31250 // Don't refresh list items that are already adapted 31251 newItems = items.not( ".ui-menu-item, .ui-menu-divider" ); 31252 newWrappers = newItems.children() 31253 .not( ".ui-menu" ) 31254 .uniqueId() 31255 .attr( { 31256 tabIndex: -1, 31257 role: this._itemRole() 31258 } ); 31259 this._addClass( newItems, "ui-menu-item" ) 31260 ._addClass( newWrappers, "ui-menu-item-wrapper" ); 31261 // Add aria-disabled attribute to any disabled menu item 31262 items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" ); 31263 // If the active item has been removed, blur the menu 31264 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { 31265 this.blur(); 31266 } 31267 }, 31268 _itemRole: function() { 31269 return { 31270 menu: "menuitem", 31271 listbox: "option" 31272 }[ this.options.role ]; 31273 }, 31274 _setOption: function( key, value ) { 31275 if ( key === "icons" ) { 31276 var icons = this.element.find( ".ui-menu-icon" ); 31277 this._removeClass( icons, null, this.options.icons.submenu ) 31278 ._addClass( icons, null, value.submenu ); 31279 } 31280 this._super( key, value ); 31281 }, 31282 _setOptionDisabled: function( value ) { 31283 this._super( value ); 31284 this.element.attr( "aria-disabled", String( value ) ); 31285 this._toggleClass( null, "ui-state-disabled", !!value ); 31286 }, 31287 focus: function( event, item ) { 31288 var nested, focused, activeParent; 31289 this.blur( event, event && event.type === "focus" ); 31290 this._scrollIntoView( item ); 31291 this.active = item.first(); 31292 focused = this.active.children( ".ui-menu-item-wrapper" ); 31293 this._addClass( focused, null, "ui-state-active" ); 31294 // Only update aria-activedescendant if there's a role 31295 // otherwise we assume focus is managed elsewhere 31296 if ( this.options.role ) { 31297 this.element.attr( "aria-activedescendant", focused.attr( "id" ) ); 31298 } 31299 // Highlight active parent menu item, if any 31300 activeParent = this.active 31301 .parent() 31302 .closest( ".ui-menu-item" ) 31303 .children( ".ui-menu-item-wrapper" ); 31304 this._addClass( activeParent, null, "ui-state-active" ); 31305 if ( event && event.type === "keydown" ) { 31306 this._close(); 31307 } else { 31308 this.timer = this._delay( function() { 31309 this._close(); 31310 }, this.delay ); 31311 } 31312 nested = item.children( ".ui-menu" ); 31313 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) { 31314 this._startOpening( nested ); 31315 } 31316 this.activeMenu = item.parent(); 31317 this._trigger( "focus", event, { item: item } ); 31318 }, 31319 _scrollIntoView: function( item ) { 31320 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight; 31321 if ( this._hasScroll() ) { 31322 borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0; 31323 paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0; 31324 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop; 31325 scroll = this.activeMenu.scrollTop(); 31326 elementHeight = this.activeMenu.height(); 31327 itemHeight = item.outerHeight(); 31328 if ( offset < 0 ) { 31329 this.activeMenu.scrollTop( scroll + offset ); 31330 } else if ( offset + itemHeight > elementHeight ) { 31331 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight ); 31332 } 31333 } 31334 }, 31335 blur: function( event, fromFocus ) { 31336 if ( !fromFocus ) { 31337 clearTimeout( this.timer ); 31338 } 31339 if ( !this.active ) { 31340 return; 31341 } 31342 this._removeClass( this.active.children( ".ui-menu-item-wrapper" ), 31343 null, "ui-state-active" ); 31344 this._trigger( "blur", event, { item: this.active } ); 31345 this.active = null; 31346 }, 31347 _startOpening: function( submenu ) { 31348 clearTimeout( this.timer ); 31349 // Don't open if already open fixes a Firefox bug that caused a .5 pixel 31350 // shift in the submenu position when mousing over the caret icon 31351 if ( submenu.attr( "aria-hidden" ) !== "true" ) { 31352 return; 31353 } 31354 this.timer = this._delay( function() { 31355 this._close(); 31356 this._open( submenu ); 31357 }, this.delay ); 31358 }, 31359 _open: function( submenu ) { 31360 var position = $.extend( { 31361 of: this.active 31362 }, this.options.position ); 31363 clearTimeout( this.timer ); 31364 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) ) 31365 .hide() 31366 .attr( "aria-hidden", "true" ); 31367 submenu 31368 .show() 31369 .removeAttr( "aria-hidden" ) 31370 .attr( "aria-expanded", "true" ) 31371 .position( position ); 31372 }, 31373 collapseAll: function( event, all ) { 31374 clearTimeout( this.timer ); 31375 this.timer = this._delay( function() {
vendor: 26,702 bytes, lines 31376-32177
31376 // If we were passed an event, look for the submenu that contains the event 31377 var currentMenu = all ? this.element : 31378 $( event && event.target ).closest( this.element.find( ".ui-menu" ) ); 31379 // If we found no valid submenu ancestor, use the main menu to close all 31380 // sub menus anyway 31381 if ( !currentMenu.length ) { 31382 currentMenu = this.element; 31383 } 31384 this._close( currentMenu ); 31385 this.blur( event ); 31386 // Work around active item staying active after menu is blurred 31387 this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" ); 31388 this.activeMenu = currentMenu; 31389 }, this.delay ); 31390 }, 31391 // With no arguments, closes the currently active menu - if nothing is active 31392 // it closes all menus. If passed an argument, it will search for menus BELOW 31393 _close: function( startMenu ) { 31394 if ( !startMenu ) { 31395 startMenu = this.active ? this.active.parent() : this.element; 31396 } 31397 startMenu.find( ".ui-menu" ) 31398 .hide() 31399 .attr( "aria-hidden", "true" ) 31400 .attr( "aria-expanded", "false" ); 31401 }, 31402 _closeOnDocumentClick: function( event ) { 31403 return !$( event.target ).closest( ".ui-menu" ).length; 31404 }, 31405 _isDivider: function( item ) { 31406 // Match hyphen, em dash, en dash 31407 return !/[^\-\u2014\u2013\s]/.test( item.text() ); 31408 }, 31409 collapse: function( event ) { 31410 var newItem = this.active && 31411 this.active.parent().closest( ".ui-menu-item", this.element ); 31412 if ( newItem && newItem.length ) { 31413 this._close(); 31414 this.focus( event, newItem ); 31415 } 31416 }, 31417 expand: function( event ) { 31418 var newItem = this.active && 31419 this.active 31420 .children( ".ui-menu " ) 31421 .find( this.options.items ) 31422 .first(); 31423 if ( newItem && newItem.length ) { 31424 this._open( newItem.parent() ); 31425 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT 31426 this._delay( function() { 31427 this.focus( event, newItem ); 31428 } ); 31429 } 31430 }, 31431 next: function( event ) { 31432 this._move( "next", "first", event ); 31433 }, 31434 previous: function( event ) { 31435 this._move( "prev", "last", event ); 31436 }, 31437 isFirstItem: function() { 31438 return this.active && !this.active.prevAll( ".ui-menu-item" ).length; 31439 }, 31440 isLastItem: function() { 31441 return this.active && !this.active.nextAll( ".ui-menu-item" ).length; 31442 }, 31443 _move: function( direction, filter, event ) { 31444 var next; 31445 if ( this.active ) { 31446 if ( direction === "first" || direction === "last" ) { 31447 next = this.active 31448 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" ) 31449 .eq( -1 ); 31450 } else { 31451 next = this.active 31452 [ direction + "All" ]( ".ui-menu-item" ) 31453 .eq( 0 ); 31454 } 31455 } 31456 if ( !next || !next.length || !this.active ) { 31457 next = this.activeMenu.find( this.options.items )[ filter ](); 31458 } 31459 this.focus( event, next ); 31460 }, 31461 nextPage: function( event ) { 31462 var item, base, height; 31463 if ( !this.active ) { 31464 this.next( event ); 31465 return; 31466 } 31467 if ( this.isLastItem() ) { 31468 return; 31469 } 31470 if ( this._hasScroll() ) { 31471 base = this.active.offset().top; 31472 height = this.element.height(); 31473 this.active.nextAll( ".ui-menu-item" ).each( function() { 31474 item = $( this ); 31475 return item.offset().top - base - height < 0; 31476 } ); 31477 this.focus( event, item ); 31478 } else { 31479 this.focus( event, this.activeMenu.find( this.options.items ) 31480 [ !this.active ? "first" : "last" ]() ); 31481 } 31482 }, 31483 previousPage: function( event ) { 31484 var item, base, height; 31485 if ( !this.active ) { 31486 this.next( event ); 31487 return; 31488 } 31489 if ( this.isFirstItem() ) { 31490 return; 31491 } 31492 if ( this._hasScroll() ) { 31493 base = this.active.offset().top; 31494 height = this.element.height(); 31495 this.active.prevAll( ".ui-menu-item" ).each( function() { 31496 item = $( this ); 31497 return item.offset().top - base + height > 0; 31498 } ); 31499 this.focus( event, item ); 31500 } else { 31501 this.focus( event, this.activeMenu.find( this.options.items ).first() ); 31502 } 31503 }, 31504 _hasScroll: function() { 31505 return this.element.outerHeight() < this.element.prop( "scrollHeight" ); 31506 }, 31507 select: function( event ) { 31508 // TODO: It should never be possible to not have an active item at this 31509 // point, but the tests don't trigger mouseenter before click. 31510 this.active = this.active || $( event.target ).closest( ".ui-menu-item" ); 31511 var ui = { item: this.active }; 31512 if ( !this.active.has( ".ui-menu" ).length ) { 31513 this.collapseAll( event, true ); 31514 } 31515 this._trigger( "select", event, ui ); 31516 }, 31517 _filterMenuItems: function( character ) { 31518 var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ), 31519 regex = new RegExp( "^" + escapedCharacter, "i" ); 31520 return this.activeMenu 31521 .find( this.options.items ) 31522 // Only match on items, not dividers or other content (#10571) 31523 .filter( ".ui-menu-item" ) 31524 .filter( function() { 31525 return regex.test( 31526 $.trim( $( this ).children( ".ui-menu-item-wrapper" ).text() ) ); 31527 } ); 31528 } 31529} ); 31530/*! 31531 * jQuery UI Autocomplete 1.12.1 31532 * http://jqueryui.com 31533 * 31534 * Copyright jQuery Foundation and other contributors 31535 * Released under the MIT license. 31536 * http://jquery.org/license 31537 */ 31538//>>label: Autocomplete 31539//>>group: Widgets 31540//>>description: Lists suggested words as the user is typing. 31541//>>docs: http://api.jqueryui.com/autocomplete/ 31542//>>demos: http://jqueryui.com/autocomplete/ 31543//>>css.structure: ../../themes/base/core.css 31544//>>css.structure: ../../themes/base/autocomplete.css 31545//>>css.theme: ../../themes/base/theme.css 31546$.widget( "ui.autocomplete", { 31547 version: "1.12.1", 31548 defaultElement: "<input>", 31549 options: { 31550 appendTo: null, 31551 autoFocus: false, 31552 delay: 300, 31553 minLength: 1, 31554 position: { 31555 my: "left top", 31556 at: "left bottom", 31557 collision: "none" 31558 }, 31559 source: null, 31560 // Callbacks 31561 change: null, 31562 close: null, 31563 focus: null, 31564 open: null, 31565 response: null, 31566 search: null, 31567 select: null 31568 }, 31569 requestIndex: 0, 31570 pending: 0, 31571 _create: function() { 31572 // Some browsers only repeat keydown events, not keypress events, 31573 // so we use the suppressKeyPress flag to determine if we've already 31574 // handled the keydown event. #7269 31575 // Unfortunately the code for & in keypress is the same as the up arrow, 31576 // so we use the suppressKeyPressRepeat flag to avoid handling keypress 31577 // events when we know the keydown event was used to modify the 31578 // search term. #7799 31579 var suppressKeyPress, suppressKeyPressRepeat, suppressInput, 31580 nodeName = this.element[ 0 ].nodeName.toLowerCase(), 31581 isTextarea = nodeName === "textarea", 31582 isInput = nodeName === "input"; 31583 // Textareas are always multi-line 31584 // Inputs are always single-line, even if inside a contentEditable element 31585 // IE also treats inputs as contentEditable 31586 // All other element types are determined by whether or not they're contentEditable 31587 this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element ); 31588 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; 31589 this.isNewMenu = true; 31590 this._addClass( "ui-autocomplete-input" ); 31591 this.element.attr( "autocomplete", "off" ); 31592 this._on( this.element, { 31593 keydown: function( event ) { 31594 if ( this.element.prop( "readOnly" ) ) { 31595 suppressKeyPress = true; 31596 suppressInput = true; 31597 suppressKeyPressRepeat = true; 31598 return; 31599 } 31600 suppressKeyPress = false; 31601 suppressInput = false; 31602 suppressKeyPressRepeat = false; 31603 var keyCode = $.ui.keyCode; 31604 switch ( event.keyCode ) { 31605 case keyCode.PAGE_UP: 31606 suppressKeyPress = true; 31607 this._move( "previousPage", event ); 31608 break; 31609 case keyCode.PAGE_DOWN: 31610 suppressKeyPress = true; 31611 this._move( "nextPage", event ); 31612 break; 31613 case keyCode.UP: 31614 suppressKeyPress = true; 31615 this._keyEvent( "previous", event ); 31616 break; 31617 case keyCode.DOWN: 31618 suppressKeyPress = true; 31619 this._keyEvent( "next", event ); 31620 break; 31621 case keyCode.ENTER: 31622 // when menu is open and has focus 31623 if ( this.menu.active ) { 31624 // #6055 - Opera still allows the keypress to occur 31625 // which causes forms to submit 31626 suppressKeyPress = true; 31627 event.preventDefault(); 31628 this.menu.select( event ); 31629 } 31630 break; 31631 case keyCode.TAB: 31632 if ( this.menu.active ) { 31633 this.menu.select( event ); 31634 } 31635 break; 31636 case keyCode.ESCAPE: 31637 if ( this.menu.element.is( ":visible" ) ) { 31638 if ( !this.isMultiLine ) { 31639 this._value( this.term ); 31640 } 31641 this.close( event ); 31642 // Different browsers have different default behavior for escape 31643 // Single press can mean undo or clear 31644 // Double press in IE means clear the whole form 31645 event.preventDefault(); 31646 } 31647 break; 31648 default: 31649 suppressKeyPressRepeat = true; 31650 // search timeout should be triggered before the input value is changed 31651 this._searchTimeout( event ); 31652 break; 31653 } 31654 }, 31655 keypress: function( event ) { 31656 if ( suppressKeyPress ) { 31657 suppressKeyPress = false; 31658 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { 31659 event.preventDefault(); 31660 } 31661 return; 31662 } 31663 if ( suppressKeyPressRepeat ) { 31664 return; 31665 } 31666 // Replicate some key handlers to allow them to repeat in Firefox and Opera 31667 var keyCode = $.ui.keyCode; 31668 switch ( event.keyCode ) { 31669 case keyCode.PAGE_UP: 31670 this._move( "previousPage", event ); 31671 break; 31672 case keyCode.PAGE_DOWN: 31673 this._move( "nextPage", event ); 31674 break; 31675 case keyCode.UP: 31676 this._keyEvent( "previous", event ); 31677 break; 31678 case keyCode.DOWN: 31679 this._keyEvent( "next", event ); 31680 break; 31681 } 31682 }, 31683 input: function( event ) { 31684 if ( suppressInput ) { 31685 suppressInput = false; 31686 event.preventDefault(); 31687 return; 31688 } 31689 this._searchTimeout( event ); 31690 }, 31691 focus: function() { 31692 this.selectedItem = null; 31693 this.previous = this._value(); 31694 }, 31695 blur: function( event ) { 31696 if ( this.cancelBlur ) { 31697 delete this.cancelBlur; 31698 return; 31699 } 31700 clearTimeout( this.searching ); 31701 this.close( event ); 31702 this._change( event ); 31703 } 31704 } ); 31705 this._initSource(); 31706 this.menu = $( "<ul>" ) 31707 .appendTo( this._appendTo() ) 31708 .menu( { 31709 // disable ARIA support, the live region takes care of that 31710 role: null 31711 } ) 31712 .hide() 31713 .menu( "instance" ); 31714 this._addClass( this.menu.element, "ui-autocomplete", "ui-front" ); 31715 this._on( this.menu.element, { 31716 mousedown: function( event ) { 31717 // prevent moving focus out of the text field 31718 event.preventDefault(); 31719 // IE doesn't prevent moving focus even with event.preventDefault() 31720 // so we set a flag to know when we should ignore the blur event 31721 this.cancelBlur = true; 31722 this._delay( function() { 31723 delete this.cancelBlur; 31724 // Support: IE 8 only 31725 // Right clicking a menu item or selecting text from the menu items will 31726 // result in focus moving out of the input. However, we've already received 31727 // and ignored the blur event because of the cancelBlur flag set above. So 31728 // we restore focus to ensure that the menu closes properly based on the user's 31729 // next actions. 31730 if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) { 31731 this.element.trigger( "focus" ); 31732 } 31733 } ); 31734 }, 31735 menufocus: function( event, ui ) { 31736 var label, item; 31737 // support: Firefox 31738 // Prevent accidental activation of menu items in Firefox (#7024 #9118) 31739 if ( this.isNewMenu ) { 31740 this.isNewMenu = false; 31741 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) { 31742 this.menu.blur(); 31743 this.document.one( "mousemove", function() { 31744 $( event.target ).trigger( event.originalEvent ); 31745 } ); 31746 return; 31747 } 31748 } 31749 item = ui.item.data( "ui-autocomplete-item" ); 31750 if ( false !== this._trigger( "focus", event, { item: item } ) ) { 31751 // use value to match what will end up in the input, if it was a key event 31752 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) { 31753 this._value( item.value ); 31754 } 31755 } 31756 // Announce the value in the liveRegion 31757 label = ui.item.attr( "aria-label" ) || item.value; 31758 if ( label && $.trim( label ).length ) { 31759 this.liveRegion.children().hide(); 31760 $( "<div>" ).text( label ).appendTo( this.liveRegion ); 31761 } 31762 }, 31763 menuselect: function( event, ui ) { 31764 var item = ui.item.data( "ui-autocomplete-item" ), 31765 previous = this.previous; 31766 // Only trigger when focus was lost (click on menu) 31767 if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) { 31768 this.element.trigger( "focus" ); 31769 this.previous = previous; 31770 // #6109 - IE triggers two focus events and the second 31771 // is asynchronous, so we need to reset the previous 31772 // term synchronously and asynchronously :-( 31773 this._delay( function() { 31774 this.previous = previous; 31775 this.selectedItem = item; 31776 } ); 31777 } 31778 if ( false !== this._trigger( "select", event, { item: item } ) ) { 31779 this._value( item.value ); 31780 } 31781 // reset the term after the select event 31782 // this allows custom select handling to work properly 31783 this.term = this._value(); 31784 this.close( event ); 31785 this.selectedItem = item; 31786 } 31787 } ); 31788 this.liveRegion = $( "<div>", { 31789 role: "status", 31790 "aria-live": "assertive", 31791 "aria-relevant": "additions" 31792 } ) 31793 .appendTo( this.document[ 0 ].body ); 31794 this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" ); 31795 // Turning off autocomplete prevents the browser from remembering the 31796 // value when navigating through history, so we re-enable autocomplete 31797 // if the page is unloaded before the widget is destroyed. #7790 31798 this._on( this.window, { 31799 beforeunload: function() { 31800 this.element.removeAttr( "autocomplete" ); 31801 } 31802 } ); 31803 }, 31804 _destroy: function() { 31805 clearTimeout( this.searching ); 31806 this.element.removeAttr( "autocomplete" ); 31807 this.menu.element.remove(); 31808 this.liveRegion.remove(); 31809 }, 31810 _setOption: function( key, value ) { 31811 this._super( key, value ); 31812 if ( key === "source" ) { 31813 this._initSource(); 31814 } 31815 if ( key === "appendTo" ) { 31816 this.menu.element.appendTo( this._appendTo() ); 31817 } 31818 if ( key === "disabled" && value && this.xhr ) { 31819 this.xhr.abort(); 31820 } 31821 }, 31822 _isEventTargetInWidget: function( event ) { 31823 var menuElement = this.menu.element[ 0 ]; 31824 return event.target === this.element[ 0 ] || 31825 event.target === menuElement || 31826 $.contains( menuElement, event.target ); 31827 }, 31828 _closeOnClickOutside: function( event ) { 31829 if ( !this._isEventTargetInWidget( event ) ) { 31830 this.close(); 31831 } 31832 }, 31833 _appendTo: function() { 31834 var element = this.options.appendTo; 31835 if ( element ) { 31836 element = element.jquery || element.nodeType ? 31837 $( element ) : 31838 this.document.find( element ).eq( 0 ); 31839 } 31840 if ( !element || !element[ 0 ] ) { 31841 element = this.element.closest( ".ui-front, dialog" ); 31842 } 31843 if ( !element.length ) { 31844 element = this.document[ 0 ].body; 31845 } 31846 return element; 31847 }, 31848 _initSource: function() { 31849 var array, url, 31850 that = this; 31851 if ( $.isArray( this.options.source ) ) { 31852 array = this.options.source; 31853 this.source = function( request, response ) { 31854 response( $.ui.autocomplete.filter( array, request.term ) ); 31855 }; 31856 } else if ( typeof this.options.source === "string" ) { 31857 url = this.options.source; 31858 this.source = function( request, response ) { 31859 if ( that.xhr ) { 31860 that.xhr.abort(); 31861 } 31862 that.xhr = $.ajax( { 31863 url: url, 31864 data: request, 31865 dataType: "json", 31866 success: function( data ) { 31867 response( data ); 31868 }, 31869 error: function() { 31870 response( [] ); 31871 } 31872 } ); 31873 }; 31874 } else { 31875 this.source = this.options.source; 31876 } 31877 }, 31878 _searchTimeout: function( event ) { 31879 clearTimeout( this.searching ); 31880 this.searching = this._delay( function() { 31881 // Search if the value has changed, or if the user retypes the same value (see #7434) 31882 var equalValues = this.term === this._value(), 31883 menuVisible = this.menu.element.is( ":visible" ), 31884 modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey; 31885 if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) { 31886 this.selectedItem = null; 31887 this.search( null, event ); 31888 } 31889 }, this.options.delay ); 31890 }, 31891 search: function( value, event ) { 31892 value = value != null ? value : this._value(); 31893 // Always save the actual value, not the one passed as an argument 31894 this.term = this._value(); 31895 if ( value.length < this.options.minLength ) { 31896 return this.close( event ); 31897 } 31898 if ( this._trigger( "search", event ) === false ) { 31899 return; 31900 } 31901 return this._search( value ); 31902 }, 31903 _search: function( value ) { 31904 this.pending++; 31905 this._addClass( "ui-autocomplete-loading" ); 31906 this.cancelSearch = false; 31907 this.source( { term: value }, this._response() ); 31908 }, 31909 _response: function() { 31910 var index = ++this.requestIndex; 31911 return $.proxy( function( content ) { 31912 if ( index === this.requestIndex ) { 31913 this.__response( content ); 31914 } 31915 this.pending--; 31916 if ( !this.pending ) { 31917 this._removeClass( "ui-autocomplete-loading" ); 31918 } 31919 }, this ); 31920 }, 31921 __response: function( content ) { 31922 if ( content ) { 31923 content = this._normalize( content ); 31924 } 31925 this._trigger( "response", null, { content: content } ); 31926 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) { 31927 this._suggest( content ); 31928 this._trigger( "open" ); 31929 } else { 31930 // use ._close() instead of .close() so we don't cancel future searches 31931 this._close(); 31932 } 31933 }, 31934 close: function( event ) { 31935 this.cancelSearch = true; 31936 this._close( event ); 31937 }, 31938 _close: function( event ) { 31939 // Remove the handler that closes the menu on outside clicks 31940 this._off( this.document, "mousedown" ); 31941 if ( this.menu.element.is( ":visible" ) ) { 31942 this.menu.element.hide(); 31943 this.menu.blur(); 31944 this.isNewMenu = true; 31945 this._trigger( "close", event ); 31946 } 31947 }, 31948 _change: function( event ) { 31949 if ( this.previous !== this._value() ) { 31950 this._trigger( "change", event, { item: this.selectedItem } ); 31951 } 31952 }, 31953 _normalize: function( items ) { 31954 // assume all items have the right format when the first item is complete 31955 if ( items.length && items[ 0 ].label && items[ 0 ].value ) { 31956 return items; 31957 } 31958 return $.map( items, function( item ) { 31959 if ( typeof item === "string" ) { 31960 return { 31961 label: item, 31962 value: item 31963 }; 31964 } 31965 return $.extend( {}, item, { 31966 label: item.label || item.value, 31967 value: item.value || item.label 31968 } ); 31969 } ); 31970 }, 31971 _suggest: function( items ) { 31972 var ul = this.menu.element.empty(); 31973 this._renderMenu( ul, items ); 31974 this.isNewMenu = true; 31975 this.menu.refresh(); 31976 // Size and position menu 31977 ul.show(); 31978 this._resizeMenu(); 31979 ul.position( $.extend( { 31980 of: this.element 31981 }, this.options.position ) ); 31982 if ( this.options.autoFocus ) { 31983 this.menu.next(); 31984 } 31985 // Listen for interactions outside of the widget (#6642) 31986 this._on( this.document, { 31987 mousedown: "_closeOnClickOutside" 31988 } ); 31989 }, 31990 _resizeMenu: function() { 31991 var ul = this.menu.element; 31992 ul.outerWidth( Math.max( 31993 // Firefox wraps long text (possibly a rounding bug) 31994 // so we add 1px to avoid the wrapping (#7513) 31995 ul.width( "" ).outerWidth() + 1, 31996 this.element.outerWidth() 31997 ) ); 31998 }, 31999 _renderMenu: function( ul, items ) { 32000 var that = this; 32001 $.each( items, function( index, item ) { 32002 that._renderItemData( ul, item ); 32003 } ); 32004 }, 32005 _renderItemData: function( ul, item ) { 32006 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item ); 32007 }, 32008 _renderItem: function( ul, item ) { 32009 return $( "<li>" ) 32010 .append( $( "<div>" ).text( item.label ) ) 32011 .appendTo( ul ); 32012 }, 32013 _move: function( direction, event ) { 32014 if ( !this.menu.element.is( ":visible" ) ) { 32015 this.search( null, event ); 32016 return; 32017 } 32018 if ( this.menu.isFirstItem() && /^previous/.test( direction ) || 32019 this.menu.isLastItem() && /^next/.test( direction ) ) { 32020 if ( !this.isMultiLine ) { 32021 this._value( this.term ); 32022 } 32023 this.menu.blur(); 32024 return; 32025 } 32026 this.menu[ direction ]( event ); 32027 }, 32028 widget: function() { 32029 return this.menu.element; 32030 }, 32031 _value: function() { 32032 return this.valueMethod.apply( this.element, arguments ); 32033 }, 32034 _keyEvent: function( keyEvent, event ) { 32035 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { 32036 this._move( keyEvent, event ); 32037 // Prevents moving cursor to beginning/end of the text field in some browsers 32038 event.preventDefault(); 32039 } 32040 }, 32041 // Support: Chrome <=50 32042 // We should be able to just use this.element.prop( "isContentEditable" ) 32043 // but hidden elements always report false in Chrome. 32044 // https://code.google.com/p/chromium/issues/detail?id=313082 32045 _isContentEditable: function( element ) { 32046 if ( !element.length ) { 32047 return false; 32048 } 32049 var editable = element.prop( "contentEditable" ); 32050 if ( editable === "inherit" ) { 32051 return this._isContentEditable( element.parent() ); 32052 } 32053 return editable === "true"; 32054 } 32055} ); 32056$.extend( $.ui.autocomplete, { 32057 escapeRegex: function( value ) { 32058 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ); 32059 }, 32060 filter: function( array, term ) { 32061 var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" ); 32062 return $.grep( array, function( value ) { 32063 return matcher.test( value.label || value.value || value ); 32064 } ); 32065 } 32066} ); 32067// Live region extension, adding a `messages` option 32068// NOTE: This is an experimental API. We are still investigating 32069// a full solution for string manipulation and internationalization. 32070$.widget( "ui.autocomplete", $.ui.autocomplete, { 32071 options: { 32072 messages: { 32073 noResults: "No search results.", 32074 results: function( amount ) { 32075 return amount + ( amount > 1 ? " results are" : " result is" ) + 32076 " available, use up and down arrow keys to navigate."; 32077 } 32078 } 32079 }, 32080 __response: function( content ) { 32081 var message; 32082 this._superApply( arguments ); 32083 if ( this.options.disabled || this.cancelSearch ) { 32084 return; 32085 } 32086 if ( content && content.length ) { 32087 message = this.options.messages.results( content.length ); 32088 } else { 32089 message = this.options.messages.noResults; 32090 } 32091 this.liveRegion.children().hide(); 32092 $( "<div>" ).text( message ).appendTo( this.liveRegion ); 32093 } 32094} ); 32095var widgetsAutocomplete = $.ui.autocomplete; 32096// jscs:disable maximumLineLength 32097/* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */ 32098/*! 32099 * jQuery UI Datepicker 1.12.1 32100 * http://jqueryui.com 32101 * 32102 * Copyright jQuery Foundation and other contributors 32103 * Released under the MIT license. 32104 * http://jquery.org/license 32105 */ 32106//>>label: Datepicker 32107//>>group: Widgets 32108//>>description: Displays a calendar from an input or inline for selecting dates. 32109//>>docs: http://api.jqueryui.com/datepicker/ 32110//>>demos: http://jqueryui.com/datepicker/ 32111//>>css.structure: ../../themes/base/core.css 32112//>>css.structure: ../../themes/base/datepicker.css 32113//>>css.theme: ../../themes/base/theme.css 32114$.extend( $.ui, { datepicker: { version: "1.12.1" } } ); 32115var datepicker_instActive; 32116function datepicker_getZindex( elem ) { 32117 var position, value; 32118 while ( elem.length && elem[ 0 ] !== document ) { 32119 // Ignore z-index if position is set to a value where z-index is ignored by the browser 32120 // This makes behavior of this function consistent across browsers 32121 // WebKit always returns auto if the element is positioned 32122 position = elem.css( "position" ); 32123 if ( position === "absolute" || position === "relative" || position === "fixed" ) { 32124 // IE returns 0 when zIndex is not specified 32125 // other browsers return a string 32126 // we ignore the case of nested elements with an explicit value of 0 32127 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div> 32128 value = parseInt( elem.css( "zIndex" ), 10 ); 32129 if ( !isNaN( value ) && value !== 0 ) { 32130 return value; 32131 } 32132 } 32133 elem = elem.parent(); 32134 } 32135 return 0; 32136} 32137/* Date picker manager. 32138 Use the singleton instance of this class, $.datepicker, to interact with the date picker. 32139 Settings for (groups of) date pickers are maintained in an instance object, 32140 allowing multiple different settings on the same page. */ 32141function Datepicker() { 32142 this._curInst = null; // The current instance in use 32143 this._keyEvent = false; // If the last event was a key event 32144 this._disabledInputs = []; // List of date picker inputs that have been disabled 32145 this._datepickerShowing = false; // True if the popup picker is showing , false if not 32146 this._inDialog = false; // True if showing within a "dialog", false if not 32147 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division 32148 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class 32149 this._appendClass = "ui-datepicker-append"; // The name of the append marker class 32150 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class 32151 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class 32152 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class 32153 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class 32154 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class 32155 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class 32156 this.regional = []; // Available regional settings, indexed by language code 32157 this.regional[ "" ] = { // Default regional settings 32158 closeText: "Done", // Display text for close link 32159 prevText: "Prev", // Display text for previous month link 32160 nextText: "Next", // Display text for next month link 32161 currentText: "Today", // Display text for current month link 32162 monthNames: [ "January","February","March","April","May","June", 32163 "July","August","September","October","November","December" ], // Names of months for drop-down and formatting 32164 monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting 32165 dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting 32166 dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting 32167 dayNamesMin: [ "Su","Mo","Tu","We","Th","Fr","Sa" ], // Column headings for days starting at Sunday 32168 weekHeader: "Wk", // Column header for week of the year 32169 dateFormat: "mm/dd/yy", // See format options on parseDate 32170 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... 32171 isRTL: false, // True if right-to-left language, false if left-to-right 32172 showMonthAfterYear: false, // True if the year select precedes month, false for month then year 32173 yearSuffix: "" // Additional text to append to the year in the month headers 32174 }; 32175 this._defaults = { // Global defaults for all the date picker instances 32176 showOn: "focus", // "focus" for popup on focus, 32177 // "button" for trigger button, or "both" for either
vendor: 6,618 bytes, lines 32178-32300
32178 showAnim: "fadeIn", // Name of jQuery animation for popup 32179 showOptions: {}, // Options for enhanced animations 32180 defaultDate: null, // Used when field is blank: actual date, 32181 // +/-number for offset from today, null for today 32182 appendText: "", // Display text following the input box, e.g. showing the format 32183 buttonText: "...", // Text for trigger button 32184 buttonImage: "", // URL for trigger button image 32185 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button 32186 hideIfNoPrevNext: false, // True to hide next/previous month links 32187 // if not applicable, false to just disable them 32188 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links 32189 gotoCurrent: false, // True if today link goes back to current selection instead 32190 changeMonth: false, // True if month can be selected directly, false if only prev/next 32191 changeYear: false, // True if year can be selected directly, false if only prev/next 32192 yearRange: "c-10:c+10", // Range of years to display in drop-down, 32193 // either relative to today's year (-nn:+nn), relative to currently displayed year 32194 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n) 32195 showOtherMonths: false, // True to show dates in other months, false to leave blank 32196 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable 32197 showWeek: false, // True to show week of the year, false to not show it 32198 calculateWeek: this.iso8601Week, // How to calculate the week of the year, 32199 // takes a Date and returns the number of the week for it 32200 shortYearCutoff: "+10", // Short year values < this are in the current century, 32201 // > this are in the previous century, 32202 // string value starting with "+" for current year + value 32203 minDate: null, // The earliest selectable date, or null for no limit 32204 maxDate: null, // The latest selectable date, or null for no limit 32205 duration: "fast", // Duration of display/closure 32206 beforeShowDay: null, // Function that takes a date and returns an array with 32207 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "", 32208 // [2] = cell title (optional), e.g. $.datepicker.noWeekends 32209 beforeShow: null, // Function that takes an input field and 32210 // returns a set of custom settings for the date picker 32211 onSelect: null, // Define a callback function when a date is selected 32212 onChangeMonthYear: null, // Define a callback function when the month or year is changed 32213 onClose: null, // Define a callback function when the datepicker is closed 32214 numberOfMonths: 1, // Number of months to show at a time 32215 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) 32216 stepMonths: 1, // Number of months to step back/forward 32217 stepBigMonths: 12, // Number of months to step back/forward for the big links 32218 altField: "", // Selector for an alternate field to store selected dates into 32219 altFormat: "", // The date format to use for the alternate field 32220 constrainInput: true, // The input is constrained by the current date format 32221 showButtonPanel: false, // True to show button panel, false to not show it 32222 autoSize: false, // True to size the input for the date format, false to leave as is 32223 disabled: false // The initial disabled state 32224 }; 32225 $.extend( this._defaults, this.regional[ "" ] ); 32226 this.regional.en = $.extend( true, {}, this.regional[ "" ] ); 32227 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en ); 32228 this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ); 32229} 32230$.extend( Datepicker.prototype, { 32231 /* Class name added to elements to indicate already configured with a date picker. */ 32232 markerClassName: "hasDatepicker", 32233 //Keep track of the maximum number of rows displayed (see #7043) 32234 maxRows: 4, 32235 // TODO rename to "widget" when switching to widget factory 32236 _widgetDatepicker: function() { 32237 return this.dpDiv; 32238 }, 32239 /* Override the default settings for all instances of the date picker. 32240 * @param settings object - the new settings to use as defaults (anonymous object) 32241 * @return the manager object 32242 */ 32243 setDefaults: function( settings ) { 32244 datepicker_extendRemove( this._defaults, settings || {} ); 32245 return this; 32246 }, 32247 /* Attach the date picker to a jQuery selection. 32248 * @param target element - the target input field or division or span 32249 * @param settings object - the new settings to use for this date picker instance (anonymous) 32250 */ 32251 _attachDatepicker: function( target, settings ) { 32252 var nodeName, inline, inst; 32253 nodeName = target.nodeName.toLowerCase(); 32254 inline = ( nodeName === "div" || nodeName === "span" ); 32255 if ( !target.id ) { 32256 this.uuid += 1; 32257 target.id = "dp" + this.uuid; 32258 } 32259 inst = this._newInst( $( target ), inline ); 32260 inst.settings = $.extend( {}, settings || {} ); 32261 if ( nodeName === "input" ) { 32262 this._connectDatepicker( target, inst ); 32263 } else if ( inline ) { 32264 this._inlineDatepicker( target, inst ); 32265 } 32266 }, 32267 /* Create a new instance object. */ 32268 _newInst: function( target, inline ) { 32269 var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars 32270 return { id: id, input: target, // associated target 32271 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection 32272 drawMonth: 0, drawYear: 0, // month being drawn 32273 inline: inline, // is datepicker inline or not 32274 dpDiv: ( !inline ? this.dpDiv : // presentation div 32275 datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) }; 32276 }, 32277 /* Attach the date picker to an input field. */ 32278 _connectDatepicker: function( target, inst ) { 32279 var input = $( target ); 32280 inst.append = $( [] ); 32281 inst.trigger = $( [] ); 32282 if ( input.hasClass( this.markerClassName ) ) { 32283 return; 32284 } 32285 this._attachments( input, inst ); 32286 input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ). 32287 on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp ); 32288 this._autoSize( inst ); 32289 $.data( target, "datepicker", inst ); 32290 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665) 32291 if ( inst.settings.disabled ) { 32292 this._disableDatepicker( target ); 32293 } 32294 }, 32295 /* Make attachments based on settings. */ 32296 _attachments: function( input, inst ) { 32297 var showOn, buttonText, buttonImage, 32298 appendText = this._get( inst, "appendText" ), 32299 isRTL = this._get( inst, "isRTL" ); 32300 if ( inst.append ) {
vendor: 6,019 bytes, lines 32301-32443
32301 inst.append.remove(); 32302 } 32303 if ( appendText ) { 32304 inst.append = $( "<span class='" + this._appendClass + "'>" + appendText + "</span>" ); 32305 input[ isRTL ? "before" : "after" ]( inst.append ); 32306 } 32307 input.off( "focus", this._showDatepicker ); 32308 if ( inst.trigger ) { 32309 inst.trigger.remove(); 32310 } 32311 showOn = this._get( inst, "showOn" ); 32312 if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field 32313 input.on( "focus", this._showDatepicker ); 32314 } 32315 if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked 32316 buttonText = this._get( inst, "buttonText" ); 32317 buttonImage = this._get( inst, "buttonImage" ); 32318 inst.trigger = $( this._get( inst, "buttonImageOnly" ) ? 32319 $( "<img/>" ).addClass( this._triggerClass ). 32320 attr( { src: buttonImage, alt: buttonText, title: buttonText } ) : 32321 $( "<button type='button'></button>" ).addClass( this._triggerClass ). 32322 html( !buttonImage ? buttonText : $( "<img/>" ).attr( 32323 { src:buttonImage, alt:buttonText, title:buttonText } ) ) ); 32324 input[ isRTL ? "before" : "after" ]( inst.trigger ); 32325 inst.trigger.on( "click", function() { 32326 if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) { 32327 $.datepicker._hideDatepicker(); 32328 } else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) { 32329 $.datepicker._hideDatepicker(); 32330 $.datepicker._showDatepicker( input[ 0 ] ); 32331 } else { 32332 $.datepicker._showDatepicker( input[ 0 ] ); 32333 } 32334 return false; 32335 } ); 32336 } 32337 }, 32338 /* Apply the maximum length for the date format. */ 32339 _autoSize: function( inst ) { 32340 if ( this._get( inst, "autoSize" ) && !inst.inline ) { 32341 var findMax, max, maxI, i, 32342 date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits 32343 dateFormat = this._get( inst, "dateFormat" ); 32344 if ( dateFormat.match( /[DM]/ ) ) { 32345 findMax = function( names ) { 32346 max = 0; 32347 maxI = 0; 32348 for ( i = 0; i < names.length; i++ ) { 32349 if ( names[ i ].length > max ) { 32350 max = names[ i ].length; 32351 maxI = i; 32352 } 32353 } 32354 return maxI; 32355 }; 32356 date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ? 32357 "monthNames" : "monthNamesShort" ) ) ) ); 32358 date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ? 32359 "dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() ); 32360 } 32361 inst.input.attr( "size", this._formatDate( inst, date ).length ); 32362 } 32363 }, 32364 /* Attach an inline date picker to a div. */ 32365 _inlineDatepicker: function( target, inst ) { 32366 var divSpan = $( target ); 32367 if ( divSpan.hasClass( this.markerClassName ) ) { 32368 return; 32369 } 32370 divSpan.addClass( this.markerClassName ).append( inst.dpDiv ); 32371 $.data( target, "datepicker", inst ); 32372 this._setDate( inst, this._getDefaultDate( inst ), true ); 32373 this._updateDatepicker( inst ); 32374 this._updateAlternate( inst ); 32375 //If disabled option is true, disable the datepicker before showing it (see ticket #5665) 32376 if ( inst.settings.disabled ) { 32377 this._disableDatepicker( target ); 32378 } 32379 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements 32380 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height 32381 inst.dpDiv.css( "display", "block" ); 32382 }, 32383 /* Pop-up the date picker in a "dialog" box. 32384 * @param input element - ignored 32385 * @param date string or Date - the initial date to display 32386 * @param onSelect function - the function to call when a date is selected 32387 * @param settings object - update the dialog date picker instance's settings (anonymous object) 32388 * @param pos int[2] - coordinates for the dialog's position within the screen or 32389 * event - with x/y coordinates or 32390 * leave empty for default (screen centre) 32391 * @return the manager object 32392 */ 32393 _dialogDatepicker: function( input, date, onSelect, settings, pos ) { 32394 var id, browserWidth, browserHeight, scrollX, scrollY, 32395 inst = this._dialogInst; // internal instance 32396 if ( !inst ) { 32397 this.uuid += 1; 32398 id = "dp" + this.uuid; 32399 this._dialogInput = $( "<input type='text' id='" + id + 32400 "' style='position: absolute; top: -100px; width: 0px;'/>" ); 32401 this._dialogInput.on( "keydown", this._doKeyDown ); 32402 $( "body" ).append( this._dialogInput ); 32403 inst = this._dialogInst = this._newInst( this._dialogInput, false ); 32404 inst.settings = {}; 32405 $.data( this._dialogInput[ 0 ], "datepicker", inst ); 32406 } 32407 datepicker_extendRemove( inst.settings, settings || {} ); 32408 date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date ); 32409 this._dialogInput.val( date ); 32410 this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null ); 32411 if ( !this._pos ) { 32412 browserWidth = document.documentElement.clientWidth; 32413 browserHeight = document.documentElement.clientHeight; 32414 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; 32415 scrollY = document.documentElement.scrollTop || document.body.scrollTop; 32416 this._pos = // should use actual width/height below 32417 [ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ]; 32418 } 32419 // Move input on screen for focus, but hidden behind dialog 32420 this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" ); 32421 inst.settings.onSelect = onSelect; 32422 this._inDialog = true; 32423 this.dpDiv.addClass( this._dialogClass ); 32424 this._showDatepicker( this._dialogInput[ 0 ] ); 32425 if ( $.blockUI ) { 32426 $.blockUI( this.dpDiv ); 32427 } 32428 $.data( this._dialogInput[ 0 ], "datepicker", inst ); 32429 return this; 32430 }, 32431 /* Detach a datepicker from its control. 32432 * @param target element - the target input field or division or span 32433 */ 32434 _destroyDatepicker: function( target ) { 32435 var nodeName, 32436 $target = $( target ), 32437 inst = $.data( target, "datepicker" ); 32438 if ( !$target.hasClass( this.markerClassName ) ) { 32439 return; 32440 } 32441 nodeName = target.nodeName.toLowerCase(); 32442 $.removeData( target, "datepicker" ); 32443 if ( nodeName === "input" ) {
vendor: 7,114 bytes, lines 32444-32635
32444 inst.append.remove(); 32445 inst.trigger.remove(); 32446 $target.removeClass( this.markerClassName ). 32447 off( "focus", this._showDatepicker ). 32448 off( "keydown", this._doKeyDown ). 32449 off( "keypress", this._doKeyPress ). 32450 off( "keyup", this._doKeyUp ); 32451 } else if ( nodeName === "div" || nodeName === "span" ) { 32452 $target.removeClass( this.markerClassName ).empty(); 32453 } 32454 if ( datepicker_instActive === inst ) { 32455 datepicker_instActive = null; 32456 } 32457 }, 32458 /* Enable the date picker to a jQuery selection. 32459 * @param target element - the target input field or division or span 32460 */ 32461 _enableDatepicker: function( target ) { 32462 var nodeName, inline, 32463 $target = $( target ), 32464 inst = $.data( target, "datepicker" ); 32465 if ( !$target.hasClass( this.markerClassName ) ) { 32466 return; 32467 } 32468 nodeName = target.nodeName.toLowerCase(); 32469 if ( nodeName === "input" ) { 32470 target.disabled = false; 32471 inst.trigger.filter( "button" ). 32472 each( function() { this.disabled = false; } ).end(). 32473 filter( "img" ).css( { opacity: "1.0", cursor: "" } ); 32474 } else if ( nodeName === "div" || nodeName === "span" ) { 32475 inline = $target.children( "." + this._inlineClass ); 32476 inline.children().removeClass( "ui-state-disabled" ); 32477 inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ). 32478 prop( "disabled", false ); 32479 } 32480 this._disabledInputs = $.map( this._disabledInputs, 32481 function( value ) { return ( value === target ? null : value ); } ); // delete entry 32482 }, 32483 /* Disable the date picker to a jQuery selection. 32484 * @param target element - the target input field or division or span 32485 */ 32486 _disableDatepicker: function( target ) { 32487 var nodeName, inline, 32488 $target = $( target ), 32489 inst = $.data( target, "datepicker" ); 32490 if ( !$target.hasClass( this.markerClassName ) ) { 32491 return; 32492 } 32493 nodeName = target.nodeName.toLowerCase(); 32494 if ( nodeName === "input" ) { 32495 target.disabled = true; 32496 inst.trigger.filter( "button" ). 32497 each( function() { this.disabled = true; } ).end(). 32498 filter( "img" ).css( { opacity: "0.5", cursor: "default" } ); 32499 } else if ( nodeName === "div" || nodeName === "span" ) { 32500 inline = $target.children( "." + this._inlineClass ); 32501 inline.children().addClass( "ui-state-disabled" ); 32502 inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ). 32503 prop( "disabled", true ); 32504 } 32505 this._disabledInputs = $.map( this._disabledInputs, 32506 function( value ) { return ( value === target ? null : value ); } ); // delete entry 32507 this._disabledInputs[ this._disabledInputs.length ] = target; 32508 }, 32509 /* Is the first field in a jQuery collection disabled as a datepicker? 32510 * @param target element - the target input field or division or span 32511 * @return boolean - true if disabled, false if enabled 32512 */ 32513 _isDisabledDatepicker: function( target ) { 32514 if ( !target ) { 32515 return false; 32516 } 32517 for ( var i = 0; i < this._disabledInputs.length; i++ ) { 32518 if ( this._disabledInputs[ i ] === target ) { 32519 return true; 32520 } 32521 } 32522 return false; 32523 }, 32524 /* Retrieve the instance data for the target control. 32525 * @param target element - the target input field or division or span 32526 * @return object - the associated instance data 32527 * @throws error if a jQuery problem getting data 32528 */ 32529 _getInst: function( target ) { 32530 try { 32531 return $.data( target, "datepicker" ); 32532 } 32533 catch ( err ) { 32534 throw "Missing instance data for this datepicker"; 32535 } 32536 }, 32537 /* Update or retrieve the settings for a date picker attached to an input field or division. 32538 * @param target element - the target input field or division or span 32539 * @param name object - the new settings to update or 32540 * string - the name of the setting to change or retrieve, 32541 * when retrieving also "all" for all instance settings or 32542 * "defaults" for all global defaults 32543 * @param value any - the new value for the setting 32544 * (omit if above is an object or to retrieve a value) 32545 */ 32546 _optionDatepicker: function( target, name, value ) { 32547 var settings, date, minDate, maxDate, 32548 inst = this._getInst( target ); 32549 if ( arguments.length === 2 && typeof name === "string" ) { 32550 return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) : 32551 ( inst ? ( name === "all" ? $.extend( {}, inst.settings ) : 32552 this._get( inst, name ) ) : null ) ); 32553 } 32554 settings = name || {}; 32555 if ( typeof name === "string" ) { 32556 settings = {}; 32557 settings[ name ] = value; 32558 } 32559 if ( inst ) { 32560 if ( this._curInst === inst ) { 32561 this._hideDatepicker(); 32562 } 32563 date = this._getDateDatepicker( target, true ); 32564 minDate = this._getMinMaxDate( inst, "min" ); 32565 maxDate = this._getMinMaxDate( inst, "max" ); 32566 datepicker_extendRemove( inst.settings, settings ); 32567 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided 32568 if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) { 32569 inst.settings.minDate = this._formatDate( inst, minDate ); 32570 } 32571 if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) { 32572 inst.settings.maxDate = this._formatDate( inst, maxDate ); 32573 } 32574 if ( "disabled" in settings ) { 32575 if ( settings.disabled ) { 32576 this._disableDatepicker( target ); 32577 } else { 32578 this._enableDatepicker( target ); 32579 } 32580 } 32581 this._attachments( $( target ), inst ); 32582 this._autoSize( inst ); 32583 this._setDate( inst, date ); 32584 this._updateAlternate( inst ); 32585 this._updateDatepicker( inst ); 32586 } 32587 }, 32588 // Change method deprecated 32589 _changeDatepicker: function( target, name, value ) { 32590 this._optionDatepicker( target, name, value ); 32591 }, 32592 /* Redraw the date picker attached to an input field or division. 32593 * @param target element - the target input field or division or span 32594 */ 32595 _refreshDatepicker: function( target ) { 32596 var inst = this._getInst( target ); 32597 if ( inst ) { 32598 this._updateDatepicker( inst ); 32599 } 32600 }, 32601 /* Set the dates for a jQuery selection. 32602 * @param target element - the target input field or division or span 32603 * @param date Date - the new date 32604 */ 32605 _setDateDatepicker: function( target, date ) { 32606 var inst = this._getInst( target ); 32607 if ( inst ) { 32608 this._setDate( inst, date ); 32609 this._updateDatepicker( inst ); 32610 this._updateAlternate( inst ); 32611 } 32612 }, 32613 /* Get the date(s) for the first entry in a jQuery selection. 32614 * @param target element - the target input field or division or span 32615 * @param noDefault boolean - true if no default date is to be used 32616 * @return Date - the current date 32617 */ 32618 _getDateDatepicker: function( target, noDefault ) { 32619 var inst = this._getInst( target ); 32620 if ( inst && !inst.inline ) { 32621 this._setDateFromField( inst, noDefault ); 32622 } 32623 return ( inst ? this._getDate( inst ) : null ); 32624 }, 32625 /* Handle keystrokes. */ 32626 _doKeyDown: function( event ) { 32627 var onSelect, dateStr, sel, 32628 inst = $.datepicker._getInst( event.target ), 32629 handled = true, 32630 isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" ); 32631 inst._keyEvent = true; 32632 if ( $.datepicker._datepickerShowing ) { 32633 switch ( event.keyCode ) { 32634 case 9: $.datepicker._hideDatepicker(); 32635 handled = false;
vendor: 4,621 bytes, lines 32636-32749
32636 break; // hide on tab out 32637 case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." + 32638 $.datepicker._currentClass + ")", inst.dpDiv ); 32639 if ( sel[ 0 ] ) { 32640 $.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] ); 32641 } 32642 onSelect = $.datepicker._get( inst, "onSelect" ); 32643 if ( onSelect ) { 32644 dateStr = $.datepicker._formatDate( inst ); 32645 // Trigger custom callback 32646 onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); 32647 } else { 32648 $.datepicker._hideDatepicker(); 32649 } 32650 return false; // don't submit the form 32651 case 27: $.datepicker._hideDatepicker(); 32652 break; // hide on escape 32653 case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 32654 -$.datepicker._get( inst, "stepBigMonths" ) : 32655 -$.datepicker._get( inst, "stepMonths" ) ), "M" ); 32656 break; // previous month/year on page up/+ ctrl 32657 case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 32658 +$.datepicker._get( inst, "stepBigMonths" ) : 32659 +$.datepicker._get( inst, "stepMonths" ) ), "M" ); 32660 break; // next month/year on page down/+ ctrl 32661 case 35: if ( event.ctrlKey || event.metaKey ) { 32662 $.datepicker._clearDate( event.target ); 32663 } 32664 handled = event.ctrlKey || event.metaKey; 32665 break; // clear on ctrl or command +end 32666 case 36: if ( event.ctrlKey || event.metaKey ) { 32667 $.datepicker._gotoToday( event.target ); 32668 } 32669 handled = event.ctrlKey || event.metaKey; 32670 break; // current on ctrl or command +home 32671 case 37: if ( event.ctrlKey || event.metaKey ) { 32672 $.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" ); 32673 } 32674 handled = event.ctrlKey || event.metaKey; 32675 // -1 day on ctrl or command +left 32676 if ( event.originalEvent.altKey ) { 32677 $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 32678 -$.datepicker._get( inst, "stepBigMonths" ) : 32679 -$.datepicker._get( inst, "stepMonths" ) ), "M" ); 32680 } 32681 // next month/year on alt +left on Mac 32682 break; 32683 case 38: if ( event.ctrlKey || event.metaKey ) { 32684 $.datepicker._adjustDate( event.target, -7, "D" ); 32685 } 32686 handled = event.ctrlKey || event.metaKey; 32687 break; // -1 week on ctrl or command +up 32688 case 39: if ( event.ctrlKey || event.metaKey ) { 32689 $.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" ); 32690 } 32691 handled = event.ctrlKey || event.metaKey; 32692 // +1 day on ctrl or command +right 32693 if ( event.originalEvent.altKey ) { 32694 $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 32695 +$.datepicker._get( inst, "stepBigMonths" ) : 32696 +$.datepicker._get( inst, "stepMonths" ) ), "M" ); 32697 } 32698 // next month/year on alt +right 32699 break; 32700 case 40: if ( event.ctrlKey || event.metaKey ) { 32701 $.datepicker._adjustDate( event.target, +7, "D" ); 32702 } 32703 handled = event.ctrlKey || event.metaKey; 32704 break; // +1 week on ctrl or command +down 32705 default: handled = false; 32706 } 32707 } else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home 32708 $.datepicker._showDatepicker( this ); 32709 } else { 32710 handled = false; 32711 } 32712 if ( handled ) { 32713 event.preventDefault(); 32714 event.stopPropagation(); 32715 } 32716 }, 32717 /* Filter entered characters - based on date format. */ 32718 _doKeyPress: function( event ) { 32719 var chars, chr, 32720 inst = $.datepicker._getInst( event.target ); 32721 if ( $.datepicker._get( inst, "constrainInput" ) ) { 32722 chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) ); 32723 chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode ); 32724 return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 ); 32725 } 32726 }, 32727 /* Synchronise manual entry and field/alternate field. */ 32728 _doKeyUp: function( event ) { 32729 var date, 32730 inst = $.datepicker._getInst( event.target ); 32731 if ( inst.input.val() !== inst.lastVal ) { 32732 try { 32733 date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ), 32734 ( inst.input ? inst.input.val() : null ), 32735 $.datepicker._getFormatConfig( inst ) ); 32736 if ( date ) { // only if valid 32737 $.datepicker._setDateFromField( inst ); 32738 $.datepicker._updateAlternate( inst ); 32739 $.datepicker._updateDatepicker( inst ); 32740 } 32741 } 32742 catch ( err ) { 32743 } 32744 } 32745 return true; 32746 }, 32747 /* Pop-up the date picker for a given input field. 32748 * If false returned from beforeShow event handler do not show. 32749 * @param input element - the input field attached to the date picker or
vendor: 4,237 bytes, lines 32750-32849
32750 * event - if triggered by focus 32751 */ 32752 _showDatepicker: function( input ) { 32753 input = input.target || input; 32754 if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger 32755 input = $( "input", input.parentNode )[ 0 ]; 32756 } 32757 if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here 32758 return; 32759 } 32760 var inst, beforeShow, beforeShowSettings, isFixed, 32761 offset, showAnim, duration; 32762 inst = $.datepicker._getInst( input ); 32763 if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) { 32764 $.datepicker._curInst.dpDiv.stop( true, true ); 32765 if ( inst && $.datepicker._datepickerShowing ) { 32766 $.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] ); 32767 } 32768 } 32769 beforeShow = $.datepicker._get( inst, "beforeShow" ); 32770 beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {}; 32771 if ( beforeShowSettings === false ) { 32772 return; 32773 } 32774 datepicker_extendRemove( inst.settings, beforeShowSettings ); 32775 inst.lastVal = null; 32776 $.datepicker._lastInput = input; 32777 $.datepicker._setDateFromField( inst ); 32778 if ( $.datepicker._inDialog ) { // hide cursor 32779 input.value = ""; 32780 } 32781 if ( !$.datepicker._pos ) { // position below input 32782 $.datepicker._pos = $.datepicker._findPos( input ); 32783 $.datepicker._pos[ 1 ] += input.offsetHeight; // add the height 32784 } 32785 isFixed = false; 32786 $( input ).parents().each( function() { 32787 isFixed |= $( this ).css( "position" ) === "fixed"; 32788 return !isFixed; 32789 } ); 32790 offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] }; 32791 $.datepicker._pos = null; 32792 //to avoid flashes on Firefox 32793 inst.dpDiv.empty(); 32794 // determine sizing offscreen 32795 inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } ); 32796 $.datepicker._updateDatepicker( inst ); 32797 // fix width for dynamic number of date pickers 32798 // and adjust position before showing 32799 offset = $.datepicker._checkOffset( inst, offset, isFixed ); 32800 inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ? 32801 "static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none", 32802 left: offset.left + "px", top: offset.top + "px" } ); 32803 if ( !inst.inline ) { 32804 showAnim = $.datepicker._get( inst, "showAnim" ); 32805 duration = $.datepicker._get( inst, "duration" ); 32806 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 ); 32807 $.datepicker._datepickerShowing = true; 32808 if ( $.effects && $.effects.effect[ showAnim ] ) { 32809 inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration ); 32810 } else { 32811 inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null ); 32812 } 32813 if ( $.datepicker._shouldFocusInput( inst ) ) { 32814 inst.input.trigger( "focus" ); 32815 } 32816 $.datepicker._curInst = inst; 32817 } 32818 }, 32819 /* Generate the date picker content. */ 32820 _updateDatepicker: function( inst ) { 32821 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043) 32822 datepicker_instActive = inst; // for delegate hover events 32823 inst.dpDiv.empty().append( this._generateHTML( inst ) ); 32824 this._attachHandlers( inst ); 32825 var origyearshtml, 32826 numMonths = this._getNumberOfMonths( inst ), 32827 cols = numMonths[ 1 ], 32828 width = 17, 32829 activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" ); 32830 if ( activeCell.length > 0 ) { 32831 datepicker_handleMouseover.apply( activeCell.get( 0 ) ); 32832 } 32833 inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" ); 32834 if ( cols > 1 ) { 32835 inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" ); 32836 } 32837 inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) + 32838 "Class" ]( "ui-datepicker-multi" ); 32839 inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) + 32840 "Class" ]( "ui-datepicker-rtl" ); 32841 if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) { 32842 inst.input.trigger( "focus" ); 32843 } 32844 // Deffered render of the years select (to avoid flashes on Firefox) 32845 if ( inst.yearshtml ) { 32846 origyearshtml = inst.yearshtml; 32847 setTimeout( function() { 32848 //assure that inst.yearshtml didn't change. 32849 if ( origyearshtml === inst.yearshtml && inst.yearshtml ) {
vendor: 5,456 bytes, lines 32850-32982
32850 inst.dpDiv.find( "select.ui-datepicker-year:first" ).replaceWith( inst.yearshtml ); 32851 } 32852 origyearshtml = inst.yearshtml = null; 32853 }, 0 ); 32854 } 32855 }, 32856 // #6694 - don't focus the input if it's already focused 32857 // this breaks the change event in IE 32858 // Support: IE and jQuery <1.9 32859 _shouldFocusInput: function( inst ) { 32860 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" ); 32861 }, 32862 /* Check positioning to remain on screen. */ 32863 _checkOffset: function( inst, offset, isFixed ) { 32864 var dpWidth = inst.dpDiv.outerWidth(), 32865 dpHeight = inst.dpDiv.outerHeight(), 32866 inputWidth = inst.input ? inst.input.outerWidth() : 0, 32867 inputHeight = inst.input ? inst.input.outerHeight() : 0, 32868 viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ), 32869 viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() ); 32870 offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 ); 32871 offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0; 32872 offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0; 32873 // Now check if datepicker is showing outside window viewport - move to a better place if so. 32874 offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ? 32875 Math.abs( offset.left + dpWidth - viewWidth ) : 0 ); 32876 offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ? 32877 Math.abs( dpHeight + inputHeight ) : 0 ); 32878 return offset; 32879 }, 32880 /* Find an object's position on the screen. */ 32881 _findPos: function( obj ) { 32882 var position, 32883 inst = this._getInst( obj ), 32884 isRTL = this._get( inst, "isRTL" ); 32885 while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden( obj ) ) ) { 32886 obj = obj[ isRTL ? "previousSibling" : "nextSibling" ]; 32887 } 32888 position = $( obj ).offset(); 32889 return [ position.left, position.top ]; 32890 }, 32891 /* Hide the date picker from view. 32892 * @param input element - the input field attached to the date picker 32893 */ 32894 _hideDatepicker: function( input ) { 32895 var showAnim, duration, postProcess, onClose, 32896 inst = this._curInst; 32897 if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) { 32898 return; 32899 } 32900 if ( this._datepickerShowing ) { 32901 showAnim = this._get( inst, "showAnim" ); 32902 duration = this._get( inst, "duration" ); 32903 postProcess = function() { 32904 $.datepicker._tidyDialog( inst ); 32905 }; 32906 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed 32907 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) { 32908 inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess ); 32909 } else { 32910 inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" : 32911 ( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess ); 32912 } 32913 if ( !showAnim ) { 32914 postProcess(); 32915 } 32916 this._datepickerShowing = false; 32917 onClose = this._get( inst, "onClose" ); 32918 if ( onClose ) { 32919 onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] ); 32920 } 32921 this._lastInput = null; 32922 if ( this._inDialog ) { 32923 this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } ); 32924 if ( $.blockUI ) { 32925 $.unblockUI(); 32926 $( "body" ).append( this.dpDiv ); 32927 } 32928 } 32929 this._inDialog = false; 32930 } 32931 }, 32932 /* Tidy up after a dialog display. */ 32933 _tidyDialog: function( inst ) { 32934 inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" ); 32935 }, 32936 /* Close date picker if clicked elsewhere. */ 32937 _checkExternalClick: function( event ) { 32938 if ( !$.datepicker._curInst ) { 32939 return; 32940 } 32941 var $target = $( event.target ), 32942 inst = $.datepicker._getInst( $target[ 0 ] ); 32943 if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId && 32944 $target.parents( "#" + $.datepicker._mainDivId ).length === 0 && 32945 !$target.hasClass( $.datepicker.markerClassName ) && 32946 !$target.closest( "." + $.datepicker._triggerClass ).length && 32947 $.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) || 32948 ( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) { 32949 $.datepicker._hideDatepicker(); 32950 } 32951 }, 32952 /* Adjust one of the date sub-fields. */ 32953 _adjustDate: function( id, offset, period ) { 32954 var target = $( id ), 32955 inst = this._getInst( target[ 0 ] ); 32956 if ( this._isDisabledDatepicker( target[ 0 ] ) ) { 32957 return; 32958 } 32959 this._adjustInstDate( inst, offset + 32960 ( period === "M" ? this._get( inst, "showCurrentAtPos" ) : 0 ), // undo positioning 32961 period ); 32962 this._updateDatepicker( inst ); 32963 }, 32964 /* Action for current link. */ 32965 _gotoToday: function( id ) { 32966 var date, 32967 target = $( id ), 32968 inst = this._getInst( target[ 0 ] ); 32969 if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) { 32970 inst.selectedDay = inst.currentDay; 32971 inst.drawMonth = inst.selectedMonth = inst.currentMonth; 32972 inst.drawYear = inst.selectedYear = inst.currentYear; 32973 } else { 32974 date = new Date(); 32975 inst.selectedDay = date.getDate(); 32976 inst.drawMonth = inst.selectedMonth = date.getMonth(); 32977 inst.drawYear = inst.selectedYear = date.getFullYear(); 32978 } 32979 this._notifyChange( inst ); 32980 this._adjustDate( target ); 32981 }, 32982 /* Action for selecting a new month/year. */
vendor: 4,554 bytes, lines 32983-33095
32983 _selectMonthYear: function( id, select, period ) { 32984 var target = $( id ), 32985 inst = this._getInst( target[ 0 ] ); 32986 inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] = 32987 inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] = 32988 parseInt( select.options[ select.selectedIndex ].value, 10 ); 32989 this._notifyChange( inst ); 32990 this._adjustDate( target ); 32991 }, 32992 /* Action for selecting a day. */ 32993 _selectDay: function( id, month, year, td ) { 32994 var inst, 32995 target = $( id ); 32996 if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) { 32997 return; 32998 } 32999 inst = this._getInst( target[ 0 ] ); 33000 inst.selectedDay = inst.currentDay = $( "a", td ).html(); 33001 inst.selectedMonth = inst.currentMonth = month; 33002 inst.selectedYear = inst.currentYear = year; 33003 this._selectDate( id, this._formatDate( inst, 33004 inst.currentDay, inst.currentMonth, inst.currentYear ) ); 33005 }, 33006 /* Erase the input field and hide the date picker. */ 33007 _clearDate: function( id ) { 33008 var target = $( id ); 33009 this._selectDate( target, "" ); 33010 }, 33011 /* Update the input field with the selected date. */ 33012 _selectDate: function( id, dateStr ) { 33013 var onSelect, 33014 target = $( id ), 33015 inst = this._getInst( target[ 0 ] ); 33016 dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) ); 33017 if ( inst.input ) { 33018 inst.input.val( dateStr ); 33019 } 33020 this._updateAlternate( inst ); 33021 onSelect = this._get( inst, "onSelect" ); 33022 if ( onSelect ) { 33023 onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); // trigger custom callback 33024 } else if ( inst.input ) { 33025 inst.input.trigger( "change" ); // fire the change event 33026 } 33027 if ( inst.inline ) { 33028 this._updateDatepicker( inst ); 33029 } else { 33030 this._hideDatepicker(); 33031 this._lastInput = inst.input[ 0 ]; 33032 if ( typeof( inst.input[ 0 ] ) !== "object" ) { 33033 inst.input.trigger( "focus" ); // restore focus 33034 } 33035 this._lastInput = null; 33036 } 33037 }, 33038 /* Update any alternate field to synchronise with the main field. */ 33039 _updateAlternate: function( inst ) { 33040 var altFormat, date, dateStr, 33041 altField = this._get( inst, "altField" ); 33042 if ( altField ) { // update alternate field too 33043 altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" ); 33044 date = this._getDate( inst ); 33045 dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) ); 33046 $( altField ).val( dateStr ); 33047 } 33048 }, 33049 /* Set as beforeShowDay function to prevent selection of weekends. 33050 * @param date Date - the date to customise 33051 * @return [boolean, string] - is this date selectable?, what is its CSS class? 33052 */ 33053 noWeekends: function( date ) { 33054 var day = date.getDay(); 33055 return [ ( day > 0 && day < 6 ), "" ]; 33056 }, 33057 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. 33058 * @param date Date - the date to get the week for 33059 * @return number - the number of the week within the year that contains this date 33060 */ 33061 iso8601Week: function( date ) { 33062 var time, 33063 checkDate = new Date( date.getTime() ); 33064 // Find Thursday of this week starting on Monday 33065 checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) ); 33066 time = checkDate.getTime(); 33067 checkDate.setMonth( 0 ); // Compare with Jan 1 33068 checkDate.setDate( 1 ); 33069 return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1; 33070 }, 33071 /* Parse a string value into a date object. 33072 * See formatDate below for the possible formats. 33073 * 33074 * @param format string - the expected format of the date 33075 * @param value string - the date in the above format 33076 * @param settings Object - attributes include: 33077 * shortYearCutoff number - the cutoff year for determining the century (optional) 33078 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) 33079 * dayNames string[7] - names of the days from Sunday (optional) 33080 * monthNamesShort string[12] - abbreviated names of the months (optional) 33081 * monthNames string[12] - names of the months (optional) 33082 * @return Date - the extracted date value or null if value is blank 33083 */ 33084 parseDate: function( format, value, settings ) { 33085 if ( format == null || value == null ) { 33086 throw "Invalid arguments"; 33087 } 33088 value = ( typeof value === "object" ? value.toString() : value + "" ); 33089 if ( value === "" ) { 33090 return null; 33091 } 33092 var iFormat, dim, extra, 33093 iValue = 0, 33094 shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff, 33095 shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp
vendor: 16,955 bytes, lines 33095-33588
33095: 33096 new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ), 33097 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort, 33098 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames, 33099 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort, 33100 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames, 33101 year = -1, 33102 month = -1, 33103 day = -1, 33104 doy = -1, 33105 literal = false, 33106 date, 33107 // Check whether a format character is doubled 33108 lookAhead = function( match ) { 33109 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match ); 33110 if ( matches ) { 33111 iFormat++; 33112 } 33113 return matches; 33114 }, 33115 // Extract a number from the string value 33116 getNumber = function( match ) { 33117 var isDoubled = lookAhead( match ), 33118 size = ( match === "@" ? 14 : ( match === "!" ? 20 : 33119 ( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ), 33120 minSize = ( match === "y" ? size : 1 ), 33121 digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ), 33122 num = value.substring( iValue ).match( digits ); 33123 if ( !num ) { 33124 throw "Missing number at position " + iValue; 33125 } 33126 iValue += num[ 0 ].length; 33127 return parseInt( num[ 0 ], 10 ); 33128 }, 33129 // Extract a name from the string value and convert to an index 33130 getName = function( match, shortNames, longNames ) { 33131 var index = -1, 33132 names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) { 33133 return [ [ k, v ] ]; 33134 } ).sort( function( a, b ) { 33135 return -( a[ 1 ].length - b[ 1 ].length ); 33136 } ); 33137 $.each( names, function( i, pair ) { 33138 var name = pair[ 1 ]; 33139 if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) { 33140 index = pair[ 0 ]; 33141 iValue += name.length; 33142 return false; 33143 } 33144 } ); 33145 if ( index !== -1 ) { 33146 return index + 1; 33147 } else { 33148 throw "Unknown name at position " + iValue; 33149 } 33150 }, 33151 // Confirm that a literal character matches the string value 33152 checkLiteral = function() { 33153 if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) { 33154 throw "Unexpected literal at position " + iValue; 33155 } 33156 iValue++; 33157 }; 33158 for ( iFormat = 0; iFormat < format.length; iFormat++ ) { 33159 if ( literal ) { 33160 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) { 33161 literal = false; 33162 } else { 33163 checkLiteral(); 33164 } 33165 } else { 33166 switch ( format.charAt( iFormat ) ) { 33167 case "d": 33168 day = getNumber( "d" ); 33169 break; 33170 case "D": 33171 getName( "D", dayNamesShort, dayNames ); 33172 break; 33173 case "o": 33174 doy = getNumber( "o" ); 33175 break; 33176 case "m": 33177 month = getNumber( "m" ); 33178 break; 33179 case "M": 33180 month = getName( "M", monthNamesShort, monthNames ); 33181 break; 33182 case "y": 33183 year = getNumber( "y" ); 33184 break; 33185 case "@": 33186 date = new Date( getNumber( "@" ) ); 33187 year = date.getFullYear(); 33188 month = date.getMonth() + 1; 33189 day = date.getDate(); 33190 break; 33191 case "!": 33192 date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 ); 33193 year = date.getFullYear(); 33194 month = date.getMonth() + 1; 33195 day = date.getDate(); 33196 break; 33197 case "'": 33198 if ( lookAhead( "'" ) ) { 33199 checkLiteral(); 33200 } else { 33201 literal = true; 33202 } 33203 break; 33204 default: 33205 checkLiteral(); 33206 } 33207 } 33208 } 33209 if ( iValue < value.length ) { 33210 extra = value.substr( iValue ); 33211 if ( !/^\s+/.test( extra ) ) { 33212 throw "Extra/unparsed characters found in date: " + extra; 33213 } 33214 } 33215 if ( year === -1 ) { 33216 year = new Date().getFullYear(); 33217 } else if ( year < 100 ) { 33218 year += new Date().getFullYear() - new Date().getFullYear() % 100 + 33219 ( year <= shortYearCutoff ? 0 : -100 ); 33220 } 33221 if ( doy > -1 ) { 33222 month = 1; 33223 day = doy; 33224 do { 33225 dim = this._getDaysInMonth( year, month - 1 ); 33226 if ( day <= dim ) { 33227 break; 33228 } 33229 month++; 33230 day -= dim; 33231 } while ( true ); 33232 } 33233 date = this._daylightSavingAdjust( new Date( year, month - 1, day ) ); 33234 if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) { 33235 throw "Invalid date"; // E.g. 31/02/00 33236 } 33237 return date; 33238 }, 33239 /* Standard date formats. */ 33240 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601) 33241 COOKIE: "D, dd M yy", 33242 ISO_8601: "yy-mm-dd", 33243 RFC_822: "D, d M y", 33244 RFC_850: "DD, dd-M-y", 33245 RFC_1036: "D, d M y", 33246 RFC_1123: "D, d M yy", 33247 RFC_2822: "D, d M yy", 33248 RSS: "D, d M y", // RFC 822 33249 TICKS: "!", 33250 TIMESTAMP: "@", 33251 W3C: "yy-mm-dd", // ISO 8601 33252 _ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) + 33253 Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ), 33254 /* Format a date object into a string value. 33255 * The format can be combinations of the following: 33256 * d - day of month (no leading zero) 33257 * dd - day of month (two digit) 33258 * o - day of year (no leading zeros) 33259 * oo - day of year (three digit) 33260 * D - day name short 33261 * DD - day name long 33262 * m - month of year (no leading zero) 33263 * mm - month of year (two digit) 33264 * M - month name short 33265 * MM - month name long 33266 * y - year (two digit) 33267 * yy - year (four digit) 33268 * @ - Unix timestamp (ms since 01/01/1970) 33269 * ! - Windows ticks (100ns since 01/01/0001) 33270 * "..." - literal text 33271 * '' - single quote 33272 * 33273 * @param format string - the desired format of the date 33274 * @param date Date - the date value to format 33275 * @param settings Object - attributes include: 33276 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) 33277 * dayNames string[7] - names of the days from Sunday (optional) 33278 * monthNamesShort string[12] - abbreviated names of the months (optional) 33279 * monthNames string[12] - names of the months (optional) 33280 * @return string - the date in the above format 33281 */ 33282 formatDate: function( format, date, settings ) { 33283 if ( !date ) { 33284 return ""; 33285 } 33286 var iFormat, 33287 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort, 33288 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames, 33289 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort, 33290 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames, 33291 // Check whether a format character is doubled 33292 lookAhead = function( match ) { 33293 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match ); 33294 if ( matches ) { 33295 iFormat++; 33296 } 33297 return matches; 33298 }, 33299 // Format a number, with leading zero if necessary 33300 formatNumber = function( match, value, len ) { 33301 var num = "" + value; 33302 if ( lookAhead( match ) ) { 33303 while ( num.length < len ) { 33304 num = "0" + num; 33305 } 33306 } 33307 return num; 33308 }, 33309 // Format a name, short or long as requested 33310 formatName = function( match, value, shortNames, longNames ) { 33311 return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] ); 33312 }, 33313 output = "", 33314 literal = false; 33315 if ( date ) { 33316 for ( iFormat = 0; iFormat < format.length; iFormat++ ) { 33317 if ( literal ) { 33318 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) { 33319 literal = false; 33320 } else { 33321 output += format.charAt( iFormat ); 33322 } 33323 } else { 33324 switch ( format.charAt( iFormat ) ) { 33325 case "d": 33326 output += formatNumber( "d", date.getDate(), 2 ); 33327 break; 33328 case "D": 33329 output += formatName( "D", date.getDay(), dayNamesShort, dayNames ); 33330 break; 33331 case "o": 33332 output += formatNumber( "o", 33333 Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 ); 33334 break; 33335 case "m": 33336 output += formatNumber( "m", date.getMonth() + 1, 2 ); 33337 break; 33338 case "M": 33339 output += formatName( "M", date.getMonth(), monthNamesShort, monthNames ); 33340 break; 33341 case "y": 33342 output += ( lookAhead( "y" ) ? date.getFullYear() : 33343 ( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 ); 33344 break; 33345 case "@": 33346 output += date.getTime(); 33347 break; 33348 case "!": 33349 output += date.getTime() * 10000 + this._ticksTo1970; 33350 break; 33351 case "'": 33352 if ( lookAhead( "'" ) ) { 33353 output += "'"; 33354 } else { 33355 literal = true; 33356 } 33357 break; 33358 default: 33359 output += format.charAt( iFormat ); 33360 } 33361 } 33362 } 33363 } 33364 return output; 33365 }, 33366 /* Extract all possible characters from the date format. */ 33367 _possibleChars: function( format ) { 33368 var iFormat, 33369 chars = "", 33370 literal = false, 33371 // Check whether a format character is doubled 33372 lookAhead = function( match ) { 33373 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match ); 33374 if ( matches ) { 33375 iFormat++; 33376 } 33377 return matches; 33378 }; 33379 for ( iFormat = 0; iFormat < format.length; iFormat++ ) { 33380 if ( literal ) { 33381 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) { 33382 literal = false; 33383 } else { 33384 chars += format.charAt( iFormat ); 33385 } 33386 } else { 33387 switch ( format.charAt( iFormat ) ) { 33388 case "d": case "m": case "y": case "@": 33389 chars += "0123456789"; 33390 break; 33391 case "D": case "M": 33392 return null; // Accept anything 33393 case "'": 33394 if ( lookAhead( "'" ) ) { 33395 chars += "'"; 33396 } else { 33397 literal = true; 33398 } 33399 break; 33400 default: 33401 chars += format.charAt( iFormat ); 33402 } 33403 } 33404 } 33405 return chars; 33406 }, 33407 /* Get a setting value, defaulting if necessary. */ 33408 _get: function( inst, name ) { 33409 return inst.settings[ name ] !== undefined ? 33410 inst.settings[ name ] : this._defaults[ name ]; 33411 }, 33412 /* Parse existing date and initialise date picker. */ 33413 _setDateFromField: function( inst, noDefault ) { 33414 if ( inst.input.val() === inst.lastVal ) { 33415 return; 33416 } 33417 var dateFormat = this._get( inst, "dateFormat" ), 33418 dates = inst.lastVal = inst.input ? inst.input.val() : null, 33419 defaultDate = this._getDefaultDate( inst ), 33420 date = defaultDate, 33421 settings = this._getFormatConfig( inst ); 33422 try { 33423 date = this.parseDate( dateFormat, dates, settings ) || defaultDate; 33424 } catch ( event ) { 33425 dates = ( noDefault ? "" : dates ); 33426 } 33427 inst.selectedDay = date.getDate(); 33428 inst.drawMonth = inst.selectedMonth = date.getMonth(); 33429 inst.drawYear = inst.selectedYear = date.getFullYear(); 33430 inst.currentDay = ( dates ? date.getDate() : 0 ); 33431 inst.currentMonth = ( dates ? date.getMonth() : 0 ); 33432 inst.currentYear = ( dates ? date.getFullYear() : 0 ); 33433 this._adjustInstDate( inst ); 33434 }, 33435 /* Retrieve the default date shown on opening. */ 33436 _getDefaultDate: function( inst ) { 33437 return this._restrictMinMax( inst, 33438 this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) ); 33439 }, 33440 /* A date may be specified as an exact value or a relative one. */ 33441 _determineDate: function( inst, date, defaultDate ) { 33442 var offsetNumeric = function( offset ) { 33443 var date = new Date(); 33444 date.setDate( date.getDate() + offset ); 33445 return date; 33446 }, 33447 offsetString = function( offset ) { 33448 try { 33449 return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ), 33450 offset, $.datepicker._getFormatConfig( inst ) ); 33451 } 33452 catch ( e ) { 33453 // Ignore 33454 } 33455 var date = ( offset.toLowerCase().match( /^c/ ) ? 33456 $.datepicker._getDate( inst ) : null ) || new Date(), 33457 year = date.getFullYear(), 33458 month = date.getMonth(), 33459 day = date.getDate(), 33460 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g, 33461 matches = pattern.exec( offset ); 33462 while ( matches ) { 33463 switch ( matches[ 2 ] || "d" ) { 33464 case "d" : case "D" : 33465 day += parseInt( matches[ 1 ], 10 ); break; 33466 case "w" : case "W" : 33467 day += parseInt( matches[ 1 ], 10 ) * 7; break; 33468 case "m" : case "M" : 33469 month += parseInt( matches[ 1 ], 10 ); 33470 day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) ); 33471 break; 33472 case "y": case "Y" : 33473 year += parseInt( matches[ 1 ], 10 ); 33474 day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) ); 33475 break; 33476 } 33477 matches = pattern.exec( offset ); 33478 } 33479 return new Date( year, month, day ); 33480 }, 33481 newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) : 33482 ( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) ); 33483 newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate ); 33484 if ( newDate ) { 33485 newDate.setHours( 0 ); 33486 newDate.setMinutes( 0 ); 33487 newDate.setSeconds( 0 ); 33488 newDate.setMilliseconds( 0 ); 33489 } 33490 return this._daylightSavingAdjust( newDate ); 33491 }, 33492 /* Handle switch to/from daylight saving. 33493 * Hours may be non-zero on daylight saving cut-over: 33494 * > 12 when midnight changeover, but then cannot generate 33495 * midnight datetime, so jump to 1AM, otherwise reset. 33496 * @param date (Date) the date to check 33497 * @return (Date) the corrected date 33498 */ 33499 _daylightSavingAdjust: function( date ) { 33500 if ( !date ) { 33501 return null; 33502 } 33503 date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 ); 33504 return date; 33505 }, 33506 /* Set the date(s) directly. */ 33507 _setDate: function( inst, date, noChange ) { 33508 var clear = !date, 33509 origMonth = inst.selectedMonth, 33510 origYear = inst.selectedYear, 33511 newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) ); 33512 inst.selectedDay = inst.currentDay = newDate.getDate(); 33513 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth(); 33514 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear(); 33515 if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) { 33516 this._notifyChange( inst ); 33517 } 33518 this._adjustInstDate( inst ); 33519 if ( inst.input ) { 33520 inst.input.val( clear ? "" : this._formatDate( inst ) ); 33521 } 33522 }, 33523 /* Retrieve the date(s) directly. */ 33524 _getDate: function( inst ) { 33525 var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null : 33526 this._daylightSavingAdjust( new Date( 33527 inst.currentYear, inst.currentMonth, inst.currentDay ) ) ); 33528 return startDate; 33529 }, 33530 /* Attach the onxxx handlers. These are declared statically so 33531 * they work with static code transformers like Caja. 33532 */ 33533 _attachHandlers: function( inst ) { 33534 var stepMonths = this._get( inst, "stepMonths" ), 33535 id = "#" + inst.id.replace( /\\\\/g, "\\" ); 33536 inst.dpDiv.find( "[data-handler]" ).map( function() { 33537 var handler = { 33538 prev: function() { 33539 $.datepicker._adjustDate( id, -stepMonths, "M" ); 33540 }, 33541 next: function() { 33542 $.datepicker._adjustDate( id, +stepMonths, "M" ); 33543 }, 33544 hide: function() { 33545 $.datepicker._hideDatepicker(); 33546 }, 33547 today: function() { 33548 $.datepicker._gotoToday( id ); 33549 }, 33550 selectDay: function() { 33551 $.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this ); 33552 return false; 33553 }, 33554 selectMonth: function() { 33555 $.datepicker._selectMonthYear( id, this, "M" ); 33556 return false; 33557 }, 33558 selectYear: function() { 33559 $.datepicker._selectMonthYear( id, this, "Y" ); 33560 return false; 33561 } 33562 }; 33563 $( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] ); 33564 } ); 33565 }, 33566 /* Generate the HTML for the current state of the date picker. */ 33567 _generateHTML: function( inst ) { 33568 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate, 33569 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin, 33570 monthNames, monthNamesShort, beforeShowDay, showOtherMonths, 33571 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate, 33572 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows, 33573 printDate, dRow, tbody, daySettings, otherMonth, unselectable, 33574 tempDate = new Date(), 33575 today = this._daylightSavingAdjust( 33576 new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time 33577 isRTL = this._get( inst, "isRTL" ), 33578 showButtonPanel = this._get( inst, "showButtonPanel" ), 33579 hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ), 33580 navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ), 33581 numMonths = this._getNumberOfMonths( inst ), 33582 showCurrentAtPos = this._get( inst, "showCurrentAtPos" ), 33583 stepMonths = this._get( inst, "stepMonths" ), 33584 isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ), 33585 currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) : 33586 new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ), 33587 minDate = this._getMinMaxDate( inst, "min" ), 33588 maxDate = this._getMinMaxDate( inst, "max" ),
vendor: 4,147 bytes, lines 33589-33657
33589 drawMonth = inst.drawMonth - showCurrentAtPos, 33590 drawYear = inst.drawYear; 33591 if ( drawMonth < 0 ) { 33592 drawMonth += 12; 33593 drawYear--; 33594 } 33595 if ( maxDate ) { 33596 maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(), 33597 maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) ); 33598 maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw ); 33599 while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) { 33600 drawMonth--; 33601 if ( drawMonth < 0 ) { 33602 drawMonth = 11; 33603 drawYear--; 33604 } 33605 } 33606 } 33607 inst.drawMonth = drawMonth; 33608 inst.drawYear = drawYear; 33609 prevText = this._get( inst, "prevText" ); 33610 prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText, 33611 this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ), 33612 this._getFormatConfig( inst ) ) ); 33613 prev = ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ? 33614 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" + 33615 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" : 33616 ( hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" ) ); 33617 nextText = this._get( inst, "nextText" ); 33618 nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText, 33619 this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ), 33620 this._getFormatConfig( inst ) ) ); 33621 next = ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ? 33622 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" + 33623 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" : 33624 ( hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" ) ); 33625 currentText = this._get( inst, "currentText" ); 33626 gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today ); 33627 currentText = ( !navigationAsDateFormat ? currentText : 33628 this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) ); 33629 controls = ( !inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" + 33630 this._get( inst, "closeText" ) + "</button>" : "" ); 33631 buttonPanel = ( showButtonPanel ) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + ( isRTL ? controls : "" ) + 33632 ( this._isInRange( inst, gotoDate ) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" + 33633 ">" + currentText + "</button>" : "" ) + ( isRTL ? "" : controls ) + "</div>" : ""; 33634 firstDay = parseInt( this._get( inst, "firstDay" ), 10 ); 33635 firstDay = ( isNaN( firstDay ) ? 0 : firstDay ); 33636 showWeek = this._get( inst, "showWeek" ); 33637 dayNames = this._get( inst, "dayNames" ); 33638 dayNamesMin = this._get( inst, "dayNamesMin" ); 33639 monthNames = this._get( inst, "monthNames" ); 33640 monthNamesShort = this._get( inst, "monthNamesShort" ); 33641 beforeShowDay = this._get( inst, "beforeShowDay" ); 33642 showOtherMonths = this._get( inst, "showOtherMonths" ); 33643 selectOtherMonths = this._get( inst, "selectOtherMonths" ); 33644 defaultDate = this._getDefaultDate( inst ); 33645 html = ""; 33646 for ( row = 0; row < numMonths[ 0 ]; row++ ) { 33647 group = ""; 33648 this.maxRows = 4; 33649 for ( col = 0; col < numMonths[ 1 ]; col++ ) { 33650 selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) ); 33651 cornerClass = " ui-corner-all"; 33652 calender = ""; 33653 if ( isMultiMonth ) { 33654 calender += "<div class='ui-datepicker-group"; 33655 if ( numMonths[ 1 ] > 1 ) { 33656 switch ( col ) { 33657 case 0: calender += " ui-datepicker-group-first";
vendor: 5,221 bytes, lines 33658-33735
33658 cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break; 33659 case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last"; 33660 cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break; 33661 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break; 33662 } 33663 } 33664 calender += "'>"; 33665 } 33666 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" + 33667 ( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) + 33668 ( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) + 33669 this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate, 33670 row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers 33671 "</div><table class='ui-datepicker-calendar'><thead>" + 33672 "<tr>"; 33673 thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" ); 33674 for ( dow = 0; dow < 7; dow++ ) { // days of the week 33675 day = ( dow + firstDay ) % 7; 33676 thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" + 33677 "<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>"; 33678 } 33679 calender += thead + "</tr></thead><tbody>"; 33680 daysInMonth = this._getDaysInMonth( drawYear, drawMonth ); 33681 if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) { 33682 inst.selectedDay = Math.min( inst.selectedDay, daysInMonth ); 33683 } 33684 leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7; 33685 curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate 33686 numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043) 33687 this.maxRows = numRows; 33688 printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) ); 33689 for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows 33690 calender += "<tr>"; 33691 tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" + 33692 this._get( inst, "calculateWeek" )( printDate ) + "</td>" ); 33693 for ( dow = 0; dow < 7; dow++ ) { // create date picker days 33694 daySettings = ( beforeShowDay ? 33695 beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] ); 33696 otherMonth = ( printDate.getMonth() !== drawMonth ); 33697 unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] || 33698 ( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate ); 33699 tbody += "<td class='" + 33700 ( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends 33701 ( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months 33702 ( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key 33703 ( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ? 33704 // or defaultDate is current printedDate and defaultDate is selectedDate 33705 " " + this._dayOverClass : "" ) + // highlight selected day 33706 ( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) + // highlight unselectable days 33707 ( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates 33708 ( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day 33709 ( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different) 33710 ( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "'" ) + "'" : "" ) + // cell title 33711 ( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions 33712 ( otherMonth && !showOtherMonths ? " " : // display for other months 33713 ( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" + 33714 ( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) + 33715 ( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day 33716 ( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months 33717 "' href='#'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date 33718 printDate.setDate( printDate.getDate() + 1 ); 33719 printDate = this._daylightSavingAdjust( printDate ); 33720 } 33721 calender += tbody + "</tr>"; 33722 } 33723 drawMonth++; 33724 if ( drawMonth > 11 ) { 33725 drawMonth = 0; 33726 drawYear++; 33727 } 33728 calender += "</tbody></table>" + ( isMultiMonth ? "</div>" + 33729 ( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" ); 33730 group += calender; 33731 } 33732 html += group; 33733 } 33734 html += buttonPanel; 33735 inst._keyEvent = false;
vendor: 4,316 bytes, lines 33736-33833
33736 return html; 33737 }, 33738 /* Generate the month and year header. */ 33739 _generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate, 33740 secondary, monthNames, monthNamesShort ) { 33741 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear, 33742 changeMonth = this._get( inst, "changeMonth" ), 33743 changeYear = this._get( inst, "changeYear" ), 33744 showMonthAfterYear = this._get( inst, "showMonthAfterYear" ), 33745 html = "<div class='ui-datepicker-title'>", 33746 monthHtml = ""; 33747 // Month selection 33748 if ( secondary || !changeMonth ) { 33749 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>"; 33750 } else { 33751 inMinYear = ( minDate && minDate.getFullYear() === drawYear ); 33752 inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear ); 33753 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>"; 33754 for ( month = 0; month < 12; month++ ) { 33755 if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) { 33756 monthHtml += "<option value='" + month + "'" + 33757 ( month === drawMonth ? " selected='selected'" : "" ) + 33758 ">" + monthNamesShort[ month ] + "</option>"; 33759 } 33760 } 33761 monthHtml += "</select>"; 33762 } 33763 if ( !showMonthAfterYear ) { 33764 html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? " " : "" ); 33765 } 33766 // Year selection 33767 if ( !inst.yearshtml ) { 33768 inst.yearshtml = ""; 33769 if ( secondary || !changeYear ) { 33770 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>"; 33771 } else { 33772 // determine range of years to display 33773 years = this._get( inst, "yearRange" ).split( ":" ); 33774 thisYear = new Date().getFullYear(); 33775 determineYear = function( value ) { 33776 var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) : 33777 ( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) : 33778 parseInt( value, 10 ) ) ); 33779 return ( isNaN( year ) ? thisYear : year ); 33780 }; 33781 year = determineYear( years[ 0 ] ); 33782 endYear = Math.max( year, determineYear( years[ 1 ] || "" ) ); 33783 year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year ); 33784 endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear ); 33785 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>"; 33786 for ( ; year <= endYear; year++ ) { 33787 inst.yearshtml += "<option value='" + year + "'" + 33788 ( year === drawYear ? " selected='selected'" : "" ) + 33789 ">" + year + "</option>"; 33790 } 33791 inst.yearshtml += "</select>"; 33792 html += inst.yearshtml; 33793 inst.yearshtml = null; 33794 } 33795 } 33796 html += this._get( inst, "yearSuffix" ); 33797 if ( showMonthAfterYear ) { 33798 html += ( secondary || !( changeMonth && changeYear ) ? " " : "" ) + monthHtml; 33799 } 33800 html += "</div>"; // Close datepicker_header 33801 return html; 33802 }, 33803 /* Adjust one of the date sub-fields. */ 33804 _adjustInstDate: function( inst, offset, period ) { 33805 var year = inst.selectedYear + ( period === "Y" ? offset : 0 ), 33806 month = inst.selectedMonth + ( period === "M" ? offset : 0 ), 33807 day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ), 33808 date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) ); 33809 inst.selectedDay = date.getDate(); 33810 inst.drawMonth = inst.selectedMonth = date.getMonth(); 33811 inst.drawYear = inst.selectedYear = date.getFullYear(); 33812 if ( period === "M" || period === "Y" ) { 33813 this._notifyChange( inst ); 33814 } 33815 }, 33816 /* Ensure a date is within any min/max bounds. */ 33817 _restrictMinMax: function( inst, date ) { 33818 var minDate = this._getMinMaxDate( inst, "min" ), 33819 maxDate = this._getMinMaxDate( inst, "max" ), 33820 newDate = ( minDate && date < minDate ? minDate : date ); 33821 return ( maxDate && newDate > maxDate ? maxDate : newDate ); 33822 }, 33823 /* Notify change of month/year. */ 33824 _notifyChange: function( inst ) { 33825 var onChange = this._get( inst, "onChangeMonthYear" ); 33826 if ( onChange ) { 33827 onChange.apply( ( inst.input ? inst.input[ 0 ] : null ), 33828 [ inst.selectedYear, inst.selectedMonth + 1, inst ] ); 33829 } 33830 }, 33831 /* Determine the number of months to show. */ 33832 _getNumberOfMonths: function( inst ) { 33833 var numMonths = this._get( inst, "numberOfMonths" );
vendor: 6,339 bytes, lines 33834-33980
33834 return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) ); 33835 }, 33836 /* Determine the current maximum date - ensure no time components are set. */ 33837 _getMinMaxDate: function( inst, minMax ) { 33838 return this._determineDate( inst, this._get( inst, minMax + "Date" ), null ); 33839 }, 33840 /* Find the number of days in a given month. */ 33841 _getDaysInMonth: function( year, month ) { 33842 return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate(); 33843 }, 33844 /* Find the day of the week of the first of a month. */ 33845 _getFirstDayOfMonth: function( year, month ) { 33846 return new Date( year, month, 1 ).getDay(); 33847 }, 33848 /* Determines if we should allow a "next/prev" month display change. */ 33849 _canAdjustMonth: function( inst, offset, curYear, curMonth ) { 33850 var numMonths = this._getNumberOfMonths( inst ), 33851 date = this._daylightSavingAdjust( new Date( curYear, 33852 curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) ); 33853 if ( offset < 0 ) { 33854 date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) ); 33855 } 33856 return this._isInRange( inst, date ); 33857 }, 33858 /* Is the given date in the accepted range? */ 33859 _isInRange: function( inst, date ) { 33860 var yearSplit, currentYear, 33861 minDate = this._getMinMaxDate( inst, "min" ), 33862 maxDate = this._getMinMaxDate( inst, "max" ), 33863 minYear = null, 33864 maxYear = null, 33865 years = this._get( inst, "yearRange" ); 33866 if ( years ) { 33867 yearSplit = years.split( ":" ); 33868 currentYear = new Date().getFullYear(); 33869 minYear = parseInt( yearSplit[ 0 ], 10 ); 33870 maxYear = parseInt( yearSplit[ 1 ], 10 ); 33871 if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) { 33872 minYear += currentYear; 33873 } 33874 if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) { 33875 maxYear += currentYear; 33876 } 33877 } 33878 return ( ( !minDate || date.getTime() >= minDate.getTime() ) && 33879 ( !maxDate || date.getTime() <= maxDate.getTime() ) && 33880 ( !minYear || date.getFullYear() >= minYear ) && 33881 ( !maxYear || date.getFullYear() <= maxYear ) ); 33882 }, 33883 /* Provide the configuration settings for formatting/parsing. */ 33884 _getFormatConfig: function( inst ) { 33885 var shortYearCutoff = this._get( inst, "shortYearCutoff" ); 33886 shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff : 33887 new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) ); 33888 return { shortYearCutoff: shortYearCutoff, 33889 dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ), 33890 monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) }; 33891 }, 33892 /* Format the given date for display. */ 33893 _formatDate: function( inst, day, month, year ) { 33894 if ( !day ) { 33895 inst.currentDay = inst.selectedDay; 33896 inst.currentMonth = inst.selectedMonth; 33897 inst.currentYear = inst.selectedYear; 33898 } 33899 var date = ( day ? ( typeof day === "object" ? day : 33900 this._daylightSavingAdjust( new Date( year, month, day ) ) ) : 33901 this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ); 33902 return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) ); 33903 } 33904} ); 33905/* 33906 * Bind hover events for datepicker elements. 33907 * Done via delegate so the binding only occurs once in the lifetime of the parent div. 33908 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. 33909 */ 33910function datepicker_bindHover( dpDiv ) { 33911 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a"; 33912 return dpDiv.on( "mouseout", selector, function() { 33913 $( this ).removeClass( "ui-state-hover" ); 33914 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) { 33915 $( this ).removeClass( "ui-datepicker-prev-hover" ); 33916 } 33917 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) { 33918 $( this ).removeClass( "ui-datepicker-next-hover" ); 33919 } 33920 } ) 33921 .on( "mouseover", selector, datepicker_handleMouseover ); 33922} 33923function datepicker_handleMouseover() { 33924 if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) { 33925 $( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" ); 33926 $( this ).addClass( "ui-state-hover" ); 33927 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) { 33928 $( this ).addClass( "ui-datepicker-prev-hover" ); 33929 } 33930 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) { 33931 $( this ).addClass( "ui-datepicker-next-hover" ); 33932 } 33933 } 33934} 33935/* jQuery extend now ignores nulls! */ 33936function datepicker_extendRemove( target, props ) { 33937 $.extend( target, props ); 33938 for ( var name in props ) { 33939 if ( props[ name ] == null ) { 33940 target[ name ] = props[ name ]; 33941 } 33942 } 33943 return target; 33944} 33945/* Invoke the datepicker functionality. 33946 @param options string - a command, optionally followed by additional parameters or 33947 Object - settings for attaching new datepicker functionality 33948 @return jQuery object */ 33949$.fn.datepicker = function( options ) { 33950 /* Verify an empty collection wasn't passed - Fixes #6976 */ 33951 if ( !this.length ) { 33952 return this; 33953 } 33954 /* Initialise the date picker. */ 33955 if ( !$.datepicker.initialized ) { 33956 $( document ).on( "mousedown", $.datepicker._checkExternalClick ); 33957 $.datepicker.initialized = true; 33958 } 33959 /* Append datepicker main container to body if not exist. */ 33960 if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) { 33961 $( "body" ).append( $.datepicker.dpDiv ); 33962 } 33963 var otherArgs = Array.prototype.slice.call( arguments, 1 ); 33964 if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) { 33965 return $.datepicker[ "_" + options + "Datepicker" ]. 33966 apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) ); 33967 } 33968 if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) { 33969 return $.datepicker[ "_" + options + "Datepicker" ]. 33970 apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) ); 33971 } 33972 return this.each( function() { 33973 typeof options === "string" ? 33974 $.datepicker[ "_" + options + "Datepicker" ]. 33975 apply( $.datepicker, [ this ].concat( otherArgs ) ) : 33976 $.datepicker._attachDatepicker( this, options ); 33977 } ); 33978}; 33979$.datepicker = new Datepicker(); // singleton instance 33980$.datepicker.initialized = false;
vendor: 69,710 bytes, lines 33981-36002
33981$.datepicker.uuid = new Date().getTime(); 33982$.datepicker.version = "1.12.1"; 33983var widgetsDatepicker = $.datepicker; 33984})); 33985 33986 /* Ende jqueryUI */ 33987 /* Start slick */ 33988 /* 33989 _ _ _ _ 33990 ___| (_) ___| | __ (_)___ 33991 / __| | |/ __| |/ / | / __| 33992 \__ \ | | (__| < _ | \__ \ 33993 |___/_|_|\___|_|\_(_)/ |___/ 33994 |__/ 33995 Version: 1.6.0 33996 Author: Ken Wheeler 33997 Website: http://kenwheeler.github.io 33998 Docs: http://kenwheeler.github.io/slick 33999 Repo: http://github.com/kenwheeler/slick 34000 Issues: http://github.com/kenwheeler/slick/issues 34001 */ 34002/* global window, document, define, jQuery, setInterval, clearInterval */ 34003(function(factory) { 34004 'use strict'; 34005 if (typeof define === 'function' && define.amd) { 34006 define(['jquery'], factory); 34007 } else if (typeof exports !== 'undefined') { 34008 module.exports = factory(require('jquery')); 34009 } else { 34010 factory(jQuery); 34011 } 34012}(function($) { 34013 'use strict'; 34014 var Slick = window.Slick || {}; 34015 Slick = (function() { 34016 var instanceUid = 0; 34017 function Slick(element, settings) { 34018 var _ = this, dataSettings; 34019 _.defaults = { 34020 accessibility: true, 34021 adaptiveHeight: false, 34022 appendArrows: $(element), 34023 appendDots: $(element), 34024 arrows: true, 34025 asNavFor: null, 34026 prevArrow: '<button type="button" data-role="none" class="slick-prev" aria-label="Previous" tabindex="0" role="button">Previous</button>', 34027 nextArrow: '<button type="button" data-role="none" class="slick-next" aria-label="Next" tabindex="0" role="button">Next</button>', 34028 autoplay: false, 34029 autoplaySpeed: 3000, 34030 centerMode: false, 34031 centerPadding: '50px', 34032 cssEase: 'ease', 34033 customPaging: function(slider, i) { 34034 return $('<button type="button" data-role="none" role="button" tabindex="0" />').text(i + 1); 34035 }, 34036 dots: false, 34037 dotsClass: 'slick-dots', 34038 draggable: true, 34039 easing: 'linear', 34040 edgeFriction: 0.35, 34041 fade: false, 34042 focusOnSelect: false, 34043 infinite: true, 34044 initialSlide: 0, 34045 lazyLoad: 'ondemand', 34046 mobileFirst: false, 34047 pauseOnHover: true, 34048 pauseOnFocus: true, 34049 pauseOnDotsHover: false, 34050 respondTo: 'window', 34051 responsive: null, 34052 rows: 1, 34053 rtl: false, 34054 slide: '', 34055 slidesPerRow: 1, 34056 slidesToShow: 1, 34057 slidesToScroll: 1, 34058 speed: 500, 34059 swipe: true, 34060 swipeToSlide: false, 34061 touchMove: true, 34062 touchThreshold: 5, 34063 useCSS: true, 34064 useTransform: true, 34065 variableWidth: false, 34066 vertical: false, 34067 verticalSwiping: false, 34068 waitForAnimate: true, 34069 zIndex: 1000 34070 }; 34071 _.initials = { 34072 animating: false, 34073 dragging: false, 34074 autoPlayTimer: null, 34075 currentDirection: 0, 34076 currentLeft: null, 34077 currentSlide: 0, 34078 direction: 1, 34079 $dots: null, 34080 listWidth: null, 34081 listHeight: null, 34082 loadIndex: 0, 34083 $nextArrow: null, 34084 $prevArrow: null, 34085 slideCount: null, 34086 slideWidth: null, 34087 $slideTrack: null, 34088 $slides: null, 34089 sliding: false, 34090 slideOffset: 0, 34091 swipeLeft: null, 34092 $list: null, 34093 touchObject: {}, 34094 transformsEnabled: false, 34095 unslicked: false 34096 }; 34097 $.extend(_, _.initials); 34098 _.activeBreakpoint = null; 34099 _.animType = null; 34100 _.animProp = null; 34101 _.breakpoints = []; 34102 _.breakpointSettings = []; 34103 _.cssTransitions = false; 34104 _.focussed = false; 34105 _.interrupted = false; 34106 _.hidden = 'hidden'; 34107 _.paused = true; 34108 _.positionProp = null; 34109 _.respondTo = null; 34110 _.rowCount = 1; 34111 _.shouldClick = true; 34112 _.$slider = $(element); 34113 _.$slidesCache = null; 34114 _.transformType = null; 34115 _.transitionType = null; 34116 _.visibilityChange = 'visibilitychange'; 34117 _.windowWidth = 0; 34118 _.windowTimer = null; 34119 dataSettings = $(element).data('slick') || {}; 34120 _.options = $.extend({}, _.defaults, settings, dataSettings); 34121 _.currentSlide = _.options.initialSlide; 34122 _.originalSettings = _.options; 34123 if (typeof document.mozHidden !== 'undefined') { 34124 _.hidden = 'mozHidden'; 34125 _.visibilityChange = 'mozvisibilitychange'; 34126 } else if (typeof document.webkitHidden !== 'undefined') { 34127 _.hidden = 'webkitHidden'; 34128 _.visibilityChange = 'webkitvisibilitychange'; 34129 } 34130 _.autoPlay = $.proxy(_.autoPlay, _); 34131 _.autoPlayClear = $.proxy(_.autoPlayClear, _); 34132 _.autoPlayIterator = $.proxy(_.autoPlayIterator, _); 34133 _.changeSlide = $.proxy(_.changeSlide, _); 34134 _.clickHandler = $.proxy(_.clickHandler, _); 34135 _.selectHandler = $.proxy(_.selectHandler, _); 34136 _.setPosition = $.proxy(_.setPosition, _); 34137 _.swipeHandler = $.proxy(_.swipeHandler, _); 34138 _.dragHandler = $.proxy(_.dragHandler, _); 34139 _.keyHandler = $.proxy(_.keyHandler, _); 34140 _.instanceUid = instanceUid++; 34141 // A simple way to check for HTML strings 34142 // Strict HTML recognition (must start with <) 34143 // Extracted from jQuery v1.11 source 34144 _.htmlExpr = /^(?:\s*(<[\w\W]+>)[^>]*)$/; 34145 _.registerBreakpoints(); 34146 _.init(true); 34147 } 34148 return Slick; 34149 }()); 34150 Slick.prototype.activateADA = function() { 34151 var _ = this; 34152 _.$slideTrack.find('.slick-active').attr({ 34153 'aria-hidden': 'false' 34154 }).find('a, input, button, select').attr({ 34155 'tabindex': '0' 34156 }); 34157 }; 34158 Slick.prototype.addSlide = Slick.prototype.slickAdd = function(markup, index, addBefore) { 34159 var _ = this; 34160 if (typeof(index) === 'boolean') { 34161 addBefore = index; 34162 index = null; 34163 } else if (index < 0 || (index >= _.slideCount)) { 34164 return false; 34165 } 34166 _.unload(); 34167 if (typeof(index) === 'number') { 34168 if (index === 0 && _.$slides.length === 0) { 34169 $(markup).appendTo(_.$slideTrack); 34170 } else if (addBefore) { 34171 $(markup).insertBefore(_.$slides.eq(index)); 34172 } else { 34173 $(markup).insertAfter(_.$slides.eq(index)); 34174 } 34175 } else { 34176 if (addBefore === true) { 34177 $(markup).prependTo(_.$slideTrack); 34178 } else { 34179 $(markup).appendTo(_.$slideTrack); 34180 } 34181 } 34182 _.$slides = _.$slideTrack.children(this.options.slide); 34183 _.$slideTrack.children(this.options.slide).detach(); 34184 _.$slideTrack.append(_.$slides); 34185 _.$slides.each(function(index, element) { 34186 $(element).attr('data-slick-index', index); 34187 }); 34188 _.$slidesCache = _.$slides; 34189 _.reinit(); 34190 }; 34191 Slick.prototype.animateHeight = function() { 34192 var _ = this; 34193 if (_.options.slidesToShow === 1 && _.options.adaptiveHeight === true && _.options.vertical === false) { 34194 var targetHeight = _.$slides.eq(_.currentSlide).outerHeight(true); 34195 _.$list.animate({ 34196 height: targetHeight 34197 }, _.options.speed); 34198 } 34199 }; 34200 Slick.prototype.animateSlide = function(targetLeft, callback) { 34201 var animProps = {}, 34202 _ = this; 34203 _.animateHeight(); 34204 if (_.options.rtl === true && _.options.vertical === false) { 34205 targetLeft = -targetLeft; 34206 } 34207 if (_.transformsEnabled === false) { 34208 if (_.options.vertical === false) { 34209 _.$slideTrack.animate({ 34210 left: targetLeft 34211 }, _.options.speed, _.options.easing, callback); 34212 } else { 34213 _.$slideTrack.animate({ 34214 top: targetLeft 34215 }, _.options.speed, _.options.easing, callback); 34216 } 34217 } else { 34218 if (_.cssTransitions === false) { 34219 if (_.options.rtl === true) { 34220 _.currentLeft = -(_.currentLeft); 34221 } 34222 $({ 34223 animStart: _.currentLeft 34224 }).animate({ 34225 animStart: targetLeft 34226 }, { 34227 duration: _.options.speed, 34228 easing: _.options.easing, 34229 step: function(now) { 34230 now = Math.ceil(now); 34231 if (_.options.vertical === false) { 34232 animProps[_.animType] = 'translate(' + 34233 now + 'px, 0px)'; 34234 _.$slideTrack.css(animProps); 34235 } else { 34236 animProps[_.animType] = 'translate(0px,' + 34237 now + 'px)'; 34238 _.$slideTrack.css(animProps); 34239 } 34240 }, 34241 complete: function() { 34242 if (callback) { 34243 callback.call(); 34244 } 34245 } 34246 }); 34247 } else { 34248 _.applyTransition(); 34249 targetLeft = Math.ceil(targetLeft); 34250 if (_.options.vertical === false) { 34251 animProps[_.animType] = 'translate3d(' + targetLeft + 'px, 0px, 0px)'; 34252 } else { 34253 animProps[_.animType] = 'translate3d(0px,' + targetLeft + 'px, 0px)'; 34254 } 34255 _.$slideTrack.css(animProps); 34256 if (callback) { 34257 setTimeout(function() { 34258 _.disableTransition(); 34259 callback.call(); 34260 }, _.options.speed); 34261 } 34262 } 34263 } 34264 }; 34265 Slick.prototype.getNavTarget = function() { 34266 var _ = this, 34267 asNavFor = _.options.asNavFor; 34268 if ( asNavFor && asNavFor !== null ) { 34269 asNavFor = $(asNavFor).not(_.$slider); 34270 } 34271 return asNavFor; 34272 }; 34273 Slick.prototype.asNavFor = function(index) { 34274 var _ = this, 34275 asNavFor = _.getNavTarget(); 34276 if ( asNavFor !== null && typeof asNavFor === 'object' ) { 34277 asNavFor.each(function() { 34278 var target = $(this).slick('getSlick'); 34279 if(!target.unslicked) { 34280 target.slideHandler(index, true); 34281 } 34282 }); 34283 } 34284 }; 34285 Slick.prototype.applyTransition = function(slide) { 34286 var _ = this, 34287 transition = {}; 34288 if (_.options.fade === false) { 34289 transition[_.transitionType] = _.transformType + ' ' + _.options.speed + 'ms ' + _.options.cssEase; 34290 } else { 34291 transition[_.transitionType] = 'opacity ' + _.options.speed + 'ms ' + _.options.cssEase; 34292 } 34293 if (_.options.fade === false) { 34294 _.$slideTrack.css(transition); 34295 } else { 34296 _.$slides.eq(slide).css(transition); 34297 } 34298 }; 34299 Slick.prototype.autoPlay = function() { 34300 var _ = this; 34301 _.autoPlayClear(); 34302 if ( _.slideCount > _.options.slidesToShow ) { 34303 _.autoPlayTimer = setInterval( _.autoPlayIterator, _.options.autoplaySpeed ); 34304 } 34305 }; 34306 Slick.prototype.autoPlayClear = function() { 34307 var _ = this; 34308 if (_.autoPlayTimer) { 34309 clearInterval(_.autoPlayTimer); 34310 } 34311 }; 34312 Slick.prototype.autoPlayIterator = function() { 34313 var _ = this, 34314 slideTo = _.currentSlide + _.options.slidesToScroll; 34315 if ( !_.paused && !_.interrupted && !_.focussed ) { 34316 if ( _.options.infinite === false ) { 34317 if ( _.direction === 1 && ( _.currentSlide + 1 ) === ( _.slideCount - 1 )) { 34318 _.direction = 0; 34319 } 34320 else if ( _.direction === 0 ) { 34321 slideTo = _.currentSlide - _.options.slidesToScroll; 34322 if ( _.currentSlide - 1 === 0 ) { 34323 _.direction = 1; 34324 } 34325 } 34326 } 34327 _.slideHandler( slideTo ); 34328 } 34329 }; 34330 Slick.prototype.buildArrows = function() { 34331 var _ = this; 34332 if (_.options.arrows === true ) { 34333 _.$prevArrow = $(_.options.prevArrow).addClass('slick-arrow'); 34334 _.$nextArrow = $(_.options.nextArrow).addClass('slick-arrow'); 34335 if( _.slideCount > _.options.slidesToShow ) { 34336 _.$prevArrow.removeClass('slick-hidden').removeAttr('aria-hidden tabindex'); 34337 _.$nextArrow.removeClass('slick-hidden').removeAttr('aria-hidden tabindex'); 34338 if (_.htmlExpr.test(_.options.prevArrow)) { 34339 _.$prevArrow.prependTo(_.options.appendArrows); 34340 } 34341 if (_.htmlExpr.test(_.options.nextArrow)) { 34342 _.$nextArrow.appendTo(_.options.appendArrows); 34343 } 34344 if (_.options.infinite !== true) { 34345 _.$prevArrow 34346 .addClass('slick-disabled') 34347 .attr('aria-disabled', 'true'); 34348 } 34349 } else { 34350 _.$prevArrow.add( _.$nextArrow ) 34351 .addClass('slick-hidden') 34352 .attr({ 34353 'aria-disabled': 'true', 34354 'tabindex': '-1' 34355 }); 34356 } 34357 } 34358 }; 34359 Slick.prototype.buildDots = function() { 34360 var _ = this, 34361 i, dot; 34362 if (_.options.dots === true && _.slideCount > _.options.slidesToShow) { 34363 _.$slider.addClass('slick-dotted'); 34364 dot = $('<ul />').addClass(_.options.dotsClass); 34365 for (i = 0; i <= _.getDotCount(); i += 1) { 34366 dot.append($('<li />').append(_.options.customPaging.call(this, _, i))); 34367 } 34368 _.$dots = dot.appendTo(_.options.appendDots); 34369 _.$dots.find('li').first().addClass('slick-active').attr('aria-hidden', 'false'); 34370 } 34371 }; 34372 Slick.prototype.buildOut = function() { 34373 var _ = this; 34374 _.$slides = 34375 _.$slider 34376 .children( _.options.slide + ':not(.slick-cloned)') 34377 .addClass('slick-slide'); 34378 _.slideCount = _.$slides.length; 34379 _.$slides.each(function(index, element) { 34380 $(element) 34381 .attr('data-slick-index', index) 34382 .data('originalStyling', $(element).attr('style') || ''); 34383 }); 34384 _.$slider.addClass('slick-slider'); 34385 _.$slideTrack = (_.slideCount === 0) ? 34386 $('<div class="slick-track"/>').appendTo(_.$slider) : 34387 _.$slides.wrapAll('<div class="slick-track"/>').parent(); 34388 _.$list = _.$slideTrack.wrap( 34389 '<div aria-live="polite" class="slick-list"/>').parent(); 34390 _.$slideTrack.css('opacity', 0); 34391 if (_.options.centerMode === true || _.options.swipeToSlide === true) { 34392 _.options.slidesToScroll = 1; 34393 } 34394 $('img[data-lazy]', _.$slider).not('[src]').addClass('slick-loading'); 34395 _.setupInfinite(); 34396 _.buildArrows(); 34397 _.buildDots(); 34398 _.updateDots(); 34399 _.setSlideClasses(typeof _.currentSlide === 'number' ? _.currentSlide : 0); 34400 if (_.options.draggable === true) { 34401 _.$list.addClass('draggable'); 34402 } 34403 }; 34404 Slick.prototype.buildRows = function() { 34405 var _ = this, a, b, c, newSlides, numOfSlides, originalSlides,slidesPerSection; 34406 newSlides = document.createDocumentFragment(); 34407 originalSlides = _.$slider.children(); 34408 if(_.options.rows > 1) { 34409 slidesPerSection = _.options.slidesPerRow * _.options.rows; 34410 numOfSlides = Math.ceil( 34411 originalSlides.length / slidesPerSection 34412 ); 34413 for(a = 0; a < numOfSlides; a++){ 34414 var slide = document.createElement('div'); 34415 for(b = 0; b < _.options.rows; b++) { 34416 var row = document.createElement('div'); 34417 for(c = 0; c < _.options.slidesPerRow; c++) { 34418 var target = (a * slidesPerSection + ((b * _.options.slidesPerRow) + c)); 34419 if (originalSlides.get(target)) { 34420 row.appendChild(originalSlides.get(target)); 34421 } 34422 } 34423 slide.appendChild(row); 34424 } 34425 newSlides.appendChild(slide); 34426 } 34427 _.$slider.empty().append(newSlides); 34428 _.$slider.children().children().children() 34429 .css({ 34430 'width':(100 / _.options.slidesPerRow) + '%', 34431 'display': 'inline-block' 34432 }); 34433 } 34434 }; 34435 Slick.prototype.checkResponsive = function(initial, forceUpdate) { 34436 var _ = this, 34437 breakpoint, targetBreakpoint, respondToWidth, triggerBreakpoint = false; 34438 var sliderWidth = _.$slider.width(); 34439 var windowWidth = window.innerWidth || $(window).width(); 34440 if (_.respondTo === 'window') { 34441 respondToWidth = windowWidth; 34442 } else if (_.respondTo === 'slider') { 34443 respondToWidth = sliderWidth; 34444 } else if (_.respondTo === 'min') { 34445 respondToWidth = Math.min(windowWidth, sliderWidth); 34446 } 34447 if ( _.options.responsive && 34448 _.options.responsive.length && 34449 _.options.responsive !== null) { 34450 targetBreakpoint = null; 34451 for (breakpoint in _.breakpoints) { 34452 if (_.breakpoints.hasOwnProperty(breakpoint)) { 34453 if (_.originalSettings.mobileFirst === false) { 34454 if (respondToWidth < _.breakpoints[breakpoint]) { 34455 targetBreakpoint = _.breakpoints[breakpoint]; 34456 } 34457 } else { 34458 if (respondToWidth > _.breakpoints[breakpoint]) { 34459 targetBreakpoint = _.breakpoints[breakpoint]; 34460 } 34461 } 34462 } 34463 } 34464 if (targetBreakpoint !== null) { 34465 if (_.activeBreakpoint !== null) { 34466 if (targetBreakpoint !== _.activeBreakpoint || forceUpdate) { 34467 _.activeBreakpoint = 34468 targetBreakpoint; 34469 if (_.breakpointSettings[targetBreakpoint] === 'unslick') { 34470 _.unslick(targetBreakpoint); 34471 } else { 34472 _.options = $.extend({}, _.originalSettings, 34473 _.breakpointSettings[ 34474 targetBreakpoint]); 34475 if (initial === true) { 34476 _.currentSlide = _.options.initialSlide; 34477 } 34478 _.refresh(initial); 34479 } 34480 triggerBreakpoint = targetBreakpoint; 34481 } 34482 } else { 34483 _.activeBreakpoint = targetBreakpoint; 34484 if (_.breakpointSettings[targetBreakpoint] === 'unslick') { 34485 _.unslick(targetBreakpoint); 34486 } else { 34487 _.options = $.extend({}, _.originalSettings, 34488 _.breakpointSettings[ 34489 targetBreakpoint]); 34490 if (initial === true) { 34491 _.currentSlide = _.options.initialSlide; 34492 } 34493 _.refresh(initial); 34494 } 34495 triggerBreakpoint = targetBreakpoint; 34496 } 34497 } else { 34498 if (_.activeBreakpoint !== null) { 34499 _.activeBreakpoint = null; 34500 _.options = _.originalSettings; 34501 if (initial === true) { 34502 _.currentSlide = _.options.initialSlide; 34503 } 34504 _.refresh(initial); 34505 triggerBreakpoint = targetBreakpoint; 34506 } 34507 } 34508 // only trigger breakpoints during an actual break. not on initialize. 34509 if( !initial && triggerBreakpoint !== false ) { 34510 _.$slider.trigger('breakpoint', [_, triggerBreakpoint]); 34511 } 34512 } 34513 }; 34514 Slick.prototype.changeSlide = function(event, dontAnimate) { 34515 var _ = this, 34516 $target = $(event.currentTarget), 34517 indexOffset, slideOffset, unevenOffset; 34518 // If target is a link, prevent default action. 34519 if($target.is('a')) { 34520 event.preventDefault(); 34521 } 34522 // If target is not the <li> element (ie: a child), find the <li>. 34523 if(!$target.is('li')) { 34524 $target = $target.closest('li'); 34525 } 34526 unevenOffset = (_.slideCount % _.options.slidesToScroll !== 0); 34527 indexOffset = unevenOffset ? 0 : (_.slideCount - _.currentSlide) % _.options.slidesToScroll; 34528 switch (event.data.message) { 34529 case 'previous': 34530 slideOffset = indexOffset === 0 ? _.options.slidesToScroll : _.options.slidesToShow - indexOffset; 34531 if (_.slideCount > _.options.slidesToShow) { 34532 _.slideHandler(_.currentSlide - slideOffset, false, dontAnimate); 34533 } 34534 break; 34535 case 'next': 34536 slideOffset = indexOffset === 0 ? _.options.slidesToScroll : indexOffset; 34537 if (_.slideCount > _.options.slidesToShow) { 34538 _.slideHandler(_.currentSlide + slideOffset, false, dontAnimate); 34539 } 34540 break; 34541 case 'index': 34542 var index = event.data.index === 0 ? 0 : 34543 event.data.index || $target.index() * _.options.slidesToScroll; 34544 _.slideHandler(_.checkNavigable(index), false, dontAnimate); 34545 $target.children().trigger('focus'); 34546 break; 34547 default: 34548 return; 34549 } 34550 }; 34551 Slick.prototype.checkNavigable = function(index) { 34552 var _ = this, 34553 navigables, prevNavigable; 34554 navigables = _.getNavigableIndexes(); 34555 prevNavigable = 0; 34556 if (index > navigables[navigables.length - 1]) { 34557 index = navigables[navigables.length - 1]; 34558 } else { 34559 for (var n in navigables) { 34560 if (index < navigables[n]) { 34561 index = prevNavigable; 34562 break; 34563 } 34564 prevNavigable = navigables[n]; 34565 } 34566 } 34567 return index; 34568 }; 34569 Slick.prototype.cleanUpEvents = function() { 34570 var _ = this; 34571 if (_.options.dots && _.$dots !== null) { 34572 $('li', _.$dots) 34573 .off('click.slick', _.changeSlide) 34574 .off('mouseenter.slick', $.proxy(_.interrupt, _, true)) 34575 .off('mouseleave.slick', $.proxy(_.interrupt, _, false)); 34576 } 34577 _.$slider.off('focus.slick blur.slick'); 34578 if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) { 34579 _.$prevArrow && _.$prevArrow.off('click.slick', _.changeSlide); 34580 _.$nextArrow && _.$nextArrow.off('click.slick', _.changeSlide); 34581 } 34582 _.$list.off('touchstart.slick mousedown.slick', _.swipeHandler); 34583 _.$list.off('touchmove.slick mousemove.slick', _.swipeHandler); 34584 _.$list.off('touchend.slick mouseup.slick', _.swipeHandler); 34585 _.$list.off('touchcancel.slick mouseleave.slick', _.swipeHandler); 34586 _.$list.off('click.slick', _.clickHandler); 34587 $(document).off(_.visibilityChange, _.visibility); 34588 _.cleanUpSlideEvents(); 34589 if (_.options.accessibility === true) { 34590 _.$list.off('keydown.slick', _.keyHandler); 34591 } 34592 if (_.options.focusOnSelect === true) { 34593 $(_.$slideTrack).children().off('click.slick', _.selectHandler); 34594 } 34595 $(window).off('orientationchange.slick.slick-' + _.instanceUid, _.orientationChange); 34596 $(window).off('resize.slick.slick-' + _.instanceUid, _.resize); 34597 $('[draggable!=true]', _.$slideTrack).off('dragstart', _.preventDefault); 34598 $(window).off('load.slick.slick-' + _.instanceUid, _.setPosition); 34599 $(document).off('ready.slick.slick-' + _.instanceUid, _.setPosition); 34600 }; 34601 Slick.prototype.cleanUpSlideEvents = function() { 34602 var _ = this; 34603 _.$list.off('mouseenter.slick', $.proxy(_.interrupt, _, true)); 34604 _.$list.off('mouseleave.slick', $.proxy(_.interrupt, _, false)); 34605 }; 34606 Slick.prototype.cleanUpRows = function() { 34607 var _ = this, originalSlides; 34608 if(_.options.rows > 1) { 34609 originalSlides = _.$slides.children().children(); 34610 originalSlides.removeAttr('style'); 34611 _.$slider.empty().append(originalSlides); 34612 } 34613 }; 34614 Slick.prototype.clickHandler = function(event) { 34615 var _ = this; 34616 if (_.shouldClick === false) { 34617 event.stopImmediatePropagation(); 34618 event.stopPropagation(); 34619 event.preventDefault(); 34620 } 34621 }; 34622 Slick.prototype.destroy = function(refresh) { 34623 var _ = this; 34624 _.autoPlayClear(); 34625 _.touchObject = {}; 34626 _.cleanUpEvents(); 34627 $('.slick-cloned', _.$slider).detach(); 34628 if (_.$dots) { 34629 _.$dots.remove(); 34630 } 34631 if ( _.$prevArrow && _.$prevArrow.length ) { 34632 _.$prevArrow 34633 .removeClass('slick-disabled slick-arrow slick-hidden') 34634 .removeAttr('aria-hidden aria-disabled tabindex') 34635 .css('display',''); 34636 if ( _.htmlExpr.test( _.options.prevArrow )) { 34637 _.$prevArrow.remove(); 34638 } 34639 } 34640 if ( _.$nextArrow && _.$nextArrow.length ) { 34641 _.$nextArrow 34642 .removeClass('slick-disabled slick-arrow slick-hidden') 34643 .removeAttr('aria-hidden aria-disabled tabindex') 34644 .css('display',''); 34645 if ( _.htmlExpr.test( _.options.nextArrow )) { 34646 _.$nextArrow.remove(); 34647 } 34648 } 34649 if (_.$slides) { 34650 _.$slides 34651 .removeClass('slick-slide slick-active slick-center slick-visible slick-current') 34652 .removeAttr('aria-hidden') 34653 .removeAttr('data-slick-index') 34654 .each(function(){ 34655 $(this).attr('style', $(this).data('originalStyling')); 34656 }); 34657 _.$slideTrack.children(this.options.slide).detach(); 34658 _.$slideTrack.detach(); 34659 _.$list.detach(); 34660 _.$slider.append(_.$slides); 34661 } 34662 _.cleanUpRows(); 34663 _.$slider.removeClass('slick-slider'); 34664 _.$slider.removeClass('slick-initialized'); 34665 _.$slider.removeClass('slick-dotted'); 34666 _.unslicked = true; 34667 if(!refresh) { 34668 _.$slider.trigger('destroy', [_]); 34669 } 34670 }; 34671 Slick.prototype.disableTransition = function(slide) { 34672 var _ = this, 34673 transition = {}; 34674 transition[_.transitionType] = ''; 34675 if (_.options.fade === false) { 34676 _.$slideTrack.css(transition); 34677 } else { 34678 _.$slides.eq(slide).css(transition); 34679 } 34680 }; 34681 Slick.prototype.fadeSlide = function(slideIndex, callback) { 34682 var _ = this; 34683 if (_.cssTransitions === false) { 34684 _.$slides.eq(slideIndex).css({ 34685 zIndex: _.options.zIndex 34686 }); 34687 _.$slides.eq(slideIndex).animate({ 34688 opacity: 1 34689 }, _.options.speed, _.options.easing, callback); 34690 } else { 34691 _.applyTransition(slideIndex); 34692 _.$slides.eq(slideIndex).css({ 34693 opacity: 1, 34694 zIndex: _.options.zIndex 34695 }); 34696 if (callback) { 34697 setTimeout(function() { 34698 _.disableTransition(slideIndex); 34699 callback.call(); 34700 }, _.options.speed); 34701 } 34702 } 34703 }; 34704 Slick.prototype.fadeSlideOut = function(slideIndex) { 34705 var _ = this; 34706 if (_.cssTransitions === false) { 34707 _.$slides.eq(slideIndex).animate({ 34708 opacity: 0, 34709 zIndex: _.options.zIndex - 2 34710 }, _.options.speed, _.options.easing); 34711 } else { 34712 _.applyTransition(slideIndex); 34713 _.$slides.eq(slideIndex).css({ 34714 opacity: 0, 34715 zIndex: _.options.zIndex - 2 34716 }); 34717 } 34718 }; 34719 Slick.prototype.filterSlides = Slick.prototype.slickFilter = function(filter) { 34720 var _ = this; 34721 if (filter !== null) { 34722 _.$slidesCache = _.$slides; 34723 _.unload(); 34724 _.$slideTrack.children(this.options.slide).detach(); 34725 _.$slidesCache.filter(filter).appendTo(_.$slideTrack); 34726 _.reinit(); 34727 } 34728 }; 34729 Slick.prototype.focusHandler = function() { 34730 var _ = this; 34731 _.$slider 34732 .off('focus.slick blur.slick') 34733 .on('focus.slick blur.slick', 34734 '*:not(.slick-arrow)', function(event) { 34735 event.stopImmediatePropagation(); 34736 var $sf = $(this); 34737 setTimeout(function() { 34738 if( _.options.pauseOnFocus ) { 34739 _.focussed = $sf.is(':focus'); 34740 _.autoPlay(); 34741 } 34742 }, 0); 34743 }); 34744 }; 34745 Slick.prototype.getCurrent = Slick.prototype.slickCurrentSlide = function() { 34746 var _ = this; 34747 return _.currentSlide; 34748 }; 34749 Slick.prototype.getDotCount = function() { 34750 var _ = this; 34751 var breakPoint = 0; 34752 var counter = 0; 34753 var pagerQty = 0; 34754 if (_.options.infinite === true) { 34755 while (breakPoint < _.slideCount) { 34756 ++pagerQty; 34757 breakPoint = counter + _.options.slidesToScroll; 34758 counter += _.options.slidesToScroll <= _.options.slidesToShow ? _.options.slidesToScroll : _.options.slidesToShow; 34759 } 34760 } else if (_.options.centerMode === true) { 34761 pagerQty = _.slideCount; 34762 } else if(!_.options.asNavFor) { 34763 pagerQty = 1 + Math.ceil((_.slideCount - _.options.slidesToShow) / _.options.slidesToScroll); 34764 }else { 34765 while (breakPoint < _.slideCount) { 34766 ++pagerQty; 34767 breakPoint = counter + _.options.slidesToScroll; 34768 counter += _.options.slidesToScroll <= _.options.slidesToShow ? _.options.slidesToScroll : _.options.slidesToShow; 34769 } 34770 } 34771 return pagerQty - 1; 34772 }; 34773 Slick.prototype.getLeft = function(slideIndex) { 34774 var _ = this, 34775 targetLeft, 34776 verticalHeight, 34777 verticalOffset = 0, 34778 targetSlide; 34779 _.slideOffset = 0; 34780 verticalHeight = _.$slides.first().outerHeight(true); 34781 if (_.options.infinite === true) { 34782 if (_.slideCount > _.options.slidesToShow) { 34783 _.slideOffset = (_.slideWidth * _.options.slidesToShow) * -1; 34784 verticalOffset = (verticalHeight * _.options.slidesToShow) * -1; 34785 } 34786 if (_.slideCount % _.options.slidesToScroll !== 0) { 34787 if (slideIndex + _.options.slidesToScroll > _.slideCount && _.slideCount > _.options.slidesToShow) { 34788 if (slideIndex > _.slideCount) { 34789 _.slideOffset = ((_.options.slidesToShow - (slideIndex - _.slideCount)) * _.slideWidth) * -1; 34790 verticalOffset = ((_.options.slidesToShow - (slideIndex - _.slideCount)) * verticalHeight) * -1; 34791 } else { 34792 _.slideOffset = ((_.slideCount % _.options.slidesToScroll) * _.slideWidth) * -1; 34793 verticalOffset = ((_.slideCount % _.options.slidesToScroll) * verticalHeight) * -1; 34794 } 34795 } 34796 } 34797 } else { 34798 if (slideIndex + _.options.slidesToShow > _.slideCount) { 34799 _.slideOffset = ((slideIndex + _.options.slidesToShow) - _.slideCount) * _.slideWidth; 34800 verticalOffset = ((slideIndex + _.options.slidesToShow) - _.slideCount) * verticalHeight; 34801 } 34802 } 34803 if (_.slideCount <= _.options.slidesToShow) { 34804 _.slideOffset = 0; 34805 verticalOffset = 0; 34806 } 34807 if (_.options.centerMode === true && _.options.infinite === true) { 34808 _.slideOffset += _.slideWidth * Math.floor(_.options.slidesToShow / 2) - _.slideWidth; 34809 } else if (_.options.centerMode === true) { 34810 _.slideOffset = 0; 34811 _.slideOffset += _.slideWidth * Math.floor(_.options.slidesToShow / 2); 34812 } 34813 if (_.options.vertical === false) { 34814 targetLeft = ((slideIndex * _.slideWidth) * -1) + _.slideOffset; 34815 } else { 34816 targetLeft = ((slideIndex * verticalHeight) * -1) + verticalOffset; 34817 } 34818 if (_.options.variableWidth === true) { 34819 if (_.slideCount <= _.options.slidesToShow || _.options.infinite === false) { 34820 targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex); 34821 } else { 34822 targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex + _.options.slidesToShow); 34823 } 34824 if (_.options.rtl === true) { 34825 if (targetSlide[0]) { 34826 targetLeft = (_.$slideTrack.width() - targetSlide[0].offsetLeft - targetSlide.width()) * -1; 34827 } else { 34828 targetLeft = 0; 34829 } 34830 } else { 34831 targetLeft = targetSlide[0] ? targetSlide[0].offsetLeft * -1 : 0; 34832 } 34833 if (_.options.centerMode === true) { 34834 if (_.slideCount <= _.options.slidesToShow || _.options.infinite === false) { 34835 targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex); 34836 } else { 34837 targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex + _.options.slidesToShow + 1); 34838 } 34839 if (_.options.rtl === true) { 34840 if (targetSlide[0]) { 34841 targetLeft = (_.$slideTrack.width() - targetSlide[0].offsetLeft - targetSlide.width()) * -1; 34842 } else { 34843 targetLeft = 0; 34844 } 34845 } else { 34846 targetLeft = targetSlide[0] ? targetSlide[0].offsetLeft * -1 : 0; 34847 } 34848 targetLeft += (_.$list.width() - targetSlide.outerWidth()) / 2; 34849 } 34850 } 34851 return targetLeft; 34852 }; 34853 Slick.prototype.getOption = Slick.prototype.slickGetOption = function(option) { 34854 var _ = this; 34855 return _.options[option]; 34856 }; 34857 Slick.prototype.getNavigableIndexes = function() { 34858 var _ = this, 34859 breakPoint = 0, 34860 counter = 0, 34861 indexes = [], 34862 max; 34863 if (_.options.infinite === false) { 34864 max = _.slideCount; 34865 } else { 34866 breakPoint = _.options.slidesToScroll * -1; 34867 counter = _.options.slidesToScroll * -1; 34868 max = _.slideCount * 2; 34869 } 34870 while (breakPoint < max) { 34871 indexes.push(breakPoint); 34872 breakPoint = counter + _.options.slidesToScroll; 34873 counter += _.options.slidesToScroll <= _.options.slidesToShow ? _.options.slidesToScroll : _.options.slidesToShow; 34874 } 34875 return indexes; 34876 }; 34877 Slick.prototype.getSlick = function() { 34878 return this; 34879 }; 34880 Slick.prototype.getSlideCount = function() { 34881 var _ = this, 34882 slidesTraversed, swipedSlide, centerOffset; 34883 centerOffset = _.options.centerMode === true ? _.slideWidth * Math.floor(_.options.slidesToShow / 2) : 0; 34884 if (_.options.swipeToSlide === true) { 34885 _.$slideTrack.find('.slick-slide').each(function(index, slide) { 34886 if (slide.offsetLeft - centerOffset + ($(slide).outerWidth() / 2) > (_.swipeLeft * -1)) { 34887 swipedSlide = slide; 34888 return false; 34889 } 34890 }); 34891 slidesTraversed = Math.abs($(swipedSlide).attr('data-slick-index') - _.currentSlide) || 1; 34892 return slidesTraversed; 34893 } else { 34894 return _.options.slidesToScroll; 34895 } 34896 }; 34897 Slick.prototype.goTo = Slick.prototype.slickGoTo = function(slide, dontAnimate) { 34898 var _ = this; 34899 _.changeSlide({ 34900 data: { 34901 message: 'index', 34902 index: parseInt(slide) 34903 } 34904 }, dontAnimate); 34905 }; 34906 Slick.prototype.init = function(creation) { 34907 var _ = this; 34908 if (!$(_.$slider).hasClass('slick-initialized')) { 34909 $(_.$slider).addClass('slick-initialized'); 34910 _.buildRows(); 34911 _.buildOut(); 34912 _.setProps(); 34913 _.startLoad(); 34914 _.loadSlider(); 34915 _.initializeEvents(); 34916 _.updateArrows(); 34917 _.updateDots(); 34918 _.checkResponsive(true); 34919 _.focusHandler(); 34920 } 34921 if (creation) { 34922 _.$slider.trigger('init', [_]); 34923 } 34924 if (_.options.accessibility === true) { 34925 _.initADA(); 34926 } 34927 if ( _.options.autoplay ) { 34928 _.paused = false; 34929 _.autoPlay(); 34930 } 34931 }; 34932 Slick.prototype.initADA = function() { 34933 var _ = this; 34934 _.$slides.add(_.$slideTrack.find('.slick-cloned')).attr({ 34935 'aria-hidden': 'true', 34936 'tabindex': '-1' 34937 }).find('a, input, button, select').attr({ 34938 'tabindex': '-1' 34939 }); 34940 _.$slideTrack.attr('role', 'listbox'); 34941 _.$slides.not(_.$slideTrack.find('.slick-cloned')).each(function(i) { 34942 $(this).attr({ 34943 'role': 'option', 34944 'aria-describedby': 'slick-slide' + _.instanceUid + i + '' 34945 }); 34946 }); 34947 if (_.$dots !== null) { 34948 _.$dots.attr('role', 'tablist').find('li').each(function(i) { 34949 $(this).attr({ 34950 'role': 'presentation', 34951 'aria-selected': 'false', 34952 'aria-controls': 'navigation' + _.instanceUid + i + '', 34953 'id': 'slick-slide' + _.instanceUid + i + '' 34954 }); 34955 }) 34956 .first().attr('aria-selected', 'true').end() 34957 .find('button').attr('role', 'button').end() 34958 .closest('div').attr('role', 'toolbar'); 34959 } 34960 _.activateADA(); 34961 }; 34962 Slick.prototype.initArrowEvents = function() { 34963 var _ = this; 34964 if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) { 34965 _.$prevArrow 34966 .off('click.slick') 34967 .on('click.slick', { 34968 message: 'previous' 34969 }, _.changeSlide); 34970 _.$nextArrow 34971 .off('click.slick') 34972 .on('click.slick', { 34973 message: 'next' 34974 }, _.changeSlide); 34975 } 34976 }; 34977 Slick.prototype.initDotEvents = function() { 34978 var _ = this; 34979 if (_.options.dots === true && _.slideCount > _.options.slidesToShow) { 34980 $('li', _.$dots).on('click.slick', { 34981 message: 'index' 34982 }, _.changeSlide); 34983 } 34984 if ( _.options.dots === true && _.options.pauseOnDotsHover === true ) { 34985 $('li', _.$dots) 34986 .on('mouseenter.slick', $.proxy(_.interrupt, _, true)) 34987 .on('mouseleave.slick', $.proxy(_.interrupt, _, false)); 34988 } 34989 }; 34990 Slick.prototype.initSlideEvents = function() { 34991 var _ = this; 34992 if ( _.options.pauseOnHover ) { 34993 _.$list.on('mouseenter.slick', $.proxy(_.interrupt, _, true)); 34994 _.$list.on('mouseleave.slick', $.proxy(_.interrupt, _, false)); 34995 } 34996 }; 34997 Slick.prototype.initializeEvents = function() { 34998 var _ = this; 34999 _.initArrowEvents(); 35000 _.initDotEvents(); 35001 _.initSlideEvents(); 35002 _.$list.on('touchstart.slick mousedown.slick', { 35003 action: 'start' 35004 }, _.swipeHandler); 35005 _.$list.on('touchmove.slick mousemove.slick', { 35006 action: 'move' 35007 }, _.swipeHandler); 35008 _.$list.on('touchend.slick mouseup.slick', { 35009 action: 'end' 35010 }, _.swipeHandler); 35011 _.$list.on('touchcancel.slick mouseleave.slick', { 35012 action: 'end' 35013 }, _.swipeHandler); 35014 _.$list.on('click.slick', _.clickHandler); 35015 $(document).on(_.visibilityChange, $.proxy(_.visibility, _)); 35016 if (_.options.accessibility === true) { 35017 _.$list.on('keydown.slick', _.keyHandler); 35018 } 35019 if (_.options.focusOnSelect === true) { 35020 $(_.$slideTrack).children().on('click.slick', _.selectHandler); 35021 } 35022 $(window).on('orientationchange.slick.slick-' + _.instanceUid, $.proxy(_.orientationChange, _)); 35023 $(window).on('resize.slick.slick-' + _.instanceUid, $.proxy(_.resize, _)); 35024 $('[draggable!=true]', _.$slideTrack).on('dragstart', _.preventDefault); 35025 $(window).on('load.slick.slick-' + _.instanceUid, _.setPosition); 35026 $(document).on('ready.slick.slick-' + _.instanceUid, _.setPosition); 35027 }; 35028 Slick.prototype.initUI = function() { 35029 var _ = this; 35030 if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) { 35031 _.$prevArrow.show(); 35032 _.$nextArrow.show(); 35033 } 35034 if (_.options.dots === true && _.slideCount > _.options.slidesToShow) { 35035 _.$dots.show(); 35036 } 35037 }; 35038 Slick.prototype.keyHandler = function(event) { 35039 var _ = this; 35040 //Dont slide if the cursor is inside the form fields and arrow keys are pressed 35041 if(!event.target.tagName.match('TEXTAREA|INPUT|SELECT')) { 35042 if (event.keyCode === 37 && _.options.accessibility === true) { 35043 _.changeSlide({ 35044 data: { 35045 message: _.options.rtl === true ? 'next' : 'previous' 35046 } 35047 }); 35048 } else if (event.keyCode === 39 && _.options.accessibility === true) { 35049 _.changeSlide({ 35050 data: { 35051 message: _.options.rtl === true ? 'previous' : 'next' 35052 } 35053 }); 35054 } 35055 } 35056 }; 35057 Slick.prototype.lazyLoad = function() { 35058 var _ = this, 35059 loadRange, cloneRange, rangeStart, rangeEnd; 35060 function loadImages(imagesScope) { 35061 $('img[data-lazy]', imagesScope).each(function() { 35062 var image = $(this), 35063 imageSource = $(this).attr('data-lazy'), 35064 imageToLoad = document.createElement('img'); 35065 imageToLoad.onload = function() { 35066 image 35067 .animate({ opacity: 0 }, 100, function() { 35068 image 35069 .attr('src', imageSource) 35070 .animate({ opacity: 1 }, 200, function() { 35071 image 35072 .removeAttr('data-lazy') 35073 .removeClass('slick-loading'); 35074 }); 35075 _.$slider.trigger('lazyLoaded', [_, image, imageSource]); 35076 }); 35077 }; 35078 imageToLoad.onerror = function() { 35079 image 35080 .removeAttr( 'data-lazy' ) 35081 .removeClass( 'slick-loading' ) 35082 .addClass( 'slick-lazyload-error' ); 35083 _.$slider.trigger('lazyLoadError', [ _, image, imageSource ]); 35084 }; 35085 imageToLoad.src = imageSource; 35086 }); 35087 } 35088 if (_.options.centerMode === true) { 35089 if (_.options.infinite === true) { 35090 rangeStart = _.currentSlide + (_.options.slidesToShow / 2 + 1); 35091 rangeEnd = rangeStart + _.options.slidesToShow + 2; 35092 } else { 35093 rangeStart = Math.max(0, _.currentSlide - (_.options.slidesToShow / 2 + 1)); 35094 rangeEnd = 2 + (_.options.slidesToShow / 2 + 1) + _.currentSlide; 35095 } 35096 } else { 35097 rangeStart = _.options.infinite ? _.options.slidesToShow + _.currentSlide : _.currentSlide; 35098 rangeEnd = Math.ceil(rangeStart + _.options.slidesToShow); 35099 if (_.options.fade === true) { 35100 if (rangeStart > 0) rangeStart--; 35101 if (rangeEnd <= _.slideCount) rangeEnd++; 35102 } 35103 } 35104 loadRange = _.$slider.find('.slick-slide').slice(rangeStart, rangeEnd); 35105 loadImages(loadRange); 35106 if (_.slideCount <= _.options.slidesToShow) { 35107 cloneRange = _.$slider.find('.slick-slide'); 35108 loadImages(cloneRange); 35109 } else 35110 if (_.currentSlide >= _.slideCount - _.options.slidesToShow) { 35111 cloneRange = _.$slider.find('.slick-cloned').slice(0, _.options.slidesToShow); 35112 loadImages(cloneRange); 35113 } else if (_.currentSlide === 0) { 35114 cloneRange = _.$slider.find('.slick-cloned').slice(_.options.slidesToShow * -1); 35115 loadImages(cloneRange); 35116 } 35117 }; 35118 Slick.prototype.loadSlider = function() { 35119 var _ = this; 35120 _.setPosition(); 35121 _.$slideTrack.css({ 35122 opacity: 1 35123 }); 35124 _.$slider.removeClass('slick-loading'); 35125 _.initUI(); 35126 if (_.options.lazyLoad === 'progressive') { 35127 _.progressiveLazyLoad(); 35128 } 35129 }; 35130 Slick.prototype.next = Slick.prototype.slickNext = function() { 35131 var _ = this; 35132 _.changeSlide({ 35133 data: { 35134 message: 'next' 35135 } 35136 }); 35137 }; 35138 Slick.prototype.orientationChange = function() { 35139 var _ = this; 35140 _.checkResponsive(); 35141 _.setPosition(); 35142 }; 35143 Slick.prototype.pause = Slick.prototype.slickPause = function() { 35144 var _ = this; 35145 _.autoPlayClear(); 35146 _.paused = true; 35147 }; 35148 Slick.prototype.play = Slick.prototype.slickPlay = function() { 35149 var _ = this; 35150 _.autoPlay(); 35151 _.options.autoplay = true; 35152 _.paused = false; 35153 _.focussed = false; 35154 _.interrupted = false; 35155 }; 35156 Slick.prototype.postSlide = function(index) { 35157 var _ = this; 35158 if( !_.unslicked ) { 35159 _.$slider.trigger('afterChange', [_, index]); 35160 _.animating = false; 35161 _.setPosition(); 35162 _.swipeLeft = null; 35163 if ( _.options.autoplay ) { 35164 _.autoPlay(); 35165 } 35166 if (_.options.accessibility === true) { 35167 _.initADA(); 35168 } 35169 } 35170 }; 35171 Slick.prototype.prev = Slick.prototype.slickPrev = function() { 35172 var _ = this; 35173 _.changeSlide({ 35174 data: { 35175 message: 'previous' 35176 } 35177 }); 35178 }; 35179 Slick.prototype.preventDefault = function(event) { 35180 event.preventDefault(); 35181 }; 35182 Slick.prototype.progressiveLazyLoad = function( tryCount ) { 35183 tryCount = tryCount || 1; 35184 var _ = this, 35185 $imgsToLoad = $( 'img[data-lazy]', _.$slider ), 35186 image, 35187 imageSource, 35188 imageToLoad; 35189 if ( $imgsToLoad.length ) { 35190 image = $imgsToLoad.first(); 35191 imageSource = image.attr('data-lazy'); 35192 imageToLoad = document.createElement('img'); 35193 imageToLoad.onload = function() { 35194 image 35195 .attr( 'src', imageSource ) 35196 .removeAttr('data-lazy') 35197 .removeClass('slick-loading'); 35198 if ( _.options.adaptiveHeight === true ) { 35199 _.setPosition(); 35200 } 35201 _.$slider.trigger('lazyLoaded', [ _, image, imageSource ]); 35202 _.progressiveLazyLoad(); 35203 }; 35204 imageToLoad.onerror = function() { 35205 if ( tryCount < 3 ) { 35206 /** 35207 * try to load the image 3 times, 35208 * leave a slight delay so we don't get 35209 * servers blocking the request. 35210 */ 35211 setTimeout( function() { 35212 _.progressiveLazyLoad( tryCount + 1 ); 35213 }, 500 ); 35214 } else { 35215 image 35216 .removeAttr( 'data-lazy' ) 35217 .removeClass( 'slick-loading' ) 35218 .addClass( 'slick-lazyload-error' ); 35219 _.$slider.trigger('lazyLoadError', [ _, image, imageSource ]); 35220 _.progressiveLazyLoad(); 35221 } 35222 }; 35223 imageToLoad.src = imageSource; 35224 } else { 35225 _.$slider.trigger('allImagesLoaded', [ _ ]); 35226 } 35227 }; 35228 Slick.prototype.refresh = function( initializing ) { 35229 var _ = this, currentSlide, lastVisibleIndex; 35230 lastVisibleIndex = _.slideCount - _.options.slidesToShow; 35231 // in non-infinite sliders, we don't want to go past the 35232 // last visible index. 35233 if( !_.options.infinite && ( _.currentSlide > lastVisibleIndex )) { 35234 _.currentSlide = lastVisibleIndex; 35235 } 35236 // if less slides than to show, go to start. 35237 if ( _.slideCount <= _.options.slidesToShow ) { 35238 _.currentSlide = 0; 35239 } 35240 currentSlide = _.currentSlide; 35241 _.destroy(true); 35242 $.extend(_, _.initials, { currentSlide: currentSlide }); 35243 _.init(); 35244 if( !initializing ) { 35245 _.changeSlide({ 35246 data: { 35247 message: 'index', 35248 index: currentSlide 35249 } 35250 }, false); 35251 } 35252 }; 35253 Slick.prototype.registerBreakpoints = function() { 35254 var _ = this, breakpoint, currentBreakpoint, l, 35255 responsiveSettings = _.options.responsive || null; 35256 if ( $.type(responsiveSettings) === 'array' && responsiveSettings.length ) { 35257 _.respondTo = _.options.respondTo || 'window'; 35258 for ( breakpoint in responsiveSettings ) { 35259 l = _.breakpoints.length-1; 35260 currentBreakpoint = responsiveSettings[breakpoint].breakpoint; 35261 if (responsiveSettings.hasOwnProperty(breakpoint)) { 35262 // loop through the breakpoints and cut out any existing 35263 // ones with the same breakpoint number, we don't want dupes. 35264 while( l >= 0 ) { 35265 if( _.breakpoints[l] && _.breakpoints[l] === currentBreakpoint ) { 35266 _.breakpoints.splice(l,1); 35267 } 35268 l--; 35269 } 35270 _.breakpoints.push(currentBreakpoint); 35271 _.breakpointSettings[currentBreakpoint] = responsiveSettings[breakpoint].settings; 35272 } 35273 } 35274 _.breakpoints.sort(function(a, b) { 35275 return ( _.options.mobileFirst ) ? a-b : b-a; 35276 }); 35277 } 35278 }; 35279 Slick.prototype.reinit = function() { 35280 var _ = this; 35281 _.$slides = 35282 _.$slideTrack 35283 .children(_.options.slide) 35284 .addClass('slick-slide'); 35285 _.slideCount = _.$slides.length; 35286 if (_.currentSlide >= _.slideCount && _.currentSlide !== 0) { 35287 _.currentSlide = _.currentSlide - _.options.slidesToScroll; 35288 } 35289 if (_.slideCount <= _.options.slidesToShow) { 35290 _.currentSlide = 0; 35291 } 35292 _.registerBreakpoints(); 35293 _.setProps(); 35294 _.setupInfinite(); 35295 _.buildArrows(); 35296 _.updateArrows(); 35297 _.initArrowEvents(); 35298 _.buildDots(); 35299 _.updateDots(); 35300 _.initDotEvents(); 35301 _.cleanUpSlideEvents(); 35302 _.initSlideEvents(); 35303 _.checkResponsive(false, true); 35304 if (_.options.focusOnSelect === true) { 35305 $(_.$slideTrack).children().on('click.slick', _.selectHandler); 35306 } 35307 _.setSlideClasses(typeof _.currentSlide === 'number' ? _.currentSlide : 0); 35308 _.setPosition(); 35309 _.focusHandler(); 35310 _.paused = !_.options.autoplay; 35311 _.autoPlay(); 35312 _.$slider.trigger('reInit', [_]); 35313 }; 35314 Slick.prototype.resize = function() { 35315 var _ = this; 35316 if ($(window).width() !== _.windowWidth) { 35317 clearTimeout(_.windowDelay); 35318 _.windowDelay = window.setTimeout(function() { 35319 _.windowWidth = $(window).width(); 35320 _.checkResponsive(); 35321 if( !_.unslicked ) { _.setPosition(); } 35322 }, 50); 35323 } 35324 }; 35325 Slick.prototype.removeSlide = Slick.prototype.slickRemove = function(index, removeBefore, removeAll) { 35326 var _ = this; 35327 if (typeof(index) === 'boolean') { 35328 removeBefore = index; 35329 index = removeBefore === true ? 0 : _.slideCount - 1; 35330 } else { 35331 index = removeBefore === true ? --index : index; 35332 } 35333 if (_.slideCount < 1 || index < 0 || index > _.slideCount - 1) { 35334 return false; 35335 } 35336 _.unload(); 35337 if (removeAll === true) { 35338 _.$slideTrack.children().remove(); 35339 } else { 35340 _.$slideTrack.children(this.options.slide).eq(index).remove(); 35341 } 35342 _.$slides = _.$slideTrack.children(this.options.slide); 35343 _.$slideTrack.children(this.options.slide).detach(); 35344 _.$slideTrack.append(_.$slides); 35345 _.$slidesCache = _.$slides; 35346 _.reinit(); 35347 }; 35348 Slick.prototype.setCSS = function(position) { 35349 var _ = this, 35350 positionProps = {}, 35351 x, y; 35352 if (_.options.rtl === true) { 35353 position = -position; 35354 } 35355 x = _.positionProp == 'left' ? Math.ceil(position) + 'px' : '0px'; 35356 y = _.positionProp == 'top' ? Math.ceil(position) + 'px' : '0px'; 35357 positionProps[_.positionProp] = position; 35358 if (_.transformsEnabled === false) { 35359 _.$slideTrack.css(positionProps); 35360 } else { 35361 positionProps = {}; 35362 if (_.cssTransitions === false) { 35363 positionProps[_.animType] = 'translate(' + x + ', ' + y + ')'; 35364 _.$slideTrack.css(positionProps); 35365 } else { 35366 positionProps[_.animType] = 'translate3d(' + x + ', ' + y + ', 0px)'; 35367 _.$slideTrack.css(positionProps); 35368 } 35369 } 35370 }; 35371 Slick.prototype.setDimensions = function() { 35372 var _ = this; 35373 if (_.options.vertical === false) { 35374 if (_.options.centerMode === true) { 35375 _.$list.css({ 35376 padding: ('0px ' + _.options.centerPadding) 35377 }); 35378 } 35379 } else { 35380 _.$list.height(_.$slides.first().outerHeight(true) * _.options.slidesToShow); 35381 if (_.options.centerMode === true) { 35382 _.$list.css({ 35383 padding: (_.options.centerPadding + ' 0px') 35384 }); 35385 } 35386 } 35387 _.listWidth = _.$list.width(); 35388 _.listHeight = _.$list.height(); 35389 if (_.options.vertical === false && _.options.variableWidth === false) { 35390 _.slideWidth = Math.ceil(_.listWidth / _.options.slidesToShow); 35391 _.$slideTrack.width(Math.ceil((_.slideWidth * _.$slideTrack.children('.slick-slide').length))); 35392 } else if (_.options.variableWidth === true) { 35393 _.$slideTrack.width(5000 * _.slideCount); 35394 } else { 35395 _.slideWidth = Math.ceil(_.listWidth); 35396 _.$slideTrack.height(Math.ceil((_.$slides.first().outerHeight(true) * _.$slideTrack.children('.slick-slide').length))); 35397 } 35398 var offset = _.$slides.first().outerWidth(true) - _.$slides.first().width(); 35399 if (_.options.variableWidth === false) _.$slideTrack.children('.slick-slide').width(_.slideWidth - offset); 35400 }; 35401 Slick.prototype.setFade = function() { 35402 var _ = this, 35403 targetLeft; 35404 _.$slides.each(function(index, element) { 35405 targetLeft = (_.slideWidth * index) * -1; 35406 if (_.options.rtl === true) { 35407 $(element).css({ 35408 position: 'relative', 35409 right: targetLeft, 35410 top: 0, 35411 zIndex: _.options.zIndex - 2, 35412 opacity: 0 35413 }); 35414 } else { 35415 $(element).css({ 35416 position: 'relative', 35417 left: targetLeft, 35418 top: 0, 35419 zIndex: _.options.zIndex - 2, 35420 opacity: 0 35421 }); 35422 } 35423 }); 35424 _.$slides.eq(_.currentSlide).css({ 35425 zIndex: _.options.zIndex - 1, 35426 opacity: 1 35427 }); 35428 }; 35429 Slick.prototype.setHeight = function() { 35430 var _ = this; 35431 if (_.options.slidesToShow === 1 && _.options.adaptiveHeight === true && _.options.vertical === false) { 35432 var targetHeight = _.$slides.eq(_.currentSlide).outerHeight(true); 35433 _.$list.css('height', targetHeight); 35434 } 35435 }; 35436 Slick.prototype.setOption = 35437 Slick.prototype.slickSetOption = function() { 35438 /** 35439 * accepts arguments in format of: 35440 * 35441 * - for changing a single option's value: 35442 * .slick("setOption", option, value, refresh ) 35443 * 35444 * - for changing a set of responsive options: 35445 * .slick("setOption", 'responsive', [{}, ...], refresh ) 35446 * 35447 * - for updating multiple values at once (not responsive) 35448 * .slick("setOption", { 'option': value, ... }, refresh ) 35449 */ 35450 var _ = this, l, item, option, value, refresh = false, type; 35451 if( $.type( arguments[0] ) === 'object' ) { 35452 option = arguments[0]; 35453 refresh = arguments[1]; 35454 type = 'multiple'; 35455 } else if ( $.type( arguments[0] ) === 'string' ) { 35456 option = arguments[0]; 35457 value = arguments[1]; 35458 refresh = arguments[2]; 35459 if ( arguments[0] === 'responsive' && $.type( arguments[1] ) === 'array' ) { 35460 type = 'responsive'; 35461 } else if ( typeof arguments[1] !== 'undefined' ) { 35462 type = 'single'; 35463 } 35464 } 35465 if ( type === 'single' ) { 35466 _.options[option] = value; 35467 } else if ( type === 'multiple' ) { 35468 $.each( option , function( opt, val ) { 35469 _.options[opt] = val; 35470 }); 35471 } else if ( type === 'responsive' ) { 35472 for ( item in value ) { 35473 if( $.type( _.options.responsive ) !== 'array' ) { 35474 _.options.responsive = [ value[item] ]; 35475 } else { 35476 l = _.options.responsive.length-1; 35477 // loop through the responsive object and splice out duplicates. 35478 while( l >= 0 ) { 35479 if( _.options.responsive[l].breakpoint === value[item].breakpoint ) { 35480 _.options.responsive.splice(l,1); 35481 } 35482 l--; 35483 } 35484 _.options.responsive.push( value[item] ); 35485 } 35486 } 35487 } 35488 if ( refresh ) { 35489 _.unload(); 35490 _.reinit(); 35491 } 35492 }; 35493 Slick.prototype.setPosition = function() { 35494 var _ = this; 35495 _.setDimensions(); 35496 _.setHeight(); 35497 if (_.options.fade === false) { 35498 _.setCSS(_.getLeft(_.currentSlide)); 35499 } else { 35500 _.setFade(); 35501 } 35502 _.$slider.trigger('setPosition', [_]); 35503 }; 35504 Slick.prototype.setProps = function() { 35505 var _ = this, 35506 bodyStyle = document.body.style; 35507 _.positionProp = _.options.vertical === true ? 'top' : 'left'; 35508 if (_.positionProp === 'top') { 35509 _.$slider.addClass('slick-vertical'); 35510 } else { 35511 _.$slider.removeClass('slick-vertical'); 35512 } 35513 if (bodyStyle.WebkitTransition !== undefined || 35514 bodyStyle.MozTransition !== undefined || 35515 bodyStyle.msTransition !== undefined) { 35516 if (_.options.useCSS === true) { 35517 _.cssTransitions = true; 35518 } 35519 } 35520 if ( _.options.fade ) { 35521 if ( typeof _.options.zIndex === 'number' ) { 35522 if( _.options.zIndex < 3 ) { 35523 _.options.zIndex = 3; 35524 } 35525 } else { 35526 _.options.zIndex = _.defaults.zIndex; 35527 } 35528 } 35529 if (bodyStyle.OTransform !== undefined) { 35530 _.animType = 'OTransform'; 35531 _.transformType = '-o-transform'; 35532 _.transitionType = 'OTransition'; 35533 if (bodyStyle.perspectiveProperty === undefined && bodyStyle.webkitPerspective === undefined) _.animType = false; 35534 } 35535 if (bodyStyle.MozTransform !== undefined) { 35536 _.animType = 'MozTransform'; 35537 _.transformType = '-moz-transform'; 35538 _.transitionType = 'MozTransition'; 35539 if (bodyStyle.perspectiveProperty === undefined && bodyStyle.MozPerspective === undefined) _.animType = false; 35540 } 35541 if (bodyStyle.webkitTransform !== undefined) { 35542 _.animType = 'webkitTransform'; 35543 _.transformType = '-webkit-transform'; 35544 _.transitionType = 'webkitTransition'; 35545 if (bodyStyle.perspectiveProperty === undefined && bodyStyle.webkitPerspective === undefined) _.animType = false; 35546 } 35547 if (bodyStyle.msTransform !== undefined) { 35548 _.animType = 'msTransform'; 35549 _.transformType = '-ms-transform'; 35550 _.transitionType = 'msTransition'; 35551 if (bodyStyle.msTransform === undefined) _.animType = false; 35552 } 35553 if (bodyStyle.transform !== undefined && _.animType !== false) { 35554 _.animType = 'transform'; 35555 _.transformType = 'transform'; 35556 _.transitionType = 'transition'; 35557 } 35558 _.transformsEnabled = _.options.useTransform && (_.animType !== null && _.animType !== false); 35559 }; 35560 Slick.prototype.setSlideClasses = function(index) { 35561 var _ = this, 35562 centerOffset, allSlides, indexOffset, remainder; 35563 allSlides = _.$slider 35564 .find('.slick-slide') 35565 .removeClass('slick-active slick-center slick-current') 35566 .attr('aria-hidden', 'true'); 35567 _.$slides 35568 .eq(index) 35569 .addClass('slick-current'); 35570 if (_.options.centerMode === true) { 35571 centerOffset = Math.floor(_.options.slidesToShow / 2); 35572 if (_.options.infinite === true) { 35573 if (index >= centerOffset && index <= (_.slideCount - 1) - centerOffset) { 35574 _.$slides 35575 .slice(index - centerOffset, index + centerOffset + 1) 35576 .addClass('slick-active') 35577 .attr('aria-hidden', 'false'); 35578 } else { 35579 indexOffset = _.options.slidesToShow + index; 35580 allSlides 35581 .slice(indexOffset - centerOffset + 1, indexOffset + centerOffset + 2) 35582 .addClass('slick-active') 35583 .attr('aria-hidden', 'false'); 35584 } 35585 if (index === 0) { 35586 allSlides 35587 .eq(allSlides.length - 1 - _.options.slidesToShow) 35588 .addClass('slick-center'); 35589 } else if (index === _.slideCount - 1) { 35590 allSlides 35591 .eq(_.options.slidesToShow) 35592 .addClass('slick-center'); 35593 } 35594 } 35595 _.$slides 35596 .eq(index) 35597 .addClass('slick-center'); 35598 } else { 35599 if (index >= 0 && index <= (_.slideCount - _.options.slidesToShow)) { 35600 _.$slides 35601 .slice(index, index + _.options.slidesToShow) 35602 .addClass('slick-active') 35603 .attr('aria-hidden', 'false'); 35604 } else if (allSlides.length <= _.options.slidesToShow) { 35605 allSlides 35606 .addClass('slick-active') 35607 .attr('aria-hidden', 'false'); 35608 } else { 35609 remainder = _.slideCount % _.options.slidesToShow; 35610 indexOffset = _.options.infinite === true ? _.options.slidesToShow + index : index; 35611 if (_.options.slidesToShow == _.options.slidesToScroll && (_.slideCount - index) < _.options.slidesToShow) { 35612 allSlides 35613 .slice(indexOffset - (_.options.slidesToShow - remainder), indexOffset + remainder) 35614 .addClass('slick-active') 35615 .attr('aria-hidden', 'false'); 35616 } else { 35617 allSlides 35618 .slice(indexOffset, indexOffset + _.options.slidesToShow) 35619 .addClass('slick-active') 35620 .attr('aria-hidden', 'false'); 35621 } 35622 } 35623 } 35624 if (_.options.lazyLoad === 'ondemand') { 35625 _.lazyLoad(); 35626 } 35627 }; 35628 Slick.prototype.setupInfinite = function() { 35629 var _ = this, 35630 i, slideIndex, infiniteCount; 35631 if (_.options.fade === true) { 35632 _.options.centerMode = false; 35633 } 35634 if (_.options.infinite === true && _.options.fade === false) { 35635 slideIndex = null; 35636 if (_.slideCount > _.options.slidesToShow) { 35637 if (_.options.centerMode === true) { 35638 infiniteCount = _.options.slidesToShow + 1; 35639 } else { 35640 infiniteCount = _.options.slidesToShow; 35641 } 35642 for (i = _.slideCount; i > (_.slideCount - 35643 infiniteCount); i -= 1) { 35644 slideIndex = i - 1; 35645 $(_.$slides[slideIndex]).clone(true).attr('id', '') 35646 .attr('data-slick-index', slideIndex - _.slideCount) 35647 .prependTo(_.$slideTrack).addClass('slick-cloned'); 35648 } 35649 for (i = 0; i < infiniteCount; i += 1) { 35650 slideIndex = i; 35651 $(_.$slides[slideIndex]).clone(true).attr('id', '') 35652 .attr('data-slick-index', slideIndex + _.slideCount) 35653 .appendTo(_.$slideTrack).addClass('slick-cloned'); 35654 } 35655 _.$slideTrack.find('.slick-cloned').find('[id]').each(function() { 35656 $(this).attr('id', ''); 35657 }); 35658 } 35659 } 35660 }; 35661 Slick.prototype.interrupt = function( toggle ) { 35662 var _ = this; 35663 if( !toggle ) { 35664 _.autoPlay(); 35665 } 35666 _.interrupted = toggle; 35667 }; 35668 Slick.prototype.selectHandler = function(event) { 35669 var _ = this; 35670 var targetElement = 35671 $(event.target).is('.slick-slide') ? 35672 $(event.target) : 35673 $(event.target).parents('.slick-slide'); 35674 var index = parseInt(targetElement.attr('data-slick-index')); 35675 if (!index) index = 0; 35676 if (_.slideCount <= _.options.slidesToShow) { 35677 _.setSlideClasses(index); 35678 _.asNavFor(index); 35679 return; 35680 } 35681 _.slideHandler(index); 35682 }; 35683 Slick.prototype.slideHandler = function(index, sync, dontAnimate) { 35684 var targetSlide, animSlide, oldSlide, slideLeft, targetLeft = null, 35685 _ = this, navTarget; 35686 sync = sync || false; 35687 if (_.animating === true && _.options.waitForAnimate === true) { 35688 return; 35689 } 35690 if (_.options.fade === true && _.currentSlide === index) { 35691 return; 35692 } 35693 if (_.slideCount <= _.options.slidesToShow) { 35694 return; 35695 } 35696 if (sync === false) { 35697 _.asNavFor(index); 35698 } 35699 targetSlide = index; 35700 targetLeft = _.getLeft(targetSlide); 35701 slideLeft = _.getLeft(_.currentSlide); 35702 _.currentLeft = _.swipeLeft === null ? slideLeft : _.swipeLeft; 35703 if (_.options.infinite === false && _.options.centerMode === false && (index < 0 || index > _.getDotCount() * _.options.slidesToScroll)) { 35704 if (_.options.fade === false) { 35705 targetSlide = _.currentSlide; 35706 if (dontAnimate !== true) { 35707 _.animateSlide(slideLeft, function() { 35708 _.postSlide(targetSlide); 35709 }); 35710 } else { 35711 _.postSlide(targetSlide); 35712 } 35713 } 35714 return; 35715 } else if (_.options.infinite === false && _.options.centerMode === true && (index < 0 || index > (_.slideCount - _.options.slidesToScroll))) { 35716 if (_.options.fade === false) { 35717 targetSlide = _.currentSlide; 35718 if (dontAnimate !== true) { 35719 _.animateSlide(slideLeft, function() { 35720 _.postSlide(targetSlide); 35721 }); 35722 } else { 35723 _.postSlide(targetSlide); 35724 } 35725 } 35726 return; 35727 } 35728 if ( _.options.autoplay ) { 35729 clearInterval(_.autoPlayTimer); 35730 } 35731 if (targetSlide < 0) { 35732 if (_.slideCount % _.options.slidesToScroll !== 0) { 35733 animSlide = _.slideCount - (_.slideCount % _.options.slidesToScroll); 35734 } else { 35735 animSlide = _.slideCount + targetSlide; 35736 } 35737 } else if (targetSlide >= _.slideCount) { 35738 if (_.slideCount % _.options.slidesToScroll !== 0) { 35739 animSlide = 0; 35740 } else { 35741 animSlide = targetSlide - _.slideCount; 35742 } 35743 } else { 35744 animSlide = targetSlide; 35745 } 35746 _.animating = true; 35747 _.$slider.trigger('beforeChange', [_, _.currentSlide, animSlide]); 35748 oldSlide = _.currentSlide; 35749 _.currentSlide = animSlide; 35750 _.setSlideClasses(_.currentSlide); 35751 if ( _.options.asNavFor ) { 35752 navTarget = _.getNavTarget(); 35753 navTarget = navTarget.slick('getSlick'); 35754 if ( navTarget.slideCount <= navTarget.options.slidesToShow ) { 35755 navTarget.setSlideClasses(_.currentSlide); 35756 } 35757 } 35758 _.updateDots(); 35759 _.updateArrows(); 35760 if (_.options.fade === true) { 35761 if (dontAnimate !== true) { 35762 _.fadeSlideOut(oldSlide); 35763 _.fadeSlide(animSlide, function() { 35764 _.postSlide(animSlide); 35765 }); 35766 } else { 35767 _.postSlide(animSlide); 35768 } 35769 _.animateHeight(); 35770 return; 35771 } 35772 if (dontAnimate !== true) { 35773 _.animateSlide(targetLeft, function() { 35774 _.postSlide(animSlide); 35775 }); 35776 } else { 35777 _.postSlide(animSlide); 35778 } 35779 }; 35780 Slick.prototype.startLoad = function() { 35781 var _ = this; 35782 if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) { 35783 _.$prevArrow.hide(); 35784 _.$nextArrow.hide(); 35785 } 35786 if (_.options.dots === true && _.slideCount > _.options.slidesToShow) { 35787 _.$dots.hide(); 35788 } 35789 _.$slider.addClass('slick-loading'); 35790 }; 35791 Slick.prototype.swipeDirection = function() { 35792 var xDist, yDist, r, swipeAngle, _ = this; 35793 xDist = _.touchObject.startX - _.touchObject.curX; 35794 yDist = _.touchObject.startY - _.touchObject.curY; 35795 r = Math.atan2(yDist, xDist); 35796 swipeAngle = Math.round(r * 180 / Math.PI); 35797 if (swipeAngle < 0) { 35798 swipeAngle = 360 - Math.abs(swipeAngle); 35799 } 35800 if ((swipeAngle <= 45) && (swipeAngle >= 0)) { 35801 return (_.options.rtl === false ? 'left' : 'right'); 35802 } 35803 if ((swipeAngle <= 360) && (swipeAngle >= 315)) { 35804 return (_.options.rtl === false ? 'left' : 'right'); 35805 } 35806 if ((swipeAngle >= 135) && (swipeAngle <= 225)) { 35807 return (_.options.rtl === false ? 'right' : 'left'); 35808 } 35809 if (_.options.verticalSwiping === true) { 35810 if ((swipeAngle >= 35) && (swipeAngle <= 135)) { 35811 return 'down'; 35812 } else { 35813 return 'up'; 35814 } 35815 } 35816 return 'vertical'; 35817 }; 35818 Slick.prototype.swipeEnd = function(event) { 35819 var _ = this, 35820 slideCount, 35821 direction; 35822 _.dragging = false; 35823 _.interrupted = false; 35824 _.shouldClick = ( _.touchObject.swipeLength > 10 ) ? false : true; 35825 if ( _.touchObject.curX === undefined ) { 35826 return false; 35827 } 35828 if ( _.touchObject.edgeHit === true ) { 35829 _.$slider.trigger('edge', [_, _.swipeDirection() ]); 35830 } 35831 if ( _.touchObject.swipeLength >= _.touchObject.minSwipe ) { 35832 direction = _.swipeDirection(); 35833 switch ( direction ) { 35834 case 'left': 35835 case 'down': 35836 slideCount = 35837 _.options.swipeToSlide ? 35838 _.checkNavigable( _.currentSlide + _.getSlideCount() ) : 35839 _.currentSlide + _.getSlideCount(); 35840 _.currentDirection = 0; 35841 break; 35842 case 'right': 35843 case 'up': 35844 slideCount = 35845 _.options.swipeToSlide ? 35846 _.checkNavigable( _.currentSlide - _.getSlideCount() ) : 35847 _.currentSlide - _.getSlideCount(); 35848 _.currentDirection = 1; 35849 break; 35850 default: 35851 } 35852 if( direction != 'vertical' ) { 35853 _.slideHandler( slideCount ); 35854 _.touchObject = {}; 35855 _.$slider.trigger('swipe', [_, direction ]); 35856 } 35857 } else { 35858 if ( _.touchObject.startX !== _.touchObject.curX ) { 35859 _.slideHandler( _.currentSlide ); 35860 _.touchObject = {}; 35861 } 35862 } 35863 }; 35864 Slick.prototype.swipeHandler = function(event) { 35865 var _ = this; 35866 if ((_.options.swipe === false) || ('ontouchend' in document && _.options.swipe === false)) { 35867 return; 35868 } else if (_.options.draggable === false && event.type.indexOf('mouse') !== -1) { 35869 return; 35870 } 35871 _.touchObject.fingerCount = event.originalEvent && event.originalEvent.touches !== undefined ? 35872 event.originalEvent.touches.length : 1; 35873 _.touchObject.minSwipe = _.listWidth / _.options 35874 .touchThreshold; 35875 if (_.options.verticalSwiping === true) { 35876 _.touchObject.minSwipe = _.listHeight / _.options 35877 .touchThreshold; 35878 } 35879 switch (event.data.action) { 35880 case 'start': 35881 _.swipeStart(event); 35882 break; 35883 case 'move': 35884 _.swipeMove(event); 35885 break; 35886 case 'end': 35887 _.swipeEnd(event); 35888 break; 35889 } 35890 }; 35891 Slick.prototype.swipeMove = function(event) { 35892 var _ = this, 35893 edgeWasHit = false, 35894 curLeft, swipeDirection, swipeLength, positionOffset, touches; 35895 touches = event.originalEvent !== undefined ? event.originalEvent.touches : null; 35896 if (!_.dragging || touches && touches.length !== 1) { 35897 return false; 35898 } 35899 curLeft = _.getLeft(_.currentSlide); 35900 _.touchObject.curX = touches !== undefined ? touches[0].pageX : event.clientX; 35901 _.touchObject.curY = touches !== undefined ? touches[0].pageY : event.clientY; 35902 _.touchObject.swipeLength = Math.round(Math.sqrt( 35903 Math.pow(_.touchObject.curX - _.touchObject.startX, 2))); 35904 if (_.options.verticalSwiping === true) { 35905 _.touchObject.swipeLength = Math.round(Math.sqrt( 35906 Math.pow(_.touchObject.curY - _.touchObject.startY, 2))); 35907 } 35908 swipeDirection = _.swipeDirection(); 35909 if (swipeDirection === 'vertical') { 35910 return; 35911 } 35912 if (event.originalEvent !== undefined && _.touchObject.swipeLength > 4) { 35913 event.preventDefault(); 35914 } 35915 positionOffset = (_.options.rtl === false ? 1 : -1) * (_.touchObject.curX > _.touchObject.startX ? 1 : -1); 35916 if (_.options.verticalSwiping === true) { 35917 positionOffset = _.touchObject.curY > _.touchObject.startY ? 1 : -1; 35918 } 35919 swipeLength = _.touchObject.swipeLength; 35920 _.touchObject.edgeHit = false; 35921 if (_.options.infinite === false) { 35922 if ((_.currentSlide === 0 && swipeDirection === 'right') || (_.currentSlide >= _.getDotCount() && swipeDirection === 'left')) { 35923 swipeLength = _.touchObject.swipeLength * _.options.edgeFriction; 35924 _.touchObject.edgeHit = true; 35925 } 35926 } 35927 if (_.options.vertical === false) { 35928 _.swipeLeft = curLeft + swipeLength * positionOffset; 35929 } else { 35930 _.swipeLeft = curLeft + (swipeLength * (_.$list.height() / _.listWidth)) * positionOffset; 35931 } 35932 if (_.options.verticalSwiping === true) { 35933 _.swipeLeft = curLeft + swipeLength * positionOffset; 35934 } 35935 if (_.options.fade === true || _.options.touchMove === false) { 35936 return false; 35937 } 35938 if (_.animating === true) { 35939 _.swipeLeft = null; 35940 return false; 35941 } 35942 _.setCSS(_.swipeLeft); 35943 }; 35944 Slick.prototype.swipeStart = function(event) { 35945 var _ = this, 35946 touches; 35947 _.interrupted = true; 35948 if (_.touchObject.fingerCount !== 1 || _.slideCount <= _.options.slidesToShow) { 35949 _.touchObject = {}; 35950 return false; 35951 } 35952 if (event.originalEvent !== undefined && event.originalEvent.touches !== undefined) { 35953 touches = event.originalEvent.touches[0]; 35954 } 35955 _.touchObject.startX = _.touchObject.curX = touches !== undefined ? touches.pageX : event.clientX; 35956 _.touchObject.startY = _.touchObject.curY = touches !== undefined ? touches.pageY : event.clientY; 35957 _.dragging = true; 35958 }; 35959 Slick.prototype.unfilterSlides = Slick.prototype.slickUnfilter = function() { 35960 var _ = this; 35961 if (_.$slidesCache !== null) { 35962 _.unload(); 35963 _.$slideTrack.children(this.options.slide).detach(); 35964 _.$slidesCache.appendTo(_.$slideTrack); 35965 _.reinit(); 35966 } 35967 }; 35968 Slick.prototype.unload = function() { 35969 var _ = this; 35970 $('.slick-cloned', _.$slider).remove(); 35971 if (_.$dots) { 35972 _.$dots.remove(); 35973 } 35974 if (_.$prevArrow && _.htmlExpr.test(_.options.prevArrow)) { 35975 _.$prevArrow.remove(); 35976 } 35977 if (_.$nextArrow && _.htmlExpr.test(_.options.nextArrow)) { 35978 _.$nextArrow.remove(); 35979 } 35980 _.$slides 35981 .removeClass('slick-slide slick-active slick-visible slick-current') 35982 .attr('aria-hidden', 'true') 35983 .css('width', ''); 35984 }; 35985 Slick.prototype.unslick = function(fromBreakpoint) { 35986 var _ = this; 35987 _.$slider.trigger('unslick', [_, fromBreakpoint]); 35988 _.destroy(); 35989 }; 35990 Slick.prototype.updateArrows = function() { 35991 var _ = this, 35992 centerOffset; 35993 centerOffset = Math.floor(_.options.slidesToShow / 2); 35994 if ( _.options.arrows === true && 35995 _.slideCount > _.options.slidesToShow && 35996 !_.options.infinite ) { 35997 _.$prevArrow.removeClass('slick-disabled').attr('aria-disabled', 'false'); 35998 _.$nextArrow.removeClass('slick-disabled').attr('aria-disabled', 'false'); 35999 if (_.currentSlide === 0) { 36000 _.$prevArrow.addClass('slick-disabled').attr('aria-disabled', 'true'); 36001 _.$nextArrow.removeClass('slick-disabled').attr('aria-disabled', 'false'); 36002 } else if (_.currentSlide >
36002= _.slideCount - _.options.slidesToShow && _.options.centerMode === false) { 36003 _.$nextArrow.addClass('slick-disabled').attr('aria-disabled', 'true'); 36004 _.$prevArrow.removeClass('slick-disabled').attr('aria-disabled', 'false'); 36005 } else if (_.currentSlide >= _.slideCount - 1 && _.options.centerMode === true) { 36006 _.$nextArrow.addClass('slick-disabled').attr('aria-disabled', 'true'); 36007 _.$prevArrow.removeClass('slick-disabled').attr('aria-disabled', 'false'); 36008 } 36009 } 36010 }; 36011 Slick.prototype.updateDots = function() { 36012 var _ = this; 36013 if (_.$dots !== null) { 36014 _.$dots 36015 .find('li') 36016 .removeClass('slick-active') 36017 .attr('aria-hidden', 'true'); 36018 _.$dots 36019 .find('li') 36020 .eq(Math.floor(_.currentSlide / _.options.slidesToScroll)) 36021 .addClass('slick-active') 36022 .attr('aria-hidden', 'false'); 36023 } 36024 }; 36025 Slick.prototype.visibility = function() { 36026 var _ = this; 36027 if ( _.options.autoplay ) { 36028 if ( document[_.hidden] ) { 36029 _.interrupted = true; 36030 } else { 36031 _.interrupted = false; 36032 } 36033 } 36034 }; 36035 $.fn.slick = function() { 36036 var _ = this, 36037 opt = arguments[0], 36038 args = Array.prototype.slice.call(arguments, 1), 36039 l = _.length, 36040 i, 36041 ret; 36042 for (i = 0; i < l; i++) { 36043 if (typeof opt == 'object' || typeof opt == 'undefined') 36044 _[i].slick = new Slick(_[i], opt); 36045 else 36046 ret = _[i].slick[opt].apply(_[i].slick, args); 36047 if (typeof ret != 'undefined') return ret; 36048 } 36049 return _; 36050 }; 36051})); 36052 36053 /* Ende slick */ 36054 /* Start jquery.magnific-popup */ 36055 /*! Magnific Popup - v0.9.9 - 2013-12-27 36056* http://dimsemenov.com/plugins/magnific-popup/ 36057* Copyright (c) 2013 Dmitry Semenov; */ 36058;(function($) { 36059 36060/*>>core*/ 36061/** 36062 * 36063 * Magnific Popup Core JS file 36064 * 36065 */ 36066 36067/** 36068 * Private static constants 36069 */ 36070var CLOSE_EVENT = 'Close', 36071 BEFORE_CLOSE_EVENT = 'BeforeClose', 36072 AFTER_CLOSE_EVENT = 'AfterClose', 36073 BEFORE_APPEND_EVENT = 'BeforeAppend', 36074 MARKUP_PARSE_EVENT = 'MarkupParse', 36075 OPEN_EVENT = 'Open', 36076 CHANGE_EVENT = 'Change', 36077 NS = 'mfp', 36078 EVENT_NS = '.' + NS, 36079 READY_CLASS = 'mfp-ready', 36080 REMOVING_CLASS = 'mfp-removing', 36081 PREVENT_CLOSE_CLASS = 'mfp-prevent-close'; 36082 36083/** 36084 * Private vars 36085 */ 36086var mfp, // As we have only one instance of MagnificPopup object, we define it locally to not to use 'this' 36087 MagnificPopup = function(){}, 36088 _isJQ = !!(window.jQuery), 36089 _prevStatus, 36090 _window = $(window), 36091 _body, 36092 _document, 36093 _prevContentType, 36094 _wrapClasses, 36095 _currPopupType; 36096 36097/** 36098 * Private functions 36099 */ 36100var _mfpOn = function(name, f) { 36101 mfp.ev.on(NS + name + EVENT_NS, f); 36102 }, 36103 _getEl = function(className, appendTo, html, raw) { 36104 var el = document.createElement('div'); 36105 el.className = 'mfp-'+className; 36106 if(html) { 36107 el.innerHTML = html; 36108 } 36109 if(!raw) { 36110 el = $(el); 36111 if(appendTo) { 36112 el.appendTo(appendTo); 36113 } 36114 } else if(appendTo) { 36115 appendTo.appendChild(el); 36116 } 36117 return el; 36118 }, 36119 _mfpTrigger = function(e, data) { 36120 mfp.ev.triggerHandler(NS + e, data); 36121 36122 if(mfp.st.callbacks) { 36123 // converts "mfpEventName" to "eventName" callback and triggers it if it's present 36124 e = e.charAt(0).toLowerCase() + e.slice(1); 36125 if(mfp.st.callbacks[e]) { 36126 mfp.st.callbacks[e].apply(mfp, $.isArray(data) ? data : [data]); 36127 } 36128 } 36129 }, 36130 _getCloseBtn = function(type) { 36131 if(type !== _currPopupType || !mfp.currTemplate.closeBtn) { 36132 mfp.currTemplate.closeBtn = $( mfp.st.closeMarkup.replace('%title%', mfp.st.tClose ) ); 36133 _currPopupType = type; 36134 } 36135 return mfp.currTemplate.closeBtn; 36136 }, 36137 // Initialize Magnific Popup only when called at least once 36138 _checkInstance = function() { 36139 if(!$.magnificPopup.instance) { 36140 mfp = new MagnificPopup(); 36141 mfp.init(); 36142 $.magnificPopup.instance = mfp; 36143 } 36144 }, 36145 // CSS transition detection, http://stackoverflow.com/questions/7264899/detect-css-transitions-using-javascript-and-without-modernizr 36146 supportsTransitions = function() { 36147 var s = document.createElement('p').style, // 's' for style. better to create an element if body yet to exist 36148 v = ['ms','O','Moz','Webkit']; // 'v' for vendor 36149 36150 if( s['transition'] !== undefined ) { 36151 return true; 36152 } 36153 36154 while( v.length ) { 36155 if( v.pop() + 'Transition' in s ) { 36156 return true; 36157 } 36158 } 36159 36160 return false;
vendor: 24,482 bytes, lines 36161-37265
36161 }; 36162 36163/** 36164 * Public functions 36165 */ 36166MagnificPopup.prototype = { 36167 36168 constructor: MagnificPopup, 36169 36170 /** 36171 * Initializes Magnific Popup plugin. 36172 * This function is triggered only once when $.fn.magnificPopup or $.magnificPopup is executed 36173 */ 36174 init: function() { 36175 var appVersion = navigator.appVersion; 36176 mfp.isIE7 = appVersion.indexOf("MSIE 7.") !== -1; 36177 mfp.isIE8 = appVersion.indexOf("MSIE 8.") !== -1; 36178 mfp.isLowIE = mfp.isIE7 || mfp.isIE8; 36179 mfp.isAndroid = (/android/gi).test(appVersion); 36180 mfp.isIOS = (/iphone|ipad|ipod/gi).test(appVersion); 36181 mfp.supportsTransition = supportsTransitions(); 36182 36183 // We disable fixed positioned lightbox on devices that don't handle it nicely. 36184 // If you know a better way of detecting this - let me know. 36185 mfp.probablyMobile = (mfp.isAndroid || mfp.isIOS || /(Opera Mini)|Kindle|webOS|BlackBerry|(Opera Mobi)|(Windows Phone)|IEMobile/i.test(navigator.userAgent) ); 36186 _document = $(document); 36187 36188 mfp.popupsCache = {}; 36189 }, 36190 36191 /** 36192 * Opens popup 36193 * @param data [description] 36194 */ 36195 open: function(data) { 36196 36197 if(!_body) { 36198 _body = $(document.body); 36199 } 36200 36201 var i; 36202 36203 if(data.isObj === false) { 36204 // convert jQuery collection to array to avoid conflicts later 36205 mfp.items = data.items.toArray(); 36206 36207 mfp.index = 0; 36208 var items = data.items, 36209 item; 36210 for(i = 0; i < items.length; i++) { 36211 item = items[i]; 36212 if(item.parsed) { 36213 item = item.el[0]; 36214 } 36215 if(item === data.el[0]) { 36216 mfp.index = i; 36217 break; 36218 } 36219 } 36220 } else { 36221 mfp.items = $.isArray(data.items) ? data.items : [data.items]; 36222 mfp.index = data.index || 0; 36223 } 36224 36225 // if popup is already opened - we just update the content 36226 if(mfp.isOpen) { 36227 mfp.updateItemHTML(); 36228 return; 36229 } 36230 36231 mfp.types = []; 36232 _wrapClasses = ''; 36233 if(data.mainEl && data.mainEl.length) { 36234 mfp.ev = data.mainEl.eq(0); 36235 } else { 36236 mfp.ev = _document; 36237 } 36238 36239 if(data.key) { 36240 if(!mfp.popupsCache[data.key]) { 36241 mfp.popupsCache[data.key] = {}; 36242 } 36243 mfp.currTemplate = mfp.popupsCache[data.key]; 36244 } else { 36245 mfp.currTemplate = {}; 36246 } 36247 36248 mfp.st = $.extend(true, {}, $.magnificPopup.defaults, data ); 36249 mfp.fixedContentPos = mfp.st.fixedContentPos === 'auto' ? !mfp.probablyMobile : mfp.st.fixedContentPos; 36250 36251 if(mfp.st.modal) { 36252 mfp.st.closeOnContentClick = false; 36253 mfp.st.closeOnBgClick = false; 36254 mfp.st.showCloseBtn = false; 36255 mfp.st.enableEscapeKey = false; 36256 } 36257 36258 36259 // Building markup 36260 // main containers are created only once 36261 if(!mfp.bgOverlay) { 36262 36263 // Dark overlay 36264 mfp.bgOverlay = _getEl('bg').on('click'+EVENT_NS, function() { 36265 mfp.close(); 36266 }); 36267 36268 mfp.wrap = _getEl('wrap').attr('tabindex', -1).on('click'+EVENT_NS, function(e) { 36269 if(mfp._checkIfClose(e.target)) { 36270 mfp.close(); 36271 } 36272 }); 36273 36274 mfp.container = _getEl('container', mfp.wrap); 36275 } 36276 36277 mfp.contentContainer = _getEl('content'); 36278 if(mfp.st.preloader) { 36279 mfp.preloader = _getEl('preloader', mfp.container, mfp.st.tLoading); 36280 } 36281 36282 // Initializing modules 36283 var modules = $.magnificPopup.modules; 36284 for(i = 0; i < modules.length; i++) { 36285 var n = modules[i]; 36286 n = n.charAt(0).toUpperCase() + n.slice(1); 36287 mfp['init'+n].call(mfp); 36288 } 36289 _mfpTrigger('BeforeOpen'); 36290 36291 if(mfp.st.showCloseBtn) { 36292 // Close button 36293 if(!mfp.st.closeBtnInside) { 36294 mfp.wrap.append( _getCloseBtn() ); 36295 } else { 36296 _mfpOn(MARKUP_PARSE_EVENT, function(e, template, values, item) { 36297 values.close_replaceWith = _getCloseBtn(item.type); 36298 }); 36299 _wrapClasses += ' mfp-close-btn-in'; 36300 } 36301 } 36302 36303 if(mfp.st.alignTop) { 36304 _wrapClasses += ' mfp-align-top'; 36305 } 36306 36307 if(mfp.fixedContentPos) { 36308 mfp.wrap.css({ 36309 overflow: mfp.st.overflowY, 36310 overflowX: 'hidden', 36311 overflowY: mfp.st.overflowY 36312 }); 36313 } else { 36314 mfp.wrap.css({ 36315 top: _window.scrollTop(), 36316 position: 'absolute' 36317 }); 36318 } 36319 if( mfp.st.fixedBgPos === false || (mfp.st.fixedBgPos === 'auto' && !mfp.fixedContentPos) ) { 36320 mfp.bgOverlay.css({ 36321 height: _document.height(), 36322 position: 'absolute' 36323 }); 36324 } 36325 36326 36327 36328 if(mfp.st.enableEscapeKey) { 36329 // Close on ESC key 36330 _document.on('keyup' + EVENT_NS, function(e) { 36331 if(e.keyCode === 27) { 36332 mfp.close(); 36333 } 36334 }); 36335 } 36336 36337 _window.on('resize' + EVENT_NS, function() { 36338 mfp.updateSize(); 36339 }); 36340 36341 if(!mfp.st.closeOnContentClick) { 36342 _wrapClasses += ' mfp-auto-cursor'; 36343 } 36344 36345 if(_wrapClasses) 36346 mfp.wrap.addClass(_wrapClasses); 36347 36348 // this triggers recalculation of layout, so we get it once to not to trigger twice 36349 var windowHeight = mfp.wH = _window.height(); 36350 36351 36352 var windowStyles = {}; 36353 36354 if( mfp.fixedContentPos ) { 36355 if(mfp._hasScrollBar(windowHeight)){ 36356 var s = mfp._getScrollbarSize(); 36357 if(s) { 36358 windowStyles.marginRight = s; 36359 } 36360 } 36361 } 36362 36363 if(mfp.fixedContentPos) { 36364 if(!mfp.isIE7) { 36365 windowStyles.overflow = 'hidden'; 36366 } else { 36367 // ie7 double-scroll bug 36368 $('body, html').css('overflow', 'hidden'); 36369 } 36370 } 36371 36372 36373 36374 var classesToadd = mfp.st.mainClass; 36375 if(mfp.isIE7) { 36376 classesToadd += ' mfp-ie7'; 36377 } 36378 if(classesToadd) { 36379 mfp._addClassToMFP( classesToadd ); 36380 } 36381 36382 // add content 36383 mfp.updateItemHTML(); 36384 36385 _mfpTrigger('BuildControls'); 36386 36387 // remove scrollbar, add margin e.t.c 36388 $('html').css(windowStyles); 36389 36390 // add everything to DOM 36391 mfp.bgOverlay.add(mfp.wrap).prependTo( mfp.st.prependTo || _body ); 36392 36393 // Save last focused element 36394 mfp._lastFocusedEl = document.activeElement; 36395 36396 // Wait for next cycle to allow CSS transition 36397 setTimeout(function() { 36398 36399 if(mfp.content) { 36400 mfp._addClassToMFP(READY_CLASS); 36401 mfp._setFocus(); 36402 } else { 36403 // if content is not defined (not loaded e.t.c) we add class only for BG 36404 mfp.bgOverlay.addClass(READY_CLASS); 36405 } 36406 36407 // Trap the focus in popup 36408 _document.on('focusin' + EVENT_NS, mfp._onFocusIn); 36409 36410 }, 16); 36411 36412 mfp.isOpen = true; 36413 mfp.updateSize(windowHeight); 36414 _mfpTrigger(OPEN_EVENT); 36415 36416 return data; 36417 }, 36418 36419 /** 36420 * Closes the popup 36421 */ 36422 close: function() { 36423 if(!mfp.isOpen) return; 36424 _mfpTrigger(BEFORE_CLOSE_EVENT); 36425 36426 mfp.isOpen = false; 36427 // for CSS3 animation 36428 if(mfp.st.removalDelay && !mfp.isLowIE && mfp.supportsTransition ) { 36429 mfp._addClassToMFP(REMOVING_CLASS); 36430 setTimeout(function() { 36431 mfp._close(); 36432 }, mfp.st.removalDelay); 36433 } else { 36434 mfp._close(); 36435 } 36436 }, 36437 36438 /** 36439 * Helper for close() function 36440 */ 36441 _close: function() { 36442 _mfpTrigger(CLOSE_EVENT); 36443 36444 var classesToRemove = REMOVING_CLASS + ' ' + READY_CLASS + ' '; 36445 36446 mfp.bgOverlay.detach(); 36447 mfp.wrap.detach(); 36448 mfp.container.empty(); 36449 36450 if(mfp.st.mainClass) { 36451 classesToRemove += mfp.st.mainClass + ' '; 36452 } 36453 36454 mfp._removeClassFromMFP(classesToRemove); 36455 36456 if(mfp.fixedContentPos) { 36457 var windowStyles = {marginRight: ''}; 36458 if(mfp.isIE7) { 36459 $('body, html').css('overflow', ''); 36460 } else { 36461 windowStyles.overflow = ''; 36462 } 36463 $('html').css(windowStyles); 36464 } 36465 36466 _document.off('keyup' + EVENT_NS + ' focusin' + EVENT_NS); 36467 mfp.ev.off(EVENT_NS); 36468 36469 // clean up DOM elements that aren't removed 36470 mfp.wrap.attr('class', 'mfp-wrap').removeAttr('style'); 36471 mfp.bgOverlay.attr('class', 'mfp-bg'); 36472 mfp.container.attr('class', 'mfp-container'); 36473 36474 // remove close button from target element 36475 if(mfp.st.showCloseBtn && 36476 (!mfp.st.closeBtnInside || mfp.currTemplate[mfp.currItem.type] === true)) { 36477 if(mfp.currTemplate.closeBtn) 36478 mfp.currTemplate.closeBtn.detach(); 36479 } 36480 36481 if(mfp._lastFocusedEl) { 36482 $(mfp._lastFocusedEl).focus(); // put tab focus back 36483 } 36484 mfp.currItem = null; 36485 mfp.content = null; 36486 mfp.currTemplate = null; 36487 mfp.prevHeight = 0; 36488 36489 _mfpTrigger(AFTER_CLOSE_EVENT); 36490 }, 36491 updateSize: function(winHeight) { 36492 36493 if(mfp.isIOS) { 36494 // fixes iOS nav bars https://github.com/dimsemenov/Magnific-Popup/issues/2 36495 var zoomLevel = document.documentElement.clientWidth / window.innerWidth; 36496 var height = window.innerHeight * zoomLevel; 36497 mfp.wrap.css('height', height); 36498 mfp.wH = height; 36499 } else { 36500 mfp.wH = winHeight || _window.height(); 36501 } 36502 // Fixes #84: popup incorrectly positioned with position:relative on body 36503 if(!mfp.fixedContentPos) { 36504 mfp.wrap.css('height', mfp.wH); 36505 } 36506 36507 _mfpTrigger('Resize'); 36508 36509 }, 36510 36511 /** 36512 * Set content of popup based on current index 36513 */ 36514 updateItemHTML: function() { 36515 var item = mfp.items[mfp.index]; 36516 36517 // Detach and perform modifications 36518 mfp.contentContainer.detach(); 36519 36520 if(mfp.content) 36521 mfp.content.detach(); 36522 36523 if(!item.parsed) { 36524 item = mfp.parseEl( mfp.index ); 36525 } 36526 36527 var type = item.type; 36528 36529 _mfpTrigger('BeforeChange', [mfp.currItem ? mfp.currItem.type : '', type]); 36530 // BeforeChange event works like so: 36531 // _mfpOn('BeforeChange', function(e, prevType, newType) { }); 36532 36533 mfp.currItem = item; 36534 36535 36536 36537 36538 36539 if(!mfp.currTemplate[type]) { 36540 var markup = mfp.st[type] ? mfp.st[type].markup : false; 36541 36542 // allows to modify markup 36543 _mfpTrigger('FirstMarkupParse', markup); 36544 36545 if(markup) { 36546 mfp.currTemplate[type] = $(markup); 36547 } else { 36548 // if there is no markup found we just define that template is parsed 36549 mfp.currTemplate[type] = true; 36550 } 36551 } 36552 36553 if(_prevContentType && _prevContentType !== item.type) { 36554 mfp.container.removeClass('mfp-'+_prevContentType+'-holder'); 36555 } 36556 36557 var newContent = mfp['get' + type.charAt(0).toUpperCase() + type.slice(1)](item, mfp.currTemplate[type]); 36558 mfp.appendContent(newContent, type); 36559 36560 item.preloaded = true; 36561 36562 _mfpTrigger(CHANGE_EVENT, item); 36563 _prevContentType = item.type; 36564 36565 // Append container back after its content changed 36566 mfp.container.prepend(mfp.contentContainer); 36567 36568 _mfpTrigger('AfterChange'); 36569 }, 36570 36571 /** 36572 * Set HTML content of popup 36573 */ 36574 appendContent: function(newContent, type) { 36575 mfp.content = newContent; 36576 36577 if(newContent) { 36578 if(mfp.st.showCloseBtn && mfp.st.closeBtnInside && 36579 mfp.currTemplate[type] === true) { 36580 // if there is no markup, we just append close button element inside 36581 if(!mfp.content.find('.mfp-close').length) { 36582 mfp.content.append(_getCloseBtn()); 36583 } 36584 } else { 36585 mfp.content = newContent; 36586 } 36587 } else { 36588 mfp.content = ''; 36589 } 36590 36591 _mfpTrigger(BEFORE_APPEND_EVENT); 36592 mfp.container.addClass('mfp-'+type+'-holder'); 36593 36594 mfp.contentContainer.append(mfp.content); 36595 }, 36596 /** 36597 * Creates Magnific Popup data object based on given data 36598 * @param {int} index Index of item to parse 36599 */ 36600 parseEl: function(index) { 36601 var item = mfp.items[index], 36602 type; 36603 36604 if(item.tagName) { 36605 item = { el: $(item) }; 36606 } else { 36607 type = item.type; 36608 item = { data: item, src: item.src }; 36609 } 36610 36611 if(item.el) { 36612 var types = mfp.types; 36613 36614 // check for 'mfp-TYPE' class 36615 for(var i = 0; i < types.length; i++) { 36616 if( item.el.hasClass('mfp-'+types[i]) ) { 36617 type = types[i]; 36618 break; 36619 } 36620 } 36621 36622 item.src = item.el.attr('data-mfp-src'); 36623 if(!item.src) { 36624 item.src = item.el.attr('href'); 36625 } 36626 } 36627 36628 item.type = type || mfp.st.type || 'inline'; 36629 item.index = index; 36630 item.parsed = true; 36631 mfp.items[index] = item; 36632 _mfpTrigger('ElementParse', item); 36633 36634 return mfp.items[index]; 36635 }, 36636 36637 /** 36638 * Initializes single popup or a group of popups 36639 */ 36640 addGroup: function(el, options) { 36641 var eHandler = function(e) { 36642 e.mfpEl = this; 36643 mfp._openClick(e, el, options); 36644 }; 36645 36646 if(!options) { 36647 options = {}; 36648 } 36649 36650 var eName = 'click.magnificPopup'; 36651 options.mainEl = el; 36652 36653 if(options.items) { 36654 options.isObj = true; 36655 el.off(eName).on(eName, eHandler); 36656 } else { 36657 options.isObj = false; 36658 if(options.delegate) { 36659 el.off(eName).on(eName, options.delegate , eHandler); 36660 } else { 36661 options.items = el; 36662 el.off(eName).on(eName, eHandler); 36663 } 36664 } 36665 }, 36666 _openClick: function(e, el, options) { 36667 var midClick = options.midClick !== undefined ? options.midClick : $.magnificPopup.defaults.midClick; 36668 36669 if(!midClick && ( e.which === 2 || e.ctrlKey || e.metaKey ) ) { 36670 return; 36671 } 36672 36673 var disableOn = options.disableOn !== undefined ? options.disableOn : $.magnificPopup.defaults.disableOn; 36674 36675 if(disableOn) { 36676 if($.isFunction(disableOn)) { 36677 if( !disableOn.call(mfp) ) { 36678 return true; 36679 } 36680 } else { // else it's number 36681 if( _window.width() < disableOn ) { 36682 return true; 36683 } 36684 } 36685 } 36686 36687 if(e.type) { 36688 e.preventDefault(); 36689 36690 // This will prevent popup from closing if element is inside and popup is already opened 36691 if(mfp.isOpen) { 36692 e.stopPropagation(); 36693 } 36694 } 36695 36696 36697 options.el = $(e.mfpEl); 36698 if(options.delegate) { 36699 options.items = el.find(options.delegate); 36700 } 36701 mfp.open(options); 36702 }, 36703 36704 /** 36705 * Updates text on preloader 36706 */ 36707 updateStatus: function(status, text) { 36708 36709 if(mfp.preloader) { 36710 if(_prevStatus !== status) { 36711 mfp.container.removeClass('mfp-s-'+_prevStatus); 36712 } 36713 36714 if(!text && status === 'loading') { 36715 text = mfp.st.tLoading; 36716 } 36717 36718 var data = { 36719 status: status, 36720 text: text 36721 }; 36722 // allows to modify status 36723 _mfpTrigger('UpdateStatus', data); 36724 36725 status = data.status; 36726 text = data.text; 36727 36728 mfp.preloader.html(text); 36729 36730 mfp.preloader.find('a').on('click', function(e) { 36731 e.stopImmediatePropagation(); 36732 }); 36733 36734 mfp.container.addClass('mfp-s-'+status); 36735 _prevStatus = status; 36736 } 36737 }, 36738 36739 /* 36740 "Private" helpers that aren't private at all 36741 */ 36742 // Check to close popup or not 36743 // "target" is an element that was clicked 36744 _checkIfClose: function(target) { 36745 36746 if($(target).hasClass(PREVENT_CLOSE_CLASS)) { 36747 return; 36748 } 36749 36750 var closeOnContent = mfp.st.closeOnContentClick; 36751 var closeOnBg = mfp.st.closeOnBgClick; 36752 36753 if(closeOnContent && closeOnBg) { 36754 return true; 36755 } else { 36756 36757 // We close the popup if click is on close button or on preloader. Or if there is no content. 36758 if(!mfp.content || $(target).hasClass('mfp-close') || (mfp.preloader && target === mfp.preloader[0]) ) { 36759 return true; 36760 } 36761 36762 // if click is outside the content 36763 if( (target !== mfp.content[0] && !$.contains(mfp.content[0].parentElement, target)) ) { 36764 if(closeOnBg) { 36765 // last check, if the clicked element is in DOM, (in case it's removed onclick) 36766 if( $.contains(document, target) ) { 36767 return true; 36768 } 36769 } 36770 } else if(closeOnContent) { 36771 return true; 36772 } 36773 36774 } 36775 return false; 36776 }, 36777 _addClassToMFP: function(cName) { 36778 mfp.bgOverlay.addClass(cName); 36779 mfp.wrap.addClass(cName); 36780 }, 36781 _removeClassFromMFP: function(cName) { 36782 this.bgOverlay.removeClass(cName); 36783 mfp.wrap.removeClass(cName); 36784 }, 36785 _hasScrollBar: function(winHeight) { 36786 return ( (mfp.isIE7 ? _document.height() : document.body.scrollHeight) > (winHeight || _window.height()) ); 36787 }, 36788 _setFocus: function() { 36789 (mfp.st.focus ? mfp.content.find(mfp.st.focus).eq(0) : mfp.wrap).focus(); 36790 }, 36791 _onFocusIn: function(e) { 36792 if( e.target !== mfp.wrap[0] && !$.contains(mfp.wrap[0], e.target) ) { 36793 mfp._setFocus(); 36794 return false; 36795 } 36796 }, 36797 _parseMarkup: function(template, values, item) { 36798 var arr; 36799 if(item.data) { 36800 values = $.extend(item.data, values); 36801 } 36802 _mfpTrigger(MARKUP_PARSE_EVENT, [template, values, item] ); 36803 36804 $.each(values, function(key, value) { 36805 if(value === undefined || value === false) { 36806 return true; 36807 } 36808 arr = key.split('_'); 36809 if(arr.length > 1) { 36810 var el = template.find(EVENT_NS + '-'+arr[0]); 36811 36812 if(el.length > 0) { 36813 var attr = arr[1]; 36814 if(attr === 'replaceWith') { 36815 if(el[0] !== value[0]) { 36816 el.replaceWith(value); 36817 } 36818 } else if(attr === 'img') { 36819 if(el.is('img')) { 36820 el.attr('src', value); 36821 } else { 36822 el.replaceWith( '<img src="'+value+'" class="' + el.attr('class') + '" />' ); 36823 } 36824 } else { 36825 el.attr(arr[1], value); 36826 } 36827 } 36828 36829 } else { 36830 template.find(EVENT_NS + '-'+key).html(value); 36831 } 36832 }); 36833 }, 36834 36835 _getScrollbarSize: function() { 36836 // thx David 36837 if(mfp.scrollbarSize === undefined) { 36838 var scrollDiv = document.createElement("div"); 36839 scrollDiv.id = "mfp-sbm"; 36840 scrollDiv.style.cssText = 'width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;'; 36841 document.body.appendChild(scrollDiv); 36842 mfp.scrollbarSize = scrollDiv.offsetWidth - scrollDiv.clientWidth; 36843 document.body.removeChild(scrollDiv); 36844 } 36845 return mfp.scrollbarSize; 36846 } 36847 36848}; /* MagnificPopup core prototype end */ 36849 36850/** 36851 * Public static functions 36852 */ 36853$.magnificPopup = { 36854 instance: null, 36855 proto: MagnificPopup.prototype, 36856 modules: [], 36857 36858 open: function(options, index) { 36859 _checkInstance(); 36860 36861 if(!options) { 36862 options = {}; 36863 } else { 36864 options = $.extend(true, {}, options); 36865 } 36866 36867 36868 options.isObj = true; 36869 options.index = index || 0; 36870 return this.instance.open(options); 36871 }, 36872 36873 close: function() { 36874 return $.magnificPopup.instance && $.magnificPopup.instance.close(); 36875 }, 36876 36877 registerModule: function(name, module) { 36878 if(module.options) { 36879 $.magnificPopup.defaults[name] = module.options; 36880 } 36881 $.extend(this.proto, module.proto); 36882 this.modules.push(name); 36883 }, 36884 36885 defaults: { 36886 36887 // Info about options is in docs: 36888 // http://dimsemenov.com/plugins/magnific-popup/documentation.html#options 36889 36890 disableOn: 0, 36891 36892 key: null, 36893 36894 midClick: false, 36895 36896 mainClass: '', 36897 36898 preloader: true, 36899 36900 focus: '', // CSS selector of input to focus after popup is opened 36901 36902 closeOnContentClick: false, 36903 36904 closeOnBgClick: true, 36905 36906 closeBtnInside: true, 36907 36908 showCloseBtn: true, 36909 36910 enableEscapeKey: true, 36911 36912 modal: false, 36913 36914 alignTop: false, 36915 removalDelay: 0, 36916 36917 prependTo: null, 36918 36919 fixedContentPos: 'auto', 36920 fixedBgPos: 'auto', 36921 36922 overflowY: 'auto', 36923 36924 closeMarkup: '<button title="%title%" type="button" class="mfp-close">×</button>', 36925 36926 tClose: 'Close (Esc)', 36927 36928 tLoading: 'Loading...' 36929 36930 } 36931}; 36932 36933$.fn.magnificPopup = function(options) { 36934 _checkInstance(); 36935 36936 var jqEl = $(this); 36937 36938 // We call some API method of first param is a string 36939 if (typeof options === "string" ) { 36940 36941 if(options === 'open') { 36942 var items, 36943 itemOpts = _isJQ ? jqEl.data('magnificPopup') : jqEl[0].magnificPopup, 36944 index = parseInt(arguments[1], 10) || 0; 36945 36946 if(itemOpts.items) { 36947 items = itemOpts.items[index]; 36948 } else { 36949 items = jqEl; 36950 if(itemOpts.delegate) { 36951 items = items.find(itemOpts.delegate); 36952 } 36953 items = items.eq( index ); 36954 } 36955 mfp._openClick({mfpEl:items}, jqEl, itemOpts); 36956 } else { 36957 if(mfp.isOpen) 36958 mfp[options].apply(mfp, Array.prototype.slice.call(arguments, 1)); 36959 } 36960 36961 } else { 36962 // clone options obj 36963 options = $.extend(true, {}, options); 36964 36965 /* 36966 * As Zepto doesn't support .data() method for objects 36967 * and it works only in normal browsers 36968 * we assign "options" object directly to the DOM element. FTW! 36969 */ 36970 if(_isJQ) { 36971 jqEl.data('magnificPopup', options); 36972 } else { 36973 jqEl[0].magnificPopup = options; 36974 } 36975 36976 mfp.addGroup(jqEl, options); 36977 36978 } 36979 return jqEl; 36980}; 36981 36982//Quick benchmark 36983/* 36984var start = performance.now(), 36985 i, 36986 rounds = 1000; 36987 36988for(i = 0; i < rounds; i++) { 36989 36990} 36991console.log('Test #1:', performance.now() - start); 36992 36993start = performance.now(); 36994for(i = 0; i < rounds; i++) { 36995 36996} 36997console.log('Test #2:', performance.now() - start); 36998*/ 36999 37000/*>>core*/ 37001 37002/*>>inline*/ 37003 37004var INLINE_NS = 'inline', 37005 _hiddenClass, 37006 _inlinePlaceholder, 37007 _lastInlineElement, 37008 _putInlineElementsBack = function() { 37009 if(_lastInlineElement) { 37010 _inlinePlaceholder.after( _lastInlineElement.addClass(_hiddenClass) ).detach(); 37011 _lastInlineElement = null; 37012 } 37013 }; 37014 37015$.magnificPopup.registerModule(INLINE_NS, { 37016 options: { 37017 hiddenClass: 'hide', // will be appended with `mfp-` prefix 37018 markup: '', 37019 tNotFound: 'Content not found' 37020 }, 37021 proto: { 37022 37023 initInline: function() { 37024 mfp.types.push(INLINE_NS); 37025 37026 _mfpOn(CLOSE_EVENT+'.'+INLINE_NS, function() { 37027 _putInlineElementsBack(); 37028 }); 37029 }, 37030 37031 getInline: function(item, template) { 37032 37033 _putInlineElementsBack(); 37034 37035 if(item.src) { 37036 var inlineSt = mfp.st.inline, 37037 el = $(item.src); 37038 37039 if(el.length) { 37040 37041 // If target element has parent - we replace it with placeholder and put it back after popup is closed 37042 var parent = el[0].parentNode; 37043 if(parent && parent.tagName) { 37044 if(!_inlinePlaceholder) { 37045 _hiddenClass = inlineSt.hiddenClass; 37046 _inlinePlaceholder = _getEl(_hiddenClass); 37047 _hiddenClass = 'mfp-'+_hiddenClass; 37048 } 37049 // replace target inline element with placeholder 37050 _lastInlineElement = el.after(_inlinePlaceholder).detach().removeClass(_hiddenClass); 37051 } 37052 37053 mfp.updateStatus('ready'); 37054 } else { 37055 mfp.updateStatus('error', inlineSt.tNotFound); 37056 el = $('<div>'); 37057 } 37058 37059 item.inlineElement = el; 37060 return el; 37061 } 37062 37063 mfp.updateStatus('ready'); 37064 mfp._parseMarkup(template, {}, item); 37065 return template; 37066 } 37067 } 37068}); 37069 37070/*>>inline*/ 37071 37072/*>>ajax*/ 37073var AJAX_NS = 'ajax', 37074 _ajaxCur, 37075 _removeAjaxCursor = function() { 37076 if(_ajaxCur) { 37077 _body.removeClass(_ajaxCur); 37078 } 37079 }, 37080 _destroyAjaxRequest = function() { 37081 _removeAjaxCursor(); 37082 if(mfp.req) { 37083 mfp.req.abort(); 37084 } 37085 }; 37086 37087$.magnificPopup.registerModule(AJAX_NS, { 37088 37089 options: { 37090 settings: null, 37091 cursor: 'mfp-ajax-cur', 37092 tError: '<a href="%url%">The content</a> could not be loaded.' 37093 }, 37094 37095 proto: { 37096 initAjax: function() { 37097 mfp.types.push(AJAX_NS); 37098 _ajaxCur = mfp.st.ajax.cursor; 37099 37100 _mfpOn(CLOSE_EVENT+'.'+AJAX_NS, _destroyAjaxRequest); 37101 _mfpOn('BeforeChange.' + AJAX_NS, _destroyAjaxRequest); 37102 }, 37103 getAjax: function(item) { 37104 37105 if(_ajaxCur) 37106 _body.addClass(_ajaxCur); 37107 37108 mfp.updateStatus('loading'); 37109 37110 var opts = $.extend({ 37111 url: item.src, 37112 success: function(data, textStatus, jqXHR) { 37113 var temp = { 37114 data:data, 37115 xhr:jqXHR 37116 }; 37117 37118 _mfpTrigger('ParseAjax', temp); 37119 37120 mfp.appendContent( $(temp.data), AJAX_NS ); 37121 37122 item.finished = true; 37123 37124 _removeAjaxCursor(); 37125 37126 mfp._setFocus(); 37127 37128 setTimeout(function() { 37129 mfp.wrap.addClass(READY_CLASS); 37130 }, 16); 37131 37132 mfp.updateStatus('ready'); 37133 37134 _mfpTrigger('AjaxContentAdded'); 37135 }, 37136 error: function() { 37137 _removeAjaxCursor(); 37138 item.finished = item.loadError = true; 37139 mfp.updateStatus('error', mfp.st.ajax.tError.replace('%url%', item.src)); 37140 } 37141 }, mfp.st.ajax.settings); 37142 37143 mfp.req = $.ajax(opts); 37144 37145 return ''; 37146 } 37147 } 37148}); 37149 37150/*>>ajax*/ 37151 37152/*>>image*/ 37153var _imgInterval, 37154 _getTitle = function(item) { 37155 if(item.data && item.data.title !== undefined) 37156 return item.data.title; 37157 37158 var src = mfp.st.image.titleSrc; 37159 37160 if(src) { 37161 if($.isFunction(src)) { 37162 return src.call(mfp, item); 37163 } else if(item.el) { 37164 return item.el.attr(src) || ''; 37165 } 37166 } 37167 return ''; 37168 }; 37169 37170$.magnificPopup.registerModule('image', { 37171 37172 options: { 37173 markup: '<div class="mfp-figure">'+ 37174 '<div class="mfp-close"></div>'+ 37175 '<figure>'+ 37176 '<div class="mfp-img"></div>'+ 37177 '<figcaption>'+ 37178 '<div class="mfp-bottom-bar">'+ 37179 '<div class="mfp-title"></div>'+ 37180 '<div class="mfp-counter"></div>'+ 37181 '</div>'+ 37182 '</figcaption>'+ 37183 '</figure>'+ 37184 '</div>', 37185 cursor: 'mfp-zoom-out-cur', 37186 titleSrc: 'title', 37187 verticalFit: true, 37188 tError: '<a href="%url%">The image</a> could not be loaded.' 37189 }, 37190 37191 proto: { 37192 initImage: function() { 37193 var imgSt = mfp.st.image, 37194 ns = '.image'; 37195 37196 mfp.types.push('image'); 37197 37198 _mfpOn(OPEN_EVENT+ns, function() { 37199 if(mfp.currItem.type === 'image' && imgSt.cursor) { 37200 _body.addClass(imgSt.cursor); 37201 } 37202 }); 37203 37204 _mfpOn(CLOSE_EVENT+ns, function() { 37205 if(imgSt.cursor) { 37206 _body.removeClass(imgSt.cursor); 37207 } 37208 _window.off('resize' + EVENT_NS); 37209 }); 37210 37211 _mfpOn('Resize'+ns, mfp.resizeImage); 37212 if(mfp.isLowIE) { 37213 _mfpOn('AfterChange', mfp.resizeImage); 37214 } 37215 }, 37216 resizeImage: function() { 37217 var item = mfp.currItem; 37218 if(!item || !item.img) return; 37219 37220 if(mfp.st.image.verticalFit) { 37221 var decr = 0; 37222 // fix box-sizing in ie7/8 37223 if(mfp.isLowIE) { 37224 decr = parseInt(item.img.css('padding-top'), 10) + parseInt(item.img.css('padding-bottom'),10); 37225 } 37226 item.img.css('max-height', mfp.wH-decr); 37227 } 37228 }, 37229 _onImageHasSize: function(item) { 37230 if(item.img) { 37231 37232 item.hasSize = true; 37233 37234 if(_imgInterval) { 37235 clearInterval(_imgInterval); 37236 } 37237 37238 item.isCheckingImgSize = false; 37239 37240 _mfpTrigger('ImageHasSize', item); 37241 37242 if(item.imgHidden) { 37243 if(mfp.content) 37244 mfp.content.removeClass('mfp-loading'); 37245 37246 item.imgHidden = false; 37247 } 37248 37249 } 37250 }, 37251 37252 /** 37253 * Function that loops until the image has size to display elements that rely on it asap 37254 */ 37255 findImageSize: function(item) { 37256 37257 var counter = 0, 37258 img = item.img[0], 37259 mfpSetInterval = function(delay) { 37260 37261 if(_imgInterval) { 37262 clearInterval(_imgInterval); 37263 } 37264 // decelerating interval that checks for size of an image 37265 _imgInterval = setInterval(function() {
37266 if(img.naturalWidth > 0) { 37267 mfp._onImageHasSize(item); 37268 return; 37269 } 37270 37271 if(counter > 200) { 37272 clearInterval(_imgInterval); 37273 } 37274 37275 counter++; 37276 if(counter === 3) { 37277 mfpSetInterval(10); 37278 } else if(counter === 40) { 37279 mfpSetInterval(50); 37280 } else if(counter === 100) { 37281 mfpSetInterval(500); 37282 } 37283 }, delay); 37284 }; 37285 37286 mfpSetInterval(1); 37287 }, 37288 37289 getImage: function(item, template) { 37290 37291 var guard = 0, 37292 37293 // image load complete handler 37294 onLoadComplete = function() { 37295 if(item) { 37296 if (item.img[0].complete) { 37297 item.img.off('.mfploader'); 37298 37299 if(item === mfp.currItem){ 37300 mfp._onImageHasSize(item); 37301 37302 mfp.updateStatus('ready'); 37303 } 37304 37305 item.hasSize = true; 37306 item.loaded = true; 37307 37308 _mfpTrigger('ImageLoadComplete'); 37309 37310 } 37311 else { 37312 // if image complete check fails 200 times (20 sec), we assume that there was an error. 37313 guard++; 37314 if(guard < 200) { 37315 setTimeout(onLoadComplete,100); 37316 } else { 37317 onLoadError(); 37318 } 37319 } 37320 } 37321 }, 37322 37323 // image error handler 37324 onLoadError = function() { 37325 if(item) { 37326 item.img.off('.mfploader'); 37327 if(item === mfp.currItem){ 37328 mfp._onImageHasSize(item); 37329 mfp.updateStatus('error', imgSt.tError.replace('%url%', item.src) ); 37330 } 37331 37332 item.hasSize = true; 37333 item.loaded = true; 37334 item.loadError = true; 37335 } 37336 }, 37337 imgSt = mfp.st.image; 37338 37339 var el = template.find('.mfp-img'); 37340 if(el.length) { 37341 var img = document.createElement('img'); 37342 img.className = 'mfp-img'; 37343 item.img = $(img).on('load.mfploader', onLoadComplete).on('error.mfploader', onLoadError); 37344 img.src = item.src; 37345 37346 // without clone() "error" event is not firing when IMG is replaced by new IMG
vendor: 8,672 bytes, lines 37347-37725
37347 // TODO: find a way to avoid such cloning 37348 if(el.is('img')) { 37349 item.img = item.img.clone(); 37350 } 37351 37352 img = item.img[0]; 37353 if(img.naturalWidth > 0) { 37354 item.hasSize = true; 37355 } else if(!img.width) { 37356 item.hasSize = false; 37357 } 37358 } 37359 37360 mfp._parseMarkup(template, { 37361 title: _getTitle(item), 37362 img_replaceWith: item.img 37363 }, item); 37364 37365 mfp.resizeImage(); 37366 37367 if(item.hasSize) { 37368 if(_imgInterval) clearInterval(_imgInterval); 37369 37370 if(item.loadError) { 37371 template.addClass('mfp-loading'); 37372 mfp.updateStatus('error', imgSt.tError.replace('%url%', item.src) ); 37373 } else { 37374 template.removeClass('mfp-loading'); 37375 mfp.updateStatus('ready'); 37376 } 37377 return template; 37378 } 37379 37380 mfp.updateStatus('loading'); 37381 item.loading = true; 37382 37383 if(!item.hasSize) { 37384 item.imgHidden = true; 37385 template.addClass('mfp-loading'); 37386 mfp.findImageSize(item); 37387 } 37388 37389 return template; 37390 } 37391 } 37392}); 37393 37394/*>>image*/ 37395 37396/*>>zoom*/ 37397var hasMozTransform, 37398 getHasMozTransform = function() { 37399 if(hasMozTransform === undefined) { 37400 hasMozTransform = document.createElement('p').style.MozTransform !== undefined; 37401 } 37402 return hasMozTransform; 37403 }; 37404 37405$.magnificPopup.registerModule('zoom', { 37406 37407 options: { 37408 enabled: false, 37409 easing: 'ease-in-out', 37410 duration: 300, 37411 opener: function(element) { 37412 return element.is('img') ? element : element.find('img'); 37413 } 37414 }, 37415 37416 proto: { 37417 37418 initZoom: function() { 37419 var zoomSt = mfp.st.zoom, 37420 ns = '.zoom', 37421 image; 37422 37423 if(!zoomSt.enabled || !mfp.supportsTransition) { 37424 return; 37425 } 37426 37427 var duration = zoomSt.duration, 37428 getElToAnimate = function(image) { 37429 var newImg = image.clone().removeAttr('style').removeAttr('class').addClass('mfp-animated-image'), 37430 transition = 'all '+(zoomSt.duration/1000)+'s ' + zoomSt.easing, 37431 cssObj = { 37432 position: 'fixed', 37433 zIndex: 9999, 37434 left: 0, 37435 top: 0, 37436 '-webkit-backface-visibility': 'hidden' 37437 }, 37438 t = 'transition'; 37439 37440 cssObj['-webkit-'+t] = cssObj['-moz-'+t] = cssObj['-o-'+t] = cssObj[t] = transition; 37441 37442 newImg.css(cssObj); 37443 return newImg; 37444 }, 37445 showMainContent = function() { 37446 mfp.content.css('visibility', 'visible'); 37447 }, 37448 openTimeout, 37449 animatedImg; 37450 37451 _mfpOn('BuildControls'+ns, function() { 37452 if(mfp._allowZoom()) { 37453 37454 clearTimeout(openTimeout); 37455 mfp.content.css('visibility', 'hidden'); 37456 37457 // Basically, all code below does is clones existing image, puts in on top of the current one and animated it 37458 37459 image = mfp._getItemToZoom(); 37460 37461 if(!image) { 37462 showMainContent(); 37463 return; 37464 } 37465 37466 animatedImg = getElToAnimate(image); 37467 37468 animatedImg.css( mfp._getOffset() ); 37469 37470 mfp.wrap.append(animatedImg); 37471 37472 openTimeout = setTimeout(function() { 37473 animatedImg.css( mfp._getOffset( true ) ); 37474 openTimeout = setTimeout(function() { 37475 37476 showMainContent(); 37477 37478 setTimeout(function() { 37479 animatedImg.remove(); 37480 image = animatedImg = null; 37481 _mfpTrigger('ZoomAnimationEnded'); 37482 }, 16); // avoid blink when switching images 37483 37484 }, duration); // this timeout equals animation duration 37485 37486 }, 16); // by adding this timeout we avoid short glitch at the beginning of animation 37487 37488 // Lots of timeouts... 37489 } 37490 }); 37491 _mfpOn(BEFORE_CLOSE_EVENT+ns, function() { 37492 if(mfp._allowZoom()) { 37493 37494 clearTimeout(openTimeout); 37495 37496 mfp.st.removalDelay = duration; 37497 37498 if(!image) { 37499 image = mfp._getItemToZoom(); 37500 if(!image) { 37501 return; 37502 } 37503 animatedImg = getElToAnimate(image); 37504 } 37505 37506 37507 animatedImg.css( mfp._getOffset(true) ); 37508 mfp.wrap.append(animatedImg); 37509 mfp.content.css('visibility', 'hidden'); 37510 37511 setTimeout(function() { 37512 animatedImg.css( mfp._getOffset() ); 37513 }, 16); 37514 } 37515 37516 }); 37517 37518 _mfpOn(CLOSE_EVENT+ns, function() { 37519 if(mfp._allowZoom()) { 37520 showMainContent(); 37521 if(animatedImg) { 37522 animatedImg.remove(); 37523 } 37524 image = null; 37525 } 37526 }); 37527 }, 37528 37529 _allowZoom: function() { 37530 return mfp.currItem.type === 'image'; 37531 }, 37532 37533 _getItemToZoom: function() { 37534 if(mfp.currItem.hasSize) { 37535 return mfp.currItem.img; 37536 } else { 37537 return false; 37538 } 37539 }, 37540 37541 // Get element postion relative to viewport 37542 _getOffset: function(isLarge) { 37543 var el; 37544 if(isLarge) { 37545 el = mfp.currItem.img; 37546 } else { 37547 el = mfp.st.zoom.opener(mfp.currItem.el || mfp.currItem); 37548 } 37549 37550 var offset = el.offset(); 37551 var paddingTop = parseInt(el.css('padding-top'),10); 37552 var paddingBottom = parseInt(el.css('padding-bottom'),10); 37553 offset.top -= ( $(window).scrollTop() - paddingTop ); 37554 37555 /* 37556 37557 Animating left + top + width/height looks glitchy in Firefox, but perfect in Chrome. And vice-versa. 37558 37559 */ 37560 var obj = { 37561 width: el.width(), 37562 // fix Zepto height+padding issue 37563 height: (_isJQ ? el.innerHeight() : el[0].offsetHeight) - paddingBottom - paddingTop 37564 }; 37565 37566 // I hate to do this, but there is no another option 37567 if( getHasMozTransform() ) { 37568 obj['-moz-transform'] = obj['transform'] = 'translate(' + offset.left + 'px,' + offset.top + 'px)'; 37569 } else { 37570 obj.left = offset.left; 37571 obj.top = offset.top; 37572 } 37573 return obj; 37574 } 37575 37576 } 37577}); 37578 37579/*>>zoom*/ 37580 37581/*>>iframe*/ 37582 37583var IFRAME_NS = 'iframe', 37584 _emptyPage = '//about:blank', 37585 _fixIframeBugs = function(isShowing) { 37586 if(mfp.currTemplate[IFRAME_NS]) { 37587 var el = mfp.currTemplate[IFRAME_NS].find('iframe'); 37588 if(el.length) { 37589 // reset src after the popup is closed to avoid "video keeps playing after popup is closed" bug 37590 if(!isShowing) { 37591 el[0].src = _emptyPage; 37592 } 37593 37594 // IE8 black screen bug fix 37595 if(mfp.isIE8) { 37596 el.css('display', isShowing ? 'block' : 'none'); 37597 } 37598 } 37599 } 37600 }; 37601 37602$.magnificPopup.registerModule(IFRAME_NS, { 37603 37604 options: { 37605 markup: '<div class="mfp-iframe-scaler">'+ 37606 '<div class="mfp-close"></div>'+ 37607 '<iframe class="mfp-iframe" src="//about:blank" frameborder="0" allowfullscreen></iframe>'+ 37608 '</div>', 37609 37610 srcAction: 'iframe_src', 37611 37612 // we don't care and support only one default type of URL by default 37613 patterns: { 37614 youtube: { 37615 index: 'youtube.com', 37616 id: 'v=', 37617 src: '//www.youtube.com/embed/%id%?autoplay=1' 37618 }, 37619 vimeo: { 37620 index: 'vimeo.com/', 37621 id: '/', 37622 src: '//player.vimeo.com/video/%id%?autoplay=1' 37623 }, 37624 gmaps: { 37625 index: '//maps.google.', 37626 src: '%id%&output=embed' 37627 } 37628 } 37629 }, 37630 37631 proto: { 37632 initIframe: function() { 37633 mfp.types.push(IFRAME_NS); 37634 37635 _mfpOn('BeforeChange', function(e, prevType, newType) { 37636 if(prevType !== newType) { 37637 if(prevType === IFRAME_NS) { 37638 _fixIframeBugs(); // iframe if removed 37639 } else if(newType === IFRAME_NS) { 37640 _fixIframeBugs(true); // iframe is showing 37641 } 37642 }// else { 37643 // iframe source is switched, don't do anything 37644 //} 37645 }); 37646 37647 _mfpOn(CLOSE_EVENT + '.' + IFRAME_NS, function() { 37648 _fixIframeBugs(); 37649 }); 37650 }, 37651 37652 getIframe: function(item, template) { 37653 var embedSrc = item.src; 37654 var iframeSt = mfp.st.iframe; 37655 37656 $.each(iframeSt.patterns, function() { 37657 if(embedSrc.indexOf( this.index ) > -1) { 37658 if(this.id) { 37659 if(typeof this.id === 'string') { 37660 embedSrc = embedSrc.substr(embedSrc.lastIndexOf(this.id)+this.id.length, embedSrc.length); 37661 } else { 37662 embedSrc = this.id.call( this, embedSrc ); 37663 } 37664 } 37665 embedSrc = this.src.replace('%id%', embedSrc ); 37666 return false; // break; 37667 } 37668 }); 37669 37670 var dataObj = {}; 37671 if(iframeSt.srcAction) { 37672 dataObj[iframeSt.srcAction] = embedSrc; 37673 } 37674 mfp._parseMarkup(template, dataObj, item); 37675 37676 mfp.updateStatus('ready'); 37677 37678 return template; 37679 } 37680 } 37681}); 37682 37683/*>>iframe*/ 37684 37685/*>>gallery*/ 37686/** 37687 * Get looped index depending on number of slides 37688 */ 37689var _getLoopedId = function(index) { 37690 var numSlides = mfp.items.length; 37691 if(index > numSlides - 1) { 37692 return index - numSlides; 37693 } else if(index < 0) { 37694 return numSlides + index; 37695 } 37696 return index; 37697 }, 37698 _replaceCurrTotal = function(text, curr, total) { 37699 return text.replace(/%curr%/gi, curr + 1).replace(/%total%/gi, total); 37700 }; 37701 37702$.magnificPopup.registerModule('gallery', { 37703 37704 options: { 37705 enabled: false, 37706 arrowMarkup: '<button title="%title%" type="button" class="mfp-arrow mfp-arrow-%dir%"></button>', 37707 preload: [0,2], 37708 navigateByImgClick: true, 37709 arrows: true, 37710 37711 tPrev: 'Previous (Left arrow key)', 37712 tNext: 'Next (Right arrow key)', 37713 tCounter: '%curr% of %total%' 37714 }, 37715 37716 proto: { 37717 initGallery: function() { 37718 37719 var gSt = mfp.st.gallery, 37720 ns = '.mfp-gallery', 37721 supportsFastClick = Boolean($.fn.mfpFastClick); 37722 37723 mfp.direction = true; // true - next, false - prev 37724 37725 if(!gSt || !gSt.enabled ) return false;
37726 37727 _wrapClasses += ' mfp-gallery'; 37728 37729 _mfpOn(OPEN_EVENT+ns, function() { 37730 37731 if(gSt.navigateByImgClick) { 37732 mfp.wrap.on('click'+ns, '.mfp-img', function() { 37733 if(mfp.items.length > 1) { 37734 mfp.next(); 37735 return false; 37736 } 37737 }); 37738 } 37739 37740 _document.on('keydown'+ns, function(e) { 37741 if (e.keyCode === 37) { 37742 mfp.prev(); 37743 } else if (e.keyCode === 39) { 37744 mfp.next(); 37745 } 37746 }); 37747 }); 37748 37749 _mfpOn('UpdateStatus'+ns, function(e, data) { 37750 if(data.text) { 37751 data.text = _replaceCurrTotal(data.text, mfp.currItem.index, mfp.items.length); 37752 } 37753 }); 37754 37755 _mfpOn(MARKUP_PARSE_EVENT+ns, function(e, element, values, item) { 37756 var l = mfp.items.length; 37757 values.counter = l > 1 ? _replaceCurrTotal(gSt.tCounter, item.index, l) : ''; 37758 }); 37759 37760 _mfpOn('BuildControls' + ns, function() { 37761 if(mfp.items.length > 1 && gSt.arrows && !mfp.arrowLeft) { 37762 var markup = gSt.arrowMarkup, 37763 arrowLeft = mfp.arrowLeft = $( markup.replace(/%title%/gi, gSt.tPrev).replace(/%dir%/gi, 'left') ).addClass(PREVENT_CLOSE_CLASS), 37764 arrowRight = mfp.arrowRight = $( markup.replace(/%title%/gi, gSt.tNext).replace(/%dir%/gi, 'right') ).addClass(PREVENT_CLOSE_CLASS); 37765 37766 var eName = supportsFastClick ? 'mfpFastClick' : 'click'; 37767 arrowLeft[eName](function() { 37768 mfp.prev(); 37769 }); 37770 arrowRight[eName](function() { 37771 mfp.next(); 37772 }); 37773 37774 // Polyfill for :before and :after (adds elements with classes mfp-a and mfp-b) 37775 if(mfp.isIE7) { 37776 _getEl('b', arrowLeft[0], false, true); 37777 _getEl('a', arrowLeft[0], false, true); 37778 _getEl('b', arrowRight[0], false, true); 37779 _getEl('a', arrowRight[0], false, true); 37780 } 37781 37782 mfp.container.append(arrowLeft.add(arrowRight)); 37783 } 37784 }); 37785 37786 _mfpOn(CHANGE_EVENT+ns, function() { 37787 if(mfp._preloadTimeout) clearTimeout(mfp._preloadTimeout); 37788 37789 mfp._preloadTimeout = setTimeout(function() { 37790 mfp.preloadNearbyImages(); 37791 mfp._preloadTimeout = null; 37792 }, 16); 37793 }); 37794 37795 _mfpOn(CLOSE_EVENT+ns, function() { 37796 _document.off(ns); 37797 mfp.wrap.off('click'+ns); 37798 37799 if(mfp.arrowLeft && supportsFastClick) { 37800 mfp.arrowLeft.add(mfp.arrowRight).destroyMfpFastClick(); 37801 } 37802 mfp.arrowRight = mfp.arrowLeft = null; 37803 }); 37804 37805 }, 37806 next: function() { 37807 mfp.direction = true; 37808 mfp.index = _getLoopedId(mfp.index + 1); 37809 mfp.updateItemHTML(); 37810 }, 37811 prev: function() { 37812 mfp.direction = false; 37813 mfp.index = _getLoopedId(mfp.index - 1); 37814 mfp.updateItemHTML(); 37815 }, 37816 goTo: function(newIndex) { 37817 mfp.direction = (newIndex >= mfp.index); 37818 mfp.index = newIndex; 37819 mfp.updateItemHTML(); 37820 }, 37821 preloadNearbyImages: function() { 37822 var p = mfp.st.gallery.preload, 37823 preloadBefore = Math.min(p[0], mfp.items.length), 37824 preloadAfter = Math.min(p[1], mfp.items.length), 37825 i; 37826 37827 for(i = 1; i <= (mfp.direction ? preloadAfter : preloadBefore); i++) { 37828 mfp._preloadItem(mfp.index+i); 37829 } 37830 for(i = 1; i <= (mfp.direction ? preloadBefore : preloadAfter); i++) { 37831 mfp._preloadItem(mfp.index-i); 37832 } 37833 }, 37834 _preloadItem: function(index) { 37835 index = _getLoopedId(index); 37836 37837 if(mfp.items[index].preloaded) { 37838 return; 37839 } 37840 37841 var item = mfp.items[index]; 37842 if(!item.parsed) { 37843 item = mfp.parseEl( index ); 37844 } 37845 37846 _mfpTrigger('LazyLoad', item); 37847 37848 if(item.type === 'image') { 37849 item.img = $('<img class="mfp-img" />').on('load.mfploader', function() { 37850 item.hasSize = true; 37851 }).on('error.mfploader', function() { 37852 item.hasSize = true; 37853 item.loadError = true; 37854 _mfpTrigger('LazyLoadError', item); 37855 }).attr('src', item.src); 37856 } 37857 37858 item.preloaded = true; 37859 } 37860 } 37861}); 37862 37863/* 37864Touch Support that might be implemented some day 37865 37866addSwipeGesture: function() { 37867 var startX, 37868 moved, 37869 multipleTouches; 37870 37871 return; 37872 37873 var namespace = '.mfp', 37874 addEventNames = function(pref, down, move, up, cancel) { 37875 mfp._tStart = pref + down + namespace; 37876 mfp._tMove = pref + move + namespace; 37877 mfp._tEnd = pref + up + namespace; 37878 mfp._tCancel = pref + cancel + namespace; 37879 }; 37880 37881 if(window.navigator.msPointerEnabled) { 37882 addEventNames('MSPointer', 'Down', 'Move', 'Up', 'Cancel'); 37883 } else if('ontouchstart' in window) { 37884 addEventNames('touch', 'start', 'move', 'end', 'cancel'); 37885 } else { 37886 return; 37887 } 37888 _window.on(mfp._tStart, function(e) { 37889 var oE = e.originalEvent; 37890 multipleTouches = moved = false;
37891 startX = oE.pageX || oE.changedTouches[0].pageX; 37892 }).on(mfp._tMove, function(e) { 37893 if(e.originalEvent.touches.length > 1) { 37894 multipleTouches = e.originalEvent.touches.length; 37895 } else { 37896 //e.preventDefault(); 37897 moved = true; 37898 } 37899 }).on(mfp._tEnd + ' ' + mfp._tCancel, function(e) { 37900 if(moved && !multipleTouches) { 37901 var oE = e.originalEvent, 37902 diff = startX - (oE.pageX || oE.changedTouches[0].pageX); 37903 37904 if(diff > 20) { 37905 mfp.next(); 37906 } else if(diff < -20) { 37907 mfp.prev(); 37908 } 37909 } 37910 }); 37911}, 37912*/ 37913 37914/*>>gallery*/ 37915 37916/*>>retina*/ 37917 37918var RETINA_NS = 'retina'; 37919 37920$.magnificPopup.registerModule(RETINA_NS, { 37921 options: { 37922 replaceSrc: function(item) { 37923 return item.src.replace(/\.\w+$/, function(m) { return '@2x' + m; }); 37924 }, 37925 ratio: 1 // Function or number. Set to 1 to disable. 37926 }, 37927 proto: { 37928 initRetina: function() { 37929 if(window.devicePixelRatio > 1) { 37930 37931 var st = mfp.st.retina, 37932 ratio = st.ratio; 37933 37934 ratio = !isNaN(ratio) ? ratio : ratio(); 37935 37936 if(ratio > 1) { 37937 _mfpOn('ImageHasSize' + '.' + RETINA_NS, function(e, item) { 37938 item.img.css({ 37939 'max-width': item.img[0].naturalWidth / ratio, 37940 'width': '100%' 37941 }); 37942 }); 37943 _mfpOn('ElementParse' + '.' + RETINA_NS, function(e, item) { 37944 item.src = st.replaceSrc(item, ratio); 37945 }); 37946 } 37947 } 37948 37949 } 37950 } 37951}); 37952 37953/*>>retina*/ 37954 37955/*>>fastclick*/ 37956/** 37957 * FastClick event implementation. (removes 300ms delay on touch devices) 37958 * Based on https://developers.google.com/mobile/articles/fast_buttons 37959 * 37960 * You may use it outside the Magnific Popup by calling just: 37961 * 37962 * $('.your-el').mfpFastClick(function() { 37963 * console.log('Clicked!'); 37964 * }); 37965 * 37966 * To unbind: 37967 * $('.your-el').destroyMfpFastClick(); 37968 * 37969 * 37970 * Note that it's a very basic and simple implementation, it blocks ghost click on the same element where it was bound. 37971 * If you need something more advanced, use plugin by FT Labs https://github.com/ftlabs/fastclick 37972 * 37973 */ 37974 37975(function() { 37976 var ghostClickDelay = 1000, 37977 supportsTouch = 'ontouchstart' in window, 37978 unbindTouchMove = function() { 37979 _window.off('touchmove'+ns+' touchend'+ns); 37980 }, 37981 eName = 'mfpFastClick', 37982 ns = '.'+eName; 37983 37984 // As Zepto.js doesn't have an easy way to add custom events (like jQuery), so we implement it in this way 37985 $.fn.mfpFastClick = function(callback) { 37986 37987 return $(this).each(function() { 37988 37989 var elem = $(this), 37990 lock; 37991 37992 if( supportsTouch ) { 37993 37994 var timeout, 37995 startX, 37996 startY, 37997 pointerMoved, 37998 point, 37999 numPointers; 38000 38001 elem.on('touchstart' + ns, function(e) { 38002 pointerMoved = false; 38003 numPointers = 1; 38004 38005 point = e.originalEvent ? e.originalEvent.touches[0] : e.touches[0]; 38006 startX = point.clientX; 38007 startY = point.clientY; 38008 38009 _window.on('touchmove'+ns, function(e) { 38010 point = e.originalEvent ? e.originalEvent.touches : e.touches; 38011 numPointers = point.length; 38012 point = point[0]; 38013 if (Math.abs(point.clientX - startX) > 10 || 38014 Math.abs(point.clientY - startY) > 10) { 38015 pointerMoved = true; 38016 unbindTouchMove(); 38017 } 38018 }).on('touchend'+ns, function(e) { 38019 unbindTouchMove(); 38020 if(pointerMoved || numPointers > 1) { 38021 return; 38022 } 38023 lock = true; 38024 e.preventDefault(); 38025 clearTimeout(timeout); 38026 timeout = setTimeout(function() { 38027 lock = false; 38028 }, ghostClickDelay); 38029 callback(); 38030 }); 38031 }); 38032 38033 } 38034 38035 elem.on('click' + ns, function() { 38036 if(!lock) { 38037 callback(); 38038 } 38039 }); 38040 }); 38041 }; 38042 38043 $.fn.destroyMfpFastClick = function() { 38044 $(this).off('touchstart' + ns + ' click' + ns); 38045 if(supportsTouch) _window.off('touchmove'+ns+' touchend'+ns); 38046 }; 38047})(); 38048 38049/*>>fastclick*/ 38050 _checkInstance(); })(window.jQuery || window.Zepto); 38051 /* Ende jquery.magnific-popup */ 38052 /* Start picturefill */ 38053 /*! Picturefill - v2.2.0 - 2014-10-30 38054 * http://scottjehl.github.io/picturefill 38055 * Copyright (c) 2014 https://github.com/scottjehl/picturefill/blob/master/Authors.txt; Licensed MIT */ 38056/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license */ 38057window.matchMedia || (window.matchMedia = function() { 38058 "use strict"; 38059 // For browsers that support matchMedium api such as IE 9 and webkit 38060 var styleMedia = (window.styleMedia || window.media); 38061 // For those that don't support matchMedium 38062 if (!styleMedia) { 38063 var style = document.createElement('style'), 38064 script = document.getElementsByTagName('script')[0], 38065 info = null; 38066 style.type = 'text/css'; 38067 style.id = 'matchmediajs-test'; 38068 script.parentNode.insertBefore(style, script); 38069 // 'style.currentStyle' is used by IE <= 8 and 'window.getComputedStyle' for all other browsers 38070 info = ('getComputedStyle' in window) && window.getComputedStyle(style, null) || style.currentStyle; 38071 styleMedia = { 38072 matchMedium: function(media) { 38073 var text = '@media ' + media + '{ #matchmediajs-test { width: 1px; } }'; 38074 // 'style.styleSheet' is used by IE <= 8 and 'style.textContent' for all other browsers 38075 if (style.styleSheet) { 38076 style.styleSheet.cssText = text; 38077 } else { 38078 style.textContent = text; 38079 } 38080 // Test if media query is true or false 38081 return info.width === '1px'; 38082 } 38083 }; 38084 } 38085 return function(media) { 38086 return { 38087 matches: styleMedia.matchMedium(media || 'all'), 38088 media: media || 'all' 38089 }; 38090 }; 38091}()); 38092/*! Picturefill - Responsive Images that work today. 38093 * Author: Scott Jehl, Filament Group, 2012 ( new proposal implemented by Shawn Jansepar ) 38094 * License: MIT/GPLv2 38095 * Spec: http://picture.responsiveimages.org/ 38096 */ 38097(function(w, doc, image) { 38098 // Enable strict mode 38099 "use strict"; 38100 // If picture is supported, well, that's awesome. Let's get outta here... 38101 if (w.HTMLPictureElement) { 38102 w.picturefill = function() {}; 38103 return; 38104 } 38105 // HTML shim|v it for old IE (IE9 will still need the HTML video tag workaround) 38106 doc.createElement("picture"); 38107 // local object for method references and testing exposure 38108 var pf = {}; 38109 // namespace 38110 pf.ns = "picturefill"; 38111 // srcset support test 38112 (function() { 38113 pf.srcsetSupported = "srcset" in image; 38114 pf.sizesSupported = "sizes" in image; 38115 })(); 38116 // just a string trim workaround 38117 pf.trim = function(str) { 38118 return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, ""); 38119 }; 38120 // just a string endsWith workaround
38121 pf.endsWith = function(str, suffix) { 38122 return str.endsWith ? str.endsWith(suffix) : str.indexOf(suffix, str.length - suffix.length) !== -1; 38123 }; 38124 /** 38125 * Shortcut method for https://w3c.github.io/webappsec/specs/mixedcontent/#restricts-mixed-content ( for easy overriding in tests ) 38126 */ 38127 pf.restrictsMixedContent = function() { 38128 return w.location.protocol === "https:"; 38129 }; 38130 /** 38131 * Shortcut method for matchMedia ( for easy overriding in tests ) 38132 */ 38133 pf.matchesMedia = function(media) { 38134 return w.matchMedia && w.matchMedia(media).matches; 38135 }; 38136 // Shortcut method for `devicePixelRatio` ( for easy overriding in tests ) 38137 pf.getDpr = function() { 38138 return (w.devicePixelRatio || 1); 38139 }; 38140 /** 38141 * Get width in css pixel value from a "length" value 38142 * http://dev.w3.org/csswg/css-values-3/#length-value 38143 */ 38144 pf.getWidthFromLength = function(length) { 38145 // If a length is specified and doesnât contain a percentage, and it is greater than 0 or using `calc`, use it. Else, use the `100vw` default. 38146 length = length && length.indexOf("%") > -1 === false && (parseFloat(length) > 0 || length.indexOf("calc(") > -1) ? length : "100vw"; 38147 /** 38148 * If length is specified in `vw` units, use `%` instead since the div weâre measuring 38149 * is injected at the top of the document. 38150 * 38151 * TODO: maybe we should put this behind a feature test for `vw`? 38152 */ 38153 length = length.replace("vw", "%"); 38154 // Create a cached element for getting length value widths 38155 if (!pf.lengthEl) { 38156 pf.lengthEl = doc.createElement("div"); 38157 // Positioning styles help prevent padding/margin/width on `html` or `body` from throwing calculations off. 38158 pf.lengthEl.style.cssText = "border:0;display:block;font-size:1em;
38158left:0;margin:0;padding:0;position:absolute;visibility:hidden"; 38159 } 38160 pf.lengthEl.style.width = length; 38161 doc.body.appendChild(pf.lengthEl); 38162 // Add a class, so that everyone knows where this element comes from 38163 pf.lengthEl.className = "helper-from-picturefill-js"; 38164 if (pf.lengthEl.offsetWidth <= 0) { 38165 // Something has gone wrong. `calc()` is in use and unsupported, most likely. Default to `100vw` (`100%`, for broader support.): 38166 pf.lengthEl.style.width = doc.documentElement.offsetWidth + "px"; 38167 } 38168 var offsetWidth = pf.lengthEl.offsetWidth; 38169 doc.body.removeChild(pf.lengthEl); 38170 return offsetWidth; 38171 }; 38172 // container of supported mime types that one might need to qualify before using 38173 pf.types = {}; 38174 // Add support for standard mime types 38175 pf.types["image/jpeg"] = true; 38176 pf.types["image/gif"] = true; 38177 pf.types["image/png"] = true; 38178 // test svg support 38179 pf.types["image/svg+xml"] = doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image", "1.1"); 38180 // test webp support, only when the markup calls for it 38181 pf.types["image/webp"] = function() { 38182 // based on Modernizr's lossless img-webp test 38183 // note: asynchronous 38184 var type = "image/webp"; 38185 image.onerror = function() { 38186 pf.types[type] = false; 38187 picturefill(); 38188 }; 38189 image.onload = function() { 38190 pf.types[type] = image.width === 1; 38191 picturefill(); 38192 }; 38193 image.src = "data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA="; 38194 }; 38195 /** 38196 * Takes a source element and checks if its type attribute is present and if so, supported 38197 * Note: for type tests that require a async logic, 38198 * you can define them as a function that'll run only if that type needs to be tested. Just make the test function call picturefill again when it is complete. 38199 * see the async webp test above for example 38200 */ 38201 pf.verifyTypeSupport = function(source) { 38202 var type = source.getAttribute("type"); 38203 // if type attribute exists, return test result, otherwise return true 38204 if (type === null || type === "") { 38205 return true; 38206 } else { 38207 // if the type test is a function, run it and return "pending" status. The function will rerun picturefill on pending elements once finished. 38208 if (typeof(pf.types[type]) === "function") { 38209 pf.types[type](); 38210 return "pending"; 38211 } else { 38212 return pf.types[type]; 38213 } 38214 } 38215 }; 38216 // Parses an individual `size` and returns the length, and optional media query 38217 pf.parseSize = function(sourceSizeStr) { 38218 var match = /(\([^)]+\))?\s*(.+)/g.exec(sourceSizeStr); 38219 return { 38220 media: match && match[1], 38221 length: match && match[2] 38222 }; 38223 }; 38224 // Takes a string of sizes and returns the width in pixels as a number 38225 pf.findWidthFromSourceSize = function(sourceSizeListStr) { 38226 // Split up source size list, ie ( max-width: 30em ) 100%, ( max-width: 50em ) 50%, 33% 38227 // or (min-width:30em) calc(30% - 15px) 38228 var sourceSizeList = pf.trim(sourceSizeListStr).split(/\s*,\s*/), 38229 winningLength; 38230 for (var i = 0, len = sourceSizeList.length; i < len; i++) { 38231 // Match <media-condition>? length, ie ( min-width: 50em ) 100% 38232 var sourceSize = sourceSizeList[i], 38233 // Split "( min-width: 50em ) 100%" into separate strings 38234 parsedSize = pf.parseSize(sourceSize), 38235 length = parsedSize.length, 38236 media = parsedSize.media; 38237 if (!length) { 38238 continue; 38239 } 38240 if (!media || pf.matchesMedia(media)) { 38241 // if there is no media query or it matches, choose this as our winning length 38242 // and end algorithm 38243 winningLength = length; 38244 break; 38245 } 38246 } 38247 // pass the length to a method that can properly determine length 38248 // in pixels based on these formats: http://dev.w3.org/csswg/css-values-3/#length-value 38249 return pf.getWidthFromLength(winningLength); 38250 }; 38251 pf.parseSrcset = function(srcset) { 38252 /** 38253 * A lot of this was pulled from Boris Smusâ parser for the now-defunct WHATWG `srcset` 38254 * https://github.com/borismus/srcset-polyfill/blob/master/js/sr
38254cset-info.js 38255 * 38256 * 1. Let input (`srcset`) be the value passed to this algorithm. 38257 * 2. Let position be a pointer into input, initially pointing at the start of the string. 38258 * 3. Let raw candidates be an initially empty ordered list of URLs with associated 38259 * unparsed descriptors. The order of entries in the list is the order in which entries 38260 * are added to the list. 38261 */ 38262 var candidates = []; 38263 while (srcset !== "") { 38264 srcset = srcset.replace(/^\s+/g, ""); 38265 // 5. Collect a sequence of characters that are not space characters, and let that be url. 38266 var pos = srcset.search(/\s/g), 38267 url, descriptor = null; 38268 if (pos !== -1) { 38269 url = srcset.slice(0, pos); 38270 var last = url.slice(-1); 38271 // 6. If url ends with a U+002C COMMA character (,), remove that character from url 38272 // and let descriptors be the empty string. Otherwise, follow these substeps 38273 // 6.1. If url is empty, then jump to the step labeled descriptor parser. 38274 if (last === "," || url === "") { 38275 url = url.replace(/,+$/, ""); 38276 descriptor = ""; 38277 } 38278 srcset = srcset.slice(pos + 1); 38279 // 6.2. Collect a sequence of characters that are not U+002C COMMA characters (,), and 38280 // let that be descriptors. 38281 if (descriptor === null) { 38282 var descpos = srcset.indexOf(","); 38283 if (descpos !== -1) { 38284 descriptor = srcset.slice(0, descpos); 38285 srcset = srcset.slice(descpos + 1); 38286 } else { 38287 descriptor = srcset; 38288 srcset = ""; 38289 } 38290 } 38291 } else { 38292 url = srcset; 38293 srcset = ""; 38294 } 38295 // 7. Add url to raw candidates, associated with descriptors. 38296 if (url || descriptor) { 38297 candidates.push({ 38298 url: url, 38299 descriptor: descriptor 38300 }); 38301 } 38302 } 38303 return candidates; 38304 }; 38305 pf.parseDescriptor = function(descriptor, sizesattr) { 38306 // 11. Descriptor parser: Let candidates be an initially empty source set. The order of entries in the list 38307 // is the order in which entries are added to the list. 38308 var sizes = sizesattr || "100vw", 38309 sizeDescriptor = descriptor && descriptor.replace(/(^\s+|\s+$)/g, ""), 38310 widthInCssPixels = pf.findWidthFromSourceSize(sizes), 38311 resCandidate; 38312 if (sizeDescriptor) { 38313 var splitDescriptor = sizeDescriptor.split(" "); 38314 for (var i = splitDescriptor.length - 1; i >= 0; i--) { 38315 var curr = splitDescriptor[i], 38316 lastchar = curr && curr.slice(curr.length - 1); 38317 if ((lastchar === "h" || lastchar === "w") && !pf.sizesSupported) { 38318 resCandidate = parseFloat((parseInt(curr, 10) / widthInCssPixels)); 38319 } else if (lastchar === "x") { 38320 var res = curr && parseFloat(curr, 10); 38321 resCandidate = res && !isNaN(res) ? res : 1; 38322 } 38323 } 38324 } 38325 return resCandidate || 1; 38326 }; 38327 /** 38328 * Takes a srcset in the form of url/ 38329 * ex. "images/pic-medium.png 1x, images/pic-medium-2x.png 2x" or 38330 * "images/pic-medium.png 400w, images/pic-medium-2x.png 800w" or 38331 * "images/pic-small.png" 38332 * Get an array of image candidates in the form of 38333 * {url: "/foo/bar.png", resolution: 1} 38334 * where resolution is http://dev.w3.org/csswg/css-values-3/#resolution-value 38335 * If sizes is specified, resolution is calculated 38336 */ 38337 pf.getCandidatesFromSourceSet = function(srcset, sizes) { 38338 var candidates = pf.parseSrcset(srcset), 38339 formattedCandidates = []; 38340 for (var i = 0, len = candidates.length; i < len; i++) { 38341 var candidate = candidates[i]; 38342 formattedCandidates.push({ 38343 url: candidate.url, 38344 resolution: pf.parseDescriptor(candidate.descriptor, sizes) 38345 }); 38346 } 38347 return formattedCandidates; 38348 }; 38349 /** 38350 * if it's an img element and it has a srcset property, 38351 * we need to remove the attribute so we can manipulate src 38352 * (the property's existence infers native srcset support, and a srcset-supporting browser will prioritize srcset's value over our winning picture candidate) 38353 * this moves srcset's value to memory for later use and removes the attr 38354 */ 38355 pf.dodgeSrcset = function(img) { 38356 if (img.srcset) { 38357 img[pf.ns].srcset = img.srcset; 38358 img.removeAttribute("srcset"); 38359 } 38360 }; 38361 // Accept a source or img element and process its srcset and sizes attrs 38362 pf.processSourceSet = function(el) { 38363 var srcset = el.getAttribute("srcset"), 38364 sizes = el.getAttribute("sizes"), 38365 candidates = []; 38366 // if it's an img element, use the cached srcset property (defined or not)
38367 if (el.nodeName.toUpperCase() === "IMG" && el[pf.ns] && el[pf.ns].srcset) { 38368 srcset = el[pf.ns].srcset; 38369 } 38370 if (srcset) { 38371 candidates = pf.getCandidatesFromSourceSet(srcset, sizes); 38372 } 38373 return candidates; 38374 }; 38375 pf.applyBestCandidate = function(candidates, picImg) { 38376 var candidate, 38377 length, 38378 bestCandidate; 38379 candidates.sort(pf.ascendingSort); 38380 length = candidates.length; 38381 bestCandidate = candidates[length - 1]; 38382 for (var i = 0; i < length; i++) { 38383 candidate = candidates[i]; 38384 if (candidate.resolution >= pf.getDpr()) { 38385 bestCandidate = candidate; 38386 break; 38387 } 38388 } 38389 if (bestCandidate && !pf.endsWith(picImg.src, bestCandidate.url)) { 38390 if (pf.restrictsMixedContent() && bestCandidate.url.substr(0, "http:".length).toLowerCase() === "http:") { 38391 if (typeof console !== undefined) { 38392 console.warn("Blocked mixed content image " + bestCandidate.url); 38393 } 38394 } else { 38395 picImg.src = bestCandidate.url; 38396 // currentSrc attribute and property to match 38397 // http://picture.responsiveimages.org/#the-img-element 38398 picImg.currentSrc = picImg.src; 38399 var style = picImg.style || {}, 38400 WebkitBackfaceVisibility = "webkitBackfaceVisibility" in style, 38401 currentZoom = style.zoom; 38402 if (WebkitBackfaceVisibility) { // See: https://github.com/scottjehl/picturefill/issues/332 38403 style.zoom = ".999"; 38404 WebkitBackfaceVisibility = picImg.offsetWidth; 38405 style.zoom = currentZoom; 38406 } 38407 } 38408 } 38409 }; 38410 pf.ascendingSort = function(a, b) { 38411 return a.resolution - b.resolution; 38412 }; 38413 /** 38414 * In IE9, <source> elements get removed if they aren't children of 38415 * video elements. Thus, we conditionally wrap source elements 38416 * using <!--[if IE 9]><video style="display: none;"><![endif]--> 38417 * and must account for that here by moving those source elements 38418 * back into the picture element. 38419 */ 38420 pf.removeVideoShim = function(picture) { 38421 var videos = picture.getElementsByTagName("video"); 38422 if (videos.length) { 38423 var video = videos[0], 38424 vsources = video.getElementsByTagName("source"); 38425 while (vsources.length) { 38426 picture.insertBefore(vsources[0], video); 38427 } 38428 // Remove the video element once we're finished removing its children 38429 video.parentNode.removeChild(video); 38430 } 38431 }; 38432 /** 38433 * Find all `img` elements, and add them to the candidate list if they have 38434 * a `picture` parent, a `sizes` attribute in basic `srcset` supporting browsers, 38435 * a `srcset` attribute at all, and they havenât been evaluated already. 38436 */ 38437 pf.getAllElements = function() { 38438 var elems = [], 38439 imgs = doc.getElementsByTagName("img"); 38440 for (var h = 0, len = imgs.length; h < len; h++) { 38441 var currImg = imgs[h]; 38442 if (currImg.parentNode.nodeName.toUpperCase() === "PICTURE" || 38443 (currImg.getAttribute("srcset") !== null) || currImg[pf.ns] && currImg[pf.ns].srcset !== null) { 38444 elems.push(currImg); 38445 } 38446 } 38447 return elems; 38448 }; 38449 pf.getMatch = function(img, picture) { 38450 var sources = picture.childNodes, 38451 match; 38452 // Go through each child, and if they have media queries, evaluate them 38453 for (var j = 0, slen = sources.length; j < slen; j++) { 38454 var source = sources[j]; 38455 // ignore non-element nodes 38456 if (source.nodeType !== 1) { 38457 continue; 38458 } 38459 // Hitting the `img` element that started everything stops the search for `sources`. 38460 // If no previous `source` matches, the `img` itself is evaluated later. 38461 if (source === img) { 38462 return match; 38463 } 38464 // ignore non-`source` nodes 38465 if (source.nodeName.toUpperCase() !== "SOURCE") { 38466 continue; 38467 } 38468 // if it's a source element that has the `src` property set, throw a warning in the console 38469 if (source.getAttribute("src") !== null && typeof console !== undefined) {
38470 console.warn("The `src` attribute is invalid on `picture` `source` element; instead, use `srcset`."); 38471 } 38472 var media = source.getAttribute("media"); 38473 // if source does not have a srcset attribute, skip 38474 if (!source.getAttribute("srcset")) { 38475 continue; 38476 } 38477 // if there's no media specified, OR w.matchMedia is supported 38478 if ((!media || pf.matchesMedia(media))) { 38479 var typeSupported = pf.verifyTypeSupport(source); 38480 if (typeSupported === true) { 38481 match = source; 38482 break; 38483 } else if (typeSupported === "pending") { 38484 return false; 38485 } 38486 } 38487 } 38488 return match; 38489 }; 38490 function picturefill(opt) { 38491 var elements, 38492 element, 38493 parent, 38494 firstMatch, 38495 candidates, 38496 options = opt || {}; 38497 elements = options.elements || pf.getAllElements(); 38498 // Loop through all elements 38499 for (var i = 0, plen = elements.length; i < plen; i++) { 38500 element = elements[i]; 38501 parent = element.parentNode; 38502 firstMatch = undefined; 38503 candidates = undefined; 38504 // immediately skip non-`img` nodes 38505 if (element.nodeName.toUpperCase() !== "IMG") { 38506 continue; 38507 } 38508 // expando for caching data on the img 38509 if (!element[pf.ns]) { 38510 element[pf.ns] = {}; 38511 } 38512 // if the element has already been evaluated, skip it unless 38513 // `options.reevaluate` is set to true ( this, for example, 38514 // is set to true when running `picturefill` on `resize` ). 38515 if (!options.reevaluate && element[pf.ns].evaluated) { 38516 continue; 38517 } 38518 // if `img` is in a `picture` element 38519 if (parent.nodeName.toUpperCase() === "PICTURE") { 38520 // IE9 video workaround 38521 pf.removeVideoShim(parent); 38522 // return the first match which might undefined 38523 // returns false if there is a pending source 38524 // TODO the return type here is brutal, cleanup 38525 firstMatch = pf.getMatch(element, parent); 38526 // if any sources are pending in this picture due to async type test(s) 38527 // remove the evaluated attr and skip for now ( the pending test will 38528 // rerun picturefill on this element when complete) 38529 if (firstMatch === false) { 38530 continue; 38531 } 38532 } else { 38533 firstMatch = undefined; 38534 } 38535 // Cache and remove `srcset` if present and weâre going to be doing `picture`/`srcset`/`sizes` polyfilling to it. 38536 if (parent.nodeName.toUpperCase() === "PICTURE" || 38537 (element.srcset && !pf.srcsetSupported) || 38538 (!pf.sizesSupported && (element.srcset && element.srcset.indexOf("w") > -1))) { 38539 pf.dodgeSrcset(element); 38540 } 38541 if (firstMatch) { 38542 candidates = pf.processSourceSet(firstMatch); 38543 pf.applyBestCandidate(candidates, element); 38544 } else { 38545 // No sources matched, so weâre down to processing the inner `img` as a source. 38546 candidates = pf.processSourceSet(element); 38547 if (element.srcset === undefined || element[pf.ns].srcset) { 38548 // Either `srcset` is completely unsupported, or we need to polyfill `sizes` functionality. 38549 pf.applyBestCandidate(candidates, element); 38550 } // Else, resolution-only `srcset` is supported natively. 38551 } 38552 // set evaluated to true to avoid unnecessary reparsing 38553 element[pf.ns].evaluated = true; 38554 } 38555 } 38556 /** 38557 * Sets up picture polyfill by polling the document and running 38558 * the polyfill every 250ms until the document is ready. 38559 * Also attaches picturefill on resize 38560 */ 38561 function runPicturefill() { 38562 picturefill(); 38563 var intervalId = setInterval(function() { 38564 // When the document has finished loading, stop checking for new images 38565 // https://github.com/ded/domready/blob/master/ready.js#L15 38566 picturefill(); 38567 if (/^loaded|^i|^c/.test(doc.readyState)) { 38568 clearInterval(intervalId); 38569 return; 38570 } 38571 }, 250); 38572 function checkResize() { 38573 var resizeThrottle; 38574 if (!w._picturefillWorking) { 38575 w._picturefillWorking = true; 38576 w.clearTimeout(resizeThrottle); 38577 resizeThrottle = w.setTimeout(function() { 38578 picturefill({ 38579 reevaluate: true 38580 }); 38581 w._picturefillWorking = false;
38582 }, 60); 38583 } 38584 } 38585 if (w.addEventListener) { 38586 w.addEventListener("resize", checkResize, false); 38587 } else if (w.attachEvent) { 38588 w.attachEvent("onresize", checkResize); 38589 } 38590 } 38591 runPicturefill(); 38592 /* expose methods for testing */ 38593 picturefill._ = pf; 38594 /* expose picturefill */ 38595 if (typeof module === "object" && typeof module.exports === "object") { 38596 // CommonJS, just export 38597 module.exports = picturefill; 38598 } else if (typeof define === "function" && define.amd) { 38599 // AMD support 38600 define(function() { 38601 return picturefill; 38602 }); 38603 } else if (typeof w === "object") { 38604 // If no AMD and we are in the browser, attach to window 38605 w.picturefill = picturefill; 38606 } 38607})(this, this.document, new this.Image()); 38608 38609 /* Ende picturefill */ 38610 /* Start navigationUtils */ 38611 function NavigationUtils() { 38612 38613 /** 38614 * HTML des overlays 38615 * @static 38616 */ 38617 NavigationUtils.prototype.overlay; 38618 38619 /** 38620 * HTML der Suche 38621 * @static 38622 */ 38623 NavigationUtils.prototype.search; 38624 38625 NavigationUtils.prototype.scrollingElements = function (menu, base) { 38626 menu.find(base.options.scrollLayer + ' a,' + base.options.scrollLayer + ' strong').not('.no-subnavigation a, .no-subnavigation strong').each(function () { 38627 var currentScrollNode = $(this); 38628 38629 if (currentScrollNode.parent().is('em')) { 38630 if (currentScrollNode.parent().parent().siblings('ul').length > 0) { 38631 currentScrollNode.addClass('has-childs'); 38632 } 38633 } else if (currentScrollNode.parent().siblings('ul').length > 0) { 38634 currentScrollNode.addClass('has-childs'); 38635 } 38636 }); 38637 }; 38638 38639 NavigationUtils.prototype.addScollingLinks = function (menu, base, device) { 38640 //Ab welcher Ebene kann gescrollt werden 38641 menu.find(base.options.scrollLayer).not('.no-subnavigation').addClass('scrollFunction'); 38642 38643 //Seitenlinks einfügen 38644 menu.find(base.options.scrollLayer + ' ul').not('.no-subnavigation').each(function () { 38645 38646 var currentUl = $(this); 38647 38648 var image = '<img src="' + base.options.backButtonImage + '" alt="' + base.options.backButtonAlt + '"/>'; 38649 currentUl.addClass('inactive'); 38650 38651 var upToImage = '<img src="' + base.options.backToFirstImage + '" alt="' + base.options.backToFirstAlt + '"/>'; 38652 if (device == 'desktop') { 38653 currentUl.prepend('<li class="back"><button>' + image + '<span>' + currentUl.closest('li').find('.has-childs').first().text() + '</span></button></li>'); 38654 currentUl.prepend('<li class="backToFirst"><button>' + upToImage + '<span>' + $(this).closest('.menu').siblings('h3').find('a, strong').text() + '</span></button></li>'); 38655 } else { 38656 currentUl.prepend('<li class="back"><button>' + image + '<span>' + currentUl.closest('li').find('.has-childs').first().text() + '</span></button></li>'); 38657 currentUl.prepend('<li class="backToFirst"><button>' + upToImage + '<span>' + $(this).closest('.level-2').find('.has-childs').first().text() + '</span></button></li>'); 38658 } 38659 }); 38660 }; 38661 38662 // Getter und setter 38663 38664 NavigationUtils.prototype.setOverlay = function (elem) { 38665 NavigationUtils.overlay = elem; 38666 }; 38667 38668 NavigationUtils.prototype.getOverlay = function () { 38669 return NavigationUtils.overlay; 38670 }; 38671 38672 NavigationUtils.prototype.setSearch = function (elem) { 38673 NavigationUtils.search = elem; 38674 }; 38675 38676 NavigationUtils.prototype.getSearch = function () { 38677 return NavigationUtils.search; 38678 }; 38679} 38680 /* Ende navigationUtils */ 38681 /* Start gsb_autosuggest */ 38682 /*! 38683 * GSB-Plugin zur Darstellung von Suchvorschlaegen 38684 * 38685 * Optionen: 38686 * minInputLength: Ab wieviel eingegebenen Zeichen werden Vorschlaege ausgegeben (optional (default: 2)) 38687 * 38688 * Author: gsb 38689 */ 38690 38691;(function ($) { 38692 if (!$.gsb) { 38693 $.gsb = {}; 38694 } 38695 $.gsb.AutoSuggestBoxCounter = 1; 38696 $.gsb.AutoSuggest = function (el, actionUrl, options) { 38697 var base = this; 38698 // Access to jQuery and DOM versions of element 38699 base.$el = $(el); 38700 base.el = el; 38701 38702 // BoxCounter 38703 base.boxNumber = $.gsb.AutoSuggestBoxCounter++; 38704 // Such-Textfeld 38705 base.$input = base.$el.find('input[type=text]:first'); 38706 base.$submit = base.$el.find('input[type=submit]:first'); 38707 if (base.$submit.length == 0) { 38708 base.$submit = base.$el.find('input[type=image]:first'); 38709 } 38710 // Add a reverse reference to the DOM object 38711 base.$el.data("gsb.AutoSuggest", base); 38712 // Aktuelle Anfrage 38713 base.reqQuery = false;
38714 // Anfragen Cachen 38715 base.queries = []; 38716 38717 // Aktuelle Position 38718 base.enterPos = -1; 38719 38720 // Debug-Mode 38721 base.debug = false; 38722 38723 /** 38724 * Intialisierung 38725 */ 38726 base.init = function (options) { 38727 base.actionUrl = actionUrl; 38728 base.options = $.extend({}, $.gsb.AutoSuggest.defaultOptions, options); 38729 38730 // AutoSuggest-Box vorbereiten und positionieren 38731 var positions = base.$input.position(); 38732 base.$box = $('<p id="searchAutoSuggestBox' + base.boxNumber + '" class="searchAutoSuggestBox"></p>'); 38733 base.$box.css({ 38734 'width': base.$input.outerWidth() - 2 + 'px', // 2px Border 38735 'top': positions.top + base.$input.outerHeight() + 'px', 38736 'left': positions.left + 'px' 38737 }); 38738 base.$box.hide(); 38739 38740 $(window).resize(function () { 38741 positions = base.$input.position(); 38742 base.$box.css({ 38743 'top': positions.top + base.$input.outerHeight() + 'px', 38744 'left': positions.left + 'px' 38745 }); 38746 }); 38747 38748 // Browser-Auto-Vervollständigung deaktivieren 38749 base.$input.attr('autocomplete', 'off'); 38750 38751 // Tastaturbefehle abfangen 38752 // Nicht mit jQuery, da alte Version dies noch nicht kann 38753 base.$input.get(0).onkeydown = function (e) { 38754 e = e || window.event; 38755 if (e) { 38756 var code = e.keyCode != undefined && null != e.keyCode ? e.keyCode : e.which; 38757 if (code == 13) return base.keydownEnter(); // Enter 38758 else if (code == 38) return base.keydownUp(); // UpArrow 38759 else if (code == 40) return base.keydownDown(); // DownArrow 38760 } 38761 }; 38762 38763 // Bei Eingabe von mehr als zwei Zeichen Liste abrufen 38764 // Nicht mit jQuery, da alte Version dies noch nicht kann 38765 base.$input.get(0).onkeyup = function (e) { 38766 var go = false; 38767 e = e || window.event; 38768 if (e) { 38769 var code = e.keyCode != undefined && null != e.keyCode ? e.keyCode : e.which; 38770 if (code != 13 && code != 38 && code != 40) { 38771 go = true; 38772 } 38773 } else { 38774 go = true; 38775 } 38776 38777 if (go) { 38778 if (base.$input.val().length >= base.options.minInputLength) { 38779 base.query(base.$input.val()); 38780 } else { 38781 base.showSuggestionBox(false); 38782 } 38783 } 38784 }; 38785 38786 //base.$input.parents('p:first').css('position', 'relative'); 38787 base.$input.after(base.$box); 38788 38789 base.$box = base.$el.find('#searchAutoSuggestBox' + base.boxNumber); 38790 38791 // Beim Defokussieren AutoSuggestbox schlieÃen 38792 base.$input.bind('blur', function () { 38793 base.showSuggestionBox(false); 38794 }); 38795 }; 38796 38797 /** 38798 * Anfrage stellen 38799 */ 38800 base.query = function (value) { 38801 base.reqQuery = value; 38802 if (typeof base.queries[base.reqQuery] == "undefined") { 38803 if (base.debug && typeof console != "undefined" && console && console.log) console.log('AutoSuggest-AJAX-Anfrage für "' + base.reqQuery + '"'); 38804 $.ajax({ 38805 url: base.actionUrl, 38806 dataType: 'json', 38807 data: { 'userQuery': value }, 38808 error: function error(jqXHR, textStatus, errorThrown) { 38809 if (base.debug && typeof console != "undefined" && console && console.log) console.log('AJAX Fehler beim Abruf der JSON-Resource ' + base.actionUrl + ': ' + textStatus + ' :: ' + errorThrown); 38810 }, 38811 success: function success(data) { 38812 base.queries[value] = data.suggestions; 38813 if (base.reqQuery == value) { 38814 if (base.debug && typeof console != "undefined" && console && console.log) console.log('AJAX-Antwort für "' + base.reqQuery + '" wird nun verarbeitet...'); 38815 if (base.debug && typeof console != "undefined" && console && console.log) console.log(data); 38816 base.showSuggestions(data.suggestions); 38817 } else { 38818 if (base.debug && typeof console != "undefined" && console && console.log) console.log('AJAX-Antwort für "' + base.reqQuery + '" ist nicht mehr relevant...'); 38819 } 38820 } 38821 }); 38822 } else { 38823 base.showSuggestions(base.queries[base.reqQuery]); 38824 } 38825 }; 38826 38827 /** 38828 * Vorschläge anzeigen 38829 */ 38830 base.showSuggestions = function (suggestions) { 38831 base.$box.empty(); 38832 var count = 0; 38833 for (var s in suggestions) { 38834 if (suggestions.hasOwnProperty(s) && suggestions[s].name) { 38835 var $link = $('<a href="#"></a>'); 38836 $link.html(suggestions[s].name + '<em>' + suggestions[s].count + '</em>'); 38837 $link.click(function (e) { 38838 e.preventDefault(); 38839 $(this).find('em').remove(); 38840 base.$input.val($(this).text()); 38841 base.$submit.click(); 38842 }); 38843 $link.appendTo(base.$box); 38844 count++; 38845 } 38846 } 38847 if (count > 0) base.showSuggestionBox(true);else base.showSuggestionBox(false); 38848 }; 38849 38850 /** 38851 * Suggestionbox ein/ausblenden 38852 */ 38853 base.showSuggestionBox = function (show) { 38854 base.enterPos = -1; 38855 if (show) { 38856 base.$box.fadeIn('fast'); 38857 } else { 38858 base.$box.fadeOut('fast'); 38859 } 38860 }; 38861 38862 /** 38863 * KeyDown: Runter 38864 */ 38865 base.keydownDown = function () { 38866 if (base.debug && typeof console != "undefined" && console && console.log) console.log('KEYDOWN down'); 38867 38868 if (base.enterPos < 0 && base.$box.find('a').length > 0) { 38869 base.$box.find('a').removeClass('active'); 38870 base.enterPos = 0; 38871 $(base.$box.find('a')[base.enterPos]).addClass('active'); 38872 } else if (base.enterPos < base.$box.find('a').length - 1) { 38873 base.$box.find('a').removeClass('active'); 38874 base.enterPos++; 38875 $(base.$box.find('a')[base.enterPos]).addClass('active'); 38876 } 38877 }; 38878 38879 /** 38880 * KeyDown: Hoch 38881 */ 38882 base.keydownUp = function () { 38883 if (base.debug && typeof console != "undefined" && console && console.log) console.log('KEYDOWN up'); 38884 38885 if (base.enterPos < 0 && base.$box.find('a').length > 0) { 38886 base.$box.find('a').removeClass('active'); 38887 base.enterPos = base.$box.find('a').length - 1; 38888 $(base.$box.find('a')[base.enterPos]).addClass('active'); 38889 } else if (base.enterPos > 0) { 38890 base.$box.find('a').removeClass('active'); 38891 base.enterPos--; 38892 $(base.$box.find('a')[base.enterPos]).addClass('active'); 38893 } 38894 }; 38895 38896 /** 38897 * KeyDown: Enter 38898 */ 38899 base.keydownEnter = function () { 38900 if (base.debug && typeof console != "undefined" && console && console.log) console.log('KEYDOWN enter'); 38901 if (base.enterPos >= 0 && base.$box.find('a').length > base.enterPos) { 38902 base.$box.find('a')[base.enterPos].click(); 38903 return false;
38904 } 38905 }; 38906 // Run initializer 38907 base.init(options); 38908 }; 38909 38910 /** 38911 * Die Standard-Optionen fuer das Plugin 38912 */ 38913 $.gsb.AutoSuggest.defaultOptions = { 38914 minInputLength: 2 38915 }; 38916 38917 $.fn.gsb_AutoSuggest = function (actionUrl, options) { 38918 return this.each(function () { 38919 new $.gsb.AutoSuggest(this, actionUrl, options); 38920 }); 38921 }; 38922})(jQuery); 38923 /* Ende gsb_autosuggest */ 38924 /* Start gsb_banner */ 38925 /** 38926 * --GSBDocStart 38927 * @module gsb_banner 38928 * @version 1.5.3 38929 * - 1.3.0 jelseber Hinzufügen der Option und Funktion positionRelative, wenn oben platziert werden Banner relativ platziert, wenn unten dann absolute mit Platzhalter 38930 * - 1.3.1 jelseber Bei positionRelative wird das Banner im DOM nach den Sprunglinks (ul.navSkip) eingebunden, damit die Sprunglinks als erstes angetabbt werden können 38931 * - 1.3.2 rkrusenb positionRelative-Animation für "bottom"-Fall gefixt 38932 * - 1.4.0 rkrusenb Option 'matomoButtons' hinzugefügt 38933 * - 1.5.0 rkrusenb Opt-In mit GSB-eigenem Cookie fuer Matomo Tracking 38934 * - 1.5.1 rkrusenb Ein/Ausschalter fuer die Datenschutz-Seite 38935 * - 1.5.2 rkrusenb Workaround - Mehrfach-Animationen auf mobilen Geräten abkürzen 38936 * - 1.5.3 rkrusenb Option 'scriptUrl' hinzugefügt 38937 * 38938 * @see {@link http://semver.org|Semantic Versioning} 38939 * @author boelenbe 38940 * 38941 * @desc Banner-Box - Dieses Modul ermöglicht die Darstellung einer Information in Form eines Popup-Banner, 38942 * welches sich animiert ein- und ausgeblendet. Dieser Banner stellt eine Ãberschrift, einen Linktext sowie ein Bild, 38943 * die aus einem Textbaustein (TextFragment) ausgelesen werden, dar. Beim erstmaligen Aufrufen der Seite mit 38944 * konfiguriertem Banner wird dieser animiert im unteren Bildschirmbereich eingeblendet. 38945 * 38946 * @example 38947 * <div id="cookiebanner" class="cookiebanner top" data-position="top" data-animation="true"> 38948 * <div class="cookiebannerbox"> 38949 * <div> 38950 * <div class="text"> 38951 * </div> 38952 * </div> 38953 * </div> 38954 * </div> 38955 * 38956 * @init 38957 * $('#cookiebanner').gsb_banner({ 38958 * animation: $('#cookiebanner').data('animation'), 38959 * position: $('#cookiebanner').data('position'), 38960 * cookieName: 'cookiebanner', 38961 * cookieLifeTimeInDaysClosed: 30 38962 * }); 38963 *--GSBDocEnd 38964 */ 38965var _paq = _paq || []; 38966;(function ($) { 38967 'use strict'; 38968 38969 if (!$.gsb) { 38970 $.gsb = {}; 38971 } 38972 /** 38973 * Initialisiert die Banner-Box 38974 * @param {DOM} el DOM-Banner-Element 38975 * @param {options} options JSON-Objekt zum überschreiben der Default-Options 38976 */ 38977 $.gsb.banner = function gsbBanner(el, options) { 38978 // To avoid scope issues, use 'base' instead of 'this' 38979 // to reference this class from internal events and functions. 38980 var base = Object.create(gsbBanner.prototype); 38981 // Access to $ and DOM versions of element 38982 base.$el = $(el); 38983 base.el = el; 38984 base.options = $.extend(true, {}, $.gsb.banner.defaultOptions, options); 38985 // Add a reverse reference to the DOM object 38986 base.$el.data('gsb.banner', base); 38987 38988 // Run initializer 38989 base.init(); 38990 }; 38991 $.gsb.banner.prototype = { 38992 38993 init: function init() { 38994 var base = this; 38995 gsb.log('gsb_banner.init()'); 38996 base.addMatomo(); 38997 base.createBanner(); 38998 base.$el.gsb_responsiveListener(base); 38999 }, 39000 39001 addMatomoFormListeners: function addMatomoFormListeners() { 39002 var base = this, 39003 container = $('#matomoTracking'), 39004 enable = container.find('[name=matomoTracking][value=true]'), 39005 disable = container.find('[name=matomoTracking][value=false]'); 39006 if (Cookies.get('matomoTracking')) { 39007 enable.prop('checked', true); 39008 } else { 39009 disable.prop('checked', true); 39010 } 39011 enable.on('click', base, base.matomoConsent); 39012 disable.on('click', base, base.matomoReject); 39013 }, 39014 39015 show: function show() { 39016 var base = this, 39017 animationSpeed = base.options.animationSpeed; 39018 gsb.log('show banner position=' + base.options.position); 39019 if (base.options.positionRelative) { 39020 base.showPositionRelative(); 39021 } else if (base.options.animation) { 39022 if (base.options.position === 'top') { 39023 base.$el.animate({ top: 0 }, animationSpeed); 39024 } else { 39025 base.$el.animate({ bottom: 0 }, animationSpeed); 39026 } 39027 } else { 39028 base.$el.css(base.options.position, 0); 39029 } 39030 base.$el.promise().done(function () { 39031 $('body').addClass(base.options.bodyVisibleClass).removeClass(base.options.bodyHiddenClass); 39032 }); 39033 }, 39034 39035 showPositionRelative: function showPositionRelative() { 39036 var base = this; 39037 if (base.options.position === 'top') { 39038 base.$el.addClass(base.options.positionRelativeClass);
39039 var $navSkipList = $(base.options.navSkipListSelector); 39040 if ($navSkipList.length > 0) { 39041 $navSkipList.after(base.$el); 39042 } else { 39043 console.warn('Das Cookiebanner wird vor der navSkip Liste eingebunden weil \'' + base.options.selectors.navSkipList + '\' nicht gefunden werden konnte.'); 39044 $('header').before(base.$el); 39045 } 39046 } else { 39047 $('footer').after(base.$el); 39048 $('.' + base.options.positionRelativePlaceholderClass).remove(); 39049 $('footer').after($('<div>').addClass(base.options.positionRelativePlaceholderClass).css('height', base.bannerHeight)); 39050 } 39051 if (base.options.animation) { 39052 base.$el.finish().css({ 39053 paddingTop: 0, 39054 paddingBottom: 0, 39055 height: 0 39056 }).animate({ 39057 height: base.bannerHeight - base.options.topOffset, 39058 paddingTop: base.bannerPadding.top, 39059 paddingBottom: base.bannerPadding.bottom 39060 }, { 39061 duration: base.options.animationSpeed, 39062 complete: function complete() { 39063 base.$el.css('height', ''); 39064 } 39065 }); 39066 } 39067 }, 39068 39069 hide: function hide(ignoreAnimation) { 39070 var base = this; 39071 if (base.bannerHeight && base.options.animation && !ignoreAnimation) { 39072 if (base.options.position === 'top') { 39073 if (base.options.positionRelative) { 39074 base.$el.animate({ height: 0, paddingTop: 0, paddingBottom: 0 }, base.options.animationSpeed, function () { 39075 base.$el.css('display', 'none'); 39076 }); 39077 } else { 39078 base.$el.animate({ top: -base.bannerHeight }, base.options.animationSpeed, function () { 39079 base.$el.css('display', 'none'); 39080 }); 39081 } 39082 } else { 39083 base.$el.animate({ bottom: -base.bannerHeight }, base.options.animationSpeed, function () { 39084 base.$el.css('display', 'none'); 39085 $('.' + base.options.positionRelativePlaceholderClass).remove(); 39086 }); 39087 } 39088 } else { 39089 base.$el.css('display', 'none'); 39090 } 39091 base.$el.promise().done(function () { 39092 $('body').addClass(base.options.bodyHiddenClass).removeClass(base.options.bodyVisibleClass); 39093 }); 39094 }, 39095 39096 createBanner: function createBanner(triggeredByResponsiveListener) { 39097 var base = this, 39098 buttons, 39099 rejectButton; 39100 39101 buttons = base.$el.find(base.options.closeButton); 39102 39103 if (!triggeredByResponsiveListener && base.options.matomoButtons) { 39104 rejectButton = buttons.first().clone().insertAfter(buttons.first()); 39105 39106 buttons.first().text(base.options.labels.consent).on('click', base, base.matomoConsent); 39107 rejectButton.text(base.options.labels.reject).on('click', base, base.matomoReject); 39108 39109 buttons = buttons.add(rejectButton); 39110 base.matomoDone = true; 39111 } 39112 39113 base.prepareState(triggeredByResponsiveListener); 39114 // hide banner 39115 base.$el.css(base.options.position, base.options.positionRelative ? 0 : -base.bannerHeight); 39116 // if no cookie 39117 if (!base.options.cookieName) { 39118 base.show(); 39119 } else if (!Cookies.get(base.options.cookieName)) { 39120 gsb.log('gsb_banner.createBanner() > no cookie'); 39121 // display banner with or without animation 39122 base.show(); 39123 } else { 39124 gsb.log('gsb_banner.createBanner() > valid cookie > hide banner'); 39125 // hide banner without animation 39126 base.hide(true); 39127 } 39128 // create close button 39129 buttons.click(function (e) { 39130 gsb.log('gsb_banner.click() > confirm'); 39131 e.preventDefault(); 39132 e.stopPropagation(); 39133 // hide banner with or without animation 39134 base.hide(); 39135 // set cookie with expiredate 39136 Cookies.set(base.options.cookieName, 'closed', { 39137 expires: base.options.cookieLifeTimeInDaysClosed, 39138 path: '/' 39139 }); 39140 }); 39141 }, 39142 39143 prepareState: function prepareState(reset) { 39144 var base = this; 39145 if (reset) { 39146 base.$el.css({ 39147 paddingTop: '', 39148 paddingBottom: '', 39149 height: '' 39150 }); 39151 } 39152 base.bannerHeight = !reset && base.bannerHeight && base.options.position === 'top' ? base.bannerHeight : base.$el.outerHeight() + base.options.topOffset; 39153 base.bannerPadding = !reset && base.bannerPadding ? base.bannerPadding : { 39154 top: base.$el.css('padding-top'), 39155 bottom: base.$el.css('padding-bottom') 39156 }; 39157 }, 39158 39159 matomoConsent: function matomoConsent(ev) { 39160 var base = ev.data; 39161 base.addMatomo(); 39162 _paq.push(['setConsentGiven']); 39163 Cookies.set('matomoTracking', true, { 39164 expires: base.options.matomoTrackingCookieLifeTimeInDays, 39165 path: '/' 39166 }); 39167 gsb.log('matomoConsent called'); 39168 }, 39169 39170 matomoReject: function matomoReject(ev) { 39171 var base = ev.data; 39172 _paq.push(['forgetConsentGiven']); 39173 Cookies.remove('matomoTracking'); 39174 gsb.log('matomoReject called'); 39175 }, 39176 39177 addMatomo: function addMatomo() { 39178 var base = this, 39179 siteId = $('body').attr('data-matomo-site-id'); 39180 39181 if (/^\d+$/.test(siteId) && $('#gsbMatomoScript').length === 0) { 39182 console.log('Matomo loaded'); 39183 _paq.push(['disableCookie']); 39184 _paq.push(['setDocumentTitle', document.domain + "/" + document.title]); 39185 _paq.push(['trackPageView']); 39186 _paq.push(['enableLinkTracking']); 39187 _paq.push(['setTrackerUrl', base.options.trackerUrl]); 39188 _paq.push(['setSiteId', Number(siteId)]); 39189 _paq.push(['setDownloadClasses', "download_stat"]); 39190 _paq.push(['setDocumentTitle', '404/URL = ' + encodeURIComponent(document.location.pathname + document.location.search) + '/From = ' + encodeURIComponent(document.referrer)]); 39191 $(document.createElement('script')).attr({ 39192 id: 'gsbMatomoScript', 39193 type: 'text/javascript', 39194 async: true, 39195 defer: true, 39196 src: base.options.scriptUrl 39197 }).insertBefore($("script:first")); 39198 } 39199 } 39200 39201 }; 39202 $.gsb.banner.defaultOptions = { 39203 animation: typeof animation === 'undefined' ? false : animation, 39204 animationSpeed: 1800, 39205 position: typeof position === 'undefined' ? 'bottom' : position, 39206 topOffset: 20, 39207 closeButton: '.close', // jquery selector 39208 bodyVisibleClass: 'banner-visible', 39209 bodyHiddenClass: 'banner-hidden', 39210 positionRelativeClass: 'cookiebanner__relative', 39211 positionRelativePlaceholderClass: 'cookiebanner__placeholder', 39212 cookieName: 'gsbbanner', 39213 cookieLifeTimeInDaysClosed: 5, 39214 respondToEvents: true, 39215 positionRelative: false, // make room for the cookiebanner in the dom to not overlay content 39216 navSkipListSelector: 'ul.navSkip', // used if positionRelative is true
39217 matomoButtons: false, 39218 matomoTrackingCookieLifeTimeInDays: 5, 39219 scriptUrl: '//piwik.itzbund.de/js/', 39220 trackerUrl: '//piwik.itzbund.de/js/', 39221 labels: { 39222 consent: typeof TRACKING_CONSENT !== "undefined" ? TRACKING_CONSENT : 'Consent', 39223 reject: typeof TRACKING_DISSENT !== "undefined" ? TRACKING_DISSENT : 'Reject' 39224 }, 39225 onRefresh: function onRefresh() { 39226 this.createBanner(true); 39227 } 39228 }; 39229 /** 39230 * Initialisiert den Aufruf der die Banner-Box 39231 * @param {options} options JSON-Objekt zum überschreiben der Default-Options 39232 */ 39233 $.fn.gsb_banner = function (options) { 39234 return this.each(function () { 39235 $.gsb.banner(this, options); 39236 }); 39237 }; 39238})(jQuery); 39239 /* Ende gsb_banner */ 39240 /* Start gsb_maxHeight */ 39241 /*! 39242 * @name maxHeight 39243 * @author @pespeloe 39244 * Licensed under the MIT license 39245 * 39246 * Container per Javascript auf die Höhe des höchsten 39247 * Containers setzen 39248 * */ 39249; 39250(function ($) { 39251 if (!$.gsb) { 39252 $.gsb = {}; 39253 } 39254 ; 39255 $.gsb.maxHeight = function (el, options) { 39256 // To avoid scope issues, use 'base' instead of 'this' 39257 // to reference this class from internal events and functions. 39258 var base = this; 39259 // Access to jQuery and DOM versions of element 39260 base.$el = $(el); 39261 base.el = el; 39262 // Add a reverse reference to the DOM object 39263 base.$el.data("gsb.maxHeight", base); 39264 base.init = function () { 39265 base.options = $.extend({}, $.gsb.maxHeight.defaultOptions, options); 39266 if (base.options.triggerFromOutside) { 39267 base.checkOptions(base); 39268 } 39269 $(window).on('resize load', function () { 39270 // um sicher zu sein das alle Bilder und somit alle Container 39271 // die entgültige Höhe haben 39272 if (typeof base.options.beforeInit === 'function') { 39273 base.options.beforeInit.call($(this), base.$el); 39274 } 39275 base.checkOptions(base); 39276 if (typeof base.options.afterInit === 'function') { 39277 base.options.afterInit.call($(this), base.$el, $items); 39278 } 39279 }); 39280 }; 39281 $.gsb.maxHeight.prototype.checkOptions = function (base) { 39282 if (base.options.elementsPerRow == null) { 39283 var $items = base.$el.find(base.options.boxes); 39284 if ($items.length > 0) { 39285 $items.css('height', 'auto'); 39286 base.setHeight($items); 39287 } 39288 } else if (base.options.elementsPerRow > 1) { 39289 var items = []; 39290 base.$el.find(base.options.boxes).each(function (index) { 39291 items.push(this); 39292 if ((index + 1) % base.options.elementsPerRow == 0) { 39293 base.setHeight($(items)); 39294 items = []; 39295 } 39296 }); 39297 } 39298 }; 39299 $.gsb.maxHeight.prototype.setHeight = function ($items) { 39300 var maxHeight = 0, 39301 maxHeightAbsoluteContainer = 0, 39302 maxHeightAdjacentElement = 0; 39303 $items.each(function () { 39304 var itemHeight = parseInt($(this).outerHeight()); 39305 var moreButton; 39306 if (base.options.absoluteElements !== undefined) { 39307 moreButton = parseInt($(this).find(base.options.absoluteElements).outerHeight(true)); 39308 if (moreButton > maxHeightAbsoluteContainer) maxHeightAbsoluteContainer = moreButton; 39309 } 39310 if (base.options.adjacentElements !== undefined) { 39311 heightAdjacentElement = parseInt($(this).parent().find(base.options.adjacentElements).outerHeight(true)); 39312 if (heightAdjacentElement > maxHeightAdjacentElement) maxHeightAdjacentElement = heightAdjacentElement; 39313 } 39314 if (itemHeight > maxHeight) maxHeight = itemHeight; 39315 }); 39316 $items.each(function () { 39317 if (base.options.adjacentElements !== undefined && $(this).parent().find(base.options.adjacentElements).length == 0) { 39318 $(this).css("height", maxHeight + maxHeightAbsoluteContainer + maxHeightAdjacentElement); 39319 } else { 39320 $(this).css("height", maxHeight + maxHeightAbsoluteContainer); 39321 } 39322 }); 39323 }; 39324 // Run initializer 39325 base.init(); 39326 }; 39327 $.gsb.maxHeight.defaultOptions = { 39328 boxes: '.slick-slide', 39329 elementsPerRow: null, 39330 absoluteElements: undefined, 39331 triggerFromOutside: false, 39332 beforeInit: undefined, 39333 afterInit: undefined, 39334 adjacentElements: undefined 39335 }; 39336 //Search Reset 39337 $.fn.gsb_maxHeight = function (options) { 39338 return this.each(function () { 39339 new $.gsb.maxHeight(this, options); 39340 }); 39341 }; 39342})(jQuery); 39343 /* Ende gsb_maxHeight */ 39344 /* Start gsb_calendar */ 39345 /*! 39346 * GSB-Plugin zur Animation und zum Nachladen von Kalender 39347 * 39348 * Author: pespeloer 39349 */ 39350; 39351(function ($) { 39352 if (!$.gsb) { 39353 $.gsb = {}; 39354 } 39355 ; 39356 39357 $.gsb.calendar = function (el, options) { 39358 // To avoid scope issues, use 'base' instead of 'this' 39359 // to reference this class from internal events and functions. 39360 var base = this; 39361 39362 // Access to jQuery and DOM versions of element 39363 base.$el = $(el); 39364 base.el = el; 39365 39366 // Add a reverse reference to the DOM object 39367 base.$el.data("gsb.calendar", base); 39368 39369 base.init = function () { 39370 base.options = $.extend({}, $.gsb.calendar.defaultOptions, options); 39371 options = base.options; 39372 39373 //Klick auf einzelnen Termin 39374 base.$el.on("click touchstart", "td > a", function (e) { 39375 e.preventDefault(); 39376 e.stopPropagation(); 39377 // --- Termine des Tages anzeigen 39378 //Schlie�en 39379 if ($(this).parent().hasClass(options.detailsOpenedClass)) { 39380 $(this).parent().removeClass(options.detailsOpenedClass).addClass(options.detailsClosedClass); 39381 } else { 39382 // Alle ge�ffneten Details schlie�en 39383 base.$el.find('.' + options.detailsOpenedClass).removeClass(options.detailsOpenedClass); 39384 $(this).parent().removeClass(options.detailsClosedClass).addClass(options.detailsOpenedClass); 39385 } 39386 }); 39387 39388 //Klick auf Zur�ckbutton 39389 base.$el.on("click touchstart", options.prevButton, function (e) { 39390 e.preventDefault(); 39391 e.stopPropagation(); 39392 base.loadCalendar($(this).data('href')); 39393 }); 39394 39395 //Klick auf Vorbutton 39396 base.$el.on("click touchstart", options.nextButton, function (e) { 39397 e.preventDefault(); 39398 e.stopPropagation(); 39399 base.loadCalendar($(this).data('href')); 39400 }); 39401 }; 39402 39403 // --- N�chsten Monat laden 39404 //1. Fadeout 39405 //2. Container leeren und wieder bef�llen 39406 //3. Fadein 39407 //4. Focus auf das erste zu fokussierende Element setzen 39408 39409 base.loadCalendar = function (href) { 39410 if (typeof options.beforeInit === 'function') { 39411 base.options.beforeInit.call($(this), base.$el); 39412 } 39413 39414 base.$el.fadeTo(options.duration, 0, function () { 39415 base.$el.load(href, function () { 39416 base.$el.fadeTo(options.duration, 1, function () { 39417 base.addA11y(); 39418 if (typeof options.afterInit === 'function') { 39419 base.options.afterInit.call($(this), base.$el); 39420 } 39421 }); 39422 }); 39423 }); 39424 }; 39425 39426 //Focus setzen 39427 base.addA11y = function (elem) { 39428 elem = elem || base.$el; 39429 var focusElements = elem.find('input,textarea,select,a,button').not(':hidden'); 39430 focusElements[0].focus(); 39431 }; 39432 39433 // Run initializer 39434 base.init(); 39435 }; 39436 39437 $.gsb.calendar.defaultOptions = { 39438 nextButton: '.next > a', 39439 prevButton: '.prev > a', 39440 fadeDuration: 400,
39441 detailsOpenedClass: 'opened', 39442 detailsClosedClass: 'closed', 39443 beforeInit: undefined, //Vor Monatswechsel 39444 afterInit: undefined //Nach Monatswechsel 39445 }; 39446 39447 //gsb Calendar 39448 $.fn.gsb_calendar = function (options) { 39449 return this.each(function () { 39450 new $.gsb.calendar(this, options); 39451 }); 39452 }; 39453})(jQuery); 39454 /* Ende gsb_calendar */ 39455 /* Start gsb_clearfields */ 39456 /*! 39457 * GSB-Plugin zum autom. Leeren von Text-Input-Feldern 39458 * 39459 * Author: sbaecker 39460 */ 39461(function ($) { 39462 jQuery.fn.attachToField = function (id, defaultValue) { 39463 var field = $('#' + id); 39464 var input_text = field.attr('value'); 39465 return jQuery(field).bind('focus', function () { 39466 if (input_text == defaultValue) { 39467 field.attr('value', ''); 39468 } 39469 }).bind('blur', function () { 39470 if (field.attr('value') == '') { 39471 field.attr('value', input_text); 39472 } 39473 input_text = field.attr('value'); 39474 }); 39475 }; 39476 39477 jQuery.gsb_clearfields = function () { 39478 // attach events to search form input 39479 39480 //HINWEIS: Bitte folgenden Zeilen im GSB einkommentieren 39481 // 39482 // // 39483 // 39484 // // 39485 // // 39486 // 39487 // 39488 // jQuery('#f6942653c85ec843c18743efed6942653d85ec843c18743f3c').attachToField('f6942653c85ec843c18743efed6942653d85ec843c18743f3c',''); 39489 // 39490 // 39491 // // 39492 // 39493 // // 39494 // // 39495 // 39496 // 39497 // jQuery('#f6942653c85ec843c18743f02d6942653d85ec843c18743f3c').attachToField('f6942653c85ec843c18743f02d6942653d85ec843c18743f3c',''); 39498 // 39499 // 39500 // // 39501 // 39502 // 39503 // // 39504 // 39505 // 39506 // 39507 39508 // HINWEIS: Bitte folgenden zeilen im GSB auskommentieren 39509 jQuery('#f7610d7612').attachToField('f7610d7612', 'Suchbegriff'); 39510 39511 return; 39512 }; 39513})(jQuery); 39514 /* Ende gsb_clearfields */ 39515 /* Start gsb_lightbox */ 39516 /** 39517 * @module gsb_lightbox 39518 * @version 1.0.0 39519 * @see {@link http://semver.org|Semantic Versioning} 39520 * @desc GSB-Wrapper-Plugin fuer magnific popup 39521 * 39522 * 39523 * @requires {@link external:jQuery} 39524 * @requires {@link external:magnific-popup} 39525 * @requires {@link external:hammerjs} 39526 * @requires {@link external:jquery-hammerjs} 39527 * 39528 * @author rkrusenb 39529 */ 39530 39531//will be prettified eventually 39532(function ($) { 39533 if (!$.gsb) { 39534 $.gsb = {}; 39535 }; 39536 $.gsb.lightbox = function (el, userOptions) { 39537 var lightbox = this, 39538 $el = lightbox.$el = $(el), 39539 options, 39540 disabled; 39541 function openerClickHandler(ev) { 39542 if (!disabled) { 39543 ev && typeof ev.preventDefault == "function" && ev.preventDefault(); 39544 $el.data('magnificPopup').index = $(this).data('gsb.lightboxopener').index; 39545 } 39546 $el.magnificPopup('open'); 39547 } 39548 function checkArrowState(mfp) { 39549 if (!options.cycle && mfp.arrowLeft && mfp.arrowRight) { 39550 if (mfp.index == 0) { 39551 mfp.arrowLeft.find('img').attr('src', options.imagePrevInactive); 39552 } else { 39553 mfp.arrowLeft.find('img').attr('src', options.imagePrev); 39554 } 39555 if (mfp.index == mfp.items.length - 1) { 39556 mfp.arrowRight.find('img').attr('src', options.imageNextInactive); 39557 } else { 39558 mfp.arrowRight.find('img').attr('src', options.imageNext); 39559 } 39560 } 39561 } 39562 function makeGallery() { 39563 options.reallyMagnificOptions.callbacks.open = function () { 39564 var mfp = this; 39565 mfp.wrap.find('.mfp-close').appendTo(mfp.contentContainer); 39566 if (options.imagePrev) { 39567 $('.mfp-arrow-left').append('<img alt="' + options.reallyMagnificOptions.gallery.tPrev + '" src="' + options.imagePrev + '">'); 39568 } 39569 if (options.imageNext) { 39570 $('.mfp-arrow-right').append('<img alt="' + options.reallyMagnificOptions.gallery.tNext + '" src="' + options.imageNext + '">'); 39571 } 39572 mfp.prev = function () { 39573 if (options.cycle || mfp.index != 0) { 39574 $.magnificPopup.proto.prev.call(this); 39575 } 39576 }; 39577 mfp.next = function () { 39578 if (options.cycle || mfp.index != mfp.items.length - 1) { 39579 $.magnificPopup.proto.next.call(this); 39580 } 39581 }; 39582 39583 checkArrowState(this); 39584 if (typeof mfp.contentContainer.hammer == "function" && !mfp.wrap.data('gsb.swipe')) { 39585 mfp.contentContainer.hammer({ 39586 drag_block_horizontal: true, 39587 stop_browser_behavior: { touchAction: 'auto' }, 39588 swipe_velocity: 0.3 39589 }).on('swiperight', function () { 39590 mfp.prev(); 39591 }).on('swipeleft', function () { 39592 mfp.next(); 39593 }).data('gsb.swipe', {}); 39594 } 39595 }; //end callbacks.open 39596 options.reallyMagnificOptions.callbacks.change = function () { 39597 checkArrowState(this); 39598 }; //end callbacks.change 39599 $.extend(options.reallyMagnificOptions, { 39600 items: $.map($(this).find(options.element), function (item) { 39601 return { 39602 src: $(item).clone().find('.loupe').remove().end().removeClass('slick-slide').attr('style', null), 39603 type: 'inline' 39604 }; 39605 }) 39606 }, (userOptions || {}).magnificOptions); 39607 $el.magnificPopup(options.reallyMagnificOptions).unbind('click'); 39608 } //end makeGallery 39609 lightbox.el = el; 39610 // Add a reverse reference to the DOM object 39611 lightbox.$el.data("gsb.lightbox", lightbox); 39612 lightbox.init = function () { 39613 var url, closeText, defer; 39614 options = lightbox.options = $.extend({}, $.gsb.lightbox.defaultOptions, userOptions); 39615 39616 //init code here 39617 options.reallyMagnificOptions = $.extend({}, $.gsb.lightbox.defaultOptions.magnificOptions); 39618 closeText = options.magnificOptions.tClose; 39619 $.extend(options.reallyMagnificOptions, { 39620 disableOn: function disableOn() { 39621 return !disabled; 39622 }, 39623 closeMarkup: '<button class="mfp-close">%title%</button>' 39624 }); 39625 39626 if (options.lightboxType == 'single') { 39627 url = $el.data('lightbox-href'); 39628 if (url) { 39629 options.reallyMagnificOptions.type = 'ajax'; 39630 options.reallyMagnificOptions.ajax.settings.url = url; 39631 } else if ($el.parents(options.element).length) { 39632 options.reallyMagnificOptions.type = 'image'; 39633 } 39634 $.extend(options.reallyMagnificOptions, (userOptions || {}).magnificOptions); 39635 $el.magnificPopup(options.reallyMagnificOptions); 39636 } else if (options.lightboxType == 'multiple') { 39637 url = $el.data('lightbox-href'); 39638 if (url) { 39639 $('<div />').load(url, makeGallery); 39640 } else { 39641 $el.on('init.slideshow.gsb', makeGallery); 39642 } 39643 $el.on('init.slideshow.gsb', function () { 39644 $el.find('.loupe').each(function (idx) { 39645 var opener = $(this), 39646 openerData = opener.data('gsb.lightboxopener') || {}; 39647 openerData.index = idx; 39648 opener.data('gsb.lightboxopener', openerData); 39649 opener.click(openerClickHandler).keydown(function (e) { 39650 if (e.which == 23) { 39651 $(this).click(); 39652 } 39653 }); 39654 }); 39655 }); 39656 $.extend(true, options.reallyMagnificOptions, { 39657 gallery: { 39658 enabled: true 39659 } 39660 }); 39661 $.extend(options.reallyMagnificOptions, (userOptions || {}).magnificOptions); 39662 } 39663 39664 //call addA11y here somewhere 39665 }; 39666 lightbox.closeLightbox = function () { 39667 $el.magnificPopup('close'); 39668 }; 39669 lightbox.disable = function () { 39670 disabled = true; 39671 }; 39672 lightbox.enable = function () { 39673 disabled = false;
39674 }; 39675 39676 lightbox.addA11y = function () { 39677 //add a11y enhancements 39678 }; 39679 // Run initializer 39680 lightbox.init(); 39681 }; 39682 /** 39683 * @typedef defaultOptions 39684 * @type {object} 39685 * @property {object} options - Default Options des Scripts 39686 * @property {string} [options.lightboxType] single oder multiple - multiple füer Bildergallerie 39687 * @property {boolean} [options.cycle] rotation an oder aus 39688 * @property {string} [options.element] Vermutlich der Container dessen Inhalt in der Lightbox angezeigt werden soll 39689 * @property {string} [options.imagePrev] Zurückblättern-Pfeil, zwingend notwendig wenn lightboxtype auf multiple steht 39690 * @property {string} [options.imageNext] Vorblättern-Pfeil, zwingend notwendig wenn lightboxtype auf multiple steht 39691 * @property {Object} [options.magnificOptions] Optionen des magnificPopups (muss aber eigentlich nichts gemacht werden) 39692 * [siehe Doku]{@link http://dimsemenov.com/plugins/magnific-popup/documentation.html#options} 39693 */ 39694 $.gsb.lightbox.defaultOptions = { 39695 lightboxType: 'single', //this is NOT the same as e.g. magnificOptions.type, 39696 cycle: false, 39697 element: '.picture', 39698 imagePrev: '', //MUST be specified if lightboxType = 'multiple' 39699 imageNext: '', //MUST be specified if lightboxType = 'multiple' 39700 magnificOptions: { 39701 //general label options 39702 tClose: typeof CLOSE == 'undefined' ? 'SchlieÃen (Esc)' : CLOSE, 39703 gallery: { 39704 //gallery label options 39705 tPrev: typeof PREV == 'undefined' ? 'Vorheriges (linke Pfeiltaste)' : PREV, // Alt text on left arrow
39706 tNext: typeof NEXT == 'undefined' ? 'Nächstes (rechte Pfeiltaste)' : NEXT, // Alt text on right arrow 39707 tCounter: typeof LIGHTBOX_X_OF_Y == 'undefined' ? '%curr% von %total%' : LIGHTBOX_X_OF_Y // Markup for "1 of 7" counter 39708 }, 39709 //main options 39710 type: 'ajax', 39711 closeOnContentClick: false, 39712 closeBtnInside: false, 39713 image: { 39714 verticalFit: true, 39715 titleSrc: function titleSrc() { 39716 return $(this.currItem && this.currItem.el).find('img').attr('alt'); 39717 } 39718 }, 39719 ajax: { 39720 settings: {} 39721 }, 39722 callbacks: { 39723 afterChange: function afterChange() { 39724 $(this.content).find('video, audio').each(function (_, el) { 39725 var data = $(el).data("gsb.Multimedia"); 39726 if (!data) { 39727 data = $(el).gsb_Multimedia().data("gsb.Multimedia"); 39728 } 39729 if (!data.workaround && typeof data.triggerRefresh == "function") { 39730 data.workaround = true; 39731 data.triggerRefresh(); //no idea why this fixes it, but nothing else will 39732 } 39733 }); 39734 }, 39735 buildControls: function buildControls() { 39736 // re-appends controls inside the main container 39737 if (this.contentContainer && this.arrowLeft && this.arrowRight) { 39738 this.contentContainer.append(this.arrowLeft.add(this.arrowRight)); 39739 } 39740 }, 39741 open: function open() { 39742 if (this.wrap && this.wrap.find) { 39743 this.wrap.find('.mfp-close').appendTo(this.contentContainer); 39744 } 39745 } 39746 } 39747 } 39748 }; 39749 $.fn.gsb_lightbox = function (options) { 39750 return this.each(function () { 39751 new $.gsb.lightbox(this, options); 39752 }); 39753 }; 39754})(jQuery); 39755 /* Ende gsb_lightbox */ 39756 /* Start gsb_serviceborder */ 39757 /*! 39758 * GSB-Plugin fuer Serviceleiste unter der Buehne 39759 * 39760 * Dabei wird die folgende HTML-Struktur erwartet 39761 * 39762 * <div id="service-border"> 39763 * <div id="tab"> 39764 * <ul class="tab"> 39765 * <li class="t-entry-1"> 39766 * <a class="navServiceNewsletter" href="...">Newsletter</a> 39767 * </li> 39768 * ... 39769 * </ul> 39770 * </div> 39771 * <div id="section-1" class="container"> 39772 * ... 39773 * </div> 39774 * ... 39775 * </div> 39776 * 39777 * Aufruf: 39778 * $("#navContent").gsb_Serviceborder(); 39779 * 39780 * Author: sbaecker 39781 * 39782 * @requires jQuery >= 1.11.1, gsb_responsiveListener 39783 * 39784 */ 39785 39786; 39787(function ($) { 39788 if (!$.gsb) { 39789 $.gsb = {}; 39790 } 39791 ; 39792 $.gsb.Serviceborder = function (el, options) { 39793 var base = this, 39794 closeclick; 39795 // Access to jQuery and DOM versions of element 39796 base.$el = $(el); 39797 base.el = el; 39798 // Add a reverse reference to the DOM object 39799 base.$el.data("gsb.Serviceborder", base); 39800 /** 39801 * Initialisierung 39802 */ 39803 base.init = function () { 39804 base.options = $.extend({}, $.gsb.Serviceborder.defaultOptions, options); 39805 base.$el.gsb_responsiveListener(base); 39806 }; 39807 base._configuration = function () { 39808 closeclick = false; 39809 39810 if (!base.$el.length) return; 39811 // Tab-Navigation einrichten 39812 if (base.$el.find(base.options.navnodes + ' span.aural').length == 0) { 39813 base.$el.find(base.options.navnodes).append('<span class="aural"> ' + base.options.show_more_text + '</span>'); 39814 } 39815 base.$el.find(base.options.navnodes).each(function () { 39816 $(this).on('click', function (e) { 39817 e.preventDefault(); 39818 e.stopPropagation(); 39819 base.showTab($(this)); 39820 return false; 39821 }); 39822 }); 39823 // Nummer des aktiven Tabs und des Tabs, der als nächstes angezeigt werden soll 39824 base.tabActive = false; 39825 base.tabToShow = false; 39826 }; 39827 /** 39828 * Einen Tab anzeigen 39829 */ 39830 base.showTab = function (obj, close) { 39831 // Objekt übergeben? 39832 if (typeof obj != 'undefined' && obj) { 39833 // Tab-Nummer aus Klassenname des li über Link parsen 39834 var regExpMatch = obj.parent('li:first').attr('class').match(/^.*\w+-(\w+)-(\d+)( .*)?$/); 39835 base.tabToShow = regExpMatch[2]; 39836 } else { 39837 // Tabs schlieÃen 39838 closeclick = true; 39839 base.tabToShow = false;
39840 } 39841 //Klick auf das Icon eines bereits geöffneten tabs 39842 if (base.tabActive == base.tabToShow) { 39843 var tabActiveId = base.options.container + base.tabActive; 39844 var $tabActive = base.$el.find(tabActiveId); 39845 $tabActive.stop(true, true).fadeOut({ duration: base.options.fadeDuration, easing: 'linear', queue: false }).slideUp({ duration: base.options.slideDuration, easing: 'linear' }); 39846 base.tabActive = false; 39847 // Tab-Ãberschriften deaktivieren 39848 base.$el.find(' ul > li .aural').text(" " + base.options.show_more_text); 39849 base.$el.find(' ul > li').removeClass('active'); 39850 } else { 39851 // Wenn Tab nicht bereits angezeigt wird 39852 if (base.tabToShow != base.tabActive && false !== base.tabToShow) { 39853 // Tab-Elemente abrufen 39854 var tabToShowId = base.options.container + base.tabToShow; 39855 var $tabToShow = base.$el.find(tabToShowId); 39856 if (!$tabToShow.length) { 39857 alert('Tab ' + tabToShowId + ' nicht vorhanden...'); 39858 return; 39859 } 39860 // Wenn nicht vorhanden, SchlieÃen-Button hinzufügen 39861 if (!$tabToShow.find('.containerinner .close').length) { 39862 var $closeButton; 39863 if (base.options.close_button_markup_mode === 'image') { 39864 $closeButton = $('<p><button tabindex="0" class="close" title="' + base.options.close + '" ><img src="' + image_url_close + '" alt="' + base.options.close + '" /></button></p>'); 39865 } else { 39866 $closeButton = $('<p><button tabindex="0" class="close">' + base.options.close + '</button></p>'); 39867 } 39868 $closeButton.appendTo(tabToShowId + ' > .containerinner:first').on('click', function () { 39869 base.showTab(); 39870 return false; 39871 }); 39872 } 39873 base.$el.find('> div .close').unbind('click').on('click', function (e) { 39874 e.preventDefault(); 39875 e.stopPropagation(); 39876 // Tab schlieÃen 39877 var tabActiveId = base.options.container + base.tabActive; 39878 var $tabActive = base.$el.find(tabActiveId); 39879 $tabToShow.stop(true, true).fadeOut({ duration: base.options.fadeDuration, easing: 'linear', queue: false }).slideUp({ duration: base.options.slideDuration, easing: 'linear' }); 39880 obj.focus(); 39881 base.tabActive = false; 39882 // Tab-Ãberschriften deaktivieren 39883 base.$el.find(' ul > li span.aural').text(' ' + base.options.show_more_text); 39884 base.$el.find('ul > li').removeClass('active'); 39885 }); 39886 // Ist gerade ein Tab geöffnet? => Ausblenden 39887 if (false !== base.tabActive) { 39888 var tabActiveId = base.options.container + base.tabActive; 39889 var $tabActive = base.$el.find(tabActiveId); 39890 $tabActive.slideUp(); 39891 } else { 39892 $tabToShow.stop(true, true).fadeIn({ duration: base.options.fadeDuration, easing: 'linear', queue: false }).css('display', 'none').slideDown({ duration: base.options.slideDuration, easing: 'linear' }); 39893 } 39894 39895 // Neuen Tab einblenden 39896 $tabToShow.slideDown(); 39897 base.tabActive = base.tabToShow; 39898 // Entsprechende Tab-Ãberschrift aktivieren 39899 base.$el.find(' ul > li span.aural').text(' ' + base.options.show_more_text); 39900 base.$el.find(' ul > li').removeClass('active'); 39901 obj.parent(':first').addClass('active'); 39902 base.$el.find(' ul > li.active .aural').text(' ' + base.options.show_less_text); 39903 } else if (false === base.tabToShow && false !== base.tabActive) { 39904 // Tab schlieÃen 39905 var tabActiveId = base.options.container + base.tabActive; 39906 var $tabActive = base.$el.find(tabActiveId); 39907 if (closeclick = true) { 39908 $tabActive.slideUp('fast'); 39909 closeclick = false; 39910 } else { 39911 $tabActive.hide(); 39912 } 39913 base.tabActive = false; 39914 // Tab-Ãberschriften deaktivieren 39915 base.$el.find(' ul > li span.aural').text(' ' + base.options.show_more_text); 39916 base.$el.find(' ul > li').removeClass('active'); 39917 } 39918 } 39919 }; //Ende showTab 39920 base._uninit = function () { 39921 //Deaktivieren der Tab-SchlieÃen Links 39922 var closeLink = base.$el.find('a.close'); 39923 if (closeLink.length > 0) { 39924 if (closeLink.closest('p').length > 0) { 39925 closeLink.closest('p').off(); 39926 } else { 39927 closeLink.off(); 39928 } 39929 } 39930 if (base.$el.find('div .close').length > 0) { 39931 base.$el.find('div .close').off(); 39932 } 39933 //Deaktivieren der Tabs 39934 if (base.$el.find(base.options.navnodes).length > 0) { 39935 base.$el.find(base.options.navnodes).off(); 39936 } 39937 //Falls noch Tabs geöffnet waren -> schlieÃen 39938 base.$el.find('.container').hide(); 39939 base.$el.find(' ul > li span.aural').text(' ' + base.options.show_more_text); 39940 base.$el.find('>ul>li').removeClass('active'); 39941 }; 39942 // Init 39943 base.init(); 39944 }; 39945 $.gsb.Serviceborder.defaultOptions = { 39946 close: typeof CLOSE == 'undefined' ? 'SchlieÃen' : CLOSE, 39947 close_button_markup_mode: 'image', 39948 navnodes: ' > ul > li > a', 39949 container: '#section-', 39950 show_more_text: typeof SHOW_MORE == 'undefined' ? 'Mehr anzeigen' : SHOW_MORE, 39951 show_less_text: typeof SHOW_LESS == 'undefined' ? 'Weniger anzeigen' : SHOW_LESS, 39952 slideDuration: 400, //MUST be integer; 200 = fast, 400 = default, 600 = slow 39953 fadeDuration: 600,
39954 respondToEvents: true, 39955 onRefresh: function onRefresh() { 39956 this._configuration(); 39957 }, 39958 responsive: [{ 39959 breakpoint: 600, 39960 onRefresh: function onRefresh() { 39961 this._uninit(); 39962 } 39963 }] 39964 }; 39965 $.fn.gsb_Serviceborder = function (options) { 39966 return this.each(function () { 39967 new $.gsb.Serviceborder(this, options); 39968 }); 39969 }; 39970})(jQuery); 39971 /* Ende gsb_serviceborder */ 39972 /* Start gsb_print */ 39973 /*! 39974 * GSB-Plugin zum autom. Leeren von Text-Input-Feldern 39975 * 39976 * Das Addon fügt einen Link "Seite drucken" in eine vorhandene Liste ein 39977 * Aufruf: $("#element").gsb_init_printlink(); 39978 * #element muss dabei ein <ul> sein, damit das html valide bleibt. 39979 * 39980 * Author: sbaecker 39981 * 39982 * @requires jQuery >= 1.11.1, gsb_responsiveListener 39983 * 39984 */ 39985; 39986(function ($) { 39987 if (!$.gsb) { 39988 $.gsb = {}; 39989 } 39990 ; 39991 $.gsb.printlink = function (el, options) { 39992 // To avoid scope issues, use 'base' instead of 'this' 39993 // to reference this class from internal events and functions. 39994 var base = this; 39995 var printInited = false; 39996 // Access to $ and DOM versions of element 39997 base.$el = $(el); 39998 base.el = el; 39999 // Add a reverse reference to the DOM object 40000 base.$el.data("gsb.printlink", base); 40001 base.init = function () { 40002 base.options = $.extend({}, $.gsb.printlink.defaultOptions, options); 40003 //Initialization Code 40004 base.$el.gsb_responsiveListener(base); 40005 }; 40006 base._printlink = function () { 40007 if (!base.$el.length) { 40008 return; 40009 } 40010 if ($('#' + base.options.printlink_id).length == 0) { 40011 pattern = $('<li id="' + base.options.printlink_id + '"><a href="#" title="' + base.options.tooltip + '">' + base.options.page_text + '</a></li>'); 40012 base.$el.prepend(pattern); 40013 } 40014 base.$el.parent().find('#' + base.options.printlink_id + ' a').on("click", function (e) { 40015 e.preventDefault(); 40016 e.stopPropagation(); 40017 window.print(); 40018 }); 40019 }; 40020 base._uninit = function () { 40021 if (base.$el.find('#' + base.options.printlink_id)) { 40022 base.$el.find('#' + base.options.printlink_id).off().remove(); 40023 } 40024 }; 40025 // Run initializer 40026 base.init(); 40027 }; 40028 $.gsb.printlink.defaultOptions = { 40029 tooltip: typeof PRINT_TOOLTIP == 'undefined' ? 'Drucken (öffnet Dialog)' : PRINT_TOOLTIP, 40030 page_text: typeof PRINT_PAGE_TEXT == 'undefined' ? 'drucken' : PRINT_PAGE_TEXT, 40031 printlink_id: 'navFunctionsPrint', 40032 respondToEvents: true, 40033 onRefresh: function onRefresh() { 40034 this._printlink(); 40035 }, 40036 responsive: [{ 40037 breakpoint: 1024, 40038 onRefresh: function onRefresh() { 40039 this._uninit(); 40040 } 40041 }] 40042 }; 40043 $.fn.gsb_printlink = function (options) { 40044 return this.each(function () { 40045 new $.gsb.printlink(this, options); 40046 }); 40047 }; 40048 $.gsb.printbutton = function (el, options) { 40049 // To avoid scope issues, use 'base' instead of 'this' 40050 // to reference this class from internal events and functions. 40051 var base = this; 40052 var printInited = false; 40053 // Access to $ and DOM versions of element 40054 base.$el = $(el); 40055 base.el = el; 40056 // Add a reverse reference to the DOM object 40057 base.$el.data("gsb.printbutton", base); 40058 base.init = function () { 40059 base.options = $.extend({}, $.gsb.printbutton.defaultOptions, options); 40060 //Initialization Code 40061 base.$el.gsb_responsiveListener(base); 40062 }; 40063 base._printbutton = function () { 40064 if (!base.$el.length) { 40065 return; 40066 } 40067 if ($('#' + base.options.printbutton_id).length == 0) { 40068 pattern = $('<span id="' + base.options.printbutton_id + '"><a class="button" href="#" title="' + base.options.tooltip + '">' + base.options.page_text + '</a></span>'); 40069 base.$el.prepend(pattern); 40070 } 40071 base.$el.parent().find('#' + base.options.printbutton_id + ' a').on("click", function (e) { 40072 e.preventDefault(); 40073 e.stopPropagation(); 40074 window.print(); 40075 }); 40076 }; 40077 base._uninit = function () { 40078 if (base.$el.find('#' + base.options.printbutton_id)) { 40079 base.$el.find('#' + base.options.printbutton_id).off().remove(); 40080 } 40081 }; 40082 // Run initializer 40083 base.init(); 40084 }; 40085 $.gsb.printbutton.defaultOptions = { 40086 tooltip: typeof PRINT_BUTTON_TOOLTIP == 'undefined' ? 'Datenblatt durcken (öffnet Dialog)' : PRINT_BUTTON_TOOLTIP, 40087 page_text: typeof PRINT_BUTTON_TEXT == 'undefined' ? 'drucken' : PRINT_BUTTON_TEXT, 40088 printbutton_id: 'navFunctionsPrint', 40089 respondToEvents: true, 40090 onRefresh: function onRefresh() { 40091 this._printbutton(); 40092 }, 40093 responsive: [{ 40094 breakpoint: 1024, 40095 onRefresh: function onRefresh() { 40096 this._uninit(); 40097 } 40098 }] 40099 }; 40100 $.fn.gsb_printbutton = function (options) { 40101 return this.each(function () { 40102 new $.gsb.printbutton(this, options); 40103 }); 40104 }; 40105})(jQuery); 40106 /* Ende gsb_print */ 40107 /* Start gsb_slideshow */ 40108 /*! 40109 * GSB-Wrapper-Plugin fuer slick.js. 40110 * 40111 * s. auch http://kenwheeler.github.io/slick/ 40112 * 40113 * Optionen: 40114 * nextButtonImage: Das Hintergrundbild fuer den aktiven weiter-Link der Navigation(default: null) 40115 * nextButtonInactiveImage: Das Hintergrundbild fuer den inaktiven weiter-Link der Navigation(default: null)
40116 * nextTitle: Das title-Attribut fuer den aktiven weiter-Link der Navigation 40117 * (default: SLIDER_NEXT bzw. 'Nächste Seite') 40118 * nextTitleInactive: Das title-Attribut fuer den inaktiven weiter-Link der Navigation 40119 * (default: SLIDER_NEXT_INACTIVE bzw. 'Keine nächste Seite') 40120 * prevButtonImage: Das Hintergrundbild fuer den aktiven zurueck-Link der Navigation(default: null) 40121 * prevButtonInactiveImage: Das Hintergrundbild fuer den aktiven zurueck-Link der Navigation(default: null) 40122 * prevTitle: Das title-Attribut fuer den aktiven zurueck-Link der Navigation 40123 * (default: SLIDER_BACK bzw. 'Vorherige Seite') 40124 * prevTitleInactive: Das title-Attribut fuer den aktiven zurueck-Link der Navigation 40125 * (default: SLIDER_BACK_INACTIVE bzw. 'Keine vorherige Seite') 40126 * playButtonImagePlaying: Das Hintergrundbild fuer den Playbutton im abspielenden Zustand(default: null) 40127 * playButtonImagePaused: Das Hintergrundbild fuer den Playbutton im pausierten Zustand(default: null) 40128 * playButtonAltTextPlaying: Das alt-Attribut fuer den Playbutton im abspielenden Zustand 40129 * (default: SLIDER_PLAY bzw. 'Animation starten') 40130 * playButtonAltTextPaused: Das alt-Attribut fuer den Playbutton im pausierten Zustand 40131 * (default: SLIDER_PAUSE bzw. 'Animation stoppen') 40132 * slickOptions: native Optionen fuer das Slick Plugin(default: null, siehe Doku oben) 40133 * slickOptions.gsb.playButton: Soll ein Playbutton angelegt werden(default: true), an dieser Stelle 40134 * hinterlegt, um responsiven Reinitialisierungmechanismus von Slick zu nutzen 40135 * 40136 * Author: anuebel 40137 */ 40138 40139/*global jQuery, console, SLIDER_NEXT, SLIDER_NEXT_INACTIVE, SLIDER_BACK, SLIDER_BACK_INACTIVE */ 40140 40141// Multimedia-Einbindung mit requireGSBComponent erweitert 40142; 40143var gsb; 40144gsb = gsb || {}; 40145(function ($) { 40146 'use strict'; 40147 40148 if (!$.gsb) { 40149 $.gsb = {}; 40150 } 40151 40152 $.gsb.Slideshow = function (el, options) { 40153 var base = this; 40154 40155 base.$el = $(el); 40156 base.el = el; 40157 base.$el.data("gsb.Slideshow", base); 40158 40159 //noinspection JSUnusedGlobalSymbols 40160 base.defaultSlickOptions = { 40161 slide: '.slide', 40162 fade: true, 40163 infinite: false, 40164 draggable: false, 40165 adaptiveHeight: false, 40166 onBeforeChange: function onBeforeChange(slick) { 40167 //ohne diese Anweisung kann die Höhenberechnung fehlschlagen 40168 //die "falschen" Elemente werden in updateTabindex wieder verborgen 40169 slick.$slides.find('video, object').show(); 40170 }, 40171 onAfterChange: function onAfterChange(slick) { 40172 base.updateNavigation(slick); 40173 base.updateTabindex(slick); 40174 }, 40175 onInit: function onInit(slick) { 40176 var slideshowPluginInstance = slick.$slider.data('gsb.Slideshow'); 40177 var onSlickInit = slideshowPluginInstance.options.onSlickInit; 40178 if (typeof onSlickInit === 'function') { 40179 onSlickInit.call(slick, slick, base); 40180 } 40181 base.updateNavigation(slick); 40182 base.initMultimedia(); 40183 base.updateTabindex(slick); 40184 base.$el.trigger('init.slideshow.gsb'); 40185 }, 40186 // gsb Namespace zur Nutzung des responsiven Reinitialisierungsmechanismus 40187 gsb: { 40188 playButton: true 40189 } 40190 }; 40191 base.initMultimedia = function initMultimedia() { 40192 var base = this; 40193 if (base.$el.find('video, audio').length > 0) { 40194 var $video = base.$el.find('video, audio'); 40195 gsb.requireGSBComponent('bundle_multimedia', $video).done(function ($video) { 40196 $video.gsb_Multimedia({ 40197 externalApiRequiresConsent: !$('body').hasClass('js-youtube-consent-not-required') 40198 }); 40199 }); 40200 } 40201 }; 40202 base.updateTabindex = function updateTabindex(slick) { 40203 //Barrierefreiheit/Tabbing workaround 40204 var focusableItems = 'a, [tabindex], textarea, input, select, button, video, object', 40205 buggedItems = 'video, object'; 40206 slick.$slides.not('.slick-active').find(focusableItems).attr('tabindex', -1).end().find(buggedItems).hide(); 40207 slick.$slides.filter('.slick-active').find(focusableItems).attr('tabindex', 0).end().find(buggedItems).show(); 40208 }; 40209 40210 base.updateNavigationArrow = function ($arrow, activeImage, inactiveImage, activeArrowButtonTitle, inactiveArrowButtonTitle) { 40211 if ($arrow) {
40212 var $arrowButton = $arrow.is('button') ? $arrow : $arrow.find('button'), 40213 $arrowImage = $arrow.find('img'); 40214 if ($arrow.hasClass('slick-disabled')) { 40215 $arrowButton.attr('disabled', ''); 40216 $arrowButton.attr('title', inactiveArrowButtonTitle); 40217 $arrowImage.attr('src', inactiveImage); 40218 $arrowImage.attr('alt', ''); 40219 } else { 40220 $arrowButton.removeAttr('disabled'); 40221 $arrowButton.attr('title', activeArrowButtonTitle); 40222 $arrowImage.attr('src', activeImage); 40223 $arrowImage.attr('alt', activeArrowButtonTitle); 40224 } 40225 } 40226 }; 40227 40228 /** 40229 * Fuehrt Manipulationen an der HTML-Struktur der Navigation durch. Dazu gehoeren u.a. die Aktualisierung der 40230 * Bilder und die Nachruestung von Elementen, die fuer die Barrierefreiheit relevant sind. 40231 * @param slick das Slick-Objekt, das Informationen ueber den Zustand des Karussells enthaelt. 40232 */ 40233 base.updateNavigation = function (slick) { 40234 if (base.options.hideArrowsIfPossible) { 40235 if (slick.$slides.length <= slick.options.slidesToShow) { 40236 base.$el.next().find('.next, .prev').hide(); 40237 } else { 40238 base.$el.next().find('.next, .prev').show(); 40239 } 40240 } 40241 40242 base.updateNavigationArrow(slick.$prevArrow, base.options.prevButtonImage, base.options.prevButtonInactiveImage, base.options.prevTitle, base.options.prevTitleInactive); 40243 base.updateNavigationArrow(slick.$nextArrow, base.options.nextButtonImage, base.options.nextButtonInactiveImage, base.options.nextTitle, base.options.nextTitleInactive); 40244 }; 40245 40246 /** 40247 * Einige der fuer das alte Slideshow-Plugin definierten Optionen werden auf die korrespondierenden 40248 * Slick-Optionen gemapt. Beispiel: pagination->dots 40249 * 40250 * Wird eine Legacy-Option in options gefunden, so wird sie dort geloescht und unter dem gemappten Namen in den 40251 * slickOptions registriert. 40252 * 40253 * @param slickOptions die Optionen, die an Slick uebergeben werden 40254 * @param options die Optionen, die an dieses Plugin uebergeben wurden 40255 */ 40256 base.handleLegacyOptions = function (slickOptions, options) { 40257 $.each($.gsb.Slideshow.slickOptionsForLegacyOptions, function (legacyOption, mappedSlickOption) { 40258 if (options.hasOwnProperty(legacyOption)) { 40259 var savedValue = options[legacyOption]; 40260 delete options[legacyOption]; 40261 slickOptions[mappedSlickOption] = savedValue; 40262 } 40263 }); 40264 }; 40265 40266 /** 40267 * Initialisiert die Dots. Wird ein Selektor angegeben, wird ausgehend von base.$el gesucht, andernfalls (also Object) 40268 * wird der Slick Standard ausgeführt. 40269 * Diese Funktion wird nur ausgeführt, wenn die Slick-Option appendDots gefüllt ist. 40270 * Sie ermöglicht es, die Postion im HTML der Dots zu bestimmen 40271 * @param slickOptions die Optionen, die an Slick uebergeben werden 40272 */ 40273 40274 base.handleDots = function (slickOptions) { 40275 var dotOptions = {}; 40276 if (typeof slickOptions.appendDots === "string") { 40277 dotOptions = { appendDots: base.$el.find(slickOptions.appendDots) }; 40278 } else { 40279 dotOptions = { appendDots: slickOptions.appendDots }; 40280 } 40281 40282 return $.extend({}, slickOptions, dotOptions); 40283 }; 40284 40285 /** 40286 * Initialisiert die Navigationspfeile. Diese duerfen erst nach einem etwaigen Austausch des HTML ermittelt werden, 40287 * da sie ggf. mit ersetzt werden. In diesem Fall wuerden ansonsten die nachgeladene Pfeile nicht 40288 * initialisiert. 40289 * @param slickOptions die Optionen, die an Slick uebergeben werden 40290 */ 40291 base.handleNavigationArrows = function (slickOptions) { 40292 var navigationArrowOptions = { 40293 nextArrow: base.$el.find('.next'), 40294 prevArrow: base.$el.find('.prev') 40295 }; 40296 return $.extend({}, navigationArrowOptions, slickOptions); 40297 }; 40298 40299 /** 40300 * Initialisiert den Playbutton, der zum Starten und Stoppen des Autoplay-Modus benutzt wird. 40301 * 40302 * Aufgrund des responsiven Reinitialisierungsmechanismus von Slick wird die Eigenschaft createPlayButton ueber 40303 * ein gsb-Objekt in den Slick-Options zur Verfuegung gestellt. 40304 * @param slickOptions die Optionen, die an Slick uebergeben werden 40305 */ 40306 base.handlePlayButton = function (slickOptions) { 40307 (function (existingOnInit) { 40308 slickOptions.onInit = function (slick) { 40309 // das zuvor konfigurierte onInit-Callback aufrufen 40310 existingOnInit.call(slick, slick); 40311 var initializedSlickOptions = slick.options; 40312 40313 function shouldCreatePlayButton() { 40314 var playButtonImagesAreConfigured = base.options.playButtonImagePlaying !== null && base.options.playButtonImagePaused !== null, 40315 createPlayButton = initializedSlickOptions.gsb.playButton; 40316 return createPlayButton && playButtonImagesAreConfigured; 40317 } 40318 40319 function preventPlay() { 40320 slick.paused = true; 40321 slick.autoPlayClear(); 40322 } 40323 40324 var $existingPlayButton = base.$el.parent().find('.navigation button.playbutton'), 40325 playButtonExists = $existingPlayButton.length; 40326 if (shouldCreatePlayButton() && !playButtonExists) { 40327 var slideshowStartsPlaying = initializedSlickOptions.autoplay, 40328 initialClassForPlayButton = slideshowStartsPlaying && 'playbutton-playing' || 'playbutton-paused', 40329 initialTitleAttrForPlayButton = slideshowStartsPlaying && base.options.playButtonAltTextPlaying || base.options.playButtonAltTextPaused, 40330 initialSrcAttrForPlayButtonImage = slideshowStartsPlaying && base.options.playButtonImagePlaying || base.options.playButtonImagePaused, 40331 initialAltAttrForPlayButtonImage = slideshowStartsPlaying && base.options.playButtonAltTextPlaying || base.options.playButtonAltTextPaused, 40332 $playButton = $('<button' + ' class="playbutton ' + initialClassForPlayButton + '"' + ' title="' + initialTitleAttrForPlayButton + '">' + '<img' + ' src="' + initialSrcAttrForPlayButtonImage + '"' + ' alt="' + initialAltAttrForPlayButtonImage + '">' + '</button>'), 40333 playButtonImage = $playButton.find('img'); 40334 base.$el.parent().find('.navigation').append($playButton); 40335 $playButton.click(function () { 40336 if ($playButton.is('.playbutton-playing')) { 40337 $playButton.removeClass().addClass('playbutton-paused').attr('title', base.options.playButtonAltTextPaused); 40338 playButtonImage.attr('src', base.options.playButtonImagePaused).attr('alt', base.options.playButtonAltTextPaused); 40339 base.$el.slick('slickPause');
40340 slick.$list.on('mouseleave.slick', preventPlay); 40341 } else { 40342 $playButton.removeClass().addClass('playbutton-playing').attr('title', base.options.playButtonAltTextPlaying); 40343 playButtonImage.attr('src', base.options.playButtonImagePlaying).attr('alt', base.options.playButtonAltTextPlaying); 40344 base.$el.slick('slickPlay'); 40345 slick.$list.off('mouseleave.slick', preventPlay); 40346 } 40347 }); 40348 } else if (!shouldCreatePlayButton() && playButtonExists) { 40349 $existingPlayButton.remove(); 40350 } 40351 }; 40352 })(slickOptions.onInit); 40353 return slickOptions; 40354 }; 40355 base.init = function () { 40356 base.options = $.extend({}, $.gsb.Slideshow.defaultOptions, options); 40357 40358 var allElementsUrl = base.$el.data('href'), 40359 initSlick = function initSlick() { 40360 var rawSlickOptions = base.options.slickOptions; 40361 delete rawSlickOptions.onInit; 40362 var slickOptions = $.extend({}, base.defaultSlickOptions, rawSlickOptions); 40363 base.handleLegacyOptions(slickOptions, base.options); 40364 slickOptions = base.handleNavigationArrows(slickOptions); 40365 slickOptions = base.handlePlayButton(slickOptions); 40366 40367 if (slickOptions.appendDots) { 40368 slickOptions = base.handleDots(slickOptions); 40369 } 40370 40371 var onSlickBeforeInit = slickOptions.onSlickBeforeInit; 40372 if (typeof onSlickBeforeInit === 'function') { 40373 onSlickBeforeInit.call(base, base); 40374 } 40375 40376 base.$el.on('init', function (e, slick) { 40377 slickOptions.onInit.call(base, slick); 40378 }); 40379 40380 base.$el.on('afterChange', function (e, slick) { 40381 slickOptions.onAfterChange.call(base, slick); 40382 }); 40383 base.$el.on('beforeChange', function (e, slick) { 40384 slickOptions.onBeforeChange.call(base, slick); 40385 }); 40386 40387 base.$el.slick(slickOptions); 40388 }, 40389 onReceiveAllElements = function onReceiveAllElements(data) { 40390 base.$el.html(data); 40391 setTimeout(function () { 40392 initSlick(); 40393 }, 300); 40394 }; 40395 40396 if (allElementsUrl) { 40397 $.get(allElementsUrl, onReceiveAllElements); 40398 } else { 40399 initSlick(); 40400 } 40401 }; 40402 40403 base.init(); 40404 }; 40405 40406 /** 40407 * Die Standard-Optionen fuer das Plugin 40408 */ 40409 $.gsb.Slideshow.defaultOptions = { 40410 hideArrowsIfPossible: false, 40411 nextButtonImage: null, 40412 nextButtonInactiveImage: null,
40413 nextTitle: typeof NEXT === 'undefined' ? 'Nächste Seite' : NEXT, 40414 nextTitleInactive: typeof NEXT_INACTIVE === 'undefined' ? 'Keine nächste Seite' : NEXT_INACTIVE, 40415 prevButtonImage: null, 40416 prevButtonInactiveImage: null, 40417 prevTitle: typeof BACK === 'undefined' ? 'Vorherige Seite' : BACK, 40418 prevTitleInactive: typeof BACK_INACTIVE === 'undefined' ? 'Keine vorherige Seite' : BACK_INACTIVE, 40419 playButtonImagePaused: null, 40420 playButtonImagePlaying: null, 40421 playButtonAltTextPaused: typeof PLAY === 'undefined' ? 'Animation starten' : PLAY, 40422 playButtonAltTextPlaying: typeof PAUSE === 'undefined' ? 'Animation stoppen' : PAUSE, 40423 paginationTitle: typeof PAGE === 'undefined' ? 'Seite' : PAGE, 40424 slickOptions: null 40425 }; 40426 40427 /** 40428 * Das Mapping von alten Optionen fuer das gsb_slideshow.js Plugin auf Slick-Optionen 40429 * @see #handleLegacyOptions 40430 */ 40431 $.gsb.Slideshow.slickOptionsForLegacyOptions = { 40432 containerElement: 'slide', 40433 elementsToSlide: 'slidesToShow', 40434 autoplay: 'autoplay', 40435 autoSpeed: 'autoplaySpeed', 40436 pagination: 'dots', 40437 pauseOnHover: 'pauseOnHover' 40438 }; 40439 40440 $.fn.gsb_Slideshow = function (options) { 40441 return this.each(function () { 40442 return new $.gsb.Slideshow(this, options); 40443 }); 40444 }; 40445})(jQuery); 40446 /* Ende gsb_slideshow */ 40447 /* Start gsb_slideshow_rowAddon */ 40448 /*! 40449 * @name slideshow_rowAddon 40450 * @author @ 40451 * Licensed under the MIT license 40452 * 40453 * @requires slick < 1.5.0, 40454 * */ 40455; 40456(function ($) { 40457 if (!$.gsb) { 40458 $.gsb = {}; 40459 } 40460 ; 40461 40462 $.gsb.slideshow_rowAddon = function (el, options, slideshow) { 40463 // To avoid scope issues, use 'base' instead of 'this' 40464 // to reference this class from internal events and functions. 40465 var base = this; 40466 40467 // Access to jQuery and DOM versions of element 40468 base.$el = $(el); 40469 base.el = el; 40470 base.slideshow = slideshow; 40471 40472 // Add a reverse reference to the DOM object 40473 base.$el.data("gsb.slideshow_rowAddon", base); 40474 40475 base.init = function () { 40476 base.options = $.extend({}, $.gsb.slideshow_rowAddon.defaultOptions, options); 40477 base.$el.gsb_responsiveListener(base); 40478 }; 40479 40480 $.gsb.slideshow_rowAddon.prototype.setRows = function () { 40481 var teaser = base.slideshow.$el.find('.slide'); 40482 var html = '<div class="' + teaser.prop("class") + '">'; 40483 if (base.options.slidesPerRow > 1) { 40484 teaser.each(function (index) { 40485 html += "<div>" + $(this).html() + "</div>"; 40486 if ((index + 1) % base.options.slidesPerRow == 0 && index < teaser.length - 1) { 40487 html += '</div><div class="' + teaser.prop("class") + '">'; 40488 } 40489 }); 40490 html += "</div>"; 40491 base.slideshow.$el.empty().html(html); 40492 } 40493 }; 40494 40495 // Run initializer 40496 base.init(); 40497 }; 40498 40499 $.gsb.slideshow_rowAddon.defaultOptions = { 40500 respondToEvents: false, 40501 slidesPerRow: 2, 40502 onRefresh: function onRefresh() { 40503 this.setRows(); 40504 }, 40505 responsive: [{ 40506 breakpoint: 640, 40507 slidesPerRow: 1, 40508 onRefresh: function onRefresh() { 40509 this.setRows(); 40510 } 40511 }] 40512 }; 40513 40514 $.fn.gsb_slideshow_rowAddon = function (options, slideshow) { 40515 return this.each(function () { 40516 new $.gsb.slideshow_rowAddon(this, options, slideshow); 40517 }); 40518 }; 40519})(jQuery); 40520 /* Ende gsb_slideshow_rowAddon */ 40521 /* Start gsb_toggle */ 40522 /** 40523 * @module gsb_toggle 40524 * @version 1.5.3 40525 * @see {@link http://semver.org|Semantic Versioning} 40526 * @author pespeloe 40527 * 40528 * @desc Dieses Modul erstellt in der Default-Konfiguration eine Accordion in small und ein Tab-Modul in large 40529 * Ãber die einzelnen Optionen kann auch nur ein Tab oder nur ein Accordion erstellt werden. Mit der Klasse "active-control" 40530 * kann festgelegt werden, welcher Tab/Accordion bei der Initialisierung geöffnet sein soll.<br> 40531 * Wenn der Inhalt der Tabs nachgeladen werden soll, muss im Template ein data-href Attribut vorhanden sein. Gleiches Vorgehen 40532 * wie bei dem Modul gsb_Sldeshow.<br><br> 40533 * Fest definiert sind die Klassen<br> 40534 * "tabs-container" -> Klasse für den Wrapper des einzelnen Tabs<br> 40535 * "heading" -> Element was für die Steuerung als Accordion dient<br> 40536 * "tabs-list" -> Wrapper der Steuerelemente als Tab<br> 40537 * "active-control" -> Aktuell ausgewählter Tab/Accordion<br> 40538 * "inactive-control" -> inaktiver Tab/Accordion<br> 40539 * "gsb-toggle" -> Klasse des "Gesamt-Wrappers" 40540 *
40541 * @requires {@link external:jQuery} 40542 * @requires gsb_responsiveListener 40543 * 40544 * @example 40545 * HTML: Velocity 40546 * <div class="tabaccordion"> 40547 * <ul class="tabs-list"> 40548 * <li class="active-control"> 40549 * <a href="#">Inhalt (Tab Control)</a> 40550 * </li> 40551 * <li> 40552 * <a href="#">Inhalt 2 (Tab Control)</a> 40553 * </li> 40554 * </ul> 40555 * <div class="tabs-container"> 40556 * <h2 class="heading active-control">Inhalt (Accordion Control)</h2> 40557 * <div> 40558 * Inhalt 40559 * </div> 40560 * <h2 class="heading">Inhalt 2 (Accordion Control)</h2> 40561 * <div> 40562 * Inhalt 2 40563 * </div> 40564 * </div> 40565 * </div> 40566 * 40567 * @example 40568 * JS: init 40569 * $('.tabaccordion').gsb_toggle({options}); 40570 * 40571 * */ 40572; 40573(function ($) { 40574 if (!$.gsb) { 40575 $.gsb = {}; 40576 } 40577 ; 40578 40579 $.gsb.toggle = function (el, options) { 40580 // Access to $ and DOM versions of element 40581 var base = this; 40582 base.$el = $(el); 40583 base.el = el; 40584 this.base = base; 40585 // Add a reverse reference to the DOM object 40586 base.$el.data("gsb.toggle", base); 40587 40588 base.init = function () { 40589 this.base.options = $.extend({}, $.gsb.toggle.defaultOptions, options); 40590 var _ = this.base; 40591 40592 if (_.options.accordion && _.options.richTextAccordion) { 40593 _.addRichtextContainer(); 40594 } else { 40595 if (base.$el.data('href')) { 40596 $.get(base.$el.data('href'), function (data) { 40597 base.$el.html(data); 40598 base.$el.gsb_responsiveListener(_); 40599 }); 40600 } else { 40601 base.$el.gsb_responsiveListener(_); 40602 } 40603 } 40604 }; 40605 // Run initializer 40606 base.init(); 40607 }; 40608 40609 /** 40610 * @typedef defaultOptions 40611 * @type {object} 40612 * @property {object} options - Default Options des Scripts 40613 * @property {boolean} [options.tab=true] - Aktiviert / Deaktiviert die Tab-Funktion 40614 * @property {string} [options.tabControls='.tabs-list > li a'] - Steuerungselemente fuer die Tab-Darstellung 40615 * @property {boolean} [options.accordion=true] - Aktiviert / Deaktiviert die Accordion-Funktion 40616 * @property {boolean} [options.richTextAccordion=false] - Aktiviert / Deaktiviert die Richtext-Accordion-Funktion -> nur wenn Option accordion true ist. ACHTUNG: Es ist nur ein Richtext-Accordion pro Seite möglich! 40617 * @property {boolean} [options.accordionCloseOther=true] - Immer nur ein Accordion geöffnet lassen 40618 * @property {boolean} [options.accordionPanelHeight=false] - Berechnet die Höhe des aufzuklappenden Elements (das aufzuklappenden Element darf nicht per CSS auf display non gesetzt sein) 40619 * @property {jQuery} [options.accordionElementToOpen=null] - Ãffnet ein Element welches nicht in der eigentlich vorgegebenen Struktur ist 40620 * @property {boolean} [options.autoplay=false] - Autoplay für Tab aktivieren 40621 * @property {string} [options.playButtonImagePaused=null] - Icon welches im stop Zustand angezeigt werden soll (nur wenn autoplay true) 40622 * @property {string} [options.playButtonImagePlaying=null] - Icon welches im play Zustand angezeigt werden soll (nur wenn autoplay true) 40623 * @property {string} [options.playButtonAltTextPaused=null] - Alttext welcher im stop Zustand angezeigt werden soll (nur wenn autoplay true) 40624 * @property {string} [options.playButtonAltTextPlaying=null] - Alttext welcher im play Zustand angezeigt werden soll (nur wenn autoplay true) 40625 * @property {string} [options.accordionHeadingTitleClosed=null] - Title welcher angezeigt werden soll, wenn ein AccordionElement geschlossen ist 40626 * @property {string} [options.accordionHeadingTitleOpened=null] - Title welcher angezeigt werden soll, wenn ein AccordionElement geöffnet ist 40627 * @property {int} [options.autoSpeed=5000] - Nach welcher Zeit soll der Tab gewechselt werden? (nur wenn autoplay true) 40628 * @property {boolean} [options.playOnLoad=false] - Direkt nach laden der Seite autoplay starten (nur wenn autoplay true) 40629 * @property {boolean} [options.pauseOnHover=true] - Wenn hover ueber Bild oder Tab autoplay stoppen (nur wenn autoplay true) 40630 * @property {boolean} [options.changeOnHover=false] - Wenn hover ueber Bild oder Tab autoplay stoppen (nur wenn autoplay true) 40631 * @property {boolean} [options.allOpen=false] - Alle Accordion-Elemente direkt geöffnet 40632 * @property {boolean} [options.animateTab=false] - Animation für den wechsel der Tabs 40633 */ 40634 $.gsb.toggle.defaultOptions = { 40635 tab: true, 40636 tabControls: "> .tabs-list > li a", 40637 elements: '> .tabs-container > div', 40638 accordionControls: '> .tabs-container > .heading', 40639 accordion: true, 40640 richTextAccordion: false, 40641 accordionCloseOther: true, 40642 accordionPanelHeight: false, 40643 accordionElementToOpen: null, 40644 accordionElementsStopPropagation: '', 40645 autoplay: false, 40646 playButtonImagePaused: null, 40647 playButtonImagePlaying: null, 40648 playButtonAltTextPaused: typeof PLAY == 'undefined' ? 'Animation starten' : PLAY, 40649 playButtonAltTextPlaying: typeof PAUSE == 'undefined' ? 'Animation stoppen' : PAUSE, 40650 accordionHeadingTitleClosed: null, 40651 accordionHeadingTitleOpened: null, 40652 autoSpeed: '5000', 40653 playOnLoad: false, 40654 pauseOnHover: true, 40655 changeOnHover: false, 40656 allOpen: false, 40657 animateTab: false, 40658 respondToEvents: true, 40659 onRefresh: function onRefresh() { 40660 this.initialize(); 40661 this.refreshTab(); 40662 }, 40663 responsive: [{ 40664 breakpoint: 600, 40665 onRefresh: function onRefresh() { 40666 this.initialize(); 40667 this.autoplayStop(); 40668 this.$el.off("mouseenter mouseleave"); 40669 this.refreshAccordion(); 40670 }, 40671 autoplay: false 40672 }] 40673 }; 40674 40675 /** 40676 * @method initialize 40677 * @desc Initialisierung des Scripts 40678 */ 40679 $.gsb.toggle.prototype.initialize = function () { 40680 var _ = this.base; 40681 40682 if (!_.$el.hasClass('gsb-toggle')) { 40683 _.$el.addClass('gsb-toggle'); 40684 _.addClasses(); 40685 _.addClickfunction(); 40686 } 40687 40688 if (_.options.autoplay) { 40689 _.autoplay(); 40690 } 40691 }; 40692 40693 /** 40694 * @method addClasses 40695 * @desc Zugehörigkeit der Ãberschriften festlegen 40696 */ 40697 $.gsb.toggle.prototype.addClasses = function () { 40698 var _ = this.base; 40699 40700 if (_.options.tab === true) { 40701 40702 //Angabe welcher Tab aktiv gesetzt werden soll 40703 var activeTabIndex = $.inArray(_.$el.find(_.options.tabControls + '.active-control').get(0), _.$el.find(_.options.tabControls)); 40704 if (activeTabIndex == -1) { 40705 activeTabIndex = 0; 40706 } 40707 40708 _.$el.find(_.options.tabControls).each(function (index) { 40709 var tabControls = $(this); 40710 if (!tabControls.is('a') || tabControls.find('>a').length == 0) { 40711 tabControls.prop("tabindex", 0); 40712 } 40713 40714 tabControls.addClass('switch-panel' + index); 40715 if (index === activeTabIndex) { 40716 tabControls.addClass("active-control"); 40717 } else { 40718 tabControls.addClass("inactive-control"); 40719 } 40720 }); 40721 40722 _.$el.find(_.options.elements).each(function (index) { 40723 var elements = $(this); 40724 elements.addClass('switch-panel' + index); 40725 if (index === activeTabIndex) { 40726 elements.addClass("panel-opened"); 40727 } else { 40728 elements.addClass("panel-closed"); 40729 } 40730 }); 40731 } 40732 40733 if (_.options.accordion === true) { 40734 // Accorion hat bei start geöffnete Elemente 40735 var hasOpendElements = false;
40736 if (_.$el.find(_.options.tabControls + ".active-control").length > 0) { 40737 hasOpendElements = true; 40738 } 40739 _.$el.find(_.options.accordionControls).each(function () { 40740 var heading = $(this); 40741 40742 if (!heading.is('button') || !heading.is('a')) { 40743 if (_.options.accordionPanelHeight) { 40744 var height = 0; 40745 heading.next().find(">").each(function () { 40746 height += heading.outerHeight(true); 40747 }); 40748 heading.next().height(height); 40749 } 40750 heading.prop("tabindex", 0); 40751 if (_.options.allOpen && !_.options.tab) { 40752 heading.addClass('active-control').attr('aria-expanded', 'true').attr('aria-selected', 'true').next().attr('aria-hidden', 'false').show(); 40753 } else if (hasOpendElements) { 40754 if (!heading.hasClass("active-control")) { 40755 heading.attr('aria-expanded', 'false').attr('aria-selected', 'false').addClass("inactive-control").next().attr('aria-hidden', 'true').hide(); 40756 } else { 40757 heading.attr('aria-expanded', 'true').attr('aria-selected', 'true').next().attr('aria-hidden', 'false').show(); 40758 } 40759 } else { 40760 heading.attr('aria-expanded', 'false').attr('aria-selected', 'false').addClass("inactive-control").next().attr('aria-hidden', 'false').hide(); 40761 } 40762 } 40763 40764 _.changeAccordionHeadingTitle(heading); 40765 }); 40766 } 40767 }; 40768 40769 /** 40770 * @method addClickfunction 40771 * @desc Click Events hinzufügen 40772 */ 40773 $.gsb.toggle.prototype.addClickfunction = function () { 40774 var _ = this.base; 40775 40776 // Accordion 40777 if (_.options.accordion === true) { 40778 _.$el.on('click keydown', _.options.accordionControls, function (e) { 40779 if (e.type === 'click' || e.which == 13) { 40780 e.preventDefault(); 40781 e.stopPropagation(); 40782 _.clickedElem = $(this); 40783 _.changeStateAccordion(); 40784 } 40785 }).find(_.options.accordionElementsStopPropagation).on('click keydown', function (e) { 40786 e.stopPropagation(); 40787 }); 40788 } 40789 if (_.options.tab === true) { 40790 40791 // Autoplay muss deaktiviert sein, da die Events focusin und focusout im Firefox derzeit nocht nicht implementiert 40792 // sind bzw. noch bugs enthalten 40793 if (_.options.changeOnHover && !_.options.autoplay) { 40794 _.$el.on('mouseenter focus touchend', _.options.tabControls, function (e) { 40795 e.preventDefault(); 40796 e.stopPropagation(); 40797 _.clickedElem = $(this); 40798 _.changeStateTab(); 40799 }); 40800 40801 // Seitenwechsel für click unterdrücken 40802 _.$el.on('click', _.options.tabControls, function (e) { 40803 e.preventDefault(); 40804 e.stopPropagation(); 40805 }); 40806 } else { 40807 _.$el.on('click keydown', _.options.tabControls, function (e) { 40808 if (e.type === 'click' || e.which == 13) { 40809 e.preventDefault(); 40810 e.stopPropagation(); 40811 _.clickedElem = $(this); 40812 _.changeStateTab(); 40813 } 40814 }); 40815 } 40816 } 40817 }; 40818 40819 /** 40820 * @method changeStateAccordion 40821 * @param {Object} elem - Geklicktes Element 40822 * @desc Passt den title des headingElements je Status an (geöffnet/geschlossen) 40823 */ 40824 $.gsb.toggle.prototype.changeAccordionHeadingTitle = function (elem) { 40825 var _ = this.base; 40826 40827 if (elem.hasClass('active-control') && _.options.accordionHeadingTitleOpened) { 40828 elem.attr('title', _.options.accordionHeadingTitleOpened); 40829 } else if (!elem.hasClass('active-control') && _.options.accordionHeadingTitleClosed) { 40830 elem.attr('title', _.options.accordionHeadingTitleClosed); 40831 } 40832 }; 40833 40834 /** 40835 * @method changeStateAccordion 40836 * @desc Open-/Close-States Accordion 40837 */ 40838 $.gsb.toggle.prototype.changeStateAccordion = function () { 40839 var _ = this.base; 40840 40841 var contentElement; 40842 if (_.options.accordionElementToOpen) { 40843 contentElement = $(_.options.accordionElementToOpen); 40844 } else { 40845 contentElement = _.clickedElem.next(); 40846 } 40847 40848 if (_.clickedElem.hasClass('inactive-control')) { 40849 if (_.options.accordionCloseOther && !_.options.accordionElementToOpen) { 40850 _.animationAccordion(_.clickedElem.parent().find('> .active-control').next(), "close"); 40851 _.$el.find('.tabs-container > .active-control').removeClass('active-control').addClass('inactive-control'); 40852 } 40853 40854 _.clickedElem.attr('aria-expanded', 'true').attr('aria-selected', 'true').removeClass('inactive-control').addClass('active-control'); 40855 40856 _.animationAccordion(contentElement, "open"); 40857 contentElement.attr('aria-hidden', 'false'); 40858 } else { 40859 _.clickedElem.attr('aria-expanded', 'false').attr('aria-selected', 'false').removeClass('active-control').addClass('inactive-control'); 40860 40861 _.animationAccordion(contentElement, "close"); 40862 contentElement.attr('aria-hidden', 'true'); 40863 } 40864 40865 _.changeAccordionHeadingTitle(_.clickedElem); 40866 }; 40867 40868 /** 40869 * @method changeStateTab 40870 * @desc Open-/Close-States Tab 40871 */ 40872 $.gsb.toggle.prototype.changeStateTab = function () { 40873 var _ = this.base; 40874 40875 if (_.clickedElem.hasClass('inactive-control')) { 40876 var panelToClose = _.$el.find('.panel-opened'); 40877 40878 // "Alles auf 0 zurücksetzen" 40879 _.$el.find('[aria-hidden=false]').attr('aria-hidden', 'true'); 40880 _.$el.find('[aria-selected=true]').attr('aria-selected', 'false'); 40881 40882 var ariaControl = _.clickedElem.attr('aria-controls'); 40883 _.$el.find('#' + ariaControl).attr('aria-hidden', 'false'); 40884 _.clickedElem.attr('aria-selected', 'true'); 40885 panelToClose.removeClass('panel-opened').addClass('panel-closed'); 40886 _.$el.find('> .tabs-container >.active-control,' + _.options.tabControls + '.active-control ').removeClass('active-control').addClass('inactive-control'); 40887 _.clickedElem.removeClass('inactive-control'); 40888 var panelToOpen = _.$el.find('> .tabs-container > .' + _.getSwitchPanelClass(_.clickedElem)); 40889 panelToOpen.removeClass('panel-closed').addClass('panel-opened'); 40890 _.clickedElem.addClass('active-control'); 40891 _.animationTab(panelToClose, panelToOpen); 40892 _.addA11y(panelToOpen); 40893 } 40894 }; 40895 40896 /** 40897 * @method animationAccordion 40898 * @desc Animation für OpenClose des Accordions 40899 * 40900 * @param elem {Object} Element welches animiert werden soll 40901 * @param type Art der Animation - {string} open / close 40902 */ 40903 $.gsb.toggle.prototype.animationAccordion = function (elem, type) { 40904 var _ = this.base; 40905 40906 if (type === 'open') { 40907 elem.slideDown(400, function () { 40908 if (_.options.accordionElementToOpen) { 40909 _.addA11y(elem); 40910 } 40911 }); 40912 } else { 40913 elem.slideUp(); 40914 } 40915 }; 40916 40917 /** 40918 * @method animationTab 40919 * @desc Animation für OpenClose des Tabs 40920 * 40921 * @param panelToClose {Object} Element welches animiert werden soll (ausblenden) 40922 * @param panelToOpen {Object} Element welches animiert werden soll (einblenden) 40923 */ 40924 $.gsb.toggle.prototype.animationTab = function (panelToClose, panelToOpen) { 40925 var _ = this.base; 40926 40927 if (_.options.animateTab) { 40928 panelToClose.fadeOut("slow", function () { 40929 panelToOpen.fadeIn("slow"); 40930 }); 40931 } else { 40932 panelToClose.hide(); 40933 panelToOpen.show(); 40934 } 40935 }; 40936 40937 /** 40938 * @method autoplay 40939 * @desc Autoplay 40940 */ 40941 $.gsb.toggle.prototype.autoplay = function () { 40942 var _ = this.base; 40943 40944 if (_.$el.find('> button').length === 0) { 40945 var button = document.createElement('button'); 40946 button.className = 'paused'; 40947 var image = document.createElement('img'); 40948 image.src = _.options.playButtonImagePlaying; 40949 image.alt = _.options.playButtonAltTextPlaying; 40950 playbutton = _.$el.append($(button).append(image)); 40951 } 40952 _.playbutton = _.$el.find('button.paused'); 40953 _.playbutton.on('click autoplayStart', function (e) { 40954 e.preventDefault(); 40955 e.stopPropagation(); 40956 if (_.playbutton.hasClass('paused')) { 40957 $(this).removeClass('paused').addClass('played'); 40958 _.autoplayStart(); 40959 _.changeStatePlayPause(_.options.playButtonImagePlaying, _.options.playButtonAltTextPlaying);
40960 _.isPaused = false; 40961 if (e.type != "autoplayStart") { 40962 //Damit nach Starten des Autoplays nicht nochmal autoplayStart von mouseleave aufgerufen wir 40963 _.isClicked = true; 40964 } 40965 } else { 40966 $(this).addClass('paused').removeClass('played'); 40967 _.autoplayStop(); 40968 _.changeStatePlayPause(_.options.playButtonImagePaused, _.options.playButtonAltTextPaused); 40969 _.isPaused = true; 40970 } 40971 }); 40972 40973 // Stop bei Hover 40974 if (_.options.pauseOnHover) { 40975 _.$el.on("mouseenter mouseleave", function (e) { 40976 if (!_.isPaused) { 40977 if (e.type == 'mouseenter') { 40978 _.autoplayStop(); 40979 } else { 40980 if (_.playbutton.hasClass('played') && !_.isClicked) { 40981 _.autoplayStart(); 40982 } 40983 _.isClicked = false; 40984 } 40985 } 40986 }); 40987 } 40988 40989 //play bei start 40990 if (_.options.playOnLoad) { 40991 _.playbutton.trigger("autoplayStart"); 40992 } 40993 }; 40994 40995 /** 40996 * @method autoplayStart 40997 * @desc Autoplay start 40998 */ 40999 $.gsb.toggle.prototype.autoplayStart = function () { 41000 var _ = this.base; 41001 41002 _.rotation = setInterval(function () { 41003 var lastTab = _.getSwitchPanelClass(_.$el.find('.tabs-list > li').last()); 41004 //Wenn letzter Tab, wieder beim ersten anfangen 41005 if (_.$el.find('.tabs-list .active-control').hasClass(lastTab[0])) { 41006 _.$el.find('.tabs-list > li').first().click(); 41007 } else { 41008 _.$el.find('.tabs-list .active-control').next().click(); 41009 } 41010 }, _.options.autoSpeed); 41011 }; 41012 41013 /** 41014 * @method autoplayStop 41015 * @desc Autoplay stop 41016 */ 41017 $.gsb.toggle.prototype.autoplayStop = function () { 41018 var _ = this.base; 41019 41020 clearInterval(_.rotation); 41021 }; 41022 41023 /** 41024 * @method refreshTab 41025 * @desc Refresh Tab 41026 */ 41027 $.gsb.toggle.prototype.refreshTab = function () { 41028 var _ = this.base; 41029 41030 if (_.options.tab) { 41031 _.$el.find('.tabs-container').removeAttr('multiselectable'); 41032 _.$el.find('.tabs-container').removeAttr('role'); 41033 _.$el.find('.heading').each(function () { 41034 $(this).removeAttr('aria-expanded'); 41035 }); 41036 41037 // Autoplay muss deaktiviert sein, da die Events focusin und focusout im Firefox derzeit nocht nicht implementiert 41038 // sind bzw. noch bugs enthalten 41039 if (_.options.changeOnHover && !_.options.autoplay) { 41040 _.$el.on('mouseenter focus', _.options.tabControls, function (e) { 41041 _.clickedElem = $(this); 41042 _.changeStateTab(); 41043 }); 41044 } 41045 41046 _.$el.find('.panel-closed').hide(); 41047 _.$el.find('.panel-opened').show(); 41048 } 41049 }; 41050 41051 /** 41052 * @method refreshAccordion 41053 * @desc Refresh Accordion 41054 */ 41055 $.gsb.toggle.prototype.refreshAccordion = function () { 41056 var _ = this.base; 41057 41058 if (_.options.accordion) { 41059 _.$el.find('.tabs-container').attr('role', 'tablist'); 41060 if (!_.options.accordionCloseOther) { 41061 _.$el.find('.tabs-container').attr('multiselectable', 'true'); 41062 } 41063 _.$el.find('.heading').each(function () { 41064 $(this).attr('aria-expanded', 'false'); 41065 $(this).hasClass('inactive-control') ? $(this).next().hide() : ""; 41066 }); 41067 } 41068 }; 41069 41070 /** 41071 * @method changeStatePlayPause 41072 * @param {string} imgsrc - Imagesource-Link 41073 * @param {string} alt - Alt-Text des Images 41074 * @desc Bild tauschen für Play/Pausebutton 41075 */ 41076 $.gsb.toggle.prototype.changeStatePlayPause = function (imgsrc, imgalt) { 41077 var _ = this.base; 41078 41079 var image = _.playbutton.find('img'); 41080 image.prop("alt", imgalt).prop("src", imgsrc); 41081 }; 41082 41083 /** 41084 * @method getSwitchPanelClass 41085 * @param {Object} elem - geklicktes Element (durchgereicht von changeState oder autoplayStart) 41086 * @desc Liefert die switch-panel Klasse des geklickten Elements 41087 */ 41088 $.gsb.toggle.prototype.getSwitchPanelClass = function (elem) { 41089 var panelClass = $.grep(elem.prop('class').split(" "), function (value) { 41090 return value.indexOf('switch-panel') > -1; 41091 }); 41092 return panelClass; 41093 }; 41094 41095 /** 41096 * @method uninitAccordion 41097 * @desc Destroy Accordion 41098 */ 41099 $.gsb.toggle.prototype.uninitAccordion = function () { 41100 var _ = this.base; 41101 41102 if (_.$el.hasClass('gsb-toggle')) { 41103 _.$el.off(); 41104 _.$el.removeClass('gsb-toggle'); 41105 _.$el.find('> .tabs-container > .heading').removeClass('active-control inactive-control').removeAttr("tabindex").next().removeAttr("style"); 41106 } 41107 }; 41108 41109 /** 41110 * @method addA11y 41111 * @desc setzt den focus auf das erste fokussierbare Element 41112 * @param elem {jQuery} Element welches nach fokussierbaren Elementen durchsucht wird. Ist mindestens ein Element vorhanden, 41113 * wird der Fokus gesetzt 41114 * @param tabPanel {jQuery} Element auf welches gesprungen werden soll, wenn im TabContainer keiner fokussierbaren Element vorhanden sind 41115 */ 41116 $.gsb.toggle.prototype.addA11y = function (elem, tabPanel) { 41117 var _ = this.base; 41118 41119 elem = elem || _.$el; 41120 var focusElements = elem.find('input,textarea,select,a,button').not(':hidden'); 41121 if (focusElements.length) { 41122 focusElements[0].focus();
41123 focusElements.last().keydown(function (e) {}); 41124 } 41125 }; 41126 41127 /** 41128 * @method addRichtextContainer 41129 * @desc Sucht im z.B. Content nach Elementen mit den Klasse startaccordion, endaccordion und accordionheadline und 41130 * baut die für gsb_toggle benötigte Struktur um diese Elemente 41131 * 41132 * Wenn alle benötigten Elemente eingebaut wurden, ruft sich das Script auf '.richtext-accordion' mit der Option 41133 * richTextAccordion nochmal selbst auf 41134 */ 41135 $.gsb.toggle.prototype.addRichtextContainer = function () { 41136 var _ = this.base; 41137 41138 _.$el.find('.startaccordion').each(function () { 41139 $(this).nextUntil('.endaccordion').addBack().add($(this).find('~.endaccordion').first()).wrapAll('<div class="tabs-container"/>'); 41140 var wrapper = $(this).parent(); 41141 41142 wrapper.find('.startaccordion, .accordionheadline').addClass('heading'); 41143 wrapper.find('.heading').each(function () { 41144 $(this).nextUntil('.heading').wrapAll('<div/>'); 41145 }); 41146 wrapper.find('.heading').last().nextUntil('.accordionend').add(wrapper.find('.accordionend')).wrapAll('<div/>'); 41147 wrapper.wrap('<div class="richtext-accordion"/>'); 41148 }); 41149 41150 _.$el.removeData('gsb.toggle'); 41151 _.$el.find('.richtext-accordion').gsb_toggle($.extend({}, _.options, { richTextAccordion: false })); 41152 }; 41153 41154 $.fn.gsb_toggle = function (options) { 41155 return this.each(function () { 41156 new $.gsb.toggle(this, options); 41157 }); 41158 }; 41159})(jQuery); 41160 /* Ende gsb_toggle */ 41161 /* Start gsb_togglebar */ 41162 /*! 41163 * GSB-Plugin zum Erstellung von Menue-Leiste fuer mobile Navigation 41164 * 41165 * Author: sbaecker 41166 * 41167 * @requires jQuery >= 1.11.1, gsb_responsiveListener 41168 */ 41169 41170; 41171(function ($) { 41172 if (!$.gsb) { 41173 $.gsb = {}; 41174 } 41175 ; 41176 $.gsb.togglebar = function (el, options) { 41177 // To avoid scope issues, use 'base' instead of 'this' 41178 // to reference this class from internal events and functions. 41179 var base = this; 41180 // Access to $ and DOM versions of element 41181 base.$el = $(el); 41182 base.el = el; 41183 // Add a reverse reference to the DOM object 41184 base.$el.data("gsb.togglebar", base); 41185 41186 base.init = function () { 41187 base.options = $.extend({}, $.gsb.togglebar.defaultOptions, options); 41188 base.$el.gsb_responsiveListener(base); 41189 }; 41190 base.generate = function () { 41191 //Initialization Code 41192 if ($('#navServiceGS').length > 0 && $('#navServiceLS').length > 0) { 41193 41194 var gs_link = $('#navServiceGS'); 41195 gs_link.find('a').attr("title", $('#navServiceGS a').text()); 41196 var gs = '<li class="navServiceGS">' + gs_link.html() + '</li>'; 41197 41198 var ls_link = $('#navServiceLS'); 41199 ls_link.find('a').attr("title", $('#navServiceLS a').text()); 41200 var ls = '<li class="navServiceLS">' + ls_link.html() + '</li>'; 41201 } else { 41202 41203 var gs = ""; 41204 var ls = ""; 41205 } 41206 if ($('#togglenav').length == 0) { 41207 base.$el.prepend('<div id="togglenav">' + '<ul class="left">' + '<li id="navMobileMenu">' + '<a href="#">Menü</a>' + '</li>' + '<li id="navMobileSearch">' + '<a href="#">Suche</a>' + '</li>' + '</ul>' + '<ul class="right">' + gs + ls + '</ul></div>'); 41208 } 41209 }; 41210 41211 //Funktion falls das Skript zur Laufzeit deaktiviert werden muss 41212 base._uninit = function () { 41213 $('#togglenav').remove(); 41214 }; 41215 41216 // Run initializer 41217 base.init(); 41218 }; 41219 $.gsb.togglebar.defaultOptions = { 41220 respondToEvents: true, 41221 onRefresh: function onRefresh() { 41222 this._uninit(); 41223 }, 41224 responsive: [{ 41225 breakpoint: 1024, 41226 onRefresh: function onRefresh() { 41227 this.generate(); 41228 } 41229 }] 41230 }; 41231 $.fn.gsb_togglebar = function (options) { 41232 return this.each(function () { 41233 new $.gsb.togglebar(this, options); 41234 }); 41235 }; 41236})(jQuery); 41237 /* Ende gsb_togglebar */ 41238 /* Start gsb_navigation_mobile */ 41239 /** 41240 * @module navigation_mobile --- Mandantenanpassung 41241 * @version 2.1.1 41242 * @see {@link http://semver.org|Semantic Versioning} 41243 * @author pespeloe 41244 * 41245 * @desc Dieses Modul fügt 41246 * 1. Wenn konfiguerte, eine "togglebar" mit den Menübutton zum Ãffnen des MMenu hinzu (base.$el.prepend) 41247 * 2. Die Grundkonfiguration des MMenu hinzu - nur Angabe der Optionen templateNavBar und menuHtml = MMenu aus SL OHNE autosuggest 41248 * 3. WAI-ARIA Support hinzu 41249 * 4. Tastaturbedienbarkeit des MMenu, bei geöffnetem Menu hinzu 41250 * 5. Den Responsive Listener hinzu 41251 *
41252 * @requires {@link external:jQuery} 41253 * @requires gsb_responsiveListener 41254 * @requires gsb_ariaSupport 41255 * 41256 * 41257 * @example 41258 * JS: init (Einfachster Aufruf) 41259 * $('#wrapperDivisions').gsb_navigation_mobile({ 41260 * menuHtml: json_url_... 41261 * }); 41262 * */ 41263; 41264(function ($) { 41265 if (!$.gsb) { 41266 $.gsb = {}; 41267 } 41268 ; 41269 41270 $.gsb.navigation_mobile = function (el, options) { 41271 // To avoid scope issues, use 'base' instead of 'this' 41272 // to reference this class from internal events and functions. 41273 var base = this; 41274 41275 // Access to jQuery and DOM versions of element 41276 base.$el = $(el); 41277 base.el = el; 41278 41279 base.utils = new NavigationUtils(); 41280 41281 // Add a reverse reference to the DOM object 41282 base.$el.data("gsb.navigation_mobile", base); 41283 41284 base.init = function () { 41285 base.options = $.extend({}, $.gsb.navigation_mobile.defaultOptions, options); 41286 $('body').gsb_responsiveListener(base); 41287 }; 41288 41289 /** 41290 * @method initMenu 41291 * @desc Initialisierung des Menüs 41292 */ 41293 $.gsb.navigation_mobile.prototype.initMenu = function () { 41294 41295 base.overlay = base.utils.getOverlay(); 41296 base.searchUtil = base.utils.getSearch(); 41297 41298 if (!base.overlay) { 41299 base.utils.setOverlay($('<div id="navigation-overlay"/>')); 41300 base.utils.getOverlay().insertAfter($(base.options.overlayPosition)); 41301 base.overlay = base.utils.getOverlay(); 41302 } else { 41303 base.overlay.detach().insertAfter($(base.options.overlayPosition)); 41304 } 41305 41306 if (!base.searchUtil) { 41307 base.utils.setSearch($('#search')); 41308 base.searchUtil = base.utils.getSearch(); 41309 } 41310 41311 if (typeof base.options.beforeInit === 'function') { 41312 base.options.beforeInit.call($(this), base); 41313 } 41314 41315 base.createMenuContainer(); 41316 41317 if (base.options.menuHtml != null) { 41318 $.ajax({ 41319 url: base.options.menuHtml, 41320 dataType: 'html', 41321 success: function success(data) { 41322 41323 base.menu = $('#menu'); 41324 base.menu.html(data); 41325 41326 var activeNode = base.menu.find('#mm-' + $('body').data('nn') + ' a').first(); 41327 $('<strong>' + activeNode.text() + '</strong>').addClass(activeNode.prop('class')).insertAfter(activeNode); 41328 activeNode.remove(); 41329 41330 base.nav = base.menu.find('.nav'); 41331 base.search = base.menu.find('.searchfieldWrapper'); 41332 41333 base.search.append(base.searchUtil); 41334 41335 base.menu.find('.level-2').each(function () { 41336 var level2 = $(this); 41337 41338 if (level2.find('>.back').length == 0) { 41339 var backLink = $('<li class="back"/>'); 41340 level2.prepend(backLink); 41341 var link = $('<button/>'); 41342 var image = $('<img src="' + base.options.backButtonImage + '" alt="' + base.options.backButtonAlt + '"/>'); 41343 link.append(image); 41344 link.append('<span>' + base.options.firstBackButtonText + '</span>'); 41345 backLink.append(link); 41346 } 41347 }); 41348 41349 base.menu.find('.level-1').addClass('active'); 41350 base.menu.find('.forward').parent().parent().siblings('ul').addClass('inactive'); 41351 41352 base.utils.scrollingElements(base.menu, base); 41353 base.utils.addScollingLinks(base.menu, base, 'mobile'); 41354 41355 base.mainNavWrapper = base.menu.find('.mainNavWrapper'); 41356 base.mainNavWrapper.css({ height: base.menu.find('.level-1').outerHeight() }); 41357 41358 base.nav.addClass('closed'); 41359 base.search.addClass('closed'); 41360 41361 base.menu.on('click', '.forward', function (e) { 41362 e.preventDefault(); 41363 e.stopPropagation(); 41364 41365 var siblingUl = $(this).parent().parent().siblings('ul'); 41366 base.mainNavWrapper.css({ height: siblingUl.outerHeight() }); 41367 siblingUl.removeClass('inactive').addClass('active'); 41368 }); 41369 41370 base.menu.on('click', '.back button', function (e) { 41371 e.preventDefault(); 41372 e.stopPropagation(); 41373 41374 $(this).closest('.active').removeClass('active').addClass('inactive'); 41375 base.mainNavWrapper.css({ height: $(this).closest('.active').outerHeight() }); 41376 }); 41377 41378 base.menu.on('click', '.backToFirst button', function (e) { 41379 e.preventDefault(); 41380 e.stopPropagation(); 41381 41382 base.setTransition($(this).parentsUntil('.level-2').filter('ul'), 'inactive'); 41383 }); 41384 41385 //Menü öffnen Button 41386 base.$el.on('click', base.options.navOpenButton, function (e) { 41387 e.stopImmediatePropagation(); 41388 e.preventDefault(); 41389 if (base.nav.hasClass('opened')) { 41390 base.changeStatus($(this), base.nav, 'close', true); 41391 } else { 41392 if (base.isOpened(base.search)) { 41393 base.$el.find(base.options.navSearchButton).trigger('click'); 41394 } 41395 base.changeStatus($(this), base.nav, 'open', true); 41396 base.setActive(base.menu); 41397 } 41398 }); 41399 41400 //Lupe der Togglebar 41401 base.$el.on('click', base.options.navSearchButton, function (e) { 41402 e.stopImmediatePropagation(); 41403 e.preventDefault(); 41404 41405 if (base.search.hasClass('opened')) { 41406 base.changeStatus($(this), base.search, 'close'); 41407 } else { 41408 if (base.isOpened(base.nav)) { 41409 base.$el.find(base.options.navOpenButton).trigger('click'); 41410 } 41411 base.changeStatus($(this), base.search, 'open'); 41412 41413 //Autosuggest initialisieren 41414 if (base.options.autosuggestURL) { 41415 base.search.gsb_AutoSuggest(base.options.autosuggestURL); 41416 } 41417 } 41418 }); 41419 41420 if (typeof base.options.afterInit === 'function') { 41421 base.options.afterInit.call($(this), base); 41422 } 41423 } 41424 }); 41425 } 41426 }; 41427 41428 // Wird nur zum öffnen oder schlieÃen mehrerer Ebenen verwendet 41429 $.gsb.navigation_mobile.prototype.setTransition = function (elementList, state) {
41430 elementList.get().reverse().forEach(function (el) { 41431 var element = $(el); 41432 if (state == 'active') { 41433 element.addClass('active').removeClass('inactive'); 41434 } else { 41435 element.addClass('inactive').removeClass('active'); 41436 } 41437 }); 41438 41439 if (state == 'active') { 41440 base.mainNavWrapper.css({ height: elementList.first().outerHeight() }); 41441 } else { 41442 base.mainNavWrapper.css({ height: elementList.last().closest('.active').outerHeight() }); 41443 } 41444 }; 41445 41446 $.gsb.navigation_mobile.prototype.setActive = function (menuBox) { 41447 var $body = $('body'); 41448 if ($body.data('nn') && menuBox.find('.scrollingLevel ul #mm-' + $body.data('nn')).length > 0) { 41449 base.setTransition(menuBox.find('#mm-' + $body.data('nn')).parentsUntil('.level-1').filter('ul'), 'active'); 41450 } 41451 }; 41452 41453 /** 41454 * @method isOpened 41455 * @desc Ãberprüfung ob Element geöffnet ist oder nicht 41456 */ 41457 $.gsb.navigation_mobile.prototype.isOpened = function (elem) { 41458 if (elem.hasClass('opened')) { 41459 return true; 41460 } else { 41461 return false; 41462 } 41463 }; 41464 41465 /** 41466 * @method changeStatus 41467 * @desc ändert den Status des Element - öffnen oder schlieÃen 41468 * @param button {Object} geklickter button 41469 * @param elem {Object} Element ein oder ausgeblendet werden soll 41470 * @param type {String} Erlaubte Werte: open | close - wird geöffnet oder geschlossen? 41471 * @param setTogglebarClass {boolean} Angabe ob Klasse active an toggleBar hinzugefuegt werden soll 41472 */ 41473 $.gsb.navigation_mobile.prototype.changeStatus = function (button, elem, type, setTogglebarClass) { 41474 41475 setTogglebarClass = setTogglebarClass || false; 41476 41477 if (type == 'open') { 41478 base.overlay.addClass('active'); 41479 button.removeClass('closed').addClass('opened'); 41480 elem.removeClass('closed').addClass('opened'); 41481 $('body').addClass('fixed'); 41482 if (setTogglebarClass) { 41483 base.$el.find('.togglebar').addClass('active'); 41484 } 41485 } else { 41486 base.overlay.removeClass('active'); 41487 button.removeClass('opened').addClass('closed'); 41488 elem.removeClass('opened').addClass('closed'); 41489 $('body').removeClass('fixed'); 41490 if (setTogglebarClass) { 41491 base.$el.find('.togglebar').removeClass('active'); 41492 } 41493 } 41494 }; 41495 41496 /** 41497 * @method createMenuContainer 41498 * @desc MMenücontainer erstellen, falls nicht vorhanden 41499 */ 41500 $.gsb.navigation_mobile.prototype.createMenuContainer = function () { 41501 if (!$('#menu').length) { 41502 $('<div id="menu"/>').insertAfter('#header'); 41503 } 41504 }; 41505 41506 /** 41507 * @method uninit 41508 * @desc Destroy Menu 41509 */ 41510 $.gsb.navigation_mobile.prototype.uninit = function () { 41511 if (base.menu) { 41512 base.menu.remove(); 41513 } 41514 }; 41515 41516 /** 41517 * @method addA11y 41518 * @desc MMenu tastaturbedienbar machen bzw. Fokus auf erste fokussierbares Element setzen 41519 */ 41520 41521 $.gsb.navigation_mobile.prototype.addA11y = function (elem) { 41522 elem = elem || base.$el; 41523 var focusElements = elem.find('button,a,input,textarea,select'); 41524 focusElements[0].focus(); 41525 focusElements.last().keydown(function (e) { 41526 if (e.keyCode === 9) { 41527 e.preventDefault(); 41528 focusElements[0].focus(); 41529 } else if (e.keyCode === 13) { 41530 return true; 41531 } 41532 }); 41533 }; 41534 41535 // Run initializer 41536 base.init(); 41537 }; 41538 41539 /** 41540 * @typedef defaultOptions 41541 * @type {object} 41542 * @property {object} options - Default Options des Scripts 41543 * @property {String} [options.menuHtml] - Pfad zum HTML des Mobilen Menüs 41544 * @property {String] [options.navOpenButton] - Selektor Menübutton in der Navigationsbar 41545 * @property {String] [options.navSearchButton] - Selektor Suche Button in der Navigationsbar 41546 * @property {function] [options.beforeInit] - Funktionen die vor dem eigentlichen Script ausgeführt werden sollen 41547 * @property {function] [options.afterInit] - Funktionen die nach dem eigentlichen Script ausgeführt werden sollen 41548 * @property {boolean] [options.respondToEvents] - Responsive Listener "Default" ausführen wenn keine Breakpoint Angabe zutrifft 41549 * @property {function] [options.onRefresh] - Responsive "Default" 41550 * @property {Array] [options.responsive] - Angaben zu den verschiedenen Breakp
41550oints - hier können auch Funktionen des Scripts ausgeführt werden, 41551 * da base übergeben wird 41552 */ 41553 41554 $.gsb.navigation_mobile.defaultOptions = { 41555 menuHtml: 'modules/navigation_mobile/navigation_mobile.html', 41556 navOpenButton: '#navMobileMenu ', 41557 navSearchButton: '#navMobileSearch', 41558 scrollLayer: '.scrollingLevel', 41559 firstBackButtonText: FIRST_BACK, 41560 backButtonImage: image_url_mobile_back_button, 41561 backButtonAlt: BACK_BUTTON, 41562 backToFirstImage: image_url_mobile_backtofirst_button, 41563 backToFirstAlt: BACKTOFIRST_BUTTON, 41564 beforeInit: null, 41565 afterInit: null, 41566 overlayPosition: '#header', 41567 autosuggestURL: '../html/modules/autosuggest/json/autosuggest.json', 41568 respondToEvents: true, 41569 onRefresh: function onRefresh() { 41570 this.uninit(); 41571 }, 41572 responsive: [{ 41573 breakpoint: 1025, 41574 onRefresh: function onRefresh() { 41575 this.uninit(); 41576 this.initMenu(); 41577 } 41578 }] 41579 }; 41580 41581 $.fn.gsb_navigation_mobile = function (options) { 41582 return this.each(function () { 41583 new $.gsb.navigation_mobile(this, options); 41584 }); 41585 }; 41586})(jQuery); 41587 /* Ende gsb_navigation_mobile */ 41588 /* Start gsb_responsivetables */ 41589 /*! 41590 * GSB-Plugin zum wrappen von Tabellen fuer die mobile Darstellung 41591 * 41592 * Author: sbaecker 41593 */ 41594 41595;(function ($) { 41596 if (!$.gsb) { 41597 $.gsb = {}; 41598 } 41599 $.gsb.responsiveTables = function (el, options) { 41600 // To avoid scope issues, use 'base' instead of 'this' 41601 // to reference this class from internal events and functions. 41602 var base = this; 41603 // Access to $ and DOM versions of element 41604 base.$el = $(el); 41605 base.el = el; 41606 // Add a reverse reference to the DOM object 41607 base.$el.data("gsb.responsiveTables", base); 41608 base.init = function () { 41609 base.options = $.extend({}, $.gsb.responsiveTables.defaultOptions, options); 41610 41611 //Initialization Code 41612 if (base.$el.find('table').length > 0) { 41613 base.$el.find('table').each(function () { 41614 switch (base.options.way) { 41615 case 'scroll': 41616 $(this).wrap('<div class="responsiveTable"></div>'); 41617 break; 41618 default: 41619 $(this).wrap('<div class="responsiveTable"></div>'); 41620 break; 41621 } 41622 }); 41623 } 41624 }; 41625 41626 // Run initializer 41627 base.init(); 41628 }; 41629 $.gsb.responsiveTables.defaultOptions = { 41630 way: 'scroll' 41631 }; 41632 41633 $.fn.gsb_responsiveTables = function (options) { 41634 return this.each(function () { 41635 new $.gsb.responsiveTables(this, options); 41636 }); 41637 }; 41638})(jQuery); 41639 /* Ende gsb_responsivetables */ 41640 /* Start gsb_tooltip */ 41641 /*! 41642 * GSB-Wrapper-Plugin fuer Foundation Tooltip-Plugin. Arbeitet als Polyfill, um von Foundation benoetigte 41643 * data-Attribute und Klassen hinzuzufuegen. 41644 * 41645 * s. auch http://foundation.zurb.com/docs/components/tooltips.html 41646 * 41647 * Optionen: 41648 * tooltipPosition: Die Position des Tooltips(top,bottom(default),left,right) 41649 * tooltipCorners: Layoutmodus des Tooltip(''(default), 'radius', 'round') 41650 * tooltipFoundationOptions: native Optionen fuer das Foundation Plugin(undefined(default), siehe Doku oben) 41651 * 41652 * Abhängigkeiten: 41653 * 41654 * - modernizr(wegen Foundation) 41655 * - foundation 41656 * - foundation-tooltip 41657 * 41658 * Author: anuebel 41659 */ 41660 41661;(function ($) { 41662 'use strict'; 41663 41664 if (!$.gsb) { 41665 $.gsb = {}; 41666 } 41667 41668 $.gsb.tooltip = function (el, options) { 41669 var base = this; 41670 base.$el = $(el); 41671 base.el = el; 41672 base.$el.data("gsb.tooltip", base); 41673 41674 base.init = function () { 41675 base.options = $.extend({}, $.gsb.tooltip.defaultOptions, options); 41676 base.$el.addClass('has-tip tip-' + base.options.tooltipPosition + ' ' + base.options.tooltipCorners).attr('data-tooltip', '').attr('aria-haspopup', 'true'); 41677 // native Optionen des Foundation Plugins durchreichen 41678 if (base.options.tooltipFoundationOptions) { 41679 var serializedFoundationOptions = JSON.stringify(base.options.tooltipFoundationOptions);
41680 base.$el.attr('data-options', serializedFoundationOptions); 41681 } 41682 }; 41683 base.init(); 41684 }; 41685 41686 $.gsb.tooltip.defaultOptions = { 41687 tooltipPosition: 'bottom', 41688 tooltipCorners: '', 41689 tooltipFoundationOptions: undefined 41690 }; 41691 41692 $.fn.gsb_tooltip = function (options) { 41693 return this.each(function () { 41694 new $.gsb.tooltip(this, options); 41695 }); 41696 }; 41697})(jQuery); 41698 /* Ende gsb_tooltip */ 41699 /* Start gsb_twoclickshare */ 41700 /*! 41701 * GSB-Wrapper-Plugin fuer Heise-2-Klickloesung 41702 * 41703 * s. auch http://www.heise.de/extras/socialshareprivacy/ 41704 * 41705 * Author: rkrusenb 41706 */ 41707(function($){ 41708 if(!$ .gsb){ 41709 $ .gsb = {}; 41710 } 41711 $ .gsb.twoclickshare = function(el, userOptions){ 41712 var state = {}, 41713 options, 41714 wrapper, 41715 toggleElement, 41716 wrapperOuter; 41717 function init(){ 41718 options = state.options = $ .extend(true, {}, $ .gsb.twoclickshare.defaultOptions, userOptions); 41719 //wrapperOuter = $('<' + options.wrapperTag + ' />').attr('id', options.wrapperId); 41720 //wrapper = state.wrapper = $('<div/>').addClass(options.wrapperInnerClass); 41721 //wrapperOuter.append(wrapper); 41722 wrapper = $('<' + options.wrapperTag + ' />').attr('id', options.wrapperId); 41723 wrapperInner = state.wrapper = $('<div/>').addClass(options.wrapperInnerClass); 41724 wrapper.append(wrapperInner); 41725 if(options.insert == 'prepend'){ 41726 $(el).prepend(wrapper); 41727 } else if(options.insert == 'append'){ 41728 $(el).append(wrapper); 41729 } else if(options.insert == 'before'){ 41730 $(el).before(wrapper); 41731 } else if(options.insert == 'after'){ 41732 $(el).after(wrapper); 41733 } 41734 wrapperInner.socialSharePrivacy(options.socialSharePrivacyOptions) 41735 .prepend('<h3>' + options.labelHeader + '</h3>') 41736 .find('.switch, .settings').attr('tabindex', 0).keydown(function(ev){ 41737 if(ev.which == 13) { 41738 $(this).trigger('click'); 41739 } 41740 }); 41741 if(options.toggleElement) { 41742 toggleElement = $(options.toggleElement, el); 41743 wrapper.find('li:first').before($('<li class="email"><a>' + options.labelFormLink + '</a></li>').find('a').attr('href', toggleElement.attr('href')).end()); 41744 wrapper.data('gsb.twoclickshare', {oldHeight: wrapper.height()}).css({top: 0, display: 'none'}).attr('aria-hidden', 'true'); 41745 toggleElement.attr('aria-haspopup', true).attr('aria-owns', options.wrapperId).attr('title', options.toggleTitleClosed).click(function(ev){ 41746 var oldHeight = wrapper.data('gsb.twoclickshare').oldHeight; 41747 ev.preventDefault(); 41748 ev.stopPropagation(); 41749 if(wrapper.is('[aria-hidden=true]')) { 41750 /* CSS sorgt dafür, dass es "hoch" slidet */ 41751 wrapper.attr('aria-hidden', 'false').css({height: 0, display: 'block'}).animate({top: -oldHeight-2, height: oldHeight}, 'slow').promise().done(function(){$(this).css('height', '').css({top: -$(this).height()-2})}); 41752 wrapper.find('.close').focus(); 41753 toggleElement.attr("title",options.toggleTitleOpened); 41754 } else { 41755 /* CSS sorgt dafür, dass es "runter" slidet */ 41756 wrapper.attr('aria-hidden', 'true').data('gsb.twoclickshare', {oldHeight: wrapper.height()}).animate({top: 0, height: 0}, 'slow').promise().done(function(){$(this).css({display: 'none'})}); 41757 toggleElement.attr("title",options.toggleTitleClosed); 41758 } 41759 }); 41760 } 41761 wrapperInner.prepend($('<button class="close" tabindex="0">' + options.labelCloseButton + '</button>').click(function(){ 41762 toggleElement.trigger('click'); 41763 toggleElement.focus(); 41764 })); 41765 } 41766 init(); 41767 }; 41768 $ .gsb.twoclickshare.defaultOptions = { 41769 insert: 'after', //where the wrapper is inserted, in relation to el, 41770 wrapperId: 'share', //ID of the wrapper element, 41771 wrapperTag: 'div', //HTML tag of the wrapper element 41772 toggleElement: '', 41773 toggleTitleClosed: typeof SHOW_MORE != "undefined" ? SHOW_MORE : 'Mehr anzeigen', 41774 toggleTitleOpened: typeof SHOW_LESS != "undefined" ? SHOW_LESS : 'SchlieÃen', 41775 wrapperInnerClass: 'wrapper-share', 41776 labelHeader: typeof TWOCLICKSHARE_TITLE != "undefined" ? TWOCLICKSHARE_TITLE : 'In sozialen Medien teilen', 41777 labelFormLink: typeof TWOCLICKSHARE_FORMLINKTEXT != "undefined" ? TWOCLICKSHARE_FORMLINKTEXT : 'E-Mail', 41778 labelCloseButton: typeof CLOSE != "undefined" ? CLOSE : 'SchlieÃen', 41779 socialSharePrivacyOptions: { //see jquery.socialshareprivacy.js for all possible options 41780 css_path: '', 41781 services: { 41782 facebook: { 41783 dummy_img: typeof(image_url_share_facebook_inactive) != "undefined" ? image_url_share_facebook_inactive : '' 41784 }, 41785 twitter: { 41786 dummy_img: typeof(image_url_share_twitter_inactive) != "undefined" ? image_url_share_twitter_inactive : '' 41787 }, 41788 gplus: { 41789 dummy_img: typeof(image_url_share_gplus_inactive) != "undefined" ? image_url_share_gplus_inactive : '' 41790 } 41791 } 41792 } 41793 }; 41794 $ .fn.gsb_twoclickshare = function(options){ 41795 return $ (this).map(function(){ 41796 return $ .gsb.twoclickshare(this, options); 41797 }); 41798 }; 41799}(jQuery)); 41800 41801 /* Ende gsb_twoclickshare */ 41802 /* Start gsb_slideNavigation */ 41803 (function ($) { 41804 if (!$.gsb) { 41805 $.gsb = {}; 41806 } 41807 $.gsb.gsb_slideNavigation = function (el, options) { 41808 // To avoid scope issues, use 'base' instead of 'this' 41809 // to reference this class from internal events and functions. 41810 var base = this; 41811 var menuBoxWidth; 41812 // Access to jQuery and DOM versions of element 41813 base.$el = $(el); 41814 base.el = el; 41815 base.maxHeight = 0; 41816 base.utils = new NavigationUtils(); 41817 base.menuBox; 41818 41819 // Add a reverse reference to the DOM object 41820 base.$el.data("gsb.gsb_slideNavigation", base); 41821 base.init = function () { 41822 base.options = $.extend({}, $.gsb.gsb_slideNavigation.defaultOptions, options); 41823 base.$el.gsb_responsiveListener(base); 41824 }; 41825 $.gsb.gsb_slideNavigation.prototype.addClickfunction = function () { 41826 41827 // Wenn Browser kein translate3d kann, translate verwenden 41828 var bodyStyle = document.body.style; 41829 base.cssTransitions = false;
41830 if (bodyStyle.WebkitTransition !== undefined || bodyStyle.MozTransition !== undefined || bodyStyle.msTransition !== undefined) { 41831 base.cssTransitions = true; 41832 } 41833 41834 //Overlay aus static Variable holen 41835 base.overlay = base.utils.getOverlay(); 41836 base.searchUtil = base.utils.getSearch(); 41837 41838 if (!base.overlay) { 41839 base.utils.setOverlay($('<div id="navigation-overlay"/>')); 41840 base.utils.getOverlay().insertAfter($(base.options.overlayPosition)); 41841 base.overlay = base.utils.getOverlay(); 41842 } else { 41843 base.overlay.detach().insertAfter($(base.options.overlayPosition)); 41844 } 41845 41846 if (!base.searchUtil) { 41847 base.utils.setSearch($('#search')); 41848 base.searchUtil = base.utils.getSearch().detach(); 41849 } else { 41850 base.searchUtil = base.searchUtil.detach(); 41851 } 41852 41853 //------------ WAI-ARIA ------------------------------------------------- 41854 // Alle Control und Contentpanel selektieren 41855 base.controlPanel = base.$el.find(base.options.hoverItem).filter(function () { 41856 if ($(this).parent().siblings('.menu').length > 0) { 41857 return $(this); 41858 } 41859 }); 41860 base.contentPanel = base.$el.find('.menu-box'); 41861 41862 // Initial alles auf "closed" setzen 41863 base.aria = base.$el.gsb_ariaSupport(base); 41864 41865 //Erste Ebene 41866 base.$el.on('click', base.options.hoverItem, function (e) { 41867 if ($(this).closest('h3').siblings('.menu').length > 0) { 41868 41869 e.preventDefault(); 41870 e.stopPropagation(); 41871 base.menuBox = $(this).closest('li').find('.menu-box'); 41872 41873 if (base.menuBox.is(':visible')) { 41874 base.utils.getOverlay().removeClass('active'); 41875 $('body').removeClass('fixedNavPrimary'); 41876 $(this).closest('h3').removeClass('opened'); 41877 base.menuBox.hide(); 41878 $(base.options.overlayItem).removeClass("active"); 41879 //SchlieÃen 41880 base.aria.updateAria(this, true, true); 41881 base.maxHeight = 0; 41882 } else { 41883 $('body').addClass('fixedNavPrimary'); 41884 base.overlay.addClass('active'); 41885 41886 //oeffnen 41887 base.aria.updateAria(this, false, true); 41888 41889 //Geöffnete Flyouts schliessen 41890 base.$el.find('.search .opened').trigger('click'); 41891 41892 base.$el.find('.opened').removeClass('opened'); 41893 base.$el.find('.menu-box:visible').hide(); 41894 base.$el.find('.active').removeClass('active'); 41895 41896 if (base.menuBox.find('>.pageLink').length == 0) { 41897 var pageLink = $('<p class="pageLink"/>'); 41898 pageLink.insertAfter(base.menuBox.find('.close')); 41899 var link = $(this).clone(); 41900 pageLink.prepend(link); 41901 pageLink.find('a').text(base.options.pageLinkText + " " + link.text()); 41902 } 41903 41904 $(base.options.overlayItem).addClass("active"); 41905 $(this).closest('h3').addClass('opened'); 41906 base.menuBox.show(); 41907 41908 if (base.menuBox.find(base.options.scrollLayer + ' ul').length > 0 && base.menuBox.find('.animate').length == 0) { 41909 base.menuBox.find(base.options.scrollLayer + ' ul').each(function () { 41910 base.setTransition($(this), 'inactive', 'true'); 41911 }); 41912 41913 base.setActive(base.menuBox, base, 'desktop'); 41914 base.menuBox.find(base.options.scrollLayer + ' ul').addClass('animate'); 41915 } 41916 41917 //Höhe des Fylouts berechnen 41918 var windowHeight = $(window).height(); 41919 var navPrimaryHeight = base.$el.outerHeight(); 41920 var offset = base.$el.offset().top; 41921 base.maxHeight = windowHeight - offset - navPrimaryHeight + $(window).scrollTop(); 41922 base.menuBox.height(base.maxHeight); 41923 base.menuBox.width(menuBoxWidth); 41924 } 41925 } 41926 }); 41927 41928 base.utils.scrollingElements(base.$el, base); 41929 base.utils.addScollingLinks(base.$el, base, 'desktop'); 41930 base.addScollingClickFunction(); 41931 41932 //SchlieÃen Button 41933 base.closeButton = base.$el.find('p.close:first').clone(); 41934 base.$el.on('click', '.close button', function (e) { 41935 e.preventDefault(); 41936 e.stopPropagation(); 41937 41938 base.$el.find('.opened a, .opened strong').focus().trigger('click'); 41939 }); 41940 41941 //Suche Button 41942 base.$el.on('click', base.options.searchLink, function (e) { 41943 e.preventDefault(); 41944 e.stopPropagation(); 41945 41946 if ($(this).hasClass('opened')) { 41947 $(this).removeClass('opened').addClass('closed'); 41948 base.overlay.removeClass('active search'); 41949 base.overlay.empty(); 41950 } else { 41951 base.$el.find('.opened a').trigger('click'); 41952 base.overlay.append(base.searchUtil); 41953 $(this).addClass('opened').removeClass('closed'); 41954 base.overlay.addClass('active search'); 41955 41956 //Autosuggest initialisieren 41957 if (base.options.autosuggestURL) { 41958 base.searchUtil.gsb_AutoSuggest(base.options.autosuggestURL); 41959 } 41960 } 41961 }); 41962 }; 41963 41964 $.gsb.gsb_slideNavigation.prototype.addScollingClickFunction = function () { 41965 // Nächster Slide 41966 base.$el.on('click', base.options.scrollLayer + ' ' + base.options.scrollButton, function (e) { 41967 e.preventDefault(); 41968 e.stopPropagation(); 41969 41970 base.liVisibility($(this), 'next'); 41971 var siblingUl = $(this).closest('li').find('ul').first(); 41972 if (siblingUl.length > 0) { 41973 base.setTransition(siblingUl, 'active'); 41974 } 41975 }); 41976 41977 // Slide zurück 41978 base.$el.on('click', '.back > button', function (e) { 41979 e.preventDefault(); 41980 e.stopPropagation(); 41981 41982 base.liVisibility($(this), 'prev'); 41983 base.setTransition($(this).parent().parent('ul'), 'inactive'); 41984 }); 41985 41986 // Zurück zum ersten Slide 41987 base.$el.on('click', '.backToFirst > button', function (e) { 41988 e.preventDefault(); 41989 e.stopPropagation(); 41990 41991 base.liVisibility($(this), 'prev', true); 41992 base.setTransition($(this).parentsUntil(base.options.scrollLayer).filter('ul'), 'inactive'); 41993 }); 41994 }; 41995 41996 /** 41997 * 41998 * @param btn - button welcher geklickt wurde 41999 * @param direction - Wird vor ider zurück Navigiert? (next,prev) 42000 * @param fullRecursive - Li´s der Ãbergeordneten Ebene ausblenden, oder rekursiv bis topLevel? 42001 */ 42002 $.gsb.gsb_slideNavigation.prototype.liVisibility = function (btn, direction, fullRecursive) { 42003 42004 fullRecursive = fullRecursive || false; 42005 var siblingsLi; 42006 if (direction == 'prev') { 42007 siblingsLi = btn.parent().parent().closest('li').siblings(); 42008 } else { 42009 siblingsLi = btn.closest('li').siblings(); 42010 } 42011 42012 if (siblingsLi.is(':hidden')) { 42013 siblingsLi.show(); 42014 } else { 42015 siblingsLi.hide(); 42016 } 42017 42018 if (fullRecursive) { 42019 var parentBackButton = siblingsLi.filter('.back').find('button'); 42020 if (parentBackButton.length > 0) { 42021 base.liVisibility(parentBackButton, 'prev', true); 42022 } 42023 } 42024 }; 42025 42026 /** 42027 * 42028 * @param elem - element welches aktiv gesetzt werden soll 42029 * @param state 42030 */ 42031 $.gsb.gsb_slideNavigation.prototype.setTransition = function (elementList, state, initialcall) { 42032 42033 initialcall = initialcall || false;
42034 elementList.get().reverse().forEach(function (el) { 42035 var element = $(el); 42036 42037 if (!initialcall) { 42038 if (elementList.find('.close').length == 0) { 42039 var closeBtnWrapper = $('<li class="closeButton"/>'); 42040 closeBtnWrapper.append(base.closeButton); 42041 elementList.append(closeBtnWrapper); 42042 42043 //setTimeout(function () { 42044 base.addA11y(elementList); 42045 //},500); 42046 } 42047 } 42048 42049 if (state == 'active') { 42050 42051 if (base.maxHeight < base.menuBox.get(0).scrollHeight) { 42052 base.maxHeight = base.menuBox.get(0).scrollHeight; 42053 } 42054 42055 element.height(base.maxHeight); 42056 setTimeout(function () { 42057 element.find('a:first').focus(); 42058 }, 500); 42059 element.addClass('active').removeClass('inactive'); 42060 var parentLiOffset = 0, 42061 menuBoxOffset = 0, 42062 translatePosition = 0; 42063 parentLiOffset = element.closest('li').offset().left; 42064 menuBoxOffset = element.closest('.menu-box').offset().left; 42065 translatePosition = parentLiOffset - menuBoxOffset; 42066 42067 if (base.cssTransitions) { 42068 element.css('transform', 'translate3d(-' + translatePosition + 'px,0,0)'); 42069 } else { 42070 element.css('transform', 'translate(-' + translatePosition + 'px,0)'); 42071 } 42072 } else { 42073 element.css('height', 'auto'); 42074 element.addClass('inactive').removeClass('active'); 42075 //}, 500); 42076 var menuBoxWidth = element.closest('.menu-box').outerWidth(), 42077 parentLiPosition = element.closest('li').position().left, 42078 translatePosition = menuBoxWidth - parentLiPosition; 42079 42080 if (base.cssTransitions) { 42081 42082 element.css('transform', 'translate3d(' + translatePosition + 'px,0,0)'); 42083 } else { 42084 element.css('transform', 'translate(' + translatePosition + 'px,0)'); 42085 } 42086 } 42087 }); 42088 }; 42089 42090 $.gsb.gsb_slideNavigation.prototype.addA11y = function (elementList) { 42091 42092 var focusElements = elementList.find('a,button'); 42093 42094 focusElements[0].focus(); 42095 focusElements.last().keydown(function (e) { 42096 if (e.keyCode === 9) { 42097 e.preventDefault(); 42098 focusElements[0].focus(); 42099 } else if (e.keyCode === 13) { 42100 return true; 42101 } 42102 }); 42103 }; 42104 42105 $.gsb.gsb_slideNavigation.prototype.setActive = function (menuBox) { 42106 var $body = $('body'); 42107 if ($body.data('nn') && menuBox.find('.scrollingLevel ul #mm-' + $body.data('nn')).length > 0) { 42108 var activeNode = base.$el.find('#mm-' + $body.data('nn')); 42109 base.setTransition(activeNode.parentsUntil(base.options.scrollLayer).filter('ul'), 'active'); 42110 activeNode.addClass('active').removeClass('inactive'); 42111 42112 base.liVisibility(activeNode.siblings('.back').find('button'), 'prev', true); 42113 } 42114 }; 42115 42116 $.gsb.gsb_slideNavigation.prototype.uninit = function () { 42117 base.$el.find('li.back,li.backToFirst').remove(); 42118 base.$el.off(); 42119 }; 42120 42121 // Run initializer 42122 base.init(); 42123 }; 42124 $.gsb.gsb_slideNavigation.defaultOptions = { 42125 hoverItem: 'h3 a, h3 strong', 42126 searchLink: '.search > a', 42127 scrollLayer: '.scrollingLevel', 42128 scrollButton: 'li .forward', 42129 pageLinkText: PAGELINK, 42130 autosuggestURL: '../html/modules/autosuggest/json/autosuggest.json', 42131 overlayItem: '#navigation-overlay', 42132 overlayPosition: '#header', 42133 backLinkAural: BACK_BUTTON, 42134 backLinkAuraltoFirst: BACKTOFIRST_BUTTON, 42135 backButtonImage: image_url_mobile_back_button, 42136 backButtonAlt: BACK_BUTTON, 42137 backToFirstImage: image_url_mobile_backtofirst_button, 42138 backToFirstAlt: BACKTOFIRST_BUTTON, 42139 ariaType: "SLIDENAV", 42140 ariaSupport: { 42141 SLIDENAV: { 42142 firstOpen: true, 42143 panel: { 42144 id: function id(base) { 42145 return base.generateID(); 42146 }, 42147 aria_expanded: ["false", "true"], 42148 aria_controls: function aria_controls(base) { 42149 return base.generateID(); 42150 } 42151 }, 42152 content: { 42153 aria_hidden: ["true", "false"], 42154 id: function id(base, index) { 42155 return base.getPanelAttribute(index, "aria-controls"); 42156 }, 42157 aria_labelledby: function aria_labelledby(base, index) { 42158 return base.getPanelAttribute(index, "id"); 42159 } 42160 } 42161 } 42162 }, 42163 respondToEvents: true, 42164 onRefresh: function onRefresh() { 42165 this.addClickfunction(); 42166 }, 42167 responsive: [{ 42168 breakpoint: 1025, 42169 onRefresh: function onRefresh() { 42170 this.uninit(); 42171 } 42172 }] 42173 }; 42174 $.fn.gsb_slideNavigation = function (options) { 42175 return this.each(function () {
vendor: 30,605 bytes, lines 42176-42876
42176 new $.gsb.gsb_slideNavigation(this, options); 42177 }); 42178 }; 42179})(jQuery); 42180 /* Ende gsb_slideNavigation */ 42181 /* Start jquery.tablesorter */ 42182 (function ($) { 42183 $.extend({ 42184 tablesorter: new 42185 function () { 42186 var parsers = [], 42187 widgets = []; 42188 this.defaults = { 42189 cssHeader: "header", 42190 cssAsc: "headerSortUp", 42191 cssDesc: "headerSortDown", 42192 cssChildRow: "expand-child", 42193 sortInitialOrder: "asc", 42194 sortMultiSortKey: "shiftKey", 42195 sortForce: null, 42196 sortAppend: null, 42197 sortLocaleCompare: true, 42198 textExtraction: "simple", 42199 parsers: {}, widgets: [], 42200 widgetZebra: { 42201 css: ["even", "odd"] 42202 }, headers: {}, widthFixed: false, 42203 cancelSelection: true, 42204 sortList: [], 42205 headerList: [], 42206 dateFormat: "us", 42207 decimal: '/\.|\,/g', 42208 onRenderHeader: null, 42209 selectorHeaders: 'thead th', 42210 debug: false 42211 }; 42212 42213 function benchmark(s, d) { 42214 log(s + "," + (new Date().getTime() - d.getTime()) + "ms"); 42215 } 42216 this.benchmark = benchmark; 42217 function log(s) { 42218 if (typeof console != "undefined" && typeof console.debug != "undefined") { 42219 console.log(s); 42220 } else { 42221 alert(s); 42222 } 42223 } 42224 function buildParserCache(table, $headers) { 42225 if (table.config.debug) { 42226 var parsersDebug = ""; 42227 } 42228 if (table.tBodies.length == 0) return; 42229 var rows = table.tBodies[0].rows; 42230 if (rows[0]) { 42231 var list = [], 42232 cells = rows[0].cells, 42233 l = cells.length; 42234 for (var i = 0; i < l; i++) { 42235 var p = false; 42236 if ($.metadata && ($($headers[i]).metadata() && $($headers[i]).metadata().sorter)) { 42237 p = getParserById($($headers[i]).metadata().sorter); 42238 } else if ((table.config.headers[i] && table.config.headers[i].sorter)) { 42239 p = getParserById(table.config.headers[i].sorter); 42240 } 42241 if (!p) { 42242 p = detectParserForColumn(table, rows, -1, i); 42243 } 42244 if (table.config.debug) { 42245 parsersDebug += "column:" + i + " parser:" + p.id + "\n"; 42246 } 42247 list.push(p); 42248 } 42249 } 42250 if (table.config.debug) { 42251 log(parsersDebug); 42252 } 42253 return list; 42254 }; 42255 function detectParserForColumn(table, rows, rowIndex, cellIndex) { 42256 var l = parsers.length, 42257 node = false, 42258 nodeValue = false, 42259 keepLooking = true; 42260 while (nodeValue == '' && keepLooking) { 42261 rowIndex++; 42262 if (rows[rowIndex]) { 42263 node = getNodeFromRowAndCellIndex(rows, rowIndex, cellIndex); 42264 nodeValue = trimAndGetNodeText(table.config, node); 42265 if (table.config.debug) { 42266 log('Checking if value was empty on row:' + rowIndex); 42267 } 42268 } else { 42269 keepLooking = false; 42270 } 42271 } 42272 for (var i = 1; i < l; i++) { 42273 if (parsers[i].is(nodeValue, table, node)) { 42274 return parsers[i]; 42275 } 42276 } 42277 return parsers[0]; 42278 } 42279 function getNodeFromRowAndCellIndex(rows, rowIndex, cellIndex) { 42280 return rows[rowIndex].cells[cellIndex]; 42281 } 42282 function trimAndGetNodeText(config, node) { 42283 return $.trim(getElementText(config, node)); 42284 } 42285 function getParserById(name) { 42286 var l = parsers.length; 42287 for (var i = 0; i < l; i++) { 42288 if (parsers[i].id.toLowerCase() == name.toLowerCase()) { 42289 return parsers[i]; 42290 } 42291 } 42292 return false; 42293 } 42294 function buildCache(table) { 42295 if (table.config.debug) { 42296 var cacheTime = new Date(); 42297 } 42298 var totalRows = (table.tBodies[0] && table.tBodies[0].rows.length) || 0, 42299 totalCells = (table.tBodies[0].rows[0] && table.tBodies[0].rows[0].cells.length) || 0, 42300 parsers = table.config.parsers, 42301 cache = { 42302 row: [], 42303 normalized: [] 42304 }; 42305 for (var i = 0; i < totalRows; ++i) { 42306 var c = $(table.tBodies[0].rows[i]), 42307 cols = []; 42308 if (c.hasClass(table.config.cssChildRow)) { 42309 cache.row[cache.row.length - 1] = cache.row[cache.row.length - 1].add(c); 42310 continue; 42311 } 42312 cache.row.push(c); 42313 for (var j = 0; j < totalCells; ++j) { 42314 cols.push(parsers[j].format(getElementText(table.config, c[0].cells[j]), table, c[0].cells[j])); 42315 } 42316 cols.push(cache.normalized.length); 42317 cache.normalized.push(cols); 42318 cols = null; 42319 }; 42320 if (table.config.debug) { 42321 benchmark("Building cache for " + totalRows + " rows:", cacheTime); 42322 } 42323 return cache; 42324 }; 42325 function getElementText(config, node) { 42326 var text = ""; 42327 if (!node) return ""; 42328 if (!config.supportsTextContent) config.supportsTextContent = node.textContent || false; 42329 if (config.textExtraction == "simple") { 42330 if (config.supportsTextContent) { 42331 text = node.textContent; 42332 } else { 42333 if (node.childNodes[0] && node.childNodes[0].hasChildNodes()) { 42334 text = node.childNodes[0].innerHTML; 42335 } else { 42336 text = node.innerHTML; 42337 } 42338 } 42339 } else { 42340 if (typeof(config.textExtraction) == "function") { 42341 text = config.textExtraction(node); 42342 } else { 42343 text = $(node).text(); 42344 } 42345 } 42346 return text; 42347 } 42348 function appendToTable(table, cache) { 42349 if (table.config.debug) { 42350 var appendTime = new Date() 42351 } 42352 var c = cache, 42353 r = c.row, 42354 n = c.normalized, 42355 totalRows = n.length, 42356 checkCell = (n[0].length - 1), 42357 tableBody = $(table.tBodies[0]), 42358 rows = []; 42359 for (var i = 0; i < totalRows; i++) { 42360 var pos = n[i][checkCell]; 42361 rows.push(r[pos]); 42362 if (!table.config.appender) { 42363 var l = r[pos].length; 42364 for (var j = 0; j < l; j++) { 42365 tableBody[0].appendChild(r[pos][j]); 42366 } 42367 } 42368 } 42369 if (table.config.appender) { 42370 table.config.appender(table, rows); 42371 } 42372 rows = null; 42373 if (table.config.debug) { 42374 benchmark("Rebuilt table:", appendTime); 42375 } 42376 applyWidget(table); 42377 setTimeout(function () { 42378 $(table).trigger("sortEnd"); 42379 }, 0); 42380 }; 42381 function buildHeaders(table) { 42382 if (table.config.debug) { 42383 var time = new Date(); 42384 } 42385 var meta = ($.metadata) ? true : false; 42386 42387 var header_index = computeTableHeaderCellIndexes(table); 42388 $tableHeaders = $(table.config.selectorHeaders, table).each(function (index) { 42389 this.column = header_index[this.parentNode.rowIndex + "-" + this.cellIndex];; 42390 this.order = formatSortingOrder(table.config.sortInitialOrder); 42391 42392 42393 this.count = this.order; 42394 if (checkHeaderMetadata(this) || checkHeaderOptions(table, index)) this.sortDisabled = true; 42395 if (checkHeaderOptionsSortingLocked(table, index)) this.order = this.lockedOrder = checkHeaderOptionsSortingLocked(table, index); 42396 if (!this.sortDisabled) { 42397 var $th = $(this).addClass(table.config.cssHeader); 42398 if (table.config.onRenderHeader) table.config.onRenderHeader.apply($th); 42399 } 42400 table.config.headerList[index] = this; 42401 }); 42402 if (table.config.debug) { 42403 benchmark("Built headers:", time); 42404 log($tableHeaders); 42405 } 42406 return $tableHeaders; 42407 }; 42408 function computeTableHeaderCellIndexes(t) { 42409 var matrix = []; 42410 var lookup = {}; 42411 var thead = t.getElementsByTagName('THEAD')[0]; 42412 var trs = thead.getElementsByTagName('TR'); 42413 for (var i = 0; i < trs.length; i++) { 42414 var cells = trs[i].cells; 42415 for (var j = 0; j < cells.length; j++) { 42416 var c = cells[j]; 42417 var rowIndex = c.parentNode.rowIndex; 42418 var cellId = rowIndex + "-" + c.cellIndex; 42419 var rowSpan = c.rowSpan || 1; 42420 var colSpan = c.colSpan || 1 42421 var firstAvailCol; 42422 if (typeof(matrix[rowIndex]) == "undefined") { 42423 matrix[rowIndex] = []; 42424 } 42425 for (var k = 0; k < matrix[rowIndex].length + 1; k++) { 42426 if (typeof(matrix[rowIndex][k]) == "undefined") { 42427 firstAvailCol = k; 42428 break; 42429 } 42430 } 42431 lookup[cellId] = firstAvailCol; 42432 for (var k = rowIndex; k < rowIndex + rowSpan; k++) { 42433 if (typeof(matrix[k]) == "undefined") { 42434 matrix[k] = []; 42435 } 42436 var matrixrow = matrix[k]; 42437 for (var l = firstAvailCol; l < firstAvailCol + colSpan; l++) { 42438 matrixrow[l] = "x"; 42439 } 42440 } 42441 } 42442 } 42443 return lookup; 42444 } 42445 function checkCellColSpan(table, rows, row) { 42446 var arr = [], 42447 r = table.tHead.rows, 42448 c = r[row].cells; 42449 for (var i = 0; i < c.length; i++) { 42450 var cell = c[i]; 42451 if (cell.colSpan > 1) { 42452 arr = arr.concat(checkCellColSpan(table, headerArr, row++)); 42453 } else { 42454 if (table.tHead.length == 1 || (cell.rowSpan > 1 || !r[row + 1])) { 42455 arr.push(cell); 42456 } 42457 } 42458 } 42459 return arr; 42460 }; 42461 function checkHeaderMetadata(cell) { 42462 if (($.metadata) && ($(cell).metadata().sorter === false)) { 42463 return true; 42464 }; 42465 return false; 42466 } 42467 function checkHeaderOptions(table, i) { 42468 if ((table.config.headers[i]) && (table.config.headers[i].sorter === false)) { 42469 return true; 42470 }; 42471 return false; 42472 } 42473 42474 function checkHeaderOptionsSortingLocked(table, i) { 42475 if ((table.config.headers[i]) && (table.config.headers[i].lockedOrder)) return table.config.headers[i].lockedOrder; 42476 return false; 42477 } 42478 42479 function applyWidget(table) { 42480 var c = table.config.widgets; 42481 var l = c.length; 42482 for (var i = 0; i < l; i++) { 42483 getWidgetById(c[i]).format(table); 42484 } 42485 } 42486 function getWidgetById(name) { 42487 var l = widgets.length; 42488 for (var i = 0; i < l; i++) { 42489 if (widgets[i].id.toLowerCase() == name.toLowerCase()) { 42490 return widgets[i]; 42491 } 42492 } 42493 }; 42494 function formatSortingOrder(v) { 42495 if (typeof(v) != "Number") { 42496 return (v.toLowerCase() == "desc") ? 1 : 0; 42497 } else { 42498 return (v == 1) ? 1 : 0; 42499 } 42500 } 42501 function isValueInArray(v, a) { 42502 var l = a.length; 42503 for (var i = 0; i < l; i++) { 42504 if (a[i][0] == v) { 42505 return true; 42506 } 42507 } 42508 return false; 42509 } 42510 function setHeadersCss(table, $headers, list, css) { 42511 $headers.removeClass(css[0]).removeClass(css[1]); 42512 var h = []; 42513 $headers.each(function (offset) { 42514 if (!this.sortDisabled) { 42515 h[this.column] = $(this); 42516 } 42517 }); 42518 var l = list.length; 42519 for (var i = 0; i < l; i++) { 42520 h[list[i][0]].addClass(css[list[i][1]]); 42521 var header = h[list[i][0]]; 42522 var lnk = header.children('a.sortUp'); 42523 var lnkText = lnk.html(); 42524var newText = "" 42525 if(header.attr('class') == 'header headerSortDown'){ 42526 newText = lnkText.replace("+", "-"); 42527 } else if(header.attr('class') == 'header headerSortUp'){ 42528 newText = lnkText.replace("-", "+"); 42529 } 42530lnk.text(newText); 42531 } 42532 } 42533 function fixColumnWidth(table, $headers) { 42534 var c = table.config; 42535 if (c.widthFixed) { 42536 var colgroup = $('<colgroup>'); 42537 $("tr:first td", table.tBodies[0]).each(function () { 42538 colgroup.append($('<col>').css('width', $(this).width())); 42539 }); 42540 $(table).prepend(colgroup); 42541 }; 42542 } 42543 function updateHeaderSortCount(table, sortList) { 42544 var c = table.config, 42545 l = sortList.length; 42546 for (var i = 0; i < l; i++) { 42547 var s = sortList[i], 42548 o = c.headerList[s[0]]; 42549 o.count = s[1]; 42550 o.count++; 42551 } 42552 } 42553 function multisort(table, sortList, cache) { 42554 if (table.config.debug) { 42555 var sortTime = new Date(); 42556 } 42557 var dynamicExp = "var sortWrapper = function(a,b) {", 42558 l = sortList.length; 42559 for (var i = 0; i < l; i++) { 42560 var c = sortList[i][0]; 42561 var order = sortList[i][1]; 42562 var s = (table.config.parsers[c].type == "text") ? ((order == 0) ? makeSortFunction("text", "asc", c) : makeSortFunction("text", "desc", c)) : ((order == 0) ? makeSortFunction("numeric", "asc", c) : makeSortFunction("numeric", "desc", c)); 42563 var e = "e" + i; 42564 dynamicExp += "var " + e + " = " + s; 42565 dynamicExp += "if(" + e + ") { return " + e + "; } "; 42566 dynamicExp += "else { "; 42567 } 42568 var orgOrderCol = cache.normalized[0].length - 1; 42569 dynamicExp += "return a[" + orgOrderCol + "]-b[" + orgOrderCol + "];"; 42570 for (var i = 0; i < l; i++) { 42571 dynamicExp += "}; "; 42572 } 42573 dynamicExp += "return 0; "; 42574 dynamicExp += "}; "; 42575 if (table.config.debug) { 42576 benchmark("Evaling expression:" + dynamicExp, new Date()); 42577 } 42578 eval(dynamicExp); 42579 cache.normalized.sort(sortWrapper); 42580 if (table.config.debug) { 42581 benchmark("Sorting on " + sortList.toString() + " and dir " + order + " time:", sortTime); 42582 } 42583 return cache; 42584 }; 42585 function makeSortFunction(type, direction, index) { 42586 var a = "a[" + index + "]", 42587 b = "b[" + index + "]"; 42588 if (type == 'text' && direction == 'asc') { 42589 return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + a + " < " + b + ") ? -1 : 1 )));"; 42590 } else if (type == 'text' && direction == 'desc') { 42591 return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + b + " < " + a + ") ? -1 : 1 )));"; 42592 } else if (type == 'numeric' && direction == 'asc') { 42593 return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + a + " - " + b + "));"; 42594 } else if (type == 'numeric' && direction == 'desc') { 42595 return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + b + " - " + a + "));"; 42596 } 42597 }; 42598 function makeSortText(i) { 42599 return "((a[" + i + "] < b[" + i + "]) ? -1 : ((a[" + i + "] > b[" + i + "]) ? 1 : 0));"; 42600 }; 42601 function makeSortTextDesc(i) { 42602 return "((b[" + i + "] < a[" + i + "]) ? -1 : ((b[" + i + "] > a[" + i + "]) ? 1 : 0));"; 42603 }; 42604 function makeSortNumeric(i) { 42605 return "a[" + i + "]-b[" + i + "];"; 42606 }; 42607 function makeSortNumericDesc(i) { 42608 return "b[" + i + "]-a[" + i + "];"; 42609 }; 42610 function sortText(a, b) { 42611 if (table.config.sortLocaleCompare) return a.localeCompare(b); 42612 return ((a < b) ? -1 : ((a > b) ? 1 : 0)); 42613 }; 42614 function sortTextDesc(a, b) { 42615 if (table.config.sortLocaleCompare) return b.localeCompare(a); 42616 return ((b < a) ? -1 : ((b > a) ? 1 : 0)); 42617 }; 42618 function sortNumeric(a, b) { 42619 return a - b; 42620 }; 42621 function sortNumericDesc(a, b) { 42622 return b - a; 42623 }; 42624 function getCachedSortType(parsers, i) { 42625 return parsers[i].type; 42626 }; 42627 this.construct = function (settings) { 42628 return this.each(function () { 42629 if (!this.tHead || !this.tBodies) return; 42630 var $this, $document, $headers, cache, config, shiftDown = 0, 42631 sortOrder; 42632 this.config = {}; 42633 config = $.extend(this.config, $.tablesorter.defaults, settings); 42634 $this = $(this); 42635 $.data(this, "tablesorter", config); 42636 $headers = buildHeaders(this); 42637 this.config.parsers = buildParserCache(this, $headers); 42638 cache = buildCache(this); 42639 var sortCSS = [config.cssDesc, config.cssAsc]; 42640 fixColumnWidth(this); 42641 $headers.click( 42642 function (e) { 42643 var totalRows = ($this[0].tBodies[0] && $this[0].tBodies[0].rows.length) || 0; 42644 if (!this.sortDisabled && totalRows > 0) { 42645 $this.trigger("sortStart"); 42646 var $cell = $(this); 42647 var i = this.column; 42648 this.order = this.count++ % 2; 42649 if(this.lockedOrder) this.order = this.lockedOrder; 42650 if (!e[config.sortMultiSortKey]) { 42651 config.sortList = []; 42652 if (config.sortForce != null) { 42653 var a = config.sortForce; 42654 for (var j = 0; j < a.length; j++) { 42655 if (a[j][0] != i) { 42656 config.sortList.push(a[j]); 42657 } 42658 } 42659 } 42660 config.sortList.push([i, this.order]); 42661 } else { 42662 if (isValueInArray(i, config.sortList)) { 42663 for (var j = 0; j < config.sortList.length; j++) { 42664 var s = config.sortList[j], 42665 o = config.headerList[s[0]]; 42666 if (s[0] == i) { 42667 o.count = s[1]; 42668 o.count++; 42669 s[1] = o.count % 2; 42670 } 42671 } 42672 } else { 42673 config.sortList.push([i, this.order]); 42674 } 42675 }; 42676 setTimeout(function () { 42677 setHeadersCss($this[0], $headers, config.sortList, sortCSS); 42678 appendToTable( 42679 $this[0], multisort( 42680 $this[0], config.sortList, cache) 42681 ); 42682 }, 1); 42683 return false; 42684 } 42685 }).mousedown(function () { 42686 if (config.cancelSelection) { 42687 this.onselectstart = function () { 42688 return false 42689 }; 42690 return false; 42691 } 42692 }); 42693 $this.bind("update", function () { 42694 var me = this; 42695 setTimeout(function () { 42696 me.config.parsers = buildParserCache( 42697 me, $headers); 42698 cache = buildCache(me); 42699 }, 1); 42700 }).bind("updateCell", function (e, cell) { 42701 var config = this.config; 42702 var pos = [(cell.parentNode.rowIndex - 1), cell.cellIndex]; 42703 cache.normalized[pos[0]][pos[1]] = config.parsers[pos[1]].format( 42704 getElementText(config, cell), cell); 42705 }).bind("sorton", function (e, list) { 42706 $(this).trigger("sortStart"); 42707 config.sortList = list; 42708 var sortList = config.sortList; 42709 updateHeaderSortCount(this, sortList); 42710 setHeadersCss(this, $headers, sortList, sortCSS); 42711 appendToTable(this, multisort(this, sortList, cache)); 42712 }).bind("appendCache", function () { 42713 appendToTable(this, cache); 42714 }).bind("applyWidgetId", function (e, id) { 42715 getWidgetById(id).format(this); 42716 }).bind("applyWidgets", function () { 42717 applyWidget(this); 42718 }); 42719 if ($.metadata && ($(this).metadata() && $(this).metadata().sortlist)) { 42720 config.sortList = $(this).metadata().sortlist; 42721 } 42722 if (config.sortList.length > 0) { 42723 $this.trigger("sorton", [config.sortList]); 42724 } 42725 applyWidget(this); 42726 }); 42727 }; 42728 this.addParser = function (parser) { 42729 var l = parsers.length, 42730 a = true; 42731 for (var i = 0; i < l; i++) { 42732 if (parsers[i].id.toLowerCase() == parser.id.toLowerCase()) { 42733 a = false; 42734 } 42735 } 42736 if (a) { 42737 parsers.push(parser); 42738 }; 42739 }; 42740 this.addWidget = function (widget) { 42741 widgets.push(widget); 42742 }; 42743 this.formatFloat = function (s) { 42744 var i = parseFloat(s); 42745 return (isNaN(i)) ? 0 : i; 42746 }; 42747 this.formatInt = function (s) { 42748 var i = parseInt(s); 42749 return (isNaN(i)) ? 0 : i; 42750 }; 42751 this.isDigit = function (s, config) { 42752 return /^[-+]?\d*$/.test($.trim(s.replace(/[,.']/g, ''))); 42753 }; 42754 this.clearTableBody = function (table) { 42755 if ($.browser.msie) { 42756 function empty() { 42757 while (this.firstChild) 42758 this.removeChild(this.firstChild); 42759 } 42760 empty.apply(table.tBodies[0]); 42761 } else { 42762 table.tBodies[0].innerHTML = ""; 42763 } 42764 }; 42765 } 42766 }); 42767 $.fn.extend({ 42768 tablesorter: $.tablesorter.construct 42769 }); 42770 var ts = $.tablesorter; 42771 ts.addParser({ 42772 id: "text", 42773 is: function (s) { 42774 return true; 42775 }, format: function (s) { 42776 return $.trim(s.toLocaleLowerCase()); 42777 }, type: "text" 42778 }); 42779 ts.addParser({ 42780 id: "digit", 42781 is: function (s, table) { 42782 var c = table.config; 42783 return $.tablesorter.isDigit(s, c); 42784 }, format: function (s) { 42785 return $.tablesorter.formatFloat(s); 42786 }, type: "numeric" 42787 }); 42788 ts.addParser({ 42789 id: "currency", 42790 is: function (s) { 42791 return /^[£$â¬?.]/.test(s); 42792 }, format: function (s) { 42793 return $.tablesorter.formatFloat(s.replace(new RegExp(/[£$â¬]/g), "")); 42794 }, type: "numeric" 42795 }); 42796 ts.addParser({ 42797 id: "ipAddress", 42798 is: function (s) { 42799 return /^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s); 42800 }, format: function (s) { 42801 var a = s.split("."), 42802 r = "", 42803 l = a.length; 42804 for (var i = 0; i < l; i++) { 42805 var item = a[i]; 42806 if (item.length == 2) { 42807 r += "0" + item; 42808 } else { 42809 r += item; 42810 } 42811 } 42812 return $.tablesorter.formatFloat(r); 42813 }, type: "numeric" 42814 }); 42815 ts.addParser({ 42816 id: "url", 42817 is: function (s) { 42818 return /^(https?|ftp|file):\/\/$/.test(s); 42819 }, format: function (s) { 42820 return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//), '')); 42821 }, type: "text" 42822 }); 42823 ts.addParser({ 42824 id: "isoDate", 42825 is: function (s) { 42826 return /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s); 42827 }, format: function (s) { 42828 return $.tablesorter.formatFloat((s != "") ? new Date(s.replace( 42829 new RegExp(/-/g), "/")).getTime() : "0"); 42830 }, type: "numeric" 42831 }); 42832 ts.addParser({ 42833 id: "percent", 42834 is: function (s) { 42835 return /\%$/.test($.trim(s)); 42836 }, format: function (s) { 42837 return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g), "")); 42838 }, type: "numeric" 42839 }); 42840 ts.addParser({ 42841 id: "usLongDate", 42842 is: function (s) { 42843 return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/)); 42844 }, format: function (s) { 42845 return $.tablesorter.formatFloat(new Date(s).getTime()); 42846 }, type: "numeric" 42847 }); 42848 ts.addParser({ 42849 id: "shortDate", 42850 is: function (s) { 42851 return /\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s); 42852 }, format: function (s, table) { 42853 var c = table.config; 42854 s = s.replace(/\-/g, "/"); 42855 if (c.dateFormat == "us") { 42856 s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$1/$2"); 42857 } else if (c.dateFormat == "uk") { 42858 s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$2/$1"); 42859 } else if (c.dateFormat == "dd/mm/yy" || c.dateFormat == "dd-mm-yy") { 42860 s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/, "$1/$2/$3"); 42861 } 42862 return $.tablesorter.formatFloat(new Date(s).getTime()); 42863 }, type: "numeric" 42864 }); 42865 ts.addParser({ 42866 id: "time", 42867 is: function (s) { 42868 return /^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s); 42869 }, format: function (s) { 42870 return $.tablesorter.formatFloat(new Date("2000/01/01 " + s).getTime()); 42871 }, type: "numeric" 42872 }); 42873 ts.addParser({ 42874 id: "metadata", 42875 is: function (s) { 42876 return false;
42877 }, format: function (s, table, cell) { 42878 var c = table.config, 42879 p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName; 42880 return $(cell).metadata()[p]; 42881 }, type: "numeric" 42882 }); 42883 // add default widgets 42884 ts.addWidget({ 42885 id: "zebra", 42886 format: function (table) { 42887 if (table.config.debug) { 42888 var time = new Date(); 42889 } 42890 var $tr, row = -1, 42891 odd; 42892 // loop through the visible rows 42893 $("tr:visible", table.tBodies[0]).each(function (i) { 42894 $tr = $(this); 42895 // style children rows the same way the parent 42896 // row was styled 42897 if (!$tr.hasClass(table.config.cssChildRow)) row++; 42898 odd = (row % 2 == 0); 42899 $tr.removeClass( 42900 table.config.widgetZebra.css[odd ? 0 : 1]).addClass( 42901 table.config.widgetZebra.css[odd ? 1 : 0]) 42902 }); 42903 if (table.config.debug) { 42904 $.tablesorter.benchmark("Applying Zebra widget", time); 42905 } 42906 } 42907 }); 42908})(jQuery); 42909 42910 /* Ende jquery.tablesorter */ 42911 /* Start tables */ 42912 /* 42913* @author jkuschel 42914* @author dsorge 42915*/ 42916(function($){ 42917 jQuery.fn.extend({ 42918 deleteCols: function(){ 42919 var table = $(this); 42920 $origTable = $('.baua-table, .bauatable').clone(); 42921 var headers = table.find('th'); 42922 var clickCount = 0; 42923 return headers.each(function(){ 42924 $(this).append('<a class="col" href="#"><img src="' + image_url_hide_td + '"' + 42925 ' alt="' + HIDE_TD + '"></a>'); 42926 $(this).find('.col').click(function(){ 42927 headers = table.find('th'); 42928 var col = headers.index($(this).parent()); 42929 table.find('tr').each(function(){ 42930 var colToDelete = $(this).find('td:eq('+col+')'); 42931 colToDelete.hide(); 42932 }); 42933 $(this).parent().hide(); 42934 clickCount++; 42935 if($('.responsiveTable').find('.reset').length == 0){ 42936 $('.baua-table, .bauatable').before('<p><a class="reset" href="#">vollständige Tabelle laden</a></p>'); 42937 } 42938 var lnkReset = $('.responsiveTable').find('.reset'); 42939 lnkReset.click(function(){ 42940 $('.baua-table, .bauatable').remove(); 42941 $('.responsiveTable').append($origTable); 42942 $('.reset').remove(); 42943 $('.baua-table, .bauatable').deleteCols(); 42944 return false; 42945 }); 42946 return false; 42947 }); 42948 }); 42949 } 42950 }); 42951 jQuery(document).ready(function(){ 42952 $('.baua-table, .bauatable').deleteCols(); 42953 }) 42954})(jQuery); 42955 42956 /* Ende tables */ 42957 /* Start gsb_infinitescrolling */ 42958 /** 42959 * GSB-Plugin infinitescrolling 42960 * 42961 * Author: pespeloe 42962 */ 42963;(function ($) { 42964 if (!$.gsb) { 42965 $.gsb = {}; 42966 } 42967 $.gsb.infinitescrolling = function (el, instanceId, options) { 42968 // To avoid scope issues, use 'base' instead of 'this' 42969 // to reference this class from internal events and functions. 42970 var base = this; 42971 // Access to $ and DOM versions of element 42972 base.$el = $(el); 42973 base.el = el; 42974 // Add a reverse reference to the DOM object 42975 base.$el.data("gsb.infinitescrolling", base); 42976 base.init = function () { 42977 base.options = $.extend({}, $.gsb.infinitescrolling.defaultOptions, options); 42978 42979 if (typeof base.options.paginationElements == 'function') { 42980 base.pagination = base.options.paginationElements.call(this, base); 42981 } else { 42982 base.pagination = base.$el.find(base.options.paginationElements); 42983 } 42984 42985 $.get(base.$el.data('href'), function (data) { 42986 base.nextLink = base.getLink(data); 42987 }); 42988 42989 if (base.pagination.length != 0) { 42990 base.addMoreButton(); 42991 base.pagination.closest(base.options.paginationBoxClass).hide(); 42992 } 42993 }; 42994 42995 $.gsb.infinitescrolling.prototype.addMoreButton = function () { 42996 base.moreButton = $('<button class="loadmore"/>'); 42997 base.moreButton.append(base.options.buttonText); 42998 base.moreButton.insertAfter(base.$el).on('click', function (e) { 42999 e.preventDefault(); 43000 e.stopPropagation(); 43001 43002 $.get(base.nextLink, function (data) { 43003 base.$el.append($(data).find(base.options.resultClass)); 43004 base.nextLink = base.getLink(data); 43005 if ($(data).find(base.options.forwardButton).length == 0) { 43006 base.moreButton.remove(); 43007 } 43008 }); 43009 }); 43010 }; 43011 43012 $.gsb.infinitescrolling.prototype.getLink = function (data) { 43013 return $(data).find(base.options.forwardButton).attr('href'); 43014 }; 43015 43016 // Run initializer 43017 base.init(); 43018 }; 43019 43020 $.gsb.infinitescrolling.defaultOptions = { 43021 paginationElements: 'a.forward', 43022 forwardButton: 'a.forward', 43023 paginationBoxClass: '.navIndex', 43024 resultClass: '.section-results .row', 43025 buttonText: typeof SHOW_MORE == 'undefined' ? 'mehr anzeigen' : SHOW_MORE 43026 }; 43027 43028 $.fn.gsb_infinitescrolling = function (options) { 43029 return this.each(function (index, value) { 43030 new $.gsb.infinitescrolling($(value), options); 43031 }); 43032 }; 43033})(jQuery); 43034 /* Ende gsb_infinitescrolling */ 43035 /* Start gsb_baua_toggle_text */ 43036 (function ($) { 43037 if (!$.gsb) { 43038 $.gsb = { baua: {} }; 43039 } else if (!$.gsb.baua) { 43040 $.gsb.baua = {}; 43041 }; 43042 $.gsb.baua.toggleText = function (el, userOptions) { 43043 var base = this; 43044 base.$el = $(el); 43045 base.options = $.extend({}, $.gsb.baua.toggleText.defaultOptions, userOptions); 43046 base.$el.data("gsb.baua.toggleText", base); 43047 base.$el.gsb_responsiveListener(base); 43048 };
43049 $.gsb.baua.toggleText.prototype.init = function init() { 43050 var base = this; 43051 base.$el.addClass('defaultHidden-element hidden'); 43052 base.$el.find('button,a,input').attr('tabindex', -1); 43053 base.$el.append('<div class="overlay"></div>'); 43054 base.fullTextButton = $("<button class='defaultHidden-opener'>" + base.options.fullTextButtonText + "</button>").insertAfter(base.$el).addClass('shown').on('click', function () { 43055 base.$el.removeClass('hidden'); 43056 if (base.$el.find('button,a,input').length > 0) { 43057 base.$el.find('button,a,input').attr('tabindex', 0); 43058 base.$el.find('button,a,input')[0].focus(); 43059 } 43060 $(this).removeClass('shown'); 43061 base.shortTextButton.addClass('shown'); 43062 }); 43063 base.shortTextButton = $("<button class='defaultHidden-closer'>" + base.options.shortTextButtonText + "</button>").insertAfter(base.$el).on('click', function () { 43064 base.$el.addClass('hidden'); 43065 base.$el.find('button,a,input').attr('tabindex', -1); 43066 $(this).removeClass('shown'); 43067 base.fullTextButton.addClass('shown').focus(); 43068 }); 43069 }; 43070 $.gsb.baua.toggleText.prototype.remove = function remove() { 43071 var base = this; 43072 if (base.fullTextButton && base.shortTextButton) { 43073 base.shortTextButton.remove(); 43074 base.fullTextButton.remove(); 43075 base.$el.find('button,a,input').removeAttr('tabindex'); 43076 base.$el.removeClass('defaultHidden-element hidden shown'); 43077 } 43078 }; 43079 $.gsb.baua.toggleText.defaultOptions = { 43080 fullTextButtonText: typeof SHOW_MORE_ARTICLE == 'undefined' ? 'Weiterlesen' : SHOW_MORE_ARTICLE, 43081 shortTextButtonText: typeof SHOW_LESS_ARTICLE == 'undefined' ? 'SchlieÃen' : SHOW_LESS_ARTICLE, 43082 respondToEvents: true, 43083 onRefresh: function onRefresh() { 43084 this.init(); 43085 } 43086 }; 43087 $.fn.gsb_baua_toggleText = function (options) { 43088 return this.each(function () { 43089 if (!$(this).data('gsb.baua.toggleText')) { 43090 new $.gsb.baua.toggleText(this, options); 43091 } 43092 }); 43093 return this; 43094 }; 43095})(jQuery); 43096 /* Ende gsb_baua_toggle_text */ 43097 /* Start gsb_baua_toggleFacet */ 43098 /** 43099 * @name toggleFacet 43100 * @version 0.0.5 43101 * @see {@link http://semver.org|Semantic Versioning} 43102 * @author pespeloe 43103 * 43104 * @desc Modulbeschreibung 43105 * 43106 * @requires {@link external:jQuery} 43107 * 43108 * @example 43109 * $('#supplement').find('.respTargetsWrapper .links').gsb_toggleFacet(); 43110 * */ 43111; 43112(function ($) { 43113 if (!$.gsb) { 43114 $.gsb = {}; 43115 } 43116 ; 43117 43118 $.gsb.baua_toggleFacet = function (el, options) { 43119 // To avoid scope issues, use 'base' instead of 'this' 43120 // to reference this class from internal events and functions. 43121 var base = this; 43122 43123 // Access to jQuery and DOM versions of element 43124 base.$el = $(el); 43125 base.el = el; 43126 43127 // Add a reverse reference to the DOM object 43128 base.$el.data("gsb.toggleFacet", base); 43129 43130 base.init = function () { 43131 base.options = $.extend({}, $.gsb.baua_toggleFacet.defaultOptions, options); 43132 base.wrapLists(); 43133 43134 if (base.$el.find('li > strong').length > 0) { 43135 base.toggleList.find('button').click(); 43136 } 43137 }; 43138 43139 /** 43140 * @method wrapLists 43141 * @desc wraped die Elemente die über initialShow hinausgehen in einem li, welches an das Ende von base.$el gehängt wird 43142 */ 43143 $.gsb.baua_toggleFacet.prototype.wrapLists = function () { 43144 if (base.$el.find('li').length > base.options.initialShow) { 43145 base.$el.append('<li class="toggle"/>'); 43146 base.toggleList = base.$el.find('.toggle'); 43147 base.toggleList.prepend("<ul/>"); 43148 43149 $.each(base.$el.find('li'), function (index) { 43150 if (index + 1 > base.options.initialShow && !$(this).hasClass('toggle')) { 43151 base.toggleList.find('ul').append($(this)); 43152 } 43153 }); 43154 43155 base.toggleList.append('<button class="hideContent">' + base.options.buttonTextClosed + '</button>'); 43156 base.toggleList.find('ul').hide(); 43157 43158 base.addClick(); 43159 } 43160 }; 43161 43162 /** 43163 * @method addClick 43164 * @desc fügt die Click-Funktion hinzu und blendet Container ein oder aus 43165 */ 43166 $.gsb.baua_toggleFacet.prototype.addClick = function () { 43167 43168 base.$el.on("click", ".toggle > button", function () { 43169 var button = $(this); 43170 if (button.hasClass('hideContent')) { 43171 base.toggleList.find('> ul').slideDown(); 43172 button.text(base.options.buttonTextOpened); 43173 button.removeClass('hideContent').addClass('showContent'); 43174 button.closest('ul').find('> li:first-child a').focus(); 43175 } else { 43176 base.toggleList.find('> ul').slideUp(); 43177 button.text(base.options.buttonTextClosed); 43178 button.removeClass('showContent').addClass('hideContent'); 43179 } 43180 }); 43181 }; 43182 43183 // Run initializer 43184 base.init(); 43185 }; 43186 43187 /** 43188 * @typedef defaultOptions 43189 * @type {object} 43190 * @property {object} options - Default Options des Scripts 43191 * @property {int} [options.initialShow] - Angabe wie viele Elemente angezeigt werden sollen 43192 * @property {String} [options.buttonTextOpened] - Text für geöffnetes Accordion 43193 * @property {String} [options.buttonTextClosed] - Text für geschlossenes Accordion 43194 * 43195 */ 43196 43197 $.gsb.baua_toggleFacet.defaultOptions = { 43198 initialShow: 3, 43199 buttonTextOpened: typeof SHOW_LESS == 'undefined' ? 'Ausblenden' : SHOW_LESS, 43200 buttonTextClosed: typeof SHOW_MORE == 'undefined' ? 'Einblenden' : SHOW_MORE 43201 }; 43202 43203 $.fn.gsb_baua_toggleFacet = function (options) { 43204 return this.each(function () { 43205 new $.gsb.baua_toggleFacet(this, options); 43206 }); 43207 }; 43208})(jQuery); 43209 /* Ende gsb_baua_toggleFacet */ 43210 /* Start gsb_multimedia */ 43211 var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; 43212 43213/* --GSBDocStart 43214 * @name: @gsb/gsb_multimedia 43215 * @version: 6.3.5 43216 * @repository: 43217 * @description: [//]: # (Diesen und folgende Kommentare auf keinen Fall löschen!) [//]: # (Nur so akzeptiert license-checker die Lizenz) [//]: # (SEE LICENSE IN LICENSE-INTERNAL.txt) [//]: # (https://license-internal.txt) 43218 * --GSBDocEnd 43219*/ 43220gsb.makeGSBModule('gsb.Multimedia', { 43221 /** 43222 * Führt die Initialisierung des GSB-Wrapper-Plugins durch. 43223 */
43224 init: function init() { 43225 var base = this; 43226 base.$elWrapper = base.$el.closest(base.options.selectors.wrapper); 43227 base.initializeMediaElement(); 43228 }, 43229 43230 /** 43231 * Führt die Initialisierung des Mediaelement.js Plugins durch. 43232 */ 43233 initializeMediaElement: function initializeMediaElement() { 43234 var base = this; 43235 var mediaelementplayerOptions = $.extend({}, base.options.mediaelementplayerOptions, base.options.settings.mediaelementplayerOptions, base.mediaelementplayerOptionsFromDataAttribute()); 43236 var $consentWrapper = void 0, 43237 $consentButton = void 0; 43238 if (mediaelementplayerOptions.hasOwnProperty('videoWidth') && !base.options.dontSetWidthAttribute) { 43239 base.$el.attr('width', mediaelementplayerOptions.videoWidth); 43240 } 43241 if (mediaelementplayerOptions.hasOwnProperty('videoHeight') && !base.options.dontSetHeightAttribute) { 43242 base.$el.attr('height', mediaelementplayerOptions.videoHeight); 43243 } 43244 base.centerVideoIfRequired(); 43245 base.setLocale(); 43246 base.$elWrapper.addClass('gsb-multimedia'); 43247 base.isExternalApi = Boolean(base.$elWrapper.find(base.options.selectors.isExternalApi).length); 43248 if (base.options.externalApiRequiresConsent && base.isExternalApi && !base.consented) { 43249 var height = base.$el.height(); 43250 var width = base.$el.width(); 43251 if (height <= 0) { 43252 // Fallback, falls die Höhe des Elements nicht abgelesen werden kann. 43253 var originalHeight = Math.floor(Number(base.$el.attr('height'))); 43254 var originalWidth = Math.floor(Number(base.$el.attr('width'))); 43255 if (width > 0) { 43256 height = Math.floor(width * (originalHeight / originalWidth)); 43257 base.$elWrapper.css({ 43258 minHeight: height 43259 }); 43260 } else { 43261 height = originalHeight; 43262 width = originalWidth; 43263 base.$elWrapper.css({ 43264 minHeight: height, 43265 minWidth: width 43266 }); 43267 } 43268 } 43269 base.$elWrapper.css({ 43270 height: height, 43271 width: width, 43272 backgroundImage: 'url(' + base.$el.attr('poster') + ')', 43273 backgroundSize: 'contain' 43274 }).addClass('consent-required'); 43275 base.$el.attr('tabindex', -1).hide(); 43276 $consentWrapper = $(base.options.markup.consentWrapper); 43277 $consentButton = $(base.options.markup.consentButton).text(base.options.consentButtonText).on('click', base, base.onClickConsentButton); 43278 $consentWrapper.find(base.options.selectors.consentContent).attr('aria-label', base.options.consentLabel).attr('role', 'group').attr('aria-roledescription', base.options.consentDescription).html(base.options.markup.consentContent)[base.options.consentButtonInsertion]($consentButton); 43279 base.$elWrapper.prepend($consentWrapper); 43280 base.$consentWrapper = $consentWrapper; 43281 43282 if (base.options.consentSetMinHeight) { 43283 $consentWrapper.css({ 43284 minHeight: height 43285 }); 43286 } 43287 43288 return; 43289 } 43290 43291 base.$el.on('success.' + base.eventName, base, base.onMepSuccess); 43292 base.$el.mediaelementplayer($.extend({}, { 43293 success: function success(fakeNode, baseEl, mepInstance) { 43294 var base = $(baseEl).data('gsb.Multimedia'); 43295 base.mep = mepInstance; 43296 base.$el.trigger('success.Multimedia.gsb', base); 43297 base.bitvTweaks(); 43298 base.$elWrapper.find(base.options.selectors.volumeSlider).hide(); 43299 base.$elWrapper.find(base.options.selectors.captionsSelect).find('label').on('click', base, base.onClickCaptionsLabel); 43300 base.$elWrapper.find(base.options.selectors.timeRail).on('dragstart touchstart mousedown', function (ev) { 43301 return ev.stopPropagation(); 43302 }); 43303 base.$el.trigger('init.Multimedia.gsb'); 43304 } 43305 }, mediaelementplayerOptions)); 43306 }, 43307 43308 // triggers hlserror.Multimedia.gsb for gsb_streamPolling_muxCom (currently only used in Saarland) 43309 onMepSuccess: function onMepSuccess(ev, base) { 43310 // make sure exposing base to success-Event-Handlers as 2. arg works 43311 var fakeNode = base.mep.media; 43312 if (fakeNode && fakeNode.hlsPlayer) { 43313 fakeNode.hlsPlayer.on(Hls.Events.ERROR, function (hlsEvType, hlsEvData) { 43314 console.warn(base.moduleName + ': HLS-Error-Callback called. Triggering event now.', Array.from(arguments)); 43315 $(fakeNode).trigger('hlserror.Multimedia.gsb', { 43316 base: base, 43317 hlsEvData: hlsEvData, 43318 hlsEvType: hlsEvType 43319 }); 43320 }); 43321 } 43322 }, 43323 43324 onClickCaptionsLabel: function onClickCaptionsLabel(ev) { 43325 var base = ev.data; 43326 //this function prevents <label> Elements from blurring their <input>s 43327 ev.preventDefault(); 43328 $(this.control).trigger('click'); 43329 }, 43330 43331 onClickConsentButton: function onClickConsentButton(ev) { 43332 var base = ev.data; 43333 base.consented = true; 43334 base.$consentWrapper.remove(); 43335 base.$elWrapper.css({ 43336 backgroundImage: '', 43337 height: '', 43338 width: '', 43339 backgroundSize: '' 43340 }).removeClass('consent-required'); 43341 if (base.$el.attr('data-consent-autoplay') !== 'false') { 43342 base.$el.attr('autoplay', 'autoplay'); 43343 } 43344 base.$el.show(); 43345 base.initializeMediaElement(); 43346 }, 43347 43348 bitvTweaks: function bitvTweaks(ev) { 43349 var base = ev ? ev.data : this; 43350 var unique = Math.random().toString(36).substr(2, 9); 43351 var $container = base.$elWrapper.find('.mejs__container'); 43352
43353 /* required for HTML validation of stringified DOM 43354 * see: https://testen.bitv-test.de/index.php?a=di&iid=99 43355 * yes, this is dumb 43356 */ 43357 base.$el.filter('audio, video').find('source').remove(); 43358 43359 base.$elWrapper.find('.mejs__volume-slider').removeAttr('href') // role=slider MUST NOT have href attribute 43360 .find('#mejs__volume-slider').attr('id', 'volume-slider-' + unique); // fix duplicate Ids 43361 base.$elWrapper.find('.mejs__volume-button button').attr('aria-describedby', 'volume-slider-' + unique); 43362 $container.attr('aria-roledescription', $container.attr('aria-label')).removeAttr('aria-label').attr('aria-labelledby', base.$el.attr('aria-labelledby')).removeAttr('tabindex').prev('.mejs__offscreen').remove(); // remove superseded aural-only label 43363 43364 base.$el.on('progress timeupdate', base, base.removeTabindex); 43365 43366 // pressable buttons: set aria-pressed 43367 base.$elWrapper.find(base.options.selectors.pressableButton).on('click updatePressedStatus.' + base.eventName, base, base.updateAriaPressed).trigger('updatePressedStatus.' + base.eventName); 43368 // exit fullscreen by pressing esc: set aria-pressed 43369 base.$elWrapper.find('.mejs__container').on('exitedfullscreen', base, base.onExitFullscreen).on('enteredfullscreen', base, base.onEnterFullscreen); 43370 43371 if (base.isExternalApi) { 43372 base.$el.attr('tabindex', '-1'); 43373 setTimeout(function () { 43374 base.$elWrapper.find('iframe').attr('tabindex', '-1'); 43375 }, 300); 43376 } 43377 }, 43378 43379 removeTabindex: function removeTabindex(ev) { 43380 var base = ev.data; 43381 if (base.options.removeTabIndexOnHidden) { 43382 if (!base.$el.is(':visible')) { 43383 base.$elWrapper.find('[tabindex]').attr('tabindex', -1); 43384 } 43385 } 43386 }, 43387 43388 updateAriaPressed: function updateAriaPressed(ev) { 43389 var base = ev.data, 43390 $parent = $(ev.currentTarget), 43391 $button = $parent.children('button'), 43392 isPressed = base.options.selectors.isPressed; 43393 if ($parent.is(isPressed)) { 43394 $button.attr('aria-pressed', 'true'); 43395 } else { 43396 $button.attr('aria-pressed', 'false'); 43397 } 43398 }, 43399 43400 onExitFullscreen: function onExitFullscreen(ev) { 43401 var base = ev.data; 43402 setTimeout(function () { 43403 base.$elWrapper.find('.mejs__fullscreen-button').trigger('updatePressedStatus'); 43404 }); 43405 base.$elWrapper.off('keydown.' + base.eventName); 43406 }, 43407 43408 onEnterFullscreen: function onEnterFullscreen(ev) { 43409 var base = ev.data; 43410 43411 base.$elWrapper.on("keydown." + base.eventName, base, base.focusControlOnKeyDown); 43412 }, 43413 43414 focusControlOnKeyDown: function focusControlOnKeyDown(ev) { 43415 var base = ev.data, 43416 playBtn = base.$elWrapper.find('.mejs__overlay-button'), 43417 controls = base.$elWrapper.find('.mejs__controls').find('a, button').add(playBtn); 43418 43419 if (ev.target === controls.last()[0] && ev.keyCode === 9 && !ev.shiftKey) { 43420 ev.preventDefault(); 43421 controls.first().focus(); 43422 } else if (ev.target === controls.first()[0]) { 43423 ev.preventDefault(); 43424 controls.last().focus(); 43425 } 43426 }, 43427 43428 /** 43429 * @method centerVideoIfRequired 43430 * @desc Zentriert das zugrunde liegende Multimedia-Element. 43431 */ 43432 centerVideoIfRequired: function centerVideoIfRequired() { 43433 var base = this; 43434 var mediaelementplayerOptions = base.options.mediaelementplayerOptions; 43435 var videoWidth = mediaelementplayerOptions && mediaelementplayerOptions.videoWidth || base.$el.attr('width'); 43436 if (base.options.center && videoWidth) { 43437 var centerContainer = void 0; 43438 var parent = base.$el.parent(); 43439 if (!parent.is(base.options.selectors.center)) { 43440 centerContainer = $(base.options.markup.center); 43441 centerContainer.css({ width: videoWidth, margin: '0 auto' }); 43442 base.$el.wrap(centerContainer); 43443 } else { 43444 centerContainer = parent; 43445 centerContainer.css({ width: videoWidth }); 43446 } 43447 } 43448 }, 43449 43450 /** 43451 * @method setLocale 43452 * @desc Setzt das Locale 43453 */ 43454 setLocale: function setLocale() { 43455 var lang = $('html').attr('lang'); 43456 if ((typeof mejs === 'undefined' ? 'undefined' : _typeof(mejs)) === 'object') { 43457 mejs.i18n.language(lang); 43458 } 43459 }, 43460 43461 /** 43462 * Parst zusätzliche Optionen für das Mediaelement.js Plugin aus dem options data-Attribut. 43463 * Die Logik dieser Funktion ist von Foundation übernommen. 43464 */ 43465 mediaelementplayerOptionsFromDataAttribute: function mediaelementplayerOptionsFromDataAttribute() { 43466 var base = this, 43467 optionsFromDataAttributeAsString = base.$el.data('options'); 43468 var opts = {}, 43469 ii = void 0, 43470 p = void 0, 43471 opts_arr = (optionsFromDataAttributeAsString || ':').split(';'); 43472 ii = opts_arr.length; 43473 43474 function isNumber(o) { 43475 return !isNaN(o - 0) && o !== null && o !== '' && o !== false && o !== true; 43476 } 43477 43478 function trim(str) { 43479 if (typeof str === 'string') { 43480 return $.trim(str); 43481 } 43482 return str; 43483 } 43484 43485 while (ii--) { 43486 p = opts_arr[ii].split(':'); 43487 p = [p[0], p.slice(1).join(':')]; 43488 43489 if (/true/i.test(p[1])) { 43490 p[1] = true; 43491 } 43492 if (/false/i.test(p[1])) { 43493 p[1] = false;
43494 } 43495 if (isNumber(p[1])) { 43496 if (p[1].indexOf('.') === -1) { 43497 p[1] = parseInt(p[1], 10); 43498 } else { 43499 p[1] = parseFloat(p[1]); 43500 } 43501 } 43502 43503 if (p.length === 2 && p[0].length > 0) { 43504 opts[trim(p[0])] = trim(p[1]); 43505 } 43506 } 43507 return opts; 43508 }, 43509 43510 defaultOptions: { 43511 center: false, 43512 /** 43513 * Die Standard-Optionen fuer das aufgerufene Mediaelement.js Plugin 43514 */ 43515 mediaelementplayerOptions: { 43516 flashName: '/static/mediaElementPlayer/flashmediaelement.swf', 43517 showPosterWhenEnded: true, 43518 features: ['playpause', 'current', 'progress', 'duration', 'tracks', 'a11y', 'volume', 'fullscreen'], 43519 /* Bindestrich notwendig für Custom Elements 43520 siehe https://stackoverflow.com/questions/9845011/are-custom-elements-valid-html5#answer-9845124 */ 43521 fakeNodeName: 'mediaelement-wrapper', 43522 iconSprite: typeof image_url_mejs_controls !== 'undefined' ? image_url_mejs_controls : undefined, 43523 classPrefix: 'mejs__' 43524 }, 43525 settings: {}, 43526 selectors: { 43527 captionsSelect: '.mejs__captions-selector', 43528 center: '.mejs__centered', 43529 consentContent: '.consent-container', 43530 isExternalApi: 'source[type="video/vimeo"], source[type="video/youtube"]', 43531 isPressed: '.audio-description-on, .video-description-on, .mejs__unfullscreen', 43532 pressableButton: '.mejs__audio-description-button, .mejs__video-description-button, .mejs__fullscreen-button', 43533 timeRail: '.mejs__time-rail', 43534 volumeSlider: '.mejs__volume-slider', 43535 wrapper: '.mejs__wrapper' 43536 }, 43537 markup: { 43538 center: '<div class=\'mejs__centered\' />', 43539 consentWrapper: '<div class="consent-wrapper"><div class="consent-container" /></div>', 43540 consentContent: '<p>' + (typeof CONSENT_TEXT !== 'undefined' ? CONSENT_TEXT : 'FALLBACK') + '</p>', 43541 consentButton: '<button type="button" class="c-button c-button--xs" />' 43542 }, 43543 externalApiRequiresConsent: true, 43544 consentLabel: typeof CONSENT_LABEL !== 'undefined' ? CONSENT_LABEL : 'FALLBACK', 43545 consentDescription: typeof CONSENT_DESCRIPTION !== 'undefined' ? CONSENT_DESCRIPTION : 'FALLBACK', 43546 consentButtonText: typeof CONSENT_BUTTON !== 'undefined' ? CONSENT_BUTTON : 'Ich akzeptiere', 43547 consentButtonInsertion: 'append', 43548 dontSetWidthAttribute: false, 43549 dontSetHeightAttribute: false, 43550 consentSetMinHeight: false, 43551 removeTabIndexOnHidden: true 43552 } 43553}); 43554 /* Ende gsb_multimedia */ 43555 /* Start init */ 43556 $(document).ready(function () { 43557 'use strict'; 43558 43559 var $body = $('body'); 43560 43561 // set js class 43562 $body.addClass('js-on').removeClass('js-off'); 43563 // carousel slider 43564 43565 var content = $('#content'); 43566 43567 // small: 1; medium: 2 vertikal; xlarge: 2 horizontal 43568 var $js_slider_1 = content.find('.js-slider-1-2v-2h .karussell'); 43569 $js_slider_1.each(function () { 43570 $(this).gsb_Slideshow({ 43571 containerElement: '.slide', 43572 autoplay: false, 43573 pagination: true, 43574 slickOptions: { 43575 onSlickBeforeInit: function onSlickBeforeInit(baseEl) { 43576 baseEl.$el.gsb_slideshow_rowAddon({ 43577 slidesPerRow: 1, 43578 responsive: [{ 43579 breakpoint: 1024, 43580 slidesPerRow: 2, 43581 onRefresh: function onRefresh() { 43582 this.setRows(); 43583 } 43584 }, { 43585 breakpoint: 640, 43586 slidesPerRow: 1, 43587 onRefresh: function onRefresh() { 43588 this.setRows(); 43589 } 43590 }] 43591 }, baseEl); 43592 }, 43593 slidesToShow: 2, 43594 slidesToScroll: 2, 43595 fade: false, 43596 responsive: [{ 43597 breakpoint: 1024, 43598 settings: { 43599 vertical: false, 43600 slidesToShow: 1, 43601 slidesToScroll: 1 43602 } 43603 }] 43604 } 43605 }); 43606 }); 43607 43608 // small: 1; medium: 2 vertikal; xlarge: 2 vertikal 43609 var $js_slider_2 = content.find('.js-slider-1-2v-2v .karussell'); 43610 $js_slider_2.each(function () { 43611 $(this).gsb_Slideshow({ 43612 containerElement: '.slide', 43613 autoplay: false, 43614 pagination: true, 43615 slickOptions: { 43616 onSlickBeforeInit: function onSlickBeforeInit(baseEl) { 43617 baseEl.$el.gsb_slideshow_rowAddon({ 43618 slidesPerRow: 2, 43619 responsive: [{ 43620 breakpoint: 640, 43621 slidesPerRow: 1, 43622 onRefresh: function onRefresh() { 43623 this.setRows(); 43624 } 43625 }] 43626 }, baseEl); 43627 }, 43628 slidesToShow: 1, 43629 slidesToScroll: 1, 43630 fade: false 43631 } 43632 }); 43633 }); 43634 43635 // small: 1; medium: 4 vertikal; xlarge: 2x2 43636 var $js_slider_3 = content.find('.js-slider-1-4v-2x2 .karussell'); 43637 $js_slider_3.each(function () { 43638 $(this).gsb_Slideshow({ 43639 containerElement: '.slide', 43640 autoplay: false, 43641 pagination: true, 43642 slickOptions: { 43643 onSlickBeforeInit: function onSlickBeforeInit(baseEl) { 43644 baseEl.$el.gsb_slideshow_rowAddon({ 43645 slidesPerRow: 2, 43646 responsive: [{ 43647 breakpoint: 1024, 43648 slidesPerRow: 4, 43649 onRefresh: function onRefresh() { 43650 this.setRows(); 43651 } 43652 }, { 43653 breakpoint: 640, 43654 slidesPerRow: 1, 43655 onRefresh: function onRefresh() { 43656 this.setRows(); 43657 } 43658 }] 43659 }, baseEl); 43660 }, 43661 slidesToShow: 2, 43662 slidesToScroll: 2, 43663 fade: false, 43664 responsive: [{ 43665 breakpoint: 1024, 43666 settings: { 43667 vertical: false, 43668 slidesToShow: 1, 43669 slidesToScroll: 1 43670 } 43671 }] 43672 } 43673 }); 43674 }); 43675 43676 // small: 1; medium: 2x2; xlarge: 2x2 43677 var $js_slider_4 = content.find('.js-slider-1-2x2-2x2 .karussell'); 43678 $js_slider_4.each(function () { 43679 $(this).gsb_Slideshow({ 43680 containerElement: '.slide', 43681 autoplay: false, 43682 pagination: true, 43683 slickOptions: { 43684 onSlickBeforeInit: function onSlickBeforeInit(baseEl) { 43685 baseEl.$el.gsb_slideshow_rowAddon({ 43686 slidesPerRow: 2, 43687 responsive: [{ 43688 breakpoint: 640, 43689 slidesPerRow: 1, 43690 onRefresh: function onRefresh() { 43691 this.setRows(); 43692 } 43693 }] 43694 }, baseEl); 43695 }, 43696 slidesToShow: 2, 43697 slidesToScroll: 2, 43698 fade: false, 43699 responsive: [{ 43700 breakpoint: 640, 43701 settings: { 43702 vertical: false, 43703 slidesToShow: 1, 43704 slidesToScroll: 1 43705 } 43706 }] 43707 } 43708 }); 43709 }); 43710 43711 // small: 1; medium: 3 vertikal; xlarge: 3 vertikal 43712 var $js_slider_5 = content.find('.js-slider-1-3v-3v .karussell'); 43713 $js_slider_5.each(function () { 43714 $(this).gsb_Slideshow({ 43715 containerElement: '.slide', 43716 autoplay: false, 43717 pagination: true, 43718 slickOptions: { 43719 onSlickBeforeInit: function onSlickBeforeInit(baseEl) { 43720 baseEl.$el.gsb_slideshow_rowAddon({ 43721 slidesPerRow: 3, 43722 responsive: [{ 43723 breakpoint: 640, 43724 slidesPerRow: 1, 43725 onRefresh: function onRefresh() { 43726 this.setRows(); 43727 } 43728 }] 43729 }, baseEl); 43730 }, 43731 slidesToShow: 1, 43732 slidesToScroll: 1, 43733 fade: false 43734 } 43735 }); 43736 }); 43737 43738 // Slider horizontal 43739 var $js_slider_6 = content.find('.js-slider .karussell'); 43740 if ($js_slider_6.length > 0) { 43741 $js_slider_6.gsb_Slideshow({ 43742 containerElement: '.slide', 43743 autoplay: false, 43744 pagination: true, 43745 slickOptions: { 43746 slidesToShow: $js_slider_6.data('horizontalelements'), 43747 slidesToScroll: 1, 43748 fade: false, 43749 responsive: [{ 43750 breakpoint: 640, 43751 settings: { 43752 slidesToShow: 1, 43753 slidesToScroll: 1 43754 } 43755 }] 43756 } 43757 }); 43758 } 43759 43760 // gallery slider
43761 var $galleryBox = $('.galleryBox'); 43762 $galleryBox.gsb_Slideshow({ 43763 slideshowControls: true, 43764 generateButtonContainer: false, 43765 autoplay: false, 43766 pagination: true, 43767 nextButtonImage: image_url_next, 43768 prevButtonImage: image_url_back, 43769 prevButtonInactiveImage: image_url_back_g, 43770 nextButtonInactiveImage: image_url_next_g, 43771 slickOptions: { 43772 adaptiveHeight: true, 43773 fade: false 43774 } 43775 }); 43776 $galleryBox.gsb_lightbox({ 43777 lightboxType: 'multiple', 43778 element: '.slide', 43779 imagePrev: image_url_back, 43780 imageNext: image_url_next, 43781 imagePrevInactive: image_url_back_g, 43782 imageNextInactive: image_url_next_g 43783 }); 43784 // banner 43785 $.each($('#cookiebanner'), function () { 43786 var $el = $(this); 43787 $el.gsb_banner({ 43788 animation: $el.data('animation'), 43789 cookieLifeTimeInDaysClosed: 30, 43790 cookieName: $el.data('cookie'), 43791 bodyHiddenClass: '', 43792 bodyVisibleClass: '', 43793 positionRelativeClass: 'c-banner__relative', 43794 positionRelativePlaceholderClass: 'c-banner__placeholder', 43795 position: $el.data('position'), 43796 positionRelative: true, 43797 matomoTrackingCookieLifeTimeInDays: 30, 43798 scriptUrl: '//www.reach-clp-biozid-helpdesk.de/piwik/matomo.js', 43799 trackerUrl: '//www.reach-clp-biozid-helpdesk.de/piwik/matomo.php', 43800 responsive: [{ 43801 breakpoint: 1024, 43802 onRefresh: function onRefresh() { 43803 this.createBanner(true); 43804 } 43805 }, { 43806 breakpoint: 600, 43807 onRefresh: function onRefresh() { 43808 this.createBanner(true); 43809 } 43810 }] 43811 }); 43812 }); 43813 43814 //BMV: Datenblatt drucken 43815 $('.printButton').gsb_printbutton(); 43816 43817 //Hier das richtige Input-Feld selektieren und den code einkommentieren 43818 $('.datepicker').find('[name=datepicker]').datepicker({ 43819 showOn: "button", 43820 buttonImage: image_url_calendar, 43821 buttonImageOnly: true, 43822 buttonText: DATEPICKER_TEXT, 43823 dateFormat: "dd.mm.yy", 43824 monthNames: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"], 43825 monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"], 43826 dayNamesMin: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"] 43827 }); 43828 43829 // calendar 43830 $('#supplement').find('.live-calendar').gsb_calendar({ 43831 beforeInit: function beforeInit() { 43832 $('#supplement .live-calendar').find('.has-tip').each(function (_, el) { 43833 $('#' + $(el).attr('aria-describedby')).remove(); 43834 }); 43835 }, 43836 afterInit: function afterInit() { 43837 $('#supplement .live-calendar').find('abbr, acronym').gsb_tooltip().foundation(); 43838 } 43839 }); 43840 43841 // flyout 43842 $('#navPrimary').gsb_slideNavigation({ 43843 autosuggestURL: json_url_mobileSearch 43844 }); 43845 43846 $('.togglebar').gsb_navigation_mobile({ 43847 autosuggestURL: json_url_mobileSearch, 43848 menuHtml: json_url_mobileMenu 43849 }); 43850 43851 // responsive table wrapper 43852 content.gsb_responsiveTables(); 43853 43854 // lightboxes 43855 $('.GlossarEntry').gsb_lightbox(); 43856 $('.picture .loupe').not('.galleryBox *').gsb_lightbox(); 43857 43858 // toggle fuer Module 43859 $("#navServiceMeta").find('ul').gsb_toggle({ 43860 tab: false, 43861 onRefresh: function onRefresh() { 43862 this.initialize(); 43863 this.refreshAccordion(); 43864 } 43865 }); 43866 content.find('.acc').gsb_toggle({ 43867 tab: false 43868 }); 43869 $("#gb-facets").find('.facet-acc').gsb_toggle({ 43870 tab: false 43871 }); 43872 43873 content.find('.tabacc').gsb_toggle(); 43874 content.gsb_toggle({ 43875 tab: false, 43876 richTextAccordion: true 43877 }); 43878 content.find('.researc').gsb_toggle({ 43879 tabControls: '> .wrapper-tabs-list .tabs-list > li a' 43880 }); 43881 43882 // tooltips for abbreviations 43883 $('abbr').gsb_tooltip(); 43884 $('acronym').gsb_tooltip(); 43885 if ($('#facets').find('ul').length) { 43886 $('#facets').find('ul').gsb_baua_toggleFacet(); 43887 } 43888 43889 var bt_toggle = $('#facets').find('.bt-toggle'); 43890 if (bt_toggle.length) { 43891 var aural = $('<span class="aural"/>'); 43892 var image = bt_toggle.find('img'); 43893 var tmpAlt, tmpSrc; 43894 aural.text(SHOW_MORE); 43895 bt_toggle.append(aural); 43896 bt_toggle.on('click', function (e) { 43897 e.preventDefault(); 43898 e.stopPropagation(); 43899 var button = $(this); 43900 if (button.hasClass('opened')) { 43901 button.removeClass('opened').addClass('closed'); 43902 $('#facets').find('.showContent').trigger('click'); 43903 aural.text(SHOW_MORE); 43904 changeImage(image); 43905 } else { 43906 button.removeClass('closed').addClass('opened'); 43907 // Quickfix um nach dem öffnen die erste Facette zu selektieren
43908 var reveredFind = $('#facets').find('.hideContent').get().reverse(); 43909 $(reveredFind).trigger('click'); 43910 aural.text(SHOW_LESS); 43911 changeImage(image); 43912 } 43913 }); 43914 } 43915 43916 var formBiozid = $('[name = ProduktMelden3]'); 43917 43918 if (formBiozid.length) { 43919 var produktartHinweis = $("#ProduktartHinweis").text(); 43920 if (produktartHinweis === "6") { 43921 formBiozid.find('[name=idProduktart]').not('[name=idProduktart][value=6]').attr('disabled', 'true'); 43922 } else if (produktartHinweis === "7") { 43923 formBiozid.find('[name=idProduktart]').not('[name=idProduktart][value=7]').attr('disabled', 'true'); 43924 } else if (produktartHinweis === "andere") { 43925 formBiozid.find('[name=idProduktart][value=6], [name=idProduktart][value=7]').attr('disabled', 'true'); 43926 } else { 43927 formBiozid.on('click', '[name=idProduktart]', function () { 43928 var input = $(this); 43929 43930 var findOther = formBiozid.find('[name=idProduktart]').not('[name=idProduktart][value=6], [name=idProduktart][value=7]'); 43931 43932 var changeOther = false; 43933 // noinspection EqualityComparisonWithCoercionJS 43934 if (input.val() == 6 || input.val() == 7) { 43935 changeOther = true; 43936 } 43937 43938 if (!$(this).is(':checked')) { 43939 if (changeOther) { 43940 formBiozid.find('[name=idProduktart]').not(input).removeAttr('disabled'); 43941 } else { 43942 if (!findOther.is(':checked')) { 43943 formBiozid.find('[name=idProduktart][value=6], [name=idProduktart][value=7]').removeAttr('disabled'); 43944 } 43945 } 43946 } else { 43947 if (changeOther) { 43948 formBiozid.find('[name=idProduktart]').not(input).attr('disabled', 'true'); 43949 } else { 43950 formBiozid.find('[name=idProduktart][value=6], [name=idProduktart][value=7]').attr('disabled', 'true'); 43951 } 43952 } 43953 }); 43954 } 43955 } 43956 43957 function changeImage(image) { 43958 tmpAlt = image.attr('alt'); 43959 tmpSrc = image.attr('src'); 43960 image.attr('src', image.attr('data-src')).attr('alt', image.attr('data-alt')); 43961 image.attr('data-src', tmpSrc).attr('data-alt', tmpAlt); 43962 } 43963 43964 // player for multimedia content 43965 var $contentNotVimeo = $('.content video, .content audio').filter(function (index, el) { 43966 return $(el).find('source[type|="video/vimeo"]').length < 1; 43967 }); 43968 var $contentVimeo = $('.content video, .content audio').filter(function (index, el) { 43969 return $(el).find('source[type|="video/vimeo"]').length > 0; 43970 }); 43971 43972 var $supplementNotVimeo = $('.supplement video, .supplement audio').filter(function (index, el) { 43973 return $(el).find('source[type|="video/vimeo"]').length < 1; 43974 }); 43975 var $supplementVimeo = $('.supplement video, .supplement audio').filter(function (index, el) { 43976 return $(el).find('source[type|="video/vimeo"]').length > 0; 43977 }); 43978 43979 gsb.requireGSBComponent('bundle_multimedia', $contentNotVimeo).done(function ($contentMedia) { 43980 $contentMedia.gsb_Multimedia({ 43981 externalApiRequiresConsent: !$body.hasClass('js-youtube-consent-not-required') 43982 }); 43983 }); 43984 43985 gsb.requireGSBComponent('bundle_multimedia', $supplementNotVimeo).done(function ($supplementMedia) { 43986 $supplementMedia.gsb_Multimedia({ 43987 externalApiRequiresConsent: !$body.hasClass('js-youtube-consent-not-required'), 43988 settings: { 43989 mediaelementplayerOptions: { 43990 videoWidth: 280, 43991 videoHeight: 158 43992 } 43993 }, 43994 responsive: [{ 43995 breakpoint: 600, 43996 settings: { 43997 mediaelementplayerOptions: { 43998 videoWidth: 280, 43999 videoHeight: 158 44000 } 44001 } 44002 }] 44003 }); 44004 }); 44005 44006 // Vimeo Content 44007 gsb.requireGSBComponent('bundle_multimedia', $contentVimeo).done(function ($media) { 44008 $media.gsb_Multimedia({ 44009 externalApiRequiresConsent: !$body.hasClass('js-external-video-api-consent-not-required'), 44010 settings: { 44011 mediaelementplayerOptions: { 44012 features: '' 44013 } 44014 } 44015 }); 44016 }); 44017 44018 gsb.requireGSBComponent('bundle_multimedia', $supplementVimeo).done(function ($media) { 44019 $media.gsb_Multimedia({ 44020 externalApiRequiresConsent: !$body.hasClass('js-external-video-api-consent-not-required'), 44021 settings: { 44022 mediaelementplayerOptions: { 44023 features: '', 44024 videoWidth: 280, 44025 videoHeight: 158 44026 } 44027 }, 44028 responsive: [{ 44029 breakpoint: 600, 44030 settings: { 44031 mediaelementplayerOptions: { 44032 features: '', 44033 videoWidth: 280, 44034 videoHeight: 158 44035 } 44036 } 44037 }] 44038 }); 44039 }); 44040 44041 // gsb_infinitescrolling 44042 var sectionresults = $('#content').find('.section-results'); 44043 if (sectionresults.length > 0) { 44044 sectionresults.gsb_infinitescrolling(); 44045 } 44046 44047 $('.intro-toggle').gsb_baua_toggleText(); 44048 44049 var searchTargetMarker = content.find('#searchTargetMarker'); 44050 if (searchTargetMarker.length > 0) { 44051 searchTargetMarker.parent().find('input.image').on('click', function (e) { 44052 e.preventDefault(); 44053 var action = $(this).closest('form').attr('action'); 44054 $(this).closest('form').attr('action', action + '#searchTargetMarker').submit(); 44055 }); 44056 } 44057 44058 $('.child-grp-anchor a').click(function (e) { 44059 e.preventDefault(); 44060 var dest = $(this).attr('href'); 44061 var parts = dest.split("#"); 44062 var trgt = parts[1]; 44063 $('html,body').animate({ 44064 scrollTop: $("#" + trgt).offset().top 44065 }, 'slow'); 44066 }); 44067 (function () { 44068 var hash = location.hash || location.href.match(/#.*$/), 44069 target; 44070 if (hash) { 44071 target = document.getElementById(hash.toString().replace('#', '')); 44072 if (target) { 44073 $('html,body').animate({ 44074 scrollTop: $(target).offset().top 44075 }, 0); 44076 } 44077 } 44078 })(); 44079 44080 (function () { 44081 var $body = $('body'), 44082 $logo = $('.logo').first().find('img'), 44083 scrolledClassValue = 'js-scrolled', 44084 defaultLogoSrc = $logo.attr('src'), 44085 $togglebar = $('.togglebar'), 44086 mobileNavigation = $togglebar.data('gsb.navigation_mobile'), 44087 handleScrolledPage = function handleScrolledPage() { 44088 function activateScrolledStateForPageIfNotAlreadyDone() { 44089 function closeTogglebarIfOpen() { 44090 if (mobileNavigation.nav && mobileNavigation.isOpened(mobileNavigation.nav)) { 44091 $(mobileNavigation.options.navOpenButton).click(); 44092 } 44093 44094 if (mobileNavigation.search && mobileNavigation.isOpened(mobileNavigation.search)) { 44095 $(mobileNavigation.options.navSearchButton).click(); 44096 } 44097 } 44098 44099 if (!$body.hasClass(scrolledClassValue)) { 44100 $body.addClass(scrolledClassValue); 44101 if (image_url_logo_scrolled) { 44102 $logo.attr('src', image_url_logo_scrolled); 44103 } 44104 closeTogglebarIfOpen(); 44105 $('body').trigger('stickyheader.scrolled'); 44106 } 44107 } 44108 44109 function deactivateScrolledStateForPage() { 44110 $body.removeClass(scrolledClassValue); 44111 $logo.attr('src', defaultLogoSrc); 44112 } 44113 44114 function scrolledStateNeedsToBeActivated() { 44115 var $openNavigation = $('.nav.opened'), 44116 userHasScrolled = $(window).scrollTop() > 0, 44117 scrolledPositionIsWithinOpenNavigation = $openNavigation.length && $(window).scrollTop() < $openNavigation.offset().top + $openNavigation.outerHeight(), 44118 mobileSearchTextfieldHasFocus = typeof mobileNavigation.search !== "undefined" && mobileNavigation.search.find('input[type="text"]:focus').length === 1; 44119 return userHasScrolled && !scrolledPositionIsWithinOpenNavigation && !mobileSearchTextfieldHasFocus; 44120 } 44121 44122 if (scrolledStateNeedsToBeActivated()) { 44123 activateScrolledStateForPageIfNotAlreadyDone(); 44124 } else { 44125 deactivateScrolledStateForPage(); 44126 } 44127 }, 44128 scrollToTopIfPageHasBeenScrolled = function scrollToTopIfPageHasBeenScrolled(e) { 44129 if ($(window).scrollTop() > 0) { 44130 e.preventDefault(); 44131 $('html,body').animate({ 44132 scrollTop: 0 44133 }, 0); 44134 } 44135 }, 44136 gotoElement = function gotoElement($jumpToElement) { 44137 if ($jumpToElement.length) { 44138 var jumpToScrollTop = $jumpToElement.offset().top - $('#header').outerHeight(true); 44139 if (!$body.hasClass('js-scrolled')) { 44140 jumpToScrollTop -= 70; 44141 } 44142 $('html,body').animate({ 44143 scrollTop: jumpToScrollTop 44144 }, 100); 44145 } 44146 },
44147 gotoHashOnInitialPageLoad = function gotoHashOnInitialPageLoad() { 44148 $body.one('stickyheader.scrolled', function () { 44149 if (window.location.hash) { 44150 var $jumpToElement = $(window.location.hash); 44151 gotoElement($jumpToElement); 44152 } 44153 }); 44154 }, 44155 handleTocJumpLinks = function handleTocJumpLinks() { 44156 $('.toc a').click(function (e) { 44157 e.preventDefault(); 44158 var hrefOfTocLink = $(this).attr('href'), 44159 hash = hrefOfTocLink.substr(hrefOfTocLink.indexOf('#')); 44160 gotoElement($(hash)); 44161 }); 44162 }; 44163 $(window).scroll(handleScrolledPage); 44164 $('#header').find('a').click(scrollToTopIfPageHasBeenScrolled); 44165 gotoHashOnInitialPageLoad(); 44166 handleTocJumpLinks(); 44167 })(); 44168 44169 // Foundation initialisieren 44170 $(document).foundation(); 44171}); 44172 /* Ende init */ 44173 44174jQuery(document).ready(function (jQuery){ 44175 // Autosuggest 44176 var searchforms = []; 44177 searchforms[1] = { 44178 id : 'searchService', 44179 action : 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Forms/Suche/DE/Servicesuche_Autosuggest_Formular?nn=6942652c85ec843c18743a51' 44180 }; 44181 searchforms[2] = { 44182 id : 'searchExpert', 44183 action : 'https://www.reach-clp-biozid-helpdesk.de/SiteGlobals/Forms/Suche/DE/Expertensuche_Autosuggest_Formular?nn=6942652c85ec843c18743a51' 44184 }; 44185 if(searchforms.length > 0){ 44186 $(searchforms).each(function(index){ 44187 var valueObj = searchforms[index],form; 44188 if(valueObj !== undefined){ 44189 form = jQuery('form[name="'+ valueObj.id +'"]'); 44190 if(form.length > 0){ 44191 form.gsb_AutoSuggest(valueObj.action); 44192 } 44193 } 44194 }); 44195 } 44196}); 44197
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.