vendor: 16,509 bytes, lines 1-518
1/* 2 * This combined file was created by the DataTables downloader builder: 3 * https://datatables.net/download 4 * 5 * To rebuild or modify this file with the latest versions of the included 6 * software please visit: 7 * https://datatables.net/download/#bs/jszip-2.5.0/dt-1.10.18/b-1.5.4/b-colvis-1.5.4/b-html5-1.5.4/cr-1.5.0/fh-3.1.4/r-2.2.2/rg-1.1.0/sc-1.5.0/sl-1.2.6 8 * 9 * Included libraries: 10 * JSZip 2.5.0, DataTables 1.10.18, Buttons 1.5.4, Column visibility 1.5.4, HTML5 export 1.5.4, ColReorder 1.5.0, FixedHeader 3.1.4, Responsive 2.2.2, RowGroup 1.1.0, Scroller 1.5.0, Select 1.2.6 11 */ 12 13/*! 14 15JSZip - A Javascript class for generating and reading zip files 16<http://stuartk.com/jszip> 17 18(c) 2009-2014 Stuart Knightley <stuart [at] stuartk.com> 19Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. 20 21JSZip uses the library pako released under the MIT license : 22https://github.com/nodeca/pako/blob/master/LICENSE 23*/ 24!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.JSZip=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ 25'use strict'; 26// private property 27var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 28 29 30// public method for encoding 31exports.encode = function(input, utf8) { 32 var output = ""; 33 var chr1, chr2, chr3, enc1, enc2, enc3, enc4; 34 var i = 0; 35 36 while (i < input.length) { 37 38 chr1 = input.charCodeAt(i++); 39 chr2 = input.charCodeAt(i++); 40 chr3 = input.charCodeAt(i++); 41 42 enc1 = chr1 >> 2; 43 enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); 44 enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); 45 enc4 = chr3 & 63; 46 47 if (isNaN(chr2)) { 48 enc3 = enc4 = 64; 49 } 50 else if (isNaN(chr3)) { 51 enc4 = 64; 52 } 53 54 output = output + _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4); 55 56 } 57 58 return output; 59}; 60 61// public method for decoding 62exports.decode = function(input, utf8) { 63 var output = ""; 64 var chr1, chr2, chr3; 65 var enc1, enc2, enc3, enc4; 66 var i = 0; 67 68 input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); 69 70 while (i < input.length) { 71 72 enc1 = _keyStr.indexOf(input.charAt(i++)); 73 enc2 = _keyStr.indexOf(input.charAt(i++)); 74 enc3 = _keyStr.indexOf(input.charAt(i++)); 75 enc4 = _keyStr.indexOf(input.charAt(i++)); 76 77 chr1 = (enc1 << 2) | (enc2 >> 4); 78 chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); 79 chr3 = ((enc3 & 3) << 6) | enc4; 80 81 output = output + String.fromCharCode(chr1); 82 83 if (enc3 != 64) { 84 output = output + String.fromCharCode(chr2); 85 } 86 if (enc4 != 64) { 87 output = output + String.fromCharCode(chr3); 88 } 89 90 } 91 92 return output; 93 94}; 95 96},{}],2:[function(_dereq_,module,exports){ 97'use strict'; 98function CompressedObject() { 99 this.compressedSize = 0; 100 this.uncompressedSize = 0; 101 this.crc32 = 0; 102 this.compressionMethod = null; 103 this.compressedContent = null; 104} 105 106CompressedObject.prototype = { 107 /** 108 * Return the decompressed content in an unspecified format. 109 * The format will depend on the decompressor. 110 * @return {Object} the decompressed content. 111 */ 112 getContent: function() { 113 return null; // see implementation 114 }, 115 /** 116 * Return the compressed content in an unspecified format. 117 * The format will depend on the compressed conten source. 118 * @return {Object} the compressed content. 119 */ 120 getCompressedContent: function() { 121 return null; // see implementation 122 } 123}; 124module.exports = CompressedObject; 125 126},{}],3:[function(_dereq_,module,exports){ 127'use strict'; 128exports.STORE = { 129 magic: "\x00\x00", 130 compress: function(content, compressionOptions) { 131 return content; // no compression 132 }, 133 uncompress: function(content) { 134 return content; // no compression 135 }, 136 compressInputType: null, 137 uncompressInputType: null 138}; 139exports.DEFLATE = _dereq_('./flate'); 140 141},{"./flate":8}],4:[function(_dereq_,module,exports){ 142'use strict'; 143 144var utils = _dereq_('./utils'); 145 146var table = [ 147 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 148 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 149 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 150 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 151 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 152 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 153 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 154 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 155 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 156 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 157 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 158 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 159 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 160 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 161 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 162 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 163 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 164 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 165 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 166 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 167 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 168 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 169 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 170 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 171 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 172 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 173 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 174 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 175 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 176 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 177 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 178 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 179 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 180 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 181 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 182 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 183 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 184 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 185 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 186 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 187 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 188 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 189 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 190 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 191 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 192 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 193 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 194 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 195 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 196 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 197 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 198 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 199 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 200 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 201 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 202 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 203 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 204 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 205 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 206 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 207 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 208 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 209 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 210 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D 211]; 212 213/** 214 * 215 * Javascript crc32 216 * http://www.webtoolkit.info/ 217 * 218 */ 219module.exports = function crc32(input, crc) { 220 if (typeof input === "undefined" || !input.length) { 221 return 0; 222 } 223 224 var isArray = utils.getTypeOf(input) !== "string"; 225 226 if (typeof(crc) == "undefined") { 227 crc = 0; 228 } 229 var x = 0; 230 var y = 0; 231 var b = 0; 232 233 crc = crc ^ (-1); 234 for (var i = 0, iTop = input.length; i < iTop; i++) { 235 b = isArray ? input[i] : input.charCodeAt(i); 236 y = (crc ^ b) & 0xFF; 237 x = table[y]; 238 crc = (crc >>> 8) ^ x; 239 } 240 241 return crc ^ (-1); 242}; 243// vim: set shiftwidth=4 softtabstop=4: 244 245},{"./utils":21}],5:[function(_dereq_,module,exports){ 246'use strict'; 247var utils = _dereq_('./utils'); 248 249function DataReader(data) { 250 this.data = null; // type : see implementation 251 this.length = 0; 252 this.index = 0; 253} 254DataReader.prototype = { 255 /** 256 * Check that the offset will not go too far. 257 * @param {string} offset the additional offset to check. 258 * @throws {Error} an Error if the offset is out of bounds. 259 */ 260 checkOffset: function(offset) { 261 this.checkIndex(this.index + offset); 262 }, 263 /** 264 * Check that the specifed index will not be too far. 265 * @param {string} newIndex the index to check. 266 * @throws {Error} an Error if the index is out of bounds. 267 */ 268 checkIndex: function(newIndex) { 269 if (this.length < newIndex || newIndex < 0) { 270 throw new Error("End of data reached (data length = " + this.length + ", asked index = " + (newIndex) + "). Corrupted zip ?"); 271 } 272 }, 273 /** 274 * Change the index. 275 * @param {number} newIndex The new index. 276 * @throws {Error} if the new index is out of the data. 277 */ 278 setIndex: function(newIndex) { 279 this.checkIndex(newIndex); 280 this.index = newIndex; 281 }, 282 /** 283 * Skip the next n bytes. 284 * @param {number} n the number of bytes to skip. 285 * @throws {Error} if the new index is out of the data. 286 */ 287 skip: function(n) { 288 this.setIndex(this.index + n); 289 }, 290 /** 291 * Get the byte at the specified index. 292 * @param {number} i the index to use. 293 * @return {number} a byte. 294 */ 295 byteAt: function(i) { 296 // see implementations 297 }, 298 /** 299 * Get the next number with a given byte size. 300 * @param {number} size the number of bytes to read. 301 * @return {number} the corresponding number. 302 */ 303 readInt: function(size) { 304 var result = 0, 305 i; 306 this.checkOffset(size); 307 for (i = this.index + size - 1; i >= this.index; i--) { 308 result = (result << 8) + this.byteAt(i); 309 } 310 this.index += size; 311 return result; 312 }, 313 /** 314 * Get the next string with a given byte size. 315 * @param {number} size the number of bytes to read. 316 * @return {string} the corresponding string. 317 */ 318 readString: function(size) { 319 return utils.transformTo("string", this.readData(size)); 320 }, 321 /** 322 * Get raw data without conversion, <size> bytes. 323 * @param {number} size the number of bytes to read. 324 * @return {Object} the raw data, implementation specific. 325 */ 326 readData: function(size) { 327 // see implementations 328 }, 329 /** 330 * Find the last occurence of a zip signature (4 bytes). 331 * @param {string} sig the signature to find. 332 * @return {number} the index of the last occurence, -1 if not found. 333 */ 334 lastIndexOfSignature: function(sig) { 335 // see implementations 336 }, 337 /** 338 * Get the next date. 339 * @return {Date} the date. 340 */ 341 readDate: function() { 342 var dostime = this.readInt(4); 343 return new Date( 344 ((dostime >> 25) & 0x7f) + 1980, // year 345 ((dostime >> 21) & 0x0f) - 1, // month 346 (dostime >> 16) & 0x1f, // day 347 (dostime >> 11) & 0x1f, // hour 348 (dostime >> 5) & 0x3f, // minute 349 (dostime & 0x1f) << 1); // second 350 } 351}; 352module.exports = DataReader; 353 354},{"./utils":21}],6:[function(_dereq_,module,exports){ 355'use strict'; 356exports.base64 = false; 357exports.binary = false; 358exports.dir = false; 359exports.createFolders = false; 360exports.date = null; 361exports.compression = null; 362exports.compressionOptions = null; 363exports.comment = null; 364exports.unixPermissions = null; 365exports.dosPermissions = null; 366 367},{}],7:[function(_dereq_,module,exports){ 368'use strict'; 369var utils = _dereq_('./utils'); 370 371/** 372 * @deprecated 373 * This function will be removed in a future version without replacement. 374 */ 375exports.string2binary = function(str) { 376 return utils.string2binary(str); 377}; 378 379/** 380 * @deprecated 381 * This function will be removed in a future version without replacement. 382 */ 383exports.string2Uint8Array = function(str) { 384 return utils.transformTo("uint8array", str); 385}; 386 387/** 388 * @deprecated 389 * This function will be removed in a future version without replacement. 390 */ 391exports.uint8Array2String = function(array) { 392 return utils.transformTo("string", array); 393}; 394 395/** 396 * @deprecated 397 * This function will be removed in a future version without replacement. 398 */ 399exports.string2Blob = function(str) { 400 var buffer = utils.transformTo("arraybuffer", str); 401 return utils.arrayBuffer2Blob(buffer); 402}; 403 404/** 405 * @deprecated 406 * This function will be removed in a future version without replacement. 407 */ 408exports.arrayBuffer2Blob = function(buffer) { 409 return utils.arrayBuffer2Blob(buffer); 410}; 411 412/** 413 * @deprecated 414 * This function will be removed in a future version without replacement. 415 */ 416exports.transformTo = function(outputType, input) { 417 return utils.transformTo(outputType, input); 418}; 419 420/** 421 * @deprecated 422 * This function will be removed in a future version without replacement. 423 */ 424exports.getTypeOf = function(input) { 425 return utils.getTypeOf(input); 426}; 427 428/** 429 * @deprecated 430 * This function will be removed in a future version without replacement. 431 */ 432exports.checkSupport = function(type) { 433 return utils.checkSupport(type); 434}; 435 436/** 437 * @deprecated 438 * This value will be removed in a future version without replacement. 439 */ 440exports.MAX_VALUE_16BITS = utils.MAX_VALUE_16BITS; 441 442/** 443 * @deprecated 444 * This value will be removed in a future version without replacement. 445 */ 446exports.MAX_VALUE_32BITS = utils.MAX_VALUE_32BITS; 447 448 449/** 450 * @deprecated 451 * This function will be removed in a future version without replacement. 452 */ 453exports.pretty = function(str) { 454 return utils.pretty(str); 455}; 456 457/** 458 * @deprecated 459 * This function will be removed in a future version without replacement. 460 */ 461exports.findCompression = function(compressionMethod) { 462 return utils.findCompression(compressionMethod); 463}; 464 465/** 466 * @deprecated 467 * This function will be removed in a future version without replacement. 468 */ 469exports.isRegExp = function (object) { 470 return utils.isRegExp(object); 471}; 472 473 474},{"./utils":21}],8:[function(_dereq_,module,exports){ 475'use strict'; 476var USE_TYPEDARRAY = (typeof Uint8Array !== 'undefined') && (typeof Uint16Array !== 'undefined') && (typeof Uint32Array !== 'undefined'); 477 478var pako = _dereq_("pako"); 479exports.uncompressInputType = USE_TYPEDARRAY ? "uint8array" : "array"; 480exports.compressInputType = USE_TYPEDARRAY ? "uint8array" : "array"; 481 482exports.magic = "\x08\x00"; 483exports.compress = function(input, compressionOptions) { 484 return pako.deflateRaw(input, { 485 level : compressionOptions.level || -1 // default compression 486 }); 487}; 488exports.uncompress = function(input) { 489 return pako.inflateRaw(input); 490}; 491 492},{"pako":24}],9:[function(_dereq_,module,exports){ 493'use strict'; 494 495var base64 = _dereq_('./base64'); 496 497/** 498Usage: 499 zip = new JSZip(); 500 zip.file("hello.txt", "Hello, World!").file("tempfile", "nothing"); 501 zip.folder("images").file("smile.gif", base64Data, {base64: true}); 502 zip.file("Xmas.txt", "Ho ho ho !", {date : new Date("December 25, 2007 00:00:01")}); 503 zip.remove("tempfile"); 504 505 base64zip = zip.generate(); 506 507**/ 508 509/** 510 * Representation a of zip file in js 511 * @constructor 512 * @param {String=|ArrayBuffer=|Uint8Array=} data the data to load, if any (optional). 513 * @param {Object=} options the options for creating this objects (optional). 514 */ 515function JSZip(data, options) { 516 // if this constructor is used without `new`, it adds `new` before itself: 517 if(!(this instanceof JSZip)) return new JSZip(data, options); 518
vendor: 3,309 bytes, lines 519-639
519 // object containing the files : 520 // { 521 // "folder/" : {...}, 522 // "folder/data.txt" : {...} 523 // } 524 this.files = {}; 525 526 this.comment = null; 527 528 // Where we are in the hierarchy 529 this.root = ""; 530 if (data) { 531 this.load(data, options); 532 } 533 this.clone = function() { 534 var newObj = new JSZip(); 535 for (var i in this) { 536 if (typeof this[i] !== "function") { 537 newObj[i] = this[i]; 538 } 539 } 540 return newObj; 541 }; 542} 543JSZip.prototype = _dereq_('./object'); 544JSZip.prototype.load = _dereq_('./load'); 545JSZip.support = _dereq_('./support'); 546JSZip.defaults = _dereq_('./defaults'); 547 548/** 549 * @deprecated 550 * This namespace will be removed in a future version without replacement. 551 */ 552JSZip.utils = _dereq_('./deprecatedPublicUtils'); 553 554JSZip.base64 = { 555 /** 556 * @deprecated 557 * This method will be removed in a future version without replacement. 558 */ 559 encode : function(input) { 560 return base64.encode(input); 561 }, 562 /** 563 * @deprecated 564 * This method will be removed in a future version without replacement. 565 */ 566 decode : function(input) { 567 return base64.decode(input); 568 } 569}; 570JSZip.compressions = _dereq_('./compressions'); 571module.exports = JSZip; 572 573},{"./base64":1,"./compressions":3,"./defaults":6,"./deprecatedPublicUtils":7,"./load":10,"./object":13,"./support":17}],10:[function(_dereq_,module,exports){ 574'use strict'; 575var base64 = _dereq_('./base64'); 576var ZipEntries = _dereq_('./zipEntries'); 577module.exports = function(data, options) { 578 var files, zipEntries, i, input; 579 options = options || {}; 580 if (options.base64) { 581 data = base64.decode(data); 582 } 583 584 zipEntries = new ZipEntries(data, options); 585 files = zipEntries.files; 586 for (i = 0; i < files.length; i++) { 587 input = files[i]; 588 this.file(input.fileName, input.decompressed, { 589 binary: true, 590 optimizedBinaryString: true, 591 date: input.date, 592 dir: input.dir, 593 comment : input.fileComment.length ? input.fileComment : null, 594 unixPermissions : input.unixPermissions, 595 dosPermissions : input.dosPermissions, 596 createFolders: options.createFolders 597 }); 598 } 599 if (zipEntries.zipComment.length) { 600 this.comment = zipEntries.zipComment; 601 } 602 603 return this; 604}; 605 606},{"./base64":1,"./zipEntries":22}],11:[function(_dereq_,module,exports){ 607(function (Buffer){ 608'use strict'; 609module.exports = function(data, encoding){ 610 return new Buffer(data, encoding); 611}; 612module.exports.test = function(b){ 613 return Buffer.isBuffer(b); 614}; 615 616}).call(this,(typeof Buffer !== "undefined" ? Buffer : undefined)) 617},{}],12:[function(_dereq_,module,exports){ 618'use strict'; 619var Uint8ArrayReader = _dereq_('./uint8ArrayReader'); 620 621function NodeBufferReader(data) { 622 this.data = data; 623 this.length = this.data.length; 624 this.index = 0; 625} 626NodeBufferReader.prototype = new Uint8ArrayReader(); 627 628/** 629 * @see DataReader.readData 630 */ 631NodeBufferReader.prototype.readData = function(size) { 632 this.checkOffset(size); 633 var result = this.data.slice(this.index, this.index + size); 634 this.index += size; 635 return result; 636}; 637module.exports = NodeBufferReader; 638 639},{"./uint8ArrayReader":18}],13
vendor: 5,595 bytes, lines 639-816
639:[function(_dereq_,module,exports){ 640'use strict'; 641var support = _dereq_('./support'); 642var utils = _dereq_('./utils'); 643var crc32 = _dereq_('./crc32'); 644var signature = _dereq_('./signature'); 645var defaults = _dereq_('./defaults'); 646var base64 = _dereq_('./base64'); 647var compressions = _dereq_('./compressions'); 648var CompressedObject = _dereq_('./compressedObject'); 649var nodeBuffer = _dereq_('./nodeBuffer'); 650var utf8 = _dereq_('./utf8'); 651var StringWriter = _dereq_('./stringWriter'); 652var Uint8ArrayWriter = _dereq_('./uint8ArrayWriter'); 653 654/** 655 * Returns the raw data of a ZipObject, decompress the content if necessary. 656 * @param {ZipObject} file the file to use. 657 * @return {String|ArrayBuffer|Uint8Array|Buffer} the data. 658 */ 659var getRawData = function(file) { 660 if (file._data instanceof CompressedObject) { 661 file._data = file._data.getContent(); 662 file.options.binary = true; 663 file.options.base64 = false; 664 665 if (utils.getTypeOf(file._data) === "uint8array") { 666 var copy = file._data; 667 // when reading an arraybuffer, the CompressedObject mechanism will keep it and subarray() a Uint8Array. 668 // if we request a file in the same format, we might get the same Uint8Array or its ArrayBuffer (the original zip file). 669 file._data = new Uint8Array(copy.length); 670 // with an empty Uint8Array, Opera fails with a "Offset larger than array size" 671 if (copy.length !== 0) { 672 file._data.set(copy, 0); 673 } 674 } 675 } 676 return file._data; 677}; 678 679/** 680 * Returns the data of a ZipObject in a binary form. If the content is an unicode string, encode it. 681 * @param {ZipObject} file the file to use. 682 * @return {String|ArrayBuffer|Uint8Array|Buffer} the data. 683 */ 684var getBinaryData = function(file) { 685 var result = getRawData(file), 686 type = utils.getTypeOf(result); 687 if (type === "string") { 688 if (!file.options.binary) { 689 // unicode text ! 690 // unicode string => binary string is a painful process, check if we can avoid it. 691 if (support.nodebuffer) { 692 return nodeBuffer(result, "utf-8"); 693 } 694 } 695 return file.asBinary(); 696 } 697 return result; 698}; 699 700/** 701 * Transform this._data into a string. 702 * @param {function} filter a function String -> String, applied if not null on the result. 703 * @return {String} the string representing this._data. 704 */ 705var dataToString = function(asUTF8) { 706 var result = getRawData(this); 707 if (result === null || typeof result === "undefined") { 708 return ""; 709 } 710 // if the data is a base64 string, we decode it before checking the encoding ! 711 if (this.options.base64) { 712 result = base64.decode(result); 713 } 714 if (asUTF8 && this.options.binary) { 715 // JSZip.prototype.utf8decode supports arrays as input 716 // skip to array => string step, utf8decode will do it. 717 result = out.utf8decode(result); 718 } 719 else { 720 // no utf8 transformation, do the array => string step. 721 result = utils.transformTo("string", result); 722 } 723 724 if (!asUTF8 && !this.options.binary) { 725 result = utils.transformTo("string", out.utf8encode(result)); 726 } 727 return result; 728}; 729/** 730 * A simple object representing a file in the zip file. 731 * @constructor 732 * @param {string} name the name of the file 733 * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data 734 * @param {Object} options the options of the file 735 */ 736var ZipObject = function(name, data, options) { 737 this.name = name; 738 this.dir = options.dir; 739 this.date = options.date; 740 this.comment = options.comment; 741 this.unixPermissions = options.unixPermissions; 742 this.dosPermissions = options.dosPermissions; 743 744 this._data = data; 745 this.options = options; 746 747 /* 748 * This object contains initial values for dir and date. 749 * With them, we can check if the user changed the deprecated metadata in 750 * `ZipObject#options` or not. 751 */ 752 this._initialMetadata = { 753 dir : options.dir, 754 date : options.date 755 }; 756}; 757 758ZipObject.prototype = { 759 /** 760 * Return the content as UTF8 string. 761 * @return {string} the UTF8 string. 762 */ 763 asText: function() { 764 return dataToString.call(this, true); 765 }, 766 /** 767 * Returns the binary content. 768 * @return {string} the content as binary. 769 */ 770 asBinary: function() { 771 return dataToString.call(this, false); 772 }, 773 /** 774 * Returns the content as a nodejs Buffer. 775 * @return {Buffer} the content as a Buffer. 776 */ 777 asNodeBuffer: function() { 778 var result = getBinaryData(this); 779 return utils.transformTo("nodebuffer", result); 780 }, 781 /** 782 * Returns the content as an Uint8Array. 783 * @return {Uint8Array} the content as an Uint8Array. 784 */ 785 asUint8Array: function() { 786 var result = getBinaryData(this); 787 return utils.transformTo("uint8array", result); 788 }, 789 /** 790 * Returns the content as an ArrayBuffer. 791 * @return {ArrayBuffer} the content as an ArrayBufer. 792 */ 793 asArrayBuffer: function() { 794 return this.asUint8Array().buffer; 795 } 796}; 797 798/** 799 * Transform an integer into a string in hexadecimal. 800 * @private 801 * @param {number} dec the number to convert. 802 * @param {number} bytes the number of bytes to generate. 803 * @returns {string} the result. 804 */ 805var decToHex = function(dec, bytes) { 806 var hex = "", 807 i; 808 for (i = 0; i < bytes; i++) { 809 hex += String.fromCharCode(dec & 0xff); 810 dec = dec >>> 8; 811 } 812 return hex; 813}; 814 815/** 816 *
vendor: 23,128 bytes, lines 816-1488
816Merge the objects passed as parameters into a new one. 817 * @private 818 * @param {...Object} var_args All objects to merge. 819 * @return {Object} a new object with the data of the others. 820 */ 821var extend = function() { 822 var result = {}, i, attr; 823 for (i = 0; i < arguments.length; i++) { // arguments is not enumerable in some browsers 824 for (attr in arguments[i]) { 825 if (arguments[i].hasOwnProperty(attr) && typeof result[attr] === "undefined") { 826 result[attr] = arguments[i][attr]; 827 } 828 } 829 } 830 return result; 831}; 832 833/** 834 * Transforms the (incomplete) options from the user into the complete 835 * set of options to create a file. 836 * @private 837 * @param {Object} o the options from the user. 838 * @return {Object} the complete set of options. 839 */ 840var prepareFileAttrs = function(o) { 841 o = o || {}; 842 if (o.base64 === true && (o.binary === null || o.binary === undefined)) { 843 o.binary = true; 844 } 845 o = extend(o, defaults); 846 o.date = o.date || new Date(); 847 if (o.compression !== null) o.compression = o.compression.toUpperCase(); 848 849 return o; 850}; 851 852/** 853 * Add a file in the current folder. 854 * @private 855 * @param {string} name the name of the file 856 * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data of the file 857 * @param {Object} o the options of the file 858 * @return {Object} the new file. 859 */ 860var fileAdd = function(name, data, o) { 861 // be sure sub folders exist 862 var dataType = utils.getTypeOf(data), 863 parent; 864 865 o = prepareFileAttrs(o); 866 867 if (typeof o.unixPermissions === "string") { 868 o.unixPermissions = parseInt(o.unixPermissions, 8); 869 } 870 871 // UNX_IFDIR 0040000 see zipinfo.c 872 if (o.unixPermissions && (o.unixPermissions & 0x4000)) { 873 o.dir = true; 874 } 875 // Bit 4 Directory 876 if (o.dosPermissions && (o.dosPermissions & 0x0010)) { 877 o.dir = true; 878 } 879 880 if (o.dir) { 881 name = forceTrailingSlash(name); 882 } 883 884 if (o.createFolders && (parent = parentFolder(name))) { 885 folderAdd.call(this, parent, true); 886 } 887 888 if (o.dir || data === null || typeof data === "undefined") { 889 o.base64 = false; 890 o.binary = false; 891 data = null; 892 dataType = null; 893 } 894 else if (dataType === "string") { 895 if (o.binary && !o.base64) { 896 // optimizedBinaryString == true means that the file has already been filtered with a 0xFF mask 897 if (o.optimizedBinaryString !== true) { 898 // this is a string, not in a base64 format. 899 // Be sure that this is a correct "binary string" 900 data = utils.string2binary(data); 901 } 902 } 903 } 904 else { // arraybuffer, uint8array, ... 905 o.base64 = false; 906 o.binary = true; 907 908 if (!dataType && !(data instanceof CompressedObject)) { 909 throw new Error("The data of '" + name + "' is in an unsupported format !"); 910 } 911 912 // special case : it's way easier to work with Uint8Array than with ArrayBuffer 913 if (dataType === "arraybuffer") { 914 data = utils.transformTo("uint8array", data); 915 } 916 } 917 918 var object = new ZipObject(name, data, o); 919 this.files[name] = object; 920 return object; 921}; 922 923/** 924 * Find the parent folder of the path. 925 * @private 926 * @param {string} path the path to use 927 * @return {string} the parent folder, or "" 928 */ 929var parentFolder = function (path) { 930 if (path.slice(-1) == '/') { 931 path = path.substring(0, path.length - 1); 932 } 933 var lastSlash = path.lastIndexOf('/'); 934 return (lastSlash > 0) ? path.substring(0, lastSlash) : ""; 935}; 936 937 938/** 939 * Returns the path with a slash at the end. 940 * @private 941 * @param {String} path the path to check. 942 * @return {String} the path with a trailing slash. 943 */ 944var forceTrailingSlash = function(path) { 945 // Check the name ends with a / 946 if (path.slice(-1) != "/") { 947 path += "/"; // IE doesn't like substr(-1) 948 } 949 return path; 950}; 951/** 952 * Add a (sub) folder in the current folder. 953 * @private 954 * @param {string} name the folder's name 955 * @param {boolean=} [createFolders] If true, automatically create sub 956 * folders. Defaults to false. 957 * @return {Object} the new folder. 958 */ 959var folderAdd = function(name, createFolders) { 960 createFolders = (typeof createFolders !== 'undefined') ? createFolders : false; 961 962 name = forceTrailingSlash(name); 963 964 // Does this folder already exist? 965 if (!this.files[name]) { 966 fileAdd.call(this, name, null, { 967 dir: true, 968 createFolders: createFolders 969 }); 970 } 971 return this.files[name]; 972}; 973 974/** 975 * Generate a JSZip.CompressedObject for a given zipOject. 976 * @param {ZipObject} file the object to read. 977 * @param {JSZip.compression} compression the compression to use. 978 * @param {Object} compressionOptions the options to use when compressing. 979 * @return {JSZip.CompressedObject} the compressed result. 980 */ 981var generateCompressedObjectFrom = function(file, compression, compressionOptions) { 982 var result = new CompressedObject(), 983 content; 984 985 // the data has not been decompressed, we might reuse things ! 986 if (file._data instanceof CompressedObject) { 987 result.uncompressedSize = file._data.uncompressedSize; 988 result.crc32 = file._data.crc32; 989 990 if (result.uncompressedSize === 0 || file.dir) { 991 compression = compressions['STORE']; 992 result.compressedContent = ""; 993 result.crc32 = 0; 994 } 995 else if (file._data.compressionMethod === compression.magic) { 996 result.compressedContent = file._data.getCompressedContent(); 997 } 998 else { 999 content = file._data.getContent(); 1000 // need to decompress / recompress 1001 result.compressedContent = compression.compress(utils.transformTo(compression.compressInputType, content), compressionOptions); 1002 } 1003 } 1004 else { 1005 // have uncompressed data 1006 content = getBinaryData(file); 1007 if (!content || content.length === 0 || file.dir) { 1008 compression = compressions['STORE']; 1009 content = ""; 1010 } 1011 result.uncompressedSize = content.length; 1012 result.crc32 = crc32(content); 1013 result.compressedContent = compression.compress(utils.transformTo(compression.compressInputType, content), compressionOptions); 1014 } 1015 1016 result.compressedSize = result.compressedContent.length; 1017 result.compressionMethod = compression.magic; 1018 1019 return result; 1020}; 1021 1022 1023 1024 1025/** 1026 * Generate the UNIX part of the external file attributes. 1027 * @param {Object} unixPermissions the unix permissions or null. 1028 * @param {Boolean} isDir true if the entry is a directory, false otherwise. 1029 * @return {Number} a 32 bit integer. 1030 * 1031 * adapted from http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute : 1032 * 1033 * TTTTsstrwxrwxrwx0000000000ADVSHR 1034 * ^^^^____________________________ file type, see zipinfo.c (UNX_*) 1035 * ^^^_________________________ setuid, setgid, sticky 1036 * ^^^^^^^^^________________ permissions 1037 * ^^^^^^^^^^______ not used ? 1038 * ^^^^^^ DOS attribute bits : Archive, Directory, Volume label, System file, Hidden, Read only 1039 */ 1040var generateUnixExternalFileAttr = function (unixPermissions, isDir) { 1041 1042 var result = unixPermissions; 1043 if (!unixPermissions) { 1044 // I can't use octal values in strict mode, hence the hexa. 1045 // 040775 => 0x41fd 1046 // 0100664 => 0x81b4 1047 result = isDir ? 0x41fd : 0x81b4; 1048 } 1049 1050 return (result & 0xFFFF) << 16; 1051}; 1052 1053/** 1054 * Generate the DOS part of the external file attributes. 1055 * @param {Object} dosPermissions the dos permissions or null. 1056 * @param {Boolean} isDir true if the entry is a directory, false otherwise. 1057 * @return {Number} a 32 bit integer. 1058 * 1059 * Bit 0 Read-Only 1060 * Bit 1 Hidden 1061 * Bit 2 System 1062 * Bit 3 Volume Label 1063 * Bit 4 Directory 1064 * Bit 5 Archive 1065 */ 1066var generateDosExternalFileAttr = function (dosPermissions, isDir) { 1067 1068 // the dir flag is already set for compatibility 1069 1070 return (dosPermissions || 0) & 0x3F; 1071}; 1072 1073/** 1074 * Generate the various parts used in the construction of the final zip file. 1075 * @param {string} name the file name. 1076 * @param {ZipObject} file the file content. 1077 * @param {JSZip.CompressedObject} compressedObject the compressed object. 1078 * @param {number} offset the current offset from the start of the zip file. 1079 * @param {String} platform let's pretend we are this platform (change platform dependents fields) 1080 * @return {object} the zip parts. 1081 */ 1082var generateZipParts = function(name, file, compressedObject, offset, platform) { 1083 var data = compressedObject.compressedContent, 1084 utfEncodedFileName = utils.transformTo("string", utf8.utf8encode(file.name)), 1085 comment = file.comment || "", 1086 utfEncodedComment = utils.transformTo("string", utf8.utf8encode(comment)), 1087 useUTF8ForFileName = utfEncodedFileName.length !== file.name.length, 1088 useUTF8ForComment = utfEncodedComment.length !== comment.length, 1089 o = file.options, 1090 dosTime, 1091 dosDate, 1092 extraFields = "", 1093 unicodePathExtraField = "", 1094 unicodeCommentExtraField = "", 1095 dir, date; 1096 1097 1098 // handle the deprecated options.dir 1099 if (file._initialMetadata.dir !== file.dir) { 1100 dir = file.dir; 1101 } else { 1102 dir = o.dir; 1103 } 1104 1105 // handle the deprecated options.date 1106 if(file._initialMetadata.date !== file.date) { 1107 date = file.date; 1108 } else { 1109 date = o.date; 1110 } 1111 1112 var extFileAttr = 0; 1113 var versionMadeBy = 0; 1114 if (dir) { 1115 // dos or unix, we set the dos dir flag 1116 extFileAttr |= 0x00010; 1117 } 1118 if(platform === "UNIX") { 1119 versionMadeBy = 0x031E; // UNIX, version 3.0 1120 extFileAttr |= generateUnixExternalFileAttr(file.unixPermissions, dir); 1121 } else { // DOS or other, fallback to DOS 1122 versionMadeBy = 0x0014; // DOS, version 2.0 1123 extFileAttr |= generateDosExternalFileAttr(file.dosPermissions, dir); 1124 } 1125 1126 // date 1127 // @see http://www.delorie.com/djgpp/doc/rbinter/it/52/13.html 1128 // @see http://www.delorie.com/djgpp/doc/rbinter/it/65/16.html 1129 // @see http://www.delorie.com/djgpp/doc/rbinter/it/66/16.html 1130 1131 dosTime = date.getHours(); 1132 dosTime = dosTime << 6; 1133 dosTime = dosTime | date.getMinutes(); 1134 dosTime = dosTime << 5; 1135 dosTime = dosTime | date.getSeconds() / 2; 1136 1137 dosDate = date.getFullYear() - 1980; 1138 dosDate = dosDate << 4; 1139 dosDate = dosDate | (date.getMonth() + 1); 1140 dosDate = dosDate << 5; 1141 dosDate = dosDate | date.getDate(); 1142 1143 if (useUTF8ForFileName) { 1144 // set the unicode path extra field. unzip needs at least one extra 1145 // field to correctly handle unicode path, so using the path is as good 1146 // as any other information. This could improve the situation with 1147 // other archive managers too. 1148 // This field is usually used without the utf8 flag, with a non 1149 // unicode path in the header (winrar, winzip). This helps (a bit) 1150 // with the messy Windows' default compressed folders feature but 1151 // breaks on p7zip which doesn't seek the unicode path extra field. 1152 // So for now, UTF-8 everywhere ! 1153 unicodePathExtraField = 1154 // Version 1155 decToHex(1, 1) + 1156 // NameCRC32 1157 decToHex(crc32(utfEncodedFileName), 4) + 1158 // UnicodeName 1159 utfEncodedFileName; 1160 1161 extraFields += 1162 // Info-ZIP Unicode Path Extra Field 1163 "\x75\x70" + 1164 // size 1165 decToHex(unicodePathExtraField.length, 2) + 1166 // content 1167 unicodePathExtraField; 1168 } 1169 1170 if(useUTF8ForComment) { 1171 1172 unicodeCommentExtraField = 1173 // Version 1174 decToHex(1, 1) + 1175 // CommentCRC32 1176 decToHex(this.crc32(utfEncodedComment), 4) + 1177 // UnicodeName 1178 utfEncodedComment; 1179 1180 extraFields += 1181 // Info-ZIP Unicode Path Extra Field 1182 "\x75\x63" + 1183 // size 1184 decToHex(unicodeCommentExtraField.length, 2) + 1185 // content 1186 unicodeCommentExtraField; 1187 } 1188 1189 var header = ""; 1190 1191 // version needed to extract 1192 header += "\x0A\x00"; 1193 // general purpose bit flag 1194 // set bit 11 if utf8 1195 header += (useUTF8ForFileName || useUTF8ForComment) ? "\x00\x08" : "\x00\x00"; 1196 // compression method 1197 header += compressedObject.compressionMethod; 1198 // last mod file time 1199 header += decToHex(dosTime, 2); 1200 // last mod file date 1201 header += decToHex(dosDate, 2); 1202 // crc-32 1203 header += decToHex(compressedObject.crc32, 4); 1204 // compressed size 1205 header += decToHex(compressedObject.compressedSize, 4); 1206 // uncompressed size 1207 header += decToHex(compressedObject.uncompressedSize, 4); 1208 // file name length 1209 header += decToHex(utfEncodedFileName.length, 2); 1210 // extra field length 1211 header += decToHex(extraFields.length, 2); 1212 1213 1214 var fileRecord = signature.LOCAL_FILE_HEADER + header + utfEncodedFileName + extraFields; 1215 1216 var dirRecord = signature.CENTRAL_FILE_HEADER + 1217 // version made by (00: DOS) 1218 decToHex(versionMadeBy, 2) + 1219 // file header (common to file and central directory) 1220 header + 1221 // file comment length 1222 decToHex(utfEncodedComment.length, 2) + 1223 // disk number start 1224 "\x00\x00" + 1225 // internal file attributes TODO 1226 "\x00\x00" + 1227 // external file attributes 1228 decToHex(extFileAttr, 4) + 1229 // relative offset of local header 1230 decToHex(offset, 4) + 1231 // file name 1232 utfEncodedFileName + 1233 // extra field 1234 extraFields + 1235 // file comment 1236 utfEncodedComment; 1237 1238 return { 1239 fileRecord: fileRecord, 1240 dirRecord: dirRecord, 1241 compressedObject: compressedObject 1242 }; 1243}; 1244 1245 1246// return the actual prototype of JSZip 1247var out = { 1248 /** 1249 * Read an existing zip and merge the data in the current JSZip object. 1250 * The implementation is in jszip-load.js, don't forget to include it. 1251 * @param {String|ArrayBuffer|Uint8Array|Buffer} stream The stream to load 1252 * @param {Object} options Options for loading the stream. 1253 * options.base64 : is the stream in base64 ? default : false 1254 * @return {JSZip} the current JSZip object 1255 */ 1256 load: function(stream, options) { 1257 throw new Error("Load method is not defined. Is the file jszip-load.js included ?"); 1258 }, 1259 1260 /** 1261 * Filter nested files/folders with the specified function. 1262 * @param {Function} search the predicate to use : 1263 * function (relativePath, file) {...} 1264 * It takes 2 arguments : the relative path and the file. 1265 * @return {Array} An array of matching elements. 1266 */ 1267 filter: function(search) { 1268 var result = [], 1269 filename, relativePath, file, fileClone; 1270 for (filename in this.files) { 1271 if (!this.files.hasOwnProperty(filename)) { 1272 continue; 1273 } 1274 file = this.files[filename]; 1275 // return a new object, don't let the user mess with our internal objects :) 1276 fileClone = new ZipObject(file.name, file._data, extend(file.options)); 1277 relativePath = filename.slice(this.root.length, filename.length); 1278 if (filename.slice(0, this.root.length) === this.root && // the file is in the current root 1279 search(relativePath, fileClone)) { // and the file matches the function 1280 result.push(fileClone); 1281 } 1282 } 1283 return result; 1284 }, 1285 1286 /** 1287 * Add a file to the zip file, or search a file. 1288 * @param {string|RegExp} name The name of the file to add (if data is defined), 1289 * the name of the file to find (if no data) or a regex to match files. 1290 * @param {String|ArrayBuffer|Uint8Array|Buffer} data The file data, either raw or base64 encoded 1291 * @param {Object} o File options 1292 * @return {JSZip|Object|Array} this JSZip object (when adding a file), 1293 * a file (when searching by string) or an array of files (when searching by regex). 1294 */ 1295 file: function(name, data, o) { 1296 if (arguments.length === 1) { 1297 if (utils.isRegExp(name)) { 1298 var regexp = name; 1299 return this.filter(function(relativePath, file) { 1300 return !file.dir && regexp.test(relativePath); 1301 }); 1302 } 1303 else { // text 1304 return this.filter(function(relativePath, file) { 1305 return !file.dir && relativePath === name; 1306 })[0] || null; 1307 } 1308 } 1309 else { // more than one argument : we have data ! 1310 name = this.root + name; 1311 fileAdd.call(this, name, data, o); 1312 } 1313 return this; 1314 }, 1315 1316 /** 1317 * Add a directory to the zip file, or search. 1318 * @param {String|RegExp} arg The name of the directory to add, or a regex to search folders. 1319 * @return {JSZip} an object with the new directory as the root, or an array containing matching folders. 1320 */ 1321 folder: function(arg) { 1322 if (!arg) { 1323 return this; 1324 } 1325 1326 if (utils.isRegExp(arg)) { 1327 return this.filter(function(relativePath, file) { 1328 return file.dir && arg.test(relativePath); 1329 }); 1330 } 1331 1332 // else, name is a new folder 1333 var name = this.root + arg; 1334 var newFolder = folderAdd.call(this, name); 1335 1336 // Allow chaining by returning a new object with this folder as the root 1337 var ret = this.clone(); 1338 ret.root = newFolder.name; 1339 return ret; 1340 }, 1341 1342 /** 1343 * Delete a file, or a directory and all sub-files, from the zip 1344 * @param {string} name the name of the file to delete 1345 * @return {JSZip} this JSZip object 1346 */ 1347 remove: function(name) { 1348 name = this.root + name; 1349 var file = this.files[name]; 1350 if (!file) { 1351 // Look for any folders 1352 if (name.slice(-1) != "/") { 1353 name += "/"; 1354 } 1355 file = this.files[name]; 1356 } 1357 1358 if (file && !file.dir) { 1359 // file 1360 delete this.files[name]; 1361 } else { 1362 // maybe a folder, delete recursively 1363 var kids = this.filter(function(relativePath, file) { 1364 return file.name.slice(0, name.length) === name; 1365 }); 1366 for (var i = 0; i < kids.length; i++) { 1367 delete this.files[kids[i].name]; 1368 } 1369 } 1370 1371 return this; 1372 }, 1373 1374 /** 1375 * Generate the complete zip file 1376 * @param {Object} options the options to generate the zip file : 1377 * - base64, (deprecated, use type instead) true to generate base64. 1378 * - compression, "STORE" by default. 1379 * - type, "base64" by default. Values are : string, base64, uint8array, arraybuffer, blob. 1380 * @return {String|Uint8Array|ArrayBuffer|Buffer|Blob} the zip file 1381 */ 1382 generate: function(options) { 1383 options = extend(options || {}, { 1384 base64: true, 1385 compression: "STORE", 1386 compressionOptions : null, 1387 type: "base64", 1388 platform: "DOS", 1389 comment: null, 1390 mimeType: 'application/zip' 1391 }); 1392 1393 utils.checkSupport(options.type); 1394 1395 // accept nodejs `process.platform` 1396 if( 1397 options.platform === 'darwin' || 1398 options.platform === 'freebsd' || 1399 options.platform === 'linux' || 1400 options.platform === 'sunos' 1401 ) { 1402 options.platform = "UNIX"; 1403 } 1404 if (options.platform === 'win32') { 1405 options.platform = "DOS"; 1406 } 1407 1408 var zipData = [], 1409 localDirLength = 0, 1410 centralDirLength = 0, 1411 writer, i, 1412 utfEncodedComment = utils.transformTo("string", this.utf8encode(options.comment || this.comment || "")); 1413 1414 // first, generate all the zip parts. 1415 for (var name in this.files) { 1416 if (!this.files.hasOwnProperty(name)) { 1417 continue; 1418 } 1419 var file = this.files[name]; 1420 1421 var compressionName = file.options.compression || options.compression.toUpperCase(); 1422 var compression = compressions[compressionName]; 1423 if (!compression) { 1424 throw new Error(compressionName + " is not a valid compression method !"); 1425 } 1426 var compressionOptions = file.options.compressionOptions || options.compressionOptions || {}; 1427 1428 var compressedObject = generateCompressedObjectFrom.call(this, file, compression, compressionOptions); 1429 1430 var zipPart = generateZipParts.call(this, name, file, compressedObject, localDirLength, options.platform); 1431 localDirLength += zipPart.fileRecord.length + compressedObject.compressedSize; 1432 centralDirLength += zipPart.dirRecord.length; 1433 zipData.push(zipPart); 1434 } 1435 1436 var dirEnd = ""; 1437 1438 // end of central dir signature 1439 dirEnd = signature.CENTRAL_DIRECTORY_END + 1440 // number of this disk 1441 "\x00\x00" + 1442 // number of the disk with the start of the central directory 1443 "\x00\x00" + 1444 // total number of entries in the central directory on this disk 1445 decToHex(zipData.length, 2) + 1446 // total number of entries in the central directory 1447 decToHex(zipData.length, 2) + 1448 // size of the central directory 4 bytes 1449 decToHex(centralDirLength, 4) + 1450 // offset of start of central directory with respect to the starting disk number 1451 decToHex(localDirLength, 4) + 1452 // .ZIP file comment length 1453 decToHex(utfEncodedComment.length, 2) + 1454 // .ZIP file comment 1455 utfEncodedComment; 1456 1457 1458 // we have all the parts (and the total length) 1459 // time to create a writer ! 1460 var typeName = options.type.toLowerCase(); 1461 if(typeName==="uint8array"||typeName==="arraybuffer"||typeName==="blob"||typeName==="nodebuffer") { 1462 writer = new Uint8ArrayWriter(localDirLength + centralDirLength + dirEnd.length); 1463 }else{ 1464 writer = new StringWriter(localDirLength + centralDirLength + dirEnd.length); 1465 } 1466 1467 for (i = 0; i < zipData.length; i++) { 1468 writer.append(zipData[i].fileRecord); 1469 writer.append(zipData[i].compressedObject.compressedContent); 1470 } 1471 for (i = 0; i < zipData.length; i++) { 1472 writer.append(zipData[i].dirRecord); 1473 } 1474 1475 writer.append(dirEnd); 1476 1477 var zip = writer.finalize(); 1478 1479 1480 1481 switch(options.type.toLowerCase()) { 1482 // case "zip is an Uint8Array" 1483 case "uint8array" : 1484 case "arraybuffer" : 1485 case "nodebuffer" : 1486 return utils.transformTo(options.type.toLowerCase(), zip); 1487 case "blob" : 1488 return utils.arrayBuffer2Blob(utils.transformTo("arraybuffer", zip), options.mimeType
vendor: 13,868 bytes, lines 1488-1954
1488); 1489 // case "zip is a string" 1490 case "base64" : 1491 return (options.base64) ? base64.encode(zip) : zip; 1492 default : // case "string" : 1493 return zip; 1494 } 1495 1496 }, 1497 1498 /** 1499 * @deprecated 1500 * This method will be removed in a future version without replacement. 1501 */ 1502 crc32: function (input, crc) { 1503 return crc32(input, crc); 1504 }, 1505 1506 /** 1507 * @deprecated 1508 * This method will be removed in a future version without replacement. 1509 */ 1510 utf8encode: function (string) { 1511 return utils.transformTo("string", utf8.utf8encode(string)); 1512 }, 1513 1514 /** 1515 * @deprecated 1516 * This method will be removed in a future version without replacement. 1517 */ 1518 utf8decode: function (input) { 1519 return utf8.utf8decode(input); 1520 } 1521}; 1522module.exports = out; 1523 1524},{"./base64":1,"./compressedObject":2,"./compressions":3,"./crc32":4,"./defaults":6,"./nodeBuffer":11,"./signature":14,"./stringWriter":16,"./support":17,"./uint8ArrayWriter":19,"./utf8":20,"./utils":21}],14:[function(_dereq_,module,exports){ 1525'use strict'; 1526exports.LOCAL_FILE_HEADER = "PK\x03\x04"; 1527exports.CENTRAL_FILE_HEADER = "PK\x01\x02"; 1528exports.CENTRAL_DIRECTORY_END = "PK\x05\x06"; 1529exports.ZIP64_CENTRAL_DIRECTORY_LOCATOR = "PK\x06\x07"; 1530exports.ZIP64_CENTRAL_DIRECTORY_END = "PK\x06\x06"; 1531exports.DATA_DESCRIPTOR = "PK\x07\x08"; 1532 1533},{}],15:[function(_dereq_,module,exports){ 1534'use strict'; 1535var DataReader = _dereq_('./dataReader'); 1536var utils = _dereq_('./utils'); 1537 1538function StringReader(data, optimizedBinaryString) { 1539 this.data = data; 1540 if (!optimizedBinaryString) { 1541 this.data = utils.string2binary(this.data); 1542 } 1543 this.length = this.data.length; 1544 this.index = 0; 1545} 1546StringReader.prototype = new DataReader(); 1547/** 1548 * @see DataReader.byteAt 1549 */ 1550StringReader.prototype.byteAt = function(i) { 1551 return this.data.charCodeAt(i); 1552}; 1553/** 1554 * @see DataReader.lastIndexOfSignature 1555 */ 1556StringReader.prototype.lastIndexOfSignature = function(sig) { 1557 return this.data.lastIndexOf(sig); 1558}; 1559/** 1560 * @see DataReader.readData 1561 */ 1562StringReader.prototype.readData = function(size) { 1563 this.checkOffset(size); 1564 // this will work because the constructor applied the "& 0xff" mask. 1565 var result = this.data.slice(this.index, this.index + size); 1566 this.index += size; 1567 return result; 1568}; 1569module.exports = StringReader; 1570 1571},{"./dataReader":5,"./utils":21}],16:[function(_dereq_,module,exports){ 1572'use strict'; 1573 1574var utils = _dereq_('./utils'); 1575 1576/** 1577 * An object to write any content to a string. 1578 * @constructor 1579 */ 1580var StringWriter = function() { 1581 this.data = []; 1582}; 1583StringWriter.prototype = { 1584 /** 1585 * Append any content to the current string. 1586 * @param {Object} input the content to add. 1587 */ 1588 append: function(input) { 1589 input = utils.transformTo("string", input); 1590 this.data.push(input); 1591 }, 1592 /** 1593 * Finalize the construction an return the result. 1594 * @return {string} the generated string. 1595 */ 1596 finalize: function() { 1597 return this.data.join(""); 1598 } 1599}; 1600 1601module.exports = StringWriter; 1602 1603},{"./utils":21}],17:[function(_dereq_,module,exports){ 1604(function (Buffer){ 1605'use strict'; 1606exports.base64 = true; 1607exports.array = true; 1608exports.string = true; 1609exports.arraybuffer = typeof ArrayBuffer !== "undefined" && typeof Uint8Array !== "undefined"; 1610// contains true if JSZip can read/generate nodejs Buffer, false otherwise. 1611// Browserify will provide a Buffer implementation for browsers, which is 1612// an augmented Uint8Array (i.e., can be used as either Buffer or U8). 1613exports.nodebuffer = typeof Buffer !== "undefined"; 1614// contains true if JSZip can read/generate Uint8Array, false otherwise. 1615exports.uint8array = typeof Uint8Array !== "undefined"; 1616 1617if (typeof ArrayBuffer === "undefined") { 1618 exports.blob = false; 1619} 1620else { 1621 var buffer = new ArrayBuffer(0); 1622 try { 1623 exports.blob = new Blob([buffer], { 1624 type: "application/zip" 1625 }).size === 0; 1626 } 1627 catch (e) { 1628 try { 1629 var Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; 1630 var builder = new Builder(); 1631 builder.append(buffer); 1632 exports.blob = builder.getBlob('application/zip').size === 0; 1633 } 1634 catch (e) { 1635 exports.blob = false; 1636 } 1637 } 1638} 1639 1640}).call(this,(typeof Buffer !== "undefined" ? Buffer : undefined)) 1641},{}],18:[function(_dereq_,module,exports){ 1642'use strict'; 1643var DataReader = _dereq_('./dataReader'); 1644 1645function Uint8ArrayReader(data) { 1646 if (data) { 1647 this.data = data; 1648 this.length = this.data.length; 1649 this.index = 0; 1650 } 1651} 1652Uint8ArrayReader.prototype = new DataReader(); 1653/** 1654 * @see DataReader.byteAt 1655 */ 1656Uint8ArrayReader.prototype.byteAt = function(i) { 1657 return this.data[i]; 1658}; 1659/** 1660 * @see DataReader.lastIndexOfSignature 1661 */ 1662Uint8ArrayReader.prototype.lastIndexOfSignature = function(sig) { 1663 var sig0 = sig.charCodeAt(0), 1664 sig1 = sig.charCodeAt(1), 1665 sig2 = sig.charCodeAt(2), 1666 sig3 = sig.charCodeAt(3); 1667 for (var i = this.length - 4; i >= 0; --i) { 1668 if (this.data[i] === sig0 && this.data[i + 1] === sig1 && this.data[i + 2] === sig2 && this.data[i + 3] === sig3) { 1669 return i; 1670 } 1671 } 1672 1673 return -1; 1674}; 1675/** 1676 * @see DataReader.readData 1677 */ 1678Uint8ArrayReader.prototype.readData = function(size) { 1679 this.checkOffset(size); 1680 if(size === 0) { 1681 // in IE10, when using subarray(idx, idx), we get the array [0x00] instead of []. 1682 return new Uint8Array(0); 1683 } 1684 var result = this.data.subarray(this.index, this.index + size); 1685 this.index += size; 1686 return result; 1687}; 1688module.exports = Uint8ArrayReader; 1689 1690},{"./dataReader":5}],19:[function(_dereq_,module,exports){ 1691'use strict'; 1692 1693var utils = _dereq_('./utils'); 1694 1695/** 1696 * An object to write any content to an Uint8Array. 1697 * @constructor 1698 * @param {number} length The length of the array. 1699 */ 1700var Uint8ArrayWriter = function(length) { 1701 this.data = new Uint8Array(length); 1702 this.index = 0; 1703}; 1704Uint8ArrayWriter.prototype = { 1705 /** 1706 * Append any content to the current array. 1707 * @param {Object} input the content to add. 1708 */ 1709 append: function(input) { 1710 if (input.length !== 0) { 1711 // with an empty Uint8Array, Opera fails with a "Offset larger than array size" 1712 input = utils.transformTo("uint8array", input); 1713 this.data.set(input, this.index); 1714 this.index += input.length; 1715 } 1716 }, 1717 /** 1718 * Finalize the construction an return the result. 1719 * @return {Uint8Array} the generated array. 1720 */ 1721 finalize: function() { 1722 return this.data; 1723 } 1724}; 1725 1726module.exports = Uint8ArrayWriter; 1727 1728},{"./utils":21}],20:[function(_dereq_,module,exports){ 1729'use strict'; 1730 1731var utils = _dereq_('./utils'); 1732var support = _dereq_('./support'); 1733var nodeBuffer = _dereq_('./nodeBuffer'); 1734 1735/** 1736 * The following functions come from pako, from pako/lib/utils/strings 1737 * released under the MIT license, see pako https://github.com/nodeca/pako/ 1738 */ 1739 1740// Table with utf8 lengths (calculated by first byte of sequence) 1741// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS, 1742// because max possible codepoint is 0x10ffff 1743var _utf8len = new Array(256); 1744for (var i=0; i<256; i++) { 1745 _utf8len[i] = (i >= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1); 1746} 1747_utf8len[254]=_utf8len[254]=1; // Invalid sequence start 1748 1749// convert string to array (typed, when possible) 1750var string2buf = function (str) { 1751 var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0; 1752 1753 // count binary size 1754 for (m_pos = 0; m_pos < str_len; m_pos++) { 1755 c = str.charCodeAt(m_pos); 1756 if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) { 1757 c2 = str.charCodeAt(m_pos+1); 1758 if ((c2 & 0xfc00) === 0xdc00) { 1759 c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); 1760 m_pos++; 1761 } 1762 } 1763 buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4; 1764 } 1765 1766 // allocate buffer 1767 if (support.uint8array) { 1768 buf = new Uint8Array(buf_len); 1769 } else { 1770 buf = new Array(buf_len); 1771 } 1772 1773 // convert 1774 for (i=0, m_pos = 0; i < buf_len; m_pos++) { 1775 c = str.charCodeAt(m_pos); 1776 if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) { 1777 c2 = str.charCodeAt(m_pos+1); 1778 if ((c2 & 0xfc00) === 0xdc00) { 1779 c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); 1780 m_pos++; 1781 } 1782 } 1783 if (c < 0x80) { 1784 /* one byte */ 1785 buf[i++] = c; 1786 } else if (c < 0x800) { 1787 /* two bytes */ 1788 buf[i++] = 0xC0 | (c >>> 6); 1789 buf[i++] = 0x80 | (c & 0x3f); 1790 } else if (c < 0x10000) { 1791 /* three bytes */ 1792 buf[i++] = 0xE0 | (c >>> 12); 1793 buf[i++] = 0x80 | (c >>> 6 & 0x3f); 1794 buf[i++] = 0x80 | (c & 0x3f); 1795 } else { 1796 /* four bytes */ 1797 buf[i++] = 0xf0 | (c >>> 18); 1798 buf[i++] = 0x80 | (c >>> 12 & 0x3f); 1799 buf[i++] = 0x80 | (c >>> 6 & 0x3f); 1800 buf[i++] = 0x80 | (c & 0x3f); 1801 } 1802 } 1803 1804 return buf; 1805}; 1806 1807// Calculate max possible position in utf8 buffer, 1808// that will not break sequence. If that's not possible 1809// - (very small limits) return max size as is. 1810// 1811// buf[] - utf8 bytes array 1812// max - length limit (mandatory); 1813var utf8border = function(buf, max) { 1814 var pos; 1815 1816 max = max || buf.length; 1817 if (max > buf.length) { max = buf.length; } 1818 1819 // go back from last position, until start of sequence found 1820 pos = max-1; 1821 while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; } 1822 1823 // Fuckup - very small and broken sequence, 1824 // return max, because we should return something anyway. 1825 if (pos < 0) { return max; } 1826 1827 // If we came to start of buffer - that means vuffer is too small, 1828 // return max too. 1829 if (pos === 0) { return max; } 1830 1831 return (pos + _utf8len[buf[pos]] > max) ? pos : max; 1832}; 1833 1834// convert array to string 1835var buf2string = function (buf) { 1836 var str, i, out, c, c_len; 1837 var len = buf.length; 1838 1839 // Reserve max possible length (2 words per char) 1840 // NB: by unknown reasons, Array is significantly faster for 1841 // String.fromCharCode.apply than Uint16Array. 1842 var utf16buf = new Array(len*2); 1843 1844 for (out=0, i=0; i<len;) { 1845 c = buf[i++]; 1846 // quick process ascii 1847 if (c < 0x80) { utf16buf[out++] = c; continue; } 1848 1849 c_len = _utf8len[c]; 1850 // skip 5 & 6 byte codes 1851 if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len-1; continue; } 1852 1853 // apply mask on first byte 1854 c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07; 1855 // join the rest 1856 while (c_len > 1 && i < len) { 1857 c = (c << 6) | (buf[i++] & 0x3f); 1858 c_len--; 1859 } 1860 1861 // terminated by end of string? 1862 if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; } 1863 1864 if (c < 0x10000) { 1865 utf16buf[out++] = c; 1866 } else { 1867 c -= 0x10000; 1868 utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff); 1869 utf16buf[out++] = 0xdc00 | (c & 0x3ff); 1870 } 1871 } 1872 1873 // shrinkBuf(utf16buf, out) 1874 if (utf16buf.length !== out) { 1875 if(utf16buf.subarray) { 1876 utf16buf = utf16buf.subarray(0, out); 1877 } else { 1878 utf16buf.length = out; 1879 } 1880 } 1881 1882 // return String.fromCharCode.apply(null, utf16buf); 1883 return utils.applyFromCharCode(utf16buf); 1884}; 1885 1886 1887// That's all for the pako functions. 1888 1889 1890/** 1891 * Transform a javascript string into an array (typed if possible) of bytes, 1892 * UTF-8 encoded. 1893 * @param {String} str the string to encode 1894 * @return {Array|Uint8Array|Buffer} the UTF-8 encoded string. 1895 */ 1896exports.utf8encode = function utf8encode(str) { 1897 if (support.nodebuffer) { 1898 return nodeBuffer(str, "utf-8"); 1899 } 1900 1901 return string2buf(str); 1902}; 1903 1904 1905/** 1906 * Transform a bytes array (or a representation) representing an UTF-8 encoded 1907 * string into a javascript string. 1908 * @param {Array|Uint8Array|Buffer} buf the data de decode 1909 * @return {String} the decoded string. 1910 */ 1911exports.utf8decode = function utf8decode(buf) { 1912 if (support.nodebuffer) { 1913 return utils.transformTo("nodebuffer", buf).toString("utf-8"); 1914 } 1915 1916 buf = utils.transformTo(support.uint8array ? "uint8array" : "array", buf); 1917 1918 // return buf2string(buf); 1919 // Chrome prefers to work with "small" chunks of data 1920 // for the method buf2string. 1921 // Firefox and Chrome has their own shortcut, IE doesn't seem to really care. 1922 var result = [], k = 0, len = buf.length, chunk = 65536; 1923 while (k < len) { 1924 var nextBoundary = utf8border(buf, Math.min(k + chunk, len)); 1925 if (support.uint8array) { 1926 result.push(buf2string(buf.subarray(k, nextBoundary))); 1927 } else { 1928 result.push(buf2string(buf.slice(k, nextBoundary))); 1929 } 1930 k = nextBoundary; 1931 } 1932 return result.join(""); 1933 1934}; 1935// vim: set shiftwidth=4 softtabstop=4: 1936 1937},{"./nodeBuffer":11,"./support":17,"./utils":21}],21:[function(_dereq_,module,exports){ 1938'use strict'; 1939var support = _dereq_('./support'); 1940var compressions = _dereq_('./compressions'); 1941var nodeBuffer = _dereq_('./nodeBuffer'); 1942/** 1943 * Convert a string to a "binary string" : a string containing only char codes between 0 and 255. 1944 * @param {string} str the string to transform. 1945 * @return {String} the binary string. 1946 */ 1947exports.string2binary = function(str) { 1948 var result = ""; 1949 for (var i = 0; i < str.length; i++) { 1950 result += String.fromCharCode(str.charCodeAt(i) & 0xff); 1951 } 1952 return result; 1953}; 1954exports.arrayBuffer2Blob = function(buffer
1954, mimeType) { 1955 exports.checkSupport("blob"); 1956 mimeType = mimeType || 'application/zip'; 1957 1958 try { 1959 // Blob constructor 1960 return new Blob([buffer], { 1961 type: mimeType 1962 }); 1963 } 1964 catch (e) { 1965 1966 try { 1967 // deprecated, browser only, old way 1968 var Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; 1969 var builder = new Builder(); 1970 builder.append(buffer); 1971 return builder.getBlob(mimeType
vendor: 13,328 bytes, lines 1971-2377
1971); 1972 } 1973 catch (e) { 1974 1975 // well, fuck ?! 1976 throw new Error("Bug : can't construct the Blob."); 1977 } 1978 } 1979 1980 1981}; 1982/** 1983 * The identity function. 1984 * @param {Object} input the input. 1985 * @return {Object} the same input. 1986 */ 1987function identity(input) { 1988 return input; 1989} 1990 1991/** 1992 * Fill in an array with a string. 1993 * @param {String} str the string to use. 1994 * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to fill in (will be mutated). 1995 * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated array. 1996 */ 1997function stringToArrayLike(str, array) { 1998 for (var i = 0; i < str.length; ++i) { 1999 array[i] = str.charCodeAt(i) & 0xFF; 2000 } 2001 return array; 2002} 2003 2004/** 2005 * Transform an array-like object to a string. 2006 * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to transform. 2007 * @return {String} the result. 2008 */ 2009function arrayLikeToString(array) { 2010 // Performances notes : 2011 // -------------------- 2012 // String.fromCharCode.apply(null, array) is the fastest, see 2013 // see http://jsperf.com/converting-a-uint8array-to-a-string/2 2014 // but the stack is limited (and we can get huge arrays !). 2015 // 2016 // result += String.fromCharCode(array[i]); generate too many strings ! 2017 // 2018 // This code is inspired by http://jsperf.com/arraybuffer-to-string-apply-performance/2 2019 var chunk = 65536; 2020 var result = [], 2021 len = array.length, 2022 type = exports.getTypeOf(array), 2023 k = 0, 2024 canUseApply = true; 2025 try { 2026 switch(type) { 2027 case "uint8array": 2028 String.fromCharCode.apply(null, new Uint8Array(0)); 2029 break; 2030 case "nodebuffer": 2031 String.fromCharCode.apply(null, nodeBuffer(0)); 2032 break; 2033 } 2034 } catch(e) { 2035 canUseApply = false; 2036 } 2037 2038 // no apply : slow and painful algorithm 2039 // default browser on android 4.* 2040 if (!canUseApply) { 2041 var resultStr = ""; 2042 for(var i = 0; i < array.length;i++) { 2043 resultStr += String.fromCharCode(array[i]); 2044 } 2045 return resultStr; 2046 } 2047 while (k < len && chunk > 1) { 2048 try { 2049 if (type === "array" || type === "nodebuffer") { 2050 result.push(String.fromCharCode.apply(null, array.slice(k, Math.min(k + chunk, len)))); 2051 } 2052 else { 2053 result.push(String.fromCharCode.apply(null, array.subarray(k, Math.min(k + chunk, len)))); 2054 } 2055 k += chunk; 2056 } 2057 catch (e) { 2058 chunk = Math.floor(chunk / 2); 2059 } 2060 } 2061 return result.join(""); 2062} 2063 2064exports.applyFromCharCode = arrayLikeToString; 2065 2066 2067/** 2068 * Copy the data from an array-like to an other array-like. 2069 * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayFrom the origin array. 2070 * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayTo the destination array which will be mutated. 2071 * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated destination array. 2072 */ 2073function arrayLikeToArrayLike(arrayFrom, arrayTo) { 2074 for (var i = 0; i < arrayFrom.length; i++) { 2075 arrayTo[i] = arrayFrom[i]; 2076 } 2077 return arrayTo; 2078} 2079 2080// a matrix containing functions to transform everything into everything. 2081var transform = {}; 2082 2083// string to ? 2084transform["string"] = { 2085 "string": identity, 2086 "array": function(input) { 2087 return stringToArrayLike(input, new Array(input.length)); 2088 }, 2089 "arraybuffer": function(input) { 2090 return transform["string"]["uint8array"](input).buffer; 2091 }, 2092 "uint8array": function(input) { 2093 return stringToArrayLike(input, new Uint8Array(input.length)); 2094 }, 2095 "nodebuffer": function(input) { 2096 return stringToArrayLike(input, nodeBuffer(input.length)); 2097 } 2098}; 2099 2100// array to ? 2101transform["array"] = { 2102 "string": arrayLikeToString, 2103 "array": identity, 2104 "arraybuffer": function(input) { 2105 return (new Uint8Array(input)).buffer; 2106 }, 2107 "uint8array": function(input) { 2108 return new Uint8Array(input); 2109 }, 2110 "nodebuffer": function(input) { 2111 return nodeBuffer(input); 2112 } 2113}; 2114 2115// arraybuffer to ? 2116transform["arraybuffer"] = { 2117 "string": function(input) { 2118 return arrayLikeToString(new Uint8Array(input)); 2119 }, 2120 "array": function(input) { 2121 return arrayLikeToArrayLike(new Uint8Array(input), new Array(input.byteLength)); 2122 }, 2123 "arraybuffer": identity, 2124 "uint8array": function(input) { 2125 return new Uint8Array(input); 2126 }, 2127 "nodebuffer": function(input) { 2128 return nodeBuffer(new Uint8Array(input)); 2129 } 2130}; 2131 2132// uint8array to ? 2133transform["uint8array"] = { 2134 "string": arrayLikeToString, 2135 "array": function(input) { 2136 return arrayLikeToArrayLike(input, new Array(input.length)); 2137 }, 2138 "arraybuffer": function(input) { 2139 return input.buffer; 2140 }, 2141 "uint8array": identity, 2142 "nodebuffer": function(input) { 2143 return nodeBuffer(input); 2144 } 2145}; 2146 2147// nodebuffer to ? 2148transform["nodebuffer"] = { 2149 "string": arrayLikeToString, 2150 "array": function(input) { 2151 return arrayLikeToArrayLike(input, new Array(input.length)); 2152 }, 2153 "arraybuffer": function(input) { 2154 return transform["nodebuffer"]["uint8array"](input).buffer; 2155 }, 2156 "uint8array": function(input) { 2157 return arrayLikeToArrayLike(input, new Uint8Array(input.length)); 2158 }, 2159 "nodebuffer": identity 2160}; 2161 2162/** 2163 * Transform an input into any type. 2164 * The supported output type are : string, array, uint8array, arraybuffer, nodebuffer. 2165 * If no output type is specified, the unmodified input will be returned. 2166 * @param {String} outputType the output type. 2167 * @param {String|Array|ArrayBuffer|Uint8Array|Buffer} input the input to convert. 2168 * @throws {Error} an Error if the browser doesn't support the requested output type. 2169 */ 2170exports.transformTo = function(outputType, input) { 2171 if (!input) { 2172 // undefined, null, etc 2173 // an empty string won't harm. 2174 input = ""; 2175 } 2176 if (!outputType) { 2177 return input; 2178 } 2179 exports.checkSupport(outputType); 2180 var inputType = exports.getTypeOf(input); 2181 var result = transform[inputType][outputType](input); 2182 return result; 2183}; 2184 2185/** 2186 * Return the type of the input. 2187 * The type will be in a format valid for JSZip.utils.transformTo : string, array, uint8array, arraybuffer. 2188 * @param {Object} input the input to identify. 2189 * @return {String} the (lowercase) type of the input. 2190 */ 2191exports.getTypeOf = function(input) { 2192 if (typeof input === "string") { 2193 return "string"; 2194 } 2195 if (Object.prototype.toString.call(input) === "[object Array]") { 2196 return "array"; 2197 } 2198 if (support.nodebuffer && nodeBuffer.test(input)) { 2199 return "nodebuffer"; 2200 } 2201 if (support.uint8array && input instanceof Uint8Array) { 2202 return "uint8array"; 2203 } 2204 if (support.arraybuffer && input instanceof ArrayBuffer) { 2205 return "arraybuffer"; 2206 } 2207}; 2208 2209/** 2210 * Throw an exception if the type is not supported. 2211 * @param {String} type the type to check. 2212 * @throws {Error} an Error if the browser doesn't support the requested type. 2213 */ 2214exports.checkSupport = function(type) { 2215 var supported = support[type.toLowerCase()]; 2216 if (!supported) { 2217 throw new Error(type + " is not supported by this browser"); 2218 } 2219}; 2220exports.MAX_VALUE_16BITS = 65535; 2221exports.MAX_VALUE_32BITS = -1; // well, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" is parsed as -1 2222 2223/** 2224 * Prettify a string read as binary. 2225 * @param {string} str the string to prettify. 2226 * @return {string} a pretty string. 2227 */ 2228exports.pretty = function(str) { 2229 var res = '', 2230 code, i; 2231 for (i = 0; i < (str || "").length; i++) { 2232 code = str.charCodeAt(i); 2233 res += '\\x' + (code < 16 ? "0" : "") + code.toString(16).toUpperCase(); 2234 } 2235 return res; 2236}; 2237 2238/** 2239 * Find a compression registered in JSZip. 2240 * @param {string} compressionMethod the method magic to find. 2241 * @return {Object|null} the JSZip compression object, null if none found. 2242 */ 2243exports.findCompression = function(compressionMethod) { 2244 for (var method in compressions) { 2245 if (!compressions.hasOwnProperty(method)) { 2246 continue; 2247 } 2248 if (compressions[method].magic === compressionMethod) { 2249 return compressions[method]; 2250 } 2251 } 2252 return null; 2253}; 2254/** 2255* Cross-window, cross-Node-context regular expression detection 2256* @param {Object} object Anything 2257* @return {Boolean} true if the object is a regular expression, 2258* false otherwise 2259*/ 2260exports.isRegExp = function (object) { 2261 return Object.prototype.toString.call(object) === "[object RegExp]"; 2262}; 2263 2264 2265},{"./compressions":3,"./nodeBuffer":11,"./support":17}],22:[function(_dereq_,module,exports){ 2266'use strict'; 2267var StringReader = _dereq_('./stringReader'); 2268var NodeBufferReader = _dereq_('./nodeBufferReader'); 2269var Uint8ArrayReader = _dereq_('./uint8ArrayReader'); 2270var utils = _dereq_('./utils'); 2271var sig = _dereq_('./signature'); 2272var ZipEntry = _dereq_('./zipEntry'); 2273var support = _dereq_('./support'); 2274var jszipProto = _dereq_('./object'); 2275// class ZipEntries {{{ 2276/** 2277 * All the entries in the zip file. 2278 * @constructor 2279 * @param {String|ArrayBuffer|Uint8Array} data the binary stream to load. 2280 * @param {Object} loadOptions Options for loading the stream. 2281 */ 2282function ZipEntries(data, loadOptions) { 2283 this.files = []; 2284 this.loadOptions = loadOptions; 2285 if (data) { 2286 this.load(data); 2287 } 2288} 2289ZipEntries.prototype = { 2290 /** 2291 * Check that the reader is on the speficied signature. 2292 * @param {string} expectedSignature the expected signature. 2293 * @throws {Error} if it is an other signature. 2294 */ 2295 checkSignature: function(expectedSignature) { 2296 var signature = this.reader.readString(4); 2297 if (signature !== expectedSignature) { 2298 throw new Error("Corrupted zip or bug : unexpected signature " + "(" + utils.pretty(signature) + ", expected " + utils.pretty(expectedSignature) + ")"); 2299 } 2300 }, 2301 /** 2302 * Read the end of the central directory. 2303 */ 2304 readBlockEndOfCentral: function() { 2305 this.diskNumber = this.reader.readInt(2); 2306 this.diskWithCentralDirStart = this.reader.readInt(2); 2307 this.centralDirRecordsOnThisDisk = this.reader.readInt(2); 2308 this.centralDirRecords = this.reader.readInt(2); 2309 this.centralDirSize = this.reader.readInt(4); 2310 this.centralDirOffset = this.reader.readInt(4); 2311 2312 this.zipCommentLength = this.reader.readInt(2); 2313 // warning : the encoding depends of the system locale 2314 // On a linux machine with LANG=en_US.utf8, this field is utf8 encoded. 2315 // On a windows machine, this field is encoded with the localized windows code page. 2316 this.zipComment = this.reader.readString(this.zipCommentLength); 2317 // To get consistent behavior with the generation part, we will assume that 2318 // this is utf8 encoded. 2319 this.zipComment = jszipProto.utf8decode(this.zipComment); 2320 }, 2321 /** 2322 * Read the end of the Zip 64 central directory. 2323 * Not merged with the method readEndOfCentral : 2324 * The end of central can coexist with its Zip64 brother, 2325 * I don't want to read the wrong number of bytes ! 2326 */ 2327 readBlockZip64EndOfCentral: function() { 2328 this.zip64EndOfCentralSize = this.reader.readInt(8); 2329 this.versionMadeBy = this.reader.readString(2); 2330 this.versionNeeded = this.reader.readInt(2); 2331 this.diskNumber = this.reader.readInt(4); 2332 this.diskWithCentralDirStart = this.reader.readInt(4); 2333 this.centralDirRecordsOnThisDisk = this.reader.readInt(8); 2334 this.centralDirRecords = this.reader.readInt(8); 2335 this.centralDirSize = this.reader.readInt(8); 2336 this.centralDirOffset = this.reader.readInt(8); 2337 2338 this.zip64ExtensibleData = {}; 2339 var extraDataSize = this.zip64EndOfCentralSize - 44, 2340 index = 0, 2341 extraFieldId, 2342 extraFieldLength, 2343 extraFieldValue; 2344 while (index < extraDataSize) { 2345 extraFieldId = this.reader.readInt(2); 2346 extraFieldLength = this.reader.readInt(4); 2347 extraFieldValue = this.reader.readString(extraFieldLength); 2348 this.zip64ExtensibleData[extraFieldId] = { 2349 id: extraFieldId, 2350 length: extraFieldLength, 2351 value: extraFieldValue 2352 }; 2353 } 2354 }, 2355 /** 2356 * Read the end of the Zip 64 central directory locator. 2357 */ 2358 readBlockZip64EndOfCentralLocator: function() { 2359 this.diskWithZip64CentralDirStart = this.reader.readInt(4); 2360 this.relativeOffsetEndOfZip64CentralDir = this.reader.readInt(8); 2361 this.disksCount = this.reader.readInt(4); 2362 if (this.disksCount > 1) { 2363 throw new Error("Multi-volumes zip are not supported"); 2364 } 2365 }, 2366 /** 2367 * Read the local files, based on the offset read in the central part. 2368 */ 2369 readLocalFiles: function() { 2370 var i, file; 2371 for (i = 0; i < this.files.length; i++) { 2372 file = this.files[i]; 2373 this.reader.setIndex(file.localHeaderOffset); 2374 this.checkSignature(sig.LOCAL_FILE_HEADER); 2375 file.readLocalPart(this.reader); 2376 file.handleUTF8(); 2377
2377 file.processAttributes(); 2378 } 2379 }, 2380 /** 2381 * Read the central directory. 2382 */ 2383 readCentralDir: function() { 2384 var file; 2385 2386 this.reader.setIndex(this.centralDirOffset); 2387 while (this.reader.readString(4) === sig.CENTRAL_FILE_HEADER) { 2388 file = new ZipEntry({ 2389 zip64: this.zip64 2390 }, this.loadOptions); 2391 file.readCentralPart(this.reader); 2392 this.files.push(file); 2393 } 2394 }, 2395 /** 2396 * Read the end of central directory. 2397 */ 2398 readEndOfCentral: function() { 2399 var offset = this.reader.lastIndexOfSignature(sig.CENTRAL_DIRECTORY_END); 2400 if (offset === -1) { 2401 // Check if the content is a truncated zip or complete garbage. 2402 // A "LOCAL_FILE_HEADER" is not required at the beginning (auto 2403 // extractible zip for example) but it can give a good hint. 2404 // If an ajax request was used without responseType, we will also 2405 // get unreadable data. 2406 var isGarbage = true; 2407 try { 2408 this.reader.setIndex(0); 2409 this.checkSignature(sig.LOCAL_FILE_HEADER); 2410 isGarbage = false;
vendor: 8,072 bytes, lines 2411-2587
2411 } catch (e) {} 2412 2413 if (isGarbage) { 2414 throw new Error("Can't find end of central directory : is this a zip file ? " + 2415 "If it is, see http://stuk.github.io/jszip/documentation/howto/read_zip.html"); 2416 } else { 2417 throw new Error("Corrupted zip : can't find end of central directory"); 2418 } 2419 } 2420 this.reader.setIndex(offset); 2421 this.checkSignature(sig.CENTRAL_DIRECTORY_END); 2422 this.readBlockEndOfCentral(); 2423 2424 2425 /* extract from the zip spec : 2426 4) If one of the fields in the end of central directory 2427 record is too small to hold required data, the field 2428 should be set to -1 (0xFFFF or 0xFFFFFFFF) and the 2429 ZIP64 format record should be created. 2430 5) The end of central directory record and the 2431 Zip64 end of central directory locator record must 2432 reside on the same disk when splitting or spanning 2433 an archive. 2434 */ 2435 if (this.diskNumber === utils.MAX_VALUE_16BITS || this.diskWithCentralDirStart === utils.MAX_VALUE_16BITS || this.centralDirRecordsOnThisDisk === utils.MAX_VALUE_16BITS || this.centralDirRecords === utils.MAX_VALUE_16BITS || this.centralDirSize === utils.MAX_VALUE_32BITS || this.centralDirOffset === utils.MAX_VALUE_32BITS) { 2436 this.zip64 = true; 2437 2438 /* 2439 Warning : the zip64 extension is supported, but ONLY if the 64bits integer read from 2440 the zip file can fit into a 32bits integer. This cannot be solved : Javascript represents 2441 all numbers as 64-bit double precision IEEE 754 floating point numbers. 2442 So, we have 53bits for integers and bitwise operations treat everything as 32bits. 2443 see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Bitwise_Operators 2444 and http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf section 8.5 2445 */ 2446 2447 // should look for a zip64 EOCD locator 2448 offset = this.reader.lastIndexOfSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR); 2449 if (offset === -1) { 2450 throw new Error("Corrupted zip : can't find the ZIP64 end of central directory locator"); 2451 } 2452 this.reader.setIndex(offset); 2453 this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR); 2454 this.readBlockZip64EndOfCentralLocator(); 2455 2456 // now the zip64 EOCD record 2457 this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir); 2458 this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_END); 2459 this.readBlockZip64EndOfCentral(); 2460 } 2461 }, 2462 prepareReader: function(data) { 2463 var type = utils.getTypeOf(data); 2464 if (type === "string" && !support.uint8array) { 2465 this.reader = new StringReader(data, this.loadOptions.optimizedBinaryString); 2466 } 2467 else if (type === "nodebuffer") { 2468 this.reader = new NodeBufferReader(data); 2469 } 2470 else { 2471 this.reader = new Uint8ArrayReader(utils.transformTo("uint8array", data)); 2472 } 2473 }, 2474 /** 2475 * Read a zip file and create ZipEntries. 2476 * @param {String|ArrayBuffer|Uint8Array|Buffer} data the binary string representing a zip file. 2477 */ 2478 load: function(data) { 2479 this.prepareReader(data); 2480 this.readEndOfCentral(); 2481 this.readCentralDir(); 2482 this.readLocalFiles(); 2483 } 2484}; 2485// }}} end of ZipEntries 2486module.exports = ZipEntries; 2487 2488},{"./nodeBufferReader":12,"./object":13,"./signature":14,"./stringReader":15,"./support":17,"./uint8ArrayReader":18,"./utils":21,"./zipEntry":23}],23:[function(_dereq_,module,exports){ 2489'use strict'; 2490var StringReader = _dereq_('./stringReader'); 2491var utils = _dereq_('./utils'); 2492var CompressedObject = _dereq_('./compressedObject'); 2493var jszipProto = _dereq_('./object'); 2494 2495var MADE_BY_DOS = 0x00; 2496var MADE_BY_UNIX = 0x03; 2497 2498// class ZipEntry {{{ 2499/** 2500 * An entry in the zip file. 2501 * @constructor 2502 * @param {Object} options Options of the current file. 2503 * @param {Object} loadOptions Options for loading the stream. 2504 */ 2505function ZipEntry(options, loadOptions) { 2506 this.options = options; 2507 this.loadOptions = loadOptions; 2508} 2509ZipEntry.prototype = { 2510 /** 2511 * say if the file is encrypted. 2512 * @return {boolean} true if the file is encrypted, false otherwise. 2513 */ 2514 isEncrypted: function() { 2515 // bit 1 is set 2516 return (this.bitFlag & 0x0001) === 0x0001; 2517 }, 2518 /** 2519 * say if the file has utf-8 filename/comment. 2520 * @return {boolean} true if the filename/comment is in utf-8, false otherwise. 2521 */ 2522 useUTF8: function() { 2523 // bit 11 is set 2524 return (this.bitFlag & 0x0800) === 0x0800; 2525 }, 2526 /** 2527 * Prepare the function used to generate the compressed content from this ZipFile. 2528 * @param {DataReader} reader the reader to use. 2529 * @param {number} from the offset from where we should read the data. 2530 * @param {number} length the length of the data to read. 2531 * @return {Function} the callback to get the compressed content (the type depends of the DataReader class). 2532 */ 2533 prepareCompressedContent: function(reader, from, length) { 2534 return function() { 2535 var previousIndex = reader.index; 2536 reader.setIndex(from); 2537 var compressedFileData = reader.readData(length); 2538 reader.setIndex(previousIndex); 2539 2540 return compressedFileData; 2541 }; 2542 }, 2543 /** 2544 * Prepare the function used to generate the uncompressed content from this ZipFile. 2545 * @param {DataReader} reader the reader to use. 2546 * @param {number} from the offset from where we should read the data. 2547 * @param {number} length the length of the data to read. 2548 * @param {JSZip.compression} compression the compression used on this file. 2549 * @param {number} uncompressedSize the uncompressed size to expect. 2550 * @return {Function} the callback to get the uncompressed content (the type depends of the DataReader class). 2551 */ 2552 prepareContent: function(reader, from, length, compression, uncompressedSize) { 2553 return function() { 2554 2555 var compressedFileData = utils.transformTo(compression.uncompressInputType, this.getCompressedContent()); 2556 var uncompressedFileData = compression.uncompress(compressedFileData); 2557 2558 if (uncompressedFileData.length !== uncompressedSize) { 2559 throw new Error("Bug : uncompressed data size mismatch"); 2560 } 2561 2562 return uncompressedFileData; 2563 }; 2564 }, 2565 /** 2566 * Read the local part of a zip file and add the info in this object. 2567 * @param {DataReader} reader the reader to use. 2568 */ 2569 readLocalPart: function(reader) { 2570 var compression, localExtraFieldsLength; 2571 2572 // we already know everything from the central dir ! 2573 // If the central dir data are false, we are doomed. 2574 // On the bright side, the local part is scary : zip64, data descriptors, both, etc. 2575 // The less data we get here, the more reliable this should be. 2576 // Let's skip the whole header and dash to the data ! 2577 reader.skip(22); 2578 // in some zip created on windows, the filename stored in the central dir contains \ instead of /. 2579 // Strangely, the filename here is OK. 2580 // I would love to treat these zip files as corrupted (see http://www.info-zip.org/FAQ.html#backslashes 2581 // or APPNOTE#4.4.17.1, "All slashes MUST be forward slashes '/'") but there are a lot of bad zip generators... 2582 // Search "unzip mismatching "local" filename continuing with "central" filename version" on 2583 // the internet. 2584 // 2585 // I think I see the logic here : the central directory is used to display 2586 // content and the local directory is used to extract the files. Mixing / and \ 2587 // may be used to display \ to windows users and use / when extracting the files.
vendor: 4,164 bytes, lines 2588-2677
2588 // Unfortunately, this lead also to some issues : http://seclists.org/fulldisclosure/2009/Sep/394 2589 this.fileNameLength = reader.readInt(2); 2590 localExtraFieldsLength = reader.readInt(2); // can't be sure this will be the same as the central dir 2591 this.fileName = reader.readString(this.fileNameLength); 2592 reader.skip(localExtraFieldsLength); 2593 2594 if (this.compressedSize == -1 || this.uncompressedSize == -1) { 2595 throw new Error("Bug or corrupted zip : didn't get enough informations from the central directory " + "(compressedSize == -1 || uncompressedSize == -1)"); 2596 } 2597 2598 compression = utils.findCompression(this.compressionMethod); 2599 if (compression === null) { // no compression found 2600 throw new Error("Corrupted zip : compression " + utils.pretty(this.compressionMethod) + " unknown (inner file : " + this.fileName + ")"); 2601 } 2602 this.decompressed = new CompressedObject(); 2603 this.decompressed.compressedSize = this.compressedSize; 2604 this.decompressed.uncompressedSize = this.uncompressedSize; 2605 this.decompressed.crc32 = this.crc32; 2606 this.decompressed.compressionMethod = this.compressionMethod; 2607 this.decompressed.getCompressedContent = this.prepareCompressedContent(reader, reader.index, this.compressedSize, compression); 2608 this.decompressed.getContent = this.prepareContent(reader, reader.index, this.compressedSize, compression, this.uncompressedSize); 2609 2610 // we need to compute the crc32... 2611 if (this.loadOptions.checkCRC32) { 2612 this.decompressed = utils.transformTo("string", this.decompressed.getContent()); 2613 if (jszipProto.crc32(this.decompressed) !== this.crc32) { 2614 throw new Error("Corrupted zip : CRC32 mismatch"); 2615 } 2616 } 2617 }, 2618 2619 /** 2620 * Read the central part of a zip file and add the info in this object. 2621 * @param {DataReader} reader the reader to use. 2622 */ 2623 readCentralPart: function(reader) { 2624 this.versionMadeBy = reader.readInt(2); 2625 this.versionNeeded = reader.readInt(2); 2626 this.bitFlag = reader.readInt(2); 2627 this.compressionMethod = reader.readString(2); 2628 this.date = reader.readDate(); 2629 this.crc32 = reader.readInt(4); 2630 this.compressedSize = reader.readInt(4); 2631 this.uncompressedSize = reader.readInt(4); 2632 this.fileNameLength = reader.readInt(2); 2633 this.extraFieldsLength = reader.readInt(2); 2634 this.fileCommentLength = reader.readInt(2); 2635 this.diskNumberStart = reader.readInt(2); 2636 this.internalFileAttributes = reader.readInt(2); 2637 this.externalFileAttributes = reader.readInt(4); 2638 this.localHeaderOffset = reader.readInt(4); 2639 2640 if (this.isEncrypted()) { 2641 throw new Error("Encrypted zip are not supported"); 2642 } 2643 2644 this.fileName = reader.readString(this.fileNameLength); 2645 this.readExtraFields(reader); 2646 this.parseZIP64ExtraField(reader); 2647 this.fileComment = reader.readString(this.fileCommentLength); 2648 }, 2649 2650 /** 2651 * Parse the external file attributes and get the unix/dos permissions. 2652 */ 2653 processAttributes: function () { 2654 this.unixPermissions = null; 2655 this.dosPermissions = null; 2656 var madeBy = this.versionMadeBy >> 8; 2657 2658 // Check if we have the DOS directory flag set. 2659 // We look for it in the DOS and UNIX permissions 2660 // but some unknown platform could set it as a compatibility flag. 2661 this.dir = this.externalFileAttributes & 0x0010 ? true : false; 2662 2663 if(madeBy === MADE_BY_DOS) { 2664 // first 6 bits (0 to 5) 2665 this.dosPermissions = this.externalFileAttributes & 0x3F; 2666 } 2667 2668 if(madeBy === MADE_BY_UNIX) { 2669 this.unixPermissions = (this.externalFileAttributes >> 16) & 0xFFFF; 2670 // the octal permissions are in (this.unixPermissions & 0x01FF).toString(8); 2671 } 2672 2673 // fail safe : if the name ends with a / it probably means a folder 2674 if (!this.dir && this.fileName.slice(-1) === '/') { 2675 this.dir = true; 2676 } 2677 },
vendor: 77,279 bytes, lines 2678-5176
2678 2679 /** 2680 * Parse the ZIP64 extra field and merge the info in the current ZipEntry. 2681 * @param {DataReader} reader the reader to use. 2682 */ 2683 parseZIP64ExtraField: function(reader) { 2684 2685 if (!this.extraFields[0x0001]) { 2686 return; 2687 } 2688 2689 // should be something, preparing the extra reader 2690 var extraReader = new StringReader(this.extraFields[0x0001].value); 2691 2692 // I really hope that these 64bits integer can fit in 32 bits integer, because js 2693 // won't let us have more. 2694 if (this.uncompressedSize === utils.MAX_VALUE_32BITS) { 2695 this.uncompressedSize = extraReader.readInt(8); 2696 } 2697 if (this.compressedSize === utils.MAX_VALUE_32BITS) { 2698 this.compressedSize = extraReader.readInt(8); 2699 } 2700 if (this.localHeaderOffset === utils.MAX_VALUE_32BITS) { 2701 this.localHeaderOffset = extraReader.readInt(8); 2702 } 2703 if (this.diskNumberStart === utils.MAX_VALUE_32BITS) { 2704 this.diskNumberStart = extraReader.readInt(4); 2705 } 2706 }, 2707 /** 2708 * Read the central part of a zip file and add the info in this object. 2709 * @param {DataReader} reader the reader to use. 2710 */ 2711 readExtraFields: function(reader) { 2712 var start = reader.index, 2713 extraFieldId, 2714 extraFieldLength, 2715 extraFieldValue; 2716 2717 this.extraFields = this.extraFields || {}; 2718 2719 while (reader.index < start + this.extraFieldsLength) { 2720 extraFieldId = reader.readInt(2); 2721 extraFieldLength = reader.readInt(2); 2722 extraFieldValue = reader.readString(extraFieldLength); 2723 2724 this.extraFields[extraFieldId] = { 2725 id: extraFieldId, 2726 length: extraFieldLength, 2727 value: extraFieldValue 2728 }; 2729 } 2730 }, 2731 /** 2732 * Apply an UTF8 transformation if needed. 2733 */ 2734 handleUTF8: function() { 2735 if (this.useUTF8()) { 2736 this.fileName = jszipProto.utf8decode(this.fileName); 2737 this.fileComment = jszipProto.utf8decode(this.fileComment); 2738 } else { 2739 var upath = this.findExtraFieldUnicodePath(); 2740 if (upath !== null) { 2741 this.fileName = upath; 2742 } 2743 var ucomment = this.findExtraFieldUnicodeComment(); 2744 if (ucomment !== null) { 2745 this.fileComment = ucomment; 2746 } 2747 } 2748 }, 2749 2750 /** 2751 * Find the unicode path declared in the extra field, if any. 2752 * @return {String} the unicode path, null otherwise. 2753 */ 2754 findExtraFieldUnicodePath: function() { 2755 var upathField = this.extraFields[0x7075]; 2756 if (upathField) { 2757 var extraReader = new StringReader(upathField.value); 2758 2759 // wrong version 2760 if (extraReader.readInt(1) !== 1) { 2761 return null; 2762 } 2763 2764 // the crc of the filename changed, this field is out of date. 2765 if (jszipProto.crc32(this.fileName) !== extraReader.readInt(4)) { 2766 return null; 2767 } 2768 2769 return jszipProto.utf8decode(extraReader.readString(upathField.length - 5)); 2770 } 2771 return null; 2772 }, 2773 2774 /** 2775 * Find the unicode comment declared in the extra field, if any. 2776 * @return {String} the unicode comment, null otherwise. 2777 */ 2778 findExtraFieldUnicodeComment: function() { 2779 var ucommentField = this.extraFields[0x6375]; 2780 if (ucommentField) { 2781 var extraReader = new StringReader(ucommentField.value); 2782 2783 // wrong version 2784 if (extraReader.readInt(1) !== 1) { 2785 return null; 2786 } 2787 2788 // the crc of the comment changed, this field is out of date. 2789 if (jszipProto.crc32(this.fileComment) !== extraReader.readInt(4)) { 2790 return null; 2791 } 2792 2793 return jszipProto.utf8decode(extraReader.readString(ucommentField.length - 5)); 2794 } 2795 return null; 2796 } 2797}; 2798module.exports = ZipEntry; 2799 2800},{"./compressedObject":2,"./object":13,"./stringReader":15,"./utils":21}],24:[function(_dereq_,module,exports){ 2801// Top level file is just a mixin of submodules & constants 2802'use strict'; 2803 2804var assign = _dereq_('./lib/utils/common').assign; 2805 2806var deflate = _dereq_('./lib/deflate'); 2807var inflate = _dereq_('./lib/inflate'); 2808var constants = _dereq_('./lib/zlib/constants'); 2809 2810var pako = {}; 2811 2812assign(pako, deflate, inflate, constants); 2813 2814module.exports = pako; 2815},{"./lib/deflate":25,"./lib/inflate":26,"./lib/utils/common":27,"./lib/zlib/constants":30}],25:[function(_dereq_,module,exports){ 2816'use strict'; 2817 2818 2819var zlib_deflate = _dereq_('./zlib/deflate.js'); 2820var utils = _dereq_('./utils/common'); 2821var strings = _dereq_('./utils/strings'); 2822var msg = _dereq_('./zlib/messages'); 2823var zstream = _dereq_('./zlib/zstream'); 2824 2825 2826/* Public constants ==========================================================*/ 2827/* ===========================================================================*/ 2828 2829var Z_NO_FLUSH = 0; 2830var Z_FINISH = 4; 2831 2832var Z_OK = 0; 2833var Z_STREAM_END = 1; 2834 2835var Z_DEFAULT_COMPRESSION = -1; 2836 2837var Z_DEFAULT_STRATEGY = 0; 2838 2839var Z_DEFLATED = 8; 2840 2841/* ===========================================================================*/ 2842 2843 2844/** 2845 * class Deflate 2846 * 2847 * Generic JS-style wrapper for zlib calls. If you don't need 2848 * streaming behaviour - use more simple functions: [[deflate]], 2849 * [[deflateRaw]] and [[gzip]]. 2850 **/ 2851 2852/* internal 2853 * Deflate.chunks -> Array 2854 * 2855 * Chunks of output data, if [[Deflate#onData]] not overriden. 2856 **/ 2857 2858/** 2859 * Deflate.result -> Uint8Array|Array 2860 * 2861 * Compressed result, generated by default [[Deflate#onData]] 2862 * and [[Deflate#onEnd]] handlers. Filled after you push last chunk 2863 * (call [[Deflate#push]] with `Z_FINISH` / `true` param). 2864 **/ 2865 2866/** 2867 * Deflate.err -> Number 2868 * 2869 * Error code after deflate finished. 0 (Z_OK) on success. 2870 * You will not need it in real life, because deflate errors 2871 * are possible only on wrong options or bad `onData` / `onEnd` 2872 * custom handlers. 2873 **/ 2874 2875/** 2876 * Deflate.msg -> String 2877 * 2878 * Error message, if [[Deflate.err]] != 0 2879 **/ 2880 2881 2882/** 2883 * new Deflate(options) 2884 * - options (Object): zlib deflate options. 2885 * 2886 * Creates new deflator instance with specified params. Throws exception 2887 * on bad params. Supported options: 2888 * 2889 * - `level` 2890 * - `windowBits` 2891 * - `memLevel` 2892 * - `strategy` 2893 * 2894 * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) 2895 * for more information on these. 2896 * 2897 * Additional options, for internal needs: 2898 * 2899 * - `chunkSize` - size of generated data chunks (16K by default) 2900 * - `raw` (Boolean) - do raw deflate 2901 * - `gzip` (Boolean) - create gzip wrapper 2902 * - `to` (String) - if equal to 'string', then result will be "binary string" 2903 * (each char code [0..255]) 2904 * - `header` (Object) - custom header for gzip 2905 * - `text` (Boolean) - true if compressed data believed to be text 2906 * - `time` (Number) - modification time, unix timestamp 2907 * - `os` (Number) - operation system code 2908 * - `extra` (Array) - array of bytes with extra data (max 65536) 2909 * - `name` (String) - file name (binary string) 2910 * - `comment` (String) - comment (binary string) 2911 * - `hcrc` (Boolean) - true if header crc should be added 2912 * 2913 * ##### Example: 2914 * 2915 * ```javascript 2916 * var pako = require('pako') 2917 * , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9]) 2918 * , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]); 2919 * 2920 * var deflate = new pako.Deflate({ level: 3}); 2921 * 2922 * deflate.push(chunk1, false); 2923 * deflate.push(chunk2, true); // true -> last chunk 2924 * 2925 * if (deflate.err) { throw new Error(deflate.err); } 2926 * 2927 * console.log(deflate.result); 2928 * ``` 2929 **/ 2930var Deflate = function(options) { 2931 2932 this.options = utils.assign({ 2933 level: Z_DEFAULT_COMPRESSION, 2934 method: Z_DEFLATED, 2935 chunkSize: 16384, 2936 windowBits: 15, 2937 memLevel: 8, 2938 strategy: Z_DEFAULT_STRATEGY, 2939 to: '' 2940 }, options || {}); 2941 2942 var opt = this.options; 2943 2944 if (opt.raw && (opt.windowBits > 0)) { 2945 opt.windowBits = -opt.windowBits; 2946 } 2947 2948 else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) { 2949 opt.windowBits += 16; 2950 } 2951 2952 this.err = 0; // error code, if happens (0 = Z_OK) 2953 this.msg = ''; // error message 2954 this.ended = false; // used to avoid multiple onEnd() calls 2955 this.chunks = []; // chunks of compressed data 2956 2957 this.strm = new zstream(); 2958 this.strm.avail_out = 0; 2959 2960 var status = zlib_deflate.deflateInit2( 2961 this.strm, 2962 opt.level, 2963 opt.method, 2964 opt.windowBits, 2965 opt.memLevel, 2966 opt.strategy 2967 ); 2968 2969 if (status !== Z_OK) { 2970 throw new Error(msg[status]); 2971 } 2972 2973 if (opt.header) { 2974 zlib_deflate.deflateSetHeader(this.strm, opt.header); 2975 } 2976}; 2977 2978/** 2979 * Deflate#push(data[, mode]) -> Boolean 2980 * - data (Uint8Array|Array|String): input data. Strings will be converted to 2981 * utf8 byte sequence. 2982 * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes. 2983 * See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH. 2984 * 2985 * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with 2986 * new compressed chunks. Returns `true` on success. The last data block must have 2987 * mode Z_FINISH (or `true`). That flush internal pending buffers and call 2988 * [[Deflate#onEnd]]. 2989 * 2990 * On fail call [[Deflate#onEnd]] with error code and return false. 2991 * 2992 * We strongly recommend to use `Uint8Array` on input for best speed (output 2993 * array format is detected automatically). Also, don't skip last param and always 2994 * use the same type in your code (boolean or number). That will improve JS speed. 2995 * 2996 * For regular `Array`-s make sure all elements are [0..255]. 2997 * 2998 * ##### Example 2999 * 3000 * ```javascript 3001 * push(chunk, false); // push one of data chunks 3002 * ... 3003 * push(chunk, true); // push last chunk 3004 * ``` 3005 **/ 3006Deflate.prototype.push = function(data, mode) { 3007 var strm = this.strm; 3008 var chunkSize = this.options.chunkSize; 3009 var status, _mode; 3010 3011 if (this.ended) { return false; } 3012 3013 _mode = (mode === ~~mode) ? mode : ((mode === true) ? Z_FINISH : Z_NO_FLUSH); 3014 3015 // Convert data if needed 3016 if (typeof data === 'string') { 3017 // If we need to compress text, change encoding to utf8. 3018 strm.input = strings.string2buf(data); 3019 } else { 3020 strm.input = data; 3021 } 3022 3023 strm.next_in = 0; 3024 strm.avail_in = strm.input.length; 3025 3026 do { 3027 if (strm.avail_out === 0) { 3028 strm.output = new utils.Buf8(chunkSize); 3029 strm.next_out = 0; 3030 strm.avail_out = chunkSize; 3031 } 3032 status = zlib_deflate.deflate(strm, _mode); /* no bad return value */ 3033 3034 if (status !== Z_STREAM_END && status !== Z_OK) { 3035 this.onEnd(status); 3036 this.ended = true; 3037 return false; 3038 } 3039 if (strm.avail_out === 0 || (strm.avail_in === 0 && _mode === Z_FINISH)) { 3040 if (this.options.to === 'string') { 3041 this.onData(strings.buf2binstring(utils.shrinkBuf(strm.output, strm.next_out))); 3042 } else { 3043 this.onData(utils.shrinkBuf(strm.output, strm.next_out)); 3044 } 3045 } 3046 } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== Z_STREAM_END); 3047 3048 // Finalize on the last chunk. 3049 if (_mode === Z_FINISH) { 3050 status = zlib_deflate.deflateEnd(this.strm); 3051 this.onEnd(status); 3052 this.ended = true; 3053 return status === Z_OK; 3054 } 3055 3056 return true; 3057}; 3058 3059 3060/** 3061 * Deflate#onData(chunk) -> Void 3062 * - chunk (Uint8Array|Array|String): ouput data. Type of array depends 3063 * on js engine support. When string output requested, each chunk 3064 * will be string. 3065 * 3066 * By default, stores data blocks in `chunks[]` property and glue 3067 * those in `onEnd`. Override this handler, if you need another behaviour. 3068 **/ 3069Deflate.prototype.onData = function(chunk) { 3070 this.chunks.push(chunk); 3071}; 3072 3073 3074/** 3075 * Deflate#onEnd(status) -> Void 3076 * - status (Number): deflate status. 0 (Z_OK) on success, 3077 * other if not. 3078 * 3079 * Called once after you tell deflate that input stream complete 3080 * or error happenned. By default - join collected chunks, 3081 * free memory and fill `results` / `err` properties. 3082 **/ 3083Deflate.prototype.onEnd = function(status) { 3084 // On success - join 3085 if (status === Z_OK) { 3086 if (this.options.to === 'string') { 3087 this.result = this.chunks.join(''); 3088 } else { 3089 this.result = utils.flattenChunks(this.chunks); 3090 } 3091 } 3092 this.chunks = []; 3093 this.err = status; 3094 this.msg = this.strm.msg; 3095}; 3096 3097 3098/** 3099 * deflate(data[, options]) -> Uint8Array|Array|String 3100 * - data (Uint8Array|Array|String): input data to compress. 3101 * - options (Object): zlib deflate options. 3102 * 3103 * Compress `data` with deflate alrorythm and `options`. 3104 * 3105 * Supported options are: 3106 * 3107 * - level 3108 * - windowBits 3109 * - memLevel 3110 * - strategy 3111 * 3112 * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) 3113 * for more information on these. 3114 * 3115 * Sugar (options): 3116 * 3117 * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify 3118 * negative windowBits implicitly. 3119 * - `to` (String) - if equal to 'string', then result will be "binary string" 3120 * (each char code [0..255]) 3121 * 3122 * ##### Example: 3123 * 3124 * ```javascript 3125 * var pako = require('pako') 3126 * , data = Uint8Array([1,2,3,4,5,6,7,8,9]); 3127 * 3128 * console.log(pako.deflate(data)); 3129 * ``` 3130 **/ 3131function deflate(input, options) { 3132 var deflator = new Deflate(options); 3133 3134 deflator.push(input, true); 3135 3136 // That will never happens, if you don't cheat with options :) 3137 if (deflator.err) { throw deflator.msg; } 3138 3139 return deflator.result; 3140} 3141 3142 3143/** 3144 * deflateRaw(data[, options]) -> Uint8Array|Array|String 3145 * - data (Uint8Array|Array|String): input data to compress. 3146 * - options (Object): zlib deflate options. 3147 * 3148 * The same as [[deflate]], but creates raw data, without wrapper 3149 * (header and adler32 crc). 3150 **/ 3151function deflateRaw(input, options) { 3152 options = options || {}; 3153 options.raw = true; 3154 return deflate(input, options); 3155} 3156 3157 3158/** 3159 * gzip(data[, options]) -> Uint8Array|Array|String 3160 * - data (Uint8Array|Array|String): input data to compress. 3161 * - options (Object): zlib deflate options. 3162 * 3163 * The same as [[deflate]], but create gzip wrapper instead of 3164 * deflate one. 3165 **/ 3166function gzip(input, options) { 3167 options = options || {}; 3168 options.gzip = true; 3169 return deflate(input, options); 3170} 3171 3172 3173exports.Deflate = Deflate; 3174exports.deflate = deflate; 3175exports.deflateRaw = deflateRaw; 3176exports.gzip = gzip; 3177},{"./utils/common":27,"./utils/strings":28,"./zlib/deflate.js":32,"./zlib/messages":37,"./zlib/zstream":39}],26:[function(_dereq_,module,exports){ 3178'use strict'; 3179 3180 3181var zlib_inflate = _dereq_('./zlib/inflate.js'); 3182var utils = _dereq_('./utils/common'); 3183var strings = _dereq_('./utils/strings'); 3184var c = _dereq_('./zlib/constants'); 3185var msg = _dereq_('./zlib/messages'); 3186var zstream = _dereq_('./zlib/zstream'); 3187var gzheader = _dereq_('./zlib/gzheader'); 3188 3189 3190/** 3191 * class Inflate 3192 * 3193 * Generic JS-style wrapper for zlib calls. If you don't need 3194 * streaming behaviour - use more simple functions: [[inflate]] 3195 * and [[inflateRaw]]. 3196 **/ 3197 3198/* internal 3199 * inflate.chunks -> Array 3200 * 3201 * Chunks of output data, if [[Inflate#onData]] not overriden. 3202 **/ 3203 3204/** 3205 * Inflate.result -> Uint8Array|Array|String 3206 * 3207 * Uncompressed result, generated by default [[Inflate#onData]] 3208 * and [[Inflate#onEnd]] handlers. Filled after you push last chunk 3209 * (call [[Inflate#push]] with `Z_FINISH` / `true` param). 3210 **/ 3211 3212/** 3213 * Inflate.err -> Number 3214 * 3215 * Error code after inflate finished. 0 (Z_OK) on success. 3216 * Should be checked if broken data possible. 3217 **/ 3218 3219/** 3220 * Inflate.msg -> String 3221 * 3222 * Error message, if [[Inflate.err]] != 0 3223 **/ 3224 3225 3226/** 3227 * new Inflate(options) 3228 * - options (Object): zlib inflate options. 3229 * 3230 * Creates new inflator instance with specified params. Throws exception 3231 * on bad params. Supported options: 3232 * 3233 * - `windowBits` 3234 * 3235 * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) 3236 * for more information on these. 3237 * 3238 * Additional options, for internal needs: 3239 * 3240 * - `chunkSize` - size of generated data chunks (16K by default) 3241 * - `raw` (Boolean) - do raw inflate 3242 * - `to` (String) - if equal to 'string', then result will be converted 3243 * from utf8 to utf16 (javascript) string. When string output requested, 3244 * chunk length can differ from `chunkSize`, depending on content. 3245 * 3246 * By default, when no options set, autodetect deflate/gzip data format via 3247 * wrapper header. 3248 * 3249 * ##### Example: 3250 * 3251 * ```javascript 3252 * var pako = require('pako') 3253 * , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9]) 3254 * , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]); 3255 * 3256 * var inflate = new pako.Inflate({ level: 3}); 3257 * 3258 * inflate.push(chunk1, false); 3259 * inflate.push(chunk2, true); // true -> last chunk 3260 * 3261 * if (inflate.err) { throw new Error(inflate.err); } 3262 * 3263 * console.log(inflate.result); 3264 * ``` 3265 **/ 3266var Inflate = function(options) { 3267 3268 this.options = utils.assign({ 3269 chunkSize: 16384, 3270 windowBits: 0, 3271 to: '' 3272 }, options || {}); 3273 3274 var opt = this.options; 3275 3276 // Force window size for `raw` data, if not set directly, 3277 // because we have no header for autodetect. 3278 if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) { 3279 opt.windowBits = -opt.windowBits; 3280 if (opt.windowBits === 0) { opt.windowBits = -15; } 3281 } 3282 3283 // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate 3284 if ((opt.windowBits >= 0) && (opt.windowBits < 16) && 3285 !(options && options.windowBits)) { 3286 opt.windowBits += 32; 3287 } 3288 3289 // Gzip header has no info about windows size, we can do autodetect only 3290 // for deflate. So, if window size not set, force it to max when gzip possible 3291 if ((opt.windowBits > 15) && (opt.windowBits < 48)) { 3292 // bit 3 (16) -> gzipped data 3293 // bit 4 (32) -> autodetect gzip/deflate 3294 if ((opt.windowBits & 15) === 0) { 3295 opt.windowBits |= 15; 3296 } 3297 } 3298 3299 this.err = 0; // error code, if happens (0 = Z_OK) 3300 this.msg = ''; // error message 3301 this.ended = false; // used to avoid multiple onEnd() calls 3302 this.chunks = []; // chunks of compressed data 3303 3304 this.strm = new zstream(); 3305 this.strm.avail_out = 0; 3306 3307 var status = zlib_inflate.inflateInit2( 3308 this.strm, 3309 opt.windowBits 3310 ); 3311 3312 if (status !== c.Z_OK) { 3313 throw new Error(msg[status]); 3314 } 3315 3316 this.header = new gzheader(); 3317 3318 zlib_inflate.inflateGetHeader(this.strm, this.header); 3319}; 3320 3321/** 3322 * Inflate#push(data[, mode]) -> Boolean 3323 * - data (Uint8Array|Array|String): input data 3324 * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes. 3325 * See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH. 3326 * 3327 * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with 3328 * new output chunks. Returns `true` on success. The last data block must have 3329 * mode Z_FINISH (or `true`). That flush internal pending buffers and call 3330 * [[Inflate#onEnd]]. 3331 * 3332 * On fail call [[Inflate#onEnd]] with error code and return false. 3333 * 3334 * We strongly recommend to use `Uint8Array` on input for best speed (output 3335 * format is detected automatically). Also, don't skip last param and always 3336 * use the same type in your code (boolean or number). That will improve JS speed. 3337 * 3338 * For regular `Array`-s make sure all elements are [0..255]. 3339 * 3340 * ##### Example 3341 * 3342 * ```javascript 3343 * push(chunk, false); // push one of data chunks 3344 * ... 3345 * push(chunk, true); // push last chunk 3346 * ``` 3347 **/ 3348Inflate.prototype.push = function(data, mode) { 3349 var strm = this.strm; 3350 var chunkSize = this.options.chunkSize; 3351 var status, _mode; 3352 var next_out_utf8, tail, utf8str; 3353 3354 if (this.ended) { return false; } 3355 _mode = (mode === ~~mode) ? mode : ((mode === true) ? c.Z_FINISH : c.Z_NO_FLUSH); 3356 3357 // Convert data if needed 3358 if (typeof data === 'string') { 3359 // Only binary strings can be decompressed on practice 3360 strm.input = strings.binstring2buf(data); 3361 } else { 3362 strm.input = data; 3363 } 3364 3365 strm.next_in = 0; 3366 strm.avail_in = strm.input.length; 3367 3368 do { 3369 if (strm.avail_out === 0) { 3370 strm.output = new utils.Buf8(chunkSize); 3371 strm.next_out = 0; 3372 strm.avail_out = chunkSize; 3373 } 3374 3375 status = zlib_inflate.inflate(strm, c.Z_NO_FLUSH); /* no bad return value */ 3376 3377 if (status !== c.Z_STREAM_END && status !== c.Z_OK) { 3378 this.onEnd(status); 3379 this.ended = true; 3380 return false; 3381 } 3382 3383 if (strm.next_out) { 3384 if (strm.avail_out === 0 || status === c.Z_STREAM_END || (strm.avail_in === 0 && _mode === c.Z_FINISH)) { 3385 3386 if (this.options.to === 'string') { 3387 3388 next_out_utf8 = strings.utf8border(strm.output, strm.next_out); 3389 3390 tail = strm.next_out - next_out_utf8; 3391 utf8str = strings.buf2string(strm.output, next_out_utf8); 3392 3393 // move tail 3394 strm.next_out = tail; 3395 strm.avail_out = chunkSize - tail; 3396 if (tail) { utils.arraySet(strm.output, strm.output, next_out_utf8, tail, 0); } 3397 3398 this.onData(utf8str); 3399 3400 } else { 3401 this.onData(utils.shrinkBuf(strm.output, strm.next_out)); 3402 } 3403 } 3404 } 3405 } while ((strm.avail_in > 0) && status !== c.Z_STREAM_END); 3406 3407 if (status === c.Z_STREAM_END) { 3408 _mode = c.Z_FINISH; 3409 } 3410 // Finalize on the last chunk. 3411 if (_mode === c.Z_FINISH) { 3412 status = zlib_inflate.inflateEnd(this.strm); 3413 this.onEnd(status); 3414 this.ended = true; 3415 return status === c.Z_OK; 3416 } 3417 3418 return true; 3419}; 3420 3421 3422/** 3423 * Inflate#onData(chunk) -> Void 3424 * - chunk (Uint8Array|Array|String): ouput data. Type of array depends 3425 * on js engine support. When string output requested, each chunk 3426 * will be string. 3427 * 3428 * By default, stores data blocks in `chunks[]` property and glue 3429 * those in `onEnd`. Override this handler, if you need another behaviour. 3430 **/ 3431Inflate.prototype.onData = function(chunk) { 3432 this.chunks.push(chunk); 3433}; 3434 3435 3436/** 3437 * Inflate#onEnd(status) -> Void 3438 * - status (Number): inflate status. 0 (Z_OK) on success, 3439 * other if not. 3440 * 3441 * Called once after you tell inflate that input stream complete 3442 * or error happenned. By default - join collected chunks, 3443 * free memory and fill `results` / `err` properties. 3444 **/ 3445Inflate.prototype.onEnd = function(status) { 3446 // On success - join 3447 if (status === c.Z_OK) { 3448 if (this.options.to === 'string') { 3449 // Glue & convert here, until we teach pako to send 3450 // utf8 alligned strings to onData 3451 this.result = this.chunks.join(''); 3452 } else { 3453 this.result = utils.flattenChunks(this.chunks); 3454 } 3455 } 3456 this.chunks = []; 3457 this.err = status; 3458 this.msg = this.strm.msg; 3459}; 3460 3461 3462/** 3463 * inflate(data[, options]) -> Uint8Array|Array|String 3464 * - data (Uint8Array|Array|String): input data to decompress. 3465 * - options (Object): zlib inflate options. 3466 * 3467 * Decompress `data` with inflate/ungzip and `options`. Autodetect 3468 * format via wrapper header by default. That's why we don't provide 3469 * separate `ungzip` method. 3470 * 3471 * Supported options are: 3472 * 3473 * - windowBits 3474 * 3475 * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) 3476 * for more information. 3477 * 3478 * Sugar (options): 3479 * 3480 * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify 3481 * negative windowBits implicitly. 3482 * - `to` (String) - if equal to 'string', then result will be converted 3483 * from utf8 to utf16 (javascript) string. When string output requested, 3484 * chunk length can differ from `chunkSize`, depending on content. 3485 * 3486 * 3487 * ##### Example: 3488 * 3489 * ```javascript 3490 * var pako = require('pako') 3491 * , input = pako.deflate([1,2,3,4,5,6,7,8,9]) 3492 * , output; 3493 * 3494 * try { 3495 * output = pako.inflate(input); 3496 * } catch (err) 3497 * console.log(err); 3498 * } 3499 * ``` 3500 **/ 3501function inflate(input, options) { 3502 var inflator = new Inflate(options); 3503 3504 inflator.push(input, true); 3505 3506 // That will never happens, if you don't cheat with options :) 3507 if (inflator.err) { throw inflator.msg; } 3508 3509 return inflator.result; 3510} 3511 3512 3513/** 3514 * inflateRaw(data[, options]) -> Uint8Array|Array|String 3515 * - data (Uint8Array|Array|String): input data to decompress. 3516 * - options (Object): zlib inflate options. 3517 * 3518 * The same as [[inflate]], but creates raw data, without wrapper 3519 * (header and adler32 crc). 3520 **/ 3521function inflateRaw(input, options) { 3522 options = options || {}; 3523 options.raw = true; 3524 return inflate(input, options); 3525} 3526 3527 3528/** 3529 * ungzip(data[, options]) -> Uint8Array|Array|String 3530 * - data (Uint8Array|Array|String): input data to decompress. 3531 * - options (Object): zlib inflate options. 3532 * 3533 * Just shortcut to [[inflate]], because it autodetects format 3534 * by header.content. Done for convenience. 3535 **/ 3536 3537 3538exports.Inflate = Inflate; 3539exports.inflate = inflate; 3540exports.inflateRaw = inflateRaw; 3541exports.ungzip = inflate; 3542 3543},{"./utils/common":27,"./utils/strings":28,"./zlib/constants":30,"./zlib/gzheader":33,"./zlib/inflate.js":35,"./zlib/messages":37,"./zlib/zstream":39}],27:[function(_dereq_,module,exports){ 3544'use strict'; 3545 3546 3547var TYPED_OK = (typeof Uint8Array !== 'undefined') && 3548 (typeof Uint16Array !== 'undefined') && 3549 (typeof Int32Array !== 'undefined'); 3550 3551 3552exports.assign = function (obj /*from1, from2, from3, ...*/) { 3553 var sources = Array.prototype.slice.call(arguments, 1); 3554 while (sources.length) { 3555 var source = sources.shift(); 3556 if (!source) { continue; } 3557 3558 if (typeof(source) !== 'object') { 3559 throw new TypeError(source + 'must be non-object'); 3560 } 3561 3562 for (var p in source) { 3563 if (source.hasOwnProperty(p)) { 3564 obj[p] = source[p]; 3565 } 3566 } 3567 } 3568 3569 return obj; 3570}; 3571 3572 3573// reduce buffer size, avoiding mem copy 3574exports.shrinkBuf = function (buf, size) { 3575 if (buf.length === size) { return buf; } 3576 if (buf.subarray) { return buf.subarray(0, size); } 3577 buf.length = size; 3578 return buf; 3579}; 3580 3581 3582var fnTyped = { 3583 arraySet: function (dest, src, src_offs, len, dest_offs) { 3584 if (src.subarray && dest.subarray) { 3585 dest.set(src.subarray(src_offs, src_offs+len), dest_offs); 3586 return; 3587 } 3588 // Fallback to ordinary array 3589 for(var i=0; i<len; i++) { 3590 dest[dest_offs + i] = src[src_offs + i]; 3591 } 3592 }, 3593 // Join array of chunks to single array. 3594 flattenChunks: function(chunks) { 3595 var i, l, len, pos, chunk, result; 3596 3597 // calculate data length 3598 len = 0; 3599 for (i=0, l=chunks.length; i<l; i++) { 3600 len += chunks[i].length; 3601 } 3602 3603 // join chunks 3604 result = new Uint8Array(len); 3605 pos = 0; 3606 for (i=0, l=chunks.length; i<l; i++) { 3607 chunk = chunks[i]; 3608 result.set(chunk, pos); 3609 pos += chunk.length; 3610 } 3611 3612 return result; 3613 } 3614}; 3615 3616var fnUntyped = { 3617 arraySet: function (dest, src, src_offs, len, dest_offs) { 3618 for(var i=0; i<len; i++) { 3619 dest[dest_offs + i] = src[src_offs + i]; 3620 } 3621 }, 3622 // Join array of chunks to single array. 3623 flattenChunks: function(chunks) { 3624 return [].concat.apply([], chunks); 3625 } 3626}; 3627 3628 3629// Enable/Disable typed arrays use, for testing 3630// 3631exports.setTyped = function (on) { 3632 if (on) { 3633 exports.Buf8 = Uint8Array; 3634 exports.Buf16 = Uint16Array; 3635 exports.Buf32 = Int32Array; 3636 exports.assign(exports, fnTyped); 3637 } else { 3638 exports.Buf8 = Array; 3639 exports.Buf16 = Array; 3640 exports.Buf32 = Array; 3641 exports.assign(exports, fnUntyped); 3642 } 3643}; 3644 3645exports.setTyped(TYPED_OK); 3646},{}],28:[function(_dereq_,module,exports){ 3647// String encode/decode helpers 3648'use strict'; 3649 3650 3651var utils = _dereq_('./common'); 3652 3653 3654// Quick check if we can use fast array to bin string conversion 3655// 3656// - apply(Array) can fail on Android 2.2 3657// - apply(Uint8Array) can fail on iOS 5.1 Safary 3658// 3659var STR_APPLY_OK = true; 3660var STR_APPLY_UIA_OK = true; 3661 3662try { String.fromCharCode.apply(null, [0]); } catch(__) { STR_APPLY_OK = false; } 3663try { String.fromCharCode.apply(null, new Uint8Array(1)); } catch(__) { STR_APPLY_UIA_OK = false; } 3664 3665 3666// Table with utf8 lengths (calculated by first byte of sequence) 3667// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS, 3668// because max possible codepoint is 0x10ffff 3669var _utf8len = new utils.Buf8(256); 3670for (var i=0; i<256; i++) { 3671 _utf8len[i] = (i >= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1); 3672} 3673_utf8len[254]=_utf8len[254]=1; // Invalid sequence start 3674 3675 3676// convert string to array (typed, when possible) 3677exports.string2buf = function (str) { 3678 var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0; 3679 3680 // count binary size 3681 for (m_pos = 0; m_pos < str_len; m_pos++) { 3682 c = str.charCodeAt(m_pos); 3683 if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) { 3684 c2 = str.charCodeAt(m_pos+1); 3685 if ((c2 & 0xfc00) === 0xdc00) { 3686 c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); 3687 m_pos++; 3688 } 3689 } 3690 buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4; 3691 } 3692 3693 // allocate buffer 3694 buf = new utils.Buf8(buf_len); 3695 3696 // convert 3697 for (i=0, m_pos = 0; i < buf_len; m_pos++) { 3698 c = str.charCodeAt(m_pos); 3699 if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) { 3700 c2 = str.charCodeAt(m_pos+1); 3701 if ((c2 & 0xfc00) === 0xdc00) { 3702 c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); 3703 m_pos++; 3704 } 3705 } 3706 if (c < 0x80) { 3707 /* one byte */ 3708 buf[i++] = c; 3709 } else if (c < 0x800) { 3710 /* two bytes */ 3711 buf[i++] = 0xC0 | (c >>> 6); 3712 buf[i++] = 0x80 | (c & 0x3f); 3713 } else if (c < 0x10000) { 3714 /* three bytes */ 3715 buf[i++] = 0xE0 | (c >>> 12); 3716 buf[i++] = 0x80 | (c >>> 6 & 0x3f); 3717 buf[i++] = 0x80 | (c & 0x3f); 3718 } else { 3719 /* four bytes */ 3720 buf[i++] = 0xf0 | (c >>> 18); 3721 buf[i++] = 0x80 | (c >>> 12 & 0x3f); 3722 buf[i++] = 0x80 | (c >>> 6 & 0x3f); 3723 buf[i++] = 0x80 | (c & 0x3f); 3724 } 3725 } 3726 3727 return buf; 3728}; 3729 3730// Helper (used in 2 places) 3731function buf2binstring(buf, len) { 3732 // use fallback for big arrays to avoid stack overflow 3733 if (len < 65537) { 3734 if ((buf.subarray && STR_APPLY_UIA_OK) || (!buf.subarray && STR_APPLY_OK)) { 3735 return String.fromCharCode.apply(null, utils.shrinkBuf(buf, len)); 3736 } 3737 } 3738 3739 var result = ''; 3740 for(var i=0; i < len; i++) { 3741 result += String.fromCharCode(buf[i]); 3742 } 3743 return result; 3744} 3745 3746 3747// Convert byte array to binary string 3748exports.buf2binstring = function(buf) { 3749 return buf2binstring(buf, buf.length); 3750}; 3751 3752 3753// Convert binary string (typed, when possible) 3754exports.binstring2buf = function(str) { 3755 var buf = new utils.Buf8(str.length); 3756 for(var i=0, len=buf.length; i < len; i++) { 3757 buf[i] = str.charCodeAt(i); 3758 } 3759 return buf; 3760}; 3761 3762 3763// convert array to string 3764exports.buf2string = function (buf, max) { 3765 var i, out, c, c_len; 3766 var len = max || buf.length; 3767 3768 // Reserve max possible length (2 words per char) 3769 // NB: by unknown reasons, Array is significantly faster for 3770 // String.fromCharCode.apply than Uint16Array. 3771 var utf16buf = new Array(len*2); 3772 3773 for (out=0, i=0; i<len;) { 3774 c = buf[i++]; 3775 // quick process ascii 3776 if (c < 0x80) { utf16buf[out++] = c; continue; } 3777 3778 c_len = _utf8len[c]; 3779 // skip 5 & 6 byte codes 3780 if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len-1; continue; } 3781 3782 // apply mask on first byte 3783 c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07; 3784 // join the rest 3785 while (c_len > 1 && i < len) { 3786 c = (c << 6) | (buf[i++] & 0x3f); 3787 c_len--; 3788 } 3789 3790 // terminated by end of string? 3791 if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; } 3792 3793 if (c < 0x10000) { 3794 utf16buf[out++] = c; 3795 } else { 3796 c -= 0x10000; 3797 utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff); 3798 utf16buf[out++] = 0xdc00 | (c & 0x3ff); 3799 } 3800 } 3801 3802 return buf2binstring(utf16buf, out); 3803}; 3804 3805 3806// Calculate max possible position in utf8 buffer, 3807// that will not break sequence. If that's not possible 3808// - (very small limits) return max size as is. 3809// 3810// buf[] - utf8 bytes array 3811// max - length limit (mandatory); 3812exports.utf8border = function(buf, max) { 3813 var pos; 3814 3815 max = max || buf.length; 3816 if (max > buf.length) { max = buf.length; } 3817 3818 // go back from last position, until start of sequence found 3819 pos = max-1; 3820 while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; } 3821 3822 // Fuckup - very small and broken sequence, 3823 // return max, because we should return something anyway. 3824 if (pos < 0) { return max; } 3825 3826 // If we came to start of buffer - that means vuffer is too small, 3827 // return max too. 3828 if (pos === 0) { return max; } 3829 3830 return (pos + _utf8len[buf[pos]] > max) ? pos : max; 3831}; 3832 3833},{"./common":27}],29:[function(_dereq_,module,exports){ 3834'use strict'; 3835 3836// Note: adler32 takes 12% for level 0 and 2% for level 6. 3837// It doesn't worth to make additional optimizationa as in original. 3838// Small size is preferable. 3839 3840function adler32(adler, buf, len, pos) { 3841 var s1 = (adler & 0xffff) |0 3842 , s2 = ((adler >>> 16) & 0xffff) |0 3843 , n = 0; 3844 3845 while (len !== 0) { 3846 // Set limit ~ twice less than 5552, to keep 3847 // s2 in 31-bits, because we force signed ints. 3848 // in other case %= will fail. 3849 n = len > 2000 ? 2000 : len; 3850 len -= n; 3851 3852 do { 3853 s1 = (s1 + buf[pos++]) |0; 3854 s2 = (s2 + s1) |0; 3855 } while (--n); 3856 3857 s1 %= 65521; 3858 s2 %= 65521; 3859 } 3860 3861 return (s1 | (s2 << 16)) |0; 3862} 3863 3864 3865module.exports = adler32; 3866},{}],30:[function(_dereq_,module,exports){ 3867module.exports = { 3868 3869 /* Allowed flush values; see deflate() and inflate() below for details */ 3870 Z_NO_FLUSH: 0, 3871 Z_PARTIAL_FLUSH: 1, 3872 Z_SYNC_FLUSH: 2, 3873 Z_FULL_FLUSH: 3, 3874 Z_FINISH: 4, 3875 Z_BLOCK: 5, 3876 Z_TREES: 6, 3877 3878 /* Return codes for the compression/decompression functions. Negative values 3879 * are errors, positive values are used for special but normal events. 3880 */ 3881 Z_OK: 0, 3882 Z_STREAM_END: 1, 3883 Z_NEED_DICT: 2, 3884 Z_ERRNO: -1, 3885 Z_STREAM_ERROR: -2, 3886 Z_DATA_ERROR: -3, 3887 //Z_MEM_ERROR: -4, 3888 Z_BUF_ERROR: -5, 3889 //Z_VERSION_ERROR: -6, 3890 3891 /* compression levels */ 3892 Z_NO_COMPRESSION: 0, 3893 Z_BEST_SPEED: 1, 3894 Z_BEST_COMPRESSION: 9, 3895 Z_DEFAULT_COMPRESSION: -1, 3896 3897 3898 Z_FILTERED: 1, 3899 Z_HUFFMAN_ONLY: 2, 3900 Z_RLE: 3, 3901 Z_FIXED: 4, 3902 Z_DEFAULT_STRATEGY: 0, 3903 3904 /* Possible values of the data_type field (though see inflate()) */ 3905 Z_BINARY: 0, 3906 Z_TEXT: 1, 3907 //Z_ASCII: 1, // = Z_TEXT (deprecated) 3908 Z_UNKNOWN: 2, 3909 3910 /* The deflate compression method */ 3911 Z_DEFLATED: 8 3912 //Z_NULL: null // Use -1 or null inline, depending on var type 3913}; 3914},{}],31:[function(_dereq_,module,exports){ 3915'use strict'; 3916 3917// Note: we can't get significant speed boost here. 3918// So write code to minimize size - no pregenerated tables 3919// and array tools dependencies. 3920 3921 3922// Use ordinary array, since untyped makes no boost here 3923function makeTable() { 3924 var c, table = []; 3925 3926 for(var n =0; n < 256; n++){ 3927 c = n; 3928 for(var k =0; k < 8; k++){ 3929 c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1)); 3930 } 3931 table[n] = c; 3932 } 3933 3934 return table; 3935} 3936 3937// Create table on load. Just 255 signed longs. Not a problem. 3938var crcTable = makeTable(); 3939 3940 3941function crc32(crc, buf, len, pos) { 3942 var t = crcTable 3943 , end = pos + len; 3944 3945 crc = crc ^ (-1); 3946 3947 for (var i = pos; i < end; i++ ) { 3948 crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF]; 3949 } 3950 3951 return (crc ^ (-1)); // >>> 0; 3952} 3953 3954 3955module.exports = crc32; 3956},{}],32:[function(_dereq_,module,exports){ 3957'use strict'; 3958 3959var utils = _dereq_('../utils/common'); 3960var trees = _dereq_('./trees'); 3961var adler32 = _dereq_('./adler32'); 3962var crc32 = _dereq_('./crc32'); 3963var msg = _dereq_('./messages'); 3964 3965/* Public constants ==========================================================*/ 3966/* ===========================================================================*/ 3967 3968 3969/* Allowed flush values; see deflate() and inflate() below for details */ 3970var Z_NO_FLUSH = 0; 3971var Z_PARTIAL_FLUSH = 1; 3972//var Z_SYNC_FLUSH = 2; 3973var Z_FULL_FLUSH = 3; 3974var Z_FINISH = 4; 3975var Z_BLOCK = 5; 3976//var Z_TREES = 6; 3977 3978 3979/* Return codes for the compression/decompression functions. Negative values 3980 * are errors, positive values are used for special but normal events. 3981 */ 3982var Z_OK = 0; 3983var Z_STREAM_END = 1; 3984//var Z_NEED_DICT = 2; 3985//var Z_ERRNO = -1; 3986var Z_STREAM_ERROR = -2; 3987var Z_DATA_ERROR = -3; 3988//var Z_MEM_ERROR = -4; 3989var Z_BUF_ERROR = -5; 3990//var Z_VERSION_ERROR = -6; 3991 3992 3993/* compression levels */ 3994//var Z_NO_COMPRESSION = 0; 3995//var Z_BEST_SPEED = 1; 3996//var Z_BEST_COMPRESSION = 9; 3997var Z_DEFAULT_COMPRESSION = -1; 3998 3999 4000var Z_FILTERED = 1; 4001var Z_HUFFMAN_ONLY = 2; 4002var Z_RLE = 3; 4003var Z_FIXED = 4; 4004var Z_DEFAULT_STRATEGY = 0; 4005 4006/* Possible values of the data_type field (though see inflate()) */ 4007//var Z_BINARY = 0; 4008//var Z_TEXT = 1; 4009//var Z_ASCII = 1; // = Z_TEXT 4010var Z_UNKNOWN = 2; 4011 4012 4013/* The deflate compression method */ 4014var Z_DEFLATED = 8; 4015 4016/*============================================================================*/ 4017 4018 4019var MAX_MEM_LEVEL = 9; 4020/* Maximum value for memLevel in deflateInit2 */ 4021var MAX_WBITS = 15; 4022/* 32K LZ77 window */ 4023var DEF_MEM_LEVEL = 8; 4024 4025 4026var LENGTH_CODES = 29; 4027/* number of length codes, not counting the special END_BLOCK code */ 4028var LITERALS = 256; 4029/* number of literal bytes 0..255 */ 4030var L_CODES = LITERALS + 1 + LENGTH_CODES; 4031/* number of Literal or Length codes, including the END_BLOCK code */ 4032var D_CODES = 30; 4033/* number of distance codes */ 4034var BL_CODES = 19; 4035/* number of codes used to transfer the bit lengths */ 4036var HEAP_SIZE = 2*L_CODES + 1; 4037/* maximum heap size */ 4038var MAX_BITS = 15; 4039/* All codes must not exceed MAX_BITS bits */ 4040 4041var MIN_MATCH = 3; 4042var MAX_MATCH = 258; 4043var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1); 4044 4045var PRESET_DICT = 0x20; 4046 4047var INIT_STATE = 42; 4048var EXTRA_STATE = 69; 4049var NAME_STATE = 73; 4050var COMMENT_STATE = 91; 4051var HCRC_STATE = 103; 4052var BUSY_STATE = 113; 4053var FINISH_STATE = 666; 4054 4055var BS_NEED_MORE = 1; /* block not completed, need more input or more output */ 4056var BS_BLOCK_DONE = 2; /* block flush performed */ 4057var BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */ 4058var BS_FINISH_DONE = 4; /* finish done, accept no more input or output */ 4059 4060var OS_CODE = 0x03; // Unix :) . Don't detect, use this default. 4061 4062function err(strm, errorCode) { 4063 strm.msg = msg[errorCode]; 4064 return errorCode; 4065} 4066 4067function rank(f) { 4068 return ((f) << 1) - ((f) > 4 ? 9 : 0); 4069} 4070 4071function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } } 4072 4073 4074/* ========================================================================= 4075 * Flush as much pending output as possible. All deflate() output goes 4076 * through this function so some applications may wish to modify it 4077 * to avoid allocating a large strm->output buffer and copying into it. 4078 * (See also read_buf()). 4079 */ 4080function flush_pending(strm) { 4081 var s = strm.state; 4082 4083 //_tr_flush_bits(s); 4084 var len = s.pending; 4085 if (len > strm.avail_out) { 4086 len = strm.avail_out; 4087 } 4088 if (len === 0) { return; } 4089 4090 utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out); 4091 strm.next_out += len; 4092 s.pending_out += len; 4093 strm.total_out += len; 4094 strm.avail_out -= len; 4095 s.pending -= len; 4096 if (s.pending === 0) { 4097 s.pending_out = 0; 4098 } 4099} 4100 4101 4102function flush_block_only (s, last) { 4103 trees._tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last); 4104 s.block_start = s.strstart; 4105 flush_pending(s.strm); 4106} 4107 4108 4109function put_byte(s, b) { 4110 s.pending_buf[s.pending++] = b; 4111} 4112 4113 4114/* ========================================================================= 4115 * Put a short in the pending buffer. The 16-bit value is put in MSB order. 4116 * IN assertion: the stream state is correct and there is enough room in 4117 * pending_buf. 4118 */ 4119function putShortMSB(s, b) { 4120// put_byte(s, (Byte)(b >> 8)); 4121// put_byte(s, (Byte)(b & 0xff)); 4122 s.pending_buf[s.pending++] = (b >>> 8) & 0xff; 4123 s.pending_buf[s.pending++] = b & 0xff; 4124} 4125 4126 4127/* =========================================================================== 4128 * Read a new buffer from the current input stream, update the adler32 4129 * and total number of bytes read. All deflate() input goes through 4130 * this function so some applications may wish to modify it to avoid 4131 * allocating a large strm->input buffer and copying from it. 4132 * (See also flush_pending()). 4133 */ 4134function read_buf(strm, buf, start, size) { 4135 var len = strm.avail_in; 4136 4137 if (len > size) { len = size; } 4138 if (len === 0) { return 0; } 4139 4140 strm.avail_in -= len; 4141 4142 utils.arraySet(buf, strm.input, strm.next_in, len, start); 4143 if (strm.state.wrap === 1) { 4144 strm.adler = adler32(strm.adler, buf, len, start); 4145 } 4146 4147 else if (strm.state.wrap === 2) { 4148 strm.adler = crc32(strm.adler, buf, len, start); 4149 } 4150 4151 strm.next_in += len; 4152 strm.total_in += len; 4153 4154 return len; 4155} 4156 4157 4158/* =========================================================================== 4159 * Set match_start to the longest match starting at the given string and 4160 * return its length. Matches shorter or equal to prev_length are discarded, 4161 * in which case the result is equal to prev_length and match_start is 4162 * garbage. 4163 * IN assertions: cur_match is the head of the hash chain for the current 4164 * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 4165 * OUT assertion: the match length is not greater than s->lookahead. 4166 */ 4167function longest_match(s, cur_match) { 4168 var chain_length = s.max_chain_length; /* max hash chain length */ 4169 var scan = s.strstart; /* current string */ 4170 var match; /* matched string */ 4171 var len; /* length of current match */ 4172 var best_len = s.prev_length; /* best match length so far */ 4173 var nice_match = s.nice_match; /* stop if match long enough */ 4174 var limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ? 4175 s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/; 4176 4177 var _win = s.window; // shortcut 4178 4179 var wmask = s.w_mask; 4180 var prev = s.prev; 4181 4182 /* Stop when cur_match becomes <= limit. To simplify the code, 4183 * we prevent matches with the string of window index 0. 4184 */ 4185 4186 var strend = s.strstart + MAX_MATCH; 4187 var scan_end1 = _win[scan + best_len - 1]; 4188 var scan_end = _win[scan + best_len]; 4189 4190 /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. 4191 * It is easy to get rid of this optimization if necessary. 4192 */ 4193 // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); 4194 4195 /* Do not waste too much time if we already have a good match: */ 4196 if (s.prev_length >= s.good_match) { 4197 chain_length >>= 2; 4198 } 4199 /* Do not look for matches beyond the end of the input. This is necessary 4200 * to make deflate deterministic. 4201 */ 4202 if (nice_match > s.lookahead) { nice_match = s.lookahead; } 4203 4204 // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); 4205 4206 do { 4207 // Assert(cur_match < s->strstart, "no future"); 4208 match = cur_match; 4209 4210 /* Skip to next match if the match length cannot increase 4211 * or if the match length is less than 2. Note that the checks below 4212 * for insufficient lookahead only occur occasionally for performance 4213 * reasons. Therefore uninitialized memory will be accessed, and 4214 * conditional jumps will be made that depend on those values. 4215 * However the length of the match is limited to the lookahead, so 4216 * the output of deflate is not affected by the uninitialized values. 4217 */ 4218 4219 if (_win[match + best_len] !== scan_end || 4220 _win[match + best_len - 1] !== scan_end1 || 4221 _win[match] !== _win[scan] || 4222 _win[++match] !== _win[scan + 1]) { 4223 continue; 4224 } 4225 4226 /* The check at best_len-1 can be removed because it will be made 4227 * again later. (This heuristic is not always a win.) 4228 * It is not necessary to compare scan[2] and match[2] since they 4229 * are always equal when the other bytes match, given that 4230 * the hash keys are equal and that HASH_BITS >= 8. 4231 */ 4232 scan += 2; 4233 match++; 4234 // Assert(*scan == *match, "match[2]?"); 4235 4236 /* We check for insufficient lookahead only every 8th comparison; 4237 * the 256th check will be made at strstart+258. 4238 */ 4239 do { 4240 /*jshint noempty:false*/ 4241 } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] && 4242 _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && 4243 _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && 4244 _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && 4245 scan < strend); 4246 4247 // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); 4248 4249 len = MAX_MATCH - (strend - scan); 4250 scan = strend - MAX_MATCH; 4251 4252 if (len > best_len) { 4253 s.match_start = cur_match; 4254 best_len = len; 4255 if (len >= nice_match) { 4256 break; 4257 } 4258 scan_end1 = _win[scan + best_len - 1]; 4259 scan_end = _win[scan + best_len]; 4260 } 4261 } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0); 4262 4263 if (best_len <= s.lookahead) { 4264 return best_len; 4265 } 4266 return s.lookahead; 4267} 4268 4269 4270/* =========================================================================== 4271 * Fill the window when the lookahead becomes insufficient. 4272 * Updates strstart and lookahead. 4273 * 4274 * IN assertion: lookahead < MIN_LOOKAHEAD 4275 * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD 4276 * At least one byte has been read, or avail_in == 0; reads are 4277 * performed for at least two bytes (required for the zip translate_eol 4278 * option -- not supported here). 4279 */ 4280function fill_window(s) { 4281 var _w_size = s.w_size; 4282 var p, n, m, more, str; 4283 4284 //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); 4285 4286 do { 4287 more = s.window_size - s.lookahead - s.strstart; 4288 4289 // JS ints have 32 bit, block below not needed 4290 /* Deal with !@#$% 64K limit: */ 4291 //if (sizeof(int) <= 2) { 4292 // if (more == 0 && s->strstart == 0 && s->lookahead == 0) { 4293 // more = wsize; 4294 // 4295 // } else if (more == (unsigned)(-1)) { 4296 // /* Very unlikely, but possible on 16 bit machine if 4297 // * strstart == 0 && lookahead == 1 (input done a byte at time) 4298 // */ 4299 // more--; 4300 // } 4301 //} 4302 4303 4304 /* If the window is almost full and there is insufficient lookahead, 4305 * move the upper half to the lower one to make room in the upper half. 4306 */ 4307 if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) { 4308 4309 utils.arraySet(s.window, s.window, _w_size, _w_size, 0); 4310 s.match_start -= _w_size; 4311 s.strstart -= _w_size; 4312 /* we now have strstart >= MAX_DIST */ 4313 s.block_start -= _w_size; 4314 4315 /* Slide the hash table (could be avoided with 32 bit values 4316 at the expense of memory usage). We slide even when level == 0 4317 to keep the hash table consistent if we switch back to level > 0 4318 later. (Using level 0 permanently is not an optimal usage of 4319 zlib, so we don't care about this pathological case.) 4320 */ 4321 4322 n = s.hash_size; 4323 p = n; 4324 do { 4325 m = s.head[--p]; 4326 s.head[p] = (m >= _w_size ? m - _w_size : 0); 4327 } while (--n); 4328 4329 n = _w_size; 4330 p = n; 4331 do { 4332 m = s.prev[--p]; 4333 s.prev[p] = (m >= _w_size ? m - _w_size : 0); 4334 /* If n is not on any hash chain, prev[n] is garbage but 4335 * its value will never be used. 4336 */ 4337 } while (--n); 4338 4339 more += _w_size; 4340 } 4341 if (s.strm.avail_in === 0) { 4342 break; 4343 } 4344 4345 /* If there was no sliding: 4346 * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && 4347 * more == window_size - lookahead - strstart 4348 * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) 4349 * => more >= window_size - 2*WSIZE + 2 4350 * In the BIG_MEM or MMAP case (not yet supported), 4351 * window_size == input_size + MIN_LOOKAHEAD && 4352 * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. 4353 * Otherwise, window_size == 2*WSIZE so more >= 2. 4354 * If there was sliding, more >= WSIZE. So in all cases, more >= 2. 4355 */ 4356 //Assert(more >= 2, "more < 2"); 4357 n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more); 4358 s.lookahead += n; 4359 4360 /* Initialize the hash value now that we have some input: */ 4361 if (s.lookahead + s.insert >= MIN_MATCH) { 4362 str = s.strstart - s.insert; 4363 s.ins_h = s.window[str]; 4364 4365 /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */ 4366 s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask; 4367//#if MIN_MATCH != 3 4368// Call update_hash() MIN_MATCH-3 more times 4369//#endif 4370 while (s.insert) { 4371 /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ 4372 s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH-1]) & s.hash_mask; 4373 4374 s.prev[str & s.w_mask] = s.head[s.ins_h]; 4375 s.head[s.ins_h] = str; 4376 str++; 4377 s.insert--; 4378 if (s.lookahead + s.insert < MIN_MATCH) { 4379 break; 4380 } 4381 } 4382 } 4383 /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, 4384 * but this is not important since only literal bytes will be emitted. 4385 */ 4386 4387 } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0); 4388 4389 /* If the WIN_INIT bytes after the end of the current data have never been 4390 * written, then zero those bytes in order to avoid memory check reports of 4391 * the use of uninitialized (or uninitialised as Julian writes) bytes by 4392 * the longest match routines. Update the high water mark for the next 4393 * time through here. WIN_INIT is set to MAX_MATCH since the longest match 4394 * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. 4395 */ 4396// if (s.high_water < s.window_size) { 4397// var curr = s.strstart + s.lookahead; 4398// var init = 0; 4399// 4400// if (s.high_water < curr) { 4401// /* Previous high water mark below current data -- zero WIN_INIT 4402// * bytes or up to end of window, whichever is less. 4403// */ 4404// init = s.window_size - curr; 4405// if (init > WIN_INIT) 4406// init = WIN_INIT; 4407// zmemzero(s->window + curr, (unsigned)init); 4408// s->high_water = curr + init; 4409// } 4410// else if (s->high_water < (ulg)curr + WIN_INIT) { 4411// /* High water mark at or above current data, but below current data 4412// * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up 4413// * to end of window, whichever is less. 4414// */ 4415// init = (ulg)curr + WIN_INIT - s->high_water; 4416// if (init > s->window_size - s->high_water) 4417// init = s->window_size - s->high_water; 4418// zmemzero(s->window + s->high_water, (unsigned)init); 4419// s->high_water += init; 4420// } 4421// } 4422// 4423// Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, 4424// "not enough room for search"); 4425} 4426 4427/* =========================================================================== 4428 * Copy without compression as much as possible from the input stream, return 4429 * the current block state. 4430 * This function does not insert new strings in the dictionary since 4431 * uncompressible data is probably not useful. This function is used 4432 * only for the level=0 compression option. 4433 * NOTE: this function should be optimized to avoid extra copying from 4434 * window to pending_buf. 4435 */ 4436function deflate_stored(s, flush) { 4437 /* Stored blocks are limited to 0xffff bytes, pending_buf is limited 4438 * to pending_buf_size, and each stored block has a 5 byte header: 4439 */ 4440 var max_block_size = 0xffff; 4441 4442 if (max_block_size > s.pending_buf_size - 5) { 4443 max_block_size = s.pending_buf_size - 5; 4444 } 4445 4446 /* Copy as much as possible from input to output: */ 4447 for (;;) { 4448 /* Fill the window as much as possible: */ 4449 if (s.lookahead <= 1) { 4450 4451 //Assert(s->strstart < s->w_size+MAX_DIST(s) || 4452 // s->block_start >= (long)s->w_size, "slide too late"); 4453// if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) || 4454// s.block_start >= s.w_size)) { 4455// throw new Error("slide too late"); 4456// } 4457 4458 fill_window(s); 4459 if (s.lookahead === 0 && flush === Z_NO_FLUSH) { 4460 return BS_NEED_MORE; 4461 } 4462 4463 if (s.lookahead === 0) { 4464 break; 4465 } 4466 /* flush the current block */ 4467 } 4468 //Assert(s->block_start >= 0L, "block gone"); 4469// if (s.block_start < 0) throw new Error("block gone"); 4470 4471 s.strstart += s.lookahead; 4472 s.lookahead = 0; 4473 4474 /* Emit a stored block if pending_buf will be full: */ 4475 var max_start = s.block_start + max_block_size; 4476 4477 if (s.strstart === 0 || s.strstart >= max_start) { 4478 /* strstart == 0 is possible when wraparound on 16-bit machine */ 4479 s.lookahead = s.strstart - max_start; 4480 s.strstart = max_start; 4481 /*** FLUSH_BLOCK(s, 0); ***/ 4482 flush_block_only(s, false); 4483 if (s.strm.avail_out === 0) { 4484 return BS_NEED_MORE; 4485 } 4486 /***/ 4487 4488 4489 } 4490 /* Flush if we may have to slide, otherwise block_start may become 4491 * negative and the data will be gone: 4492 */ 4493 if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) { 4494 /*** FLUSH_BLOCK(s, 0); ***/ 4495 flush_block_only(s, false); 4496 if (s.strm.avail_out === 0) { 4497 return BS_NEED_MORE; 4498 } 4499 /***/ 4500 } 4501 } 4502 4503 s.insert = 0; 4504 4505 if (flush === Z_FINISH) { 4506 /*** FLUSH_BLOCK(s, 1); ***/ 4507 flush_block_only(s, true); 4508 if (s.strm.avail_out === 0) { 4509 return BS_FINISH_STARTED; 4510 } 4511 /***/ 4512 return BS_FINISH_DONE; 4513 } 4514 4515 if (s.strstart > s.block_start) { 4516 /*** FLUSH_BLOCK(s, 0); ***/ 4517 flush_block_only(s, false); 4518 if (s.strm.avail_out === 0) { 4519 return BS_NEED_MORE; 4520 } 4521 /***/ 4522 } 4523 4524 return BS_NEED_MORE; 4525} 4526 4527/* =========================================================================== 4528 * Compress as much as possible from the input stream, return the current 4529 * block state. 4530 * This function does not perform lazy evaluation of matches and inserts 4531 * new strings in the dictionary only for unmatched strings or for short 4532 * matches. It is used only for the fast compression options. 4533 */ 4534function deflate_fast(s, flush) { 4535 var hash_head; /* head of the hash chain */ 4536 var bflush; /* set if current block must be flushed */ 4537 4538 for (;;) { 4539 /* Make sure that we always have enough lookahead, except 4540 * at the end of the input file. We need MAX_MATCH bytes 4541 * for the next match, plus MIN_MATCH bytes to insert the 4542 * string following the next match. 4543 */ 4544 if (s.lookahead < MIN_LOOKAHEAD) { 4545 fill_window(s); 4546 if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) { 4547 return BS_NEED_MORE; 4548 } 4549 if (s.lookahead === 0) { 4550 break; /* flush the current block */ 4551 } 4552 } 4553 4554 /* Insert the string window[strstart .. strstart+2] in the 4555 * dictionary, and set hash_head to the head of the hash chain: 4556 */ 4557 hash_head = 0/*NIL*/; 4558 if (s.lookahead >= MIN_MATCH) { 4559 /*** INSERT_STRING(s, s.strstart, hash_head); ***/ 4560 s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; 4561 hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; 4562 s.head[s.ins_h] = s.strstart; 4563 /***/ 4564 } 4565 4566 /* Find the longest match, discarding those <= prev_length. 4567 * At this point we have always match_length < MIN_MATCH 4568 */ 4569 if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) { 4570 /* To simplify the code, we prevent matches with the string 4571 * of window index 0 (in particular we have to avoid a match 4572 * of the string with itself at the start of the input file). 4573 */ 4574 s.match_length = longest_match(s, hash_head); 4575 /* longest_match() sets match_start */ 4576 } 4577 if (s.match_length >= MIN_MATCH) { 4578 // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only 4579 4580 /*** _tr_tally_dist(s, s.strstart - s.match_start, 4581 s.match_length - MIN_MATCH, bflush); ***/ 4582 bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH); 4583 4584 s.lookahead -= s.match_length; 4585 4586 /* Insert new strings in the hash table only if the match length 4587 * is not too large. This saves time but degrades compression. 4588 */ 4589 if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) { 4590 s.match_length--; /* string at strstart already in table */ 4591 do { 4592 s.strstart++; 4593 /*** INSERT_STRING(s, s.strstart, hash_head); ***/ 4594 s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; 4595 hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; 4596 s.head[s.ins_h] = s.strstart; 4597 /***/ 4598 /* strstart never exceeds WSIZE-MAX_MATCH, so there are 4599 * always MIN_MATCH bytes ahead. 4600 */ 4601 } while (--s.match_length !== 0); 4602 s.strstart++; 4603 } else 4604 { 4605 s.strstart += s.match_length; 4606 s.match_length = 0; 4607 s.ins_h = s.window[s.strstart]; 4608 /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */ 4609 s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask; 4610 4611//#if MIN_MATCH != 3 4612// Call UPDATE_HASH() MIN_MATCH-3 more times 4613//#endif 4614 /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not 4615 * matter since it will be recomputed at next deflate call. 4616 */ 4617 } 4618 } else { 4619 /* No match, output a literal byte */ 4620 //Tracevv((stderr,"%c", s.window[s.strstart])); 4621 /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ 4622 bflush = trees._tr_tally(s, 0, s.window[s.strstart]); 4623 4624 s.lookahead--; 4625 s.strstart++; 4626 } 4627 if (bflush) { 4628 /*** FLUSH_BLOCK(s, 0); ***/ 4629 flush_block_only(s, false); 4630 if (s.strm.avail_out === 0) { 4631 return BS_NEED_MORE; 4632 } 4633 /***/ 4634 } 4635 } 4636 s.insert = ((s.strstart < (MIN_MATCH-1)) ? s.strstart : MIN_MATCH-1); 4637 if (flush === Z_FINISH) { 4638 /*** FLUSH_BLOCK(s, 1); ***/ 4639 flush_block_only(s, true); 4640 if (s.strm.avail_out === 0) { 4641 return BS_FINISH_STARTED; 4642 } 4643 /***/ 4644 return BS_FINISH_DONE; 4645 } 4646 if (s.last_lit) { 4647 /*** FLUSH_BLOCK(s, 0); ***/ 4648 flush_block_only(s, false); 4649 if (s.strm.avail_out === 0) { 4650 return BS_NEED_MORE; 4651 } 4652 /***/ 4653 } 4654 return BS_BLOCK_DONE; 4655} 4656 4657/* =========================================================================== 4658 * Same as above, but achieves better compression. We use a lazy 4659 * evaluation for matches: a match is finally adopted only if there is 4660 * no better match at the next window position. 4661 */ 4662function deflate_slow(s, flush) { 4663 var hash_head; /* head of hash chain */ 4664 var bflush; /* set if current block must be flushed */ 4665 4666 var max_insert; 4667 4668 /* Process the input block. */ 4669 for (;;) { 4670 /* Make sure that we always have enough lookahead, except 4671 * at the end of the input file. We need MAX_MATCH bytes 4672 * for the next match, plus MIN_MATCH bytes to insert the 4673 * string following the next match. 4674 */ 4675 if (s.lookahead < MIN_LOOKAHEAD) { 4676 fill_window(s); 4677 if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) { 4678 return BS_NEED_MORE; 4679 } 4680 if (s.lookahead === 0) { break; } /* flush the current block */ 4681 } 4682 4683 /* Insert the string window[strstart .. strstart+2] in the 4684 * dictionary, and set hash_head to the head of the hash chain: 4685 */ 4686 hash_head = 0/*NIL*/; 4687 if (s.lookahead >= MIN_MATCH) { 4688 /*** INSERT_STRING(s, s.strstart, hash_head); ***/ 4689 s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; 4690 hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; 4691 s.head[s.ins_h] = s.strstart; 4692 /***/ 4693 } 4694 4695 /* Find the longest match, discarding those <= prev_length. 4696 */ 4697 s.prev_length = s.match_length; 4698 s.prev_match = s.match_start; 4699 s.match_length = MIN_MATCH-1; 4700 4701 if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match && 4702 s.strstart - hash_head <= (s.w_size-MIN_LOOKAHEAD)/*MAX_DIST(s)*/) { 4703 /* To simplify the code, we prevent matches with the string 4704 * of window index 0 (in particular we have to avoid a match 4705 * of the string with itself at the start of the input file). 4706 */ 4707 s.match_length = longest_match(s, hash_head); 4708 /* longest_match() sets match_start */ 4709 4710 if (s.match_length <= 5 && 4711 (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) { 4712 4713 /* If prev_match is also MIN_MATCH, match_start is garbage 4714 * but we will ignore the current match anyway. 4715 */ 4716 s.match_length = MIN_MATCH-1; 4717 } 4718 } 4719 /* If there was a match at the previous step and the current 4720 * match is not better, output the previous match: 4721 */ 4722 if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) { 4723 max_insert = s.strstart + s.lookahead - MIN_MATCH; 4724 /* Do not insert strings in hash table beyond this. */ 4725 4726 //check_match(s, s.strstart-1, s.prev_match, s.prev_length); 4727 4728 /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match, 4729 s.prev_length - MIN_MATCH, bflush);***/ 4730 bflush = trees._tr_tally(s, s.strstart - 1- s.prev_match, s.prev_length - MIN_MATCH); 4731 /* Insert in hash table all strings up to the end of the match. 4732 * strstart-1 and strstart are already inserted. If there is not 4733 * enough lookahead, the last two strings are not inserted in 4734 * the hash table. 4735 */ 4736 s.lookahead -= s.prev_length-1; 4737 s.prev_length -= 2; 4738 do { 4739 if (++s.strstart <= max_insert) { 4740 /*** INSERT_STRING(s, s.strstart, hash_head); ***/ 4741 s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; 4742 hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; 4743 s.head[s.ins_h] = s.strstart; 4744 /***/ 4745 } 4746 } while (--s.prev_length !== 0); 4747 s.match_available = 0; 4748 s.match_length = MIN_MATCH-1; 4749 s.strstart++; 4750 4751 if (bflush) { 4752 /*** FLUSH_BLOCK(s, 0); ***/ 4753 flush_block_only(s, false); 4754 if (s.strm.avail_out === 0) { 4755 return BS_NEED_MORE; 4756 } 4757 /***/ 4758 } 4759 4760 } else if (s.match_available) { 4761 /* If there was no match at the previous position, output a 4762 * single literal. If there was a match but the current match 4763 * is longer, truncate the previous match to a single literal. 4764 */ 4765 //Tracevv((stderr,"%c", s->window[s->strstart-1])); 4766 /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ 4767 bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]); 4768 4769 if (bflush) { 4770 /*** FLUSH_BLOCK_ONLY(s, 0) ***/ 4771 flush_block_only(s, false); 4772 /***/ 4773 } 4774 s.strstart++; 4775 s.lookahead--; 4776 if (s.strm.avail_out === 0) { 4777 return BS_NEED_MORE; 4778 } 4779 } else { 4780 /* There is no previous match to compare with, wait for 4781 * the next step to decide. 4782 */ 4783 s.match_available = 1; 4784 s.strstart++; 4785 s.lookahead--; 4786 } 4787 } 4788 //Assert (flush != Z_NO_FLUSH, "no flush?"); 4789 if (s.match_available) { 4790 //Tracevv((stderr,"%c", s->window[s->strstart-1])); 4791 /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ 4792 bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]); 4793 4794 s.match_available = 0; 4795 } 4796 s.insert = s.strstart < MIN_MATCH-1 ? s.strstart : MIN_MATCH-1; 4797 if (flush === Z_FINISH) { 4798 /*** FLUSH_BLOCK(s, 1); ***/ 4799 flush_block_only(s, true); 4800 if (s.strm.avail_out === 0) { 4801 return BS_FINISH_STARTED; 4802 } 4803 /***/ 4804 return BS_FINISH_DONE; 4805 } 4806 if (s.last_lit) { 4807 /*** FLUSH_BLOCK(s, 0); ***/ 4808 flush_block_only(s, false); 4809 if (s.strm.avail_out === 0) { 4810 return BS_NEED_MORE; 4811 } 4812 /***/ 4813 } 4814 4815 return BS_BLOCK_DONE; 4816} 4817 4818 4819/* =========================================================================== 4820 * For Z_RLE, simply look for runs of bytes, generate matches only of distance 4821 * one. Do not maintain a hash table. (It will be regenerated if this run of 4822 * deflate switches away from Z_RLE.) 4823 */ 4824function deflate_rle(s, flush) { 4825 var bflush; /* set if current block must be flushed */ 4826 var prev; /* byte at distance one to match */ 4827 var scan, strend; /* scan goes up to strend for length of run */ 4828 4829 var _win = s.window; 4830 4831 for (;;) { 4832 /* Make sure that we always have enough lookahead, except 4833 * at the end of the input file. We need MAX_MATCH bytes 4834 * for the longest run, plus one for the unrolled loop. 4835 */ 4836 if (s.lookahead <= MAX_MATCH) { 4837 fill_window(s); 4838 if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) { 4839 return BS_NEED_MORE; 4840 } 4841 if (s.lookahead === 0) { break; } /* flush the current block */ 4842 } 4843 4844 /* See how many times the previous byte repeats */ 4845 s.match_length = 0; 4846 if (s.lookahead >= MIN_MATCH && s.strstart > 0) { 4847 scan = s.strstart - 1; 4848 prev = _win[scan]; 4849 if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) { 4850 strend = s.strstart + MAX_MATCH; 4851 do { 4852 /*jshint noempty:false*/ 4853 } while (prev === _win[++scan] && prev === _win[++scan] && 4854 prev === _win[++scan] && prev === _win[++scan] && 4855 prev === _win[++scan] && prev === _win[++scan] && 4856 prev === _win[++scan] && prev === _win[++scan] && 4857 scan < strend); 4858 s.match_length = MAX_MATCH - (strend - scan); 4859 if (s.match_length > s.lookahead) { 4860 s.match_length = s.lookahead; 4861 } 4862 } 4863 //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); 4864 } 4865 4866 /* Emit match if have run of MIN_MATCH or longer, else emit literal */ 4867 if (s.match_length >= MIN_MATCH) { 4868 //check_match(s, s.strstart, s.strstart - 1, s.match_length); 4869 4870 /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/ 4871 bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH); 4872 4873 s.lookahead -= s.match_length; 4874 s.strstart += s.match_length; 4875 s.match_length = 0; 4876 } else { 4877 /* No match, output a literal byte */ 4878 //Tracevv((stderr,"%c", s->window[s->strstart])); 4879 /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ 4880 bflush = trees._tr_tally(s, 0, s.window[s.strstart]); 4881 4882 s.lookahead--; 4883 s.strstart++; 4884 } 4885 if (bflush) { 4886 /*** FLUSH_BLOCK(s, 0); ***/ 4887 flush_block_only(s, false); 4888 if (s.strm.avail_out === 0) { 4889 return BS_NEED_MORE; 4890 } 4891 /***/ 4892 } 4893 } 4894 s.insert = 0; 4895 if (flush === Z_FINISH) { 4896 /*** FLUSH_BLOCK(s, 1); ***/ 4897 flush_block_only(s, true); 4898 if (s.strm.avail_out === 0) { 4899 return BS_FINISH_STARTED; 4900 } 4901 /***/ 4902 return BS_FINISH_DONE; 4903 } 4904 if (s.last_lit) { 4905 /*** FLUSH_BLOCK(s, 0); ***/ 4906 flush_block_only(s, false); 4907 if (s.strm.avail_out === 0) { 4908 return BS_NEED_MORE; 4909 } 4910 /***/ 4911 } 4912 return BS_BLOCK_DONE; 4913} 4914 4915/* =========================================================================== 4916 * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. 4917 * (It will be regenerated if this run of deflate switches away from Huffman.) 4918 */ 4919function deflate_huff(s, flush) { 4920 var bflush; /* set if current block must be flushed */ 4921 4922 for (;;) { 4923 /* Make sure that we have a literal to write. */ 4924 if (s.lookahead === 0) { 4925 fill_window(s); 4926 if (s.lookahead === 0) { 4927 if (flush === Z_NO_FLUSH) { 4928 return BS_NEED_MORE; 4929 } 4930 break; /* flush the current block */ 4931 } 4932 } 4933 4934 /* Output a literal byte */ 4935 s.match_length = 0; 4936 //Tracevv((stderr,"%c", s->window[s->strstart])); 4937 /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ 4938 bflush = trees._tr_tally(s, 0, s.window[s.strstart]); 4939 s.lookahead--; 4940 s.strstart++; 4941 if (bflush) { 4942 /*** FLUSH_BLOCK(s, 0); ***/ 4943 flush_block_only(s, false); 4944 if (s.strm.avail_out === 0) { 4945 return BS_NEED_MORE; 4946 } 4947 /***/ 4948 } 4949 } 4950 s.insert = 0; 4951 if (flush === Z_FINISH) { 4952 /*** FLUSH_BLOCK(s, 1); ***/ 4953 flush_block_only(s, true); 4954 if (s.strm.avail_out === 0) { 4955 return BS_FINISH_STARTED; 4956 } 4957 /***/ 4958 return BS_FINISH_DONE; 4959 } 4960 if (s.last_lit) { 4961 /*** FLUSH_BLOCK(s, 0); ***/ 4962 flush_block_only(s, false); 4963 if (s.strm.avail_out === 0) { 4964 return BS_NEED_MORE; 4965 } 4966 /***/ 4967 } 4968 return BS_BLOCK_DONE; 4969} 4970 4971/* Values for max_lazy_match, good_match and max_chain_length, depending on 4972 * the desired pack level (0..9). The values given below have been tuned to 4973 * exclude worst case performance for pathological files. Better values may be 4974 * found for specific files. 4975 */ 4976var Config = function (good_length, max_lazy, nice_length, max_chain, func) { 4977 this.good_length = good_length; 4978 this.max_lazy = max_lazy; 4979 this.nice_length = nice_length; 4980 this.max_chain = max_chain; 4981 this.func = func; 4982}; 4983 4984var configuration_table; 4985 4986configuration_table = [ 4987 /* good lazy nice chain */ 4988 new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */ 4989 new Config(4, 4, 8, 4, deflate_fast), /* 1 max speed, no lazy matches */ 4990 new Config(4, 5, 16, 8, deflate_fast), /* 2 */ 4991 new Config(4, 6, 32, 32, deflate_fast), /* 3 */ 4992 4993 new Config(4, 4, 16, 16, deflate_slow), /* 4 lazy matches */ 4994 new Config(8, 16, 32, 32, deflate_slow), /* 5 */ 4995 new Config(8, 16, 128, 128, deflate_slow), /* 6 */ 4996 new Config(8, 32, 128, 256, deflate_slow), /* 7 */ 4997 new Config(32, 128, 258, 1024, deflate_slow), /* 8 */ 4998 new Config(32, 258, 258, 4096, deflate_slow) /* 9 max compression */ 4999]; 5000 5001 5002/* =========================================================================== 5003 * Initialize the "longest match" routines for a new zlib stream 5004 */ 5005function lm_init(s) { 5006 s.window_size = 2 * s.w_size; 5007 5008 /*** CLEAR_HASH(s); ***/ 5009 zero(s.head); // Fill with NIL (= 0); 5010 5011 /* Set the default configuration parameters: 5012 */ 5013 s.max_lazy_match = configuration_table[s.level].max_lazy; 5014 s.good_match = configuration_table[s.level].good_length; 5015 s.nice_match = configuration_table[s.level].nice_length; 5016 s.max_chain_length = configuration_table[s.level].max_chain; 5017 5018 s.strstart = 0; 5019 s.block_start = 0; 5020 s.lookahead = 0; 5021 s.insert = 0; 5022 s.match_length = s.prev_length = MIN_MATCH - 1; 5023 s.match_available = 0; 5024 s.ins_h = 0; 5025} 5026 5027 5028function DeflateState() { 5029 this.strm = null; /* pointer back to this zlib stream */ 5030 this.status = 0; /* as the name implies */ 5031 this.pending_buf = null; /* output still pending */ 5032 this.pending_buf_size = 0; /* size of pending_buf */ 5033 this.pending_out = 0; /* next pending byte to output to the stream */ 5034 this.pending = 0; /* nb of bytes in the pending buffer */ 5035 this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ 5036 this.gzhead = null; /* gzip header information to write */ 5037 this.gzindex = 0; /* where in extra, name, or comment */ 5038 this.method = Z_DEFLATED; /* can only be DEFLATED */ 5039 this.last_flush = -1; /* value of flush param for previous deflate call */ 5040 5041 this.w_size = 0; /* LZ77 window size (32K by default) */ 5042 this.w_bits = 0; /* log2(w_size) (8..16) */ 5043 this.w_mask = 0; /* w_size - 1 */ 5044 5045 this.window = null; 5046 /* Sliding window. Input bytes are read into the second half of the window, 5047 * and move to the first half later to keep a dictionary of at least wSize 5048 * bytes. With this organization, matches are limited to a distance of 5049 * wSize-MAX_MATCH bytes, but this ensures that IO is always 5050 * performed with a length multiple of the block size. 5051 */ 5052 5053 this.window_size = 0; 5054 /* Actual size of window: 2*wSize, except when the user input buffer 5055 * is directly used as sliding window. 5056 */ 5057 5058 this.prev = null; 5059 /* Link to older string with same hash index. To limit the size of this 5060 * array to 64K, this link is maintained only for the last 32K strings. 5061 * An index in this array is thus a window index modulo 32K. 5062 */ 5063 5064 this.head = null; /* Heads of the hash chains or NIL. */ 5065 5066 this.ins_h = 0; /* hash index of string to be inserted */ 5067 this.hash_size = 0; /* number of elements in hash table */ 5068 this.hash_bits = 0; /* log2(hash_size) */ 5069 this.hash_mask = 0; /* hash_size-1 */ 5070 5071 this.hash_shift = 0; 5072 /* Number of bits by which ins_h must be shifted at each input 5073 * step. It must be such that after MIN_MATCH steps, the oldest 5074 * byte no longer takes part in the hash key, that is: 5075 * hash_shift * MIN_MATCH >= hash_bits 5076 */ 5077 5078 this.block_start = 0; 5079 /* Window position at the beginning of the current output block. Gets 5080 * negative when the window is moved backwards. 5081 */ 5082 5083 this.match_length = 0; /* length of best match */ 5084 this.prev_match = 0; /* previous match */ 5085 this.match_available = 0; /* set if previous match exists */ 5086 this.strstart = 0; /* start of string to insert */ 5087 this.match_start = 0; /* start of matching string */ 5088 this.lookahead = 0; /* number of valid bytes ahead in window */ 5089 5090 this.prev_length = 0; 5091 /* Length of the best match at previous step. Matches not greater than this 5092 * are discarded. This is used in the lazy match evaluation. 5093 */ 5094 5095 this.max_chain_length = 0; 5096 /* To speed up deflation, hash chains are never searched beyond this 5097 * length. A higher limit improves compression ratio but degrades the 5098 * speed. 5099 */ 5100 5101 this.max_lazy_match = 0; 5102 /* Attempt to find a better match only when the current match is strictly 5103 * smaller than this value. This mechanism is used only for compression 5104 * levels >= 4. 5105 */ 5106 // That's alias to max_lazy_match, don't use directly 5107 //this.max_insert_length = 0; 5108 /* Insert new strings in the hash table only if the match length is not 5109 * greater than this length. This saves time but degrades compression. 5110 * max_insert_length is used only for compression levels <= 3. 5111 */ 5112 5113 this.level = 0; /* compression level (1..9) */ 5114 this.strategy = 0; /* favor or force Huffman coding*/ 5115 5116 this.good_match = 0; 5117 /* Use a faster search when the previous match is longer than this */ 5118 5119 this.nice_match = 0; /* Stop searching when current match exceeds this */ 5120 5121 /* used by trees.c: */ 5122 5123 /* Didn't use ct_data typedef below to suppress compiler warning */ 5124 5125 // struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ 5126 // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ 5127 // struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ 5128 5129 // Use flat array of DOUBLE size, with interleaved fata, 5130 // because JS does not support effective 5131 this.dyn_ltree = new utils.Buf16(HEAP_SIZE * 2); 5132 this.dyn_dtree = new utils.Buf16((2*D_CODES+1) * 2); 5133 this.bl_tree = new utils.Buf16((2*BL_CODES+1) * 2); 5134 zero(this.dyn_ltree); 5135 zero(this.dyn_dtree); 5136 zero(this.bl_tree); 5137 5138 this.l_desc = null; /* desc. for literal tree */ 5139 this.d_desc = null; /* desc. for distance tree */ 5140 this.bl_desc = null; /* desc. for bit length tree */ 5141 5142 //ush bl_count[MAX_BITS+1]; 5143 this.bl_count = new utils.Buf16(MAX_BITS+1); 5144 /* number of codes at each bit length for an optimal tree */ 5145 5146 //int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ 5147 this.heap = new utils.Buf16(2*L_CODES+1); /* heap used to build the Huffman trees */ 5148 zero(this.heap); 5149 5150 this.heap_len = 0; /* number of elements in the heap */ 5151 this.heap_max = 0; /* element of largest frequency */ 5152 /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. 5153 * The same heap array is used to build all trees. 5154 */ 5155 5156 this.depth = new utils.Buf16(2*L_CODES+1); //uch depth[2*L_CODES+1]; 5157 zero(this.depth); 5158 /* Depth of each subtree used as tie breaker for trees of equal frequency 5159 */ 5160 5161 this.l_buf = 0; /* buffer index for literals or lengths */ 5162 5163 this.lit_bufsize = 0; 5164 /* Size of match buffer for literals/lengths. There are 4 reasons for 5165 * limiting lit_bufsize to 64K: 5166 * - frequencies can be kept in 16 bit counters 5167 * - if compression is not successful for the first block, all input 5168 * data is still in the window so we can still emit a stored block even 5169 * when input comes from standard input. (This can also be done for 5170 * all blocks if lit_bufsize is not greater than 32K.) 5171 * - if compression is not successful for a file smaller than 64K, we can 5172 * even emit a stored file instead of a stored block (saving 5 bytes). 5173 * This is applicable only for zip (not gzip or zlib). 5174 * - creating new Huffman trees less frequently may not provide fast 5175 * adaptation to changes in the input data statistics. (Take for 5176 * example a binary file with poorly compressible code followed by
vendor: 3,610 bytes, lines 5177-5317
5177 * a highly compressible string table.) Smaller buffer sizes give 5178 * fast adaptation but have of course the overhead of transmitting 5179 * trees more frequently. 5180 * - I can't count above 4 5181 */ 5182 5183 this.last_lit = 0; /* running index in l_buf */ 5184 5185 this.d_buf = 0; 5186 /* Buffer index for distances. To simplify the code, d_buf and l_buf have 5187 * the same number of elements. To use different lengths, an extra flag 5188 * array would be necessary. 5189 */ 5190 5191 this.opt_len = 0; /* bit length of current block with optimal trees */ 5192 this.static_len = 0; /* bit length of current block with static trees */ 5193 this.matches = 0; /* number of string matches in current block */ 5194 this.insert = 0; /* bytes at end of window left to insert */ 5195 5196 5197 this.bi_buf = 0; 5198 /* Output buffer. bits are inserted starting at the bottom (least 5199 * significant bits). 5200 */ 5201 this.bi_valid = 0; 5202 /* Number of valid bits in bi_buf. All bits above the last valid bit 5203 * are always zero. 5204 */ 5205 5206 // Used for window memory init. We safely ignore it for JS. That makes 5207 // sense only for pointers and memory check tools. 5208 //this.high_water = 0; 5209 /* High water mark offset in window for initialized bytes -- bytes above 5210 * this are set to zero in order to avoid memory check warnings when 5211 * longest match routines access bytes past the input. This is then 5212 * updated to the new high water mark. 5213 */ 5214} 5215 5216 5217function deflateResetKeep(strm) { 5218 var s; 5219 5220 if (!strm || !strm.state) { 5221 return err(strm, Z_STREAM_ERROR); 5222 } 5223 5224 strm.total_in = strm.total_out = 0; 5225 strm.data_type = Z_UNKNOWN; 5226 5227 s = strm.state; 5228 s.pending = 0; 5229 s.pending_out = 0; 5230 5231 if (s.wrap < 0) { 5232 s.wrap = -s.wrap; 5233 /* was made negative by deflate(..., Z_FINISH); */ 5234 } 5235 s.status = (s.wrap ? INIT_STATE : BUSY_STATE); 5236 strm.adler = (s.wrap === 2) ? 5237 0 // crc32(0, Z_NULL, 0) 5238 : 5239 1; // adler32(0, Z_NULL, 0) 5240 s.last_flush = Z_NO_FLUSH; 5241 trees._tr_init(s); 5242 return Z_OK; 5243} 5244 5245 5246function deflateReset(strm) { 5247 var ret = deflateResetKeep(strm); 5248 if (ret === Z_OK) { 5249 lm_init(strm.state); 5250 } 5251 return ret; 5252} 5253 5254 5255function deflateSetHeader(strm, head) { 5256 if (!strm || !strm.state) { return Z_STREAM_ERROR; } 5257 if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; } 5258 strm.state.gzhead = head; 5259 return Z_OK; 5260} 5261 5262 5263function deflateInit2(strm, level, method, windowBits, memLevel, strategy) { 5264 if (!strm) { // === Z_NULL 5265 return Z_STREAM_ERROR; 5266 } 5267 var wrap = 1; 5268 5269 if (level === Z_DEFAULT_COMPRESSION) { 5270 level = 6; 5271 } 5272 5273 if (windowBits < 0) { /* suppress zlib wrapper */ 5274 wrap = 0; 5275 windowBits = -windowBits; 5276 } 5277 5278 else if (windowBits > 15) { 5279 wrap = 2; /* write gzip wrapper instead */ 5280 windowBits -= 16; 5281 } 5282 5283 5284 if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED || 5285 windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || 5286 strategy < 0 || strategy > Z_FIXED) { 5287 return err(strm, Z_STREAM_ERROR); 5288 } 5289 5290 5291 if (windowBits === 8) { 5292 windowBits = 9; 5293 } 5294 /* until 256-byte window bug fixed */ 5295 5296 var s = new DeflateState(); 5297 5298 strm.state = s; 5299 s.strm = strm; 5300 5301 s.wrap = wrap; 5302 s.gzhead = null; 5303 s.w_bits = windowBits; 5304 s.w_size = 1 << s.w_bits; 5305 s.w_mask = s.w_size - 1; 5306 5307 s.hash_bits = memLevel + 7; 5308 s.hash_size = 1 << s.hash_bits; 5309 s.hash_mask = s.hash_size - 1; 5310 s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH); 5311 5312 s.window = new utils.Buf8(s.w_size * 2); 5313 s.head = new utils.Buf16(s.hash_size); 5314 s.prev = new utils.Buf16(s.w_size); 5315 5316 // Don't need mem init magic for JS. 5317 //s.high_water = 0;
vendor: 12,835 bytes, lines 5317-5742
5317 /* nothing written to s->window yet */ 5318 5319 s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ 5320 5321 s.pending_buf_size = s.lit_bufsize * 4; 5322 s.pending_buf = new utils.Buf8(s.pending_buf_size); 5323 5324 s.d_buf = s.lit_bufsize >> 1; 5325 s.l_buf = (1 + 2) * s.lit_bufsize; 5326 5327 s.level = level; 5328 s.strategy = strategy; 5329 s.method = method; 5330 5331 return deflateReset(strm); 5332} 5333 5334function deflateInit(strm, level) { 5335 return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); 5336} 5337 5338 5339function deflate(strm, flush) { 5340 var old_flush, s; 5341 var beg, val; // for gzip header write only 5342 5343 if (!strm || !strm.state || 5344 flush > Z_BLOCK || flush < 0) { 5345 return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR; 5346 } 5347 5348 s = strm.state; 5349 5350 if (!strm.output || 5351 (!strm.input && strm.avail_in !== 0) || 5352 (s.status === FINISH_STATE && flush !== Z_FINISH)) { 5353 return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR); 5354 } 5355 5356 s.strm = strm; /* just in case */ 5357 old_flush = s.last_flush; 5358 s.last_flush = flush; 5359 5360 /* Write the header */ 5361 if (s.status === INIT_STATE) { 5362 5363 if (s.wrap === 2) { // GZIP header 5364 strm.adler = 0; //crc32(0L, Z_NULL, 0); 5365 put_byte(s, 31); 5366 put_byte(s, 139); 5367 put_byte(s, 8); 5368 if (!s.gzhead) { // s->gzhead == Z_NULL 5369 put_byte(s, 0); 5370 put_byte(s, 0); 5371 put_byte(s, 0); 5372 put_byte(s, 0); 5373 put_byte(s, 0); 5374 put_byte(s, s.level === 9 ? 2 : 5375 (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? 5376 4 : 0)); 5377 put_byte(s, OS_CODE); 5378 s.status = BUSY_STATE; 5379 } 5380 else { 5381 put_byte(s, (s.gzhead.text ? 1 : 0) + 5382 (s.gzhead.hcrc ? 2 : 0) + 5383 (!s.gzhead.extra ? 0 : 4) + 5384 (!s.gzhead.name ? 0 : 8) + 5385 (!s.gzhead.comment ? 0 : 16) 5386 ); 5387 put_byte(s, s.gzhead.time & 0xff); 5388 put_byte(s, (s.gzhead.time >> 8) & 0xff); 5389 put_byte(s, (s.gzhead.time >> 16) & 0xff); 5390 put_byte(s, (s.gzhead.time >> 24) & 0xff); 5391 put_byte(s, s.level === 9 ? 2 : 5392 (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? 5393 4 : 0)); 5394 put_byte(s, s.gzhead.os & 0xff); 5395 if (s.gzhead.extra && s.gzhead.extra.length) { 5396 put_byte(s, s.gzhead.extra.length & 0xff); 5397 put_byte(s, (s.gzhead.extra.length >> 8) & 0xff); 5398 } 5399 if (s.gzhead.hcrc) { 5400 strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0); 5401 } 5402 s.gzindex = 0; 5403 s.status = EXTRA_STATE; 5404 } 5405 } 5406 else // DEFLATE header 5407 { 5408 var header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8; 5409 var level_flags = -1; 5410 5411 if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) { 5412 level_flags = 0; 5413 } else if (s.level < 6) { 5414 level_flags = 1; 5415 } else if (s.level === 6) { 5416 level_flags = 2; 5417 } else { 5418 level_flags = 3; 5419 } 5420 header |= (level_flags << 6); 5421 if (s.strstart !== 0) { header |= PRESET_DICT; } 5422 header += 31 - (header % 31); 5423 5424 s.status = BUSY_STATE; 5425 putShortMSB(s, header); 5426 5427 /* Save the adler32 of the preset dictionary: */ 5428 if (s.strstart !== 0) { 5429 putShortMSB(s, strm.adler >>> 16); 5430 putShortMSB(s, strm.adler & 0xffff); 5431 } 5432 strm.adler = 1; // adler32(0L, Z_NULL, 0); 5433 } 5434 } 5435 5436//#ifdef GZIP 5437 if (s.status === EXTRA_STATE) { 5438 if (s.gzhead.extra/* != Z_NULL*/) { 5439 beg = s.pending; /* start of bytes to update crc */ 5440 5441 while (s.gzindex < (s.gzhead.extra.length & 0xffff)) { 5442 if (s.pending === s.pending_buf_size) { 5443 if (s.gzhead.hcrc && s.pending > beg) { 5444 strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); 5445 } 5446 flush_pending(strm); 5447 beg = s.pending; 5448 if (s.pending === s.pending_buf_size) { 5449 break; 5450 } 5451 } 5452 put_byte(s, s.gzhead.extra[s.gzindex] & 0xff); 5453 s.gzindex++; 5454 } 5455 if (s.gzhead.hcrc && s.pending > beg) { 5456 strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); 5457 } 5458 if (s.gzindex === s.gzhead.extra.length) { 5459 s.gzindex = 0; 5460 s.status = NAME_STATE; 5461 } 5462 } 5463 else { 5464 s.status = NAME_STATE; 5465 } 5466 } 5467 if (s.status === NAME_STATE) { 5468 if (s.gzhead.name/* != Z_NULL*/) { 5469 beg = s.pending; /* start of bytes to update crc */ 5470 //int val; 5471 5472 do { 5473 if (s.pending === s.pending_buf_size) { 5474 if (s.gzhead.hcrc && s.pending > beg) { 5475 strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); 5476 } 5477 flush_pending(strm); 5478 beg = s.pending; 5479 if (s.pending === s.pending_buf_size) { 5480 val = 1; 5481 break; 5482 } 5483 } 5484 // JS specific: little magic to add zero terminator to end of string 5485 if (s.gzindex < s.gzhead.name.length) { 5486 val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff; 5487 } else { 5488 val = 0; 5489 } 5490 put_byte(s, val); 5491 } while (val !== 0); 5492 5493 if (s.gzhead.hcrc && s.pending > beg){ 5494 strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); 5495 } 5496 if (val === 0) { 5497 s.gzindex = 0; 5498 s.status = COMMENT_STATE; 5499 } 5500 } 5501 else { 5502 s.status = COMMENT_STATE; 5503 } 5504 } 5505 if (s.status === COMMENT_STATE) { 5506 if (s.gzhead.comment/* != Z_NULL*/) { 5507 beg = s.pending; /* start of bytes to update crc */ 5508 //int val; 5509 5510 do { 5511 if (s.pending === s.pending_buf_size) { 5512 if (s.gzhead.hcrc && s.pending > beg) { 5513 strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); 5514 } 5515 flush_pending(strm); 5516 beg = s.pending; 5517 if (s.pending === s.pending_buf_size) { 5518 val = 1; 5519 break; 5520 } 5521 } 5522 // JS specific: little magic to add zero terminator to end of string 5523 if (s.gzindex < s.gzhead.comment.length) { 5524 val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff; 5525 } else { 5526 val = 0; 5527 } 5528 put_byte(s, val); 5529 } while (val !== 0); 5530 5531 if (s.gzhead.hcrc && s.pending > beg) { 5532 strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); 5533 } 5534 if (val === 0) { 5535 s.status = HCRC_STATE; 5536 } 5537 } 5538 else { 5539 s.status = HCRC_STATE; 5540 } 5541 } 5542 if (s.status === HCRC_STATE) { 5543 if (s.gzhead.hcrc) { 5544 if (s.pending + 2 > s.pending_buf_size) { 5545 flush_pending(strm); 5546 } 5547 if (s.pending + 2 <= s.pending_buf_size) { 5548 put_byte(s, strm.adler & 0xff); 5549 put_byte(s, (strm.adler >> 8) & 0xff); 5550 strm.adler = 0; //crc32(0L, Z_NULL, 0); 5551 s.status = BUSY_STATE; 5552 } 5553 } 5554 else { 5555 s.status = BUSY_STATE; 5556 } 5557 } 5558//#endif 5559 5560 /* Flush as much pending output as possible */ 5561 if (s.pending !== 0) { 5562 flush_pending(strm); 5563 if (strm.avail_out === 0) { 5564 /* Since avail_out is 0, deflate will be called again with 5565 * more output space, but possibly with both pending and 5566 * avail_in equal to zero. There won't be anything to do, 5567 * but this is not an error situation so make sure we 5568 * return OK instead of BUF_ERROR at next call of deflate: 5569 */ 5570 s.last_flush = -1; 5571 return Z_OK; 5572 } 5573 5574 /* Make sure there is something to do and avoid duplicate consecutive 5575 * flushes. For repeated and useless calls with Z_FINISH, we keep 5576 * returning Z_STREAM_END instead of Z_BUF_ERROR. 5577 */ 5578 } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) && 5579 flush !== Z_FINISH) { 5580 return err(strm, Z_BUF_ERROR); 5581 } 5582 5583 /* User must not provide more input after the first FINISH: */ 5584 if (s.status === FINISH_STATE && strm.avail_in !== 0) { 5585 return err(strm, Z_BUF_ERROR); 5586 } 5587 5588 /* Start a new block or continue the current one. 5589 */ 5590 if (strm.avail_in !== 0 || s.lookahead !== 0 || 5591 (flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) { 5592 var bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) : 5593 (s.strategy === Z_RLE ? deflate_rle(s, flush) : 5594 configuration_table[s.level].func(s, flush)); 5595 5596 if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) { 5597 s.status = FINISH_STATE; 5598 } 5599 if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) { 5600 if (strm.avail_out === 0) { 5601 s.last_flush = -1; 5602 /* avoid BUF_ERROR next call, see above */ 5603 } 5604 return Z_OK; 5605 /* If flush != Z_NO_FLUSH && avail_out == 0, the next call 5606 * of deflate should use the same flush parameter to make sure 5607 * that the flush is complete. So we don't have to output an 5608 * empty block here, this will be done at next call. This also 5609 * ensures that for a very small output buffer, we emit at most 5610 * one empty block. 5611 */ 5612 } 5613 if (bstate === BS_BLOCK_DONE) { 5614 if (flush === Z_PARTIAL_FLUSH) { 5615 trees._tr_align(s); 5616 } 5617 else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ 5618 5619 trees._tr_stored_block(s, 0, 0, false); 5620 /* For a full flush, this empty block will be recognized 5621 * as a special marker by inflate_sync(). 5622 */ 5623 if (flush === Z_FULL_FLUSH) { 5624 /*** CLEAR_HASH(s); ***/ /* forget history */ 5625 zero(s.head); // Fill with NIL (= 0); 5626 5627 if (s.lookahead === 0) { 5628 s.strstart = 0; 5629 s.block_start = 0; 5630 s.insert = 0; 5631 } 5632 } 5633 } 5634 flush_pending(strm); 5635 if (strm.avail_out === 0) { 5636 s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */ 5637 return Z_OK; 5638 } 5639 } 5640 } 5641 //Assert(strm->avail_out > 0, "bug2"); 5642 //if (strm.avail_out <= 0) { throw new Error("bug2");} 5643 5644 if (flush !== Z_FINISH) { return Z_OK; } 5645 if (s.wrap <= 0) { return Z_STREAM_END; } 5646 5647 /* Write the trailer */ 5648 if (s.wrap === 2) { 5649 put_byte(s, strm.adler & 0xff); 5650 put_byte(s, (strm.adler >> 8) & 0xff); 5651 put_byte(s, (strm.adler >> 16) & 0xff); 5652 put_byte(s, (strm.adler >> 24) & 0xff); 5653 put_byte(s, strm.total_in & 0xff); 5654 put_byte(s, (strm.total_in >> 8) & 0xff); 5655 put_byte(s, (strm.total_in >> 16) & 0xff); 5656 put_byte(s, (strm.total_in >> 24) & 0xff); 5657 } 5658 else 5659 { 5660 putShortMSB(s, strm.adler >>> 16); 5661 putShortMSB(s, strm.adler & 0xffff); 5662 } 5663 5664 flush_pending(strm); 5665 /* If avail_out is zero, the application will call deflate again 5666 * to flush the rest. 5667 */ 5668 if (s.wrap > 0) { s.wrap = -s.wrap; } 5669 /* write the trailer only once! */ 5670 return s.pending !== 0 ? Z_OK : Z_STREAM_END; 5671} 5672 5673function deflateEnd(strm) { 5674 var status; 5675 5676 if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) { 5677 return Z_STREAM_ERROR; 5678 } 5679 5680 status = strm.state.status; 5681 if (status !== INIT_STATE && 5682 status !== EXTRA_STATE && 5683 status !== NAME_STATE && 5684 status !== COMMENT_STATE && 5685 status !== HCRC_STATE && 5686 status !== BUSY_STATE && 5687 status !== FINISH_STATE 5688 ) { 5689 return err(strm, Z_STREAM_ERROR); 5690 } 5691 5692 strm.state = null; 5693 5694 return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK; 5695} 5696 5697/* ========================================================================= 5698 * Copy the source state to the destination state 5699 */ 5700//function deflateCopy(dest, source) { 5701// 5702//} 5703 5704exports.deflateInit = deflateInit; 5705exports.deflateInit2 = deflateInit2; 5706exports.deflateReset = deflateReset; 5707exports.deflateResetKeep = deflateResetKeep; 5708exports.deflateSetHeader = deflateSetHeader; 5709exports.deflate = deflate; 5710exports.deflateEnd = deflateEnd; 5711exports.deflateInfo = 'pako deflate (from Nodeca project)'; 5712 5713/* Not implemented 5714exports.deflateBound = deflateBound; 5715exports.deflateCopy = deflateCopy; 5716exports.deflateSetDictionary = deflateSetDictionary; 5717exports.deflateParams = deflateParams; 5718exports.deflatePending = deflatePending; 5719exports.deflatePrime = deflatePrime; 5720exports.deflateTune = deflateTune; 5721*/ 5722},{"../utils/common":27,"./adler32":29,"./crc32":31,"./messages":37,"./trees":38}],33:[function(_dereq_,module,exports){ 5723'use strict'; 5724 5725 5726function GZheader() { 5727 /* true if compressed data believed to be text */ 5728 this.text = 0; 5729 /* modification time */ 5730 this.time = 0; 5731 /* extra flags (not used when writing a gzip file) */ 5732 this.xflags = 0; 5733 /* operating system */ 5734 this.os = 0; 5735 /* pointer to extra field or Z_NULL if none */ 5736 this.extra = null; 5737 /* extra field length (valid if extra != Z_NULL) */ 5738 this.extra_len = 0; // Actually, we don't need it in JS, 5739 // but leave for few code modifications 5740 5741 // 5742 // Setup limits is not necessary because in js we should not preallocate memory
5742
vendor: 110,633 bytes, lines 5742-9167
5742 5743 // for inflate use constant limit in 65536 bytes 5744 // 5745 5746 /* space at extra (only when reading header) */ 5747 // this.extra_max = 0; 5748 /* pointer to zero-terminated file name or Z_NULL */ 5749 this.name = ''; 5750 /* space at name (only when reading header) */ 5751 // this.name_max = 0; 5752 /* pointer to zero-terminated comment or Z_NULL */ 5753 this.comment = ''; 5754 /* space at comment (only when reading header) */ 5755 // this.comm_max = 0; 5756 /* true if there was or will be a header crc */ 5757 this.hcrc = 0; 5758 /* true when done reading gzip header (not used when writing a gzip file) */ 5759 this.done = false; 5760} 5761 5762module.exports = GZheader; 5763},{}],34:[function(_dereq_,module,exports){ 5764'use strict'; 5765 5766// See state defs from inflate.js 5767var BAD = 30; /* got a data error -- remain here until reset */ 5768var TYPE = 12; /* i: waiting for type bits, including last-flag bit */ 5769 5770/* 5771 Decode literal, length, and distance codes and write out the resulting 5772 literal and match bytes until either not enough input or output is 5773 available, an end-of-block is encountered, or a data error is encountered. 5774 When large enough input and output buffers are supplied to inflate(), for 5775 example, a 16K input buffer and a 64K output buffer, more than 95% of the 5776 inflate execution time is spent in this routine. 5777 5778 Entry assumptions: 5779 5780 state.mode === LEN 5781 strm.avail_in >= 6 5782 strm.avail_out >= 258 5783 start >= strm.avail_out 5784 state.bits < 8 5785 5786 On return, state.mode is one of: 5787 5788 LEN -- ran out of enough output space or enough available input 5789 TYPE -- reached end of block code, inflate() to interpret next block 5790 BAD -- error in block data 5791 5792 Notes: 5793 5794 - The maximum input bits used by a length/distance pair is 15 bits for the 5795 length code, 5 bits for the length extra, 15 bits for the distance code, 5796 and 13 bits for the distance extra. This totals 48 bits, or six bytes. 5797 Therefore if strm.avail_in >= 6, then there is enough input to avoid 5798 checking for available input while decoding. 5799 5800 - The maximum bytes that a single length/distance pair can output is 258 5801 bytes, which is the maximum length that can be coded. inflate_fast() 5802 requires strm.avail_out >= 258 for each loop to avoid checking for 5803 output space. 5804 */ 5805module.exports = function inflate_fast(strm, start) { 5806 var state; 5807 var _in; /* local strm.input */ 5808 var last; /* have enough input while in < last */ 5809 var _out; /* local strm.output */ 5810 var beg; /* inflate()'s initial strm.output */ 5811 var end; /* while out < end, enough space available */ 5812//#ifdef INFLATE_STRICT 5813 var dmax; /* maximum distance from zlib header */ 5814//#endif 5815 var wsize; /* window size or zero if not using window */ 5816 var whave; /* valid bytes in the window */ 5817 var wnext; /* window write index */ 5818 var window; /* allocated sliding window, if wsize != 0 */ 5819 var hold; /* local strm.hold */ 5820 var bits; /* local strm.bits */ 5821 var lcode; /* local strm.lencode */ 5822 var dcode; /* local strm.distcode */ 5823 var lmask; /* mask for first level of length codes */ 5824 var dmask; /* mask for first level of distance codes */ 5825 var here; /* retrieved table entry */ 5826 var op; /* code bits, operation, extra bits, or */ 5827 /* window position, window bytes to copy */ 5828 var len; /* match length, unused bytes */ 5829 var dist; /* match distance */ 5830 var from; /* where to copy match from */ 5831 var from_source; 5832 5833 5834 var input, output; // JS specific, because we have no pointers 5835 5836 /* copy state to local variables */ 5837 state = strm.state; 5838 //here = state.here; 5839 _in = strm.next_in; 5840 input = strm.input; 5841 last = _in + (strm.avail_in - 5); 5842 _out = strm.next_out; 5843 output = strm.output; 5844 beg = _out - (start - strm.avail_out); 5845 end = _out + (strm.avail_out - 257); 5846//#ifdef INFLATE_STRICT 5847 dmax = state.dmax; 5848//#endif 5849 wsize = state.wsize; 5850 whave = state.whave; 5851 wnext = state.wnext; 5852 window = state.window; 5853 hold = state.hold; 5854 bits = state.bits; 5855 lcode = state.lencode; 5856 dcode = state.distcode; 5857 lmask = (1 << state.lenbits) - 1; 5858 dmask = (1 << state.distbits) - 1; 5859 5860 5861 /* decode literals and length/distances until end-of-block or not enough 5862 input data or output space */ 5863 5864 top: 5865 do { 5866 if (bits < 15) { 5867 hold += input[_in++] << bits; 5868 bits += 8; 5869 hold += input[_in++] << bits; 5870 bits += 8; 5871 } 5872 5873 here = lcode[hold & lmask]; 5874 5875 dolen: 5876 for (;;) { // Goto emulation 5877 op = here >>> 24/*here.bits*/; 5878 hold >>>= op; 5879 bits -= op; 5880 op = (here >>> 16) & 0xff/*here.op*/; 5881 if (op === 0) { /* literal */ 5882 //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? 5883 // "inflate: literal '%c'\n" : 5884 // "inflate: literal 0x%02x\n", here.val)); 5885 output[_out++] = here & 0xffff/*here.val*/; 5886 } 5887 else if (op & 16) { /* length base */ 5888 len = here & 0xffff/*here.val*/; 5889 op &= 15; /* number of extra bits */ 5890 if (op) { 5891 if (bits < op) { 5892 hold += input[_in++] << bits; 5893 bits += 8; 5894 } 5895 len += hold & ((1 << op) - 1); 5896 hold >>>= op; 5897 bits -= op; 5898 } 5899 //Tracevv((stderr, "inflate: length %u\n", len)); 5900 if (bits < 15) { 5901 hold += input[_in++] << bits; 5902 bits += 8; 5903 hold += input[_in++] << bits; 5904 bits += 8; 5905 } 5906 here = dcode[hold & dmask]; 5907 5908 dodist: 5909 for (;;) { // goto emulation 5910 op = here >>> 24/*here.bits*/; 5911 hold >>>= op; 5912 bits -= op; 5913 op = (here >>> 16) & 0xff/*here.op*/; 5914 5915 if (op & 16) { /* distance base */ 5916 dist = here & 0xffff/*here.val*/; 5917 op &= 15; /* number of extra bits */ 5918 if (bits < op) { 5919 hold += input[_in++] << bits; 5920 bits += 8; 5921 if (bits < op) { 5922 hold += input[_in++] << bits; 5923 bits += 8; 5924 } 5925 } 5926 dist += hold & ((1 << op) - 1); 5927//#ifdef INFLATE_STRICT 5928 if (dist > dmax) { 5929 strm.msg = 'invalid distance too far back'; 5930 state.mode = BAD; 5931 break top; 5932 } 5933//#endif 5934 hold >>>= op; 5935 bits -= op; 5936 //Tracevv((stderr, "inflate: distance %u\n", dist)); 5937 op = _out - beg; /* max distance in output */ 5938 if (dist > op) { /* see if copy from window */ 5939 op = dist - op; /* distance back in window */ 5940 if (op > whave) { 5941 if (state.sane) { 5942 strm.msg = 'invalid distance too far back'; 5943 state.mode = BAD; 5944 break top; 5945 } 5946 5947// (!) This block is disabled in zlib defailts, 5948// don't enable it for binary compatibility 5949//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR 5950// if (len <= op - whave) { 5951// do { 5952// output[_out++] = 0; 5953// } while (--len); 5954// continue top; 5955// } 5956// len -= op - whave; 5957// do { 5958// output[_out++] = 0; 5959// } while (--op > whave); 5960// if (op === 0) { 5961// from = _out - dist; 5962// do { 5963// output[_out++] = output[from++]; 5964// } while (--len); 5965// continue top; 5966// } 5967//#endif 5968 } 5969 from = 0; // window index 5970 from_source = window; 5971 if (wnext === 0) { /* very common case */ 5972 from += wsize - op; 5973 if (op < len) { /* some from window */ 5974 len -= op; 5975 do { 5976 output[_out++] = window[from++]; 5977 } while (--op); 5978 from = _out - dist; /* rest from output */ 5979 from_source = output; 5980 } 5981 } 5982 else if (wnext < op) { /* wrap around window */ 5983 from += wsize + wnext - op; 5984 op -= wnext; 5985 if (op < len) { /* some from end of window */ 5986 len -= op; 5987 do { 5988 output[_out++] = window[from++]; 5989 } while (--op); 5990 from = 0; 5991 if (wnext < len) { /* some from start of window */ 5992 op = wnext; 5993 len -= op; 5994 do { 5995 output[_out++] = window[from++]; 5996 } while (--op); 5997 from = _out - dist; /* rest from output */ 5998 from_source = output; 5999 } 6000 } 6001 } 6002 else { /* contiguous in window */ 6003 from += wnext - op; 6004 if (op < len) { /* some from window */ 6005 len -= op; 6006 do { 6007 output[_out++] = window[from++]; 6008 } while (--op); 6009 from = _out - dist; /* rest from output */ 6010 from_source = output; 6011 } 6012 } 6013 while (len > 2) { 6014 output[_out++] = from_source[from++]; 6015 output[_out++] = from_source[from++]; 6016 output[_out++] = from_source[from++]; 6017 len -= 3; 6018 } 6019 if (len) { 6020 output[_out++] = from_source[from++]; 6021 if (len > 1) { 6022 output[_out++] = from_source[from++]; 6023 } 6024 } 6025 } 6026 else { 6027 from = _out - dist; /* copy direct from output */ 6028 do { /* minimum length is three */ 6029 output[_out++] = output[from++]; 6030 output[_out++] = output[from++]; 6031 output[_out++] = output[from++]; 6032 len -= 3; 6033 } while (len > 2); 6034 if (len) { 6035 output[_out++] = output[from++]; 6036 if (len > 1) { 6037 output[_out++] = output[from++]; 6038 } 6039 } 6040 } 6041 } 6042 else if ((op & 64) === 0) { /* 2nd level distance code */ 6043 here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; 6044 continue dodist; 6045 } 6046 else { 6047 strm.msg = 'invalid distance code'; 6048 state.mode = BAD; 6049 break top; 6050 } 6051 6052 break; // need to emulate goto via "continue" 6053 } 6054 } 6055 else if ((op & 64) === 0) { /* 2nd level length code */ 6056 here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; 6057 continue dolen; 6058 } 6059 else if (op & 32) { /* end-of-block */ 6060 //Tracevv((stderr, "inflate: end of block\n")); 6061 state.mode = TYPE; 6062 break top; 6063 } 6064 else { 6065 strm.msg = 'invalid literal/length code'; 6066 state.mode = BAD; 6067 break top; 6068 } 6069 6070 break; // need to emulate goto via "continue" 6071 } 6072 } while (_in < last && _out < end); 6073 6074 /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ 6075 len = bits >> 3; 6076 _in -= len; 6077 bits -= len << 3; 6078 hold &= (1 << bits) - 1; 6079 6080 /* update state and return */ 6081 strm.next_in = _in; 6082 strm.next_out = _out; 6083 strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last)); 6084 strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end)); 6085 state.hold = hold; 6086 state.bits = bits; 6087 return; 6088}; 6089 6090},{}],35:[function(_dereq_,module,exports){ 6091'use strict'; 6092 6093 6094var utils = _dereq_('../utils/common'); 6095var adler32 = _dereq_('./adler32'); 6096var crc32 = _dereq_('./crc32'); 6097var inflate_fast = _dereq_('./inffast'); 6098var inflate_table = _dereq_('./inftrees'); 6099 6100var CODES = 0; 6101var LENS = 1; 6102var DISTS = 2; 6103 6104/* Public constants ==========================================================*/ 6105/* ===========================================================================*/ 6106 6107 6108/* Allowed flush values; see deflate() and inflate() below for details */ 6109//var Z_NO_FLUSH = 0; 6110//var Z_PARTIAL_FLUSH = 1; 6111//var Z_SYNC_FLUSH = 2; 6112//var Z_FULL_FLUSH = 3; 6113var Z_FINISH = 4; 6114var Z_BLOCK = 5; 6115var Z_TREES = 6; 6116 6117 6118/* Return codes for the compression/decompression functions. Negative values 6119 * are errors, positive values are used for special but normal events. 6120 */ 6121var Z_OK = 0; 6122var Z_STREAM_END = 1; 6123var Z_NEED_DICT = 2; 6124//var Z_ERRNO = -1; 6125var Z_STREAM_ERROR = -2; 6126var Z_DATA_ERROR = -3; 6127var Z_MEM_ERROR = -4; 6128var Z_BUF_ERROR = -5; 6129//var Z_VERSION_ERROR = -6; 6130 6131/* The deflate compression method */ 6132var Z_DEFLATED = 8; 6133 6134 6135/* STATES ====================================================================*/ 6136/* ===========================================================================*/ 6137 6138 6139var HEAD = 1; /* i: waiting for magic header */ 6140var FLAGS = 2; /* i: waiting for method and flags (gzip) */ 6141var TIME = 3; /* i: waiting for modification time (gzip) */ 6142var OS = 4; /* i: waiting for extra flags and operating system (gzip) */ 6143var EXLEN = 5; /* i: waiting for extra length (gzip) */ 6144var EXTRA = 6; /* i: waiting for extra bytes (gzip) */ 6145var NAME = 7; /* i: waiting for end of file name (gzip) */ 6146var COMMENT = 8; /* i: waiting for end of comment (gzip) */ 6147var HCRC = 9; /* i: waiting for header crc (gzip) */ 6148var DICTID = 10; /* i: waiting for dictionary check value */ 6149var DICT = 11; /* waiting for inflateSetDictionary() call */ 6150var TYPE = 12; /* i: waiting for type bits, including last-flag bit */ 6151var TYPEDO = 13; /* i: same, but skip check to exit inflate on new block */ 6152var STORED = 14; /* i: waiting for stored size (length and complement) */ 6153var COPY_ = 15; /* i/o: same as COPY below, but only first time in */ 6154var COPY = 16; /* i/o: waiting for input or output to copy stored block */ 6155var TABLE = 17; /* i: waiting for dynamic block table lengths */ 6156var LENLENS = 18; /* i: waiting for code length code lengths */ 6157var CODELENS = 19; /* i: waiting for length/lit and distance code lengths */ 6158var LEN_ = 20; /* i: same as LEN below, but only first time in */ 6159var LEN = 21; /* i: waiting for length/lit/eob code */ 6160var LENEXT = 22; /* i: waiting for length extra bits */ 6161var DIST = 23; /* i: waiting for distance code */ 6162var DISTEXT = 24; /* i: waiting for distance extra bits */ 6163var MATCH = 25; /* o: waiting for output space to copy string */ 6164var LIT = 26; /* o: waiting for output space to write literal */ 6165var CHECK = 27; /* i: waiting for 32-bit check value */ 6166var LENGTH = 28; /* i: waiting for 32-bit length (gzip) */ 6167var DONE = 29; /* finished check, done -- remain here until reset */ 6168var BAD = 30; /* got a data error -- remain here until reset */ 6169var MEM = 31; /* got an inflate() memory error -- remain here until reset */ 6170var SYNC = 32; /* looking for synchronization bytes to restart inflate() */ 6171 6172/* ===========================================================================*/ 6173 6174 6175 6176var ENOUGH_LENS = 852; 6177var ENOUGH_DISTS = 592; 6178//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); 6179 6180var MAX_WBITS = 15; 6181/* 32K LZ77 window */ 6182var DEF_WBITS = MAX_WBITS; 6183 6184 6185function ZSWAP32(q) { 6186 return (((q >>> 24) & 0xff) + 6187 ((q >>> 8) & 0xff00) + 6188 ((q & 0xff00) << 8) + 6189 ((q & 0xff) << 24)); 6190} 6191 6192 6193function InflateState() { 6194 this.mode = 0; /* current inflate mode */ 6195 this.last = false; /* true if processing last block */ 6196 this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ 6197 this.havedict = false; /* true if dictionary provided */ 6198 this.flags = 0; /* gzip header method and flags (0 if zlib) */ 6199 this.dmax = 0; /* zlib header max distance (INFLATE_STRICT) */ 6200 this.check = 0; /* protected copy of check value */ 6201 this.total = 0; /* protected copy of output count */ 6202 // TODO: may be {} 6203 this.head = null; /* where to save gzip header information */ 6204 6205 /* sliding window */ 6206 this.wbits = 0; /* log base 2 of requested window size */ 6207 this.wsize = 0; /* window size or zero if not using window */ 6208 this.whave = 0; /* valid bytes in the window */ 6209 this.wnext = 0; /* window write index */ 6210 this.window = null; /* allocated sliding window, if needed */ 6211 6212 /* bit accumulator */ 6213 this.hold = 0; /* input bit accumulator */ 6214 this.bits = 0; /* number of bits in "in" */ 6215 6216 /* for string and stored block copying */ 6217 this.length = 0; /* literal or length of data to copy */ 6218 this.offset = 0; /* distance back to copy string from */ 6219 6220 /* for table and code decoding */ 6221 this.extra = 0; /* extra bits needed */ 6222 6223 /* fixed and dynamic code tables */ 6224 this.lencode = null; /* starting table for length/literal codes */ 6225 this.distcode = null; /* starting table for distance codes */ 6226 this.lenbits = 0; /* index bits for lencode */ 6227 this.distbits = 0; /* index bits for distcode */ 6228 6229 /* dynamic table building */ 6230 this.ncode = 0; /* number of code length code lengths */ 6231 this.nlen = 0; /* number of length code lengths */ 6232 this.ndist = 0; /* number of distance code lengths */ 6233 this.have = 0; /* number of code lengths in lens[] */ 6234 this.next = null; /* next available space in codes[] */ 6235 6236 this.lens = new utils.Buf16(320); /* temporary storage for code lengths */ 6237 this.work = new utils.Buf16(288); /* work area for code table building */ 6238 6239 /* 6240 because we don't have pointers in js, we use lencode and distcode directly 6241 as buffers so we don't need codes 6242 */ 6243 //this.codes = new utils.Buf32(ENOUGH); /* space for code tables */ 6244 this.lendyn = null; /* dynamic table for length/literal codes (JS specific) */ 6245 this.distdyn = null; /* dynamic table for distance codes (JS specific) */ 6246 this.sane = 0; /* if false, allow invalid distance too far */ 6247 this.back = 0; /* bits back of last unprocessed length/lit */ 6248 this.was = 0; /* initial length of match */ 6249} 6250 6251function inflateResetKeep(strm) { 6252 var state; 6253 6254 if (!strm || !strm.state) { return Z_STREAM_ERROR; } 6255 state = strm.state; 6256 strm.total_in = strm.total_out = state.total = 0; 6257 strm.msg = ''; /*Z_NULL*/ 6258 if (state.wrap) { /* to support ill-conceived Java test suite */ 6259 strm.adler = state.wrap & 1; 6260 } 6261 state.mode = HEAD; 6262 state.last = 0; 6263 state.havedict = 0; 6264 state.dmax = 32768; 6265 state.head = null/*Z_NULL*/; 6266 state.hold = 0; 6267 state.bits = 0; 6268 //state.lencode = state.distcode = state.next = state.codes; 6269 state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS); 6270 state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS); 6271 6272 state.sane = 1; 6273 state.back = -1; 6274 //Tracev((stderr, "inflate: reset\n")); 6275 return Z_OK; 6276} 6277 6278function inflateReset(strm) { 6279 var state; 6280 6281 if (!strm || !strm.state) { return Z_STREAM_ERROR; } 6282 state = strm.state; 6283 state.wsize = 0; 6284 state.whave = 0; 6285 state.wnext = 0; 6286 return inflateResetKeep(strm); 6287 6288} 6289 6290function inflateReset2(strm, windowBits) { 6291 var wrap; 6292 var state; 6293 6294 /* get the state */ 6295 if (!strm || !strm.state) { return Z_STREAM_ERROR; } 6296 state = strm.state; 6297 6298 /* extract wrap request from windowBits parameter */ 6299 if (windowBits < 0) { 6300 wrap = 0; 6301 windowBits = -windowBits; 6302 } 6303 else { 6304 wrap = (windowBits >> 4) + 1; 6305 if (windowBits < 48) { 6306 windowBits &= 15; 6307 } 6308 } 6309 6310 /* set number of window bits, free window if different */ 6311 if (windowBits && (windowBits < 8 || windowBits > 15)) { 6312 return Z_STREAM_ERROR; 6313 } 6314 if (state.window !== null && state.wbits !== windowBits) { 6315 state.window = null; 6316 } 6317 6318 /* update state and reset the rest of it */ 6319 state.wrap = wrap; 6320 state.wbits = windowBits; 6321 return inflateReset(strm); 6322} 6323 6324function inflateInit2(strm, windowBits) { 6325 var ret; 6326 var state; 6327 6328 if (!strm) { return Z_STREAM_ERROR; } 6329 //strm.msg = Z_NULL; /* in case we return an error */ 6330 6331 state = new InflateState(); 6332 6333 //if (state === Z_NULL) return Z_MEM_ERROR; 6334 //Tracev((stderr, "inflate: allocated\n")); 6335 strm.state = state; 6336 state.window = null/*Z_NULL*/; 6337 ret = inflateReset2(strm, windowBits); 6338 if (ret !== Z_OK) { 6339 strm.state = null/*Z_NULL*/; 6340 } 6341 return ret; 6342} 6343 6344function inflateInit(strm) { 6345 return inflateInit2(strm, DEF_WBITS); 6346} 6347 6348 6349/* 6350 Return state with length and distance decoding tables and index sizes set to 6351 fixed code decoding. Normally this returns fixed tables from inffixed.h. 6352 If BUILDFIXED is defined, then instead this routine builds the tables the 6353 first time it's called, and returns those tables the first time and 6354 thereafter. This reduces the size of the code by about 2K bytes, in 6355 exchange for a little execution time. However, BUILDFIXED should not be 6356 used for threaded applications, since the rewriting of the tables and virgin 6357 may not be thread-safe. 6358 */ 6359var virgin = true; 6360 6361var lenfix, distfix; // We have no pointers in JS, so keep tables separate 6362 6363function fixedtables(state) { 6364 /* build fixed huffman tables if first call (may not be thread safe) */ 6365 if (virgin) { 6366 var sym; 6367 6368 lenfix = new utils.Buf32(512); 6369 distfix = new utils.Buf32(32); 6370 6371 /* literal/length table */ 6372 sym = 0; 6373 while (sym < 144) { state.lens[sym++] = 8; } 6374 while (sym < 256) { state.lens[sym++] = 9; } 6375 while (sym < 280) { state.lens[sym++] = 7; } 6376 while (sym < 288) { state.lens[sym++] = 8; } 6377 6378 inflate_table(LENS, state.lens, 0, 288, lenfix, 0, state.work, {bits: 9}); 6379 6380 /* distance table */ 6381 sym = 0; 6382 while (sym < 32) { state.lens[sym++] = 5; } 6383 6384 inflate_table(DISTS, state.lens, 0, 32, distfix, 0, state.work, {bits: 5}); 6385 6386 /* do this just once */ 6387 virgin = false; 6388 } 6389 6390 state.lencode = lenfix; 6391 state.lenbits = 9; 6392 state.distcode = distfix; 6393 state.distbits = 5; 6394} 6395 6396 6397/* 6398 Update the window with the last wsize (normally 32K) bytes written before 6399 returning. If window does not exist yet, create it. This is only called 6400 when a window is already in use, or when output has been written during this 6401 inflate call, but the end of the deflate stream has not been reached yet. 6402 It is also called to create a window for dictionary data when a dictionary 6403 is loaded. 6404 6405 Providing output buffers larger than 32K to inflate() should provide a speed 6406 advantage, since only the last 32K of output is copied to the sliding window 6407 upon return from inflate(), and since all distances after the first 32K of 6408 output will fall in the output data, making match copies simpler and faster. 6409 The advantage may be dependent on the size of the processor's data caches. 6410 */ 6411function updatewindow(strm, src, end, copy) { 6412 var dist; 6413 var state = strm.state; 6414 6415 /* if it hasn't been done already, allocate space for the window */ 6416 if (state.window === null) { 6417 state.wsize = 1 << state.wbits; 6418 state.wnext = 0; 6419 state.whave = 0; 6420 6421 state.window = new utils.Buf8(state.wsize); 6422 } 6423 6424 /* copy state->wsize or less output bytes into the circular window */ 6425 if (copy >= state.wsize) { 6426 utils.arraySet(state.window,src, end - state.wsize, state.wsize, 0); 6427 state.wnext = 0; 6428 state.whave = state.wsize; 6429 } 6430 else { 6431 dist = state.wsize - state.wnext; 6432 if (dist > copy) { 6433 dist = copy; 6434 } 6435 //zmemcpy(state->window + state->wnext, end - copy, dist); 6436 utils.arraySet(state.window,src, end - copy, dist, state.wnext); 6437 copy -= dist; 6438 if (copy) { 6439 //zmemcpy(state->window, end - copy, copy); 6440 utils.arraySet(state.window,src, end - copy, copy, 0); 6441 state.wnext = copy; 6442 state.whave = state.wsize; 6443 } 6444 else { 6445 state.wnext += dist; 6446 if (state.wnext === state.wsize) { state.wnext = 0; } 6447 if (state.whave < state.wsize) { state.whave += dist; } 6448 } 6449 } 6450 return 0; 6451} 6452 6453function inflate(strm, flush) { 6454 var state; 6455 var input, output; // input/output buffers 6456 var next; /* next input INDEX */ 6457 var put; /* next output INDEX */ 6458 var have, left; /* available input and output */ 6459 var hold; /* bit buffer */ 6460 var bits; /* bits in bit buffer */ 6461 var _in, _out; /* save starting available input and output */ 6462 var copy; /* number of stored or match bytes to copy */ 6463 var from; /* where to copy match bytes from */ 6464 var from_source; 6465 var here = 0; /* current decoding table entry */ 6466 var here_bits, here_op, here_val; // paked "here" denormalized (JS specific) 6467 //var last; /* parent table entry */ 6468 var last_bits, last_op, last_val; // paked "last" denormalized (JS specific) 6469 var len; /* length to copy for repeats, bits to drop */ 6470 var ret; /* return code */ 6471 var hbuf = new utils.Buf8(4); /* buffer for gzip header crc calculation */ 6472 var opts; 6473 6474 var n; // temporary var for NEED_BITS 6475 6476 var order = /* permutation of code lengths */ 6477 [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]; 6478 6479 6480 if (!strm || !strm.state || !strm.output || 6481 (!strm.input && strm.avail_in !== 0)) { 6482 return Z_STREAM_ERROR; 6483 } 6484 6485 state = strm.state; 6486 if (state.mode === TYPE) { state.mode = TYPEDO; } /* skip check */ 6487 6488 6489 //--- LOAD() --- 6490 put = strm.next_out; 6491 output = strm.output; 6492 left = strm.avail_out; 6493 next = strm.next_in; 6494 input = strm.input; 6495 have = strm.avail_in; 6496 hold = state.hold; 6497 bits = state.bits; 6498 //--- 6499 6500 _in = have; 6501 _out = left; 6502 ret = Z_OK; 6503 6504 inf_leave: // goto emulation 6505 for (;;) { 6506 switch (state.mode) { 6507 case HEAD: 6508 if (state.wrap === 0) { 6509 state.mode = TYPEDO; 6510 break; 6511 } 6512 //=== NEEDBITS(16); 6513 while (bits < 16) { 6514 if (have === 0) { break inf_leave; } 6515 have--; 6516 hold += input[next++] << bits; 6517 bits += 8; 6518 } 6519 //===// 6520 if ((state.wrap & 2) && hold === 0x8b1f) { /* gzip header */ 6521 state.check = 0/*crc32(0L, Z_NULL, 0)*/; 6522 //=== CRC2(state.check, hold); 6523 hbuf[0] = hold & 0xff; 6524 hbuf[1] = (hold >>> 8) & 0xff; 6525 state.check = crc32(state.check, hbuf, 2, 0); 6526 //===// 6527 6528 //=== INITBITS(); 6529 hold = 0; 6530 bits = 0; 6531 //===// 6532 state.mode = FLAGS; 6533 break; 6534 } 6535 state.flags = 0; /* expect zlib header */ 6536 if (state.head) { 6537 state.head.done = false; 6538 } 6539 if (!(state.wrap & 1) || /* check if zlib header allowed */ 6540 (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) { 6541 strm.msg = 'incorrect header check'; 6542 state.mode = BAD; 6543 break; 6544 } 6545 if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) { 6546 strm.msg = 'unknown compression method'; 6547 state.mode = BAD; 6548 break; 6549 } 6550 //--- DROPBITS(4) ---// 6551 hold >>>= 4; 6552 bits -= 4; 6553 //---// 6554 len = (hold & 0x0f)/*BITS(4)*/ + 8; 6555 if (state.wbits === 0) { 6556 state.wbits = len; 6557 } 6558 else if (len > state.wbits) { 6559 strm.msg = 'invalid window size'; 6560 state.mode = BAD; 6561 break; 6562 } 6563 state.dmax = 1 << len; 6564 //Tracev((stderr, "inflate: zlib header ok\n")); 6565 strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/; 6566 state.mode = hold & 0x200 ? DICTID : TYPE; 6567 //=== INITBITS(); 6568 hold = 0; 6569 bits = 0; 6570 //===// 6571 break; 6572 case FLAGS: 6573 //=== NEEDBITS(16); */ 6574 while (bits < 16) { 6575 if (have === 0) { break inf_leave; } 6576 have--; 6577 hold += input[next++] << bits; 6578 bits += 8; 6579 } 6580 //===// 6581 state.flags = hold; 6582 if ((state.flags & 0xff) !== Z_DEFLATED) { 6583 strm.msg = 'unknown compression method'; 6584 state.mode = BAD; 6585 break; 6586 } 6587 if (state.flags & 0xe000) { 6588 strm.msg = 'unknown header flags set'; 6589 state.mode = BAD; 6590 break; 6591 } 6592 if (state.head) { 6593 state.head.text = ((hold >> 8) & 1); 6594 } 6595 if (state.flags & 0x0200) { 6596 //=== CRC2(state.check, hold); 6597 hbuf[0] = hold & 0xff; 6598 hbuf[1] = (hold >>> 8) & 0xff; 6599 state.check = crc32(state.check, hbuf, 2, 0); 6600 //===// 6601 } 6602 //=== INITBITS(); 6603 hold = 0; 6604 bits = 0; 6605 //===// 6606 state.mode = TIME; 6607 /* falls through */ 6608 case TIME: 6609 //=== NEEDBITS(32); */ 6610 while (bits < 32) { 6611 if (have === 0) { break inf_leave; } 6612 have--; 6613 hold += input[next++] << bits; 6614 bits += 8; 6615 } 6616 //===// 6617 if (state.head) { 6618 state.head.time = hold; 6619 } 6620 if (state.flags & 0x0200) { 6621 //=== CRC4(state.check, hold) 6622 hbuf[0] = hold & 0xff; 6623 hbuf[1] = (hold >>> 8) & 0xff; 6624 hbuf[2] = (hold >>> 16) & 0xff; 6625 hbuf[3] = (hold >>> 24) & 0xff; 6626 state.check = crc32(state.check, hbuf, 4, 0); 6627 //=== 6628 } 6629 //=== INITBITS(); 6630 hold = 0; 6631 bits = 0; 6632 //===// 6633 state.mode = OS; 6634 /* falls through */ 6635 case OS: 6636 //=== NEEDBITS(16); */ 6637 while (bits < 16) { 6638 if (have === 0) { break inf_leave; } 6639 have--; 6640 hold += input[next++] << bits; 6641 bits += 8; 6642 } 6643 //===// 6644 if (state.head) { 6645 state.head.xflags = (hold & 0xff); 6646 state.head.os = (hold >> 8); 6647 } 6648 if (state.flags & 0x0200) { 6649 //=== CRC2(state.check, hold); 6650 hbuf[0] = hold & 0xff; 6651 hbuf[1] = (hold >>> 8) & 0xff; 6652 state.check = crc32(state.check, hbuf, 2, 0); 6653 //===// 6654 } 6655 //=== INITBITS(); 6656 hold = 0; 6657 bits = 0; 6658 //===// 6659 state.mode = EXLEN; 6660 /* falls through */ 6661 case EXLEN: 6662 if (state.flags & 0x0400) { 6663 //=== NEEDBITS(16); */ 6664 while (bits < 16) { 6665 if (have === 0) { break inf_leave; } 6666 have--; 6667 hold += input[next++] << bits; 6668 bits += 8; 6669 } 6670 //===// 6671 state.length = hold; 6672 if (state.head) { 6673 state.head.extra_len = hold; 6674 } 6675 if (state.flags & 0x0200) { 6676 //=== CRC2(state.check, hold); 6677 hbuf[0] = hold & 0xff; 6678 hbuf[1] = (hold >>> 8) & 0xff; 6679 state.check = crc32(state.check, hbuf, 2, 0); 6680 //===// 6681 } 6682 //=== INITBITS(); 6683 hold = 0; 6684 bits = 0; 6685 //===// 6686 } 6687 else if (state.head) { 6688 state.head.extra = null/*Z_NULL*/; 6689 } 6690 state.mode = EXTRA; 6691 /* falls through */ 6692 case EXTRA: 6693 if (state.flags & 0x0400) { 6694 copy = state.length; 6695 if (copy > have) { copy = have; } 6696 if (copy) { 6697 if (state.head) { 6698 len = state.head.extra_len - state.length; 6699 if (!state.head.extra) { 6700 // Use untyped array for more conveniend processing later 6701 state.head.extra = new Array(state.head.extra_len); 6702 } 6703 utils.arraySet( 6704 state.head.extra, 6705 input, 6706 next, 6707 // extra field is limited to 65536 bytes 6708 // - no need for additional size check 6709 copy, 6710 /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/ 6711 len 6712 ); 6713 //zmemcpy(state.head.extra + len, next, 6714 // len + copy > state.head.extra_max ? 6715 // state.head.extra_max - len : copy); 6716 } 6717 if (state.flags & 0x0200) { 6718 state.check = crc32(state.check, input, copy, next); 6719 } 6720 have -= copy; 6721 next += copy; 6722 state.length -= copy; 6723 } 6724 if (state.length) { break inf_leave; } 6725 } 6726 state.length = 0; 6727 state.mode = NAME; 6728 /* falls through */ 6729 case NAME: 6730 if (state.flags & 0x0800) { 6731 if (have === 0) { break inf_leave; } 6732 copy = 0; 6733 do { 6734 // TODO: 2 or 1 bytes? 6735 len = input[next + copy++]; 6736 /* use constant limit because in js we should not preallocate memory */ 6737 if (state.head && len && 6738 (state.length < 65536 /*state.head.name_max*/)) { 6739 state.head.name += String.fromCharCode(len); 6740 } 6741 } while (len && copy < have); 6742 6743 if (state.flags & 0x0200) { 6744 state.check = crc32(state.check, input, copy, next); 6745 } 6746 have -= copy; 6747 next += copy; 6748 if (len) { break inf_leave; } 6749 } 6750 else if (state.head) { 6751 state.head.name = null; 6752 } 6753 state.length = 0; 6754 state.mode = COMMENT; 6755 /* falls through */ 6756 case COMMENT: 6757 if (state.flags & 0x1000) { 6758 if (have === 0) { break inf_leave; } 6759 copy = 0; 6760 do { 6761 len = input[next + copy++]; 6762 /* use constant limit because in js we should not preallocate memory */ 6763 if (state.head && len && 6764 (state.length < 65536 /*state.head.comm_max*/)) { 6765 state.head.comment += String.fromCharCode(len); 6766 } 6767 } while (len && copy < have); 6768 if (state.flags & 0x0200) { 6769 state.check = crc32(state.check, input, copy, next); 6770 } 6771 have -= copy; 6772 next += copy; 6773 if (len) { break inf_leave; } 6774 } 6775 else if (state.head) { 6776 state.head.comment = null; 6777 } 6778 state.mode = HCRC; 6779 /* falls through */ 6780 case HCRC: 6781 if (state.flags & 0x0200) { 6782 //=== NEEDBITS(16); */ 6783 while (bits < 16) { 6784 if (have === 0) { break inf_leave; } 6785 have--; 6786 hold += input[next++] << bits; 6787 bits += 8; 6788 } 6789 //===// 6790 if (hold !== (state.check & 0xffff)) { 6791 strm.msg = 'header crc mismatch'; 6792 state.mode = BAD; 6793 break; 6794 } 6795 //=== INITBITS(); 6796 hold = 0; 6797 bits = 0; 6798 //===// 6799 } 6800 if (state.head) { 6801 state.head.hcrc = ((state.flags >> 9) & 1); 6802 state.head.done = true; 6803 } 6804 strm.adler = state.check = 0 /*crc32(0L, Z_NULL, 0)*/; 6805 state.mode = TYPE; 6806 break; 6807 case DICTID: 6808 //=== NEEDBITS(32); */ 6809 while (bits < 32) { 6810 if (have === 0) { break inf_leave; } 6811 have--; 6812 hold += input[next++] << bits; 6813 bits += 8; 6814 } 6815 //===// 6816 strm.adler = state.check = ZSWAP32(hold); 6817 //=== INITBITS(); 6818 hold = 0; 6819 bits = 0; 6820 //===// 6821 state.mode = DICT; 6822 /* falls through */ 6823 case DICT: 6824 if (state.havedict === 0) { 6825 //--- RESTORE() --- 6826 strm.next_out = put; 6827 strm.avail_out = left; 6828 strm.next_in = next; 6829 strm.avail_in = have; 6830 state.hold = hold; 6831 state.bits = bits; 6832 //--- 6833 return Z_NEED_DICT; 6834 } 6835 strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/; 6836 state.mode = TYPE; 6837 /* falls through */ 6838 case TYPE: 6839 if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; } 6840 /* falls through */ 6841 case TYPEDO: 6842 if (state.last) { 6843 //--- BYTEBITS() ---// 6844 hold >>>= bits & 7; 6845 bits -= bits & 7; 6846 //---// 6847 state.mode = CHECK; 6848 break; 6849 } 6850 //=== NEEDBITS(3); */ 6851 while (bits < 3) { 6852 if (have === 0) { break inf_leave; } 6853 have--; 6854 hold += input[next++] << bits; 6855 bits += 8; 6856 } 6857 //===// 6858 state.last = (hold & 0x01)/*BITS(1)*/; 6859 //--- DROPBITS(1) ---// 6860 hold >>>= 1; 6861 bits -= 1; 6862 //---// 6863 6864 switch ((hold & 0x03)/*BITS(2)*/) { 6865 case 0: /* stored block */ 6866 //Tracev((stderr, "inflate: stored block%s\n", 6867 // state.last ? " (last)" : "")); 6868 state.mode = STORED; 6869 break; 6870 case 1: /* fixed block */ 6871 fixedtables(state); 6872 //Tracev((stderr, "inflate: fixed codes block%s\n", 6873 // state.last ? " (last)" : "")); 6874 state.mode = LEN_; /* decode codes */ 6875 if (flush === Z_TREES) { 6876 //--- DROPBITS(2) ---// 6877 hold >>>= 2; 6878 bits -= 2; 6879 //---// 6880 break inf_leave; 6881 } 6882 break; 6883 case 2: /* dynamic block */ 6884 //Tracev((stderr, "inflate: dynamic codes block%s\n", 6885 // state.last ? " (last)" : "")); 6886 state.mode = TABLE; 6887 break; 6888 case 3: 6889 strm.msg = 'invalid block type'; 6890 state.mode = BAD; 6891 } 6892 //--- DROPBITS(2) ---// 6893 hold >>>= 2; 6894 bits -= 2; 6895 //---// 6896 break; 6897 case STORED: 6898 //--- BYTEBITS() ---// /* go to byte boundary */ 6899 hold >>>= bits & 7; 6900 bits -= bits & 7; 6901 //---// 6902 //=== NEEDBITS(32); */ 6903 while (bits < 32) { 6904 if (have === 0) { break inf_leave; } 6905 have--; 6906 hold += input[next++] << bits; 6907 bits += 8; 6908 } 6909 //===// 6910 if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) { 6911 strm.msg = 'invalid stored block lengths'; 6912 state.mode = BAD; 6913 break; 6914 } 6915 state.length = hold & 0xffff; 6916 //Tracev((stderr, "inflate: stored length %u\n", 6917 // state.length)); 6918 //=== INITBITS(); 6919 hold = 0; 6920 bits = 0; 6921 //===// 6922 state.mode = COPY_; 6923 if (flush === Z_TREES) { break inf_leave; } 6924 /* falls through */ 6925 case COPY_: 6926 state.mode = COPY; 6927 /* falls through */ 6928 case COPY: 6929 copy = state.length; 6930 if (copy) { 6931 if (copy > have) { copy = have; } 6932 if (copy > left) { copy = left; } 6933 if (copy === 0) { break inf_leave; } 6934 //--- zmemcpy(put, next, copy); --- 6935 utils.arraySet(output, input, next, copy, put); 6936 //---// 6937 have -= copy; 6938 next += copy; 6939 left -= copy; 6940 put += copy; 6941 state.length -= copy; 6942 break; 6943 } 6944 //Tracev((stderr, "inflate: stored end\n")); 6945 state.mode = TYPE; 6946 break; 6947 case TABLE: 6948 //=== NEEDBITS(14); */ 6949 while (bits < 14) { 6950 if (have === 0) { break inf_leave; } 6951 have--; 6952 hold += input[next++] << bits; 6953 bits += 8; 6954 } 6955 //===// 6956 state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257; 6957 //--- DROPBITS(5) ---// 6958 hold >>>= 5; 6959 bits -= 5; 6960 //---// 6961 state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1; 6962 //--- DROPBITS(5) ---// 6963 hold >>>= 5; 6964 bits -= 5; 6965 //---// 6966 state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4; 6967 //--- DROPBITS(4) ---// 6968 hold >>>= 4; 6969 bits -= 4; 6970 //---// 6971//#ifndef PKZIP_BUG_WORKAROUND 6972 if (state.nlen > 286 || state.ndist > 30) { 6973 strm.msg = 'too many length or distance symbols'; 6974 state.mode = BAD; 6975 break; 6976 } 6977//#endif 6978 //Tracev((stderr, "inflate: table sizes ok\n")); 6979 state.have = 0; 6980 state.mode = LENLENS; 6981 /* falls through */ 6982 case LENLENS: 6983 while (state.have < state.ncode) { 6984 //=== NEEDBITS(3); 6985 while (bits < 3) { 6986 if (have === 0) { break inf_leave; } 6987 have--; 6988 hold += input[next++] << bits; 6989 bits += 8; 6990 } 6991 //===// 6992 state.lens[order[state.have++]] = (hold & 0x07);//BITS(3); 6993 //--- DROPBITS(3) ---// 6994 hold >>>= 3; 6995 bits -= 3; 6996 //---// 6997 } 6998 while (state.have < 19) { 6999 state.lens[order[state.have++]] = 0; 7000 } 7001 // We have separate tables & no pointers. 2 commented lines below not needed. 7002 //state.next = state.codes; 7003 //state.lencode = state.next; 7004 // Switch to use dynamic table 7005 state.lencode = state.lendyn; 7006 state.lenbits = 7; 7007 7008 opts = {bits: state.lenbits}; 7009 ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts); 7010 state.lenbits = opts.bits; 7011 7012 if (ret) { 7013 strm.msg = 'invalid code lengths set'; 7014 state.mode = BAD; 7015 break; 7016 } 7017 //Tracev((stderr, "inflate: code lengths ok\n")); 7018 state.have = 0; 7019 state.mode = CODELENS; 7020 /* falls through */ 7021 case CODELENS: 7022 while (state.have < state.nlen + state.ndist) { 7023 for (;;) { 7024 here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/ 7025 here_bits = here >>> 24; 7026 here_op = (here >>> 16) & 0xff; 7027 here_val = here & 0xffff; 7028 7029 if ((here_bits) <= bits) { break; } 7030 //--- PULLBYTE() ---// 7031 if (have === 0) { break inf_leave; } 7032 have--; 7033 hold += input[next++] << bits; 7034 bits += 8; 7035 //---// 7036 } 7037 if (here_val < 16) { 7038 //--- DROPBITS(here.bits) ---// 7039 hold >>>= here_bits; 7040 bits -= here_bits; 7041 //---// 7042 state.lens[state.have++] = here_val; 7043 } 7044 else { 7045 if (here_val === 16) { 7046 //=== NEEDBITS(here.bits + 2); 7047 n = here_bits + 2; 7048 while (bits < n) { 7049 if (have === 0) { break inf_leave; } 7050 have--; 7051 hold += input[next++] << bits; 7052 bits += 8; 7053 } 7054 //===// 7055 //--- DROPBITS(here.bits) ---// 7056 hold >>>= here_bits; 7057 bits -= here_bits; 7058 //---// 7059 if (state.have === 0) { 7060 strm.msg = 'invalid bit length repeat'; 7061 state.mode = BAD; 7062 break; 7063 } 7064 len = state.lens[state.have - 1]; 7065 copy = 3 + (hold & 0x03);//BITS(2); 7066 //--- DROPBITS(2) ---// 7067 hold >>>= 2; 7068 bits -= 2; 7069 //---// 7070 } 7071 else if (here_val === 17) { 7072 //=== NEEDBITS(here.bits + 3); 7073 n = here_bits + 3; 7074 while (bits < n) { 7075 if (have === 0) { break inf_leave; } 7076 have--; 7077 hold += input[next++] << bits; 7078 bits += 8; 7079 } 7080 //===// 7081 //--- DROPBITS(here.bits) ---// 7082 hold >>>= here_bits; 7083 bits -= here_bits; 7084 //---// 7085 len = 0; 7086 copy = 3 + (hold & 0x07);//BITS(3); 7087 //--- DROPBITS(3) ---// 7088 hold >>>= 3; 7089 bits -= 3; 7090 //---// 7091 } 7092 else { 7093 //=== NEEDBITS(here.bits + 7); 7094 n = here_bits + 7; 7095 while (bits < n) { 7096 if (have === 0) { break inf_leave; } 7097 have--; 7098 hold += input[next++] << bits; 7099 bits += 8; 7100 } 7101 //===// 7102 //--- DROPBITS(here.bits) ---// 7103 hold >>>= here_bits; 7104 bits -= here_bits; 7105 //---// 7106 len = 0; 7107 copy = 11 + (hold & 0x7f);//BITS(7); 7108 //--- DROPBITS(7) ---// 7109 hold >>>= 7; 7110 bits -= 7; 7111 //---// 7112 } 7113 if (state.have + copy > state.nlen + state.ndist) { 7114 strm.msg = 'invalid bit length repeat'; 7115 state.mode = BAD; 7116 break; 7117 } 7118 while (copy--) { 7119 state.lens[state.have++] = len; 7120 } 7121 } 7122 } 7123 7124 /* handle error breaks in while */ 7125 if (state.mode === BAD) { break; } 7126 7127 /* check for end-of-block code (better have one) */ 7128 if (state.lens[256] === 0) { 7129 strm.msg = 'invalid code -- missing end-of-block'; 7130 state.mode = BAD; 7131 break; 7132 } 7133 7134 /* build code tables -- note: do not change the lenbits or distbits 7135 values here (9 and 6) without reading the comments in inftrees.h 7136 concerning the ENOUGH constants, which depend on those values */ 7137 state.lenbits = 9; 7138 7139 opts = {bits: state.lenbits}; 7140 ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts); 7141 // We have separate tables & no pointers. 2 commented lines below not needed. 7142 // state.next_index = opts.table_index; 7143 state.lenbits = opts.bits; 7144 // state.lencode = state.next; 7145 7146 if (ret) { 7147 strm.msg = 'invalid literal/lengths set'; 7148 state.mode = BAD; 7149 break; 7150 } 7151 7152 state.distbits = 6; 7153 //state.distcode.copy(state.codes); 7154 // Switch to use dynamic table 7155 state.distcode = state.distdyn; 7156 opts = {bits: state.distbits}; 7157 ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts); 7158 // We have separate tables & no pointers. 2 commented lines below not needed. 7159 // state.next_index = opts.table_index; 7160 state.distbits = opts.bits; 7161 // state.distcode = state.next; 7162 7163 if (ret) { 7164 strm.msg = 'invalid distances set'; 7165 state.mode = BAD; 7166 break; 7167 } 7168 //Tracev((stderr, 'inflate: codes ok\n')); 7169 state.mode = LEN_; 7170 if (flush === Z_TREES) { break inf_leave; } 7171 /* falls through */ 7172 case LEN_: 7173 state.mode = LEN; 7174 /* falls through */ 7175 case LEN: 7176 if (have >= 6 && left >= 258) { 7177 //--- RESTORE() --- 7178 strm.next_out = put; 7179 strm.avail_out = left; 7180 strm.next_in = next; 7181 strm.avail_in = have; 7182 state.hold = hold; 7183 state.bits = bits; 7184 //--- 7185 inflate_fast(strm, _out); 7186 //--- LOAD() --- 7187 put = strm.next_out; 7188 output = strm.output; 7189 left = strm.avail_out; 7190 next = strm.next_in; 7191 input = strm.input; 7192 have = strm.avail_in; 7193 hold = state.hold; 7194 bits = state.bits; 7195 //--- 7196 7197 if (state.mode === TYPE) { 7198 state.back = -1; 7199 } 7200 break; 7201 } 7202 state.back = 0; 7203 for (;;) { 7204 here = state.lencode[hold & ((1 << state.lenbits) -1)]; /*BITS(state.lenbits)*/ 7205 here_bits = here >>> 24; 7206 here_op = (here >>> 16) & 0xff; 7207 here_val = here & 0xffff; 7208 7209 if (here_bits <= bits) { break; } 7210 //--- PULLBYTE() ---// 7211 if (have === 0) { break inf_leave; } 7212 have--; 7213 hold += input[next++] << bits; 7214 bits += 8; 7215 //---// 7216 } 7217 if (here_op && (here_op & 0xf0) === 0) { 7218 last_bits = here_bits; 7219 last_op = here_op; 7220 last_val = here_val; 7221 for (;;) { 7222 here = state.lencode[last_val + 7223 ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)]; 7224 here_bits = here >>> 24; 7225 here_op = (here >>> 16) & 0xff; 7226 here_val = here & 0xffff; 7227 7228 if ((last_bits + here_bits) <= bits) { break; } 7229 //--- PULLBYTE() ---// 7230 if (have === 0) { break inf_leave; } 7231 have--; 7232 hold += input[next++] << bits; 7233 bits += 8; 7234 //---// 7235 } 7236 //--- DROPBITS(last.bits) ---// 7237 hold >>>= last_bits; 7238 bits -= last_bits; 7239 //---// 7240 state.back += last_bits; 7241 } 7242 //--- DROPBITS(here.bits) ---// 7243 hold >>>= here_bits; 7244 bits -= here_bits; 7245 //---// 7246 state.back += here_bits; 7247 state.length = here_val; 7248 if (here_op === 0) { 7249 //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? 7250 // "inflate: literal '%c'\n" : 7251 // "inflate: literal 0x%02x\n", here.val)); 7252 state.mode = LIT; 7253 break; 7254 } 7255 if (here_op & 32) { 7256 //Tracevv((stderr, "inflate: end of block\n")); 7257 state.back = -1; 7258 state.mode = TYPE; 7259 break; 7260 } 7261 if (here_op & 64) { 7262 strm.msg = 'invalid literal/length code'; 7263 state.mode = BAD; 7264 break; 7265 } 7266 state.extra = here_op & 15; 7267 state.mode = LENEXT; 7268 /* falls through */ 7269 case LENEXT: 7270 if (state.extra) { 7271 //=== NEEDBITS(state.extra); 7272 n = state.extra; 7273 while (bits < n) { 7274 if (have === 0) { break inf_leave; } 7275 have--; 7276 hold += input[next++] << bits; 7277 bits += 8; 7278 } 7279 //===// 7280 state.length += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/; 7281 //--- DROPBITS(state.extra) ---// 7282 hold >>>= state.extra; 7283 bits -= state.extra; 7284 //---// 7285 state.back += state.extra; 7286 } 7287 //Tracevv((stderr, "inflate: length %u\n", state.length)); 7288 state.was = state.length; 7289 state.mode = DIST; 7290 /* falls through */ 7291 case DIST: 7292 for (;;) { 7293 here = state.distcode[hold & ((1 << state.distbits) -1)];/*BITS(state.distbits)*/ 7294 here_bits = here >>> 24; 7295 here_op = (here >>> 16) & 0xff; 7296 here_val = here & 0xffff; 7297 7298 if ((here_bits) <= bits) { break; } 7299 //--- PULLBYTE() ---// 7300 if (have === 0) { break inf_leave; } 7301 have--; 7302 hold += input[next++] << bits; 7303 bits += 8; 7304 //---// 7305 } 7306 if ((here_op & 0xf0) === 0) { 7307 last_bits = here_bits; 7308 last_op = here_op; 7309 last_val = here_val; 7310 for (;;) { 7311 here = state.distcode[last_val + 7312 ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)]; 7313 here_bits = here >>> 24; 7314 here_op = (here >>> 16) & 0xff; 7315 here_val = here & 0xffff; 7316 7317 if ((last_bits + here_bits) <= bits) { break; } 7318 //--- PULLBYTE() ---// 7319 if (have === 0) { break inf_leave; } 7320 have--; 7321 hold += input[next++] << bits; 7322 bits += 8; 7323 //---// 7324 } 7325 //--- DROPBITS(last.bits) ---// 7326 hold >>>= last_bits; 7327 bits -= last_bits; 7328 //---// 7329 state.back += last_bits; 7330 } 7331 //--- DROPBITS(here.bits) ---// 7332 hold >>>= here_bits; 7333 bits -= here_bits; 7334 //---// 7335 state.back += here_bits; 7336 if (here_op & 64) { 7337 strm.msg = 'invalid distance code'; 7338 state.mode = BAD; 7339 break; 7340 } 7341 state.offset = here_val; 7342 state.extra = (here_op) & 15; 7343 state.mode = DISTEXT; 7344 /* falls through */ 7345 case DISTEXT: 7346 if (state.extra) { 7347 //=== NEEDBITS(state.extra); 7348 n = state.extra; 7349 while (bits < n) { 7350 if (have === 0) { break inf_leave; } 7351 have--; 7352 hold += input[next++] << bits; 7353 bits += 8; 7354 } 7355 //===// 7356 state.offset += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/; 7357 //--- DROPBITS(state.extra) ---// 7358 hold >>>= state.extra; 7359 bits -= state.extra; 7360 //---// 7361 state.back += state.extra; 7362 } 7363//#ifdef INFLATE_STRICT 7364 if (state.offset > state.dmax) { 7365 strm.msg = 'invalid distance too far back'; 7366 state.mode = BAD; 7367 break; 7368 } 7369//#endif 7370 //Tracevv((stderr, "inflate: distance %u\n", state.offset)); 7371 state.mode = MATCH; 7372 /* falls through */ 7373 case MATCH: 7374 if (left === 0) { break inf_leave; } 7375 copy = _out - left; 7376 if (state.offset > copy) { /* copy from window */ 7377 copy = state.offset - copy; 7378 if (copy > state.whave) { 7379 if (state.sane) { 7380 strm.msg = 'invalid distance too far back'; 7381 state.mode = BAD; 7382 break; 7383 } 7384// (!) This block is disabled in zlib defailts, 7385// don't enable it for binary compatibility 7386//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR 7387// Trace((stderr, "inflate.c too far\n")); 7388// copy -= state.whave; 7389// if (copy > state.length) { copy = state.length; } 7390// if (copy > left) { copy = left; } 7391// left -= copy; 7392// state.length -= copy; 7393// do { 7394// output[put++] = 0; 7395// } while (--copy); 7396// if (state.length === 0) { state.mode = LEN; } 7397// break; 7398//#endif 7399 } 7400 if (copy > state.wnext) { 7401 copy -= state.wnext; 7402 from = state.wsize - copy; 7403 } 7404 else { 7405 from = state.wnext - copy; 7406 } 7407 if (copy > state.length) { copy = state.length; } 7408 from_source = state.window; 7409 } 7410 else { /* copy from output */ 7411 from_source = output; 7412 from = put - state.offset; 7413 copy = state.length; 7414 } 7415 if (copy > left) { copy = left; } 7416 left -= copy; 7417 state.length -= copy; 7418 do { 7419 output[put++] = from_source[from++]; 7420 } while (--copy); 7421 if (state.length === 0) { state.mode = LEN; } 7422 break; 7423 case LIT: 7424 if (left === 0) { break inf_leave; } 7425 output[put++] = state.length; 7426 left--; 7427 state.mode = LEN; 7428 break; 7429 case CHECK: 7430 if (state.wrap) { 7431 //=== NEEDBITS(32); 7432 while (bits < 32) { 7433 if (have === 0) { break inf_leave; } 7434 have--; 7435 // Use '|' insdead of '+' to make sure that result is signed 7436 hold |= input[next++] << bits; 7437 bits += 8; 7438 } 7439 //===// 7440 _out -= left; 7441 strm.total_out += _out; 7442 state.total += _out; 7443 if (_out) { 7444 strm.adler = state.check = 7445 /*UPDATE(state.check, put - _out, _out);*/ 7446 (state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out)); 7447 7448 } 7449 _out = left; 7450 // NB: crc32 stored as signed 32-bit int, ZSWAP32 returns signed too 7451 if ((state.flags ? hold : ZSWAP32(hold)) !== state.check) { 7452 strm.msg = 'incorrect data check'; 7453 state.mode = BAD; 7454 break; 7455 } 7456 //=== INITBITS(); 7457 hold = 0; 7458 bits = 0; 7459 //===// 7460 //Tracev((stderr, "inflate: check matches trailer\n")); 7461 } 7462 state.mode = LENGTH; 7463 /* falls through */ 7464 case LENGTH: 7465 if (state.wrap && state.flags) { 7466 //=== NEEDBITS(32); 7467 while (bits < 32) { 7468 if (have === 0) { break inf_leave; } 7469 have--; 7470 hold += input[next++] << bits; 7471 bits += 8; 7472 } 7473 //===// 7474 if (hold !== (state.total & 0xffffffff)) { 7475 strm.msg = 'incorrect length check'; 7476 state.mode = BAD; 7477 break; 7478 } 7479 //=== INITBITS(); 7480 hold = 0; 7481 bits = 0; 7482 //===// 7483 //Tracev((stderr, "inflate: length matches trailer\n")); 7484 } 7485 state.mode = DONE; 7486 /* falls through */ 7487 case DONE: 7488 ret = Z_STREAM_END; 7489 break inf_leave; 7490 case BAD: 7491 ret = Z_DATA_ERROR; 7492 break inf_leave; 7493 case MEM: 7494 return Z_MEM_ERROR; 7495 case SYNC: 7496 /* falls through */ 7497 default: 7498 return Z_STREAM_ERROR; 7499 } 7500 } 7501 7502 // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave" 7503 7504 /* 7505 Return from inflate(), updating the total counts and the check value. 7506 If there was no progress during the inflate() call, return a buffer 7507 error. Call updatewindow() to create and/or update the window state. 7508 Note: a memory error from inflate() is non-recoverable. 7509 */ 7510 7511 //--- RESTORE() --- 7512 strm.next_out = put; 7513 strm.avail_out = left; 7514 strm.next_in = next; 7515 strm.avail_in = have; 7516 state.hold = hold; 7517 state.bits = bits; 7518 //--- 7519 7520 if (state.wsize || (_out !== strm.avail_out && state.mode < BAD && 7521 (state.mode < CHECK || flush !== Z_FINISH))) { 7522 if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) { 7523 state.mode = MEM; 7524 return Z_MEM_ERROR; 7525 } 7526 } 7527 _in -= strm.avail_in; 7528 _out -= strm.avail_out; 7529 strm.total_in += _in; 7530 strm.total_out += _out; 7531 state.total += _out; 7532 if (state.wrap && _out) { 7533 strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/ 7534 (state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out)); 7535 } 7536 strm.data_type = state.bits + (state.last ? 64 : 0) + 7537 (state.mode === TYPE ? 128 : 0) + 7538 (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0); 7539 if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) { 7540 ret = Z_BUF_ERROR; 7541 } 7542 return ret; 7543} 7544 7545function inflateEnd(strm) { 7546 7547 if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) { 7548 return Z_STREAM_ERROR; 7549 } 7550 7551 var state = strm.state; 7552 if (state.window) { 7553 state.window = null; 7554 } 7555 strm.state = null; 7556 return Z_OK; 7557} 7558 7559function inflateGetHeader(strm, head) { 7560 var state; 7561 7562 /* check state */ 7563 if (!strm || !strm.state) { return Z_STREAM_ERROR; } 7564 state = strm.state; 7565 if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; } 7566 7567 /* save header structure */ 7568 state.head = head; 7569 head.done = false; 7570 return Z_OK; 7571} 7572 7573 7574exports.inflateReset = inflateReset; 7575exports.inflateReset2 = inflateReset2; 7576exports.inflateResetKeep = inflateResetKeep; 7577exports.inflateInit = inflateInit; 7578exports.inflateInit2 = inflateInit2; 7579exports.inflate = inflate; 7580exports.inflateEnd = inflateEnd; 7581exports.inflateGetHeader = inflateGetHeader; 7582exports.inflateInfo = 'pako inflate (from Nodeca project)'; 7583 7584/* Not implemented 7585exports.inflateCopy = inflateCopy; 7586exports.inflateGetDictionary = inflateGetDictionary; 7587exports.inflateMark = inflateMark; 7588exports.inflatePrime = inflatePrime; 7589exports.inflateSetDictionary = inflateSetDictionary; 7590exports.inflateSync = inflateSync; 7591exports.inflateSyncPoint = inflateSyncPoint; 7592exports.inflateUndermine = inflateUndermine; 7593*/ 7594},{"../utils/common":27,"./adler32":29,"./crc32":31,"./inffast":34,"./inftrees":36}],36:[function(_dereq_,module,exports){ 7595'use strict'; 7596 7597 7598var utils = _dereq_('../utils/common'); 7599 7600var MAXBITS = 15; 7601var ENOUGH_LENS = 852; 7602var ENOUGH_DISTS = 592; 7603//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); 7604 7605var CODES = 0; 7606var LENS = 1; 7607var DISTS = 2; 7608 7609var lbase = [ /* Length codes 257..285 base */ 7610 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 7611 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 7612]; 7613 7614var lext = [ /* Length codes 257..285 extra */ 7615 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 7616 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78 7617]; 7618 7619var dbase = [ /* Distance codes 0..29 base */ 7620 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 7621 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 7622 8193, 12289, 16385, 24577, 0, 0 7623]; 7624 7625var dext = [ /* Distance codes 0..29 extra */ 7626 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 7627 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 7628 28, 28, 29, 29, 64, 64 7629]; 7630 7631module.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts) 7632{ 7633 var bits = opts.bits; 7634 //here = opts.here; /* table entry for duplication */ 7635 7636 var len = 0; /* a code's length in bits */ 7637 var sym = 0; /* index of code symbols */ 7638 var min = 0, max = 0; /* minimum and maximum code lengths */ 7639 var root = 0; /* number of index bits for root table */ 7640 var curr = 0; /* number of index bits for current table */ 7641 var drop = 0; /* code bits to drop for sub-table */ 7642 var left = 0; /* number of prefix codes available */ 7643 var used = 0; /* code entries in table used */ 7644 var huff = 0; /* Huffman code */ 7645 var incr; /* for incrementing code, index */ 7646 var fill; /* index for replicating entries */ 7647 var low; /* low bits for current root entry */ 7648 var mask; /* mask for low root bits */ 7649 var next; /* next available space in table */ 7650 var base = null; /* base value table to use */ 7651 var base_index = 0; 7652// var shoextra; /* extra bits table to use */ 7653 var end; /* use base and extra for symbol > end */ 7654 var count = new utils.Buf16(MAXBITS+1); //[MAXBITS+1]; /* number of codes of each length */ 7655 var offs = new utils.Buf16(MAXBITS+1); //[MAXBITS+1]; /* offsets in table for each length */ 7656 var extra = null; 7657 var extra_index = 0; 7658 7659 var here_bits, here_op, here_val; 7660 7661 /* 7662 Process a set of code lengths to create a canonical Huffman code. The 7663 code lengths are lens[0..codes-1]. Each length corresponds to the 7664 symbols 0..codes-1. The Huffman code is generated by first sorting the 7665 symbols by length from short to long, and retaining the symbol order 7666 for codes with equal lengths. Then the code starts with all zero bits 7667 for the first code of the shortest length, and the codes are integer 7668 increments for the same length, and zeros are appended as the length 7669 increases. For the deflate format, these bits are stored backwards 7670 from their more natural integer increment ordering, and so when the 7671 decoding tables are built in the large loop below, the integer codes 7672 are incremented backwards. 7673 7674 This routine assumes, but does not check, that all of the entries in 7675 lens[] are in the range 0..MAXBITS. The caller must assure this. 7676 1..MAXBITS is interpreted as that code length. zero means that that 7677 symbol does not occur in this code. 7678 7679 The codes are sorted by computing a count of codes for each length, 7680 creating from that a table of starting indices for each length in the 7681 sorted table, and then entering the symbols in order in the sorted 7682 table. The sorted table is work[], with that space being provided by 7683 the caller. 7684 7685 The length counts are used for other purposes as well, i.e. finding 7686 the minimum and maximum length codes, determining if there are any 7687 codes at all, checking for a valid set of lengths, and looking ahead 7688 at length counts to determine sub-table sizes when building the 7689 decoding tables. 7690 */ 7691 7692 /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ 7693 for (len = 0; len <= MAXBITS; len++) { 7694 count[len] = 0; 7695 } 7696 for (sym = 0; sym < codes; sym++) { 7697 count[lens[lens_index + sym]]++; 7698 } 7699 7700 /* bound code lengths, force root to be within code lengths */ 7701 root = bits; 7702 for (max = MAXBITS; max >= 1; max--) { 7703 if (count[max] !== 0) { break; } 7704 } 7705 if (root > max) { 7706 root = max; 7707 } 7708 if (max === 0) { /* no symbols to code at all */ 7709 //table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */ 7710 //table.bits[opts.table_index] = 1; //here.bits = (var char)1; 7711 //table.val[opts.table_index++] = 0; //here.val = (var short)0; 7712 table[table_index++] = (1 << 24) | (64 << 16) | 0; 7713 7714 7715 //table.op[opts.table_index] = 64; 7716 //table.bits[opts.table_index] = 1; 7717 //table.val[opts.table_index++] = 0; 7718 table[table_index++] = (1 << 24) | (64 << 16) | 0; 7719 7720 opts.bits = 1; 7721 return 0; /* no symbols, but wait for decoding to report error */ 7722 } 7723 for (min = 1; min < max; min++) { 7724 if (count[min] !== 0) { break; } 7725 } 7726 if (root < min) { 7727 root = min; 7728 } 7729 7730 /* check for an over-subscribed or incomplete set of lengths */ 7731 left = 1; 7732 for (len = 1; len <= MAXBITS; len++) { 7733 left <<= 1; 7734 left -= count[len]; 7735 if (left < 0) { 7736 return -1; 7737 } /* over-subscribed */ 7738 } 7739 if (left > 0 && (type === CODES || max !== 1)) { 7740 return -1; /* incomplete set */ 7741 } 7742 7743 /* generate offsets into symbol table for each length for sorting */ 7744 offs[1] = 0; 7745 for (len = 1; len < MAXBITS; len++) { 7746 offs[len + 1] = offs[len] + count[len]; 7747 } 7748 7749 /* sort symbols by length, by symbol order within each length */ 7750 for (sym = 0; sym < codes; sym++) { 7751 if (lens[lens_index + sym] !== 0) { 7752 work[offs[lens[lens_index + sym]]++] = sym; 7753 } 7754 } 7755 7756 /* 7757 Create and fill in decoding tables. In this loop, the table being 7758 filled is at next and has curr index bits. The code being used is huff 7759 with length len. That code is converted to an index by dropping drop 7760 bits off of the bottom. For codes where len is less than drop + curr, 7761 those top drop + curr - len bits are incremented through all values to 7762 fill the table with replicated entries. 7763 7764 root is the number of index bits for the root table. When len exceeds 7765 root, sub-tables are created pointed to by the root entry with an index 7766 of the low root bits of huff. This is saved in low to check for when a 7767 new sub-table should be started. drop is zero when the root table is 7768 being filled, and drop is root when sub-tables are being filled. 7769 7770 When a new sub-table is needed, it is necessary to look ahead in the 7771 code lengths to determine what size sub-table is needed. The length 7772 counts are used for this, and so count[] is decremented as codes are 7773 entered in the tables. 7774 7775 used keeps track of how many table entries have been allocated from the 7776 provided *table space. It is checked for LENS and DIST tables against 7777 the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in 7778 the initial root table size constants. See the comments in inftrees.h 7779 for more information. 7780 7781 sym increments through all symbols, and the loop terminates when 7782 all codes of length max, i.e. all codes, have been processed. This 7783 routine permits incomplete codes, so another loop after this one fills 7784 in the rest of the decoding tables with invalid code markers. 7785 */ 7786 7787 /* set up for code type */ 7788 // poor man optimization - use if-else instead of switch, 7789 // to avoid deopts in old v8 7790 if (type === CODES) { 7791 base = extra = work; /* dummy value--not used */ 7792 end = 19; 7793 } else if (type === LENS) { 7794 base = lbase; 7795 base_index -= 257; 7796 extra = lext; 7797 extra_index -= 257; 7798 end = 256; 7799 } else { /* DISTS */ 7800 base = dbase; 7801 extra = dext; 7802 end = -1; 7803 } 7804 7805 /* initialize opts for loop */ 7806 huff = 0; /* starting code */ 7807 sym = 0; /* starting code symbol */ 7808 len = min; /* starting code length */ 7809 next = table_index; /* current table to fill in */ 7810 curr = root; /* current table index bits */ 7811 drop = 0; /* current bits to drop from code for index */ 7812 low = -1; /* trigger new sub-table when len > root */ 7813 used = 1 << root; /* use root table entries */ 7814 mask = used - 1; /* mask for comparing low */ 7815 7816 /* check available table space */ 7817 if ((type === LENS && used > ENOUGH_LENS) || 7818 (type === DISTS && used > ENOUGH_DISTS)) { 7819 return 1; 7820 } 7821 7822 var i=0; 7823 /* process all codes and make table entries */ 7824 for (;;) { 7825 i++; 7826 /* create table entry */ 7827 here_bits = len - drop; 7828 if (work[sym] < end) { 7829 here_op = 0; 7830 here_val = work[sym]; 7831 } 7832 else if (work[sym] > end) { 7833 here_op = extra[extra_index + work[sym]]; 7834 here_val = base[base_index + work[sym]]; 7835 } 7836 else { 7837 here_op = 32 + 64; /* end of block */ 7838 here_val = 0; 7839 } 7840 7841 /* replicate for those indices with low len bits equal to huff */ 7842 incr = 1 << (len - drop); 7843 fill = 1 << curr; 7844 min = fill; /* save offset to next table */ 7845 do { 7846 fill -= incr; 7847 table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0; 7848 } while (fill !== 0); 7849 7850 /* backwards increment the len-bit code huff */ 7851 incr = 1 << (len - 1); 7852 while (huff & incr) { 7853 incr >>= 1; 7854 } 7855 if (incr !== 0) { 7856 huff &= incr - 1; 7857 huff += incr; 7858 } else { 7859 huff = 0; 7860 } 7861 7862 /* go to next symbol, update count, len */ 7863 sym++; 7864 if (--count[len] === 0) { 7865 if (len === max) { break; } 7866 len = lens[lens_index + work[sym]]; 7867 } 7868 7869 /* create new sub-table if needed */ 7870 if (len > root && (huff & mask) !== low) { 7871 /* if first time, transition to sub-tables */ 7872 if (drop === 0) { 7873 drop = root; 7874 } 7875 7876 /* increment past last table */ 7877 next += min; /* here min is 1 << curr */ 7878 7879 /* determine length of next table */ 7880 curr = len - drop; 7881 left = 1 << curr; 7882 while (curr + drop < max) { 7883 left -= count[curr + drop]; 7884 if (left <= 0) { break; } 7885 curr++; 7886 left <<= 1; 7887 } 7888 7889 /* check for enough space */ 7890 used += 1 << curr; 7891 if ((type === LENS && used > ENOUGH_LENS) || 7892 (type === DISTS && used > ENOUGH_DISTS)) { 7893 return 1; 7894 } 7895 7896 /* point entry in root table to sub-table */ 7897 low = huff & mask; 7898 /*table.op[low] = curr; 7899 table.bits[low] = root; 7900 table.val[low] = next - opts.table_index;*/ 7901 table[low] = (root << 24) | (curr << 16) | (next - table_index) |0; 7902 } 7903 } 7904 7905 /* fill in remaining table entry if code is incomplete (guaranteed to have 7906 at most one remaining entry, since if the code is incomplete, the 7907 maximum code length that was allowed to get this far is one bit) */ 7908 if (huff !== 0) { 7909 //table.op[next + huff] = 64; /* invalid code marker */ 7910 //table.bits[next + huff] = len - drop; 7911 //table.val[next + huff] = 0; 7912 table[next + huff] = ((len - drop) << 24) | (64 << 16) |0; 7913 } 7914 7915 /* set return parameters */ 7916 //opts.table_index += used; 7917 opts.bits = root; 7918 return 0; 7919}; 7920 7921},{"../utils/common":27}],37:[function(_dereq_,module,exports){ 7922'use strict'; 7923 7924module.exports = { 7925 '2': 'need dictionary', /* Z_NEED_DICT 2 */ 7926 '1': 'stream end', /* Z_STREAM_END 1 */ 7927 '0': '', /* Z_OK 0 */ 7928 '-1': 'file error', /* Z_ERRNO (-1) */ 7929 '-2': 'stream error', /* Z_STREAM_ERROR (-2) */ 7930 '-3': 'data error', /* Z_DATA_ERROR (-3) */ 7931 '-4': 'insufficient memory', /* Z_MEM_ERROR (-4) */ 7932 '-5': 'buffer error', /* Z_BUF_ERROR (-5) */ 7933 '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */ 7934}; 7935},{}],38:[function(_dereq_,module,exports){ 7936'use strict'; 7937 7938 7939var utils = _dereq_('../utils/common'); 7940 7941/* Public constants ==========================================================*/ 7942/* ===========================================================================*/ 7943 7944 7945//var Z_FILTERED = 1; 7946//var Z_HUFFMAN_ONLY = 2; 7947//var Z_RLE = 3; 7948var Z_FIXED = 4; 7949//var Z_DEFAULT_STRATEGY = 0; 7950 7951/* Possible values of the data_type field (though see inflate()) */ 7952var Z_BINARY = 0; 7953var Z_TEXT = 1; 7954//var Z_ASCII = 1; // = Z_TEXT 7955var Z_UNKNOWN = 2; 7956 7957/*============================================================================*/ 7958 7959 7960function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } } 7961 7962// From zutil.h 7963 7964var STORED_BLOCK = 0; 7965var STATIC_TREES = 1; 7966var DYN_TREES = 2; 7967/* The three kinds of block type */ 7968 7969var MIN_MATCH = 3; 7970var MAX_MATCH = 258; 7971/* The minimum and maximum match lengths */ 7972 7973// From deflate.h 7974/* =========================================================================== 7975 * Internal compression state. 7976 */ 7977 7978var LENGTH_CODES = 29; 7979/* number of length codes, not counting the special END_BLOCK code */ 7980 7981var LITERALS = 256; 7982/* number of literal bytes 0..255 */ 7983 7984var L_CODES = LITERALS + 1 + LENGTH_CODES; 7985/* number of Literal or Length codes, including the END_BLOCK code */ 7986 7987var D_CODES = 30; 7988/* number of distance codes */ 7989 7990var BL_CODES = 19; 7991/* number of codes used to transfer the bit lengths */ 7992 7993var HEAP_SIZE = 2*L_CODES + 1; 7994/* maximum heap size */ 7995 7996var MAX_BITS = 15; 7997/* All codes must not exceed MAX_BITS bits */ 7998 7999var Buf_size = 16; 8000/* size of bit buffer in bi_buf */ 8001 8002 8003/* =========================================================================== 8004 * Constants 8005 */ 8006 8007var MAX_BL_BITS = 7; 8008/* Bit length codes must not exceed MAX_BL_BITS bits */ 8009 8010var END_BLOCK = 256; 8011/* end of block literal code */ 8012 8013var REP_3_6 = 16; 8014/* repeat previous bit length 3-6 times (2 bits of repeat count) */ 8015 8016var REPZ_3_10 = 17; 8017/* repeat a zero length 3-10 times (3 bits of repeat count) */ 8018 8019var REPZ_11_138 = 18; 8020/* repeat a zero length 11-138 times (7 bits of repeat count) */ 8021 8022var extra_lbits = /* extra bits for each length code */ 8023 [0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0]; 8024 8025var extra_dbits = /* extra bits for each distance code */ 8026 [0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13]; 8027 8028var extra_blbits = /* extra bits for each bit length code */ 8029 [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7]; 8030 8031var bl_order = 8032 [16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]; 8033/* The lengths of the bit length codes are sent in order of decreasing 8034 * probability, to avoid transmitting the lengths for unused bit length codes. 8035 */ 8036 8037/* =========================================================================== 8038 * Local data. These are initialized only once. 8039 */ 8040 8041// We pre-fill arrays with 0 to avoid uninitialized gaps 8042 8043var DIST_CODE_LEN = 512; /* see definition of array dist_code below */ 8044 8045// !!!! Use flat array insdead of structure, Freq = i*2, Len = i*2+1 8046var static_ltree = new Array((L_CODES+2) * 2); 8047zero(static_ltree); 8048/* The static literal tree. Since the bit lengths are imposed, there is no 8049 * need for the L_CODES extra codes used during heap construction. However 8050 * The codes 286 and 287 are needed to build a canonical tree (see _tr_init 8051 * below). 8052 */ 8053 8054var static_dtree = new Array(D_CODES * 2); 8055zero(static_dtree); 8056/* The static distance tree. (Actually a trivial tree since all codes use 8057 * 5 bits.) 8058 */ 8059 8060var _dist_code = new Array(DIST_CODE_LEN); 8061zero(_dist_code); 8062/* Distance codes. The first 256 values correspond to the distances 8063 * 3 .. 258, the last 256 values correspond to the top 8 bits of 8064 * the 15 bit distances. 8065 */ 8066 8067var _length_code = new Array(MAX_MATCH-MIN_MATCH+1); 8068zero(_length_code); 8069/* length code for each normalized match length (0 == MIN_MATCH) */ 8070 8071var base_length = new Array(LENGTH_CODES); 8072zero(base_length); 8073/* First normalized length for each code (0 = MIN_MATCH) */ 8074 8075var base_dist = new Array(D_CODES); 8076zero(base_dist); 8077/* First normalized distance for each code (0 = distance of 1) */ 8078 8079 8080var StaticTreeDesc = function (static_tree, extra_bits, extra_base, elems, max_length) { 8081 8082 this.static_tree = static_tree; /* static tree or NULL */ 8083 this.extra_bits = extra_bits; /* extra bits for each code or NULL */ 8084 this.extra_base = extra_base; /* base index for extra_bits */ 8085 this.elems = elems; /* max number of elements in the tree */ 8086 this.max_length = max_length; /* max bit length for the codes */ 8087 8088 // show if `static_tree` has data or dummy - needed for monomorphic objects 8089 this.has_stree = static_tree && static_tree.length; 8090}; 8091 8092 8093var static_l_desc; 8094var static_d_desc; 8095var static_bl_desc; 8096 8097 8098var TreeDesc = function(dyn_tree, stat_desc) { 8099 this.dyn_tree = dyn_tree; /* the dynamic tree */ 8100 this.max_code = 0; /* largest code with non zero frequency */ 8101 this.stat_desc = stat_desc; /* the corresponding static tree */ 8102}; 8103 8104 8105 8106function d_code(dist) { 8107 return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)]; 8108} 8109 8110 8111/* =========================================================================== 8112 * Output a short LSB first on the stream. 8113 * IN assertion: there is enough room in pendingBuf. 8114 */ 8115function put_short (s, w) { 8116// put_byte(s, (uch)((w) & 0xff)); 8117// put_byte(s, (uch)((ush)(w) >> 8)); 8118 s.pending_buf[s.pending++] = (w) & 0xff; 8119 s.pending_buf[s.pending++] = (w >>> 8) & 0xff; 8120} 8121 8122 8123/* =========================================================================== 8124 * Send a value on a given number of bits. 8125 * IN assertion: length <= 16 and value fits in length bits. 8126 */ 8127function send_bits(s, value, length) { 8128 if (s.bi_valid > (Buf_size - length)) { 8129 s.bi_buf |= (value << s.bi_valid) & 0xffff; 8130 put_short(s, s.bi_buf); 8131 s.bi_buf = value >> (Buf_size - s.bi_valid); 8132 s.bi_valid += length - Buf_size; 8133 } else { 8134 s.bi_buf |= (value << s.bi_valid) & 0xffff; 8135 s.bi_valid += length; 8136 } 8137} 8138 8139 8140function send_code(s, c, tree) { 8141 send_bits(s, tree[c*2]/*.Code*/, tree[c*2 + 1]/*.Len*/); 8142} 8143 8144 8145/* =========================================================================== 8146 * Reverse the first len bits of a code, using straightforward code (a faster 8147 * method would use a table) 8148 * IN assertion: 1 <= len <= 15 8149 */ 8150function bi_reverse(code, len) { 8151 var res = 0; 8152 do { 8153 res |= code & 1; 8154 code >>>= 1; 8155 res <<= 1; 8156 } while (--len > 0); 8157 return res >>> 1; 8158} 8159 8160 8161/* =========================================================================== 8162 * Flush the bit buffer, keeping at most 7 bits in it. 8163 */ 8164function bi_flush(s) { 8165 if (s.bi_valid === 16) { 8166 put_short(s, s.bi_buf); 8167 s.bi_buf = 0; 8168 s.bi_valid = 0; 8169 8170 } else if (s.bi_valid >= 8) { 8171 s.pending_buf[s.pending++] = s.bi_buf & 0xff; 8172 s.bi_buf >>= 8; 8173 s.bi_valid -= 8; 8174 } 8175} 8176 8177 8178/* =========================================================================== 8179 * Compute the optimal bit lengths for a tree and update the total bit length 8180 * for the current block. 8181 * IN assertion: the fields freq and dad are set, heap[heap_max] and 8182 * above are the tree nodes sorted by increasing frequency. 8183 * OUT assertions: the field len is set to the optimal bit length, the 8184 * array bl_count contains the frequencies for each bit length. 8185 * The length opt_len is updated; static_len is also updated if stree is 8186 * not null. 8187 */ 8188function gen_bitlen(s, desc) 8189// deflate_state *s; 8190// tree_desc *desc; /* the tree descriptor */ 8191{ 8192 var tree = desc.dyn_tree; 8193 var max_code = desc.max_code; 8194 var stree = desc.stat_desc.static_tree; 8195 var has_stree = desc.stat_desc.has_stree; 8196 var extra = desc.stat_desc.extra_bits; 8197 var base = desc.stat_desc.extra_base; 8198 var max_length = desc.stat_desc.max_length; 8199 var h; /* heap index */ 8200 var n, m; /* iterate over the tree elements */ 8201 var bits; /* bit length */ 8202 var xbits; /* extra bits */ 8203 var f; /* frequency */ 8204 var overflow = 0; /* number of elements with bit length too large */ 8205 8206 for (bits = 0; bits <= MAX_BITS; bits++) { 8207 s.bl_count[bits] = 0; 8208 } 8209 8210 /* In a first pass, compute the optimal bit lengths (which may 8211 * overflow in the case of the bit length tree). 8212 */ 8213 tree[s.heap[s.heap_max]*2 + 1]/*.Len*/ = 0; /* root of the heap */ 8214 8215 for (h = s.heap_max+1; h < HEAP_SIZE; h++) { 8216 n = s.heap[h]; 8217 bits = tree[tree[n*2 +1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1; 8218 if (bits > max_length) { 8219 bits = max_length; 8220 overflow++; 8221 } 8222 tree[n*2 + 1]/*.Len*/ = bits; 8223 /* We overwrite tree[n].Dad which is no longer needed */ 8224 8225 if (n > max_code) { continue; } /* not a leaf node */ 8226 8227 s.bl_count[bits]++; 8228 xbits = 0; 8229 if (n >= base) { 8230 xbits = extra[n-base]; 8231 } 8232 f = tree[n * 2]/*.Freq*/; 8233 s.opt_len += f * (bits + xbits); 8234 if (has_stree) { 8235 s.static_len += f * (stree[n*2 + 1]/*.Len*/ + xbits); 8236 } 8237 } 8238 if (overflow === 0) { return; } 8239 8240 // Trace((stderr,"\nbit length overflow\n")); 8241 /* This happens for example on obj2 and pic of the Calgary corpus */ 8242 8243 /* Find the first bit length which could increase: */ 8244 do { 8245 bits = max_length-1; 8246 while (s.bl_count[bits] === 0) { bits--; } 8247 s.bl_count[bits]--; /* move one leaf down the tree */ 8248 s.bl_count[bits+1] += 2; /* move one overflow item as its brother */ 8249 s.bl_count[max_length]--; 8250 /* The brother of the overflow item also moves one step up, 8251 * but this does not affect bl_count[max_length] 8252 */ 8253 overflow -= 2; 8254 } while (overflow > 0); 8255 8256 /* Now recompute all bit lengths, scanning in increasing frequency. 8257 * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all 8258 * lengths instead of fixing only the wrong ones. This idea is taken 8259 * from 'ar' written by Haruhiko Okumura.) 8260 */ 8261 for (bits = max_length; bits !== 0; bits--) { 8262 n = s.bl_count[bits]; 8263 while (n !== 0) { 8264 m = s.heap[--h]; 8265 if (m > max_code) { continue; } 8266 if (tree[m*2 + 1]/*.Len*/ !== bits) { 8267 // Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); 8268 s.opt_len += (bits - tree[m*2 + 1]/*.Len*/)*tree[m*2]/*.Freq*/; 8269 tree[m*2 + 1]/*.Len*/ = bits; 8270 } 8271 n--; 8272 } 8273 } 8274} 8275 8276 8277/* =========================================================================== 8278 * Generate the codes for a given tree and bit counts (which need not be 8279 * optimal). 8280 * IN assertion: the array bl_count contains the bit length statistics for 8281 * the given tree and the field len is set for all tree elements. 8282 * OUT assertion: the field code is set for all tree elements of non 8283 * zero code length. 8284 */ 8285function gen_codes(tree, max_code, bl_count) 8286// ct_data *tree; /* the tree to decorate */ 8287// int max_code; /* largest code with non zero frequency */ 8288// ushf *bl_count; /* number of codes at each bit length */ 8289{ 8290 var next_code = new Array(MAX_BITS+1); /* next code value for each bit length */ 8291 var code = 0; /* running code value */ 8292 var bits; /* bit index */ 8293 var n; /* code index */ 8294 8295 /* The distribution counts are first used to generate the code values 8296 * without bit reversal. 8297 */ 8298 for (bits = 1; bits <= MAX_BITS; bits++) { 8299 next_code[bits] = code = (code + bl_count[bits-1]) << 1; 8300 } 8301 /* Check that the bit counts in bl_count are consistent. The last code 8302 * must be all ones. 8303 */ 8304 //Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1, 8305 // "inconsistent bit counts"); 8306 //Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); 8307 8308 for (n = 0; n <= max_code; n++) { 8309 var len = tree[n*2 + 1]/*.Len*/; 8310 if (len === 0) { continue; } 8311 /* Now reverse the bits */ 8312 tree[n*2]/*.Code*/ = bi_reverse(next_code[len]++, len); 8313 8314 //Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", 8315 // n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1)); 8316 } 8317} 8318 8319 8320/* =========================================================================== 8321 * Initialize the various 'constant' tables. 8322 */ 8323function tr_static_init() { 8324 var n; /* iterates over tree elements */ 8325 var bits; /* bit counter */ 8326 var length; /* length value */ 8327 var code; /* code value */ 8328 var dist; /* distance index */ 8329 var bl_count = new Array(MAX_BITS+1); 8330 /* number of codes at each bit length for an optimal tree */ 8331 8332 // do check in _tr_init() 8333 //if (static_init_done) return; 8334 8335 /* For some embedded targets, global variables are not initialized: */ 8336/*#ifdef NO_INIT_GLOBAL_POINTERS 8337 static_l_desc.static_tree = static_ltree; 8338 static_l_desc.extra_bits = extra_lbits; 8339 static_d_desc.static_tree = static_dtree; 8340 static_d_desc.extra_bits = extra_dbits; 8341 static_bl_desc.extra_bits = extra_blbits; 8342#endif*/ 8343 8344 /* Initialize the mapping length (0..255) -> length code (0..28) */ 8345 length = 0; 8346 for (code = 0; code < LENGTH_CODES-1; code++) { 8347 base_length[code] = length; 8348 for (n = 0; n < (1<<extra_lbits[code]); n++) { 8349 _length_code[length++] = code; 8350 } 8351 } 8352 //Assert (length == 256, "tr_static_init: length != 256"); 8353 /* Note that the length 255 (match length 258) can be represented 8354 * in two different ways: code 284 + 5 bits or code 285, so we 8355 * overwrite length_code[255] to use the best encoding: 8356 */ 8357 _length_code[length-1] = code; 8358 8359 /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ 8360 dist = 0; 8361 for (code = 0 ; code < 16; code++) { 8362 base_dist[code] = dist; 8363 for (n = 0; n < (1<<extra_dbits[code]); n++) { 8364 _dist_code[dist++] = code; 8365 } 8366 } 8367 //Assert (dist == 256, "tr_static_init: dist != 256"); 8368 dist >>= 7; /* from now on, all distances are divided by 128 */ 8369 for ( ; code < D_CODES; code++) { 8370 base_dist[code] = dist << 7; 8371 for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { 8372 _dist_code[256 + dist++] = code; 8373 } 8374 } 8375 //Assert (dist == 256, "tr_static_init: 256+dist != 512"); 8376 8377 /* Construct the codes of the static literal tree */ 8378 for (bits = 0; bits <= MAX_BITS; bits++) { 8379 bl_count[bits] = 0; 8380 } 8381 8382 n = 0; 8383 while (n <= 143) { 8384 static_ltree[n*2 + 1]/*.Len*/ = 8; 8385 n++; 8386 bl_count[8]++; 8387 } 8388 while (n <= 255) { 8389 static_ltree[n*2 + 1]/*.Len*/ = 9; 8390 n++; 8391 bl_count[9]++; 8392 } 8393 while (n <= 279) { 8394 static_ltree[n*2 + 1]/*.Len*/ = 7; 8395 n++; 8396 bl_count[7]++; 8397 } 8398 while (n <= 287) { 8399 static_ltree[n*2 + 1]/*.Len*/ = 8; 8400 n++; 8401 bl_count[8]++; 8402 } 8403 /* Codes 286 and 287 do not exist, but we must include them in the 8404 * tree construction to get a canonical Huffman tree (longest code 8405 * all ones) 8406 */ 8407 gen_codes(static_ltree, L_CODES+1, bl_count); 8408 8409 /* The static distance tree is trivial: */ 8410 for (n = 0; n < D_CODES; n++) { 8411 static_dtree[n*2 + 1]/*.Len*/ = 5; 8412 static_dtree[n*2]/*.Code*/ = bi_reverse(n, 5); 8413 } 8414 8415 // Now data ready and we can init static trees 8416 static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS); 8417 static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES, MAX_BITS); 8418 static_bl_desc =new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES, MAX_BL_BITS); 8419 8420 //static_init_done = true; 8421} 8422 8423 8424/* =========================================================================== 8425 * Initialize a new block. 8426 */ 8427function init_block(s) { 8428 var n; /* iterates over tree elements */ 8429 8430 /* Initialize the trees. */ 8431 for (n = 0; n < L_CODES; n++) { s.dyn_ltree[n*2]/*.Freq*/ = 0; } 8432 for (n = 0; n < D_CODES; n++) { s.dyn_dtree[n*2]/*.Freq*/ = 0; } 8433 for (n = 0; n < BL_CODES; n++) { s.bl_tree[n*2]/*.Freq*/ = 0; } 8434 8435 s.dyn_ltree[END_BLOCK*2]/*.Freq*/ = 1; 8436 s.opt_len = s.static_len = 0; 8437 s.last_lit = s.matches = 0; 8438} 8439 8440 8441/* =========================================================================== 8442 * Flush the bit buffer and align the output on a byte boundary 8443 */ 8444function bi_windup(s) 8445{ 8446 if (s.bi_valid > 8) { 8447 put_short(s, s.bi_buf); 8448 } else if (s.bi_valid > 0) { 8449 //put_byte(s, (Byte)s->bi_buf); 8450 s.pending_buf[s.pending++] = s.bi_buf; 8451 } 8452 s.bi_buf = 0; 8453 s.bi_valid = 0; 8454} 8455 8456/* =========================================================================== 8457 * Copy a stored block, storing first the length and its 8458 * one's complement if requested. 8459 */ 8460function copy_block(s, buf, len, header) 8461//DeflateState *s; 8462//charf *buf; /* the input data */ 8463//unsigned len; /* its length */ 8464//int header; /* true if block header must be written */ 8465{ 8466 bi_windup(s); /* align on byte boundary */ 8467 8468 if (header) { 8469 put_short(s, len); 8470 put_short(s, ~len); 8471 } 8472// while (len--) { 8473// put_byte(s, *buf++); 8474// } 8475 utils.arraySet(s.pending_buf, s.window, buf, len, s.pending); 8476 s.pending += len; 8477} 8478 8479/* =========================================================================== 8480 * Compares to subtrees, using the tree depth as tie breaker when 8481 * the subtrees have equal frequency. This minimizes the worst case length. 8482 */ 8483function smaller(tree, n, m, depth) { 8484 var _n2 = n*2; 8485 var _m2 = m*2; 8486 return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ || 8487 (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m])); 8488} 8489 8490/* =========================================================================== 8491 * Restore the heap property by moving down the tree starting at node k, 8492 * exchanging a node with the smallest of its two sons if necessary, stopping 8493 * when the heap property is re-established (each father smaller than its 8494 * two sons). 8495 */ 8496function pqdownheap(s, tree, k) 8497// deflate_state *s; 8498// ct_data *tree; /* the tree to restore */ 8499// int k; /* node to move down */ 8500{ 8501 var v = s.heap[k]; 8502 var j = k << 1; /* left son of k */ 8503 while (j <= s.heap_len) { 8504 /* Set j to the smallest of the two sons: */ 8505 if (j < s.heap_len && 8506 smaller(tree, s.heap[j+1], s.heap[j], s.depth)) { 8507 j++; 8508 } 8509 /* Exit if v is smaller than both sons */ 8510 if (smaller(tree, v, s.heap[j], s.depth)) { break; } 8511 8512 /* Exchange v with the smallest son */ 8513 s.heap[k] = s.heap[j]; 8514 k = j; 8515 8516 /* And continue down the tree, setting j to the left son of k */ 8517 j <<= 1; 8518 } 8519 s.heap[k] = v; 8520} 8521 8522 8523// inlined manually 8524// var SMALLEST = 1; 8525 8526/* =========================================================================== 8527 * Send the block data compressed using the given Huffman trees 8528 */ 8529function compress_block(s, ltree, dtree) 8530// deflate_state *s; 8531// const ct_data *ltree; /* literal tree */ 8532// const ct_data *dtree; /* distance tree */ 8533{ 8534 var dist; /* distance of matched string */ 8535 var lc; /* match length or unmatched char (if dist == 0) */ 8536 var lx = 0; /* running index in l_buf */ 8537 var code; /* the code to send */ 8538 var extra; /* number of extra bits to send */ 8539 8540 if (s.last_lit !== 0) { 8541 do { 8542 dist = (s.pending_buf[s.d_buf + lx*2] << 8) | (s.pending_buf[s.d_buf + lx*2 + 1]); 8543 lc = s.pending_buf[s.l_buf + lx]; 8544 lx++; 8545 8546 if (dist === 0) { 8547 send_code(s, lc, ltree); /* send a literal byte */ 8548 //Tracecv(isgraph(lc), (stderr," '%c' ", lc)); 8549 } else { 8550 /* Here, lc is the match length - MIN_MATCH */ 8551 code = _length_code[lc]; 8552 send_code(s, code+LITERALS+1, ltree); /* send the length code */ 8553 extra = extra_lbits[code]; 8554 if (extra !== 0) { 8555 lc -= base_length[code]; 8556 send_bits(s, lc, extra); /* send the extra length bits */ 8557 } 8558 dist--; /* dist is now the match distance - 1 */ 8559 code = d_code(dist); 8560 //Assert (code < D_CODES, "bad d_code"); 8561 8562 send_code(s, code, dtree); /* send the distance code */ 8563 extra = extra_dbits[code]; 8564 if (extra !== 0) { 8565 dist -= base_dist[code]; 8566 send_bits(s, dist, extra); /* send the extra distance bits */ 8567 } 8568 } /* literal or match pair ? */ 8569 8570 /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ 8571 //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, 8572 // "pendingBuf overflow"); 8573 8574 } while (lx < s.last_lit); 8575 } 8576 8577 send_code(s, END_BLOCK, ltree); 8578} 8579 8580 8581/* =========================================================================== 8582 * Construct one Huffman tree and assigns the code bit strings and lengths. 8583 * Update the total bit length for the current block. 8584 * IN assertion: the field freq is set for all tree elements. 8585 * OUT assertions: the fields len and code are set to the optimal bit length 8586 * and corresponding code. The length opt_len is updated; static_len is 8587 * also updated if stree is not null. The field max_code is set. 8588 */ 8589function build_tree(s, desc) 8590// deflate_state *s; 8591// tree_desc *desc; /* the tree descriptor */ 8592{ 8593 var tree = desc.dyn_tree; 8594 var stree = desc.stat_desc.static_tree; 8595 var has_stree = desc.stat_desc.has_stree; 8596 var elems = desc.stat_desc.elems; 8597 var n, m; /* iterate over heap elements */ 8598 var max_code = -1; /* largest code with non zero frequency */ 8599 var node; /* new node being created */ 8600 8601 /* Construct the initial heap, with least frequent element in 8602 * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. 8603 * heap[0] is not used. 8604 */ 8605 s.heap_len = 0; 8606 s.heap_max = HEAP_SIZE; 8607 8608 for (n = 0; n < elems; n++) { 8609 if (tree[n * 2]/*.Freq*/ !== 0) { 8610 s.heap[++s.heap_len] = max_code = n; 8611 s.depth[n] = 0; 8612 8613 } else { 8614 tree[n*2 + 1]/*.Len*/ = 0; 8615 } 8616 } 8617 8618 /* The pkzip format requires that at least one distance code exists, 8619 * and that at least one bit should be sent even if there is only one 8620 * possible code. So to avoid special checks later on we force at least 8621 * two codes of non zero frequency. 8622 */ 8623 while (s.heap_len < 2) { 8624 node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0); 8625 tree[node * 2]/*.Freq*/ = 1; 8626 s.depth[node] = 0; 8627 s.opt_len--; 8628 8629 if (has_stree) { 8630 s.static_len -= stree[node*2 + 1]/*.Len*/; 8631 } 8632 /* node is 0 or 1 so it does not have extra bits */ 8633 } 8634 desc.max_code = max_code; 8635 8636 /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, 8637 * establish sub-heaps of increasing lengths: 8638 */ 8639 for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); } 8640 8641 /* Construct the Huffman tree by repeatedly combining the least two 8642 * frequent nodes. 8643 */ 8644 node = elems; /* next internal node of the tree */ 8645 do { 8646 //pqremove(s, tree, n); /* n = node of least frequency */ 8647 /*** pqremove ***/ 8648 n = s.heap[1/*SMALLEST*/]; 8649 s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--]; 8650 pqdownheap(s, tree, 1/*SMALLEST*/); 8651 /***/ 8652 8653 m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */ 8654 8655 s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */ 8656 s.heap[--s.heap_max] = m; 8657 8658 /* Create a new node father of n and m */ 8659 tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/; 8660 s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1; 8661 tree[n*2 + 1]/*.Dad*/ = tree[m*2 + 1]/*.Dad*/ = node; 8662 8663 /* and insert the new node in the heap */ 8664 s.heap[1/*SMALLEST*/] = node++; 8665 pqdownheap(s, tree, 1/*SMALLEST*/); 8666 8667 } while (s.heap_len >= 2); 8668 8669 s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/]; 8670 8671 /* At this point, the fields freq and dad are set. We can now 8672 * generate the bit lengths. 8673 */ 8674 gen_bitlen(s, desc); 8675 8676 /* The field len is now set, we can generate the bit codes */ 8677 gen_codes(tree, max_code, s.bl_count); 8678} 8679 8680 8681/* =========================================================================== 8682 * Scan a literal or distance tree to determine the frequencies of the codes 8683 * in the bit length tree. 8684 */ 8685function scan_tree(s, tree, max_code) 8686// deflate_state *s; 8687// ct_data *tree; /* the tree to be scanned */ 8688// int max_code; /* and its largest code of non zero frequency */ 8689{ 8690 var n; /* iterates over all tree elements */ 8691 var prevlen = -1; /* last emitted length */ 8692 var curlen; /* length of current code */ 8693 8694 var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */ 8695 8696 var count = 0; /* repeat count of the current code */ 8697 var max_count = 7; /* max repeat count */ 8698 var min_count = 4; /* min repeat count */ 8699 8700 if (nextlen === 0) { 8701 max_count = 138; 8702 min_count = 3; 8703 } 8704 tree[(max_code+1)*2 + 1]/*.Len*/ = 0xffff; /* guard */ 8705 8706 for (n = 0; n <= max_code; n++) { 8707 curlen = nextlen; 8708 nextlen = tree[(n+1)*2 + 1]/*.Len*/; 8709 8710 if (++count < max_count && curlen === nextlen) { 8711 continue; 8712 8713 } else if (count < min_count) { 8714 s.bl_tree[curlen * 2]/*.Freq*/ += count; 8715 8716 } else if (curlen !== 0) { 8717 8718 if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; } 8719 s.bl_tree[REP_3_6*2]/*.Freq*/++; 8720 8721 } else if (count <= 10) { 8722 s.bl_tree[REPZ_3_10*2]/*.Freq*/++; 8723 8724 } else { 8725 s.bl_tree[REPZ_11_138*2]/*.Freq*/++; 8726 } 8727 8728 count = 0; 8729 prevlen = curlen; 8730 8731 if (nextlen === 0) { 8732 max_count = 138; 8733 min_count = 3; 8734 8735 } else if (curlen === nextlen) { 8736 max_count = 6; 8737 min_count = 3; 8738 8739 } else { 8740 max_count = 7; 8741 min_count = 4; 8742 } 8743 } 8744} 8745 8746 8747/* =========================================================================== 8748 * Send a literal or distance tree in compressed form, using the codes in 8749 * bl_tree. 8750 */ 8751function send_tree(s, tree, max_code) 8752// deflate_state *s; 8753// ct_data *tree; /* the tree to be scanned */ 8754// int max_code; /* and its largest code of non zero frequency */ 8755{ 8756 var n; /* iterates over all tree elements */ 8757 var prevlen = -1; /* last emitted length */ 8758 var curlen; /* length of current code */ 8759 8760 var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */ 8761 8762 var count = 0; /* repeat count of the current code */ 8763 var max_count = 7; /* max repeat count */ 8764 var min_count = 4; /* min repeat count */ 8765 8766 /* tree[max_code+1].Len = -1; */ /* guard already set */ 8767 if (nextlen === 0) { 8768 max_count = 138; 8769 min_count = 3; 8770 } 8771 8772 for (n = 0; n <= max_code; n++) { 8773 curlen = nextlen; 8774 nextlen = tree[(n+1)*2 + 1]/*.Len*/; 8775 8776 if (++count < max_count && curlen === nextlen) { 8777 continue; 8778 8779 } else if (count < min_count) { 8780 do { send_code(s, curlen, s.bl_tree); } while (--count !== 0); 8781 8782 } else if (curlen !== 0) { 8783 if (curlen !== prevlen) { 8784 send_code(s, curlen, s.bl_tree); 8785 count--; 8786 } 8787 //Assert(count >= 3 && count <= 6, " 3_6?"); 8788 send_code(s, REP_3_6, s.bl_tree); 8789 send_bits(s, count-3, 2); 8790 8791 } else if (count <= 10) { 8792 send_code(s, REPZ_3_10, s.bl_tree); 8793 send_bits(s, count-3, 3); 8794 8795 } else { 8796 send_code(s, REPZ_11_138, s.bl_tree); 8797 send_bits(s, count-11, 7); 8798 } 8799 8800 count = 0; 8801 prevlen = curlen; 8802 if (nextlen === 0) { 8803 max_count = 138; 8804 min_count = 3; 8805 8806 } else if (curlen === nextlen) { 8807 max_count = 6; 8808 min_count = 3; 8809 8810 } else { 8811 max_count = 7; 8812 min_count = 4; 8813 } 8814 } 8815} 8816 8817 8818/* =========================================================================== 8819 * Construct the Huffman tree for the bit lengths and return the index in 8820 * bl_order of the last bit length code to send. 8821 */ 8822function build_bl_tree(s) { 8823 var max_blindex; /* index of last bit length code of non zero freq */ 8824 8825 /* Determine the bit length frequencies for literal and distance trees */ 8826 scan_tree(s, s.dyn_ltree, s.l_desc.max_code); 8827 scan_tree(s, s.dyn_dtree, s.d_desc.max_code); 8828 8829 /* Build the bit length tree: */ 8830 build_tree(s, s.bl_desc); 8831 /* opt_len now includes the length of the tree representations, except 8832 * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. 8833 */ 8834 8835 /* Determine the number of bit length codes to send. The pkzip format 8836 * requires that at least 4 bit length codes be sent. (appnote.txt says 8837 * 3 but the actual value used is 4.) 8838 */ 8839 for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { 8840 if (s.bl_tree[bl_order[max_blindex]*2 + 1]/*.Len*/ !== 0) { 8841 break; 8842 } 8843 } 8844 /* Update opt_len to include the bit length tree and counts */ 8845 s.opt_len += 3*(max_blindex+1) + 5+5+4; 8846 //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", 8847 // s->opt_len, s->static_len)); 8848 8849 return max_blindex; 8850} 8851 8852 8853/* =========================================================================== 8854 * Send the header for a block using dynamic Huffman trees: the counts, the 8855 * lengths of the bit length codes, the literal tree and the distance tree. 8856 * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. 8857 */ 8858function send_all_trees(s, lcodes, dcodes, blcodes) 8859// deflate_state *s; 8860// int lcodes, dcodes, blcodes; /* number of codes for each tree */ 8861{ 8862 var rank; /* index in bl_order */ 8863 8864 //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); 8865 //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, 8866 // "too many codes"); 8867 //Tracev((stderr, "\nbl counts: ")); 8868 send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ 8869 send_bits(s, dcodes-1, 5); 8870 send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ 8871 for (rank = 0; rank < blcodes; rank++) { 8872 //Tracev((stderr, "\nbl code %2d ", bl_order[rank])); 8873 send_bits(s, s.bl_tree[bl_order[rank]*2 + 1]/*.Len*/, 3); 8874 } 8875 //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); 8876 8877 send_tree(s, s.dyn_ltree, lcodes-1); /* literal tree */ 8878 //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); 8879 8880 send_tree(s, s.dyn_dtree, dcodes-1); /* distance tree */ 8881 //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); 8882} 8883 8884 8885/* =========================================================================== 8886 * Check if the data type is TEXT or BINARY, using the following algorithm: 8887 * - TEXT if the two conditions below are satisfied: 8888 * a) There are no non-portable control characters belonging to the 8889 * "black list" (0..6, 14..25, 28..31). 8890 * b) There is at least one printable character belonging to the 8891 * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). 8892 * - BINARY otherwise. 8893 * - The following partially-portable control characters form a 8894 * "gray list" that is ignored in this detection algorithm: 8895 * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). 8896 * IN assertion: the fields Freq of dyn_ltree are set. 8897 */ 8898function detect_data_type(s) { 8899 /* black_mask is the bit mask of black-listed bytes 8900 * set bits 0..6, 14..25, and 28..31 8901 * 0xf3ffc07f = binary 11110011111111111100000001111111 8902 */ 8903 var black_mask = 0xf3ffc07f; 8904 var n; 8905 8906 /* Check for non-textual ("black-listed") bytes. */ 8907 for (n = 0; n <= 31; n++, black_mask >>>= 1) { 8908 if ((black_mask & 1) && (s.dyn_ltree[n*2]/*.Freq*/ !== 0)) { 8909 return Z_BINARY; 8910 } 8911 } 8912 8913 /* Check for textual ("white-listed") bytes. */ 8914 if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 || 8915 s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) { 8916 return Z_TEXT; 8917 } 8918 for (n = 32; n < LITERALS; n++) { 8919 if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) { 8920 return Z_TEXT; 8921 } 8922 } 8923 8924 /* There are no "black-listed" or "white-listed" bytes: 8925 * this stream either is empty or has tolerated ("gray-listed") bytes only. 8926 */ 8927 return Z_BINARY; 8928} 8929 8930 8931var static_init_done = false; 8932 8933/* =========================================================================== 8934 * Initialize the tree data structures for a new zlib stream. 8935 */ 8936function _tr_init(s) 8937{ 8938 8939 if (!static_init_done) { 8940 tr_static_init(); 8941 static_init_done = true; 8942 } 8943 8944 s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc); 8945 s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc); 8946 s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc); 8947 8948 s.bi_buf = 0; 8949 s.bi_valid = 0; 8950 8951 /* Initialize the first block of the first file: */ 8952 init_block(s); 8953} 8954 8955 8956/* =========================================================================== 8957 * Send a stored block 8958 */ 8959function _tr_stored_block(s, buf, stored_len, last) 8960//DeflateState *s; 8961//charf *buf; /* input block */ 8962//ulg stored_len; /* length of input block */ 8963//int last; /* one if this is the last block for a file */ 8964{ 8965 send_bits(s, (STORED_BLOCK<<1)+(last ? 1 : 0), 3); /* send block type */ 8966 copy_block(s, buf, stored_len, true); /* with header */ 8967} 8968 8969 8970/* =========================================================================== 8971 * Send one empty static block to give enough lookahead for inflate. 8972 * This takes 10 bits, of which 7 may remain in the bit buffer. 8973 */ 8974function _tr_align(s) { 8975 send_bits(s, STATIC_TREES<<1, 3); 8976 send_code(s, END_BLOCK, static_ltree); 8977 bi_flush(s); 8978} 8979 8980 8981/* =========================================================================== 8982 * Determine the best encoding for the current block: dynamic trees, static 8983 * trees or store, and output the encoded block to the zip file. 8984 */ 8985function _tr_flush_block(s, buf, stored_len, last) 8986//DeflateState *s; 8987//charf *buf; /* input block, or NULL if too old */ 8988//ulg stored_len; /* length of input block */ 8989//int last; /* one if this is the last block for a file */ 8990{ 8991 var opt_lenb, static_lenb; /* opt_len and static_len in bytes */ 8992 var max_blindex = 0; /* index of last bit length code of non zero freq */ 8993 8994 /* Build the Huffman trees unless a stored block is forced */ 8995 if (s.level > 0) { 8996 8997 /* Check if the file is binary or text */ 8998 if (s.strm.data_type === Z_UNKNOWN) { 8999 s.strm.data_type = detect_data_type(s); 9000 } 9001 9002 /* Construct the literal and distance trees */ 9003 build_tree(s, s.l_desc); 9004 // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, 9005 // s->static_len)); 9006 9007 build_tree(s, s.d_desc); 9008 // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, 9009 // s->static_len)); 9010 /* At this point, opt_len and static_len are the total bit lengths of 9011 * the compressed block data, excluding the tree representations. 9012 */ 9013 9014 /* Build the bit length tree for the above two trees, and get the index 9015 * in bl_order of the last bit length code to send. 9016 */ 9017 max_blindex = build_bl_tree(s); 9018 9019 /* Determine the best encoding. Compute the block lengths in bytes. */ 9020 opt_lenb = (s.opt_len+3+7) >>> 3; 9021 static_lenb = (s.static_len+3+7) >>> 3; 9022 9023 // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", 9024 // opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, 9025 // s->last_lit)); 9026 9027 if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; } 9028 9029 } else { 9030 // Assert(buf != (char*)0, "lost buf"); 9031 opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ 9032 } 9033 9034 if ((stored_len+4 <= opt_lenb) && (buf !== -1)) { 9035 /* 4: two words for the lengths */ 9036 9037 /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. 9038 * Otherwise we can't have processed more than WSIZE input bytes since 9039 * the last block flush, because compression would have been 9040 * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to 9041 * transform a block into a stored block. 9042 */ 9043 _tr_stored_block(s, buf, stored_len, last); 9044 9045 } else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) { 9046 9047 send_bits(s, (STATIC_TREES<<1) + (last ? 1 : 0), 3); 9048 compress_block(s, static_ltree, static_dtree); 9049 9050 } else { 9051 send_bits(s, (DYN_TREES<<1) + (last ? 1 : 0), 3); 9052 send_all_trees(s, s.l_desc.max_code+1, s.d_desc.max_code+1, max_blindex+1); 9053 compress_block(s, s.dyn_ltree, s.dyn_dtree); 9054 } 9055 // Assert (s->compressed_len == s->bits_sent, "bad compressed size"); 9056 /* The above check is made mod 2^32, for files larger than 512 MB 9057 * and uLong implemented on 32 bits. 9058 */ 9059 init_block(s); 9060 9061 if (last) { 9062 bi_windup(s); 9063 } 9064 // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, 9065 // s->compressed_len-7*last)); 9066} 9067 9068/* =========================================================================== 9069 * Save the match info and tally the frequency counts. Return true if 9070 * the current block must be flushed. 9071 */ 9072function _tr_tally(s, dist, lc) 9073// deflate_state *s; 9074// unsigned dist; /* distance of matched string */ 9075// unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ 9076{ 9077 //var out_length, in_length, dcode; 9078 9079 s.pending_buf[s.d_buf + s.last_lit * 2] = (dist >>> 8) & 0xff; 9080 s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff; 9081 9082 s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff; 9083 s.last_lit++; 9084 9085 if (dist === 0) { 9086 /* lc is the unmatched char */ 9087 s.dyn_ltree[lc*2]/*.Freq*/++; 9088 } else { 9089 s.matches++; 9090 /* Here, lc is the match length - MIN_MATCH */ 9091 dist--; /* dist = match distance - 1 */ 9092 //Assert((ush)dist < (ush)MAX_DIST(s) && 9093 // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && 9094 // (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); 9095 9096 s.dyn_ltree[(_length_code[lc]+LITERALS+1) * 2]/*.Freq*/++; 9097 s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++; 9098 } 9099 9100// (!) This block is disabled in zlib defailts, 9101// don't enable it for binary compatibility 9102 9103//#ifdef TRUNCATE_BLOCK 9104// /* Try to guess if it is profitable to stop the current block here */ 9105// if ((s.last_lit & 0x1fff) === 0 && s.level > 2) { 9106// /* Compute an upper bound for the compressed length */ 9107// out_length = s.last_lit*8; 9108// in_length = s.strstart - s.block_start; 9109// 9110// for (dcode = 0; dcode < D_CODES; dcode++) { 9111// out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]); 9112// } 9113// out_length >>>= 3; 9114// //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", 9115// // s->last_lit, in_length, out_length, 9116// // 100L - out_length*100L/in_length)); 9117// if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) { 9118// return true; 9119// } 9120// } 9121//#endif 9122 9123 return (s.last_lit === s.lit_bufsize-1); 9124 /* We avoid equality with lit_bufsize because of wraparound at 64K 9125 * on 16 bit machines and because stored blocks are restricted to 9126 * 64K-1 bytes. 9127 */ 9128} 9129 9130exports._tr_init = _tr_init; 9131exports._tr_stored_block = _tr_stored_block; 9132exports._tr_flush_block = _tr_flush_block; 9133exports._tr_tally = _tr_tally; 9134exports._tr_align = _tr_align; 9135},{"../utils/common":27}],39:[function(_dereq_,module,exports){ 9136'use strict'; 9137 9138 9139function ZStream() { 9140 /* next input byte */ 9141 this.input = null; // JS specific, because we have no pointers 9142 this.next_in = 0; 9143 /* number of bytes available at input */ 9144 this.avail_in = 0; 9145 /* total number of input bytes read so far */ 9146 this.total_in = 0; 9147 /* next output byte should be put there */ 9148 this.output = null; // JS specific, because we have no pointers 9149 this.next_out = 0; 9150 /* remaining free space at output */ 9151 this.avail_out = 0; 9152 /* total number of bytes output so far */ 9153 this.total_out = 0; 9154 /* last error message, NULL if no error */ 9155 this.msg = ''/*Z_NULL*/; 9156 /* not visible by applications */ 9157 this.state = null; 9158 /* best guess about the data type: binary or text */ 9159 this.data_type = 2/*Z_UNKNOWN*/; 9160 /* adler32 value of the uncompressed data */ 9161 this.adler = 0; 9162} 9163 9164module.exports = ZStream; 9165},{}]},{},[9]) 9166(9) 9167});
9168 9169/*! DataTables 1.10.18 9170 * ©2008-2018 SpryMedia Ltd - datatables.net/license 9171 */ 9172 9173/** 9174 * @summary DataTables 9175 * @description Paginate, search and order HTML tables 9176 * @version 1.10.18 9177 * @file jquery.dataTables.js 9178 * @author SpryMedia Ltd 9179 * @contact www.datatables.net 9180 * @copyright Copyright 2008-2018 SpryMedia Ltd. 9181 * 9182 * This source file is free software, available under the following license: 9183 * MIT license - http://datatables.net/license 9184 * 9185 * This source file is distributed in the hope that it will be useful, but 9186 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 9187 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. 9188 * 9189 * For details please refer to: http://www.datatables.net 9190 */ 9191 9192/*jslint evil: true, undef: true, browser: true */ 9193/*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,_pluck_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*/ 9194 9195(function( factory ) { 9196 "use strict"; 9197 9198 if ( typeof define === 'function' && define.amd ) { 9199 // AMD 9200 define( ['jquery'], function ( $ ) { 9201 return factory( $, window, document ); 9202 } ); 9203 } 9204 else if ( typeof exports === 'object' ) { 9205 // CommonJS 9206 module.exports = function (root, $) { 9207 if ( ! root ) { 9208 // CommonJS environments without a window global must pass a 9209 // root. This will give an error otherwise 9210 root = window; 9211 } 9212 9213 if ( ! $ ) { 9214 $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window 9215 require('jquery') : 9216 require('jquery')( root ); 9217 } 9218 9219 return factory( $, root, root.document ); 9220 }; 9221 } 9222 else { 9223 // Browser 9224 factory( jQuery, window, document ); 9225 } 9226} 9227(function( $, window, document, undefined ) { 9228 "use strict"; 9229 9230 /** 9231 * DataTables is a plug-in for the jQuery Javascript library. It is a highly 9232 * flexible tool, based upon the foundations of progressive enhancement, 9233 * which will add advanced interaction controls to any HTML table. For a 9234 * full list of features please refer to 9235 * [DataTables.net](href="http://datatables.net). 9236 * 9237 * Note that the `DataTable` object is not a global variable but is aliased 9238 * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may 9239 * be accessed. 9240 * 9241 * @class 9242 * @param {object} [init={}] Configuration object for DataTables. Options 9243 * are defined by {@link DataTable.defaults} 9244 * @requires jQuery 1.7+ 9245 * 9246 * @example 9247 * // Basic initialisation 9248 * $(document).ready( function { 9249 * $('#example').dataTable(); 9250 * } ); 9251 * 9252 * @example 9253 * // Initialisation with configuration options - in this case, disable 9254 * // pagination and sorting. 9255 * $(document).ready( function { 9256 * $('#example').dataTable( { 9257 * "paginate": false, 9258 * "sort": false 9259 * } ); 9260 * } ); 9261 */ 9262 var DataTable = function ( options ) 9263 {
vendor: 6,636 bytes, lines 9263-9422
9263 9264 /** 9265 * Perform a jQuery selector action on the table's TR elements (from the tbody) and 9266 * return the resulting jQuery object. 9267 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on 9268 * @param {object} [oOpts] Optional parameters for modifying the rows to be included 9269 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter 9270 * criterion ("applied") or all TR elements (i.e. no filter). 9271 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array. 9272 * Can be either 'current', whereby the current sorting of the table is used, or 9273 * 'original' whereby the original order the data was read into the table is used. 9274 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page 9275 * ("current") or not ("all"). If 'current' is given, then order is assumed to be 9276 * 'current' and filter is 'applied', regardless of what they might be given as. 9277 * @returns {object} jQuery object, filtered by the given selector. 9278 * @dtopt API 9279 * @deprecated Since v1.10 9280 * 9281 * @example 9282 * $(document).ready(function() { 9283 * var oTable = $('#example').dataTable(); 9284 * 9285 * // Highlight every second row 9286 * oTable.$('tr:odd').css('backgroundColor', 'blue'); 9287 * } ); 9288 * 9289 * @example 9290 * $(document).ready(function() { 9291 * var oTable = $('#example').dataTable(); 9292 * 9293 * // Filter to rows with 'Webkit' in them, add a background colour and then 9294 * // remove the filter, thus highlighting the 'Webkit' rows only. 9295 * oTable.fnFilter('Webkit'); 9296 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue'); 9297 * oTable.fnFilter(''); 9298 * } ); 9299 */ 9300 this.$ = function ( sSelector, oOpts ) 9301 { 9302 return this.api(true).$( sSelector, oOpts ); 9303 }; 9304 9305 9306 /** 9307 * Almost identical to $ in operation, but in this case returns the data for the matched 9308 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes 9309 * rather than any descendants, so the data can be obtained for the row/cell. If matching 9310 * rows are found, the data returned is the original data array/object that was used to 9311 * create the row (or a generated array if from a DOM source). 9312 * 9313 * This method is often useful in-combination with $ where both functions are given the 9314 * same parameters and the array indexes will match identically. 9315 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on 9316 * @param {object} [oOpts] Optional parameters for modifying the rows to be included 9317 * @param {string} [oOpts.filter=none] Select elements that meet the current filter 9318 * criterion ("applied") or all elements (i.e. no filter). 9319 * @param {string} [oOpts.order=current] Order of the data in the processed array. 9320 * Can be either 'current', whereby the current sorting of the table is used, or 9321 * 'original' whereby the original order the data was read into the table is used. 9322 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page 9323 * ("current") or not ("all"). If 'current' is given, then order is assumed to be 9324 * 'current' and filter is 'applied', regardless of what they might be given as. 9325 * @returns {array} Data for the matched elements. If any elements, as a result of the 9326 * selector, were not TR, TD or TH elements in the DataTable, they will have a null 9327 * entry in the array. 9328 * @dtopt API 9329 * @deprecated Since v1.10 9330 * 9331 * @example 9332 * $(document).ready(function() { 9333 * var oTable = $('#example').dataTable(); 9334 * 9335 * // Get the data from the first row in the table 9336 * var data = oTable._('tr:first'); 9337 * 9338 * // Do something useful with the data 9339 * alert( "First cell is: "+data[0] ); 9340 * } ); 9341 * 9342 * @example 9343 * $(document).ready(function() { 9344 * var oTable = $('#example').dataTable(); 9345 * 9346 * // Filter to 'Webkit' and get all data for 9347 * oTable.fnFilter('Webkit'); 9348 * var data = oTable._('tr', {"search": "applied"}); 9349 * 9350 * // Do something with the data 9351 * alert( data.length+" rows matched the search" ); 9352 * } ); 9353 */ 9354 this._ = function ( sSelector, oOpts ) 9355 { 9356 return this.api(true).rows( sSelector, oOpts ).data(); 9357 }; 9358 9359 9360 /** 9361 * Create a DataTables Api instance, with the currently selected tables for 9362 * the Api's context. 9363 * @param {boolean} [traditional=false] Set the API instance's context to be 9364 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was 9365 * used in the API presented by DataTables 1.9- (i.e. the traditional mode), 9366 * or if all tables captured in the jQuery object should be used. 9367 * @return {DataTables.Api} 9368 */ 9369 this.api = function ( traditional ) 9370 { 9371 return traditional ? 9372 new _Api( 9373 _fnSettingsFromNode( this[ _ext.iApiIndex ] ) 9374 ) : 9375 new _Api( this ); 9376 }; 9377 9378 9379 /** 9380 * Add a single new row or multiple rows of data to the table. Please note 9381 * that this is suitable for client-side processing only - if you are using 9382 * server-side processing (i.e. "bServerSide": true), then to add data, you 9383 * must add it to the data source, i.e. the server-side, through an Ajax call. 9384 * @param {array|object} data The data to be added to the table. This can be: 9385 * <ul> 9386 * <li>1D array of data - add a single row with the data provided</li> 9387 * <li>2D array of arrays - add multiple rows in a single call</li> 9388 * <li>object - data object when using <i>mData</i></li> 9389 * <li>array of objects - multiple data objects when using <i>mData</i></li> 9390 * </ul> 9391 * @param {bool} [redraw=true] redraw the table or not 9392 * @returns {array} An array of integers, representing the list of indexes in 9393 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to 9394 * the table. 9395 * @dtopt API 9396 * @deprecated Since v1.10 9397 * 9398 * @example 9399 * // Global var for counter 9400 * var giCount = 2; 9401 * 9402 * $(document).ready(function() { 9403 * $('#example').dataTable(); 9404 * } ); 9405 * 9406 * function fnClickAddRow() { 9407 * $('#example').dataTable().fnAddData( [ 9408 * giCount+".1", 9409 * giCount+".2", 9410 * giCount+".3", 9411 * giCount+".4" ] 9412 * ); 9413 * 9414 * giCount++; 9415 * } 9416 */ 9417 this.fnAddData = function( data, redraw ) 9418 { 9419 var api = this.api( true ); 9420 9421 /* Check if we want to add multiple rows or not */ 9422 var rows =
9422$.isArray(data) && ( $
vendor: 18,409 bytes, lines 9422-10018
9422.isArray(data[0]) || $.isPlainObject(data[0]) ) ? 9423 api.rows.add( data ) : 9424 api.row.add( data ); 9425 9426 if ( redraw === undefined || redraw ) { 9427 api.draw(); 9428 } 9429 9430 return rows.flatten().toArray(); 9431 }; 9432 9433 9434 /** 9435 * This function will make DataTables recalculate the column sizes, based on the data 9436 * contained in the table and the sizes applied to the columns (in the DOM, CSS or 9437 * through the sWidth parameter). This can be useful when the width of the table's 9438 * parent element changes (for example a window resize). 9439 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to 9440 * @dtopt API 9441 * @deprecated Since v1.10 9442 * 9443 * @example 9444 * $(document).ready(function() { 9445 * var oTable = $('#example').dataTable( { 9446 * "sScrollY": "200px", 9447 * "bPaginate": false 9448 * } ); 9449 * 9450 * $(window).on('resize', function () { 9451 * oTable.fnAdjustColumnSizing(); 9452 * } ); 9453 * } ); 9454 */ 9455 this.fnAdjustColumnSizing = function ( bRedraw ) 9456 { 9457 var api = this.api( true ).columns.adjust(); 9458 var settings = api.settings()[0]; 9459 var scroll = settings.oScroll; 9460 9461 if ( bRedraw === undefined || bRedraw ) { 9462 api.draw( false ); 9463 } 9464 else if ( scroll.sX !== "" || scroll.sY !== "" ) { 9465 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */ 9466 _fnScrollDraw( settings ); 9467 } 9468 }; 9469 9470 9471 /** 9472 * Quickly and simply clear a table 9473 * @param {bool} [bRedraw=true] redraw the table or not 9474 * @dtopt API 9475 * @deprecated Since v1.10 9476 * 9477 * @example 9478 * $(document).ready(function() { 9479 * var oTable = $('#example').dataTable(); 9480 * 9481 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...) 9482 * oTable.fnClearTable(); 9483 * } ); 9484 */ 9485 this.fnClearTable = function( bRedraw ) 9486 { 9487 var api = this.api( true ).clear(); 9488 9489 if ( bRedraw === undefined || bRedraw ) { 9490 api.draw(); 9491 } 9492 }; 9493 9494 9495 /** 9496 * The exact opposite of 'opening' a row, this function will close any rows which 9497 * are currently 'open'. 9498 * @param {node} nTr the table row to 'close' 9499 * @returns {int} 0 on success, or 1 if failed (can't find the row) 9500 * @dtopt API 9501 * @deprecated Since v1.10 9502 * 9503 * @example 9504 * $(document).ready(function() { 9505 * var oTable; 9506 * 9507 * // 'open' an information row when a row is clicked on 9508 * $('#example tbody tr').click( function () { 9509 * if ( oTable.fnIsOpen(this) ) { 9510 * oTable.fnClose( this ); 9511 * } else { 9512 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 9513 * } 9514 * } ); 9515 * 9516 * oTable = $('#example').dataTable(); 9517 * } ); 9518 */ 9519 this.fnClose = function( nTr ) 9520 { 9521 this.api( true ).row( nTr ).child.hide(); 9522 }; 9523 9524 9525 /** 9526 * Remove a row for the table 9527 * @param {mixed} target The index of the row from aoData to be deleted, or 9528 * the TR element you want to delete 9529 * @param {function|null} [callBack] Callback function 9530 * @param {bool} [redraw=true] Redraw the table or not 9531 * @returns {array} The row that was deleted 9532 * @dtopt API 9533 * @deprecated Since v1.10 9534 * 9535 * @example 9536 * $(document).ready(function() { 9537 * var oTable = $('#example').dataTable(); 9538 * 9539 * // Immediately remove the first row 9540 * oTable.fnDeleteRow( 0 ); 9541 * } ); 9542 */ 9543 this.fnDeleteRow = function( target, callback, redraw ) 9544 { 9545 var api = this.api( true ); 9546 var rows = api.rows( target ); 9547 var settings = rows.settings()[0]; 9548 var data = settings.aoData[ rows[0][0] ]; 9549 9550 rows.remove(); 9551 9552 if ( callback ) { 9553 callback.call( this, settings, data ); 9554 } 9555 9556 if ( redraw === undefined || redraw ) { 9557 api.draw(); 9558 } 9559 9560 return data; 9561 }; 9562 9563 9564 /** 9565 * Restore the table to it's original state in the DOM by removing all of DataTables 9566 * enhancements, alterations to the DOM structure of the table and event listeners. 9567 * @param {boolean} [remove=false] Completely remove the table from the DOM 9568 * @dtopt API 9569 * @deprecated Since v1.10 9570 * 9571 * @example 9572 * $(document).ready(function() { 9573 * // This example is fairly pointless in reality, but shows how fnDestroy can be used 9574 * var oTable = $('#example').dataTable(); 9575 * oTable.fnDestroy(); 9576 * } ); 9577 */ 9578 this.fnDestroy = function ( remove ) 9579 { 9580 this.api( true ).destroy( remove ); 9581 }; 9582 9583 9584 /** 9585 * Redraw the table 9586 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw. 9587 * @dtopt API 9588 * @deprecated Since v1.10 9589 * 9590 * @example 9591 * $(document).ready(function() { 9592 * var oTable = $('#example').dataTable(); 9593 * 9594 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-) 9595 * oTable.fnDraw(); 9596 * } ); 9597 */ 9598 this.fnDraw = function( complete ) 9599 { 9600 // Note that this isn't an exact match to the old call to _fnDraw - it takes 9601 // into account the new data, but can hold position. 9602 this.api( true ).draw( complete ); 9603 }; 9604 9605 9606 /** 9607 * Filter the input based on data 9608 * @param {string} sInput String to filter the table on 9609 * @param {int|null} [iColumn] Column to limit filtering to 9610 * @param {bool} [bRegex=false] Treat as regular expression or not 9611 * @param {bool} [bSmart=true] Perform smart filtering or not 9612 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es) 9613 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false) 9614 * @dtopt API 9615 * @deprecated Since v1.10 9616 * 9617 * @example 9618 * $(document).ready(function() { 9619 * var oTable = $('#example').dataTable(); 9620 * 9621 * // Sometime later - filter... 9622 * oTable.fnFilter( 'test string' ); 9623 * } ); 9624 */ 9625 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive ) 9626 { 9627 var api = this.api( true ); 9628 9629 if ( iColumn === null || iColumn === undefined ) { 9630 api.search( sInput, bRegex, bSmart, bCaseInsensitive ); 9631 } 9632 else { 9633 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive ); 9634 } 9635 9636 api.draw(); 9637 }; 9638 9639 9640 /** 9641 * Get the data for the whole table, an individual row or an individual cell based on the 9642 * provided parameters. 9643 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as 9644 * a TR node then the data source for the whole row will be returned. If given as a 9645 * TD/TH cell node then iCol will be automatically calculated and the data for the 9646 * cell returned. If given as an integer, then this is treated as the aoData internal 9647 * data index for the row (see fnGetPosition) and the data for that row used. 9648 * @param {int} [col] Optional column index that you want the data of. 9649 * @returns {array|object|string} If mRow is undefined, then the data for all rows is 9650 * returned. If mRow is defined, just data for that row, and is iCol is 9651 * defined, only data for the designated cell is returned. 9652 * @dtopt API 9653 * @deprecated Since v1.10 9654 * 9655 * @example 9656 * // Row data 9657 * $(document).ready(function() { 9658 * oTable = $('#example').dataTable(); 9659 * 9660 * oTable.$('tr').click( function () { 9661 * var data = oTable.fnGetData( this ); 9662 * // ... do something with the array / object of data for the row 9663 * } ); 9664 * } ); 9665 * 9666 * @example 9667 * // Individual cell data 9668 * $(document).ready(function() { 9669 * oTable = $('#example').dataTable(); 9670 * 9671 * oTable.$('td').click( function () { 9672 * var sData = oTable.fnGetData( this ); 9673 * alert( 'The cell clicked on had the value of '+sData ); 9674 * } ); 9675 * } ); 9676 */ 9677 this.fnGetData = function( src, col ) 9678 { 9679 var api = this.api( true ); 9680 9681 if ( src !== undefined ) { 9682 var type = src.nodeName ? src.nodeName.toLowerCase() : ''; 9683 9684 return col !== undefined || type == 'td' || type == 'th' ? 9685 api.cell( src, col ).data() : 9686 api.row( src ).data() || null; 9687 } 9688 9689 return api.data().toArray(); 9690 }; 9691 9692 9693 /** 9694 * Get an array of the TR nodes that are used in the table's body. Note that you will 9695 * typically want to use the '$' API method in preference to this as it is more 9696 * flexible. 9697 * @param {int} [iRow] Optional row index for the TR element you want 9698 * @returns {array|node} If iRow is undefined, returns an array of all TR elements 9699 * in the table's body, or iRow is defined, just the TR element requested. 9700 * @dtopt API 9701 * @deprecated Since v1.10 9702 * 9703 * @example 9704 * $(document).ready(function() { 9705 * var oTable = $('#example').dataTable(); 9706 * 9707 * // Get the nodes from the table 9708 * var nNodes = oTable.fnGetNodes( ); 9709 * } ); 9710 */ 9711 this.fnGetNodes = function( iRow ) 9712 { 9713 var api = this.api( true ); 9714 9715 return iRow !== undefined ? 9716 api.row( iRow ).node() : 9717 api.rows().nodes().flatten().toArray(); 9718 }; 9719 9720 9721 /** 9722 * Get the array indexes of a particular cell from it's DOM element 9723 * and column index including hidden columns 9724 * @param {node} node this can either be a TR, TD or TH in the table's body 9725 * @returns {int} If nNode is given as a TR, then a single index is returned, or 9726 * if given as a cell, an array of [row index, column index (visible), 9727 * column index (all)] is given. 9728 * @dtopt API 9729 * @deprecated Since v1.10 9730 * 9731 * @example 9732 * $(document).ready(function() { 9733 * $('#example tbody td').click( function () { 9734 * // Get the position of the current data from the node 9735 * var aPos = oTable.fnGetPosition( this ); 9736 * 9737 * // Get the data array for this row 9738 * var aData = oTable.fnGetData( aPos[0] ); 9739 * 9740 * // Update the data array and return the value 9741 * aData[ aPos[1] ] = 'clicked'; 9742 * this.innerHTML = 'clicked'; 9743 * } ); 9744 * 9745 * // Init DataTables 9746 * oTable = $('#example').dataTable(); 9747 * } ); 9748 */ 9749 this.fnGetPosition = function( node ) 9750 { 9751 var api = this.api( true ); 9752 var nodeName = node.nodeName.toUpperCase(); 9753 9754 if ( nodeName == 'TR' ) { 9755 return api.row( node ).index(); 9756 } 9757 else if ( nodeName == 'TD' || nodeName == 'TH' ) { 9758 var cell = api.cell( node ).index(); 9759 9760 return [ 9761 cell.row, 9762 cell.columnVisible, 9763 cell.column 9764 ]; 9765 } 9766 return null; 9767 }; 9768 9769 9770 /** 9771 * Check to see if a row is 'open' or not. 9772 * @param {node} nTr the table row to check 9773 * @returns {boolean} true if the row is currently open, false otherwise 9774 * @dtopt API 9775 * @deprecated Since v1.10 9776 * 9777 * @example 9778 * $(document).ready(function() { 9779 * var oTable; 9780 * 9781 * // 'open' an information row when a row is clicked on 9782 * $('#example tbody tr').click( function () { 9783 * if ( oTable.fnIsOpen(this) ) { 9784 * oTable.fnClose( this ); 9785 * } else { 9786 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 9787 * } 9788 * } ); 9789 * 9790 * oTable = $('#example').dataTable(); 9791 * } ); 9792 */ 9793 this.fnIsOpen = function( nTr ) 9794 { 9795 return this.api( true ).row( nTr ).child.isShown(); 9796 }; 9797 9798 9799 /** 9800 * This function will place a new row directly after a row which is currently 9801 * on display on the page, with the HTML contents that is passed into the 9802 * function. This can be used, for example, to ask for confirmation that a 9803 * particular record should be deleted. 9804 * @param {node} nTr The table row to 'open' 9805 * @param {string|node|jQuery} mHtml The HTML to put into the row 9806 * @param {string} sClass Class to give the new TD cell 9807 * @returns {node} The row opened. Note that if the table row passed in as the 9808 * first parameter, is not found in the table, this method will silently 9809 * return. 9810 * @dtopt API 9811 * @deprecated Since v1.10 9812 * 9813 * @example 9814 * $(document).ready(function() { 9815 * var oTable; 9816 * 9817 * // 'open' an information row when a row is clicked on 9818 * $('#example tbody tr').click( function () { 9819 * if ( oTable.fnIsOpen(this) ) { 9820 * oTable.fnClose( this ); 9821 * } else { 9822 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 9823 * } 9824 * } ); 9825 * 9826 * oTable = $('#example').dataTable(); 9827 * } ); 9828 */ 9829 this.fnOpen = function( nTr, mHtml, sClass ) 9830 { 9831 return this.api( true ) 9832 .row( nTr ) 9833 .child( mHtml, sClass ) 9834 .show() 9835 .child()[0]; 9836 }; 9837 9838 9839 /** 9840 * Change the pagination - provides the internal logic for pagination in a simple API 9841 * function. With this function you can have a DataTables table go to the next, 9842 * previous, first or last pages. 9843 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last" 9844 * or page number to jump to (integer), note that page 0 is the first page. 9845 * @param {bool} [bRedraw=true] Redraw the table or not 9846 * @dtopt API 9847 * @deprecated Since v1.10 9848 * 9849 * @example 9850 * $(document).ready(function() { 9851 * var oTable = $('#example').dataTable(); 9852 * oTable.fnPageChange( 'next' ); 9853 * } ); 9854 */ 9855 this.fnPageChange = function ( mAction, bRedraw ) 9856 { 9857 var api = this.api( true ).page( mAction ); 9858 9859 if ( bRedraw === undefined || bRedraw ) { 9860 api.draw(false); 9861 } 9862 }; 9863 9864 9865 /** 9866 * Show a particular column 9867 * @param {int} iCol The column whose display should be changed 9868 * @param {bool} bShow Show (true) or hide (false) the column 9869 * @param {bool} [bRedraw=true] Redraw the table or not 9870 * @dtopt API 9871 * @deprecated Since v1.10 9872 * 9873 * @example 9874 * $(document).ready(function() { 9875 * var oTable = $('#example').dataTable(); 9876 * 9877 * // Hide the second column after initialisation 9878 * oTable.fnSetColumnVis( 1, false ); 9879 * } ); 9880 */ 9881 this.fnSetColumnVis = function ( iCol, bShow, bRedraw ) 9882 { 9883 var api = this.api( true ).column( iCol ).visible( bShow ); 9884 9885 if ( bRedraw === undefined || bRedraw ) { 9886 api.columns.adjust().draw(); 9887 } 9888 }; 9889 9890 9891 /** 9892 * Get the settings for a particular table for external manipulation 9893 * @returns {object} DataTables settings object. See 9894 * {@link DataTable.models.oSettings} 9895 * @dtopt API 9896 * @deprecated Since v1.10 9897 * 9898 * @example 9899 * $(document).ready(function() { 9900 * var oTable = $('#example').dataTable(); 9901 * var oSettings = oTable.fnSettings(); 9902 * 9903 * // Show an example parameter from the settings 9904 * alert( oSettings._iDisplayStart ); 9905 * } ); 9906 */ 9907 this.fnSettings = function() 9908 { 9909 return _fnSettingsFromNode( this[_ext.iApiIndex] ); 9910 }; 9911 9912 9913 /** 9914 * Sort the table by a particular column 9915 * @param {int} iCol the data index to sort on. Note that this will not match the 9916 * 'display index' if you have hidden data entries 9917 * @dtopt API 9918 * @deprecated Since v1.10 9919 * 9920 * @example 9921 * $(document).ready(function() { 9922 * var oTable = $('#example').dataTable(); 9923 * 9924 * // Sort immediately with columns 0 and 1 9925 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] ); 9926 * } ); 9927 */ 9928 this.fnSort = function( aaSort ) 9929 { 9930 this.api( true ).order( aaSort ).draw(); 9931 }; 9932 9933 9934 /** 9935 * Attach a sort listener to an element for a given column 9936 * @param {node} nNode the element to attach the sort listener to 9937 * @param {int} iColumn the column that a click on this node will sort on 9938 * @param {function} [fnCallback] callback function when sort is run 9939 * @dtopt API 9940 * @deprecated Since v1.10 9941 * 9942 * @example 9943 * $(document).ready(function() { 9944 * var oTable = $('#example').dataTable(); 9945 * 9946 * // Sort on column 1, when 'sorter' is clicked on 9947 * oTable.fnSortListener( document.getElementById('sorter'), 1 ); 9948 * } ); 9949 */ 9950 this.fnSortListener = function( nNode, iColumn, fnCallback ) 9951 { 9952 this.api( true ).order.listener( nNode, iColumn, fnCallback ); 9953 }; 9954 9955 9956 /** 9957 * Update a table cell or row - this method will accept either a single value to 9958 * update the cell with, an array of values with one element for each column or 9959 * an object in the same format as the original data source. The function is 9960 * self-referencing in order to make the multi column updates easier. 9961 * @param {object|array|string} mData Data to update the cell/row with 9962 * @param {node|int} mRow TR element you want to update or the aoData index 9963 * @param {int} [iColumn] The column to update, give as null or undefined to 9964 * update a whole row. 9965 * @param {bool} [bRedraw=true] Redraw the table or not 9966 * @param {bool} [bAction=true] Perform pre-draw actions or not 9967 * @returns {int} 0 on success, 1 on error 9968 * @dtopt API 9969 * @deprecated Since v1.10 9970 * 9971 * @example 9972 * $(document).ready(function() { 9973 * var oTable = $('#example').dataTable(); 9974 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell 9975 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row 9976 * } ); 9977 */ 9978 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction ) 9979 { 9980 var api = this.api( true ); 9981 9982 if ( iColumn === undefined || iColumn === null ) { 9983 api.row( mRow ).data( mData ); 9984 } 9985 else { 9986 api.cell( mRow, iColumn ).data( mData ); 9987 } 9988 9989 if ( bAction === undefined || bAction ) { 9990 api.columns.adjust(); 9991 } 9992 9993 if ( bRedraw === undefined || bRedraw ) { 9994 api.draw(); 9995 } 9996 return 0; 9997 }; 9998 9999 10000 /** 10001 * Provide a common method for plug-ins to check the version of DataTables being used, in order 10002 * to ensure compatibility. 10003 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the 10004 * formats "X" and "X.Y" are also acceptable. 10005 * @returns {boolean} true if this version of DataTables is greater or equal to the required 10006 * version, or false if this version of DataTales is not suitable 10007 * @method 10008 * @dtopt API 10009 * @deprecated Since v1.10 10010 * 10011 * @example 10012 * $(document).ready(function() { 10013 * var oTable = $('#example').dataTable(); 10014 * alert( oTable.fnVersionCheck( '1.9.0' ) ); 10015 * } ); 10016 */ 10017 this.fnVersionCheck = _ext.fnVersionCheck; 10018
vendor: 57,803 bytes, lines 10019-12039
10019 10020 var _that = this; 10021 var emptyInit = options === undefined; 10022 var len = this.length; 10023 10024 if ( emptyInit ) { 10025 options = {}; 10026 } 10027 10028 this.oApi = this.internal = _ext.internal; 10029 10030 // Extend with old style plug-in API methods 10031 for ( var fn in DataTable.ext.internal ) { 10032 if ( fn ) { 10033 this[fn] = _fnExternApiFunc(fn); 10034 } 10035 } 10036 10037 this.each(function() { 10038 // For each initialisation we want to give it a clean initialisation 10039 // object that can be bashed around 10040 var o = {}; 10041 var oInit = len > 1 ? // optimisation for single table case 10042 _fnExtend( o, options, true ) : 10043 options; 10044 10045 /*global oInit,_that,emptyInit*/ 10046 var i=0, iLen, j, jLen, k, kLen; 10047 var sId = this.getAttribute( 'id' ); 10048 var bInitHandedOff = false; 10049 var defaults = DataTable.defaults; 10050 var $this = $(this); 10051 10052 10053 /* Sanity check */ 10054 if ( this.nodeName.toLowerCase() != 'table' ) 10055 { 10056 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 ); 10057 return; 10058 } 10059 10060 /* Backwards compatibility for the defaults */ 10061 _fnCompatOpts( defaults ); 10062 _fnCompatCols( defaults.column ); 10063 10064 /* Convert the camel-case defaults to Hungarian */ 10065 _fnCamelToHungarian( defaults, defaults, true ); 10066 _fnCamelToHungarian( defaults.column, defaults.column, true ); 10067 10068 /* Setting up the initialisation object */ 10069 _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) ); 10070 10071 10072 10073 /* Check to see if we are re-initialising a table */ 10074 var allSettings = DataTable.settings; 10075 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ ) 10076 { 10077 var s = allSettings[i]; 10078 10079 /* Base check on table node */ 10080 if ( 10081 s.nTable == this || 10082 (s.nTHead && s.nTHead.parentNode == this) || 10083 (s.nTFoot && s.nTFoot.parentNode == this) 10084 ) { 10085 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve; 10086 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy; 10087 10088 if ( emptyInit || bRetrieve ) 10089 { 10090 return s.oInstance; 10091 } 10092 else if ( bDestroy ) 10093 { 10094 s.oInstance.fnDestroy(); 10095 break; 10096 } 10097 else 10098 { 10099 _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 ); 10100 return; 10101 } 10102 } 10103 10104 /* If the element we are initialising has the same ID as a table which was previously 10105 * initialised, but the table nodes don't match (from before) then we destroy the old 10106 * instance by simply deleting it. This is under the assumption that the table has been 10107 * destroyed by other methods. Anyone using non-id selectors will need to do this manually 10108 */ 10109 if ( s.sTableId == this.id ) 10110 { 10111 allSettings.splice( i, 1 ); 10112 break; 10113 } 10114 } 10115 10116 /* Ensure the table has an ID - required for accessibility */ 10117 if ( sId === null || sId === "" ) 10118 { 10119 sId = "DataTables_Table_"+(DataTable.ext._unique++); 10120 this.id = sId; 10121 } 10122 10123 /* Create the settings object for this table and set some of the default parameters */ 10124 var oSettings = $.extend( true, {}, DataTable.models.oSettings, { 10125 "sDestroyWidth": $this[0].style.width, 10126 "sInstance": sId, 10127 "sTableId": sId 10128 } ); 10129 oSettings.nTable = this; 10130 oSettings.oApi = _that.internal; 10131 oSettings.oInit = oInit; 10132 10133 allSettings.push( oSettings ); 10134 10135 // Need to add the instance after the instance after the settings object has been added 10136 // to the settings array, so we can self reference the table instance if more than one 10137 oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable(); 10138 10139 // Backwards compatibility, before we apply all the defaults 10140 _fnCompatOpts( oInit ); 10141 _fnLanguageCompat( oInit.oLanguage ); 10142 10143 // If the length menu is given, but the init display length is not, use the length menu 10144 if ( oInit.aLengthMenu && ! oInit.iDisplayLength ) 10145 { 10146 oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ? 10147 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0]; 10148 } 10149 10150 // Apply the defaults and init options to make a single init object will all 10151 // options defined from defaults and instance options. 10152 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit ); 10153 10154 10155 // Map the initialisation options onto the settings object 10156 _fnMap( oSettings.oFeatures, oInit, [ 10157 "bPaginate", 10158 "bLengthChange", 10159 "bFilter", 10160 "bSort", 10161 "bSortMulti", 10162 "bInfo", 10163 "bProcessing", 10164 "bAutoWidth", 10165 "bSortClasses", 10166 "bServerSide", 10167 "bDeferRender" 10168 ] ); 10169 _fnMap( oSettings, oInit, [ 10170 "asStripeClasses", 10171 "ajax", 10172 "fnServerData", 10173 "fnFormatNumber", 10174 "sServerMethod", 10175 "aaSorting", 10176 "aaSortingFixed", 10177 "aLengthMenu", 10178 "sPaginationType", 10179 "sAjaxSource", 10180 "sAjaxDataProp", 10181 "iStateDuration", 10182 "sDom", 10183 "bSortCellsTop", 10184 "iTabIndex", 10185 "fnStateLoadCallback", 10186 "fnStateSaveCallback", 10187 "renderer", 10188 "searchDelay", 10189 "rowId", 10190 [ "iCookieDuration", "iStateDuration" ], // backwards compat 10191 [ "oSearch", "oPreviousSearch" ], 10192 [ "aoSearchCols", "aoPreSearchCols" ], 10193 [ "iDisplayLength", "_iDisplayLength" ] 10194 ] ); 10195 _fnMap( oSettings.oScroll, oInit, [ 10196 [ "sScrollX", "sX" ], 10197 [ "sScrollXInner", "sXInner" ], 10198 [ "sScrollY", "sY" ], 10199 [ "bScrollCollapse", "bCollapse" ] 10200 ] ); 10201 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" ); 10202 10203 /* Callback functions which are array driven */ 10204 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' ); 10205 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' ); 10206 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' ); 10207 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' ); 10208 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' ); 10209 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' ); 10210 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' ); 10211 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' ); 10212 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' ); 10213 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' ); 10214 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' ); 10215 10216 oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId ); 10217 10218 /* Browser support detection */ 10219 _fnBrowserDetect( oSettings ); 10220 10221 var oClasses = oSettings.oClasses; 10222 10223 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses ); 10224 $this.addClass( oClasses.sTable ); 10225 10226 10227 if ( oSettings.iInitDisplayStart === undefined ) 10228 { 10229 /* Display start point, taking into account the save saving */ 10230 oSettings.iInitDisplayStart = oInit.iDisplayStart; 10231 oSettings._iDisplayStart = oInit.iDisplayStart; 10232 } 10233 10234 if ( oInit.iDeferLoading !== null ) 10235 { 10236 oSettings.bDeferLoading = true; 10237 var tmp = $.isArray( oInit.iDeferLoading ); 10238 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading; 10239 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading; 10240 } 10241 10242 /* Language definitions */ 10243 var oLanguage = oSettings.oLanguage; 10244 $.extend( true, oLanguage, oInit.oLanguage ); 10245 10246 if ( oLanguage.sUrl ) 10247 { 10248 /* Get the language definitions from a file - because this Ajax call makes the language 10249 * get async to the remainder of this function we use bInitHandedOff to indicate that 10250 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor 10251 */ 10252 $.ajax( { 10253 dataType: 'json', 10254 url: oLanguage.sUrl, 10255 success: function ( json ) { 10256 _fnLanguageCompat( json ); 10257 _fnCamelToHungarian( defaults.oLanguage, json ); 10258 $.extend( true, oLanguage, json ); 10259 _fnInitialise( oSettings ); 10260 }, 10261 error: function () { 10262 // Error occurred loading language file, continue on as best we can 10263 _fnInitialise( oSettings ); 10264 } 10265 } ); 10266 bInitHandedOff = true; 10267 } 10268 10269 /* 10270 * Stripes 10271 */ 10272 if ( oInit.asStripeClasses === null ) 10273 { 10274 oSettings.asStripeClasses =[ 10275 oClasses.sStripeOdd, 10276 oClasses.sStripeEven 10277 ]; 10278 } 10279 10280 /* Remove row stripe classes if they are already on the table row */ 10281 var stripeClasses = oSettings.asStripeClasses; 10282 var rowOne = $this.children('tbody').find('tr').eq(0); 10283 if ( $.inArray( true, $.map( stripeClasses, function(el, i) { 10284 return rowOne.hasClass(el); 10285 } ) ) !== -1 ) { 10286 $('tbody tr', this).removeClass( stripeClasses.join(' ') ); 10287 oSettings.asDestroyStripes = stripeClasses.slice(); 10288 } 10289 10290 /* 10291 * Columns 10292 * See if we should load columns automatically or use defined ones 10293 */ 10294 var anThs = []; 10295 var aoColumnsInit; 10296 var nThead = this.getElementsByTagName('thead'); 10297 if ( nThead.length !== 0 ) 10298 { 10299 _fnDetectHeader( oSettings.aoHeader, nThead[0] ); 10300 anThs = _fnGetUniqueThs( oSettings ); 10301 } 10302 10303 /* If not given a column array, generate one with nulls */ 10304 if ( oInit.aoColumns === null ) 10305 { 10306 aoColumnsInit = []; 10307 for ( i=0, iLen=anThs.length ; i<iLen ; i++ ) 10308 { 10309 aoColumnsInit.push( null ); 10310 } 10311 } 10312 else 10313 { 10314 aoColumnsInit = oInit.aoColumns; 10315 } 10316 10317 /* Add the columns */ 10318 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ ) 10319 { 10320 _fnAddColumn( oSettings, anThs ? anThs[i] : null ); 10321 } 10322 10323 /* Apply the column definitions */ 10324 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) { 10325 _fnColumnOptions( oSettings, iCol, oDef ); 10326 } ); 10327 10328 /* HTML5 attribute detection - build an mData object automatically if the 10329 * attributes are found 10330 */ 10331 if ( rowOne.length ) { 10332 var a = function ( cell, name ) { 10333 return cell.getAttribute( 'data-'+name ) !== null ? name : null; 10334 }; 10335 10336 $( rowOne[0] ).children('th, td').each( function (i, cell) { 10337 var col = oSettings.aoColumns[i]; 10338 10339 if ( col.mData === i ) { 10340 var sort = a( cell, 'sort' ) || a( cell, 'order' ); 10341 var filter = a( cell, 'filter' ) || a( cell, 'search' ); 10342 10343 if ( sort !== null || filter !== null ) { 10344 col.mData = { 10345 _: i+'.display', 10346 sort: sort !== null ? i+'.@data-'+sort : undefined, 10347 type: sort !== null ? i+'.@data-'+sort : undefined, 10348 filter: filter !== null ? i+'.@data-'+filter : undefined 10349 }; 10350 10351 _fnColumnOptions( oSettings, i ); 10352 } 10353 } 10354 } ); 10355 } 10356 10357 var features = oSettings.oFeatures; 10358 var loadedInit = function () { 10359 /* 10360 * Sorting 10361 * @todo For modularisation (1.11) this needs to do into a sort start up handler 10362 */ 10363 10364 // If aaSorting is not defined, then we use the first indicator in asSorting 10365 // in case that has been altered, so the default sort reflects that option 10366 if ( oInit.aaSorting === undefined ) { 10367 var sorting = oSettings.aaSorting; 10368 for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) { 10369 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0]; 10370 } 10371 } 10372 10373 /* Do a first pass on the sorting classes (allows any size changes to be taken into 10374 * account, and also will apply sorting disabled classes if disabled 10375 */ 10376 _fnSortingClasses( oSettings ); 10377 10378 if ( features.bSort ) { 10379 _fnCallbackReg( oSettings, 'aoDrawCallback', function () { 10380 if ( oSettings.bSorted ) { 10381 var aSort = _fnSortFlatten( oSettings ); 10382 var sortedColumns = {}; 10383 10384 $.each( aSort, function (i, val) { 10385 sortedColumns[ val.src ] = val.dir; 10386 } ); 10387 10388 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] ); 10389 _fnSortAria( oSettings ); 10390 } 10391 } ); 10392 } 10393 10394 _fnCallbackReg( oSettings, 'aoDrawCallback', function () { 10395 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) { 10396 _fnSortingClasses( oSettings ); 10397 } 10398 }, 'sc' ); 10399 10400 10401 /* 10402 * Final init 10403 * Cache the header, body and footer as required, creating them if needed 10404 */ 10405 10406 // Work around for Webkit bug 83867 - store the caption-side before removing from doc 10407 var captions = $this.children('caption').each( function () { 10408 this._captionSide = $(this).css('caption-side'); 10409 } ); 10410 10411 var thead = $this.children('thead'); 10412 if ( thead.length === 0 ) { 10413 thead = $('<thead/>').appendTo($this); 10414 } 10415 oSettings.nTHead = thead[0]; 10416 10417 var tbody = $this.children('tbody'); 10418 if ( tbody.length === 0 ) { 10419 tbody = $('<tbody/>').appendTo($this); 10420 } 10421 oSettings.nTBody = tbody[0]; 10422 10423 var tfoot = $this.children('tfoot'); 10424 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) { 10425 // If we are a scrolling table, and no footer has been given, then we need to create 10426 // a tfoot element for the caption element to be appended to 10427 tfoot = $('<tfoot/>').appendTo($this); 10428 } 10429 10430 if ( tfoot.length === 0 || tfoot.children().length === 0 ) { 10431 $this.addClass( oClasses.sNoFooter ); 10432 } 10433 else if ( tfoot.length > 0 ) { 10434 oSettings.nTFoot = tfoot[0]; 10435 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot ); 10436 } 10437 10438 /* Check if there is data passing into the constructor */ 10439 if ( oInit.aaData ) { 10440 for ( i=0 ; i<oInit.aaData.length ; i++ ) { 10441 _fnAddData( oSettings, oInit.aaData[ i ] ); 10442 } 10443 } 10444 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) { 10445 /* Grab the data from the page - only do this when deferred loading or no Ajax 10446 * source since there is no point in reading the DOM data if we are then going 10447 * to replace it with Ajax data 10448 */ 10449 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') ); 10450 } 10451 10452 /* Copy the data index array */ 10453 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); 10454 10455 /* Initialisation complete - table can be drawn */ 10456 oSettings.bInitialised = true; 10457 10458 /* Check if we need to initialise the table (it might not have been handed off to the 10459 * language processor) 10460 */ 10461 if ( bInitHandedOff === false ) { 10462 _fnInitialise( oSettings ); 10463 } 10464 }; 10465 10466 /* Must be done after everything which can be overridden by the state saving! */ 10467 if ( oInit.bStateSave ) 10468 { 10469 features.bStateSave = true; 10470 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' ); 10471 _fnLoadState( oSettings, oInit, loadedInit ); 10472 } 10473 else { 10474 loadedInit(); 10475 } 10476 10477 } ); 10478 _that = null; 10479 return this; 10480 }; 10481 10482 10483 /* 10484 * It is useful to have variables which are scoped locally so only the 10485 * DataTables functions can access them and they don't leak into global space. 10486 * At the same time these functions are often useful over multiple files in the 10487 * core and API, so we list, or at least document, all variables which are used 10488 * by DataTables as private variables here. This also ensures that there is no 10489 * clashing of variable names and that they can easily referenced for reuse. 10490 */ 10491 10492 10493 // Defined else where 10494 // _selector_run 10495 // _selector_opts 10496 // _selector_first 10497 // _selector_row_indexes 10498 10499 var _ext; // DataTable.ext 10500 var _Api; // DataTable.Api 10501 var _api_register; // DataTable.Api.register 10502 var _api_registerPlural; // DataTable.Api.registerPlural 10503 10504 var _re_dic = {}; 10505 var _re_new_lines = /[\r\n]/g; 10506 var _re_html = /<.*?>/g; 10507 10508 // This is not strict ISO8601 - Date.parse() is quite lax, although 10509 // implementations differ between browsers. 10510 var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/; 10511 10512 // Escape regular expression special characters 10513 var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' ); 10514 10515 // http://en.wikipedia.org/wiki/Foreign_exchange_market 10516 // - \u20BD - Russian ruble. 10517 // - \u20a9 - South Korean Won 10518 // - \u20BA - Turkish Lira 10519 // - \u20B9 - Indian Rupee 10520 // - R - Brazil (R$) and South Africa 10521 // - fr - Swiss Franc 10522 // - kr - Swedish krona, Norwegian krone and Danish krone 10523 // - \u2009 is thin space and \u202F is narrow no-break space, both used in many 10524 // - É - Bitcoin 10525 // - Î - Ethereum 10526 // standards as thousands separators. 10527 var _re_formatted_numeric = /[',$£â¬Â¥%\u2009\u202F\u20BD\u20a9\u20BArfkÉÎ]/gi; 10528 10529 10530 var _empty = function ( d ) { 10531 return !d || d === true || d === '-' ? true : false; 10532 }; 10533 10534 10535 var _intVal = function ( s ) { 10536 var integer = parseInt( s, 10 ); 10537 return !isNaN(integer) && isFinite(s) ? integer : null; 10538 }; 10539 10540 // Convert from a formatted number with characters other than `.` as the 10541 // decimal place, to a Javascript number 10542 var _numToDecimal = function ( num, decimalPoint ) { 10543 // Cache created regular expressions for speed as this function is called often 10544 if ( ! _re_dic[ decimalPoint ] ) { 10545 _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' ); 10546 } 10547 return typeof num === 'string' && decimalPoint !== '.' ? 10548 num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) : 10549 num; 10550 }; 10551 10552 10553 var _isNumber = function ( d, decimalPoint, formatted ) { 10554 var strType = typeof d === 'string'; 10555 10556 // If empty return immediately so there must be a number if it is a 10557 // formatted string (this stops the string "k", or "kr", etc being detected 10558 // as a formatted number for currency 10559 if ( _empty( d ) ) { 10560 return true; 10561 } 10562 10563 if ( decimalPoint && strType ) { 10564 d = _numToDecimal( d, decimalPoint ); 10565 } 10566 10567 if ( formatted && strType ) { 10568 d = d.replace( _re_formatted_numeric, '' ); 10569 } 10570 10571 return !isNaN( parseFloat(d) ) && isFinite( d ); 10572 }; 10573 10574 10575 // A string without HTML in it can be considered to be HTML still 10576 var _isHtml = function ( d ) { 10577 return _empty( d ) || typeof d === 'string'; 10578 }; 10579 10580 10581 var _htmlNumeric = function ( d, decimalPoint, formatted ) { 10582 if ( _empty( d ) ) { 10583 return true; 10584 } 10585 10586 var html = _isHtml( d ); 10587 return ! html ? 10588 null : 10589 _isNumber( _stripHtml( d ), decimalPoint, formatted ) ? 10590 true : 10591 null; 10592 }; 10593 10594 10595 var _pluck = function ( a, prop, prop2 ) { 10596 var out = []; 10597 var i=0, ien=a.length; 10598 10599 // Could have the test in the loop for slightly smaller code, but speed 10600 // is essential here 10601 if ( prop2 !== undefined ) { 10602 for ( ; i<ien ; i++ ) { 10603 if ( a[i] && a[i][ prop ] ) { 10604 out.push( a[i][ prop ][ prop2 ] ); 10605 } 10606 } 10607 } 10608 else { 10609 for ( ; i<ien ; i++ ) { 10610 if ( a[i] ) { 10611 out.push( a[i][ prop ] ); 10612 } 10613 } 10614 } 10615 10616 return out; 10617 }; 10618 10619 10620 // Basically the same as _pluck, but rather than looping over `a` we use `order` 10621 // as the indexes to pick from `a` 10622 var _pluck_order = function ( a, order, prop, prop2 ) 10623 { 10624 var out = []; 10625 var i=0, ien=order.length; 10626 10627 // Could have the test in the loop for slightly smaller code, but speed 10628 // is essential here 10629 if ( prop2 !== undefined ) { 10630 for ( ; i<ien ; i++ ) { 10631 if ( a[ order[i] ][ prop ] ) { 10632 out.push( a[ order[i] ][ prop ][ prop2 ] ); 10633 } 10634 } 10635 } 10636 else { 10637 for ( ; i<ien ; i++ ) { 10638 out.push( a[ order[i] ][ prop ] ); 10639 } 10640 } 10641 10642 return out; 10643 }; 10644 10645 10646 var _range = function ( len, start ) 10647 { 10648 var out = []; 10649 var end; 10650 10651 if ( start === undefined ) { 10652 start = 0; 10653 end = len; 10654 } 10655 else { 10656 end = start; 10657 start = len; 10658 } 10659 10660 for ( var i=start ; i<end ; i++ ) { 10661 out.push( i ); 10662 } 10663 10664 return out; 10665 }; 10666 10667 10668 var _removeEmpty = function ( a ) 10669 { 10670 var out = []; 10671 10672 for ( var i=0, ien=a.length ; i<ien ; i++ ) { 10673 if ( a[i] ) { // careful - will remove all falsy values! 10674 out.push( a[i] ); 10675 } 10676 } 10677 10678 return out; 10679 }; 10680 10681 10682 var _stripHtml = function ( d ) { 10683 return d.replace( _re_html, '' ); 10684 }; 10685 10686 10687 /** 10688 * Determine if all values in the array are unique. This means we can short 10689 * cut the _unique method at the cost of a single loop. A sorted array is used 10690 * to easily check the values. 10691 * 10692 * @param {array} src Source array 10693 * @return {boolean} true if all unique, false otherwise 10694 * @ignore 10695 */ 10696 var _areAllUnique = function ( src ) { 10697 if ( src.length < 2 ) { 10698 return true; 10699 } 10700 10701 var sorted = src.slice().sort(); 10702 var last = sorted[0]; 10703 10704 for ( var i=1, ien=sorted.length ; i<ien ; i++ ) { 10705 if ( sorted[i] === last ) { 10706 return false; 10707 } 10708 10709 last = sorted[i]; 10710 } 10711 10712 return true; 10713 }; 10714 10715 10716 /** 10717 * Find the unique elements in a source array. 10718 * 10719 * @param {array} src Source array 10720 * @return {array} Array of unique items 10721 * @ignore 10722 */ 10723 var _unique = function ( src ) 10724 { 10725 if ( _areAllUnique( src ) ) { 10726 return src.slice(); 10727 } 10728 10729 // A faster unique method is to use object keys to identify used values, 10730 // but this doesn't work with arrays or objects, which we must also 10731 // consider. See jsperf.com/compare-array-unique-versions/4 for more 10732 // information. 10733 var 10734 out = [], 10735 val, 10736 i, ien=src.length, 10737 j, k=0; 10738 10739 again: for ( i=0 ; i<ien ; i++ ) { 10740 val = src[i]; 10741 10742 for ( j=0 ; j<k ; j++ ) { 10743 if ( out[j] === val ) { 10744 continue again; 10745 } 10746 } 10747 10748 out.push( val ); 10749 k++; 10750 } 10751 10752 return out; 10753 }; 10754 10755 10756 /** 10757 * DataTables utility methods 10758 * 10759 * This namespace provides helper methods that DataTables uses internally to 10760 * create a DataTable, but which are not exclusively used only for DataTables. 10761 * These methods can be used by extension authors to save the duplication of 10762 * code. 10763 * 10764 * @namespace 10765 */ 10766 DataTable.util = { 10767 /** 10768 * Throttle the calls to a function. Arguments and context are maintained 10769 * for the throttled function. 10770 * 10771 * @param {function} fn Function to be called 10772 * @param {integer} freq Call frequency in mS 10773 * @return {function} Wrapped function 10774 */ 10775 throttle: function ( fn, freq ) { 10776 var 10777 frequency = freq !== undefined ? freq : 200, 10778 last, 10779 timer; 10780 10781 return function () { 10782 var 10783 that = this, 10784 now = +new Date(), 10785 args = arguments; 10786 10787 if ( last && now < last + frequency ) { 10788 clearTimeout( timer ); 10789 10790 timer = setTimeout( function () { 10791 last = undefined; 10792 fn.apply( that, args ); 10793 }, frequency ); 10794 } 10795 else { 10796 last = now; 10797 fn.apply( that, args ); 10798 } 10799 }; 10800 }, 10801 10802 10803 /** 10804 * Escape a string such that it can be used in a regular expression 10805 * 10806 * @param {string} val string to escape 10807 * @returns {string} escaped string 10808 */ 10809 escapeRegex: function ( val ) { 10810 return val.replace( _re_escape_regex, '\\$1' ); 10811 } 10812 }; 10813 10814 10815 10816 /** 10817 * Create a mapping object that allows camel case parameters to be looked up 10818 * for their Hungarian counterparts. The mapping is stored in a private 10819 * parameter called `_hungarianMap` which can be accessed on the source object. 10820 * @param {object} o 10821 * @memberof DataTable#oApi 10822 */ 10823 function _fnHungarianMap ( o ) 10824 { 10825 var 10826 hungarian = 'a aa ai ao as b fn i m o s ', 10827 match, 10828 newKey, 10829 map = {}; 10830 10831 $.each( o, function (key, val) { 10832 match = key.match(/^([^A-Z]+?)([A-Z])/); 10833 10834 if ( match && hungarian.indexOf(match[1]+' ') !== -1 ) 10835 { 10836 newKey = key.replace( match[0], match[2].toLowerCase() ); 10837 map[ newKey ] = key; 10838 10839 if ( match[1] === 'o' ) 10840 { 10841 _fnHungarianMap( o[key] ); 10842 } 10843 } 10844 } ); 10845 10846 o._hungarianMap = map; 10847 } 10848 10849 10850 /** 10851 * Convert from camel case parameters to Hungarian, based on a Hungarian map 10852 * created by _fnHungarianMap. 10853 * @param {object} src The model object which holds all parameters that can be 10854 * mapped. 10855 * @param {object} user The object to convert from camel case to Hungarian. 10856 * @param {boolean} force When set to `true`, properties which already have a 10857 * Hungarian value in the `user` object will be overwritten. Otherwise they 10858 * won't be. 10859 * @memberof DataTable#oApi 10860 */ 10861 function _fnCamelToHungarian ( src, user, force ) 10862 { 10863 if ( ! src._hungarianMap ) { 10864 _fnHungarianMap( src ); 10865 } 10866 10867 var hungarianKey; 10868 10869 $.each( user, function (key, val) { 10870 hungarianKey = src._hungarianMap[ key ]; 10871 10872 if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) ) 10873 { 10874 // For objects, we need to buzz down into the object to copy parameters 10875 if ( hungarianKey.charAt(0) === 'o' ) 10876 { 10877 // Copy the camelCase options over to the hungarian 10878 if ( ! user[ hungarianKey ] ) { 10879 user[ hungarianKey ] = {}; 10880 } 10881 $.extend( true, user[hungarianKey], user[key] ); 10882 10883 _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force ); 10884 } 10885 else { 10886 user[hungarianKey] = user[ key ]; 10887 } 10888 } 10889 } ); 10890 } 10891 10892 10893 /** 10894 * Language compatibility - when certain options are given, and others aren't, we 10895 * need to duplicate the values over, in order to provide backwards compatibility 10896 * with older language files. 10897 * @param {object} oSettings dataTables settings object 10898 * @memberof DataTable#oApi 10899 */ 10900 function _fnLanguageCompat( lang ) 10901 { 10902 // Note the use of the Hungarian notation for the parameters in this method as 10903 // this is called after the mapping of camelCase to Hungarian 10904 var defaults = DataTable.defaults.oLanguage; 10905 10906 // Default mapping 10907 var defaultDecimal = defaults.sDecimal; 10908 if ( defaultDecimal ) { 10909 _addNumericSort( defaultDecimal ); 10910 } 10911 10912 if ( lang ) { 10913 var zeroRecords = lang.sZeroRecords; 10914 10915 // Backwards compatibility - if there is no sEmptyTable given, then use the same as 10916 // sZeroRecords - assuming that is given. 10917 if ( ! lang.sEmptyTable && zeroRecords && 10918 defaults.sEmptyTable === "No data available in table" ) 10919 { 10920 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' ); 10921 } 10922 10923 // Likewise with loading records 10924 if ( ! lang.sLoadingRecords && zeroRecords && 10925 defaults.sLoadingRecords === "Loading..." ) 10926 { 10927 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' ); 10928 } 10929 10930 // Old parameter name of the thousands separator mapped onto the new 10931 if ( lang.sInfoThousands ) { 10932 lang.sThousands = lang.sInfoThousands; 10933 } 10934 10935 var decimal = lang.sDecimal; 10936 if ( decimal && defaultDecimal !== decimal ) { 10937 _addNumericSort( decimal ); 10938 } 10939 } 10940 } 10941 10942 10943 /** 10944 * Map one parameter onto another 10945 * @param {object} o Object to map 10946 * @param {*} knew The new parameter name 10947 * @param {*} old The old parameter name 10948 */ 10949 var _fnCompatMap = function ( o, knew, old ) { 10950 if ( o[ knew ] !== undefined ) { 10951 o[ old ] = o[ knew ]; 10952 } 10953 }; 10954 10955 10956 /** 10957 * Provide backwards compatibility for the main DT options. Note that the new 10958 * options are mapped onto the old parameters, so this is an external interface 10959 * change only. 10960 * @param {object} init Object to map 10961 */ 10962 function _fnCompatOpts ( init ) 10963 { 10964 _fnCompatMap( init, 'ordering', 'bSort' ); 10965 _fnCompatMap( init, 'orderMulti', 'bSortMulti' ); 10966 _fnCompatMap( init, 'orderClasses', 'bSortClasses' ); 10967 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' ); 10968 _fnCompatMap( init, 'order', 'aaSorting' ); 10969 _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' ); 10970 _fnCompatMap( init, 'paging', 'bPaginate' ); 10971 _fnCompatMap( init, 'pagingType', 'sPaginationType' ); 10972 _fnCompatMap( init, 'pageLength', 'iDisplayLength' ); 10973 _fnCompatMap( init, 'searching', 'bFilter' ); 10974 10975 // Boolean initialisation of x-scrolling 10976 if ( typeof init.sScrollX === 'boolean' ) { 10977 init.sScrollX = init.sScrollX ? '100%' : ''; 10978 } 10979 if ( typeof init.scrollX === 'boolean' ) { 10980 init.scrollX = init.scrollX ? '100%' : ''; 10981 } 10982 10983 // Column search objects are in an array, so it needs to be converted 10984 // element by element 10985 var searchCols = init.aoSearchCols; 10986 10987 if ( searchCols ) { 10988 for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) { 10989 if ( searchCols[i] ) { 10990 _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] ); 10991 } 10992 } 10993 } 10994 } 10995 10996 10997 /** 10998 * Provide backwards compatibility for column options. Note that the new options 10999 * are mapped onto the old parameters, so this is an external interface change 11000 * only. 11001 * @param {object} init Object to map 11002 */ 11003 function _fnCompatCols ( init ) 11004 { 11005 _fnCompatMap( init, 'orderable', 'bSortable' ); 11006 _fnCompatMap( init, 'orderData', 'aDataSort' ); 11007 _fnCompatMap( init, 'orderSequence', 'asSorting' ); 11008 _fnCompatMap( init, 'orderDataType', 'sortDataType' ); 11009 11010 // orderData can be given as an integer 11011 var dataSort = init.aDataSort; 11012 if ( typeof dataSort === 'number' && ! $.isArray( dataSort ) ) { 11013 init.aDataSort = [ dataSort ]; 11014 } 11015 } 11016 11017 11018 /** 11019 * Browser feature detection for capabilities, quirks 11020 * @param {object} settings dataTables settings object 11021 * @memberof DataTable#oApi 11022 */ 11023 function _fnBrowserDetect( settings ) 11024 { 11025 // We don't need to do this every time DataTables is constructed, the values 11026 // calculated are specific to the browser and OS configuration which we 11027 // don't expect to change between initialisations 11028 if ( ! DataTable.__browser ) { 11029 var browser = {}; 11030 DataTable.__browser = browser; 11031 11032 // Scrolling feature / quirks detection 11033 var n = $('<div/>') 11034 .css( { 11035 position: 'fixed', 11036 top: 0, 11037 left: $(window).scrollLeft()*-1, // allow for scrolling 11038 height: 1, 11039 width: 1, 11040 overflow: 'hidden' 11041 } ) 11042 .append( 11043 $('<div/>') 11044 .css( { 11045 position: 'absolute', 11046 top: 1, 11047 left: 1, 11048 width: 100, 11049 overflow: 'scroll' 11050 } ) 11051 .append( 11052 $('<div/>') 11053 .css( { 11054 width: '100%', 11055 height: 10 11056 } ) 11057 ) 11058 ) 11059 .appendTo( 'body' ); 11060 11061 var outer = n.children(); 11062 var inner = outer.children(); 11063 11064 // Numbers below, in order, are: 11065 // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth 11066 // 11067 // IE6 XP: 100 100 100 83 11068 // IE7 Vista: 100 100 100 83 11069 // IE 8+ Windows: 83 83 100 83 11070 // Evergreen Windows: 83 83 100 83 11071 // Evergreen Mac with scrollbars: 85 85 100 85 11072 // Evergreen Mac without scrollbars: 100 100 100 100 11073 11074 // Get scrollbar width 11075 browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth; 11076 11077 // IE6/7 will oversize a width 100% element inside a scrolling element, to 11078 // include the width of the scrollbar, while other browsers ensure the inner 11079 // element is contained without forcing scrolling 11080 browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100; 11081 11082 // In rtl text layout, some browsers (most, but not all) will place the 11083 // scrollbar on the left, rather than the right. 11084 browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1; 11085 11086 // IE8- don't provide height and width for getBoundingClientRect 11087 browser.bBounding = n[0].getBoundingClientRect().width ? true : false; 11088 11089 n.remove(); 11090 } 11091 11092 $.extend( settings.oBrowser, DataTable.__browser ); 11093 settings.oScroll.iBarWidth = DataTable.__browser.barWidth; 11094 } 11095 11096 11097 /** 11098 * Array.prototype reduce[Right] method, used for browsers which don't support 11099 * JS 1.6. Done this way to reduce code size, since we iterate either way 11100 * @param {object} settings dataTables settings object 11101 * @memberof DataTable#oApi 11102 */ 11103 function _fnReduce ( that, fn, init, start, end, inc ) 11104 { 11105 var 11106 i = start, 11107 value, 11108 isSet = false; 11109 11110 if ( init !== undefined ) { 11111 value = init; 11112 isSet = true; 11113 } 11114 11115 while ( i !== end ) { 11116 if ( ! that.hasOwnProperty(i) ) { 11117 continue; 11118 } 11119 11120 value = isSet ? 11121 fn( value, that[i], i, that ) : 11122 that[i]; 11123 11124 isSet = true; 11125 i += inc; 11126 } 11127 11128 return value; 11129 } 11130 11131 /** 11132 * Add a column to the list used for the table with default values 11133 * @param {object} oSettings dataTables settings object 11134 * @param {node} nTh The th element for this column 11135 * @memberof DataTable#oApi 11136 */ 11137 function _fnAddColumn( oSettings, nTh ) 11138 { 11139 // Add column to aoColumns array 11140 var oDefaults = DataTable.defaults.column; 11141 var iCol = oSettings.aoColumns.length; 11142 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, { 11143 "nTh": nTh ? nTh : document.createElement('th'), 11144 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '', 11145 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol], 11146 "mData": oDefaults.mData ? oDefaults.mData : iCol, 11147 idx: iCol 11148 } ); 11149 oSettings.aoColumns.push( oCol ); 11150 11151 // Add search object for column specific search. Note that the `searchCols[ iCol ]` 11152 // passed into extend can be undefined. This allows the user to give a default 11153 // with only some of the parameters defined, and also not give a default 11154 var searchCols = oSettings.aoPreSearchCols; 11155 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] ); 11156 11157 // Use the default column options function to initialise classes etc 11158 _fnColumnOptions( oSettings, iCol, $(nTh).data() ); 11159 } 11160 11161 11162 /** 11163 * Apply options for a column 11164 * @param {object} oSettings dataTables settings object 11165 * @param {int} iCol column index to consider 11166 * @param {object} oOptions object with sType, bVisible and bSearchable etc 11167 * @memberof DataTable#oApi 11168 */ 11169 function _fnColumnOptions( oSettings, iCol, oOptions ) 11170 { 11171 var oCol = oSettings.aoColumns[ iCol ]; 11172 var oClasses = oSettings.oClasses; 11173 var th = $(oCol.nTh); 11174 11175 // Try to get width information from the DOM. We can't get it from CSS 11176 // as we'd need to parse the CSS stylesheet. `width` option can override 11177 if ( ! oCol.sWidthOrig ) { 11178 // Width attribute 11179 oCol.sWidthOrig = th.attr('width') || null; 11180 11181 // Style attribute 11182 var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/); 11183 if ( t ) { 11184 oCol.sWidthOrig = t[1]; 11185 } 11186 } 11187 11188 /* User specified column options */ 11189 if ( oOptions !== undefined && oOptions !== null ) 11190 { 11191 // Backwards compatibility 11192 _fnCompatCols( oOptions ); 11193 11194 // Map camel case parameters to their Hungarian counterparts 11195 _fnCamelToHungarian( DataTable.defaults.column, oOptions ); 11196 11197 /* Backwards compatibility for mDataProp */ 11198 if ( oOptions.mDataProp !== undefined && !oOptions.mData ) 11199 { 11200 oOptions.mData = oOptions.mDataProp; 11201 } 11202 11203 if ( oOptions.sType ) 11204 { 11205 oCol._sManualType = oOptions.sType; 11206 } 11207 11208 // `class` is a reserved word in Javascript, so we need to provide 11209 // the ability to use a valid name for the camel case input 11210 if ( oOptions.className && ! oOptions.sClass ) 11211 { 11212 oOptions.sClass = oOptions.className; 11213 } 11214 if ( oOptions.sClass ) { 11215 th.addClass( oOptions.sClass ); 11216 } 11217 11218 $.extend( oCol, oOptions ); 11219 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" ); 11220 11221 /* iDataSort to be applied (backwards compatibility), but aDataSort will take 11222 * priority if defined 11223 */ 11224 if ( oOptions.iDataSort !== undefined ) 11225 { 11226 oCol.aDataSort = [ oOptions.iDataSort ]; 11227 } 11228 _fnMap( oCol, oOptions, "aDataSort" ); 11229 } 11230 11231 /* Cache the data get and set functions for speed */ 11232 var mDataSrc = oCol.mData; 11233 var mData = _fnGetObjectDataFn( mDataSrc ); 11234 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null; 11235 11236 var attrTest = function( src ) { 11237 return typeof src === 'string' && src.indexOf('@') !== -1; 11238 }; 11239 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && ( 11240 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter) 11241 ); 11242 oCol._setter = null; 11243 11244 oCol.fnGetData = function (rowData, type, meta) { 11245 var innerData = mData( rowData, type, undefined, meta ); 11246 11247 return mRender && type ? 11248 mRender( innerData, type, rowData, meta ) : 11249 innerData; 11250 }; 11251 oCol.fnSetData = function ( rowData, val, meta ) { 11252 return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta ); 11253 }; 11254 11255 // Indicate if DataTables should read DOM data as an object or array 11256 // Used in _fnGetRowElements 11257 if ( typeof mDataSrc !== 'number' ) { 11258 oSettings._rowReadObject = true; 11259 } 11260 11261 /* Feature sorting overrides column specific when off */ 11262 if ( !oSettings.oFeatures.bSort ) 11263 { 11264 oCol.bSortable = false; 11265 th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called 11266 } 11267 11268 /* Check that the class assignment is correct for sorting */ 11269 var bAsc = $.inArray('asc', oCol.asSorting) !== -1; 11270 var bDesc = $.inArray('desc', oCol.asSorting) !== -1; 11271 if ( !oCol.bSortable || (!bAsc && !bDesc) ) 11272 { 11273 oCol.sSortingClass = oClasses.sSortableNone; 11274 oCol.sSortingClassJUI = ""; 11275 } 11276 else if ( bAsc && !bDesc ) 11277 { 11278 oCol.sSortingClass = oClasses.sSortableAsc; 11279 oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed; 11280 } 11281 else if ( !bAsc && bDesc ) 11282 { 11283 oCol.sSortingClass = oClasses.sSortableDesc; 11284 oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed; 11285 } 11286 else 11287 { 11288 oCol.sSortingClass = oClasses.sSortable; 11289 oCol.sSortingClassJUI = oClasses.sSortJUI; 11290 } 11291 } 11292 11293 11294 /** 11295 * Adjust the table column widths for new data. Note: you would probably want to 11296 * do a redraw after calling this function! 11297 * @param {object} settings dataTables settings object 11298 * @memberof DataTable#oApi 11299 */ 11300 function _fnAdjustColumnSizing ( settings ) 11301 { 11302 /* Not interested in doing column width calculation if auto-width is disabled */ 11303 if ( settings.oFeatures.bAutoWidth !== false ) 11304 { 11305 var columns = settings.aoColumns; 11306 11307 _fnCalculateColumnWidths( settings ); 11308 for ( var i=0 , iLen=columns.length ; i<iLen ; i++ ) 11309 { 11310 columns[i].nTh.style.width = columns[i].sWidth; 11311 } 11312 } 11313 11314 var scroll = settings.oScroll; 11315 if ( scroll.sY !== '' || scroll.sX !== '') 11316 { 11317 _fnScrollDraw( settings ); 11318 } 11319 11320 _fnCallbackFire( settings, null, 'column-sizing', [settings] ); 11321 } 11322 11323 11324 /** 11325 * Covert the index of a visible column to the index in the data array (take account 11326 * of hidden columns) 11327 * @param {object} oSettings dataTables settings object 11328 * @param {int} iMatch Visible column index to lookup 11329 * @returns {int} i the data index 11330 * @memberof DataTable#oApi 11331 */ 11332 function _fnVisibleToColumnIndex( oSettings, iMatch ) 11333 { 11334 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); 11335 11336 return typeof aiVis[iMatch] === 'number' ? 11337 aiVis[iMatch] : 11338 null; 11339 } 11340 11341 11342 /** 11343 * Covert the index of an index in the data array and convert it to the visible 11344 * column index (take account of hidden columns) 11345 * @param {int} iMatch Column index to lookup 11346 * @param {object} oSettings dataTables settings object 11347 * @returns {int} i the data index 11348 * @memberof DataTable#oApi 11349 */ 11350 function _fnColumnIndexToVisible( oSettings, iMatch ) 11351 { 11352 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); 11353 var iPos = $.inArray( iMatch, aiVis ); 11354 11355 return iPos !== -1 ? iPos : null; 11356 } 11357 11358 11359 /** 11360 * Get the number of visible columns 11361 * @param {object} oSettings dataTables settings object 11362 * @returns {int} i the number of visible columns 11363 * @memberof DataTable#oApi 11364 */ 11365 function _fnVisbleColumns( oSettings ) 11366 { 11367 var vis = 0; 11368 11369 // No reduce in IE8, use a loop for now 11370 $.each( oSettings.aoColumns, function ( i, col ) { 11371 if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) { 11372 vis++; 11373 } 11374 } ); 11375 11376 return vis; 11377 } 11378 11379 11380 /** 11381 * Get an array of column indexes that match a given property 11382 * @param {object} oSettings dataTables settings object 11383 * @param {string} sParam Parameter in aoColumns to look for - typically 11384 * bVisible or bSearchable 11385 * @returns {array} Array of indexes with matched properties 11386 * @memberof DataTable#oApi 11387 */ 11388 function _fnGetColumns( oSettings, sParam ) 11389 { 11390 var a = []; 11391 11392 $.map( oSettings.aoColumns, function(val, i) { 11393 if ( val[sParam] ) { 11394 a.push( i ); 11395 } 11396 } ); 11397 11398 return a; 11399 } 11400 11401 11402 /** 11403 * Calculate the 'type' of a column 11404 * @param {object} settings dataTables settings object 11405 * @memberof DataTable#oApi 11406 */ 11407 function _fnColumnTypes ( settings ) 11408 { 11409 var columns = settings.aoColumns; 11410 var data = settings.aoData; 11411 var types = DataTable.ext.type.detect; 11412 var i, ien, j, jen, k, ken; 11413 var col, cell, detectedType, cache; 11414 11415 // For each column, spin over the 11416 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 11417 col = columns[i]; 11418 cache = []; 11419 11420 if ( ! col.sType && col._sManualType ) { 11421 col.sType = col._sManualType; 11422 } 11423 else if ( ! col.sType ) { 11424 for ( j=0, jen=types.length ; j<jen ; j++ ) { 11425 for ( k=0, ken=data.length ; k<ken ; k++ ) { 11426 // Use a cache array so we only need to get the type data 11427 // from the formatter once (when using multiple detectors) 11428 if ( cache[k] === undefined ) { 11429 cache[k] = _fnGetCellData( settings, k, i, 'type' ); 11430 } 11431 11432 detectedType = types[j]( cache[k], settings ); 11433 11434 // If null, then this type can't apply to this column, so 11435 // rather than testing all cells, break out. There is an 11436 // exception for the last type which is `html`. We need to 11437 // scan all rows since it is possible to mix string and HTML 11438 // types 11439 if ( ! detectedType && j !== types.length-1 ) { 11440 break; 11441 } 11442 11443 // Only a single match is needed for html type since it is 11444 // bottom of the pile and very similar to string 11445 if ( detectedType === 'html' ) { 11446 break; 11447 } 11448 } 11449 11450 // Type is valid for all data points in the column - use this 11451 // type 11452 if ( detectedType ) { 11453 col.sType = detectedType; 11454 break; 11455 } 11456 } 11457 11458 // Fall back - if no type was detected, always use string 11459 if ( ! col.sType ) { 11460 col.sType = 'string'; 11461 } 11462 } 11463 } 11464 } 11465 11466 11467 /** 11468 * Take the column definitions and static columns arrays and calculate how 11469 * they relate to column indexes. The callback function will then apply the 11470 * definition found for a column to a suitable configuration object. 11471 * @param {object} oSettings dataTables settings object 11472 * @param {array} aoColDefs The aoColumnDefs array that is to be applied 11473 * @param {array} aoCols The aoColumns array that defines columns individually 11474 * @param {function} fn Callback function - takes two parameters, the calculated 11475 * column index and the definition for that column. 11476 * @memberof DataTable#oApi 11477 */ 11478 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn ) 11479 { 11480 var i, iLen, j, jLen, k, kLen, def; 11481 var columns = oSettings.aoColumns; 11482 11483 // Column definitions with aTargets 11484 if ( aoColDefs ) 11485 { 11486 /* Loop over the definitions array - loop in reverse so first instance has priority */ 11487 for ( i=aoColDefs.length-1 ; i>=0 ; i-- ) 11488 { 11489 def = aoColDefs[i]; 11490 11491 /* Each definition can target multiple columns, as it is an array */ 11492 var aTargets = def.targets !== undefined ? 11493 def.targets : 11494 def.aTargets; 11495 11496 if ( ! $.isArray( aTargets ) ) 11497 { 11498 aTargets = [ aTargets ]; 11499 } 11500 11501 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ ) 11502 { 11503 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 ) 11504 { 11505 /* Add columns that we don't yet know about */ 11506 while( columns.length <= aTargets[j] ) 11507 { 11508 _fnAddColumn( oSettings ); 11509 } 11510 11511 /* Integer, basic index */ 11512 fn( aTargets[j], def ); 11513 } 11514 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 ) 11515 { 11516 /* Negative integer, right to left column counting */ 11517 fn( columns.length+aTargets[j], def ); 11518 } 11519 else if ( typeof aTargets[j] === 'string' ) 11520 { 11521 /* Class name matching on TH element */ 11522 for ( k=0, kLen=columns.length ; k<kLen ; k++ ) 11523 { 11524 if ( aTargets[j] == "_all" || 11525 $(columns[k].nTh).hasClass( aTargets[j] ) ) 11526 { 11527 fn( k, def ); 11528 } 11529 } 11530 } 11531 } 11532 } 11533 } 11534 11535 // Statically defined columns array 11536 if ( aoCols ) 11537 { 11538 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) 11539 { 11540 fn( i, aoCols[i] ); 11541 } 11542 } 11543 } 11544 11545 /** 11546 * Add a data array to the table, creating DOM node etc. This is the parallel to 11547 * _fnGatherData, but for adding rows from a Javascript source, rather than a 11548 * DOM source. 11549 * @param {object} oSettings dataTables settings object 11550 * @param {array} aData data array to be added 11551 * @param {node} [nTr] TR element to add to the table - optional. If not given, 11552 * DataTables will create a row automatically 11553 * @param {array} [anTds] Array of TD|TH elements for the row - must be given 11554 * if nTr is. 11555 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed 11556 * @memberof DataTable#oApi 11557 */ 11558 function _fnAddData ( oSettings, aDataIn, nTr, anTds ) 11559 { 11560 /* Create the object for storing information about this new row */ 11561 var iRow = oSettings.aoData.length; 11562 var oData = $.extend( true, {}, DataTable.models.oRow, { 11563 src: nTr ? 'dom' : 'data', 11564 idx: iRow 11565 } ); 11566 11567 oData._aData = aDataIn; 11568 oSettings.aoData.push( oData ); 11569 11570 /* Create the cells */ 11571 var nTd, sThisType; 11572 var columns = oSettings.aoColumns; 11573 11574 // Invalidate the column types as the new data needs to be revalidated 11575 for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) 11576 { 11577 columns[i].sType = null; 11578 } 11579 11580 /* Add to the display array */ 11581 oSettings.aiDisplayMaster.push( iRow ); 11582 11583 var id = oSettings.rowIdFn( aDataIn ); 11584 if ( id !== undefined ) { 11585 oSettings.aIds[ id ] = oData; 11586 } 11587 11588 /* Create the DOM information, or register it if already present */ 11589 if ( nTr || ! oSettings.oFeatures.bDeferRender ) 11590 { 11591 _fnCreateTr( oSettings, iRow, nTr, anTds ); 11592 } 11593 11594 return iRow; 11595 } 11596 11597 11598 /** 11599 * Add one or more TR elements to the table. Generally we'd expect to 11600 * use this for reading data from a DOM sourced table, but it could be 11601 * used for an TR element. Note that if a TR is given, it is used (i.e. 11602 * it is not cloned). 11603 * @param {object} settings dataTables settings object 11604 * @param {array|node|jQuery} trs The TR element(s) to add to the table 11605 * @returns {array} Array of indexes for the added rows 11606 * @memberof DataTable#oApi 11607 */ 11608 function _fnAddTr( settings, trs ) 11609 { 11610 var row; 11611 11612 // Allow an individual node to be passed in 11613 if ( ! (trs instanceof $) ) { 11614 trs = $(trs); 11615 } 11616 11617 return trs.map( function (i, el) { 11618 row = _fnGetRowElements( settings, el ); 11619 return _fnAddData( settings, row.data, el, row.cells ); 11620 } ); 11621 } 11622 11623 11624 /** 11625 * Take a TR element and convert it to an index in aoData 11626 * @param {object} oSettings dataTables settings object 11627 * @param {node} n the TR element to find 11628 * @returns {int} index if the node is found, null if not 11629 * @memberof DataTable#oApi 11630 */ 11631 function _fnNodeToDataIndex( oSettings, n ) 11632 { 11633 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null; 11634 } 11635 11636 11637 /** 11638 * Take a TD element and convert it into a column data index (not the visible index) 11639 * @param {object} oSettings dataTables settings object 11640 * @param {int} iRow The row number the TD/TH can be found in 11641 * @param {node} n The TD/TH element to find 11642 * @returns {int} index if the node is found, -1 if not 11643 * @memberof DataTable#oApi 11644 */ 11645 function _fnNodeToColumnIndex( oSettings, iRow, n ) 11646 { 11647 return $.inArray( n, oSettings.aoData[ iRow ].anCells ); 11648 } 11649 11650 11651 /** 11652 * Get the data for a given cell from the internal cache, taking into account data mapping 11653 * @param {object} settings dataTables settings object 11654 * @param {int} rowIdx aoData row id 11655 * @param {int} colIdx Column index 11656 * @param {string} type data get type ('display', 'type' 'filter' 'sort') 11657 * @returns {*} Cell data 11658 * @memberof DataTable#oApi 11659 */ 11660 function _fnGetCellData( settings, rowIdx, colIdx, type ) 11661 { 11662 var draw = settings.iDraw; 11663 var col = settings.aoColumns[colIdx]; 11664 var rowData = settings.aoData[rowIdx]._aData; 11665 var defaultContent = col.sDefaultContent; 11666 var cellData = col.fnGetData( rowData, type, { 11667 settings: settings, 11668 row: rowIdx, 11669 col: colIdx 11670 } ); 11671 11672 if ( cellData === undefined ) { 11673 if ( settings.iDrawError != draw && defaultContent === null ) { 11674 _fnLog( settings, 0, "Requested unknown parameter "+ 11675 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+ 11676 " for row "+rowIdx+", column "+colIdx, 4 ); 11677 settings.iDrawError = draw; 11678 } 11679 return defaultContent; 11680 } 11681 11682 // When the data source is null and a specific data type is requested (i.e. 11683 // not the original data), we can use default column data 11684 if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) { 11685 cellData = defaultContent; 11686 } 11687 else if ( typeof cellData === 'function' ) { 11688 // If the data source is a function, then we run it and use the return, 11689 // executing in the scope of the data object (for instances) 11690 return cellData.call( rowData ); 11691 } 11692 11693 if ( cellData === null && type == 'display' ) { 11694 return ''; 11695 } 11696 return cellData; 11697 } 11698 11699 11700 /** 11701 * Set the value for a specific cell, into the internal data cache 11702 * @param {object} settings dataTables settings object 11703 * @param {int} rowIdx aoData row id 11704 * @param {int} colIdx Column index 11705 * @param {*} val Value to set 11706 * @memberof DataTable#oApi 11707 */ 11708 function _fnSetCellData( settings, rowIdx, colIdx, val ) 11709 { 11710 var col = settings.aoColumns[colIdx]; 11711 var rowData = settings.aoData[rowIdx]._aData; 11712 11713 col.fnSetData( rowData, val, { 11714 settings: settings, 11715 row: rowIdx, 11716 col: colIdx 11717 } ); 11718 } 11719 11720 11721 // Private variable that is used to match action syntax in the data property object 11722 var __reArray = /\[.*?\]$/; 11723 var __reFn = /\(\)$/; 11724 11725 /** 11726 * Split string on periods, taking into account escaped periods 11727 * @param {string} str String to split 11728 * @return {array} Split string 11729 */ 11730 function _fnSplitObjNotation( str ) 11731 { 11732 return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) { 11733 return s.replace(/\\\./g, '.'); 11734 } ); 11735 } 11736 11737 11738 /** 11739 * Return a function that can be used to get data from a source object, taking 11740 * into account the ability to use nested objects as a source 11741 * @param {string|int|function} mSource The data source for the object 11742 * @returns {function} Data get function 11743 * @memberof DataTable#oApi 11744 */ 11745 function _fnGetObjectDataFn( mSource ) 11746 { 11747 if ( $.isPlainObject( mSource ) ) 11748 { 11749 /* Build an object of get functions, and wrap them in a single call */ 11750 var o = {}; 11751 $.each( mSource, function (key, val) { 11752 if ( val ) { 11753 o[key] = _fnGetObjectDataFn( val ); 11754 } 11755 } ); 11756 11757 return function (data, type, row, meta) { 11758 var t = o[type] || o._; 11759 return t !== undefined ? 11760 t(data, type, row, meta) : 11761 data; 11762 }; 11763 } 11764 else if ( mSource === null ) 11765 { 11766 /* Give an empty string for rendering / sorting etc */ 11767 return function (data) { // type, row and meta also passed, but not used 11768 return data; 11769 }; 11770 } 11771 else if ( typeof mSource === 'function' ) 11772 { 11773 return function (data, type, row, meta) { 11774 return mSource( data, type, row, meta ); 11775 }; 11776 } 11777 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || 11778 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) ) 11779 { 11780 /* If there is a . in the source string then the data source is in a 11781 * nested object so we loop over the data for each level to get the next 11782 * level down. On each loop we test for undefined, and if found immediately 11783 * return. This allows entire objects to be missing and sDefaultContent to 11784 * be used if defined, rather than throwing an error 11785 */ 11786 var fetchData = function (data, type, src) { 11787 var arrayNotation, funcNotation, out, innerSrc; 11788 11789 if ( src !== "" ) 11790 { 11791 var a = _fnSplitObjNotation( src ); 11792 11793 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) 11794 { 11795 // Check if we are dealing with special notation 11796 arrayNotation = a[i].match(__reArray); 11797 funcNotation = a[i].match(__reFn); 11798 11799 if ( arrayNotation ) 11800 { 11801 // Array notation 11802 a[i] = a[i].replace(__reArray, ''); 11803 11804 // Condition allows simply [] to be passed in 11805 if ( a[i] !== "" ) { 11806 data = data[ a[i] ]; 11807 } 11808 out = []; 11809 11810 // Get the remainder of the nested object to get 11811 a.splice( 0, i+1 ); 11812 innerSrc = a.join('.'); 11813 11814 // Traverse each entry in the array getting the properties requested 11815 if ( $.isArray( data ) ) { 11816 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) { 11817 out.push( fetchData( data[j], type, innerSrc ) ); 11818 } 11819 } 11820 11821 // If a string is given in between the array notation indicators, that 11822 // is used to join the strings together, otherwise an array is returned 11823 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1); 11824 data = (join==="") ? out : out.join(join); 11825 11826 // The inner call to fetchData has already traversed through the remainder 11827 // of the source requested, so we exit from the loop 11828 break; 11829 } 11830 else if ( funcNotation ) 11831 { 11832 // Function call 11833 a[i] = a[i].replace(__reFn, ''); 11834 data = data[ a[i] ](); 11835 continue; 11836 } 11837 11838 if ( data === null || data[ a[i] ] === undefined ) 11839 { 11840 return undefined; 11841 } 11842 data = data[ a[i] ]; 11843 } 11844 } 11845 11846 return data; 11847 }; 11848 11849 return function (data, type) { // row and meta also passed, but not used 11850 return fetchData( data, type, mSource ); 11851 }; 11852 } 11853 else 11854 { 11855 /* Array or flat object mapping */ 11856 return function (data, type) { // row and meta also passed, but not used 11857 return data[mSource]; 11858 }; 11859 } 11860 } 11861 11862 11863 /** 11864 * Return a function that can be used to set data from a source object, taking 11865 * into account the ability to use nested objects as a source 11866 * @param {string|int|function} mSource The data source for the object 11867 * @returns {function} Data set function 11868 * @memberof DataTable#oApi 11869 */ 11870 function _fnSetObjectDataFn( mSource ) 11871 { 11872 if ( $.isPlainObject( mSource ) ) 11873 { 11874 /* Unlike get, only the underscore (global) option is used for for 11875 * setting data since we don't know the type here. This is why an object 11876 * option is not documented for `mData` (which is read/write), but it is 11877 * for `mRender` which is read only. 11878 */ 11879 return _fnSetObjectDataFn( mSource._ ); 11880 } 11881 else if ( mSource === null ) 11882 { 11883 /* Nothing to do when the data source is null */ 11884 return function () {}; 11885 } 11886 else if ( typeof mSource === 'function' ) 11887 { 11888 return function (data, val, meta) { 11889 mSource( data, 'set', val, meta ); 11890 }; 11891 } 11892 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || 11893 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) ) 11894 { 11895 /* Like the get, we need to get data from a nested object */ 11896 var setData = function (data, val, src) { 11897 var a = _fnSplitObjNotation( src ), b; 11898 var aLast = a[a.length-1]; 11899 var arrayNotation, funcNotation, o, innerSrc; 11900 11901 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) 11902 { 11903 // Check if we are dealing with an array notation request 11904 arrayNotation = a[i].match(__reArray); 11905 funcNotation = a[i].match(__reFn); 11906 11907 if ( arrayNotation ) 11908 { 11909 a[i] = a[i].replace(__reArray, ''); 11910 data[ a[i] ] = []; 11911 11912 // Get the remainder of the nested object to set so we can recurse 11913 b = a.slice(); 11914 b.splice( 0, i+1 ); 11915 innerSrc = b.join('.'); 11916 11917 // Traverse each entry in the array setting the properties requested 11918 if ( $.isArray( val ) ) 11919 { 11920 for ( var j=0, jLen=val.length ; j<jLen ; j++ ) 11921 { 11922 o = {}; 11923 setData( o, val[j], innerSrc ); 11924 data[ a[i] ].push( o ); 11925 } 11926 } 11927 else 11928 { 11929 // We've been asked to save data to an array, but it 11930 // isn't array data to be saved. Best that can be done 11931 // is to just save the value. 11932 data[ a[i] ] = val; 11933 } 11934 11935 // The inner call to setData has already traversed through the remainder 11936 // of the source and has set the data, thus we can exit here 11937 return; 11938 } 11939 else if ( funcNotation ) 11940 { 11941 // Function call 11942 a[i] = a[i].replace(__reFn, ''); 11943 data = data[ a[i] ]( val ); 11944 } 11945 11946 // If the nested object doesn't currently exist - since we are 11947 // trying to set the value - create it 11948 if ( data[ a[i] ] === null || data[ a[i] ] === undefined ) 11949 { 11950 data[ a[i] ] = {}; 11951 } 11952 data = data[ a[i] ]; 11953 } 11954 11955 // Last item in the input - i.e, the actual set 11956 if ( aLast.match(__reFn ) ) 11957 { 11958 // Function call 11959 data = data[ aLast.replace(__reFn, '') ]( val ); 11960 } 11961 else 11962 { 11963 // If array notation is used, we just want to strip it and use the property name 11964 // and assign the value. If it isn't used, then we get the result we want anyway 11965 data[ aLast.replace(__reArray, '') ] = val; 11966 } 11967 }; 11968 11969 return function (data, val) { // meta is also passed in, but not used 11970 return setData( data, val, mSource ); 11971 }; 11972 } 11973 else 11974 { 11975 /* Array or flat object mapping */ 11976 return function (data, val) { // meta is also passed in, but not used 11977 data[mSource] = val; 11978 }; 11979 } 11980 } 11981 11982 11983 /** 11984 * Return an array with the full table data 11985 * @param {object} oSettings dataTables settings object 11986 * @returns array {array} aData Master data array 11987 * @memberof DataTable#oApi 11988 */ 11989 function _fnGetDataMaster ( settings ) 11990 { 11991 return _pluck( settings.aoData, '_aData' ); 11992 } 11993 11994 11995 /** 11996 * Nuke the table 11997 * @param {object} oSettings dataTables settings object 11998 * @memberof DataTable#oApi 11999 */ 12000 function _fnClearTable( settings ) 12001 { 12002 settings.aoData.length = 0; 12003 settings.aiDisplayMaster.length = 0; 12004 settings.aiDisplay.length = 0; 12005 settings.aIds = {}; 12006 } 12007 12008 12009 /** 12010 * Take an array of integers (index array) and remove a target integer (value - not 12011 * the key!) 12012 * @param {array} a Index array to target 12013 * @param {int} iTarget value to find 12014 * @memberof DataTable#oApi 12015 */ 12016 function _fnDeleteIndex( a, iTarget, splice ) 12017 { 12018 var iTargetIndex = -1; 12019 12020 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) 12021 { 12022 if ( a[i] == iTarget ) 12023 { 12024 iTargetIndex = i; 12025 } 12026 else if ( a[i] > iTarget ) 12027 { 12028 a[i]--; 12029 } 12030 } 12031 12032 if ( iTargetIndex != -1 && splice === undefined ) 12033 { 12034 a.splice( iTargetIndex, 1 ); 12035 } 12036 } 12037 12038 12039 /**
12040 * Mark cached data as invalid such that a re-read of the data will occur when 12041 * the cached data is next requested. Also update from the data source object. 12042 * 12043 * @param {object} settings DataTables settings object 12044 * @param {int} rowIdx Row index to invalidate 12045 * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom' 12046 * or 'data' 12047 * @param {int} [colIdx] Column index to invalidate. If undefined the whole 12048 * row will be invalidated 12049 * @memberof DataTable#oApi 12050 * 12051 * @todo For the modularisation of v1.11 this will need to become a callback, so 12052 * the sort and filter methods can subscribe to it. That will required 12053 * initialisation options for sorting, which is why it is not already baked in 12054 */ 12055 function _fnInvalidate( settings, rowIdx, src, colIdx ) 12056 { 12057 var row = settings.aoData[ rowIdx ]; 12058 var i, ien; 12059 var cellWrite = function ( cell, col ) { 12060 // This is very frustrating, but in IE if you just write directly 12061 // to innerHTML, and elements that are overwritten are GC'ed, 12062 // even if there is a reference to them elsewhere 12063 while ( cell.childNodes.length ) { 12064 cell.removeChild( cell.firstChild ); 12065 } 12066 12067 cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' ); 12068 }; 12069 12070 // Are we reading last data from DOM or the data object? 12071 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) { 12072 // Read the data from the DOM 12073 row._aData = _fnGetRowElements( 12074 settings, row, colIdx, colIdx === undefined ? undefined : row._aData 12075 ) 12076 .data; 12077 } 12078 else { 12079 // Reading from data object, update the DOM 12080 var cells = row.anCells; 12081 12082 if ( cells ) { 12083 if ( colIdx !== undefined ) { 12084 cellWrite( cells[colIdx], colIdx ); 12085 } 12086 else { 12087 for ( i=0, ien=cells.length ; i<ien ; i++ ) { 12088 cellWrite( cells[i], i ); 12089 } 12090 } 12091 } 12092 } 12093 12094 // For both row and cell invalidation, the cached data for sorting and 12095 // filtering is nulled out 12096 row._aSortData = null; 12097 row._aFilterData = null; 12098 12099 // Invalidate the type for a specific column (if given) or all columns since 12100 // the data might have changed 12101 var cols = settings.aoColumns; 12102 if ( colIdx !== undefined ) { 12103 cols[ colIdx ].sType = null; 12104 } 12105 else { 12106 for ( i=0, ien=cols.length ; i<ien ; i++ ) { 12107 cols[i].sType = null; 12108 } 12109 12110 // Update DataTables special `DT_*` attributes for the row 12111 _fnRowAttributes( settings, row ); 12112 } 12113 } 12114 12115 12116 /** 12117 * Build a data source object from an HTML row, reading the contents of the 12118 * cells that are in the row. 12119 * 12120 * @param {object} settings DataTables settings object 12121 * @param {node|object} TR element from which to read data or existing row 12122 * object from which to re-read the data from the cells 12123 * @param {int} [colIdx] Optional column index 12124 * @param {array|object} [d] Data source object. If `colIdx` is given then this 12125 * parameter should also be given and will be used to write the data into. 12126 * Only the column in question will be written 12127 * @returns {object} Object with two parameters: `data` the data read, in 12128 * document order, and `cells` and array of nodes (they can be useful to the 12129 * caller, so rather than needing a second traversal to get them, just return 12130 * them from here). 12131 * @memberof DataTable#oApi 12132 */ 12133 function _fnGetRowElements( settings, row, colIdx, d ) 12134 { 12135 var 12136 tds = [], 12137 td = row.firstChild, 12138 name, col, o, i=0, contents, 12139 columns = settings.aoColumns, 12140 objectRead = settings._rowReadObject; 12141 12142 // Allow the data object to be passed in, or construct 12143 d = d !== undefined ? 12144 d : 12145 objectRead ? 12146 {} : 12147 []; 12148 12149 var attr = function ( str, td ) { 12150 if ( typeof str === 'string' ) { 12151 var idx = str.indexOf('@'); 12152 12153 if ( idx !== -1 ) { 12154 var attr = str.substring( idx+1 ); 12155 var setter = _fnSetObjectDataFn( str ); 12156 setter( d, td.getAttribute( attr ) ); 12157 } 12158 } 12159 }; 12160 12161 // Read data from a cell and store into the data object 12162 var cellProcess = function ( cell ) { 12163 if ( colIdx === undefined || colIdx === i ) { 12164 col = columns[i]; 12165 contents = $.trim(cell.innerHTML); 12166 12167 if ( col && col._bAttrSrc ) { 12168 var setter = _fnSetObjectDataFn( col.mData._ ); 12169 setter( d, contents ); 12170 12171 attr( col.mData.sort, cell ); 12172 attr( col.mData.type, cell ); 12173 attr( col.mData.filter, cell ); 12174 } 12175 else { 12176 // Depending on the `data` option for the columns the data can 12177 // be read to either an object or an array.
vendor: 10,997 bytes, lines 12178-12600
12178 if ( objectRead ) { 12179 if ( ! col._setter ) { 12180 // Cache the setter function 12181 col._setter = _fnSetObjectDataFn( col.mData ); 12182 } 12183 col._setter( d, contents ); 12184 } 12185 else { 12186 d[i] = contents; 12187 } 12188 } 12189 } 12190 12191 i++; 12192 }; 12193 12194 if ( td ) { 12195 // `tr` element was passed in 12196 while ( td ) { 12197 name = td.nodeName.toUpperCase(); 12198 12199 if ( name == "TD" || name == "TH" ) { 12200 cellProcess( td ); 12201 tds.push( td ); 12202 } 12203 12204 td = td.nextSibling; 12205 } 12206 } 12207 else { 12208 // Existing row object passed in 12209 tds = row.anCells; 12210 12211 for ( var j=0, jen=tds.length ; j<jen ; j++ ) { 12212 cellProcess( tds[j] ); 12213 } 12214 } 12215 12216 // Read the ID from the DOM if present 12217 var rowNode = row.firstChild ? row : row.nTr; 12218 12219 if ( rowNode ) { 12220 var id = rowNode.getAttribute( 'id' ); 12221 12222 if ( id ) { 12223 _fnSetObjectDataFn( settings.rowId )( d, id ); 12224 } 12225 } 12226 12227 return { 12228 data: d, 12229 cells: tds 12230 }; 12231 } 12232 /** 12233 * Create a new TR element (and it's TD children) for a row 12234 * @param {object} oSettings dataTables settings object 12235 * @param {int} iRow Row to consider 12236 * @param {node} [nTrIn] TR element to add to the table - optional. If not given, 12237 * DataTables will create a row automatically 12238 * @param {array} [anTds] Array of TD|TH elements for the row - must be given 12239 * if nTr is. 12240 * @memberof DataTable#oApi 12241 */ 12242 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds ) 12243 { 12244 var 12245 row = oSettings.aoData[iRow], 12246 rowData = row._aData, 12247 cells = [], 12248 nTr, nTd, oCol, 12249 i, iLen; 12250 12251 if ( row.nTr === null ) 12252 { 12253 nTr = nTrIn || document.createElement('tr'); 12254 12255 row.nTr = nTr; 12256 row.anCells = cells; 12257 12258 /* Use a private property on the node to allow reserve mapping from the node 12259 * to the aoData array for fast look up 12260 */ 12261 nTr._DT_RowIndex = iRow; 12262 12263 /* Special parameters can be given by the data source to be used on the row */ 12264 _fnRowAttributes( oSettings, row ); 12265 12266 /* Process each column */ 12267 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 12268 { 12269 oCol = oSettings.aoColumns[i]; 12270 12271 nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType ); 12272 nTd._DT_CellIndex = { 12273 row: iRow, 12274 column: i 12275 }; 12276 12277 cells.push( nTd ); 12278 12279 // Need to create the HTML if new, or if a rendering function is defined 12280 if ( (!nTrIn || oCol.mRender || oCol.mData !== i) && 12281 (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display') 12282 ) { 12283 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' ); 12284 } 12285 12286 /* Add user defined class */ 12287 if ( oCol.sClass ) 12288 { 12289 nTd.className += ' '+oCol.sClass; 12290 } 12291 12292 // Visibility - add or remove as required 12293 if ( oCol.bVisible && ! nTrIn ) 12294 { 12295 nTr.appendChild( nTd ); 12296 } 12297 else if ( ! oCol.bVisible && nTrIn ) 12298 { 12299 nTd.parentNode.removeChild( nTd ); 12300 } 12301 12302 if ( oCol.fnCreatedCell ) 12303 { 12304 oCol.fnCreatedCell.call( oSettings.oInstance, 12305 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i 12306 ); 12307 } 12308 } 12309 12310 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow, cells] ); 12311 } 12312 12313 // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved 12314 // and deployed 12315 row.nTr.setAttribute( 'role', 'row' ); 12316 } 12317 12318 12319 /** 12320 * Add attributes to a row based on the special `DT_*` parameters in a data 12321 * source object. 12322 * @param {object} settings DataTables settings object 12323 * @param {object} DataTables row object for the row to be modified 12324 * @memberof DataTable#oApi 12325 */ 12326 function _fnRowAttributes( settings, row ) 12327 { 12328 var tr = row.nTr; 12329 var data = row._aData; 12330 12331 if ( tr ) { 12332 var id = settings.rowIdFn( data ); 12333 12334 if ( id ) { 12335 tr.id = id; 12336 } 12337 12338 if ( data.DT_RowClass ) { 12339 // Remove any classes added by DT_RowClass before 12340 var a = data.DT_RowClass.split(' '); 12341 row.__rowc = row.__rowc ? 12342 _unique( row.__rowc.concat( a ) ) : 12343 a; 12344 12345 $(tr) 12346 .removeClass( row.__rowc.join(' ') ) 12347 .addClass( data.DT_RowClass ); 12348 } 12349 12350 if ( data.DT_RowAttr ) { 12351 $(tr).attr( data.DT_RowAttr ); 12352 } 12353 12354 if ( data.DT_RowData ) { 12355 $(tr).data( data.DT_RowData ); 12356 } 12357 } 12358 } 12359 12360 12361 /** 12362 * Create the HTML header for the table 12363 * @param {object} oSettings dataTables settings object 12364 * @memberof DataTable#oApi 12365 */ 12366 function _fnBuildHead( oSettings ) 12367 { 12368 var i, ien, cell, row, column; 12369 var thead = oSettings.nTHead; 12370 var tfoot = oSettings.nTFoot; 12371 var createHeader = $('th, td', thead).length === 0; 12372 var classes = oSettings.oClasses; 12373 var columns = oSettings.aoColumns; 12374 12375 if ( createHeader ) { 12376 row = $('<tr/>').appendTo( thead ); 12377 } 12378 12379 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 12380 column = columns[i]; 12381 cell = $( column.nTh ).addClass( column.sClass ); 12382 12383 if ( createHeader ) { 12384 cell.appendTo( row ); 12385 } 12386 12387 // 1.11 move into sorting 12388 if ( oSettings.oFeatures.bSort ) { 12389 cell.addClass( column.sSortingClass ); 12390 12391 if ( column.bSortable !== false ) { 12392 cell 12393 .attr( 'tabindex', oSettings.iTabIndex ) 12394 .attr( 'aria-controls', oSettings.sTableId ); 12395 12396 _fnSortAttachListener( oSettings, column.nTh, i ); 12397 } 12398 } 12399 12400 if ( column.sTitle != cell[0].innerHTML ) { 12401 cell.html( column.sTitle ); 12402 } 12403 12404 _fnRenderer( oSettings, 'header' )( 12405 oSettings, cell, column, classes 12406 ); 12407 } 12408 12409 if ( createHeader ) { 12410 _fnDetectHeader( oSettings.aoHeader, thead ); 12411 } 12412 12413 /* ARIA role for the rows */ 12414 $(thead).find('>tr').attr('role', 'row'); 12415 12416 /* Deal with the footer - add classes if required */ 12417 $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH ); 12418 $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH ); 12419 12420 // Cache the footer cells. Note that we only take the cells from the first 12421 // row in the footer. If there is more than one row the user wants to 12422 // interact with, they need to use the table().foot() method. Note also this 12423 // allows cells to be used for multiple columns using colspan 12424 if ( tfoot !== null ) { 12425 var cells = oSettings.aoFooter[0]; 12426 12427 for ( i=0, ien=cells.length ; i<ien ; i++ ) { 12428 column = columns[i]; 12429 column.nTf = cells[i].cell; 12430 12431 if ( column.sClass ) { 12432 $(column.nTf).addClass( column.sClass ); 12433 } 12434 } 12435 } 12436 } 12437 12438 12439 /** 12440 * Draw the header (or footer) element based on the column visibility states. The 12441 * methodology here is to use the layout array from _fnDetectHeader, modified for 12442 * the instantaneous column visibility, to construct the new layout. The grid is 12443 * traversed over cell at a time in a rows x columns grid fashion, although each 12444 * cell insert can cover multiple elements in the grid - which is tracks using the 12445 * aApplied array. Cell inserts in the grid will only occur where there isn't 12446 * already a cell in that position. 12447 * @param {object} oSettings dataTables settings object 12448 * @param array {objects} aoSource Layout array from _fnDetectHeader 12449 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc, 12450 * @memberof DataTable#oApi 12451 */ 12452 function _fnDrawHead( oSettings, aoSource, bIncludeHidden ) 12453 { 12454 var i, iLen, j, jLen, k, kLen, n, nLocalTr; 12455 var aoLocal = []; 12456 var aApplied = []; 12457 var iColumns = oSettings.aoColumns.length; 12458 var iRowspan, iColspan; 12459 12460 if ( ! aoSource ) 12461 { 12462 return; 12463 } 12464 12465 if ( bIncludeHidden === undefined ) 12466 { 12467 bIncludeHidden = false; 12468 } 12469 12470 /* Make a copy of the master layout array, but without the visible columns in it */ 12471 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ ) 12472 { 12473 aoLocal[i] = aoSource[i].slice(); 12474 aoLocal[i].nTr = aoSource[i].nTr; 12475 12476 /* Remove any columns which are currently hidden */ 12477 for ( j=iColumns-1 ; j>=0 ; j-- ) 12478 { 12479 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden ) 12480 { 12481 aoLocal[i].splice( j, 1 ); 12482 } 12483 } 12484 12485 /* Prep the applied array - it needs an element for each row */ 12486 aApplied.push( [] ); 12487 } 12488 12489 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ ) 12490 { 12491 nLocalTr = aoLocal[i].nTr; 12492 12493 /* All cells are going to be replaced, so empty out the row */ 12494 if ( nLocalTr ) 12495 { 12496 while( (n = nLocalTr.firstChild) ) 12497 { 12498 nLocalTr.removeChild( n ); 12499 } 12500 } 12501 12502 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ ) 12503 { 12504 iRowspan = 1; 12505 iColspan = 1; 12506 12507 /* Check to see if there is already a cell (row/colspan) covering our target 12508 * insert point. If there is, then there is nothing to do. 12509 */ 12510 if ( aApplied[i][j] === undefined ) 12511 { 12512 nLocalTr.appendChild( aoLocal[i][j].cell ); 12513 aApplied[i][j] = 1; 12514 12515 /* Expand the cell to cover as many rows as needed */ 12516 while ( aoLocal[i+iRowspan] !== undefined && 12517 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell ) 12518 { 12519 aApplied[i+iRowspan][j] = 1; 12520 iRowspan++; 12521 } 12522 12523 /* Expand the cell to cover as many columns as needed */ 12524 while ( aoLocal[i][j+iColspan] !== undefined && 12525 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell ) 12526 { 12527 /* Must update the applied array over the rows for the columns */ 12528 for ( k=0 ; k<iRowspan ; k++ ) 12529 { 12530 aApplied[i+k][j+iColspan] = 1; 12531 } 12532 iColspan++; 12533 } 12534 12535 /* Do the actual expansion in the DOM */ 12536 $(aoLocal[i][j].cell) 12537 .attr('rowspan', iRowspan) 12538 .attr('colspan', iColspan); 12539 } 12540 } 12541 } 12542 } 12543 12544 12545 /** 12546 * Insert the required TR nodes into the table for display 12547 * @param {object} oSettings dataTables settings object 12548 * @memberof DataTable#oApi 12549 */ 12550 function _fnDraw( oSettings ) 12551 { 12552 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */ 12553 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] ); 12554 if ( $.inArray( false, aPreDraw ) !== -1 ) 12555 { 12556 _fnProcessingDisplay( oSettings, false ); 12557 return; 12558 } 12559 12560 var i, iLen, n; 12561 var anRows = []; 12562 var iRowCount = 0; 12563 var asStripeClasses = oSettings.asStripeClasses; 12564 var iStripes = asStripeClasses.length; 12565 var iOpenRows = oSettings.aoOpenRows.length; 12566 var oLang = oSettings.oLanguage; 12567 var iInitDisplayStart = oSettings.iInitDisplayStart; 12568 var bServerSide = _fnDataSource( oSettings ) == 'ssp'; 12569 var aiDisplay = oSettings.aiDisplay; 12570 12571 oSettings.bDrawing = true; 12572 12573 /* Check and see if we have an initial draw position from state saving */ 12574 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 ) 12575 { 12576 oSettings._iDisplayStart = bServerSide ? 12577 iInitDisplayStart : 12578 iInitDisplayStart >= oSettings.fnRecordsDisplay() ? 12579 0 : 12580 iInitDisplayStart; 12581 12582 oSettings.iInitDisplayStart = -1; 12583 } 12584 12585 var iDisplayStart = oSettings._iDisplayStart; 12586 var iDisplayEnd = oSettings.fnDisplayEnd(); 12587 12588 /* Server-side processing draw intercept */ 12589 if ( oSettings.bDeferLoading ) 12590 { 12591 oSettings.bDeferLoading = false; 12592 oSettings.iDraw++; 12593 _fnProcessingDisplay( oSettings, false ); 12594 } 12595 else if ( !bServerSide ) 12596 { 12597 oSettings.iDraw++; 12598 } 12599 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) ) 12600 {
vendor: 10,503 bytes, lines 12600-12989
12600 12601 return; 12602 } 12603 12604 if ( aiDisplay.length !== 0 ) 12605 { 12606 var iStart = bServerSide ? 0 : iDisplayStart; 12607 var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd; 12608 12609 for ( var j=iStart ; j<iEnd ; j++ ) 12610 { 12611 var iDataIndex = aiDisplay[j]; 12612 var aoData = oSettings.aoData[ iDataIndex ]; 12613 if ( aoData.nTr === null ) 12614 { 12615 _fnCreateTr( oSettings, iDataIndex ); 12616 } 12617 12618 var nRow = aoData.nTr; 12619 12620 /* Remove the old striping classes and then add the new one */ 12621 if ( iStripes !== 0 ) 12622 { 12623 var sStripe = asStripeClasses[ iRowCount % iStripes ]; 12624 if ( aoData._sRowStripe != sStripe ) 12625 { 12626 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe ); 12627 aoData._sRowStripe = sStripe; 12628 } 12629 } 12630 12631 // Row callback functions - might want to manipulate the row 12632 // iRowCount and j are not currently documented. Are they at all 12633 // useful? 12634 _fnCallbackFire( oSettings, 'aoRowCallback', null, 12635 [nRow, aoData._aData, iRowCount, j, iDataIndex] ); 12636 12637 anRows.push( nRow ); 12638 iRowCount++; 12639 } 12640 } 12641 else 12642 { 12643 /* Table is empty - create a row with an empty message in it */ 12644 var sZero = oLang.sZeroRecords; 12645 if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' ) 12646 { 12647 sZero = oLang.sLoadingRecords; 12648 } 12649 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 ) 12650 { 12651 sZero = oLang.sEmptyTable; 12652 } 12653 12654 anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } ) 12655 .append( $('<td />', { 12656 'valign': 'top', 12657 'colSpan': _fnVisbleColumns( oSettings ), 12658 'class': oSettings.oClasses.sRowEmpty 12659 } ).html( sZero ) )[0]; 12660 } 12661 12662 /* Header and footer callbacks */ 12663 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], 12664 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); 12665 12666 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], 12667 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); 12668 12669 var body = $(oSettings.nTBody); 12670 12671 body.children().detach(); 12672 body.append( $(anRows) ); 12673 12674 /* Call all required callback functions for the end of a draw */ 12675 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] ); 12676 12677 /* Draw is complete, sorting and filtering must be as well */ 12678 oSettings.bSorted = false; 12679 oSettings.bFiltered = false; 12680 oSettings.bDrawing = false; 12681 } 12682 12683 12684 /** 12685 * Redraw the table - taking account of the various features which are enabled 12686 * @param {object} oSettings dataTables settings object 12687 * @param {boolean} [holdPosition] Keep the current paging position. By default 12688 * the paging is reset to the first page 12689 * @memberof DataTable#oApi 12690 */ 12691 function _fnReDraw( settings, holdPosition ) 12692 { 12693 var 12694 features = settings.oFeatures, 12695 sort = features.bSort, 12696 filter = features.bFilter; 12697 12698 if ( sort ) { 12699 _fnSort( settings ); 12700 } 12701 12702 if ( filter ) { 12703 _fnFilterComplete( settings, settings.oPreviousSearch ); 12704 } 12705 else { 12706 // No filtering, so we want to just use the display master 12707 settings.aiDisplay = settings.aiDisplayMaster.slice(); 12708 } 12709 12710 if ( holdPosition !== true ) { 12711 settings._iDisplayStart = 0; 12712 } 12713 12714 // Let any modules know about the draw hold position state (used by 12715 // scrolling internally) 12716 settings._drawHold = holdPosition; 12717 12718 _fnDraw( settings ); 12719 12720 settings._drawHold = false; 12721 } 12722 12723 12724 /** 12725 * Add the options to the page HTML for the table 12726 * @param {object} oSettings dataTables settings object 12727 * @memberof DataTable#oApi 12728 */ 12729 function _fnAddOptionsHtml ( oSettings ) 12730 { 12731 var classes = oSettings.oClasses; 12732 var table = $(oSettings.nTable); 12733 var holding = $('<div/>').insertBefore( table ); // Holding element for speed 12734 var features = oSettings.oFeatures; 12735 12736 // All DataTables are wrapped in a div 12737 var insert = $('<div/>', { 12738 id: oSettings.sTableId+'_wrapper', 12739 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter) 12740 } ); 12741 12742 oSettings.nHolding = holding[0]; 12743 oSettings.nTableWrapper = insert[0]; 12744 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling; 12745 12746 /* Loop over the user set positioning and place the elements as needed */ 12747 var aDom = oSettings.sDom.split(''); 12748 var featureNode, cOption, nNewNode, cNext, sAttr, j; 12749 for ( var i=0 ; i<aDom.length ; i++ ) 12750 { 12751 featureNode = null; 12752 cOption = aDom[i]; 12753 12754 if ( cOption == '<' ) 12755 { 12756 /* New container div */ 12757 nNewNode = $('<div/>')[0]; 12758 12759 /* Check to see if we should append an id and/or a class name to the container */ 12760 cNext = aDom[i+1]; 12761 if ( cNext == "'" || cNext == '"' ) 12762 { 12763 sAttr = ""; 12764 j = 2; 12765 while ( aDom[i+j] != cNext ) 12766 { 12767 sAttr += aDom[i+j]; 12768 j++; 12769 } 12770 12771 /* Replace jQuery UI constants @todo depreciated */ 12772 if ( sAttr == "H" ) 12773 { 12774 sAttr = classes.sJUIHeader; 12775 } 12776 else if ( sAttr == "F" ) 12777 { 12778 sAttr = classes.sJUIFooter; 12779 } 12780 12781 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic 12782 * breaks the string into parts and applies them as needed 12783 */ 12784 if ( sAttr.indexOf('.') != -1 ) 12785 { 12786 var aSplit = sAttr.split('.'); 12787 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1); 12788 nNewNode.className = aSplit[1]; 12789 } 12790 else if ( sAttr.charAt(0) == "#" ) 12791 { 12792 nNewNode.id = sAttr.substr(1, sAttr.length-1); 12793 } 12794 else 12795 { 12796 nNewNode.className = sAttr; 12797 } 12798 12799 i += j; /* Move along the position array */ 12800 } 12801 12802 insert.append( nNewNode ); 12803 insert = $(nNewNode); 12804 } 12805 else if ( cOption == '>' ) 12806 { 12807 /* End container div */ 12808 insert = insert.parent(); 12809 } 12810 // @todo Move options into their own plugins? 12811 else if ( cOption == 'l' && features.bPaginate && features.bLengthChange ) 12812 { 12813 /* Length */ 12814 featureNode = _fnFeatureHtmlLength( oSettings ); 12815 } 12816 else if ( cOption == 'f' && features.bFilter ) 12817 { 12818 /* Filter */ 12819 featureNode = _fnFeatureHtmlFilter( oSettings ); 12820 } 12821 else if ( cOption == 'r' && features.bProcessing ) 12822 { 12823 /* pRocessing */ 12824 featureNode = _fnFeatureHtmlProcessing( oSettings ); 12825 } 12826 else if ( cOption == 't' ) 12827 { 12828 /* Table */ 12829 featureNode = _fnFeatureHtmlTable( oSettings ); 12830 } 12831 else if ( cOption == 'i' && features.bInfo ) 12832 { 12833 /* Info */ 12834 featureNode = _fnFeatureHtmlInfo( oSettings ); 12835 } 12836 else if ( cOption == 'p' && features.bPaginate ) 12837 { 12838 /* Pagination */ 12839 featureNode = _fnFeatureHtmlPaginate( oSettings ); 12840 } 12841 else if ( DataTable.ext.feature.length !== 0 ) 12842 { 12843 /* Plug-in features */ 12844 var aoFeatures = DataTable.ext.feature; 12845 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ ) 12846 { 12847 if ( cOption == aoFeatures[k].cFeature ) 12848 { 12849 featureNode = aoFeatures[k].fnInit( oSettings ); 12850 break; 12851 } 12852 } 12853 } 12854 12855 /* Add to the 2D features array */ 12856 if ( featureNode ) 12857 { 12858 var aanFeatures = oSettings.aanFeatures; 12859 12860 if ( ! aanFeatures[cOption] ) 12861 { 12862 aanFeatures[cOption] = []; 12863 } 12864 12865 aanFeatures[cOption].push( featureNode ); 12866 insert.append( featureNode ); 12867 } 12868 } 12869 12870 /* Built our DOM structure - replace the holding div with what we want */ 12871 holding.replaceWith( insert ); 12872 oSettings.nHolding = null; 12873 } 12874 12875 12876 /** 12877 * Use the DOM source to create up an array of header cells. The idea here is to 12878 * create a layout grid (array) of rows x columns, which contains a reference 12879 * to the cell that that point in the grid (regardless of col/rowspan), such that 12880 * any column / row could be removed and the new grid constructed 12881 * @param array {object} aLayout Array to store the calculated layout in 12882 * @param {node} nThead The header/footer element for the table 12883 * @memberof DataTable#oApi 12884 */ 12885 function _fnDetectHeader ( aLayout, nThead ) 12886 { 12887 var nTrs = $(nThead).children('tr'); 12888 var nTr, nCell; 12889 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan; 12890 var bUnique; 12891 var fnShiftCol = function ( a, i, j ) { 12892 var k = a[i]; 12893 while ( k[j] ) { 12894 j++; 12895 } 12896 return j; 12897 }; 12898 12899 aLayout.splice( 0, aLayout.length ); 12900 12901 /* We know how many rows there are in the layout - so prep it */ 12902 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 12903 { 12904 aLayout.push( [] ); 12905 } 12906 12907 /* Calculate a layout array */ 12908 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 12909 { 12910 nTr = nTrs[i]; 12911 iColumn = 0; 12912 12913 /* For every cell in the row... */ 12914 nCell = nTr.firstChild; 12915 while ( nCell ) { 12916 if ( nCell.nodeName.toUpperCase() == "TD" || 12917 nCell.nodeName.toUpperCase() == "TH" ) 12918 { 12919 /* Get the col and rowspan attributes from the DOM and sanitise them */ 12920 iColspan = nCell.getAttribute('colspan') * 1; 12921 iRowspan = nCell.getAttribute('rowspan') * 1; 12922 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan; 12923 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan; 12924 12925 /* There might be colspan cells already in this row, so shift our target 12926 * accordingly 12927 */ 12928 iColShifted = fnShiftCol( aLayout, i, iColumn ); 12929 12930 /* Cache calculation for unique columns */ 12931 bUnique = iColspan === 1 ? true : false; 12932 12933 /* If there is col / rowspan, copy the information into the layout grid */ 12934 for ( l=0 ; l<iColspan ; l++ ) 12935 { 12936 for ( k=0 ; k<iRowspan ; k++ ) 12937 { 12938 aLayout[i+k][iColShifted+l] = { 12939 "cell": nCell, 12940 "unique": bUnique 12941 }; 12942 aLayout[i+k].nTr = nTr; 12943 } 12944 } 12945 } 12946 nCell = nCell.nextSibling; 12947 } 12948 } 12949 } 12950 12951 12952 /** 12953 * Get an array of unique th elements, one for each column 12954 * @param {object} oSettings dataTables settings object 12955 * @param {node} nHeader automatically detect the layout from this node - optional 12956 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional 12957 * @returns array {node} aReturn list of unique th's 12958 * @memberof DataTable#oApi 12959 */ 12960 function _fnGetUniqueThs ( oSettings, nHeader, aLayout ) 12961 { 12962 var aReturn = []; 12963 if ( !aLayout ) 12964 { 12965 aLayout = oSettings.aoHeader; 12966 if ( nHeader ) 12967 { 12968 aLayout = []; 12969 _fnDetectHeader( aLayout, nHeader ); 12970 } 12971 } 12972 12973 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ ) 12974 { 12975 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ ) 12976 { 12977 if ( aLayout[i][j].unique && 12978 (!aReturn[j] || !oSettings.bSortCellsTop) ) 12979 { 12980 aReturn[j] = aLayout[i][j].cell; 12981 } 12982 } 12983 } 12984 12985 return aReturn; 12986 } 12987 12988 /** 12989 *
vendor: 47,797 bytes, lines 12989-14636
12989Create an Ajax call based on the table's settings, taking into account that 12990 * parameters can have multiple forms, and backwards compatibility. 12991 * 12992 * @param {object} oSettings dataTables settings object 12993 * @param {array} data Data to send to the server, required by 12994 * DataTables - may be augmented by developer callbacks 12995 * @param {function} fn Callback function to run when data is obtained 12996 */ 12997 function _fnBuildAjax( oSettings, data, fn ) 12998 { 12999 // Compatibility with 1.9-, allow fnServerData and event to manipulate 13000 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] ); 13001 13002 // Convert to object based for 1.10+ if using the old array scheme which can 13003 // come from server-side processing or serverParams 13004 if ( data && $.isArray(data) ) { 13005 var tmp = {}; 13006 var rbracket = /(.*?)\[\]$/; 13007 13008 $.each( data, function (key, val) { 13009 var match = val.name.match(rbracket); 13010 13011 if ( match ) { 13012 // Support for arrays 13013 var name = match[0]; 13014 13015 if ( ! tmp[ name ] ) { 13016 tmp[ name ] = []; 13017 } 13018 tmp[ name ].push( val.value ); 13019 } 13020 else { 13021 tmp[val.name] = val.value; 13022 } 13023 } ); 13024 data = tmp; 13025 } 13026 13027 var ajaxData; 13028 var ajax = oSettings.ajax; 13029 var instance = oSettings.oInstance; 13030 var callback = function ( json ) { 13031 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] ); 13032 fn( json ); 13033 }; 13034 13035 if ( $.isPlainObject( ajax ) && ajax.data ) 13036 { 13037 ajaxData = ajax.data; 13038 13039 var newData = typeof ajaxData === 'function' ? 13040 ajaxData( data, oSettings ) : // fn can manipulate data or return 13041 ajaxData; // an object object or array to merge 13042 13043 // If the function returned something, use that alone 13044 data = typeof ajaxData === 'function' && newData ? 13045 newData : 13046 $.extend( true, data, newData ); 13047 13048 // Remove the data property as we've resolved it already and don't want 13049 // jQuery to do it again (it is restored at the end of the function) 13050 delete ajax.data; 13051 } 13052 13053 var baseAjax = { 13054 "data": data, 13055 "success": function (json) { 13056 var error = json.error || json.sError; 13057 if ( error ) { 13058 _fnLog( oSettings, 0, error ); 13059 } 13060 13061 oSettings.json = json; 13062 callback( json ); 13063 }, 13064 "dataType": "json", 13065 "cache": false, 13066 "type": oSettings.sServerMethod, 13067 "error": function (xhr, error, thrown) { 13068 var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] ); 13069 13070 if ( $.inArray( true, ret ) === -1 ) { 13071 if ( error == "parsererror" ) { 13072 _fnLog( oSettings, 0, 'Invalid JSON response', 1 ); 13073 } 13074 else if ( xhr.readyState === 4 ) { 13075 _fnLog( oSettings, 0, 'Ajax error', 7 ); 13076 } 13077 } 13078 13079 _fnProcessingDisplay( oSettings, false ); 13080 } 13081 }; 13082 13083 // Store the data submitted for the API 13084 oSettings.oAjaxData = data; 13085 13086 // Allow plug-ins and external processes to modify the data 13087 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] ); 13088 13089 if ( oSettings.fnServerData ) 13090 { 13091 // DataTables 1.9- compatibility 13092 oSettings.fnServerData.call( instance, 13093 oSettings.sAjaxSource, 13094 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format 13095 return { name: key, value: val }; 13096 } ), 13097 callback, 13098 oSettings 13099 ); 13100 } 13101 else if ( oSettings.sAjaxSource || typeof ajax === 'string' ) 13102 { 13103 // DataTables 1.9- compatibility 13104 oSettings.jqXHR = $.ajax( $.extend( baseAjax, { 13105 url: ajax || oSettings.sAjaxSource 13106 } ) ); 13107 } 13108 else if ( typeof ajax === 'function' ) 13109 { 13110 // Is a function - let the caller define what needs to be done 13111 oSettings.jqXHR = ajax.call( instance, data, callback, oSettings ); 13112 } 13113 else 13114 { 13115 // Object to extend the base settings 13116 oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) ); 13117 13118 // Restore for next time around 13119 ajax.data = ajaxData; 13120 } 13121 } 13122 13123 13124 /** 13125 * Update the table using an Ajax call 13126 * @param {object} settings dataTables settings object 13127 * @returns {boolean} Block the table drawing or not 13128 * @memberof DataTable#oApi 13129 */ 13130 function _fnAjaxUpdate( settings ) 13131 { 13132 if ( settings.bAjaxDataGet ) { 13133 settings.iDraw++; 13134 _fnProcessingDisplay( settings, true ); 13135 13136 _fnBuildAjax( 13137 settings, 13138 _fnAjaxParameters( settings ), 13139 function(json) { 13140 _fnAjaxUpdateDraw( settings, json ); 13141 } 13142 ); 13143 13144 return false; 13145 } 13146 return true; 13147 } 13148 13149 13150 /** 13151 * Build up the parameters in an object needed for a server-side processing 13152 * request. Note that this is basically done twice, is different ways - a modern 13153 * method which is used by default in DataTables 1.10 which uses objects and 13154 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if 13155 * the sAjaxSource option is used in the initialisation, or the legacyAjax 13156 * option is set. 13157 * @param {object} oSettings dataTables settings object 13158 * @returns {bool} block the table drawing or not 13159 * @memberof DataTable#oApi 13160 */ 13161 function _fnAjaxParameters( settings ) 13162 { 13163 var 13164 columns = settings.aoColumns, 13165 columnCount = columns.length, 13166 features = settings.oFeatures, 13167 preSearch = settings.oPreviousSearch, 13168 preColSearch = settings.aoPreSearchCols, 13169 i, data = [], dataProp, column, columnSearch, 13170 sort = _fnSortFlatten( settings ), 13171 displayStart = settings._iDisplayStart, 13172 displayLength = features.bPaginate !== false ? 13173 settings._iDisplayLength : 13174 -1; 13175 13176 var param = function ( name, value ) { 13177 data.push( { 'name': name, 'value': value } ); 13178 }; 13179 13180 // DataTables 1.9- compatible method 13181 param( 'sEcho', settings.iDraw ); 13182 param( 'iColumns', columnCount ); 13183 param( 'sColumns', _pluck( columns, 'sName' ).join(',') ); 13184 param( 'iDisplayStart', displayStart ); 13185 param( 'iDisplayLength', displayLength ); 13186 13187 // DataTables 1.10+ method 13188 var d = { 13189 draw: settings.iDraw, 13190 columns: [], 13191 order: [], 13192 start: displayStart, 13193 length: displayLength, 13194 search: { 13195 value: preSearch.sSearch, 13196 regex: preSearch.bRegex 13197 } 13198 }; 13199 13200 for ( i=0 ; i<columnCount ; i++ ) { 13201 column = columns[i]; 13202 columnSearch = preColSearch[i]; 13203 dataProp = typeof column.mData=="function" ? 'function' : column.mData ; 13204 13205 d.columns.push( { 13206 data: dataProp, 13207 name: column.sName, 13208 searchable: column.bSearchable, 13209 orderable: column.bSortable, 13210 search: { 13211 value: columnSearch.sSearch, 13212 regex: columnSearch.bRegex 13213 } 13214 } ); 13215 13216 param( "mDataProp_"+i, dataProp ); 13217 13218 if ( features.bFilter ) { 13219 param( 'sSearch_'+i, columnSearch.sSearch ); 13220 param( 'bRegex_'+i, columnSearch.bRegex ); 13221 param( 'bSearchable_'+i, column.bSearchable ); 13222 } 13223 13224 if ( features.bSort ) { 13225 param( 'bSortable_'+i, column.bSortable ); 13226 } 13227 } 13228 13229 if ( features.bFilter ) { 13230 param( 'sSearch', preSearch.sSearch ); 13231 param( 'bRegex', preSearch.bRegex ); 13232 } 13233 13234 if ( features.bSort ) { 13235 $.each( sort, function ( i, val ) { 13236 d.order.push( { column: val.col, dir: val.dir } ); 13237 13238 param( 'iSortCol_'+i, val.col ); 13239 param( 'sSortDir_'+i, val.dir ); 13240 } ); 13241 13242 param( 'iSortingCols', sort.length ); 13243 } 13244 13245 // If the legacy.ajax parameter is null, then we automatically decide which 13246 // form to use, based on sAjaxSource 13247 var legacy = DataTable.ext.legacy.ajax; 13248 if ( legacy === null ) { 13249 return settings.sAjaxSource ? data : d; 13250 } 13251 13252 // Otherwise, if legacy has been specified then we use that to decide on the 13253 // form 13254 return legacy ? data : d; 13255 } 13256 13257 13258 /** 13259 * Data the data from the server (nuking the old) and redraw the table 13260 * @param {object} oSettings dataTables settings object 13261 * @param {object} json json data return from the server. 13262 * @param {string} json.sEcho Tracking flag for DataTables to match requests 13263 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering 13264 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering 13265 * @param {array} json.aaData The data to display on this page 13266 * @param {string} [json.sColumns] Column ordering (sName, comma separated) 13267 * @memberof DataTable#oApi 13268 */ 13269 function _fnAjaxUpdateDraw ( settings, json ) 13270 { 13271 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation. 13272 // Support both 13273 var compat = function ( old, modern ) { 13274 return json[old] !== undefined ? json[old] : json[modern]; 13275 }; 13276 13277 var data = _fnAjaxDataSrc( settings, json ); 13278 var draw = compat( 'sEcho', 'draw' ); 13279 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' ); 13280 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' ); 13281 13282 if ( draw ) { 13283 // Protect against out of sequence returns 13284 if ( draw*1 < settings.iDraw ) { 13285 return; 13286 } 13287 settings.iDraw = draw * 1; 13288 } 13289 13290 _fnClearTable( settings ); 13291 settings._iRecordsTotal = parseInt(recordsTotal, 10); 13292 settings._iRecordsDisplay = parseInt(recordsFiltered, 10); 13293 13294 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 13295 _fnAddData( settings, data[i] ); 13296 } 13297 settings.aiDisplay = settings.aiDisplayMaster.slice(); 13298 13299 settings.bAjaxDataGet = false; 13300 _fnDraw( settings ); 13301 13302 if ( ! settings._bInitComplete ) { 13303 _fnInitComplete( settings, json ); 13304 } 13305 13306 settings.bAjaxDataGet = true; 13307 _fnProcessingDisplay( settings, false ); 13308 } 13309 13310 13311 /** 13312 * Get the data from the JSON data source to use for drawing a table. Using 13313 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the 13314 * source object, or from a processing function. 13315 * @param {object} oSettings dataTables settings object 13316 * @param {object} json Data source object / array from the server 13317 * @return {array} Array of data to use 13318 */ 13319 function _fnAjaxDataSrc ( oSettings, json ) 13320 { 13321 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ? 13322 oSettings.ajax.dataSrc : 13323 oSettings.sAjaxDataProp; // Compatibility with 1.9-. 13324 13325 // Compatibility with 1.9-. In order to read from aaData, check if the 13326 // default has been changed, if not, check for aaData 13327 if ( dataSrc === 'data' ) { 13328 return json.aaData || json[dataSrc]; 13329 } 13330 13331 return dataSrc !== "" ? 13332 _fnGetObjectDataFn( dataSrc )( json ) : 13333 json; 13334 } 13335 13336 /** 13337 * Generate the node required for filtering text 13338 * @returns {node} Filter control element 13339 * @param {object} oSettings dataTables settings object 13340 * @memberof DataTable#oApi 13341 */ 13342 function _fnFeatureHtmlFilter ( settings ) 13343 { 13344 var classes = settings.oClasses; 13345 var tableId = settings.sTableId; 13346 var language = settings.oLanguage; 13347 var previousSearch = settings.oPreviousSearch; 13348 var features = settings.aanFeatures; 13349 var input = '<input type="search" class="'+classes.sFilterInput+'"/>'; 13350 13351 var str = language.sSearch; 13352 str = str.match(/_INPUT_/) ? 13353 str.replace('_INPUT_', input) : 13354 str+input; 13355 13356 var filter = $('<div/>', { 13357 'id': ! features.f ? tableId+'_filter' : null, 13358 'class': classes.sFilter 13359 } ) 13360 .append( $('<label/>' ).append( str ) ); 13361 13362 var searchFn = function() { 13363 /* Update all other filter input elements for the new display */ 13364 var n = features.f; 13365 var val = !this.value ? "" : this.value; // mental IE8 fix :-( 13366 13367 /* Now do the filter */ 13368 if ( val != previousSearch.sSearch ) { 13369 _fnFilterComplete( settings, { 13370 "sSearch": val, 13371 "bRegex": previousSearch.bRegex, 13372 "bSmart": previousSearch.bSmart , 13373 "bCaseInsensitive": previousSearch.bCaseInsensitive 13374 } ); 13375 13376 // Need to redraw, without resorting 13377 settings._iDisplayStart = 0; 13378 _fnDraw( settings ); 13379 } 13380 }; 13381 13382 var searchDelay = settings.searchDelay !== null ? 13383 settings.searchDelay : 13384 _fnDataSource( settings ) === 'ssp' ? 13385 400 : 13386 0; 13387 13388 var jqFilter = $('input', filter) 13389 .val( previousSearch.sSearch ) 13390 .attr( 'placeholder', language.sSearchPlaceholder ) 13391 .on( 13392 'keyup.DT search.DT input.DT paste.DT cut.DT', 13393 searchDelay ? 13394 _fnThrottle( searchFn, searchDelay ) : 13395 searchFn 13396 ) 13397 .on( 'keypress.DT', function(e) { 13398 /* Prevent form submission */ 13399 if ( e.keyCode == 13 ) { 13400 return false; 13401 } 13402 } ) 13403 .attr('aria-controls', tableId); 13404 13405 // Update the input elements whenever the table is filtered 13406 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) { 13407 if ( settings === s ) { 13408 // IE9 throws an 'unknown error' if document.activeElement is used 13409 // inside an iframe or frame... 13410 try { 13411 if ( jqFilter[0] !== document.activeElement ) { 13412 jqFilter.val( previousSearch.sSearch ); 13413 } 13414 } 13415 catch ( e ) {} 13416 } 13417 } ); 13418 13419 return filter[0]; 13420 } 13421 13422 13423 /** 13424 * Filter the table using both the global filter and column based filtering 13425 * @param {object} oSettings dataTables settings object 13426 * @param {object} oSearch search information 13427 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0) 13428 * @memberof DataTable#oApi 13429 */ 13430 function _fnFilterComplete ( oSettings, oInput, iForce ) 13431 { 13432 var oPrevSearch = oSettings.oPreviousSearch; 13433 var aoPrevSearch = oSettings.aoPreSearchCols; 13434 var fnSaveFilter = function ( oFilter ) { 13435 /* Save the filtering values */ 13436 oPrevSearch.sSearch = oFilter.sSearch; 13437 oPrevSearch.bRegex = oFilter.bRegex; 13438 oPrevSearch.bSmart = oFilter.bSmart; 13439 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive; 13440 }; 13441 var fnRegex = function ( o ) { 13442 // Backwards compatibility with the bEscapeRegex option 13443 return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex; 13444 }; 13445 13446 // Resolve any column types that are unknown due to addition or invalidation 13447 // @todo As per sort - can this be moved into an event handler? 13448 _fnColumnTypes( oSettings ); 13449 13450 /* In server-side processing all filtering is done by the server, so no point hanging around here */ 13451 if ( _fnDataSource( oSettings ) != 'ssp' ) 13452 { 13453 /* Global filter */ 13454 _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive ); 13455 fnSaveFilter( oInput ); 13456 13457 /* Now do the individual column filter */ 13458 for ( var i=0 ; i<aoPrevSearch.length ; i++ ) 13459 { 13460 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]), 13461 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive ); 13462 } 13463 13464 /* Custom filtering */ 13465 _fnFilterCustom( oSettings ); 13466 } 13467 else 13468 { 13469 fnSaveFilter( oInput ); 13470 } 13471 13472 /* Tell the draw function we have been filtering */ 13473 oSettings.bFiltered = true; 13474 _fnCallbackFire( oSettings, null, 'search', [oSettings] ); 13475 } 13476 13477 13478 /** 13479 * Apply custom filtering functions 13480 * @param {object} oSettings dataTables settings object 13481 * @memberof DataTable#oApi 13482 */ 13483 function _fnFilterCustom( settings ) 13484 { 13485 var filters = DataTable.ext.search; 13486 var displayRows = settings.aiDisplay; 13487 var row, rowIdx; 13488 13489 for ( var i=0, ien=filters.length ; i<ien ; i++ ) { 13490 var rows = []; 13491 13492 // Loop over each row and see if it should be included 13493 for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) { 13494 rowIdx = displayRows[ j ]; 13495 row = settings.aoData[ rowIdx ]; 13496 13497 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) { 13498 rows.push( rowIdx ); 13499 } 13500 } 13501 13502 // So the array reference doesn't break set the results into the 13503 // existing array 13504 displayRows.length = 0; 13505 $.merge( displayRows, rows ); 13506 } 13507 } 13508 13509 13510 /** 13511 * Filter the table on a per-column basis 13512 * @param {object} oSettings dataTables settings object 13513 * @param {string} sInput string to filter on 13514 * @param {int} iColumn column to filter 13515 * @param {bool} bRegex treat search string as a regular expression or not 13516 * @param {bool} bSmart use smart filtering or not 13517 * @param {bool} bCaseInsensitive Do case insenstive matching or not 13518 * @memberof DataTable#oApi 13519 */ 13520 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive ) 13521 { 13522 if ( searchStr === '' ) { 13523 return; 13524 } 13525 13526 var data; 13527 var out = []; 13528 var display = settings.aiDisplay; 13529 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive ); 13530 13531 for ( var i=0 ; i<display.length ; i++ ) { 13532 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ]; 13533 13534 if ( rpSearch.test( data ) ) { 13535 out.push( display[i] ); 13536 } 13537 } 13538 13539 settings.aiDisplay = out; 13540 } 13541 13542 13543 /** 13544 * Filter the data table based on user input and draw the table 13545 * @param {object} settings dataTables settings object 13546 * @param {string} input string to filter on 13547 * @param {int} force optional - force a research of the master array (1) or not (undefined or 0) 13548 * @param {bool} regex treat as a regular expression or not 13549 * @param {bool} smart perform smart filtering or not 13550 * @param {bool} caseInsensitive Do case insenstive matching or not 13551 * @memberof DataTable#oApi 13552 */ 13553 function _fnFilter( settings, input, force, regex, smart, caseInsensitive ) 13554 { 13555 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive ); 13556 var prevSearch = settings.oPreviousSearch.sSearch; 13557 var displayMaster = settings.aiDisplayMaster; 13558 var display, invalidated, i; 13559 var filtered = []; 13560 13561 // Need to take account of custom filtering functions - always filter 13562 if ( DataTable.ext.search.length !== 0 ) { 13563 force = true; 13564 } 13565 13566 // Check if any of the rows were invalidated 13567 invalidated = _fnFilterData( settings ); 13568 13569 // If the input is blank - we just want the full data set 13570 if ( input.length <= 0 ) { 13571 settings.aiDisplay = displayMaster.slice(); 13572 } 13573 else { 13574 // New search - start from the master array 13575 if ( invalidated || 13576 force || 13577 prevSearch.length > input.length || 13578 input.indexOf(prevSearch) !== 0 || 13579 settings.bSorted // On resort, the display master needs to be 13580 // re-filtered since indexes will have changed 13581 ) { 13582 settings.aiDisplay = displayMaster.slice(); 13583 } 13584 13585 // Search the display array 13586 display = settings.aiDisplay; 13587 13588 for ( i=0 ; i<display.length ; i++ ) { 13589 if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) { 13590 filtered.push( display[i] ); 13591 } 13592 } 13593 13594 settings.aiDisplay = filtered; 13595 } 13596 } 13597 13598 13599 /** 13600 * Build a regular expression object suitable for searching a table 13601 * @param {string} sSearch string to search for 13602 * @param {bool} bRegex treat as a regular expression or not 13603 * @param {bool} bSmart perform smart filtering or not 13604 * @param {bool} bCaseInsensitive Do case insensitive matching or not 13605 * @returns {RegExp} constructed object 13606 * @memberof DataTable#oApi 13607 */ 13608 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive ) 13609 { 13610 search = regex ? 13611 search : 13612 _fnEscapeRegex( search ); 13613 13614 if ( smart ) { 13615 /* For smart filtering we want to allow the search to work regardless of 13616 * word order. We also want double quoted text to be preserved, so word 13617 * order is important - a la google. So this is what we want to 13618 * generate: 13619 * 13620 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$ 13621 */ 13622 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) { 13623 if ( word.charAt(0) === '"' ) { 13624 var m = word.match( /^"(.*)"$/ ); 13625 word = m ? m[1] : word; 13626 } 13627 13628 return word.replace('"', ''); 13629 } ); 13630 13631 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$'; 13632 } 13633 13634 return new RegExp( search, caseInsensitive ? 'i' : '' ); 13635 } 13636 13637 13638 /** 13639 * Escape a string such that it can be used in a regular expression 13640 * @param {string} sVal string to escape 13641 * @returns {string} escaped string 13642 * @memberof DataTable#oApi 13643 */ 13644 var _fnEscapeRegex = DataTable.util.escapeRegex; 13645 13646 var __filter_div = $('<div>')[0]; 13647 var __filter_div_textContent = __filter_div.textContent !== undefined; 13648 13649 // Update the filtering data for each row if needed (by invalidation or first run) 13650 function _fnFilterData ( settings ) 13651 { 13652 var columns = settings.aoColumns; 13653 var column; 13654 var i, j, ien, jen, filterData, cellData, row; 13655 var fomatters = DataTable.ext.type.search; 13656 var wasInvalidated = false; 13657 13658 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 13659 row = settings.aoData[i]; 13660 13661 if ( ! row._aFilterData ) { 13662 filterData = []; 13663 13664 for ( j=0, jen=columns.length ; j<jen ; j++ ) { 13665 column = columns[j]; 13666 13667 if ( column.bSearchable ) { 13668 cellData = _fnGetCellData( settings, i, j, 'filter' ); 13669 13670 if ( fomatters[ column.sType ] ) { 13671 cellData = fomatters[ column.sType ]( cellData ); 13672 } 13673 13674 // Search in DataTables 1.10 is string based. In 1.11 this 13675 // should be altered to also allow strict type checking. 13676 if ( cellData === null ) { 13677 cellData = ''; 13678 } 13679 13680 if ( typeof cellData !== 'string' && cellData.toString ) { 13681 cellData = cellData.toString(); 13682 } 13683 } 13684 else { 13685 cellData = ''; 13686 } 13687 13688 // If it looks like there is an HTML entity in the string, 13689 // attempt to decode it so sorting works as expected. Note that 13690 // we could use a single line of jQuery to do this, but the DOM 13691 // method used here is much faster http://jsperf.com/html-decode 13692 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) { 13693 __filter_div.innerHTML = cellData; 13694 cellData = __filter_div_textContent ? 13695 __filter_div.textContent : 13696 __filter_div.innerText; 13697 } 13698 13699 if ( cellData.replace ) { 13700 cellData = cellData.replace(/[\r\n]/g, ''); 13701 } 13702 13703 filterData.push( cellData ); 13704 } 13705 13706 row._aFilterData = filterData; 13707 row._sFilterRow = filterData.join(' '); 13708 wasInvalidated = true; 13709 } 13710 } 13711 13712 return wasInvalidated; 13713 } 13714 13715 13716 /** 13717 * Convert from the internal Hungarian notation to camelCase for external 13718 * interaction 13719 * @param {object} obj Object to convert 13720 * @returns {object} Inverted object 13721 * @memberof DataTable#oApi 13722 */ 13723 function _fnSearchToCamel ( obj ) 13724 { 13725 return { 13726 search: obj.sSearch, 13727 smart: obj.bSmart, 13728 regex: obj.bRegex, 13729 caseInsensitive: obj.bCaseInsensitive 13730 }; 13731 } 13732 13733 13734 13735 /** 13736 * Convert from camelCase notation to the internal Hungarian. We could use the 13737 * Hungarian convert function here, but this is cleaner 13738 * @param {object} obj Object to convert 13739 * @returns {object} Inverted object 13740 * @memberof DataTable#oApi 13741 */ 13742 function _fnSearchToHung ( obj ) 13743 { 13744 return { 13745 sSearch: obj.search, 13746 bSmart: obj.smart, 13747 bRegex: obj.regex, 13748 bCaseInsensitive: obj.caseInsensitive 13749 }; 13750 } 13751 13752 /** 13753 * Generate the node required for the info display 13754 * @param {object} oSettings dataTables settings object 13755 * @returns {node} Information element 13756 * @memberof DataTable#oApi 13757 */ 13758 function _fnFeatureHtmlInfo ( settings ) 13759 { 13760 var 13761 tid = settings.sTableId, 13762 nodes = settings.aanFeatures.i, 13763 n = $('<div/>', { 13764 'class': settings.oClasses.sInfo, 13765 'id': ! nodes ? tid+'_info' : null 13766 } ); 13767 13768 if ( ! nodes ) { 13769 // Update display on each draw 13770 settings.aoDrawCallback.push( { 13771 "fn": _fnUpdateInfo, 13772 "sName": "information" 13773 } ); 13774 13775 n 13776 .attr( 'role', 'status' ) 13777 .attr( 'aria-live', 'polite' ); 13778 13779 // Table is described by our info div 13780 $(settings.nTable).attr( 'aria-describedby', tid+'_info' ); 13781 } 13782 13783 return n[0]; 13784 } 13785 13786 13787 /** 13788 * Update the information elements in the display 13789 * @param {object} settings dataTables settings object 13790 * @memberof DataTable#oApi 13791 */ 13792 function _fnUpdateInfo ( settings ) 13793 { 13794 /* Show information about the table */ 13795 var nodes = settings.aanFeatures.i; 13796 if ( nodes.length === 0 ) { 13797 return; 13798 } 13799 13800 var 13801 lang = settings.oLanguage, 13802 start = settings._iDisplayStart+1, 13803 end = settings.fnDisplayEnd(), 13804 max = settings.fnRecordsTotal(), 13805 total = settings.fnRecordsDisplay(), 13806 out = total ? 13807 lang.sInfo : 13808 lang.sInfoEmpty; 13809 13810 if ( total !== max ) { 13811 /* Record set after filtering */ 13812 out += ' ' + lang.sInfoFiltered; 13813 } 13814 13815 // Convert the macros 13816 out += lang.sInfoPostFix; 13817 out = _fnInfoMacros( settings, out ); 13818 13819 var callback = lang.fnInfoCallback; 13820 if ( callback !== null ) { 13821 out = callback.call( settings.oInstance, 13822 settings, start, end, max, total, out 13823 ); 13824 } 13825 13826 $(nodes).html( out ); 13827 } 13828 13829 13830 function _fnInfoMacros ( settings, str ) 13831 { 13832 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only 13833 // internally 13834 var 13835 formatter = settings.fnFormatNumber, 13836 start = settings._iDisplayStart+1, 13837 len = settings._iDisplayLength, 13838 vis = settings.fnRecordsDisplay(), 13839 all = len === -1; 13840 13841 return str. 13842 replace(/_START_/g, formatter.call( settings, start ) ). 13843 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ). 13844 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ). 13845 replace(/_TOTAL_/g, formatter.call( settings, vis ) ). 13846 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ). 13847 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ); 13848 } 13849 13850 13851 13852 /** 13853 * Draw the table for the first time, adding all required features 13854 * @param {object} settings dataTables settings object 13855 * @memberof DataTable#oApi 13856 */ 13857 function _fnInitialise ( settings ) 13858 { 13859 var i, iLen, iAjaxStart=settings.iInitDisplayStart; 13860 var columns = settings.aoColumns, column; 13861 var features = settings.oFeatures; 13862 var deferLoading = settings.bDeferLoading; // value modified by the draw 13863 13864 /* Ensure that the table data is fully initialised */ 13865 if ( ! settings.bInitialised ) { 13866 setTimeout( function(){ _fnInitialise( settings ); }, 200 ); 13867 return; 13868 } 13869 13870 /* Show the display HTML options */ 13871 _fnAddOptionsHtml( settings ); 13872 13873 /* Build and draw the header / footer for the table */ 13874 _fnBuildHead( settings ); 13875 _fnDrawHead( settings, settings.aoHeader ); 13876 _fnDrawHead( settings, settings.aoFooter ); 13877 13878 /* Okay to show that something is going on now */ 13879 _fnProcessingDisplay( settings, true ); 13880 13881 /* Calculate sizes for columns */ 13882 if ( features.bAutoWidth ) { 13883 _fnCalculateColumnWidths( settings ); 13884 } 13885 13886 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) { 13887 column = columns[i]; 13888 13889 if ( column.sWidth ) { 13890 column.nTh.style.width = _fnStringToCss( column.sWidth ); 13891 } 13892 } 13893 13894 _fnCallbackFire( settings, null, 'preInit', [settings] ); 13895 13896 // If there is default sorting required - let's do it. The sort function 13897 // will do the drawing for us. Otherwise we draw the table regardless of the 13898 // Ajax source - this allows the table to look initialised for Ajax sourcing 13899 // data (show 'loading' message possibly) 13900 _fnReDraw( settings ); 13901 13902 // Server-side processing init complete is done by _fnAjaxUpdateDraw 13903 var dataSrc = _fnDataSource( settings ); 13904 if ( dataSrc != 'ssp' || deferLoading ) { 13905 // if there is an ajax source load the data 13906 if ( dataSrc == 'ajax' ) { 13907 _fnBuildAjax( settings, [], function(json) { 13908 var aData = _fnAjaxDataSrc( settings, json ); 13909 13910 // Got the data - add it to the table 13911 for ( i=0 ; i<aData.length ; i++ ) { 13912 _fnAddData( settings, aData[i] ); 13913 } 13914 13915 // Reset the init display for cookie saving. We've already done 13916 // a filter, and therefore cleared it before. So we need to make 13917 // it appear 'fresh' 13918 settings.iInitDisplayStart = iAjaxStart; 13919 13920 _fnReDraw( settings ); 13921 13922 _fnProcessingDisplay( settings, false ); 13923 _fnInitComplete( settings, json ); 13924 }, settings ); 13925 } 13926 else { 13927 _fnProcessingDisplay( settings, false ); 13928 _fnInitComplete( settings ); 13929 } 13930 } 13931 } 13932 13933 13934 /** 13935 * Draw the table for the first time, adding all required features 13936 * @param {object} oSettings dataTables settings object 13937 * @param {object} [json] JSON from the server that completed the table, if using Ajax source 13938 * with client-side processing (optional) 13939 * @memberof DataTable#oApi 13940 */ 13941 function _fnInitComplete ( settings, json ) 13942 { 13943 settings._bInitComplete = true; 13944 13945 // When data was added after the initialisation (data or Ajax) we need to 13946 // calculate the column sizing 13947 if ( json || settings.oInit.aaData ) { 13948 _fnAdjustColumnSizing( settings ); 13949 } 13950 13951 _fnCallbackFire( settings, null, 'plugin-init', [settings, json] ); 13952 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] ); 13953 } 13954 13955 13956 function _fnLengthChange ( settings, val ) 13957 { 13958 var len = parseInt( val, 10 ); 13959 settings._iDisplayLength = len; 13960 13961 _fnLengthOverflow( settings ); 13962 13963 // Fire length change event 13964 _fnCallbackFire( settings, null, 'length', [settings, len] ); 13965 } 13966 13967 13968 /** 13969 * Generate the node required for user display length changing 13970 * @param {object} settings dataTables settings object 13971 * @returns {node} Display length feature node 13972 * @memberof DataTable#oApi 13973 */ 13974 function _fnFeatureHtmlLength ( settings ) 13975 { 13976 var 13977 classes = settings.oClasses, 13978 tableId = settings.sTableId, 13979 menu = settings.aLengthMenu, 13980 d2 = $.isArray( menu[0] ), 13981 lengths = d2 ? menu[0] : menu, 13982 language = d2 ? menu[1] : menu; 13983 13984 var select = $('<select/>', { 13985 'name': tableId+'_length', 13986 'aria-controls': tableId, 13987 'class': classes.sLengthSelect 13988 } ); 13989 13990 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) { 13991 select[0][ i ] = new Option( 13992 typeof language[i] === 'number' ? 13993 settings.fnFormatNumber( language[i] ) : 13994 language[i], 13995 lengths[i] 13996 ); 13997 } 13998 13999 var div = $('<div><label/></div>').addClass( classes.sLength ); 14000 if ( ! settings.aanFeatures.l ) { 14001 div[0].id = tableId+'_length'; 14002 } 14003 14004 div.children().append( 14005 settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML ) 14006 ); 14007 14008 // Can't use `select` variable as user might provide their own and the 14009 // reference is broken by the use of outerHTML 14010 $('select', div) 14011 .val( settings._iDisplayLength ) 14012 .on( 'change.DT', function(e) { 14013 _fnLengthChange( settings, $(this).val() ); 14014 _fnDraw( settings ); 14015 } ); 14016 14017 // Update node value whenever anything changes the table's length 14018 $(settings.nTable).on( 'length.dt.DT', function (e, s, len) { 14019 if ( settings === s ) { 14020 $('select', div).val( len ); 14021 } 14022 } ); 14023 14024 return div[0]; 14025 } 14026 14027 14028 14029 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 14030 * Note that most of the paging logic is done in 14031 * DataTable.ext.pager 14032 */ 14033 14034 /** 14035 * Generate the node required for default pagination 14036 * @param {object} oSettings dataTables settings object 14037 * @returns {node} Pagination feature node 14038 * @memberof DataTable#oApi 14039 */ 14040 function _fnFeatureHtmlPaginate ( settings ) 14041 { 14042 var 14043 type = settings.sPaginationType, 14044 plugin = DataTable.ext.pager[ type ], 14045 modern = typeof plugin === 'function', 14046 redraw = function( settings ) { 14047 _fnDraw( settings ); 14048 }, 14049 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0], 14050 features = settings.aanFeatures; 14051 14052 if ( ! modern ) { 14053 plugin.fnInit( settings, node, redraw ); 14054 } 14055 14056 /* Add a draw callback for the pagination on first instance, to update the paging display */ 14057 if ( ! features.p ) 14058 { 14059 node.id = settings.sTableId+'_paginate'; 14060 14061 settings.aoDrawCallback.push( { 14062 "fn": function( settings ) { 14063 if ( modern ) { 14064 var 14065 start = settings._iDisplayStart, 14066 len = settings._iDisplayLength, 14067 visRecords = settings.fnRecordsDisplay(), 14068 all = len === -1, 14069 page = all ? 0 : Math.ceil( start / len ), 14070 pages = all ? 1 : Math.ceil( visRecords / len ), 14071 buttons = plugin(page, pages), 14072 i, ien; 14073 14074 for ( i=0, ien=features.p.length ; i<ien ; i++ ) { 14075 _fnRenderer( settings, 'pageButton' )( 14076 settings, features.p[i], i, buttons, page, pages 14077 ); 14078 } 14079 } 14080 else { 14081 plugin.fnUpdate( settings, redraw ); 14082 } 14083 }, 14084 "sName": "pagination" 14085 } ); 14086 } 14087 14088 return node; 14089 } 14090 14091 14092 /** 14093 * Alter the display settings to change the page 14094 * @param {object} settings DataTables settings object 14095 * @param {string|int} action Paging action to take: "first", "previous", 14096 * "next" or "last" or page number to jump to (integer) 14097 * @param [bool] redraw Automatically draw the update or not 14098 * @returns {bool} true page has changed, false - no change 14099 * @memberof DataTable#oApi 14100 */ 14101 function _fnPageChange ( settings, action, redraw ) 14102 { 14103 var 14104 start = settings._iDisplayStart, 14105 len = settings._iDisplayLength, 14106 records = settings.fnRecordsDisplay(); 14107 14108 if ( records === 0 || len === -1 ) 14109 { 14110 start = 0; 14111 } 14112 else if ( typeof action === "number" ) 14113 { 14114 start = action * len; 14115 14116 if ( start > records ) 14117 { 14118 start = 0; 14119 } 14120 } 14121 else if ( action == "first" ) 14122 { 14123 start = 0; 14124 } 14125 else if ( action == "previous" ) 14126 { 14127 start = len >= 0 ? 14128 start - len : 14129 0; 14130 14131 if ( start < 0 ) 14132 { 14133 start = 0; 14134 } 14135 } 14136 else if ( action == "next" ) 14137 { 14138 if ( start + len < records ) 14139 { 14140 start += len; 14141 } 14142 } 14143 else if ( action == "last" ) 14144 { 14145 start = Math.floor( (records-1) / len) * len; 14146 } 14147 else 14148 { 14149 _fnLog( settings, 0, "Unknown paging action: "+action, 5 ); 14150 } 14151 14152 var changed = settings._iDisplayStart !== start; 14153 settings._iDisplayStart = start; 14154 14155 if ( changed ) { 14156 _fnCallbackFire( settings, null, 'page', [settings] ); 14157 14158 if ( redraw ) { 14159 _fnDraw( settings ); 14160 } 14161 } 14162 14163 return changed; 14164 } 14165 14166 14167 14168 /** 14169 * Generate the node required for the processing node 14170 * @param {object} settings dataTables settings object 14171 * @returns {node} Processing element 14172 * @memberof DataTable#oApi 14173 */ 14174 function _fnFeatureHtmlProcessing ( settings ) 14175 { 14176 return $('<div/>', { 14177 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null, 14178 'class': settings.oClasses.sProcessing 14179 } ) 14180 .html( settings.oLanguage.sProcessing ) 14181 .insertBefore( settings.nTable )[0]; 14182 } 14183 14184 14185 /** 14186 * Display or hide the processing indicator 14187 * @param {object} settings dataTables settings object 14188 * @param {bool} show Show the processing indicator (true) or not (false) 14189 * @memberof DataTable#oApi 14190 */ 14191 function _fnProcessingDisplay ( settings, show ) 14192 { 14193 if ( settings.oFeatures.bProcessing ) { 14194 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' ); 14195 } 14196 14197 _fnCallbackFire( settings, null, 'processing', [settings, show] ); 14198 } 14199 14200 /** 14201 * Add any control elements for the table - specifically scrolling 14202 * @param {object} settings dataTables settings object 14203 * @returns {node} Node to add to the DOM 14204 * @memberof DataTable#oApi 14205 */ 14206 function _fnFeatureHtmlTable ( settings ) 14207 { 14208 var table = $(settings.nTable); 14209 14210 // Add the ARIA grid role to the table 14211 table.attr( 'role', 'grid' ); 14212 14213 // Scrolling from here on in 14214 var scroll = settings.oScroll; 14215 14216 if ( scroll.sX === '' && scroll.sY === '' ) { 14217 return settings.nTable; 14218 } 14219 14220 var scrollX = scroll.sX; 14221 var scrollY = scroll.sY; 14222 var classes = settings.oClasses; 14223 var caption = table.children('caption'); 14224 var captionSide = caption.length ? caption[0]._captionSide : null; 14225 var headerClone = $( table[0].cloneNode(false) ); 14226 var footerClone = $( table[0].cloneNode(false) ); 14227 var footer = table.children('tfoot'); 14228 var _div = '<div/>'; 14229 var size = function ( s ) { 14230 return !s ? null : _fnStringToCss( s ); 14231 }; 14232 14233 if ( ! footer.length ) { 14234 footer = null; 14235 } 14236 14237 /* 14238 * The HTML structure that we want to generate in this function is: 14239 * div - scroller 14240 * div - scroll head 14241 * div - scroll head inner 14242 * table - scroll head table 14243 * thead - thead 14244 * div - scroll body 14245 * table - table (master table) 14246 * thead - thead clone for sizing 14247 * tbody - tbody 14248 * div - scroll foot 14249 * div - scroll foot inner 14250 * table - scroll foot table 14251 * tfoot - tfoot 14252 */ 14253 var scroller = $( _div, { 'class': classes.sScrollWrapper } ) 14254 .append( 14255 $(_div, { 'class': classes.sScrollHead } ) 14256 .css( { 14257 overflow: 'hidden', 14258 position: 'relative', 14259 border: 0, 14260 width: scrollX ? size(scrollX) : '100%' 14261 } ) 14262 .append( 14263 $(_div, { 'class': classes.sScrollHeadInner } ) 14264 .css( { 14265 'box-sizing': 'content-box', 14266 width: scroll.sXInner || '100%' 14267 } ) 14268 .append( 14269 headerClone 14270 .removeAttr('id') 14271 .css( 'margin-left', 0 ) 14272 .append( captionSide === 'top' ? caption : null ) 14273 .append( 14274 table.children('thead') 14275 ) 14276 ) 14277 ) 14278 ) 14279 .append( 14280 $(_div, { 'class': classes.sScrollBody } ) 14281 .css( { 14282 position: 'relative', 14283 overflow: 'auto', 14284 width: size( scrollX ) 14285 } ) 14286 .append( table ) 14287 ); 14288 14289 if ( footer ) { 14290 scroller.append( 14291 $(_div, { 'class': classes.sScrollFoot } ) 14292 .css( { 14293 overflow: 'hidden', 14294 border: 0, 14295 width: scrollX ? size(scrollX) : '100%' 14296 } ) 14297 .append( 14298 $(_div, { 'class': classes.sScrollFootInner } ) 14299 .append( 14300 footerClone 14301 .removeAttr('id') 14302 .css( 'margin-left', 0 ) 14303 .append( captionSide === 'bottom' ? caption : null ) 14304 .append( 14305 table.children('tfoot') 14306 ) 14307 ) 14308 ) 14309 ); 14310 } 14311 14312 var children = scroller.children(); 14313 var scrollHead = children[0]; 14314 var scrollBody = children[1]; 14315 var scrollFoot = footer ? children[2] : null; 14316 14317 // When the body is scrolled, then we also want to scroll the headers 14318 if ( scrollX ) { 14319 $(scrollBody).on( 'scroll.DT', function (e) { 14320 var scrollLeft = this.scrollLeft; 14321 14322 scrollHead.scrollLeft = scrollLeft; 14323 14324 if ( footer ) { 14325 scrollFoot.scrollLeft = scrollLeft; 14326 } 14327 } ); 14328 } 14329 14330 $(scrollBody).css( 14331 scrollY && scroll.bCollapse ? 'max-height' : 'height', 14332 scrollY 14333 ); 14334 14335 settings.nScrollHead = scrollHead; 14336 settings.nScrollBody = scrollBody; 14337 settings.nScrollFoot = scrollFoot; 14338 14339 // On redraw - align columns 14340 settings.aoDrawCallback.push( { 14341 "fn": _fnScrollDraw, 14342 "sName": "scrolling" 14343 } ); 14344 14345 return scroller[0]; 14346 } 14347 14348 14349 14350 /** 14351 * Update the header, footer and body tables for resizing - i.e. column 14352 * alignment. 14353 * 14354 * Welcome to the most horrible function DataTables. The process that this 14355 * function follows is basically: 14356 * 1. Re-create the table inside the scrolling div 14357 * 2. Take live measurements from the DOM 14358 * 3. Apply the measurements to align the columns 14359 * 4. Clean up 14360 * 14361 * @param {object} settings dataTables settings object 14362 * @memberof DataTable#oApi 14363 */ 14364 function _fnScrollDraw ( settings ) 14365 { 14366 // Given that this is such a monster function, a lot of variables are use 14367 // to try and keep the minimised size as small as possible 14368 var 14369 scroll = settings.oScroll, 14370 scrollX = scroll.sX, 14371 scrollXInner = scroll.sXInner, 14372 scrollY = scroll.sY, 14373 barWidth = scroll.iBarWidth, 14374 divHeader = $(settings.nScrollHead); 14375 14376 // OVERRIDE 14377 // prevent error if divHeader still not existing 14378 // to let next js run smoothly 14379 if ('undefined' == typeof divHeader[0]) 14380 return; 14381 14382 var 14383 divHeaderStyle = divHeader[0].style, 14384 divHeaderInner = divHeader.children('div'), 14385 divHeaderInnerStyle = divHeaderInner[0].style, 14386 divHeaderTable = divHeaderInner.children('table'), 14387 divBodyEl = settings.nScrollBody, 14388 divBody = $(divBodyEl), 14389 divBodyStyle = divBodyEl.style, 14390 divFooter = $(settings.nScrollFoot), 14391 divFooterInner = divFooter.children('div'), 14392 divFooterTable = divFooterInner.children('table'), 14393 header = $(settings.nTHead), 14394 table = $(settings.nTable), 14395 tableEl = table[0], 14396 tableStyle = tableEl.style, 14397 footer = settings.nTFoot ? $(settings.nTFoot) : null, 14398 browser = settings.oBrowser, 14399 ie67 = browser.bScrollOversize, 14400 dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ), 14401 headerTrgEls, footerTrgEls, 14402 headerSrcEls, footerSrcEls, 14403 headerCopy, footerCopy, 14404 headerWidths=[], footerWidths=[], 14405 headerContent=[], footerContent=[], 14406 idx, correction, sanityWidth, 14407 zeroOut = function(nSizer) { 14408 var style = nSizer.style; 14409 style.paddingTop = "0"; 14410 style.paddingBottom = "0"; 14411 style.borderTopWidth = "0"; 14412 style.borderBottomWidth = "0"; 14413 style.height = 0; 14414 }; 14415 14416 // If the scrollbar visibility has changed from the last draw, we need to 14417 // adjust the column sizes as the table width will have changed to account 14418 // for the scrollbar 14419 var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight; 14420 14421 if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) { 14422 settings.scrollBarVis = scrollBarVis; 14423 _fnAdjustColumnSizing( settings ); 14424 return; // adjust column sizing will call this function again 14425 } 14426 else { 14427 settings.scrollBarVis = scrollBarVis; 14428 } 14429 14430 /* 14431 * 1. Re-create the table inside the scrolling div 14432 */ 14433 14434 // Remove the old minimised thead and tfoot elements in the inner table 14435 table.children('thead, tfoot').remove(); 14436 14437 if ( footer ) { 14438 footerCopy = footer.clone().prependTo( table ); 14439 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized 14440 footerSrcEls = footerCopy.find('tr'); 14441 } 14442 14443 // Clone the current header and footer elements and then place it into the inner table 14444 headerCopy = header.clone().prependTo( table ); 14445 headerTrgEls = header.find('tr'); // original header is in its own table 14446 headerSrcEls = headerCopy.find('tr'); 14447 headerCopy.find('th, td').removeAttr('tabindex'); 14448 14449 14450 /* 14451 * 2. Take live measurements from the DOM - do not alter the DOM itself! 14452 */ 14453 14454 // Remove old sizing and apply the calculated column widths 14455 // Get the unique column headers in the newly created (cloned) header. We want to apply the 14456 // calculated sizes to this header 14457 if ( ! scrollX ) 14458 { 14459 divBodyStyle.width = '100%'; 14460 divHeader[0].style.width = '100%'; 14461 } 14462 14463 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) { 14464 idx = _fnVisibleToColumnIndex( settings, i ); 14465 el.style.width = settings.aoColumns[idx].sWidth; 14466 } ); 14467 14468 if ( footer ) { 14469 _fnApplyToChildren( function(n) { 14470 n.style.width = ""; 14471 }, footerSrcEls ); 14472 } 14473 14474 // Size the table as a whole 14475 sanityWidth = table.outerWidth(); 14476 if ( scrollX === "" ) { 14477 // No x scrolling 14478 tableStyle.width = "100%"; 14479 14480 // IE7 will make the width of the table when 100% include the scrollbar 14481 // - which is shouldn't. When there is a scrollbar we need to take this 14482 // into account. 14483 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight || 14484 divBody.css('overflow-y') == "scroll") 14485 ) { 14486 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth); 14487 } 14488 14489 // Recalculate the sanity width 14490 sanityWidth = table.outerWidth(); 14491 } 14492 else if ( scrollXInner !== "" ) { 14493 // legacy x scroll inner has been given - use it 14494 tableStyle.width = _fnStringToCss(scrollXInner); 14495 14496 // Recalculate the sanity width 14497 sanityWidth = table.outerWidth(); 14498 } 14499 14500 // Hidden header should have zero height, so remove padding and borders. Then 14501 // set the width based on the real headers 14502 14503 // Apply all styles in one pass 14504 _fnApplyToChildren( zeroOut, headerSrcEls ); 14505 14506 // Read all widths in next pass 14507 _fnApplyToChildren( function(nSizer) { 14508 headerContent.push( nSizer.innerHTML ); 14509 headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); 14510 }, headerSrcEls ); 14511 14512 // Apply all widths in final pass 14513 _fnApplyToChildren( function(nToSize, i) { 14514 // Only apply widths to the DataTables detected header cells - this 14515 // prevents complex headers from having contradictory sizes applied 14516 if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) { 14517 nToSize.style.width = headerWidths[i]; 14518 } 14519 }, headerTrgEls ); 14520 14521 $(headerSrcEls).height(0); 14522 14523 /* Same again with the footer if we have one */ 14524 if ( footer ) 14525 { 14526 _fnApplyToChildren( zeroOut, footerSrcEls ); 14527 14528 _fnApplyToChildren( function(nSizer) { 14529 footerContent.push( nSizer.innerHTML ); 14530 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); 14531 }, footerSrcEls ); 14532 14533 _fnApplyToChildren( function(nToSize, i) { 14534 nToSize.style.width = footerWidths[i]; 14535 }, footerTrgEls ); 14536 14537 $(footerSrcEls).height(0); 14538 } 14539 14540 14541 /* 14542 * 3. Apply the measurements 14543 */ 14544 14545 // "Hide" the header and footer that we used for the sizing. We need to keep 14546 // the content of the cell so that the width applied to the header and body 14547 // both match, but we want to hide it completely. We want to also fix their 14548 // width to what they currently are 14549 _fnApplyToChildren( function(nSizer, i) { 14550 nSizer.innerHTML = '<div class="dataTables_sizing">'+headerContent[i]+'</div>'; 14551 nSizer.childNodes[0].style.height = "0"; 14552 nSizer.childNodes[0].style.overflow = "hidden"; 14553 nSizer.style.width = headerWidths[i]; 14554 }, headerSrcEls ); 14555 14556 if ( footer ) 14557 { 14558 _fnApplyToChildren( function(nSizer, i) { 14559 nSizer.innerHTML = '<div class="dataTables_sizing">'+footerContent[i]+'</div>'; 14560 nSizer.childNodes[0].style.height = "0"; 14561 nSizer.childNodes[0].style.overflow = "hidden"; 14562 nSizer.style.width = footerWidths[i]; 14563 }, footerSrcEls ); 14564 } 14565 14566 // Sanity check that the table is of a sensible width. If not then we are going to get 14567 // misalignment - try to prevent this by not allowing the table to shrink below its min width 14568 if ( table.outerWidth() < sanityWidth ) 14569 { 14570 // The min width depends upon if we have a vertical scrollbar visible or not */ 14571 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight || 14572 divBody.css('overflow-y') == "scroll")) ? 14573 sanityWidth+barWidth : 14574 sanityWidth; 14575 14576 // IE6/7 are a law unto themselves... 14577 if ( ie67 && (divBodyEl.scrollHeight > 14578 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll") 14579 ) { 14580 tableStyle.width = _fnStringToCss( correction-barWidth ); 14581 } 14582 14583 // And give the user a warning that we've stopped the table getting too small 14584 if ( scrollX === "" || scrollXInner !== "" ) { 14585 _fnLog( settings, 1, 'Possible column misalignment', 6 ); 14586 } 14587 } 14588 else 14589 { 14590 correction = '100%'; 14591 } 14592 14593 // Apply to the container elements 14594 divBodyStyle.width = _fnStringToCss( correction ); 14595 divHeaderStyle.width = _fnStringToCss( correction ); 14596 14597 if ( footer ) { 14598 settings.nScrollFoot.style.width = _fnStringToCss( correction ); 14599 } 14600 14601 14602 /* 14603 * 4. Clean up 14604 */ 14605 if ( ! scrollY ) { 14606 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting 14607 * the scrollbar height from the visible display, rather than adding it on. We need to 14608 * set the height in order to sort this. Don't want to do it in any other browsers. 14609 */ 14610 if ( ie67 ) { 14611 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth ); 14612 } 14613 } 14614 14615 /* Finally set the width's of the header and footer tables */ 14616 var iOuterWidth = table.outerWidth(); 14617 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth ); 14618 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth ); 14619 14620 // Figure out if there are scrollbar present - if so then we need a the header and footer to 14621 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) 14622 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll"; 14623 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' ); 14624 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px"; 14625 14626 if ( footer ) { 14627 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth ); 14628 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth ); 14629 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px"; 14630 } 14631 14632 // Correct DOM ordering for colgroup - comes before the thead 14633 table.children('colgroup').insertBefore( table.children('thead') ); 14634 14635 /* Adjust the position of the header in case we loose the y-scrollbar */ 14636 divBody.scroll(
vendor: 11,594 bytes, lines 14636-15034
14636); 14637 14638 // If sorting or filtering has occurred, jump the scrolling back to the top 14639 // only if we aren't holding the position 14640 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) { 14641 divBodyEl.scrollTop = 0; 14642 } 14643 } 14644 14645 14646 14647 /** 14648 * Apply a given function to the display child nodes of an element array (typically 14649 * TD children of TR rows 14650 * @param {function} fn Method to apply to the objects 14651 * @param array {nodes} an1 List of elements to look through for display children 14652 * @param array {nodes} an2 Another list (identical structure to the first) - optional 14653 * @memberof DataTable#oApi 14654 */ 14655 function _fnApplyToChildren( fn, an1, an2 ) 14656 { 14657 var index=0, i=0, iLen=an1.length; 14658 var nNode1, nNode2; 14659 14660 while ( i < iLen ) { 14661 nNode1 = an1[i].firstChild; 14662 nNode2 = an2 ? an2[i].firstChild : null; 14663 14664 while ( nNode1 ) { 14665 if ( nNode1.nodeType === 1 ) { 14666 if ( an2 ) { 14667 fn( nNode1, nNode2, index ); 14668 } 14669 else { 14670 fn( nNode1, index ); 14671 } 14672 14673 index++; 14674 } 14675 14676 nNode1 = nNode1.nextSibling; 14677 nNode2 = an2 ? nNode2.nextSibling : null; 14678 } 14679 14680 i++; 14681 } 14682 } 14683 14684 14685 14686 var __re_html_remove = /<.*?>/g; 14687 14688 14689 /** 14690 * Calculate the width of columns for the table 14691 * @param {object} oSettings dataTables settings object 14692 * @memberof DataTable#oApi 14693 */ 14694 function _fnCalculateColumnWidths ( oSettings ) 14695 { 14696 var 14697 table = oSettings.nTable, 14698 columns = oSettings.aoColumns, 14699 scroll = oSettings.oScroll, 14700 scrollY = scroll.sY, 14701 scrollX = scroll.sX, 14702 scrollXInner = scroll.sXInner, 14703 columnCount = columns.length, 14704 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ), 14705 headerCells = $('th', oSettings.nTHead), 14706 tableWidthAttr = table.getAttribute('width'), // from DOM element 14707 tableContainer = table.parentNode, 14708 userInputs = false, 14709 i, column, columnIdx, width, outerWidth, 14710 browser = oSettings.oBrowser, 14711 ie67 = browser.bScrollOversize; 14712 14713 var styleWidth = table.style.width; 14714 if ( styleWidth && styleWidth.indexOf('%') !== -1 ) { 14715 tableWidthAttr = styleWidth; 14716 } 14717 14718 /* Convert any user input sizes into pixel sizes */ 14719 for ( i=0 ; i<visibleColumns.length ; i++ ) { 14720 column = columns[ visibleColumns[i] ]; 14721 14722 if ( column.sWidth !== null ) { 14723 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer ); 14724 14725 userInputs = true; 14726 } 14727 } 14728 14729 /* If the number of columns in the DOM equals the number that we have to 14730 * process in DataTables, then we can use the offsets that are created by 14731 * the web- browser. No custom sizes can be set in order for this to happen, 14732 * nor scrolling used 14733 */ 14734 if ( ie67 || ! userInputs && ! scrollX && ! scrollY && 14735 columnCount == _fnVisbleColumns( oSettings ) && 14736 columnCount == headerCells.length 14737 ) { 14738 for ( i=0 ; i<columnCount ; i++ ) { 14739 var colIdx = _fnVisibleToColumnIndex( oSettings, i ); 14740 14741 if ( colIdx !== null ) { 14742 columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() ); 14743 } 14744 } 14745 } 14746 else 14747 { 14748 // Otherwise construct a single row, worst case, table with the widest 14749 // node in the data, assign any user defined widths, then insert it into 14750 // the DOM and allow the browser to do all the hard work of calculating 14751 // table widths 14752 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table 14753 .css( 'visibility', 'hidden' ) 14754 .removeAttr( 'id' ); 14755 14756 // Clean up the table body 14757 tmpTable.find('tbody tr').remove(); 14758 var tr = $('<tr/>').appendTo( tmpTable.find('tbody') ); 14759 14760 // Clone the table header and footer - we can't use the header / footer 14761 // from the cloned table, since if scrolling is active, the table's 14762 // real header and footer are contained in different table tags 14763 tmpTable.find('thead, tfoot').remove(); 14764 tmpTable 14765 .append( $(oSettings.nTHead).clone() ) 14766 .append( $(oSettings.nTFoot).clone() ); 14767 14768 // Remove any assigned widths from the footer (from scrolling) 14769 tmpTable.find('tfoot th, tfoot td').css('width', ''); 14770 14771 // Apply custom sizing to the cloned header 14772 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] ); 14773 14774 for ( i=0 ; i<visibleColumns.length ; i++ ) { 14775 column = columns[ visibleColumns[i] ]; 14776 14777 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ? 14778 _fnStringToCss( column.sWidthOrig ) : 14779 ''; 14780 14781 // For scrollX we need to force the column width otherwise the 14782 // browser will collapse it. If this width is smaller than the 14783 // width the column requires, then it will have no effect 14784 if ( column.sWidthOrig && scrollX ) { 14785 $( headerCells[i] ).append( $('<div/>').css( { 14786 width: column.sWidthOrig, 14787 margin: 0, 14788 padding: 0, 14789 border: 0, 14790 height: 1 14791 } ) ); 14792 } 14793 } 14794 14795 // Find the widest cell for each column and put it into the table 14796 if ( oSettings.aoData.length ) { 14797 for ( i=0 ; i<visibleColumns.length ; i++ ) { 14798 columnIdx = visibleColumns[i]; 14799 column = columns[ columnIdx ]; 14800 14801 $( _fnGetWidestNode( oSettings, columnIdx ) ) 14802 .clone( false ) 14803 .append( column.sContentPadding ) 14804 .appendTo( tr ); 14805 } 14806 } 14807 14808 // Tidy the temporary table - remove name attributes so there aren't 14809 // duplicated in the dom (radio elements for example) 14810 $('[name]', tmpTable).removeAttr('name'); 14811 14812 // Table has been built, attach to the document so we can work with it. 14813 // A holding element is used, positioned at the top of the container 14814 // with minimal height, so it has no effect on if the container scrolls 14815 // or not. Otherwise it might trigger scrolling when it actually isn't 14816 // needed 14817 var holder = $('<div/>').css( scrollX || scrollY ? 14818 { 14819 position: 'absolute', 14820 top: 0, 14821 left: 0, 14822 height: 1, 14823 right: 0, 14824 overflow: 'hidden' 14825 } : 14826 {} 14827 ) 14828 .append( tmpTable ) 14829 .appendTo( tableContainer ); 14830 14831 // When scrolling (X or Y) we want to set the width of the table as 14832 // appropriate. However, when not scrolling leave the table width as it 14833 // is. This results in slightly different, but I think correct behaviour 14834 if ( scrollX && scrollXInner ) { 14835 tmpTable.width( scrollXInner ); 14836 } 14837 else if ( scrollX ) { 14838 tmpTable.css( 'width', 'auto' ); 14839 tmpTable.removeAttr('width'); 14840 14841 // If there is no width attribute or style, then allow the table to 14842 // collapse 14843 if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) { 14844 tmpTable.width( tableContainer.clientWidth ); 14845 } 14846 } 14847 else if ( scrollY ) { 14848 tmpTable.width( tableContainer.clientWidth ); 14849 } 14850 else if ( tableWidthAttr ) { 14851 tmpTable.width( tableWidthAttr ); 14852 } 14853 14854 // Get the width of each column in the constructed table - we need to 14855 // know the inner width (so it can be assigned to the other table's 14856 // cells) and the outer width so we can calculate the full width of the 14857 // table. This is safe since DataTables requires a unique cell for each 14858 // column, but if ever a header can span multiple columns, this will 14859 // need to be modified. 14860 var total = 0; 14861 for ( i=0 ; i<visibleColumns.length ; i++ ) { 14862 var cell = $(headerCells[i]); 14863 var border = cell.outerWidth() - cell.width(); 14864 14865 // Use getBounding... where possible (not IE8-) because it can give 14866 // sub-pixel accuracy, which we then want to round up! 14867 var bounding = browser.bBounding ? 14868 Math.ceil( headerCells[i].getBoundingClientRect().width ) : 14869 cell.outerWidth(); 14870 14871 // Total is tracked to remove any sub-pixel errors as the outerWidth 14872 // of the table might not equal the total given here (IE!). 14873 total += bounding; 14874 14875 // Width for each column to use 14876 columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border ); 14877 } 14878 14879 table.style.width = _fnStringToCss( total ); 14880 14881 // Finished with the table - ditch it 14882 holder.remove(); 14883 } 14884 14885 // If there is a width attr, we want to attach an event listener which 14886 // allows the table sizing to automatically adjust when the window is 14887 // resized. Use the width attr rather than CSS, since we can't know if the 14888 // CSS is a relative value or absolute - DOM read is always px. 14889 if ( tableWidthAttr ) { 14890 table.style.width = _fnStringToCss( tableWidthAttr ); 14891 } 14892 14893 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) { 14894 var bindResize = function () { 14895 $(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () { 14896 _fnAdjustColumnSizing( oSettings ); 14897 } ) ); 14898 }; 14899 14900 // IE6/7 will crash if we bind a resize event handler on page load. 14901 // To be removed in 1.11 which drops IE6/7 support 14902 if ( ie67 ) { 14903 setTimeout( bindResize, 1000 ); 14904 } 14905 else { 14906 bindResize(); 14907 } 14908 14909 oSettings._reszEvt = true; 14910 } 14911 } 14912 14913 14914 /** 14915 * Throttle the calls to a function. Arguments and context are maintained for 14916 * the throttled function 14917 * @param {function} fn Function to be called 14918 * @param {int} [freq=200] call frequency in mS 14919 * @returns {function} wrapped function 14920 * @memberof DataTable#oApi 14921 */ 14922 var _fnThrottle = DataTable.util.throttle; 14923 14924 14925 /** 14926 * Convert a CSS unit width to pixels (e.g. 2em) 14927 * @param {string} width width to be converted 14928 * @param {node} parent parent to get the with for (required for relative widths) - optional 14929 * @returns {int} width in pixels 14930 * @memberof DataTable#oApi 14931 */ 14932 function _fnConvertToWidth ( width, parent ) 14933 { 14934 if ( ! width ) { 14935 return 0; 14936 } 14937 14938 var n = $('<div/>') 14939 .css( 'width', _fnStringToCss( width ) ) 14940 .appendTo( parent || document.body ); 14941 14942 var val = n[0].offsetWidth; 14943 n.remove(); 14944 14945 return val; 14946 } 14947 14948 14949 /** 14950 * Get the widest node 14951 * @param {object} settings dataTables settings object 14952 * @param {int} colIdx column of interest 14953 * @returns {node} widest table node 14954 * @memberof DataTable#oApi 14955 */ 14956 function _fnGetWidestNode( settings, colIdx ) 14957 { 14958 var idx = _fnGetMaxLenString( settings, colIdx ); 14959 if ( idx < 0 ) { 14960 return null; 14961 } 14962 14963 var data = settings.aoData[ idx ]; 14964 return ! data.nTr ? // Might not have been created when deferred rendering 14965 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] : 14966 data.anCells[ colIdx ]; 14967 } 14968 14969 14970 /** 14971 * Get the maximum strlen for each data column 14972 * @param {object} settings dataTables settings object 14973 * @param {int} colIdx column of interest 14974 * @returns {string} max string length for each column 14975 * @memberof DataTable#oApi 14976 */ 14977 function _fnGetMaxLenString( settings, colIdx ) 14978 { 14979 var s, max=-1, maxIdx = -1; 14980 14981 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 14982 s = _fnGetCellData( settings, i, colIdx, 'display' )+''; 14983 s = s.replace( __re_html_remove, '' ); 14984 s = s.replace( / /g, ' ' ); 14985 14986 if ( s.length > max ) { 14987 max = s.length; 14988 maxIdx = i; 14989 } 14990 } 14991 14992 return maxIdx; 14993 } 14994 14995 14996 /** 14997 * Append a CSS unit (only if required) to a string 14998 * @param {string} value to css-ify 14999 * @returns {string} value with css unit 15000 * @memberof DataTable#oApi 15001 */ 15002 function _fnStringToCss( s ) 15003 { 15004 if ( s === null ) { 15005 return '0px'; 15006 } 15007 15008 if ( typeof s == 'number' ) { 15009 return s < 0 ? 15010 '0px' : 15011 s+'px'; 15012 } 15013 15014 // Check it has a unit character already 15015 return s.match(/\d$/) ? 15016 s+'px' : 15017 s; 15018 } 15019 15020 15021 15022 function _fnSortFlatten ( settings ) 15023 { 15024 var 15025 i, iLen, k, kLen, 15026 aSort = [], 15027 aiOrig = [], 15028 aoColumns = settings.aoColumns, 15029 aDataSort, iCol, sType, srcCol, 15030 fixed = settings.aaSortingFixed, 15031 fixedObj = $.isPlainObject( fixed ), 15032 nestedSort = [], 15033 add = function ( a ) { 15034 if ( a.length && !
vendor: 39,758 bytes, lines 15034-16555
15034$.isArray( a[0] ) ) { 15035 // 1D array 15036 nestedSort.push( a ); 15037 } 15038 else { 15039 // 2D array 15040 $.merge( nestedSort, a ); 15041 } 15042 }; 15043 15044 // Build the sort array, with pre-fix and post-fix options if they have been 15045 // specified 15046 if ( $.isArray( fixed ) ) { 15047 add( fixed ); 15048 } 15049 15050 if ( fixedObj && fixed.pre ) { 15051 add( fixed.pre ); 15052 } 15053 15054 add( settings.aaSorting ); 15055 15056 if (fixedObj && fixed.post ) { 15057 add( fixed.post ); 15058 } 15059 15060 for ( i=0 ; i<nestedSort.length ; i++ ) 15061 { 15062 srcCol = nestedSort[i][0]; 15063 aDataSort = aoColumns[ srcCol ].aDataSort; 15064 15065 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ ) 15066 { 15067 iCol = aDataSort[k]; 15068 sType = aoColumns[ iCol ].sType || 'string'; 15069 15070 if ( nestedSort[i]._idx === undefined ) { 15071 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting ); 15072 } 15073 15074 aSort.push( { 15075 src: srcCol, 15076 col: iCol, 15077 dir: nestedSort[i][1], 15078 index: nestedSort[i]._idx, 15079 type: sType, 15080 formatter: DataTable.ext.type.order[ sType+"-pre" ] 15081 } ); 15082 } 15083 } 15084 15085 return aSort; 15086 } 15087 15088 /** 15089 * Change the order of the table 15090 * @param {object} oSettings dataTables settings object 15091 * @memberof DataTable#oApi 15092 * @todo This really needs split up! 15093 */ 15094 function _fnSort ( oSettings ) 15095 { 15096 var 15097 i, ien, iLen, j, jLen, k, kLen, 15098 sDataType, nTh, 15099 aiOrig = [], 15100 oExtSort = DataTable.ext.type.order, 15101 aoData = oSettings.aoData, 15102 aoColumns = oSettings.aoColumns, 15103 aDataSort, data, iCol, sType, oSort, 15104 formatters = 0, 15105 sortCol, 15106 displayMaster = oSettings.aiDisplayMaster, 15107 aSort; 15108 15109 // Resolve any column types that are unknown due to addition or invalidation 15110 // @todo Can this be moved into a 'data-ready' handler which is called when 15111 // data is going to be used in the table? 15112 _fnColumnTypes( oSettings ); 15113 15114 aSort = _fnSortFlatten( oSettings ); 15115 15116 for ( i=0, ien=aSort.length ; i<ien ; i++ ) { 15117 sortCol = aSort[i]; 15118 15119 // Track if we can use the fast sort algorithm 15120 if ( sortCol.formatter ) { 15121 formatters++; 15122 } 15123 15124 // Load the data needed for the sort, for each cell 15125 _fnSortData( oSettings, sortCol.col ); 15126 } 15127 15128 /* No sorting required if server-side or no sorting array */ 15129 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 ) 15130 { 15131 // Create a value - key array of the current row positions such that we can use their 15132 // current position during the sort, if values match, in order to perform stable sorting 15133 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) { 15134 aiOrig[ displayMaster[i] ] = i; 15135 } 15136 15137 /* Do the sort - here we want multi-column sorting based on a given data source (column) 15138 * and sorting function (from oSort) in a certain direction. It's reasonably complex to 15139 * follow on it's own, but this is what we want (example two column sorting): 15140 * fnLocalSorting = function(a,b){ 15141 * var iTest; 15142 * iTest = oSort['string-asc']('data11', 'data12'); 15143 * if (iTest !== 0) 15144 * return iTest; 15145 * iTest = oSort['numeric-desc']('data21', 'data22'); 15146 * if (iTest !== 0) 15147 * return iTest; 15148 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] ); 15149 * } 15150 * Basically we have a test for each sorting column, if the data in that column is equal, 15151 * test the next column. If all columns match, then we use a numeric sort on the row 15152 * positions in the original data array to provide a stable sort. 15153 * 15154 * Note - I know it seems excessive to have two sorting methods, but the first is around 15155 * 15% faster, so the second is only maintained for backwards compatibility with sorting 15156 * methods which do not have a pre-sort formatting function. 15157 */ 15158 if ( formatters === aSort.length ) { 15159 // All sort types have formatting functions 15160 displayMaster.sort( function ( a, b ) { 15161 var 15162 x, y, k, test, sort, 15163 len=aSort.length, 15164 dataA = aoData[a]._aSortData, 15165 dataB = aoData[b]._aSortData; 15166 15167 for ( k=0 ; k<len ; k++ ) { 15168 sort = aSort[k]; 15169 15170 x = dataA[ sort.col ]; 15171 y = dataB[ sort.col ]; 15172 15173 test = x<y ? -1 : x>y ? 1 : 0; 15174 if ( test !== 0 ) { 15175 return sort.dir === 'asc' ? test : -test; 15176 } 15177 } 15178 15179 x = aiOrig[a]; 15180 y = aiOrig[b]; 15181 return x<y ? -1 : x>y ? 1 : 0; 15182 } ); 15183 } 15184 else { 15185 // Depreciated - remove in 1.11 (providing a plug-in option) 15186 // Not all sort types have formatting methods, so we have to call their sorting 15187 // methods. 15188 displayMaster.sort( function ( a, b ) { 15189 var 15190 x, y, k, l, test, sort, fn, 15191 len=aSort.length, 15192 dataA = aoData[a]._aSortData, 15193 dataB = aoData[b]._aSortData; 15194 15195 for ( k=0 ; k<len ; k++ ) { 15196 sort = aSort[k]; 15197 15198 x = dataA[ sort.col ]; 15199 y = dataB[ sort.col ]; 15200 15201 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ]; 15202 test = fn( x, y ); 15203 if ( test !== 0 ) { 15204 return test; 15205 } 15206 } 15207 15208 x = aiOrig[a]; 15209 y = aiOrig[b]; 15210 return x<y ? -1 : x>y ? 1 : 0; 15211 } ); 15212 } 15213 } 15214 15215 /* Tell the draw function that we have sorted the data */ 15216 oSettings.bSorted = true; 15217 } 15218 15219 15220 function _fnSortAria ( settings ) 15221 { 15222 var label; 15223 var nextSort; 15224 var columns = settings.aoColumns; 15225 var aSort = _fnSortFlatten( settings ); 15226 var oAria = settings.oLanguage.oAria; 15227 15228 // ARIA attributes - need to loop all columns, to update all (removing old 15229 // attributes as needed) 15230 for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) 15231 { 15232 var col = columns[i]; 15233 var asSorting = col.asSorting; 15234 var sTitle = col.sTitle.replace( /<.*?>/g, "" ); 15235 var th = col.nTh; 15236 15237 // IE7 is throwing an error when setting these properties with jQuery's 15238 // attr() and removeAttr() methods... 15239 th.removeAttribute('aria-sort'); 15240 15241 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */ 15242 if ( col.bSortable ) { 15243 if ( aSort.length > 0 && aSort[0].col == i ) { 15244 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" ); 15245 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0]; 15246 } 15247 else { 15248 nextSort = asSorting[0]; 15249 } 15250 15251 label = sTitle + ( nextSort === "asc" ? 15252 oAria.sSortAscending : 15253 oAria.sSortDescending 15254 ); 15255 } 15256 else { 15257 label = sTitle; 15258 } 15259 15260 th.setAttribute('aria-label', label); 15261 } 15262 } 15263 15264 15265 /** 15266 * Function to run on user sort request 15267 * @param {object} settings dataTables settings object 15268 * @param {node} attachTo node to attach the handler to 15269 * @param {int} colIdx column sorting index 15270 * @param {boolean} [append=false] Append the requested sort to the existing 15271 * sort if true (i.e. multi-column sort) 15272 * @param {function} [callback] callback function 15273 * @memberof DataTable#oApi 15274 */ 15275 function _fnSortListener ( settings, colIdx, append, callback ) 15276 { 15277 var col = settings.aoColumns[ colIdx ]; 15278 var sorting = settings.aaSorting; 15279 var asSorting = col.asSorting; 15280 var nextSortIdx; 15281 var next = function ( a, overflow ) { 15282 var idx = a._idx; 15283 if ( idx === undefined ) { 15284 idx = $.inArray( a[1], asSorting ); 15285 } 15286 15287 return idx+1 < asSorting.length ? 15288 idx+1 : 15289 overflow ? 15290 null : 15291 0; 15292 }; 15293 15294 // Convert to 2D array if needed 15295 if ( typeof sorting[0] === 'number' ) { 15296 sorting = settings.aaSorting = [ sorting ]; 15297 } 15298 15299 // If appending the sort then we are multi-column sorting 15300 if ( append && settings.oFeatures.bSortMulti ) { 15301 // Are we already doing some kind of sort on this column? 15302 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') ); 15303 15304 if ( sortIdx !== -1 ) { 15305 // Yes, modify the sort 15306 nextSortIdx = next( sorting[sortIdx], true ); 15307 15308 if ( nextSortIdx === null && sorting.length === 1 ) { 15309 nextSortIdx = 0; // can't remove sorting completely 15310 } 15311 15312 if ( nextSortIdx === null ) { 15313 sorting.splice( sortIdx, 1 ); 15314 } 15315 else { 15316 sorting[sortIdx][1] = asSorting[ nextSortIdx ]; 15317 sorting[sortIdx]._idx = nextSortIdx; 15318 } 15319 } 15320 else { 15321 // No sort on this column yet 15322 sorting.push( [ colIdx, asSorting[0], 0 ] ); 15323 sorting[sorting.length-1]._idx = 0; 15324 } 15325 } 15326 else if ( sorting.length && sorting[0][0] == colIdx ) { 15327 // Single column - already sorting on this column, modify the sort 15328 nextSortIdx = next( sorting[0] ); 15329 15330 sorting.length = 1; 15331 sorting[0][1] = asSorting[ nextSortIdx ]; 15332 sorting[0]._idx = nextSortIdx; 15333 } 15334 else { 15335 // Single column - sort only on this column 15336 sorting.length = 0; 15337 sorting.push( [ colIdx, asSorting[0] ] ); 15338 sorting[0]._idx = 0; 15339 } 15340 15341 // Run the sort by calling a full redraw 15342 _fnReDraw( settings ); 15343 15344 // callback used for async user interaction 15345 if ( typeof callback == 'function' ) { 15346 callback( settings ); 15347 } 15348 } 15349 15350 15351 /** 15352 * Attach a sort handler (click) to a node 15353 * @param {object} settings dataTables settings object 15354 * @param {node} attachTo node to attach the handler to 15355 * @param {int} colIdx column sorting index 15356 * @param {function} [callback] callback function 15357 * @memberof DataTable#oApi 15358 */ 15359 function _fnSortAttachListener ( settings, attachTo, colIdx, callback ) 15360 { 15361 var col = settings.aoColumns[ colIdx ]; 15362 15363 _fnBindAction( attachTo, {}, function (e) { 15364 /* If the column is not sortable - don't to anything */ 15365 if ( col.bSortable === false ) { 15366 return; 15367 } 15368 15369 // If processing is enabled use a timeout to allow the processing 15370 // display to be shown - otherwise to it synchronously 15371 if ( settings.oFeatures.bProcessing ) { 15372 _fnProcessingDisplay( settings, true ); 15373 15374 setTimeout( function() { 15375 _fnSortListener( settings, colIdx, e.shiftKey, callback ); 15376 15377 // In server-side processing, the draw callback will remove the 15378 // processing display 15379 if ( _fnDataSource( settings ) !== 'ssp' ) { 15380 _fnProcessingDisplay( settings, false ); 15381 } 15382 }, 0 ); 15383 } 15384 else { 15385 _fnSortListener( settings, colIdx, e.shiftKey, callback ); 15386 } 15387 } ); 15388 } 15389 15390 15391 /** 15392 * Set the sorting classes on table's body, Note: it is safe to call this function 15393 * when bSort and bSortClasses are false 15394 * @param {object} oSettings dataTables settings object 15395 * @memberof DataTable#oApi 15396 */ 15397 function _fnSortingClasses( settings ) 15398 { 15399 var oldSort = settings.aLastSort; 15400 var sortClass = settings.oClasses.sSortColumn; 15401 var sort = _fnSortFlatten( settings ); 15402 var features = settings.oFeatures; 15403 var i, ien, colIdx; 15404 15405 if ( features.bSort && features.bSortClasses ) { 15406 // Remove old sorting classes 15407 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) { 15408 colIdx = oldSort[i].src; 15409 15410 // Remove column sorting 15411 $( _pluck( settings.aoData, 'anCells', colIdx ) ) 15412 .removeClass( sortClass + (i<2 ? i+1 : 3) ); 15413 } 15414 15415 // Add new column sorting 15416 for ( i=0, ien=sort.length ; i<ien ; i++ ) { 15417 colIdx = sort[i].src; 15418 15419 $( _pluck( settings.aoData, 'anCells', colIdx ) ) 15420 .addClass( sortClass + (i<2 ? i+1 : 3) ); 15421 } 15422 } 15423 15424 settings.aLastSort = sort; 15425 } 15426 15427 15428 // Get the data to sort a column, be it from cache, fresh (populating the 15429 // cache), or from a sort formatter 15430 function _fnSortData( settings, idx ) 15431 { 15432 // Custom sorting function - provided by the sort data type 15433 var column = settings.aoColumns[ idx ]; 15434 var customSort = DataTable.ext.order[ column.sSortDataType ]; 15435 var customData; 15436 15437 if ( customSort ) { 15438 customData = customSort.call( settings.oInstance, settings, idx, 15439 _fnColumnIndexToVisible( settings, idx ) 15440 ); 15441 } 15442 15443 // Use / populate cache 15444 var row, cellData; 15445 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ]; 15446 15447 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 15448 row = settings.aoData[i]; 15449 15450 if ( ! row._aSortData ) { 15451 row._aSortData = []; 15452 } 15453 15454 if ( ! row._aSortData[idx] || customSort ) { 15455 cellData = customSort ? 15456 customData[i] : // If there was a custom sort function, use data from there 15457 _fnGetCellData( settings, i, idx, 'sort' ); 15458 15459 row._aSortData[ idx ] = formatter ? 15460 formatter( cellData ) : 15461 cellData; 15462 } 15463 } 15464 } 15465 15466 15467 15468 /** 15469 * Save the state of a table 15470 * @param {object} oSettings dataTables settings object 15471 * @memberof DataTable#oApi 15472 */ 15473 function _fnSaveState ( settings ) 15474 { 15475 if ( !settings.oFeatures.bStateSave || settings.bDestroying ) 15476 { 15477 return; 15478 } 15479 15480 /* Store the interesting variables */ 15481 var state = { 15482 time: +new Date(), 15483 start: settings._iDisplayStart, 15484 length: settings._iDisplayLength, 15485 order: $.extend( true, [], settings.aaSorting ), 15486 search: _fnSearchToCamel( settings.oPreviousSearch ), 15487 columns: $.map( settings.aoColumns, function ( col, i ) { 15488 return { 15489 visible: col.bVisible, 15490 search: _fnSearchToCamel( settings.aoPreSearchCols[i] ) 15491 }; 15492 } ) 15493 }; 15494 15495 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] ); 15496 15497 settings.oSavedState = state; 15498 settings.fnStateSaveCallback.call( settings.oInstance, settings, state ); 15499 } 15500 15501 15502 /** 15503 * Attempt to load a saved table state 15504 * @param {object} oSettings dataTables settings object 15505 * @param {object} oInit DataTables init object so we can override settings 15506 * @param {function} callback Callback to execute when the state has been loaded 15507 * @memberof DataTable#oApi 15508 */ 15509 function _fnLoadState ( settings, oInit, callback ) 15510 { 15511 var i, ien; 15512 var columns = settings.aoColumns; 15513 var loaded = function ( s ) { 15514 if ( ! s || ! s.time ) { 15515 callback(); 15516 return; 15517 } 15518 15519 // Allow custom and plug-in manipulation functions to alter the saved data set and 15520 // cancelling of loading by returning false 15521 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] ); 15522 if ( $.inArray( false, abStateLoad ) !== -1 ) { 15523 callback(); 15524 return; 15525 } 15526 15527 // Reject old data 15528 var duration = settings.iStateDuration; 15529 if ( duration > 0 && s.time < +new Date() - (duration*1000) ) { 15530 callback(); 15531 return; 15532 } 15533 15534 // Number of columns have changed - all bets are off, no restore of settings 15535 if ( s.columns && columns.length !== s.columns.length ) { 15536 callback(); 15537 return; 15538 } 15539 15540 // Store the saved state so it might be accessed at any time 15541 settings.oLoadedState = $.extend( true, {}, s ); 15542 15543 // Restore key features - todo - for 1.11 this needs to be done by 15544 // subscribed events 15545 if ( s.start !== undefined ) { 15546 settings._iDisplayStart = s.start; 15547 settings.iInitDisplayStart = s.start; 15548 } 15549 if ( s.length !== undefined ) { 15550 settings._iDisplayLength = s.length; 15551 } 15552 15553 // Order 15554 if ( s.order !== undefined ) { 15555 settings.aaSorting = []; 15556 $.each( s.order, function ( i, col ) { 15557 settings.aaSorting.push( col[0] >= columns.length ? 15558 [ 0, col[1] ] : 15559 col 15560 ); 15561 } ); 15562 } 15563 15564 // Search 15565 if ( s.search !== undefined ) { 15566 $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) ); 15567 } 15568 15569 // Columns 15570 // 15571 if ( s.columns ) { 15572 for ( i=0, ien=s.columns.length ; i<ien ; i++ ) { 15573 var col = s.columns[i]; 15574 15575 // Visibility 15576 if ( col.visible !== undefined ) { 15577 columns[i].bVisible = col.visible; 15578 } 15579 15580 // Search 15581 if ( col.search !== undefined ) { 15582 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) ); 15583 } 15584 } 15585 } 15586 15587 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] ); 15588 callback(); 15589 } 15590 15591 if ( ! settings.oFeatures.bStateSave ) { 15592 callback(); 15593 return; 15594 } 15595 15596 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded ); 15597 15598 if ( state !== undefined ) { 15599 loaded( state ); 15600 } 15601 // otherwise, wait for the loaded callback to be executed 15602 } 15603 15604 15605 /** 15606 * Return the settings object for a particular table 15607 * @param {node} table table we are using as a dataTable 15608 * @returns {object} Settings object - or null if not found 15609 * @memberof DataTable#oApi 15610 */ 15611 function _fnSettingsFromNode ( table ) 15612 { 15613 var settings = DataTable.settings; 15614 var idx = $.inArray( table, _pluck( settings, 'nTable' ) ); 15615 15616 return idx !== -1 ? 15617 settings[ idx ] : 15618 null; 15619 } 15620 15621 15622 /** 15623 * Log an error message 15624 * @param {object} settings dataTables settings object 15625 * @param {int} level log error messages, or display them to the user 15626 * @param {string} msg error message 15627 * @param {int} tn Technical note id to get more information about the error. 15628 * @memberof DataTable#oApi 15629 */ 15630 function _fnLog( settings, level, msg, tn ) 15631 { 15632 msg = 'DataTables warning: '+ 15633 (settings ? 'table id='+settings.sTableId+' - ' : '')+msg; 15634 15635 if ( tn ) { 15636 msg += '. For more information about this error, please see '+ 15637 'http://datatables.net/tn/'+tn; 15638 } 15639 15640 if ( ! level ) { 15641 // Backwards compatibility pre 1.10 15642 var ext = DataTable.ext; 15643 var type = ext.sErrMode || ext.errMode; 15644 15645 if ( settings ) { 15646 _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] ); 15647 } 15648 15649 if ( type == 'alert' ) { 15650 alert( msg ); 15651 } 15652 else if ( type == 'throw' ) { 15653 throw new Error(msg); 15654 } 15655 else if ( typeof type == 'function' ) { 15656 type( settings, tn, msg ); 15657 } 15658 } 15659 else if ( window.console && console.log ) { 15660 console.log( msg ); 15661 } 15662 } 15663 15664 15665 /** 15666 * See if a property is defined on one object, if so assign it to the other object 15667 * @param {object} ret target object 15668 * @param {object} src source object 15669 * @param {string} name property 15670 * @param {string} [mappedName] name to map too - optional, name used if not given 15671 * @memberof DataTable#oApi 15672 */ 15673 function _fnMap( ret, src, name, mappedName ) 15674 { 15675 if ( $.isArray( name ) ) { 15676 $.each( name, function (i, val) { 15677 if ( $.isArray( val ) ) { 15678 _fnMap( ret, src, val[0], val[1] ); 15679 } 15680 else { 15681 _fnMap( ret, src, val ); 15682 } 15683 } ); 15684 15685 return; 15686 } 15687 15688 if ( mappedName === undefined ) { 15689 mappedName = name; 15690 } 15691 15692 if ( src[name] !== undefined ) { 15693 ret[mappedName] = src[name]; 15694 } 15695 } 15696 15697 15698 /** 15699 * Extend objects - very similar to jQuery.extend, but deep copy objects, and 15700 * shallow copy arrays. The reason we need to do this, is that we don't want to 15701 * deep copy array init values (such as aaSorting) since the dev wouldn't be 15702 * able to override them, but we do want to deep copy arrays. 15703 * @param {object} out Object to extend 15704 * @param {object} extender Object from which the properties will be applied to 15705 * out 15706 * @param {boolean} breakRefs If true, then arrays will be sliced to take an 15707 * independent copy with the exception of the `data` or `aaData` parameters 15708 * if they are present. This is so you can pass in a collection to 15709 * DataTables and have that used as your data source without breaking the 15710 * references 15711 * @returns {object} out Reference, just for convenience - out === the return. 15712 * @memberof DataTable#oApi 15713 * @todo This doesn't take account of arrays inside the deep copied objects. 15714 */ 15715 function _fnExtend( out, extender, breakRefs ) 15716 { 15717 var val; 15718 15719 for ( var prop in extender ) { 15720 if ( extender.hasOwnProperty(prop) ) { 15721 val = extender[prop]; 15722 15723 if ( $.isPlainObject( val ) ) { 15724 if ( ! $.isPlainObject( out[prop] ) ) { 15725 out[prop] = {}; 15726 } 15727 $.extend( true, out[prop], val ); 15728 } 15729 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) { 15730 out[prop] = val.slice(); 15731 } 15732 else { 15733 out[prop] = val; 15734 } 15735 } 15736 } 15737 15738 return out; 15739 } 15740 15741 15742 /** 15743 * Bind an event handers to allow a click or return key to activate the callback. 15744 * This is good for accessibility since a return on the keyboard will have the 15745 * same effect as a click, if the element has focus. 15746 * @param {element} n Element to bind the action to 15747 * @param {object} oData Data object to pass to the triggered function 15748 * @param {function} fn Callback function for when the event is triggered 15749 * @memberof DataTable#oApi 15750 */ 15751 function _fnBindAction( n, oData, fn ) 15752 { 15753 $(n) 15754 .on( 'click.DT', oData, function (e) { 15755 $(n).blur(); // Remove focus outline for mouse users 15756 fn(e); 15757 } ) 15758 .on( 'keypress.DT', oData, function (e){ 15759 if ( e.which === 13 ) { 15760 e.preventDefault(); 15761 fn(e); 15762 } 15763 } ) 15764 .on( 'selectstart.DT', function () { 15765 /* Take the brutal approach to cancelling text selection */ 15766 return false; 15767 } ); 15768 } 15769 15770 15771 /** 15772 * Register a callback function. Easily allows a callback function to be added to 15773 * an array store of callback functions that can then all be called together. 15774 * @param {object} oSettings dataTables settings object 15775 * @param {string} sStore Name of the array storage for the callbacks in oSettings 15776 * @param {function} fn Function to be called back 15777 * @param {string} sName Identifying name for the callback (i.e. a label) 15778 * @memberof DataTable#oApi 15779 */ 15780 function _fnCallbackReg( oSettings, sStore, fn, sName ) 15781 { 15782 if ( fn ) 15783 { 15784 oSettings[sStore].push( { 15785 "fn": fn, 15786 "sName": sName 15787 } ); 15788 } 15789 } 15790 15791 15792 /** 15793 * Fire callback functions and trigger events. Note that the loop over the 15794 * callback array store is done backwards! Further note that you do not want to 15795 * fire off triggers in time sensitive applications (for example cell creation) 15796 * as its slow. 15797 * @param {object} settings dataTables settings object 15798 * @param {string} callbackArr Name of the array storage for the callbacks in 15799 * oSettings 15800 * @param {string} eventName Name of the jQuery custom event to trigger. If 15801 * null no trigger is fired 15802 * @param {array} args Array of arguments to pass to the callback function / 15803 * trigger 15804 * @memberof DataTable#oApi 15805 */ 15806 function _fnCallbackFire( settings, callbackArr, eventName, args ) 15807 { 15808 var ret = []; 15809 15810 if ( callbackArr ) { 15811 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) { 15812 return val.fn.apply( settings.oInstance, args ); 15813 } ); 15814 } 15815 15816 if ( eventName !== null ) { 15817 var e = $.Event( eventName+'.dt' ); 15818 15819 $(settings.nTable).trigger( e, args ); 15820 15821 ret.push( e.result ); 15822 } 15823 15824 return ret; 15825 } 15826 15827 15828 function _fnLengthOverflow ( settings ) 15829 { 15830 var 15831 start = settings._iDisplayStart, 15832 end = settings.fnDisplayEnd(), 15833 len = settings._iDisplayLength; 15834 15835 /* If we have space to show extra rows (backing up from the end point - then do so */ 15836 if ( start >= end ) 15837 { 15838 start = end - len; 15839 } 15840 15841 // Keep the start record on the current page 15842 start -= (start % len); 15843 15844 if ( len === -1 || start < 0 ) 15845 { 15846 start = 0; 15847 } 15848 15849 settings._iDisplayStart = start; 15850 } 15851 15852 15853 function _fnRenderer( settings, type ) 15854 { 15855 var renderer = settings.renderer; 15856 var host = DataTable.ext.renderer[type]; 15857 15858 if ( $.isPlainObject( renderer ) && renderer[type] ) { 15859 // Specific renderer for this type. If available use it, otherwise use 15860 // the default. 15861 return host[renderer[type]] || host._; 15862 } 15863 else if ( typeof renderer === 'string' ) { 15864 // Common renderer - if there is one available for this type use it, 15865 // otherwise use the default 15866 return host[renderer] || host._; 15867 } 15868 15869 // Use the default 15870 return host._; 15871 } 15872 15873 15874 /** 15875 * Detect the data source being used for the table. Used to simplify the code 15876 * a little (ajax) and to make it compress a little smaller. 15877 * 15878 * @param {object} settings dataTables settings object 15879 * @returns {string} Data source 15880 * @memberof DataTable#oApi 15881 */ 15882 function _fnDataSource ( settings ) 15883 { 15884 if ( settings.oFeatures.bServerSide ) { 15885 return 'ssp'; 15886 } 15887 else if ( settings.ajax || settings.sAjaxSource ) { 15888 return 'ajax'; 15889 } 15890 return 'dom'; 15891 } 15892 15893 15894 15895 15896 /** 15897 * Computed structure of the DataTables API, defined by the options passed to 15898 * `DataTable.Api.register()` when building the API. 15899 * 15900 * The structure is built in order to speed creation and extension of the Api 15901 * objects since the extensions are effectively pre-parsed. 15902 * 15903 * The array is an array of objects with the following structure, where this 15904 * base array represents the Api prototype base: 15905 * 15906 * [ 15907 * { 15908 * name: 'data' -- string - Property name 15909 * val: function () {}, -- function - Api method (or undefined if just an object 15910 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result 15911 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property 15912 * }, 15913 * { 15914 * name: 'row' 15915 * val: {}, 15916 * methodExt: [ ... ], 15917 * propExt: [ 15918 * { 15919 * name: 'data' 15920 * val: function () {}, 15921 * methodExt: [ ... ], 15922 * propExt: [ ... ] 15923 * }, 15924 * ... 15925 * ] 15926 * } 15927 * ] 15928 * 15929 * @type {Array} 15930 * @ignore 15931 */ 15932 var __apiStruct = []; 15933 15934 15935 /** 15936 * `Array.prototype` reference. 15937 * 15938 * @type object 15939 * @ignore 15940 */ 15941 var __arrayProto = Array.prototype; 15942 15943 15944 /** 15945 * Abstraction for `context` parameter of the `Api` constructor to allow it to 15946 * take several different forms for ease of use. 15947 * 15948 * Each of the input parameter types will be converted to a DataTables settings 15949 * object where possible. 15950 * 15951 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one 15952 * of: 15953 * 15954 * * `string` - jQuery selector. Any DataTables' matching the given selector 15955 * with be found and used. 15956 * * `node` - `TABLE` node which has already been formed into a DataTable. 15957 * * `jQuery` - A jQuery object of `TABLE` nodes. 15958 * * `object` - DataTables settings object 15959 * * `DataTables.Api` - API instance 15960 * @return {array|null} Matching DataTables settings objects. `null` or 15961 * `undefined` is returned if no matching DataTable is found. 15962 * @ignore 15963 */ 15964 var _toSettings = function ( mixed ) 15965 { 15966 var idx, jq; 15967 var settings = DataTable.settings; 15968 var tables = $.map( settings, function (el, i) { 15969 return el.nTable; 15970 } ); 15971 15972 if ( ! mixed ) { 15973 return []; 15974 } 15975 else if ( mixed.nTable && mixed.oApi ) { 15976 // DataTables settings object 15977 return [ mixed ]; 15978 } 15979 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) { 15980 // Table node 15981 idx = $.inArray( mixed, tables ); 15982 return idx !== -1 ? [ settings[idx] ] : null; 15983 } 15984 else if ( mixed && typeof mixed.settings === 'function' ) { 15985 return mixed.settings().toArray(); 15986 } 15987 else if ( typeof mixed === 'string' ) { 15988 // jQuery selector 15989 jq = $(mixed); 15990 } 15991 else if ( mixed instanceof $ ) { 15992 // jQuery object (also DataTables instance) 15993 jq = mixed; 15994 } 15995 15996 if ( jq ) { 15997 return jq.map( function(i) { 15998 idx = $.inArray( this, tables ); 15999 return idx !== -1 ? settings[idx] : null; 16000 } ).toArray(); 16001 } 16002 }; 16003 16004 16005 /** 16006 * DataTables API class - used to control and interface with one or more 16007 * DataTables enhanced tables. 16008 * 16009 * The API class is heavily based on jQuery, presenting a chainable interface 16010 * that you can use to interact with tables. Each instance of the API class has 16011 * a "context" - i.e. the tables that it will operate on. This could be a single 16012 * table, all tables on a page or a sub-set thereof. 16013 * 16014 * Additionally the API is designed to allow you to easily work with the data in 16015 * the tables, retrieving and manipulating it as required. This is done by 16016 * presenting the API class as an array like interface. The contents of the 16017 * array depend upon the actions requested by each method (for example 16018 * `rows().nodes()` will return an array of nodes, while `rows().data()` will 16019 * return an array of objects or arrays depending upon your table's 16020 * configuration). The API object has a number of array like methods (`push`, 16021 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`, 16022 * `unique` etc) to assist your working with the data held in a table. 16023 * 16024 * Most methods (those which return an Api instance) are chainable, which means 16025 * the return from a method call also has all of the methods available that the 16026 * top level object had. For example, these two calls are equivalent: 16027 * 16028 * // Not chained 16029 * api.row.add( {...} ); 16030 * api.draw(); 16031 * 16032 * // Chained 16033 * api.row.add( {...} ).draw(); 16034 * 16035 * @class DataTable.Api 16036 * @param {array|object|string|jQuery} context DataTable identifier. This is 16037 * used to define which DataTables enhanced tables this API will operate on. 16038 * Can be one of: 16039 * 16040 * * `string` - jQuery selector. Any DataTables' matching the given selector 16041 * with be found and used. 16042 * * `node` - `TABLE` node which has already been formed into a DataTable. 16043 * * `jQuery` - A jQuery object of `TABLE` nodes. 16044 * * `object` - DataTables settings object 16045 * @param {array} [data] Data to initialise the Api instance with. 16046 * 16047 * @example 16048 * // Direct initialisation during DataTables construction 16049 * var api = $('#example').DataTable(); 16050 * 16051 * @example 16052 * // Initialisation using a DataTables jQuery object 16053 * var api = $('#example').dataTable().api(); 16054 * 16055 * @example 16056 * // Initialisation as a constructor 16057 * var api = new $.fn.DataTable.Api( 'table.dataTable' ); 16058 */ 16059 _Api = function ( context, data ) 16060 { 16061 if ( ! (this instanceof _Api) ) { 16062 return new _Api( context, data ); 16063 } 16064 16065 var settings = []; 16066 var ctxSettings = function ( o ) { 16067 var a = _toSettings( o ); 16068 if ( a ) { 16069 settings = settings.concat( a ); 16070 } 16071 }; 16072 16073 if ( $.isArray( context ) ) { 16074 for ( var i=0, ien=context.length ; i<ien ; i++ ) { 16075 ctxSettings( context[i] ); 16076 } 16077 } 16078 else { 16079 ctxSettings( context ); 16080 } 16081 16082 // Remove duplicates 16083 this.context = _unique( settings ); 16084 16085 // Initial data 16086 if ( data ) { 16087 $.merge( this, data ); 16088 } 16089 16090 // selector 16091 this.selector = { 16092 rows: null, 16093 cols: null, 16094 opts: null 16095 }; 16096 16097 _Api.extend( this, this, __apiStruct ); 16098 }; 16099 16100 DataTable.Api = _Api; 16101 16102 // Don't destroy the existing prototype, just extend it. Required for jQuery 2's 16103 // isPlainObject. 16104 $.extend( _Api.prototype, { 16105 any: function () 16106 { 16107 return this.count() !== 0; 16108 }, 16109 16110 16111 concat: __arrayProto.concat, 16112 16113 16114 context: [], // array of table settings objects 16115 16116 16117 count: function () 16118 { 16119 return this.flatten().length; 16120 }, 16121 16122 16123 each: function ( fn ) 16124 { 16125 for ( var i=0, ien=this.length ; i<ien; i++ ) { 16126 fn.call( this, this[i], i, this ); 16127 } 16128 16129 return this; 16130 }, 16131 16132 16133 eq: function ( idx ) 16134 { 16135 var ctx = this.context; 16136 16137 return ctx.length > idx ? 16138 new _Api( ctx[idx], this[idx] ) : 16139 null; 16140 }, 16141 16142 16143 filter: function ( fn ) 16144 { 16145 var a = []; 16146 16147 if ( __arrayProto.filter ) { 16148 a = __arrayProto.filter.call( this, fn, this ); 16149 } 16150 else { 16151 // Compatibility for browsers without EMCA-252-5 (JS 1.6) 16152 for ( var i=0, ien=this.length ; i<ien ; i++ ) { 16153 if ( fn.call( this, this[i], i, this ) ) { 16154 a.push( this[i] ); 16155 } 16156 } 16157 } 16158 16159 return new _Api( this.context, a ); 16160 }, 16161 16162 16163 flatten: function () 16164 { 16165 var a = []; 16166 return new _Api( this.context, a.concat.apply( a, this.toArray() ) ); 16167 }, 16168 16169 16170 join: __arrayProto.join, 16171 16172 16173 indexOf: __arrayProto.indexOf || function (obj, start) 16174 { 16175 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) { 16176 if ( this[i] === obj ) { 16177 return i; 16178 } 16179 } 16180 return -1; 16181 }, 16182 16183 iterator: function ( flatten, type, fn, alwaysNew ) { 16184 var 16185 a = [], ret, 16186 i, ien, j, jen, 16187 context = this.context, 16188 rows, items, item, 16189 selector = this.selector; 16190 16191 // Argument shifting 16192 if ( typeof flatten === 'string' ) { 16193 alwaysNew = fn; 16194 fn = type; 16195 type = flatten; 16196 flatten = false; 16197 } 16198 16199 for ( i=0, ien=context.length ; i<ien ; i++ ) { 16200 var apiInst = new _Api( context[i] ); 16201 16202 if ( type === 'table' ) { 16203 ret = fn.call( apiInst, context[i], i ); 16204 16205 if ( ret !== undefined ) { 16206 a.push( ret ); 16207 } 16208 } 16209 else if ( type === 'columns' || type === 'rows' ) { 16210 // this has same length as context - one entry for each table 16211 ret = fn.call( apiInst, context[i], this[i], i ); 16212 16213 if ( ret !== undefined ) { 16214 a.push( ret ); 16215 } 16216 } 16217 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) { 16218 // columns and rows share the same structure. 16219 // 'this' is an array of column indexes for each context 16220 items = this[i]; 16221 16222 if ( type === 'column-rows' ) { 16223 rows = _selector_row_indexes( context[i], selector.opts ); 16224 } 16225 16226 for ( j=0, jen=items.length ; j<jen ; j++ ) { 16227 item = items[j]; 16228 16229 if ( type === 'cell' ) { 16230 ret = fn.call( apiInst, context[i], item.row, item.column, i, j ); 16231 } 16232 else { 16233 ret = fn.call( apiInst, context[i], item, i, j, rows ); 16234 } 16235 16236 if ( ret !== undefined ) { 16237 a.push( ret ); 16238 } 16239 } 16240 } 16241 } 16242 16243 if ( a.length || alwaysNew ) { 16244 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a ); 16245 var apiSelector = api.selector; 16246 apiSelector.rows = selector.rows; 16247 apiSelector.cols = selector.cols; 16248 apiSelector.opts = selector.opts; 16249 return api; 16250 } 16251 return this; 16252 }, 16253 16254 16255 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start) 16256 { 16257 // Bit cheeky... 16258 return this.indexOf.apply( this.toArray.reverse(), arguments ); 16259 }, 16260 16261 16262 length: 0, 16263 16264 16265 map: function ( fn ) 16266 { 16267 var a = []; 16268 16269 if ( __arrayProto.map ) { 16270 a = __arrayProto.map.call( this, fn, this ); 16271 } 16272 else { 16273 // Compatibility for browsers without EMCA-252-5 (JS 1.6) 16274 for ( var i=0, ien=this.length ; i<ien ; i++ ) { 16275 a.push( fn.call( this, this[i], i ) ); 16276 } 16277 } 16278 16279 return new _Api( this.context, a ); 16280 }, 16281 16282 16283 pluck: function ( prop ) 16284 { 16285 return this.map( function ( el ) { 16286 return el[ prop ]; 16287 } ); 16288 }, 16289 16290 pop: __arrayProto.pop, 16291 16292 16293 push: __arrayProto.push, 16294 16295 16296 // Does not return an API instance 16297 reduce: __arrayProto.reduce || function ( fn, init ) 16298 { 16299 return _fnReduce( this, fn, init, 0, this.length, 1 ); 16300 }, 16301 16302 16303 reduceRight: __arrayProto.reduceRight || function ( fn, init ) 16304 { 16305 return _fnReduce( this, fn, init, this.length-1, -1, -1 ); 16306 }, 16307 16308 16309 reverse: __arrayProto.reverse, 16310 16311 16312 // Object with rows, columns and opts 16313 selector: null, 16314 16315 16316 shift: __arrayProto.shift, 16317 16318 16319 slice: function () { 16320 return new _Api( this.context, this ); 16321 }, 16322 16323 16324 sort: __arrayProto.sort, // ? name - order? 16325 16326 16327 splice: __arrayProto.splice, 16328 16329 16330 toArray: function () 16331 { 16332 return __arrayProto.slice.call( this ); 16333 }, 16334 16335 16336 to$: function () 16337 { 16338 return $( this ); 16339 }, 16340 16341 16342 toJQuery: function () 16343 { 16344 return $( this ); 16345 }, 16346 16347 16348 unique: function () 16349 { 16350 return new _Api( this.context, _unique(this) ); 16351 }, 16352 16353 16354 unshift: __arrayProto.unshift 16355 } ); 16356 16357 16358 _Api.extend = function ( scope, obj, ext ) 16359 { 16360 // Only extend API instances and static properties of the API 16361 if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) { 16362 return; 16363 } 16364 16365 var 16366 i, ien, 16367 j, jen, 16368 struct, inner, 16369 methodScoping = function ( scope, fn, struc ) { 16370 return function () { 16371 var ret = fn.apply( scope, arguments ); 16372 16373 // Method extension 16374 _Api.extend( ret, ret, struc.methodExt ); 16375 return ret; 16376 }; 16377 }; 16378 16379 for ( i=0, ien=ext.length ; i<ien ; i++ ) { 16380 struct = ext[i]; 16381 16382 // Value 16383 obj[ struct.name ] = typeof struct.val === 'function' ? 16384 methodScoping( scope, struct.val, struct ) : 16385 $.isPlainObject( struct.val ) ? 16386 {} : 16387 struct.val; 16388 16389 obj[ struct.name ].__dt_wrapper = true; 16390 16391 // Property extension 16392 _Api.extend( scope, obj[ struct.name ], struct.propExt ); 16393 } 16394 }; 16395 16396 16397 // @todo - Is there need for an augment function? 16398 // _Api.augment = function ( inst, name ) 16399 // { 16400 // // Find src object in the structure from the name 16401 // var parts = name.split('.'); 16402 16403 // _Api.extend( inst, obj ); 16404 // }; 16405 16406 16407 // [ 16408 // { 16409 // name: 'data' -- string - Property name 16410 // val: function () {}, -- function - Api method (or undefined if just an object 16411 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result 16412 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property 16413 // }, 16414 // { 16415 // name: 'row' 16416 // val: {}, 16417 // methodExt: [ ... ], 16418 // propExt: [ 16419 // { 16420 // name: 'data' 16421 // val: function () {}, 16422 // methodExt: [ ... ], 16423 // propExt: [ ... ] 16424 // }, 16425 // ... 16426 // ] 16427 // } 16428 // ] 16429 16430 _Api.register = _api_register = function ( name, val ) 16431 { 16432 if ( $.isArray( name ) ) { 16433 for ( var j=0, jen=name.length ; j<jen ; j++ ) { 16434 _Api.register( name[j], val ); 16435 } 16436 return; 16437 } 16438 16439 var 16440 i, ien, 16441 heir = name.split('.'), 16442 struct = __apiStruct, 16443 key, method; 16444 16445 var find = function ( src, name ) { 16446 for ( var i=0, ien=src.length ; i<ien ; i++ ) { 16447 if ( src[i].name === name ) { 16448 return src[i]; 16449 } 16450 } 16451 return null; 16452 }; 16453 16454 for ( i=0, ien=heir.length ; i<ien ; i++ ) { 16455 method = heir[i].indexOf('()') !== -1; 16456 key = method ? 16457 heir[i].replace('()', '') : 16458 heir[i]; 16459 16460 var src = find( struct, key ); 16461 if ( ! src ) { 16462 src = { 16463 name: key, 16464 val: {}, 16465 methodExt: [], 16466 propExt: [] 16467 }; 16468 struct.push( src ); 16469 } 16470 16471 if ( i === ien-1 ) { 16472 src.val = val; 16473 } 16474 else { 16475 struct = method ? 16476 src.methodExt : 16477 src.propExt; 16478 } 16479 } 16480 }; 16481 16482 16483 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) { 16484 _Api.register( pluralName, val ); 16485 16486 _Api.register( singularName, function () { 16487 var ret = val.apply( this, arguments ); 16488 16489 if ( ret === this ) { 16490 // Returned item is the API instance that was passed in, return it 16491 return this; 16492 } 16493 else if ( ret instanceof _Api ) { 16494 // New API instance returned, want the value from the first item 16495 // in the returned array for the singular result. 16496 return ret.length ? 16497 $.isArray( ret[0] ) ? 16498 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced' 16499 ret[0] : 16500 undefined; 16501 } 16502 16503 // Non-API return - just fire it back 16504 return ret; 16505 } ); 16506 }; 16507 16508 16509 /** 16510 * Selector for HTML tables. Apply the given selector to the give array of 16511 * DataTables settings objects. 16512 * 16513 * @param {string|integer} [selector] jQuery selector string or integer 16514 * @param {array} Array of DataTables settings objects to be filtered 16515 * @return {array} 16516 * @ignore 16517 */ 16518 var __table_selector = function ( selector, a ) 16519 { 16520 // Integer is used to pick out a table by index 16521 if ( typeof selector === 'number' ) { 16522 return [ a[ selector ] ]; 16523 } 16524 16525 // Perform a jQuery selector on the table nodes 16526 var nodes = $.map( a, function (el, i) { 16527 return el.nTable; 16528 } ); 16529 16530 return $(nodes) 16531 .filter( selector ) 16532 .map( function (i) { 16533 // Need to translate back from the table node to the settings 16534 var idx = $.inArray( this, nodes ); 16535 return a[ idx ]; 16536 } ) 16537 .toArray(); 16538 }; 16539 16540 16541 16542 /** 16543 * Context selector for the API's context (i.e. the tables the API instance 16544 * refers to. 16545 * 16546 * @name DataTable.Api#tables 16547 * @param {string|integer} [selector] Selector to pick which tables the iterator 16548 * should operate on. If not given, all tables in the current context are 16549 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to 16550 * select multiple tables or as an integer to select a single table. 16551 * @returns {DataTable.Api} Returns a new API instance if a selector is given. 16552 */ 16553 _api_register( 'tables()', function ( selector ) { 16554 // A new instance is created if there was a selector specified 16555 return selector
vendor: 9,632 bytes, lines 16555-16903
16555 ? 16556 new _Api( __table_selector( selector, this.context ) ) : 16557 this; 16558 } ); 16559 16560 16561 _api_register( 'table()', function ( selector ) { 16562 var tables = this.tables( selector ); 16563 var ctx = tables.context; 16564 16565 // Truncate to the first matched table 16566 return ctx.length ? 16567 new _Api( ctx[0] ) : 16568 tables; 16569 } ); 16570 16571 16572 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () { 16573 return this.iterator( 'table', function ( ctx ) { 16574 return ctx.nTable; 16575 }, 1 ); 16576 } ); 16577 16578 16579 _api_registerPlural( 'tables().body()', 'table().body()' , function () { 16580 return this.iterator( 'table', function ( ctx ) { 16581 return ctx.nTBody; 16582 }, 1 ); 16583 } ); 16584 16585 16586 _api_registerPlural( 'tables().header()', 'table().header()' , function () { 16587 return this.iterator( 'table', function ( ctx ) { 16588 return ctx.nTHead; 16589 }, 1 ); 16590 } ); 16591 16592 16593 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () { 16594 return this.iterator( 'table', function ( ctx ) { 16595 return ctx.nTFoot; 16596 }, 1 ); 16597 } ); 16598 16599 16600 _api_registerPlural( 'tables().containers()', 'table().container()' , function () { 16601 return this.iterator( 'table', function ( ctx ) { 16602 return ctx.nTableWrapper; 16603 }, 1 ); 16604 } ); 16605 16606 16607 16608 /** 16609 * Redraw the tables in the current context. 16610 */ 16611 _api_register( 'draw()', function ( paging ) { 16612 return this.iterator( 'table', function ( settings ) { 16613 if ( paging === 'page' ) { 16614 _fnDraw( settings ); 16615 } 16616 else { 16617 if ( typeof paging === 'string' ) { 16618 paging = paging === 'full-hold' ? 16619 false : 16620 true; 16621 } 16622 16623 _fnReDraw( settings, paging===false ); 16624 } 16625 } ); 16626 } ); 16627 16628 16629 16630 /** 16631 * Get the current page index. 16632 * 16633 * @return {integer} Current page index (zero based) 16634 *//** 16635 * Set the current page. 16636 * 16637 * Note that if you attempt to show a page which does not exist, DataTables will 16638 * not throw an error, but rather reset the paging. 16639 * 16640 * @param {integer|string} action The paging action to take. This can be one of: 16641 * * `integer` - The page index to jump to 16642 * * `string` - An action to take: 16643 * * `first` - Jump to first page. 16644 * * `next` - Jump to the next page 16645 * * `previous` - Jump to previous page 16646 * * `last` - Jump to the last page. 16647 * @returns {DataTables.Api} this 16648 */ 16649 _api_register( 'page()', function ( action ) { 16650 if ( action === undefined ) { 16651 return this.page.info().page; // not an expensive call 16652 } 16653 16654 // else, have an action to take on all tables 16655 return this.iterator( 'table', function ( settings ) { 16656 _fnPageChange( settings, action ); 16657 } ); 16658 } ); 16659 16660 16661 /** 16662 * Paging information for the first table in the current context. 16663 * 16664 * If you require paging information for another table, use the `table()` method 16665 * with a suitable selector. 16666 * 16667 * @return {object} Object with the following properties set: 16668 * * `page` - Current page index (zero based - i.e. the first page is `0`) 16669 * * `pages` - Total number of pages 16670 * * `start` - Display index for the first record shown on the current page 16671 * * `end` - Display index for the last record shown on the current page 16672 * * `length` - Display length (number of records). Note that generally `start 16673 * + length = end`, but this is not always true, for example if there are 16674 * only 2 records to show on the final page, with a length of 10. 16675 * * `recordsTotal` - Full data set length 16676 * * `recordsDisplay` - Data set length once the current filtering criterion 16677 * are applied. 16678 */ 16679 _api_register( 'page.info()', function ( action ) { 16680 if ( this.context.length === 0 ) { 16681 return undefined; 16682 } 16683 16684 var 16685 settings = this.context[0], 16686 start = settings._iDisplayStart, 16687 len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1, 16688 visRecords = settings.fnRecordsDisplay(), 16689 all = len === -1; 16690 16691 return { 16692 "page": all ? 0 : Math.floor( start / len ), 16693 "pages": all ? 1 : Math.ceil( visRecords / len ), 16694 "start": start, 16695 "end": settings.fnDisplayEnd(), 16696 "length": len, 16697 "recordsTotal": settings.fnRecordsTotal(), 16698 "recordsDisplay": visRecords, 16699 "serverSide": _fnDataSource( settings ) === 'ssp' 16700 }; 16701 } ); 16702 16703 16704 /** 16705 * Get the current page length. 16706 * 16707 * @return {integer} Current page length. Note `-1` indicates that all records 16708 * are to be shown. 16709 *//** 16710 * Set the current page length. 16711 * 16712 * @param {integer} Page length to set. Use `-1` to show all records. 16713 * @returns {DataTables.Api} this 16714 */ 16715 _api_register( 'page.len()', function ( len ) { 16716 // Note that we can't call this function 'length()' because `length` 16717 // is a Javascript property of functions which defines how many arguments 16718 // the function expects. 16719 if ( len === undefined ) { 16720 return this.context.length !== 0 ? 16721 this.context[0]._iDisplayLength : 16722 undefined; 16723 } 16724 16725 // else, set the page length 16726 return this.iterator( 'table', function ( settings ) { 16727 _fnLengthChange( settings, len ); 16728 } ); 16729 } ); 16730 16731 16732 16733 var __reload = function ( settings, holdPosition, callback ) { 16734 // Use the draw event to trigger a callback 16735 if ( callback ) { 16736 var api = new _Api( settings ); 16737 16738 api.one( 'draw', function () { 16739 callback( api.ajax.json() ); 16740 } ); 16741 } 16742 16743 if ( _fnDataSource( settings ) == 'ssp' ) { 16744 _fnReDraw( settings, holdPosition ); 16745 } 16746 else { 16747 _fnProcessingDisplay( settings, true ); 16748 16749 // Cancel an existing request 16750 var xhr = settings.jqXHR; 16751 if ( xhr && xhr.readyState !== 4 ) { 16752 xhr.abort(); 16753 } 16754 16755 // Trigger xhr 16756 _fnBuildAjax( settings, [], function( json ) { 16757 _fnClearTable( settings ); 16758 16759 var data = _fnAjaxDataSrc( settings, json ); 16760 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 16761 _fnAddData( settings, data[i] ); 16762 } 16763 16764 _fnReDraw( settings, holdPosition ); 16765 _fnProcessingDisplay( settings, false ); 16766 } ); 16767 } 16768 }; 16769 16770 16771 /** 16772 * Get the JSON response from the last Ajax request that DataTables made to the 16773 * server. Note that this returns the JSON from the first table in the current 16774 * context. 16775 * 16776 * @return {object} JSON received from the server. 16777 */ 16778 _api_register( 'ajax.json()', function () { 16779 var ctx = this.context; 16780 16781 if ( ctx.length > 0 ) { 16782 return ctx[0].json; 16783 } 16784 16785 // else return undefined; 16786 } ); 16787 16788 16789 /** 16790 * Get the data submitted in the last Ajax request 16791 */ 16792 _api_register( 'ajax.params()', function () { 16793 var ctx = this.context; 16794 16795 if ( ctx.length > 0 ) { 16796 return ctx[0].oAjaxData; 16797 } 16798 16799 // else return undefined; 16800 } ); 16801 16802 16803 /** 16804 * Reload tables from the Ajax data source. Note that this function will 16805 * automatically re-draw the table when the remote data has been loaded. 16806 * 16807 * @param {boolean} [reset=true] Reset (default) or hold the current paging 16808 * position. A full re-sort and re-filter is performed when this method is 16809 * called, which is why the pagination reset is the default action. 16810 * @returns {DataTables.Api} this 16811 */ 16812 _api_register( 'ajax.reload()', function ( callback, resetPaging ) { 16813 return this.iterator( 'table', function (settings) { 16814 __reload( settings, resetPaging===false, callback ); 16815 } ); 16816 } ); 16817 16818 16819 /** 16820 * Get the current Ajax URL. Note that this returns the URL from the first 16821 * table in the current context. 16822 * 16823 * @return {string} Current Ajax source URL 16824 *//** 16825 * Set the Ajax URL. Note that this will set the URL for all tables in the 16826 * current context. 16827 * 16828 * @param {string} url URL to set. 16829 * @returns {DataTables.Api} this 16830 */ 16831 _api_register( 'ajax.url()', function ( url ) { 16832 var ctx = this.context; 16833 16834 if ( url === undefined ) { 16835 // get 16836 if ( ctx.length === 0 ) { 16837 return undefined; 16838 } 16839 ctx = ctx[0]; 16840 16841 return ctx.ajax ? 16842 $.isPlainObject( ctx.ajax ) ? 16843 ctx.ajax.url : 16844 ctx.ajax : 16845 ctx.sAjaxSource; 16846 } 16847 16848 // set 16849 return this.iterator( 'table', function ( settings ) { 16850 if ( $.isPlainObject( settings.ajax ) ) { 16851 settings.ajax.url = url; 16852 } 16853 else { 16854 settings.ajax = url; 16855 } 16856 // No need to consider sAjaxSource here since DataTables gives priority 16857 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any 16858 // value of `sAjaxSource` redundant. 16859 } ); 16860 } ); 16861 16862 16863 /** 16864 * Load data from the newly set Ajax URL. Note that this method is only 16865 * available when `ajax.url()` is used to set a URL. Additionally, this method 16866 * has the same effect as calling `ajax.reload()` but is provided for 16867 * convenience when setting a new URL. Like `ajax.reload()` it will 16868 * automatically redraw the table once the remote data has been loaded. 16869 * 16870 * @returns {DataTables.Api} this 16871 */ 16872 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) { 16873 // Same as a reload, but makes sense to present it for easy access after a 16874 // url change 16875 return this.iterator( 'table', function ( ctx ) { 16876 __reload( ctx, resetPaging===false, callback ); 16877 } ); 16878 } ); 16879 16880 16881 16882 16883 var _selector_run = function ( type, selector, selectFn, settings, opts ) 16884 { 16885 var 16886 out = [], res, 16887 a, i, ien, j, jen, 16888 selectorType = typeof selector; 16889 16890 // Can't just check for isArray here, as an API or jQuery instance might be 16891 // given with their array like look 16892 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) { 16893 selector = [ selector ]; 16894 } 16895 16896 for ( i=0, ien=selector.length ; i<ien ; i++ ) { 16897 // Only split on simple strings - complex expressions will be jQuery selectors 16898 a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ? 16899 selector[i].split(',') : 16900 [ selector[i] ]; 16901 16902 for ( j=0, jen=a.length ; j<jen ; j++ ) { 16903 res = selectFn( typeof a[j] === 'string' ?
vendor: 47,871 bytes, lines 16903-18703
16903$.trim(a[j]) : a[j] ); 16904 16905 if ( res && res.length ) { 16906 out = out.concat( res ); 16907 } 16908 } 16909 } 16910 16911 // selector extensions 16912 var ext = _ext.selector[ type ]; 16913 if ( ext.length ) { 16914 for ( i=0, ien=ext.length ; i<ien ; i++ ) { 16915 out = ext[i]( settings, opts, out ); 16916 } 16917 } 16918 16919 return _unique( out ); 16920 }; 16921 16922 16923 var _selector_opts = function ( opts ) 16924 { 16925 if ( ! opts ) { 16926 opts = {}; 16927 } 16928 16929 // Backwards compatibility for 1.9- which used the terminology filter rather 16930 // than search 16931 if ( opts.filter && opts.search === undefined ) { 16932 opts.search = opts.filter; 16933 } 16934 16935 return $.extend( { 16936 search: 'none', 16937 order: 'current', 16938 page: 'all' 16939 }, opts ); 16940 }; 16941 16942 16943 var _selector_first = function ( inst ) 16944 { 16945 // Reduce the API instance to the first item found 16946 for ( var i=0, ien=inst.length ; i<ien ; i++ ) { 16947 if ( inst[i].length > 0 ) { 16948 // Assign the first element to the first item in the instance 16949 // and truncate the instance and context 16950 inst[0] = inst[i]; 16951 inst[0].length = 1; 16952 inst.length = 1; 16953 inst.context = [ inst.context[i] ]; 16954 16955 return inst; 16956 } 16957 } 16958 16959 // Not found - return an empty instance 16960 inst.length = 0; 16961 return inst; 16962 }; 16963 16964 16965 var _selector_row_indexes = function ( settings, opts ) 16966 { 16967 var 16968 i, ien, tmp, a=[], 16969 displayFiltered = settings.aiDisplay, 16970 displayMaster = settings.aiDisplayMaster; 16971 16972 var 16973 search = opts.search, // none, applied, removed 16974 order = opts.order, // applied, current, index (original - compatibility with 1.9) 16975 page = opts.page; // all, current 16976 16977 if ( _fnDataSource( settings ) == 'ssp' ) { 16978 // In server-side processing mode, most options are irrelevant since 16979 // rows not shown don't exist and the index order is the applied order 16980 // Removed is a special case - for consistency just return an empty 16981 // array 16982 return search === 'removed' ? 16983 [] : 16984 _range( 0, displayMaster.length ); 16985 } 16986 else if ( page == 'current' ) { 16987 // Current page implies that order=current and fitler=applied, since it is 16988 // fairly senseless otherwise, regardless of what order and search actually 16989 // are 16990 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) { 16991 a.push( displayFiltered[i] ); 16992 } 16993 } 16994 else if ( order == 'current' || order == 'applied' ) { 16995 if ( search == 'none') { 16996 a = displayMaster.slice(); 16997 } 16998 else if ( search == 'applied' ) { 16999 a = displayFiltered.slice(); 17000 } 17001 else if ( search == 'removed' ) { 17002 // O(n+m) solution by creating a hash map 17003 var displayFilteredMap = {}; 17004 17005 for ( var i=0, ien=displayFiltered.length ; i<ien ; i++ ) { 17006 displayFilteredMap[displayFiltered[i]] = null; 17007 } 17008 17009 a = $.map( displayMaster, function (el) { 17010 return ! displayFilteredMap.hasOwnProperty(el) ? 17011 el : 17012 null; 17013 } ); 17014 } 17015 } 17016 else if ( order == 'index' || order == 'original' ) { 17017 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 17018 if ( search == 'none' ) { 17019 a.push( i ); 17020 } 17021 else { // applied | removed 17022 tmp = $.inArray( i, displayFiltered ); 17023 17024 if ((tmp === -1 && search == 'removed') || 17025 (tmp >= 0 && search == 'applied') ) 17026 { 17027 a.push( i ); 17028 } 17029 } 17030 } 17031 } 17032 17033 return a; 17034 }; 17035 17036 17037 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 17038 * Rows 17039 * 17040 * {} - no selector - use all available rows 17041 * {integer} - row aoData index 17042 * {node} - TR node 17043 * {string} - jQuery selector to apply to the TR elements 17044 * {array} - jQuery array of nodes, or simply an array of TR nodes 17045 * 17046 */ 17047 var __row_selector = function ( settings, selector, opts ) 17048 { 17049 var rows; 17050 var run = function ( sel ) { 17051 var selInt = _intVal( sel ); 17052 var i, ien; 17053 var aoData = settings.aoData; 17054 17055 // Short cut - selector is a number and no options provided (default is 17056 // all records, so no need to check if the index is in there, since it 17057 // must be - dev error if the index doesn't exist). 17058 if ( selInt !== null && ! opts ) { 17059 return [ selInt ]; 17060 } 17061 17062 if ( ! rows ) { 17063 rows = _selector_row_indexes( settings, opts ); 17064 } 17065 17066 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) { 17067 // Selector - integer 17068 return [ selInt ]; 17069 } 17070 else if ( sel === null || sel === undefined || sel === '' ) { 17071 // Selector - none 17072 return rows; 17073 } 17074 17075 // Selector - function 17076 if ( typeof sel === 'function' ) { 17077 return $.map( rows, function (idx) { 17078 var row = aoData[ idx ]; 17079 return sel( idx, row._aData, row.nTr ) ? idx : null; 17080 } ); 17081 } 17082 17083 // Selector - node 17084 if ( sel.nodeName ) { 17085 var rowIdx = sel._DT_RowIndex; // Property added by DT for fast lookup 17086 var cellIdx = sel._DT_CellIndex; 17087 17088 if ( rowIdx !== undefined ) { 17089 // Make sure that the row is actually still present in the table 17090 return aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ? 17091 [ rowIdx ] : 17092 []; 17093 } 17094 else if ( cellIdx ) { 17095 return aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel ? 17096 [ cellIdx.row ] : 17097 []; 17098 } 17099 else { 17100 var host = $(sel).closest('*[data-dt-row]'); 17101 return host.length ? 17102 [ host.data('dt-row') ] : 17103 []; 17104 } 17105 } 17106 17107 // ID selector. Want to always be able to select rows by id, regardless 17108 // of if the tr element has been created or not, so can't rely upon 17109 // jQuery here - hence a custom implementation. This does not match 17110 // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything, 17111 // but to select it using a CSS selector engine (like Sizzle or 17112 // querySelect) it would need to need to be escaped for some characters. 17113 // DataTables simplifies this for row selectors since you can select 17114 // only a row. A # indicates an id any anything that follows is the id - 17115 // unescaped. 17116 if ( typeof sel === 'string' && sel.charAt(0) === '#' ) { 17117 // get row index from id 17118 var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ]; 17119 if ( rowObj !== undefined ) { 17120 return [ rowObj.idx ]; 17121 } 17122 17123 // need to fall through to jQuery in case there is DOM id that 17124 // matches 17125 } 17126 17127 // Get nodes in the order from the `rows` array with null values removed 17128 var nodes = _removeEmpty( 17129 _pluck_order( settings.aoData, rows, 'nTr' ) 17130 ); 17131 17132 // Selector - jQuery selector string, array of nodes or jQuery object/ 17133 // As jQuery's .filter() allows jQuery objects to be passed in filter, 17134 // it also allows arrays, so this will cope with all three options 17135 return $(nodes) 17136 .filter( sel ) 17137 .map( function () { 17138 return this._DT_RowIndex; 17139 } ) 17140 .toArray(); 17141 }; 17142 17143 return _selector_run( 'row', selector, run, settings, opts ); 17144 }; 17145 17146 17147 _api_register( 'rows()', function ( selector, opts ) { 17148 // argument shifting 17149 if ( selector === undefined ) { 17150 selector = ''; 17151 } 17152 else if ( $.isPlainObject( selector ) ) { 17153 opts = selector; 17154 selector = ''; 17155 } 17156 17157 opts = _selector_opts( opts ); 17158 17159 var inst = this.iterator( 'table', function ( settings ) { 17160 return __row_selector( settings, selector, opts ); 17161 }, 1 ); 17162 17163 // Want argument shifting here and in __row_selector? 17164 inst.selector.rows = selector; 17165 inst.selector.opts = opts; 17166 17167 return inst; 17168 } ); 17169 17170 _api_register( 'rows().nodes()', function () { 17171 return this.iterator( 'row', function ( settings, row ) { 17172 return settings.aoData[ row ].nTr || undefined; 17173 }, 1 ); 17174 } ); 17175 17176 _api_register( 'rows().data()', function () { 17177 return this.iterator( true, 'rows', function ( settings, rows ) { 17178 return _pluck_order( settings.aoData, rows, '_aData' ); 17179 }, 1 ); 17180 } ); 17181 17182 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) { 17183 return this.iterator( 'row', function ( settings, row ) { 17184 var r = settings.aoData[ row ]; 17185 return type === 'search' ? r._aFilterData : r._aSortData; 17186 }, 1 ); 17187 } ); 17188 17189 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) { 17190 return this.iterator( 'row', function ( settings, row ) { 17191 _fnInvalidate( settings, row, src ); 17192 } ); 17193 } ); 17194 17195 _api_registerPlural( 'rows().indexes()', 'row().index()', function () { 17196 return this.iterator( 'row', function ( settings, row ) { 17197 return row; 17198 }, 1 ); 17199 } ); 17200 17201 _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) { 17202 var a = []; 17203 var context = this.context; 17204 17205 // `iterator` will drop undefined values, but in this case we want them 17206 for ( var i=0, ien=context.length ; i<ien ; i++ ) { 17207 for ( var j=0, jen=this[i].length ; j<jen ; j++ ) { 17208 var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData ); 17209 a.push( (hash === true ? '#' : '' )+ id ); 17210 } 17211 } 17212 17213 return new _Api( context, a ); 17214 } ); 17215 17216 _api_registerPlural( 'rows().remove()', 'row().remove()', function () { 17217 var that = this; 17218 17219 this.iterator( 'row', function ( settings, row, thatIdx ) { 17220 var data = settings.aoData; 17221 var rowData = data[ row ]; 17222 var i, ien, j, jen; 17223 var loopRow, loopCells; 17224 17225 data.splice( row, 1 ); 17226 17227 // Update the cached indexes 17228 for ( i=0, ien=data.length ; i<ien ; i++ ) { 17229 loopRow = data[i]; 17230 loopCells = loopRow.anCells; 17231 17232 // Rows 17233 if ( loopRow.nTr !== null ) { 17234 loopRow.nTr._DT_RowIndex = i; 17235 } 17236 17237 // Cells 17238 if ( loopCells !== null ) { 17239 for ( j=0, jen=loopCells.length ; j<jen ; j++ ) { 17240 loopCells[j]._DT_CellIndex.row = i; 17241 } 17242 } 17243 } 17244 17245 // Delete from the display arrays 17246 _fnDeleteIndex( settings.aiDisplayMaster, row ); 17247 _fnDeleteIndex( settings.aiDisplay, row ); 17248 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes 17249 17250 // For server-side processing tables - subtract the deleted row from the count 17251 if ( settings._iRecordsDisplay > 0 ) { 17252 settings._iRecordsDisplay--; 17253 } 17254 17255 // Check for an 'overflow' they case for displaying the table 17256 _fnLengthOverflow( settings ); 17257 17258 // Remove the row's ID reference if there is one 17259 var id = settings.rowIdFn( rowData._aData ); 17260 if ( id !== undefined ) { 17261 delete settings.aIds[ id ]; 17262 } 17263 } ); 17264 17265 this.iterator( 'table', function ( settings ) { 17266 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 17267 settings.aoData[i].idx = i; 17268 } 17269 } ); 17270 17271 return this; 17272 } ); 17273 17274 17275 _api_register( 'rows.add()', function ( rows ) { 17276 var newRows = this.iterator( 'table', function ( settings ) { 17277 var row, i, ien; 17278 var out = []; 17279 17280 for ( i=0, ien=rows.length ; i<ien ; i++ ) { 17281 row = rows[i]; 17282 17283 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { 17284 out.push( _fnAddTr( settings, row )[0] ); 17285 } 17286 else { 17287 out.push( _fnAddData( settings, row ) ); 17288 } 17289 } 17290 17291 return out; 17292 }, 1 ); 17293 17294 // Return an Api.rows() extended instance, so rows().nodes() etc can be used 17295 var modRows = this.rows( -1 ); 17296 modRows.pop(); 17297 $.merge( modRows, newRows ); 17298 17299 return modRows; 17300 } ); 17301 17302 17303 17304 17305 17306 /** 17307 * 17308 */ 17309 _api_register( 'row()', function ( selector, opts ) { 17310 return _selector_first( this.rows( selector, opts ) ); 17311 } ); 17312 17313 17314 _api_register( 'row().data()', function ( data ) { 17315 var ctx = this.context; 17316 17317 if ( data === undefined ) { 17318 // Get 17319 return ctx.length && this.length ? 17320 ctx[0].aoData[ this[0] ]._aData : 17321 undefined; 17322 } 17323 17324 // Set 17325 var row = ctx[0].aoData[ this[0] ]; 17326 row._aData = data; 17327 17328 // If the DOM has an id, and the data source is an array 17329 if ( $.isArray( data ) && row.nTr.id ) { 17330 _fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id ); 17331 } 17332 17333 // Automatically invalidate 17334 _fnInvalidate( ctx[0], this[0], 'data' ); 17335 17336 return this; 17337 } ); 17338 17339 17340 _api_register( 'row().node()', function () { 17341 var ctx = this.context; 17342 17343 return ctx.length && this.length ? 17344 ctx[0].aoData[ this[0] ].nTr || null : 17345 null; 17346 } ); 17347 17348 17349 _api_register( 'row.add()', function ( row ) { 17350 // Allow a jQuery object to be passed in - only a single row is added from 17351 // it though - the first element in the set 17352 if ( row instanceof $ && row.length ) { 17353 row = row[0]; 17354 } 17355 17356 var rows = this.iterator( 'table', function ( settings ) { 17357 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { 17358 return _fnAddTr( settings, row )[0]; 17359 } 17360 return _fnAddData( settings, row ); 17361 } ); 17362 17363 // Return an Api.rows() extended instance, with the newly added row selected 17364 return this.row( rows[0] ); 17365 } ); 17366 17367 17368 17369 var __details_add = function ( ctx, row, data, klass ) 17370 { 17371 // Convert to array of TR elements 17372 var rows = []; 17373 var addRow = function ( r, k ) { 17374 // Recursion to allow for arrays of jQuery objects 17375 if ( $.isArray( r ) || r instanceof $ ) { 17376 for ( var i=0, ien=r.length ; i<ien ; i++ ) { 17377 addRow( r[i], k ); 17378 } 17379 return; 17380 } 17381 17382 // If we get a TR element, then just add it directly - up to the dev 17383 // to add the correct number of columns etc 17384 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) { 17385 rows.push( r ); 17386 } 17387 else { 17388 // Otherwise create a row with a wrapper 17389 var created = $('<tr><td/></tr>').addClass( k ); 17390 $('td', created) 17391 .addClass( k ) 17392 .html( r ) 17393 [0].colSpan = _fnVisbleColumns( ctx ); 17394 17395 rows.push( created[0] ); 17396 } 17397 }; 17398 17399 addRow( data, klass ); 17400 17401 if ( row._details ) { 17402 row._details.detach(); 17403 } 17404 17405 row._details = $(rows); 17406 17407 // If the children were already shown, that state should be retained 17408 if ( row._detailsShow ) { 17409 row._details.insertAfter( row.nTr ); 17410 } 17411 }; 17412 17413 17414 var __details_remove = function ( api, idx ) 17415 { 17416 var ctx = api.context; 17417 17418 if ( ctx.length ) { 17419 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ]; 17420 17421 if ( row && row._details ) { 17422 row._details.remove(); 17423 17424 row._detailsShow = undefined; 17425 row._details = undefined; 17426 } 17427 } 17428 }; 17429 17430 17431 var __details_display = function ( api, show ) { 17432 var ctx = api.context; 17433 17434 if ( ctx.length && api.length ) { 17435 var row = ctx[0].aoData[ api[0] ]; 17436 17437 if ( row._details ) { 17438 row._detailsShow = show; 17439 17440 if ( show ) { 17441 row._details.insertAfter( row.nTr ); 17442 } 17443 else { 17444 row._details.detach(); 17445 } 17446 17447 __details_events( ctx[0] ); 17448 } 17449 } 17450 }; 17451 17452 17453 var __details_events = function ( settings ) 17454 { 17455 var api = new _Api( settings ); 17456 var namespace = '.dt.DT_details'; 17457 var drawEvent = 'draw'+namespace; 17458 var colvisEvent = 'column-visibility'+namespace; 17459 var destroyEvent = 'destroy'+namespace; 17460 var data = settings.aoData; 17461 17462 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent ); 17463 17464 if ( _pluck( data, '_details' ).length > 0 ) { 17465 // On each draw, insert the required elements into the document 17466 api.on( drawEvent, function ( e, ctx ) { 17467 if ( settings !== ctx ) { 17468 return; 17469 } 17470 17471 api.rows( {page:'current'} ).eq(0).each( function (idx) { 17472 // Internal data grab 17473 var row = data[ idx ]; 17474 17475 if ( row._detailsShow ) { 17476 row._details.insertAfter( row.nTr ); 17477 } 17478 } ); 17479 } ); 17480 17481 // Column visibility change - update the colspan 17482 api.on( colvisEvent, function ( e, ctx, idx, vis ) { 17483 if ( settings !== ctx ) { 17484 return; 17485 } 17486 17487 // Update the colspan for the details rows (note, only if it already has 17488 // a colspan) 17489 var row, visible = _fnVisbleColumns( ctx ); 17490 17491 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 17492 row = data[i]; 17493 17494 if ( row._details ) { 17495 row._details.children('td[colspan]').attr('colspan', visible ); 17496 } 17497 } 17498 } ); 17499 17500 // Table destroyed - nuke any child rows 17501 api.on( destroyEvent, function ( e, ctx ) { 17502 if ( settings !== ctx ) { 17503 return; 17504 } 17505 17506 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 17507 if ( data[i]._details ) { 17508 __details_remove( api, i ); 17509 } 17510 } 17511 } ); 17512 } 17513 }; 17514 17515 // Strings for the method names to help minification 17516 var _emp = ''; 17517 var _child_obj = _emp+'row().child'; 17518 var _child_mth = _child_obj+'()'; 17519 17520 // data can be: 17521 // tr 17522 // string 17523 // jQuery or array of any of the above 17524 _api_register( _child_mth, function ( data, klass ) { 17525 var ctx = this.context; 17526 17527 if ( data === undefined ) { 17528 // get 17529 return ctx.length && this.length ? 17530 ctx[0].aoData[ this[0] ]._details : 17531 undefined; 17532 } 17533 else if ( data === true ) { 17534 // show 17535 this.child.show(); 17536 } 17537 else if ( data === false ) { 17538 // remove 17539 __details_remove( this ); 17540 } 17541 else if ( ctx.length && this.length ) { 17542 // set 17543 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass ); 17544 } 17545 17546 return this; 17547 } ); 17548 17549 17550 _api_register( [ 17551 _child_obj+'.show()', 17552 _child_mth+'.show()' // only when `child()` was called with parameters (without 17553 ], function ( show ) { // it returns an object and this method is not executed) 17554 __details_display( this, true ); 17555 return this; 17556 } ); 17557 17558 17559 _api_register( [ 17560 _child_obj+'.hide()', 17561 _child_mth+'.hide()' // only when `child()` was called with parameters (without 17562 ], function () { // it returns an object and this method is not executed) 17563 __details_display( this, false ); 17564 return this; 17565 } ); 17566 17567 17568 _api_register( [ 17569 _child_obj+'.remove()', 17570 _child_mth+'.remove()' // only when `child()` was called with parameters (without 17571 ], function () { // it returns an object and this method is not executed) 17572 __details_remove( this ); 17573 return this; 17574 } ); 17575 17576 17577 _api_register( _child_obj+'.isShown()', function () { 17578 var ctx = this.context; 17579 17580 if ( ctx.length && this.length ) { 17581 // _detailsShown as false or undefined will fall through to return false 17582 return ctx[0].aoData[ this[0] ]._detailsShow || false; 17583 } 17584 return false; 17585 } ); 17586 17587 17588 17589 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 17590 * Columns 17591 * 17592 * {integer} - column index (>=0 count from left, <0 count from right) 17593 * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right) 17594 * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right) 17595 * "{string}:name" - column name 17596 * "{string}" - jQuery selector on column header nodes 17597 * 17598 */ 17599 17600 // can be an array of these items, comma separated list, or an array of comma 17601 // separated lists 17602 17603 var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/; 17604 17605 17606 // r1 and r2 are redundant - but it means that the parameters match for the 17607 // iterator callback in columns().data() 17608 var __columnData = function ( settings, column, r1, r2, rows ) { 17609 var a = []; 17610 for ( var row=0, ien=rows.length ; row<ien ; row++ ) { 17611 a.push( _fnGetCellData( settings, rows[row], column ) ); 17612 } 17613 return a; 17614 }; 17615 17616 17617 var __column_selector = function ( settings, selector, opts ) 17618 { 17619 var 17620 columns = settings.aoColumns, 17621 names = _pluck( columns, 'sName' ), 17622 nodes = _pluck( columns, 'nTh' ); 17623 17624 var run = function ( s ) { 17625 var selInt = _intVal( s ); 17626 17627 // Selector - all 17628 if ( s === '' ) { 17629 return _range( columns.length ); 17630 } 17631 17632 // Selector - index 17633 if ( selInt !== null ) { 17634 return [ selInt >= 0 ? 17635 selInt : // Count from left 17636 columns.length + selInt // Count from right (+ because its a negative value) 17637 ]; 17638 } 17639 17640 // Selector = function 17641 if ( typeof s === 'function' ) { 17642 var rows = _selector_row_indexes( settings, opts ); 17643 17644 return $.map( columns, function (col, idx) { 17645 return s( 17646 idx, 17647 __columnData( settings, idx, 0, 0, rows ), 17648 nodes[ idx ] 17649 ) ? idx : null; 17650 } ); 17651 } 17652 17653 // jQuery or string selector 17654 var match = typeof s === 'string' ? 17655 s.match( __re_column_selector ) : 17656 ''; 17657 17658 if ( match ) { 17659 switch( match[2] ) { 17660 case 'visIdx': 17661 case 'visible': 17662 var idx = parseInt( match[1], 10 ); 17663 // Visible index given, convert to column index 17664 if ( idx < 0 ) { 17665 // Counting from the right 17666 var visColumns = $.map( columns, function (col,i) { 17667 return col.bVisible ? i : null; 17668 } ); 17669 return [ visColumns[ visColumns.length + idx ] ]; 17670 } 17671 // Counting from the left 17672 return [ _fnVisibleToColumnIndex( settings, idx ) ]; 17673 17674 case 'name': 17675 // match by name. `names` is column index complete and in order 17676 return $.map( names, function (name, i) { 17677 return name === match[1] ? i : null; 17678 } ); 17679 17680 default: 17681 return []; 17682 } 17683 } 17684 17685 // Cell in the table body 17686 if ( s.nodeName && s._DT_CellIndex ) { 17687 return [ s._DT_CellIndex.column ]; 17688 } 17689 17690 // jQuery selector on the TH elements for the columns 17691 var jqResult = $( nodes ) 17692 .filter( s ) 17693 .map( function () { 17694 return $.inArray( this, nodes ); // `nodes` is column index complete and in order 17695 } ) 17696 .toArray(); 17697 17698 if ( jqResult.length || ! s.nodeName ) { 17699 return jqResult; 17700 } 17701 17702 // Otherwise a node which might have a `dt-column` data attribute, or be 17703 // a child or such an element 17704 var host = $(s).closest('*[data-dt-column]'); 17705 return host.length ? 17706 [ host.data('dt-column') ] : 17707 []; 17708 }; 17709 17710 return _selector_run( 'column', selector, run, settings, opts ); 17711 }; 17712 17713 17714 var __setColumnVis = function ( settings, column, vis ) { 17715 var 17716 cols = settings.aoColumns, 17717 col = cols[ column ], 17718 data = settings.aoData, 17719 row, cells, i, ien, tr; 17720 17721 // Get 17722 if ( vis === undefined ) { 17723 return col.bVisible; 17724 } 17725 17726 // Set 17727 // No change 17728 if ( col.bVisible === vis ) { 17729 return; 17730 } 17731 17732 if ( vis ) { 17733 // Insert column 17734 // Need to decide if we should use appendChild or insertBefore 17735 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 ); 17736 17737 for ( i=0, ien=data.length ; i<ien ; i++ ) { 17738 tr = data[i].nTr; 17739 cells = data[i].anCells; 17740 17741 if ( tr ) { 17742 // insertBefore can act like appendChild if 2nd arg is null 17743 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null ); 17744 } 17745 } 17746 } 17747 else { 17748 // Remove column 17749 $( _pluck( settings.aoData, 'anCells', column ) ).detach(); 17750 } 17751 17752 // Common actions 17753 col.bVisible = vis; 17754 _fnDrawHead( settings, settings.aoHeader ); 17755 _fnDrawHead( settings, settings.aoFooter ); 17756 17757 // Update colspan for no records display. Child rows and extensions will use their own 17758 // listeners to do this - only need to update the empty table item here 17759 if ( ! settings.aiDisplay.length ) { 17760 $(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings)); 17761 } 17762 17763 _fnSaveState( settings ); 17764 }; 17765 17766 17767 _api_register( 'columns()', function ( selector, opts ) { 17768 // argument shifting 17769 if ( selector === undefined ) { 17770 selector = ''; 17771 } 17772 else if ( $.isPlainObject( selector ) ) { 17773 opts = selector; 17774 selector = ''; 17775 } 17776 17777 opts = _selector_opts( opts ); 17778 17779 var inst = this.iterator( 'table', function ( settings ) { 17780 return __column_selector( settings, selector, opts ); 17781 }, 1 ); 17782 17783 // Want argument shifting here and in _row_selector? 17784 inst.selector.cols = selector; 17785 inst.selector.opts = opts; 17786 17787 return inst; 17788 } ); 17789 17790 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) { 17791 return this.iterator( 'column', function ( settings, column ) { 17792 return settings.aoColumns[column].nTh; 17793 }, 1 ); 17794 } ); 17795 17796 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) { 17797 return this.iterator( 'column', function ( settings, column ) { 17798 return settings.aoColumns[column].nTf; 17799 }, 1 ); 17800 } ); 17801 17802 _api_registerPlural( 'columns().data()', 'column().data()', function () { 17803 return this.iterator( 'column-rows', __columnData, 1 ); 17804 } ); 17805 17806 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () { 17807 return this.iterator( 'column', function ( settings, column ) { 17808 return settings.aoColumns[column].mData; 17809 }, 1 ); 17810 } ); 17811 17812 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) { 17813 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { 17814 return _pluck_order( settings.aoData, rows, 17815 type === 'search' ? '_aFilterData' : '_aSortData', column 17816 ); 17817 }, 1 ); 17818 } ); 17819 17820 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () { 17821 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { 17822 return _pluck_order( settings.aoData, rows, 'anCells', column ) ; 17823 }, 1 ); 17824 } ); 17825 17826 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) { 17827 var ret = this.iterator( 'column', function ( settings, column ) { 17828 if ( vis === undefined ) { 17829 return settings.aoColumns[ column ].bVisible; 17830 } // else 17831 __setColumnVis( settings, column, vis ); 17832 } ); 17833 17834 // Group the column visibility changes 17835 if ( vis !== undefined ) { 17836 // Second loop once the first is done for events 17837 this.iterator( 'column', function ( settings, column ) { 17838 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] ); 17839 } ); 17840 17841 if ( calc === undefined || calc ) { 17842 this.columns.adjust(); 17843 } 17844 } 17845 17846 return ret; 17847 } ); 17848 17849 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) { 17850 return this.iterator( 'column', function ( settings, column ) { 17851 return type === 'visible' ? 17852 _fnColumnIndexToVisible( settings, column ) : 17853 column; 17854 }, 1 ); 17855 } ); 17856 17857 _api_register( 'columns.adjust()', function () { 17858 return this.iterator( 'table', function ( settings ) { 17859 _fnAdjustColumnSizing( settings ); 17860 }, 1 ); 17861 } ); 17862 17863 _api_register( 'column.index()', function ( type, idx ) { 17864 if ( this.context.length !== 0 ) { 17865 var ctx = this.context[0]; 17866 17867 if ( type === 'fromVisible' || type === 'toData' ) { 17868 return _fnVisibleToColumnIndex( ctx, idx ); 17869 } 17870 else if ( type === 'fromData' || type === 'toVisible' ) { 17871 return _fnColumnIndexToVisible( ctx, idx ); 17872 } 17873 } 17874 } ); 17875 17876 _api_register( 'column()', function ( selector, opts ) { 17877 return _selector_first( this.columns( selector, opts ) ); 17878 } ); 17879 17880 17881 17882 var __cell_selector = function ( settings, selector, opts ) 17883 { 17884 var data = settings.aoData; 17885 var rows = _selector_row_indexes( settings, opts ); 17886 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) ); 17887 var allCells = $( [].concat.apply([], cells) ); 17888 var row; 17889 var columns = settings.aoColumns.length; 17890 var a, i, ien, j, o, host; 17891 17892 var run = function ( s ) { 17893 var fnSelector = typeof s === 'function'; 17894 17895 if ( s === null || s === undefined || fnSelector ) { 17896 // All cells and function selectors 17897 a = []; 17898 17899 for ( i=0, ien=rows.length ; i<ien ; i++ ) { 17900 row = rows[i]; 17901 17902 for ( j=0 ; j<columns ; j++ ) { 17903 o = { 17904 row: row, 17905 column: j 17906 }; 17907 17908 if ( fnSelector ) { 17909 // Selector - function 17910 host = data[ row ]; 17911 17912 if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) { 17913 a.push( o ); 17914 } 17915 } 17916 else { 17917 // Selector - all 17918 a.push( o ); 17919 } 17920 } 17921 } 17922 17923 return a; 17924 } 17925 17926 // Selector - index 17927 if ( $.isPlainObject( s ) ) { 17928 // Valid cell index and its in the array of selectable rows 17929 return s.column !== undefined && s.row !== undefined && $.inArray( s.row, rows ) !== -1 ? 17930 [s] : 17931 []; 17932 } 17933 17934 // Selector - jQuery filtered cells 17935 var jqResult = allCells 17936 .filter( s ) 17937 .map( function (i, el) { 17938 return { // use a new object, in case someone changes the values 17939 row: el._DT_CellIndex.row, 17940 column: el._DT_CellIndex.column 17941 }; 17942 } ) 17943 .toArray(); 17944 17945 if ( jqResult.length || ! s.nodeName ) { 17946 return jqResult; 17947 } 17948 17949 // Otherwise the selector is a node, and there is one last option - the 17950 // element might be a child of an element which has dt-row and dt-column 17951 // data attributes 17952 host = $(s).closest('*[data-dt-row]'); 17953 return host.length ? 17954 [ { 17955 row: host.data('dt-row'), 17956 column: host.data('dt-column') 17957 } ] : 17958 []; 17959 }; 17960 17961 return _selector_run( 'cell', selector, run, settings, opts ); 17962 }; 17963 17964 17965 17966 17967 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) { 17968 // Argument shifting 17969 if ( $.isPlainObject( rowSelector ) ) { 17970 // Indexes 17971 if ( rowSelector.row === undefined ) { 17972 // Selector options in first parameter 17973 opts = rowSelector; 17974 rowSelector = null; 17975 } 17976 else { 17977 // Cell index objects in first parameter 17978 opts = columnSelector; 17979 columnSelector = null; 17980 } 17981 } 17982 if ( $.isPlainObject( columnSelector ) ) { 17983 opts = columnSelector; 17984 columnSelector = null; 17985 } 17986 17987 // Cell selector 17988 if ( columnSelector === null || columnSelector === undefined ) { 17989 return this.iterator( 'table', function ( settings ) { 17990 return __cell_selector( settings, rowSelector, _selector_opts( opts ) ); 17991 } ); 17992 } 17993 17994 // Row + column selector 17995 var columns = this.columns( columnSelector ); 17996 var rows = this.rows( rowSelector ); 17997 var a, i, ien, j, jen; 17998 17999 this.iterator( 'table', function ( settings, idx ) { 18000 a = []; 18001 18002 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) { 18003 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) { 18004 a.push( { 18005 row: rows[idx][i], 18006 column: columns[idx][j] 18007 } ); 18008 } 18009 } 18010 }, 1 ); 18011 18012 // Now pass through the cell selector for options 18013 var cells = this.cells( a, opts ); 18014 18015 $.extend( cells.selector, { 18016 cols: columnSelector, 18017 rows: rowSelector, 18018 opts: opts 18019 } ); 18020 18021 return cells; 18022 } ); 18023 18024 18025 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () { 18026 return this.iterator( 'cell', function ( settings, row, column ) { 18027 var data = settings.aoData[ row ]; 18028 18029 return data && data.anCells ? 18030 data.anCells[ column ] : 18031 undefined; 18032 }, 1 ); 18033 } ); 18034 18035 18036 _api_register( 'cells().data()', function () { 18037 return this.iterator( 'cell', function ( settings, row, column ) { 18038 return _fnGetCellData( settings, row, column ); 18039 }, 1 ); 18040 } ); 18041 18042 18043 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) { 18044 type = type === 'search' ? '_aFilterData' : '_aSortData'; 18045 18046 return this.iterator( 'cell', function ( settings, row, column ) { 18047 return settings.aoData[ row ][ type ][ column ]; 18048 }, 1 ); 18049 } ); 18050 18051 18052 _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) { 18053 return this.iterator( 'cell', function ( settings, row, column ) { 18054 return _fnGetCellData( settings, row, column, type ); 18055 }, 1 ); 18056 } ); 18057 18058 18059 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () { 18060 return this.iterator( 'cell', function ( settings, row, column ) { 18061 return { 18062 row: row, 18063 column: column, 18064 columnVisible: _fnColumnIndexToVisible( settings, column ) 18065 }; 18066 }, 1 ); 18067 } ); 18068 18069 18070 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) { 18071 return this.iterator( 'cell', function ( settings, row, column ) { 18072 _fnInvalidate( settings, row, src, column ); 18073 } ); 18074 } ); 18075 18076 18077 18078 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) { 18079 return _selector_first( this.cells( rowSelector, columnSelector, opts ) ); 18080 } ); 18081 18082 18083 _api_register( 'cell().data()', function ( data ) { 18084 var ctx = this.context; 18085 var cell = this[0]; 18086 18087 if ( data === undefined ) { 18088 // Get 18089 return ctx.length && cell.length ? 18090 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) : 18091 undefined; 18092 } 18093 18094 // Set 18095 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data ); 18096 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column ); 18097 18098 return this; 18099 } ); 18100 18101 18102 18103 /** 18104 * Get current ordering (sorting) that has been applied to the table. 18105 * 18106 * @returns {array} 2D array containing the sorting information for the first 18107 * table in the current context. Each element in the parent array represents 18108 * a column being sorted upon (i.e. multi-sorting with two columns would have 18109 * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is 18110 * the column index that the sorting condition applies to, the second is the 18111 * direction of the sort (`desc` or `asc`) and, optionally, the third is the 18112 * index of the sorting order from the `column.sorting` initialisation array. 18113 *//** 18114 * Set the ordering for the table. 18115 * 18116 * @param {integer} order Column index to sort upon. 18117 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`) 18118 * @returns {DataTables.Api} this 18119 *//** 18120 * Set the ordering for the table. 18121 * 18122 * @param {array} order 1D array of sorting information to be applied. 18123 * @param {array} [...] Optional additional sorting conditions 18124 * @returns {DataTables.Api} this 18125 *//** 18126 * Set the ordering for the table. 18127 * 18128 * @param {array} order 2D array of sorting information to be applied. 18129 * @returns {DataTables.Api} this 18130 */ 18131 _api_register( 'order()', function ( order, dir ) { 18132 var ctx = this.context; 18133 18134 if ( order === undefined ) { 18135 // get 18136 return ctx.length !== 0 ? 18137 ctx[0].aaSorting : 18138 undefined; 18139 } 18140 18141 // set 18142 if ( typeof order === 'number' ) { 18143 // Simple column / direction passed in 18144 order = [ [ order, dir ] ]; 18145 } 18146 else if ( order.length && ! $.isArray( order[0] ) ) { 18147 // Arguments passed in (list of 1D arrays) 18148 order = Array.prototype.slice.call( arguments ); 18149 } 18150 // otherwise a 2D array was passed in 18151 18152 return this.iterator( 'table', function ( settings ) { 18153 settings.aaSorting = order.slice(); 18154 } ); 18155 } ); 18156 18157 18158 /** 18159 * Attach a sort listener to an element for a given column 18160 * 18161 * @param {node|jQuery|string} node Identifier for the element(s) to attach the 18162 * listener to. This can take the form of a single DOM node, a jQuery 18163 * collection of nodes or a jQuery selector which will identify the node(s). 18164 * @param {integer} column the column that a click on this node will sort on 18165 * @param {function} [callback] callback function when sort is run 18166 * @returns {DataTables.Api} this 18167 */ 18168 _api_register( 'order.listener()', function ( node, column, callback ) { 18169 return this.iterator( 'table', function ( settings ) { 18170 _fnSortAttachListener( settings, node, column, callback ); 18171 } ); 18172 } ); 18173 18174 18175 _api_register( 'order.fixed()', function ( set ) { 18176 if ( ! set ) { 18177 var ctx = this.context; 18178 var fixed = ctx.length ? 18179 ctx[0].aaSortingFixed : 18180 undefined; 18181 18182 return $.isArray( fixed ) ? 18183 { pre: fixed } : 18184 fixed; 18185 } 18186 18187 return this.iterator( 'table', function ( settings ) { 18188 settings.aaSortingFixed = $.extend( true, {}, set ); 18189 } ); 18190 } ); 18191 18192 18193 // Order by the selected column(s) 18194 _api_register( [ 18195 'columns().order()', 18196 'column().order()' 18197 ], function ( dir ) { 18198 var that = this; 18199 18200 return this.iterator( 'table', function ( settings, i ) { 18201 var sort = []; 18202 18203 $.each( that[i], function (j, col) { 18204 sort.push( [ col, dir ] ); 18205 } ); 18206 18207 settings.aaSorting = sort; 18208 } ); 18209 } ); 18210 18211 18212 18213 _api_register( 'search()', function ( input, regex, smart, caseInsen ) { 18214 var ctx = this.context; 18215 18216 if ( input === undefined ) { 18217 // get 18218 return ctx.length !== 0 ? 18219 ctx[0].oPreviousSearch.sSearch : 18220 undefined; 18221 } 18222 18223 // set 18224 return this.iterator( 'table', function ( settings ) { 18225 if ( ! settings.oFeatures.bFilter ) { 18226 return; 18227 } 18228 18229 _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, { 18230 "sSearch": input+"", 18231 "bRegex": regex === null ? false : regex, 18232 "bSmart": smart === null ? true : smart, 18233 "bCaseInsensitive": caseInsen === null ? true : caseInsen 18234 } ), 1 ); 18235 } ); 18236 } ); 18237 18238 18239 _api_registerPlural( 18240 'columns().search()', 18241 'column().search()', 18242 function ( input, regex, smart, caseInsen ) { 18243 return this.iterator( 'column', function ( settings, column ) { 18244 var preSearch = settings.aoPreSearchCols; 18245 18246 if ( input === undefined ) { 18247 // get 18248 return preSearch[ column ].sSearch; 18249 } 18250 18251 // set 18252 if ( ! settings.oFeatures.bFilter ) { 18253 return; 18254 } 18255 18256 $.extend( preSearch[ column ], { 18257 "sSearch": input+"", 18258 "bRegex": regex === null ? false : regex, 18259 "bSmart": smart === null ? true : smart, 18260 "bCaseInsensitive": caseInsen === null ? true : caseInsen 18261 } ); 18262 18263 _fnFilterComplete( settings, settings.oPreviousSearch, 1 ); 18264 } ); 18265 } 18266 ); 18267 18268 /* 18269 * State API methods 18270 */ 18271 18272 _api_register( 'state()', function () { 18273 return this.context.length ? 18274 this.context[0].oSavedState : 18275 null; 18276 } ); 18277 18278 18279 _api_register( 'state.clear()', function () { 18280 return this.iterator( 'table', function ( settings ) { 18281 // Save an empty object 18282 settings.fnStateSaveCallback.call( settings.oInstance, settings, {} ); 18283 } ); 18284 } ); 18285 18286 18287 _api_register( 'state.loaded()', function () { 18288 return this.context.length ? 18289 this.context[0].oLoadedState : 18290 null; 18291 } ); 18292 18293 18294 _api_register( 'state.save()', function () { 18295 return this.iterator( 'table', function ( settings ) { 18296 _fnSaveState( settings ); 18297 } ); 18298 } ); 18299 18300 18301 18302 /** 18303 * Provide a common method for plug-ins to check the version of DataTables being 18304 * used, in order to ensure compatibility. 18305 * 18306 * @param {string} version Version string to check for, in the format "X.Y.Z". 18307 * Note that the formats "X" and "X.Y" are also acceptable. 18308 * @returns {boolean} true if this version of DataTables is greater or equal to 18309 * the required version, or false if this version of DataTales is not 18310 * suitable 18311 * @static 18312 * @dtopt API-Static 18313 * 18314 * @example 18315 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) ); 18316 */ 18317 DataTable.versionCheck = DataTable.fnVersionCheck = function( version ) 18318 { 18319 var aThis = DataTable.version.split('.'); 18320 var aThat = version.split('.'); 18321 var iThis, iThat; 18322 18323 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) { 18324 iThis = parseInt( aThis[i], 10 ) || 0; 18325 iThat = parseInt( aThat[i], 10 ) || 0; 18326 18327 // Parts are the same, keep comparing 18328 if (iThis === iThat) { 18329 continue; 18330 } 18331 18332 // Parts are different, return immediately 18333 return iThis > iThat; 18334 } 18335 18336 return true; 18337 }; 18338 18339 18340 /** 18341 * Check if a `<table>` node is a DataTable table already or not. 18342 * 18343 * @param {node|jquery|string} table Table node, jQuery object or jQuery 18344 * selector for the table to test. Note that if more than more than one 18345 * table is passed on, only the first will be checked 18346 * @returns {boolean} true the table given is a DataTable, or false otherwise 18347 * @static 18348 * @dtopt API-Static 18349 * 18350 * @example 18351 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) { 18352 * $('#example').dataTable(); 18353 * } 18354 */ 18355 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table ) 18356 { 18357 var t = $(table).get(0); 18358 var is = false; 18359 18360 if ( table instanceof DataTable.Api ) { 18361 return true; 18362 } 18363 18364 $.each( DataTable.settings, function (i, o) { 18365 var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null; 18366 var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null; 18367 18368 if ( o.nTable === t || head === t || foot === t ) { 18369 is = true; 18370 } 18371 } ); 18372 18373 return is; 18374 }; 18375 18376 18377 /** 18378 * Get all DataTable tables that have been initialised - optionally you can 18379 * select to get only currently visible tables. 18380 * 18381 * @param {boolean} [visible=false] Flag to indicate if you want all (default) 18382 * or visible tables only. 18383 * @returns {array} Array of `table` nodes (not DataTable instances) which are 18384 * DataTables 18385 * @static 18386 * @dtopt API-Static 18387 * 18388 * @example 18389 * $.each( $.fn.dataTable.tables(true), function () { 18390 * $(table).DataTable().columns.adjust(); 18391 * } ); 18392 */ 18393 DataTable.tables = DataTable.fnTables = function ( visible ) 18394 { 18395 var api = false; 18396 18397 if ( $.isPlainObject( visible ) ) { 18398 api = visible.api; 18399 visible = visible.visible; 18400 } 18401 18402 var a = $.map( DataTable.settings, function (o) { 18403 if ( !visible || (visible && $(o.nTable).is(':visible')) ) { 18404 return o.nTable; 18405 } 18406 } ); 18407 18408 return api ? 18409 new _Api( a ) : 18410 a; 18411 }; 18412 18413 18414 /** 18415 * Convert from camel case parameters to Hungarian notation. This is made public 18416 * for the extensions to provide the same ability as DataTables core to accept 18417 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase 18418 * parameters. 18419 * 18420 * @param {object} src The model object which holds all parameters that can be 18421 * mapped. 18422 * @param {object} user The object to convert from camel case to Hungarian. 18423 * @param {boolean} force When set to `true`, properties which already have a 18424 * Hungarian value in the `user` object will be overwritten. Otherwise they 18425 * won't be. 18426 */ 18427 DataTable.camelToHungarian = _fnCamelToHungarian; 18428 18429 18430 18431 /** 18432 * 18433 */ 18434 _api_register( '$()', function ( selector, opts ) { 18435 var 18436 rows = this.rows( opts ).nodes(), // Get all rows 18437 jqRows = $(rows); 18438 18439 return $( [].concat( 18440 jqRows.filter( selector ).toArray(), 18441 jqRows.find( selector ).toArray() 18442 ) ); 18443 } ); 18444 18445 18446 // jQuery functions to operate on the tables 18447 $.each( [ 'on', 'one', 'off' ], function (i, key) { 18448 _api_register( key+'()', function ( /* event, handler */ ) { 18449 var args = Array.prototype.slice.call(arguments); 18450 18451 // Add the `dt` namespace automatically if it isn't already present 18452 args[0] = $.map( args[0].split( /\s/ ), function ( e ) { 18453 return ! e.match(/\.dt\b/) ? 18454 e+'.dt' : 18455 e; 18456 } ).join( ' ' ); 18457 18458 var inst = $( this.tables().nodes() ); 18459 inst[key].apply( inst, args ); 18460 return this; 18461 } ); 18462 } ); 18463 18464 18465 _api_register( 'clear()', function () { 18466 return this.iterator( 'table', function ( settings ) { 18467 _fnClearTable( settings ); 18468 } ); 18469 } ); 18470 18471 18472 _api_register( 'settings()', function () { 18473 return new _Api( this.context, this.context ); 18474 } ); 18475 18476 18477 _api_register( 'init()', function () { 18478 var ctx = this.context; 18479 return ctx.length ? ctx[0].oInit : null; 18480 } ); 18481 18482 18483 _api_register( 'data()', function () { 18484 return this.iterator( 'table', function ( settings ) { 18485 return _pluck( settings.aoData, '_aData' ); 18486 } ).flatten(); 18487 } ); 18488 18489 18490 _api_register( 'destroy()', function ( remove ) { 18491 remove = remove || false; 18492 18493 return this.iterator( 'table', function ( settings ) { 18494 var orig = settings.nTableWrapper.parentNode; 18495 var classes = settings.oClasses; 18496 var table = settings.nTable; 18497 var tbody = settings.nTBody; 18498 var thead = settings.nTHead; 18499 var tfoot = settings.nTFoot; 18500 var jqTable = $(table); 18501 var jqTbody = $(tbody); 18502 var jqWrapper = $(settings.nTableWrapper); 18503 var rows = $.map( settings.aoData, function (r) { return r.nTr; } ); 18504 var i, ien; 18505 18506 // Flag to note that the table is currently being destroyed - no action 18507 // should be taken 18508 settings.bDestroying = true; 18509 18510 // Fire off the destroy callbacks for plug-ins etc 18511 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] ); 18512 18513 // If not being removed from the document, make all columns visible 18514 if ( ! remove ) { 18515 new _Api( settings ).columns().visible( true ); 18516 } 18517 18518 // Blitz all `DT` namespaced events (these are internal events, the 18519 // lowercase, `dt` events are user subscribed and they are responsible 18520 // for removing them 18521 jqWrapper.off('.DT').find(':not(tbody *)').off('.DT'); 18522 $(window).off('.DT-'+settings.sInstance); 18523 18524 // When scrolling we had to break the table up - restore it 18525 if ( table != thead.parentNode ) { 18526 jqTable.children('thead').detach(); 18527 jqTable.append( thead ); 18528 } 18529 18530 if ( tfoot && table != tfoot.parentNode ) { 18531 jqTable.children('tfoot').detach(); 18532 jqTable.append( tfoot ); 18533 } 18534 18535 settings.aaSorting = []; 18536 settings.aaSortingFixed = []; 18537 _fnSortingClasses( settings ); 18538 18539 $( rows ).removeClass( settings.asStripeClasses.join(' ') ); 18540 18541 $('th, td', thead).removeClass( classes.sSortable+' '+ 18542 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone 18543 ); 18544 18545 // Add the TR elements back into the table in their original order 18546 jqTbody.children().detach(); 18547 jqTbody.append( rows ); 18548 18549 // Remove the DataTables generated nodes, events and classes 18550 var removedMethod = remove ? 'remove' : 'detach'; 18551 jqTable[ removedMethod ](); 18552 jqWrapper[ removedMethod ](); 18553 18554 // If we need to reattach the table to the document 18555 if ( ! remove && orig ) { 18556 // insertBefore acts like appendChild if !arg[1] 18557 orig.insertBefore( table, settings.nTableReinsertBefore ); 18558 18559 // Restore the width of the original table - was read from the style property, 18560 // so we can restore directly to that 18561 jqTable 18562 .css( 'width', settings.sDestroyWidth ) 18563 .removeClass( classes.sTable ); 18564 18565 // If the were originally stripe classes - then we add them back here. 18566 // Note this is not fool proof (for example if not all rows had stripe 18567 // classes - but it's a good effort without getting carried away 18568 ien = settings.asDestroyStripes.length; 18569 18570 if ( ien ) { 18571 jqTbody.children().each( function (i) { 18572 $(this).addClass( settings.asDestroyStripes[i % ien] ); 18573 } ); 18574 } 18575 } 18576 18577 /* Remove the settings object from the settings array */ 18578 var idx = $.inArray( settings, DataTable.settings ); 18579 if ( idx !== -1 ) { 18580 DataTable.settings.splice( idx, 1 ); 18581 } 18582 } ); 18583 } ); 18584 18585 18586 // Add the `every()` method for rows, columns and cells in a compact form 18587 $.each( [ 'column', 'row', 'cell' ], function ( i, type ) { 18588 _api_register( type+'s().every()', function ( fn ) { 18589 var opts = this.selector.opts; 18590 var api = this; 18591 18592 return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) { 18593 // Rows and columns: 18594 // arg1 - index 18595 // arg2 - table counter 18596 // arg3 - loop counter 18597 // arg4 - undefined 18598 // Cells: 18599 // arg1 - row index 18600 // arg2 - column index 18601 // arg3 - table counter 18602 // arg4 - loop counter 18603 fn.call( 18604 api[ type ]( 18605 arg1, 18606 type==='cell' ? arg2 : opts, 18607 type==='cell' ? opts : undefined 18608 ), 18609 arg1, arg2, arg3, arg4 18610 ); 18611 } ); 18612 } ); 18613 } ); 18614 18615 18616 // i18n method for extensions to be able to use the language object from the 18617 // DataTable 18618 _api_register( 'i18n()', function ( token, def, plural ) { 18619 var ctx = this.context[0]; 18620 var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage ); 18621 18622 if ( resolved === undefined ) { 18623 resolved = def; 18624 } 18625 18626 if ( plural !== undefined && $.isPlainObject( resolved ) ) { 18627 resolved = resolved[ plural ] !== undefined ? 18628 resolved[ plural ] : 18629 resolved._; 18630 } 18631 18632 return resolved.replace( '%d', plural ); // nb: plural might be undefined, 18633 } ); 18634 18635 /** 18636 * Version string for plug-ins to check compatibility. Allowed format is 18637 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used 18638 * only for non-release builds. See http://semver.org/ for more information. 18639 * @member 18640 * @type string 18641 * @default Version number 18642 */ 18643 DataTable.version = "1.10.18"; 18644 18645 /** 18646 * Private data store, containing all of the settings objects that are 18647 * created for the tables on a given page. 18648 * 18649 * Note that the `DataTable.settings` object is aliased to 18650 * `jQuery.fn.dataTableExt` through which it may be accessed and 18651 * manipulated, or `jQuery.fn.dataTable.settings`. 18652 * @member 18653 * @type array 18654 * @default [] 18655 * @private 18656 */ 18657 DataTable.settings = []; 18658 18659 /** 18660 * Object models container, for the various models that DataTables has 18661 * available to it. These models define the objects that are used to hold 18662 * the active state and configuration of the table. 18663 * @namespace 18664 */ 18665 DataTable.models = {}; 18666 18667 18668 18669 /** 18670 * Template object for the way in which DataTables holds information about 18671 * search information for the global filter and individual column filters. 18672 * @namespace 18673 */ 18674 DataTable.models.oSearch = { 18675 /** 18676 * Flag to indicate if the filtering should be case insensitive or not 18677 * @type boolean 18678 * @default true 18679 */ 18680 "bCaseInsensitive": true, 18681 18682 /** 18683 * Applied search term 18684 * @type string 18685 * @default <i>Empty string</i> 18686 */ 18687 "sSearch": "", 18688 18689 /** 18690 * Flag to indicate if the search term should be interpreted as a 18691 * regular expression (true) or not (false) and therefore and special 18692 * regex characters escaped. 18693 * @type boolean 18694 * @default false 18695 */ 18696 "bRegex": false, 18697 18698 /** 18699 * Flag to indicate if DataTables is to use its smart filtering or not. 18700 * @type boolean 18701 * @default true 18702 */ 18703 "bSmart": tru
vendor: 11,217 bytes, lines 18703-19061
18703e 18704 }; 18705 18706 18707 18708 18709 /** 18710 * Template object for the way in which DataTables holds information about 18711 * each individual row. This is the object format used for the settings 18712 * aoData array. 18713 * @namespace 18714 */ 18715 DataTable.models.oRow = { 18716 /** 18717 * TR element for the row 18718 * @type node 18719 * @default null 18720 */ 18721 "nTr": null, 18722 18723 /** 18724 * Array of TD elements for each row. This is null until the row has been 18725 * created. 18726 * @type array nodes 18727 * @default [] 18728 */ 18729 "anCells": null, 18730 18731 /** 18732 * Data object from the original data source for the row. This is either 18733 * an array if using the traditional form of DataTables, or an object if 18734 * using mData options. The exact type will depend on the passed in 18735 * data from the data source, or will be an array if using DOM a data 18736 * source. 18737 * @type array|object 18738 * @default [] 18739 */ 18740 "_aData": [], 18741 18742 /** 18743 * Sorting data cache - this array is ostensibly the same length as the 18744 * number of columns (although each index is generated only as it is 18745 * needed), and holds the data that is used for sorting each column in the 18746 * row. We do this cache generation at the start of the sort in order that 18747 * the formatting of the sort data need be done only once for each cell 18748 * per sort. This array should not be read from or written to by anything 18749 * other than the master sorting methods. 18750 * @type array 18751 * @default null 18752 * @private 18753 */ 18754 "_aSortData": null, 18755 18756 /** 18757 * Per cell filtering data cache. As per the sort data cache, used to 18758 * increase the performance of the filtering in DataTables 18759 * @type array 18760 * @default null 18761 * @private 18762 */ 18763 "_aFilterData": null, 18764 18765 /** 18766 * Filtering data cache. This is the same as the cell filtering cache, but 18767 * in this case a string rather than an array. This is easily computed with 18768 * a join on `_aFilterData`, but is provided as a cache so the join isn't 18769 * needed on every search (memory traded for performance) 18770 * @type array 18771 * @default null 18772 * @private 18773 */ 18774 "_sFilterRow": null, 18775 18776 /** 18777 * Cache of the class name that DataTables has applied to the row, so we 18778 * can quickly look at this variable rather than needing to do a DOM check 18779 * on className for the nTr property. 18780 * @type string 18781 * @default <i>Empty string</i> 18782 * @private 18783 */ 18784 "_sRowStripe": "", 18785 18786 /** 18787 * Denote if the original data source was from the DOM, or the data source 18788 * object. This is used for invalidating data, so DataTables can 18789 * automatically read data from the original source, unless uninstructed 18790 * otherwise. 18791 * @type string 18792 * @default null 18793 * @private 18794 */ 18795 "src": null, 18796 18797 /** 18798 * Index in the aoData array. This saves an indexOf lookup when we have the 18799 * object, but want to know the index 18800 * @type integer 18801 * @default -1 18802 * @private 18803 */ 18804 "idx": -1 18805 }; 18806 18807 18808 /** 18809 * Template object for the column information object in DataTables. This object 18810 * is held in the settings aoColumns array and contains all the information that 18811 * DataTables needs about each individual column. 18812 * 18813 * Note that this object is related to {@link DataTable.defaults.column} 18814 * but this one is the internal data store for DataTables's cache of columns. 18815 * It should NOT be manipulated outside of DataTables. Any configuration should 18816 * be done through the initialisation options. 18817 * @namespace 18818 */ 18819 DataTable.models.oColumn = { 18820 /** 18821 * Column index. This could be worked out on-the-fly with $.inArray, but it 18822 * is faster to just hold it as a variable 18823 * @type integer 18824 * @default null 18825 */ 18826 "idx": null, 18827 18828 /** 18829 * A list of the columns that sorting should occur on when this column 18830 * is sorted. That this property is an array allows multi-column sorting 18831 * to be defined for a column (for example first name / last name columns 18832 * would benefit from this). The values are integers pointing to the 18833 * columns to be sorted on (typically it will be a single integer pointing 18834 * at itself, but that doesn't need to be the case). 18835 * @type array 18836 */ 18837 "aDataSort": null, 18838 18839 /** 18840 * Define the sorting directions that are applied to the column, in sequence 18841 * as the column is repeatedly sorted upon - i.e. the first value is used 18842 * as the sorting direction when the column if first sorted (clicked on). 18843 * Sort it again (click again) and it will move on to the next index. 18844 * Repeat until loop. 18845 * @type array 18846 */ 18847 "asSorting": null, 18848 18849 /** 18850 * Flag to indicate if the column is searchable, and thus should be included 18851 * in the filtering or not. 18852 * @type boolean 18853 */ 18854 "bSearchable": null, 18855 18856 /** 18857 * Flag to indicate if the column is sortable or not. 18858 * @type boolean 18859 */ 18860 "bSortable": null, 18861 18862 /** 18863 * Flag to indicate if the column is currently visible in the table or not 18864 * @type boolean 18865 */ 18866 "bVisible": null, 18867 18868 /** 18869 * Store for manual type assignment using the `column.type` option. This 18870 * is held in store so we can manipulate the column's `sType` property. 18871 * @type string 18872 * @default null 18873 * @private 18874 */ 18875 "_sManualType": null, 18876 18877 /** 18878 * Flag to indicate if HTML5 data attributes should be used as the data 18879 * source for filtering or sorting. True is either are. 18880 * @type boolean 18881 * @default false 18882 * @private 18883 */ 18884 "_bAttrSrc": false, 18885 18886 /** 18887 * Developer definable function that is called whenever a cell is created (Ajax source, 18888 * etc) or processed for input (DOM source). This can be used as a compliment to mRender 18889 * allowing you to modify the DOM element (add background colour for example) when the 18890 * element is available. 18891 * @type function 18892 * @param {element} nTd The TD node that has been created 18893 * @param {*} sData The Data for the cell 18894 * @param {array|object} oData The data for the whole row 18895 * @param {int} iRow The row index for the aoData data store 18896 * @default null 18897 */ 18898 "fnCreatedCell": null, 18899 18900 /** 18901 * Function to get data from a cell in a column. You should <b>never</b> 18902 * access data directly through _aData internally in DataTables - always use 18903 * the method attached to this property. It allows mData to function as 18904 * required. This function is automatically assigned by the column 18905 * initialisation method 18906 * @type function 18907 * @param {array|object} oData The data array/object for the array 18908 * (i.e. aoData[]._aData) 18909 * @param {string} sSpecific The specific data type you want to get - 18910 * 'display', 'type' 'filter' 'sort' 18911 * @returns {*} The data for the cell from the given row's data 18912 * @default null 18913 */ 18914 "fnGetData": null, 18915 18916 /** 18917 * Function to set data for a cell in the column. You should <b>never</b> 18918 * set the data directly to _aData internally in DataTables - always use 18919 * this method. It allows mData to function as required. This function 18920 * is automatically assigned by the column initialisation method 18921 * @type function 18922 * @param {array|object} oData The data array/object for the array 18923 * (i.e. aoData[]._aData) 18924 * @param {*} sValue Value to set 18925 * @default null 18926 */ 18927 "fnSetData": null, 18928 18929 /** 18930 * Property to read the value for the cells in the column from the data 18931 * source array / object. If null, then the default content is used, if a 18932 * function is given then the return from the function is used. 18933 * @type function|int|string|null 18934 * @default null 18935 */ 18936 "mData": null, 18937 18938 /** 18939 * Partner property to mData which is used (only when defined) to get 18940 * the data - i.e. it is basically the same as mData, but without the 18941 * 'set' option, and also the data fed to it is the result from mData. 18942 * This is the rendering method to match the data method of mData. 18943 * @type function|int|string|null 18944 * @default null 18945 */ 18946 "mRender": null, 18947 18948 /** 18949 * Unique header TH/TD element for this column - this is what the sorting 18950 * listener is attached to (if sorting is enabled.) 18951 * @type node 18952 * @default null 18953 */ 18954 "nTh": null, 18955 18956 /** 18957 * Unique footer TH/TD element for this column (if there is one). Not used 18958 * in DataTables as such, but can be used for plug-ins to reference the 18959 * footer for each column. 18960 * @type node 18961 * @default null 18962 */ 18963 "nTf": null, 18964 18965 /** 18966 * The class to apply to all TD elements in the table's TBODY for the column 18967 * @type string 18968 * @default null 18969 */ 18970 "sClass": null, 18971 18972 /** 18973 * When DataTables calculates the column widths to assign to each column, 18974 * it finds the longest string in each column and then constructs a 18975 * temporary table and reads the widths from that. The problem with this 18976 * is that "mmm" is much wider then "iiii", but the latter is a longer 18977 * string - thus the calculation can go wrong (doing it properly and putting 18978 * it into an DOM object and measuring that is horribly(!) slow). Thus as 18979 * a "work around" we provide this option. It will append its value to the 18980 * text that is found to be the longest string for the column - i.e. padding. 18981 * @type string 18982 */ 18983 "sContentPadding": null, 18984 18985 /** 18986 * Allows a default value to be given for a column's data, and will be used 18987 * whenever a null data source is encountered (this can be because mData 18988 * is set to null, or because the data source itself is null). 18989 * @type string 18990 * @default null 18991 */ 18992 "sDefaultContent": null, 18993 18994 /** 18995 * Name for the column, allowing reference to the column by name as well as 18996 * by index (needs a lookup to work by name). 18997 * @type string 18998 */ 18999 "sName": null, 19000 19001 /** 19002 * Custom sorting data type - defines which of the available plug-ins in 19003 * afnSortData the custom sorting will use - if any is defined. 19004 * @type string 19005 * @default std 19006 */ 19007 "sSortDataType": 'std', 19008 19009 /** 19010 * Class to be applied to the header element when sorting on this column 19011 * @type string 19012 * @default null 19013 */ 19014 "sSortingClass": null, 19015 19016 /** 19017 * Class to be applied to the header element when sorting on this column - 19018 * when jQuery UI theming is used. 19019 * @type string 19020 * @default null 19021 */ 19022 "sSortingClassJUI": null, 19023 19024 /** 19025 * Title of the column - what is seen in the TH element (nTh). 19026 * @type string 19027 */ 19028 "sTitle": null, 19029 19030 /** 19031 * Column sorting and filtering type 19032 * @type string 19033 * @default null 19034 */ 19035 "sType": null, 19036 19037 /** 19038 * Width of the column 19039 * @type string 19040 * @default null 19041 */ 19042 "sWidth": null, 19043 19044 /** 19045 * Width of the column when it was first "encountered" 19046 * @type string 19047 * @default null 19048 */ 19049 "sWidthOrig": null 19050 }; 19051 19052 19053 /* 19054 * Developer note: The properties of the object below are given in Hungarian 19055 * notation, that was used as the interface for DataTables prior to v1.10, however 19056 * from v1.10 onwards the primary interface is camel case. In order to avoid 19057 * breaking backwards compatibility utterly with this change, the Hungarian 19058 * version is still, internally the primary interface, but is is not documented 19059 * - hence the @name tags in each doc comment. This allows a Javascript function 19060 * to create a map from Hungarian notation to camel case (going the other direction 19061 * would require each property to be listed, which would a
19061t around 3K to the size 19062 * of DataTables, while this method is about a 0.5K hit
vendor: 57,087 bytes, lines 19062-20838
19062. 19063 * 19064 * Ultimately this does pave the way for Hungarian notation to be dropped 19065 * completely, but that is a massive amount of work and will break current 19066 * installs (therefore is on-hold until v2). 19067 */ 19068 19069 /** 19070 * Initialisation options that can be given to DataTables at initialisation 19071 * time. 19072 * @namespace 19073 */ 19074 DataTable.defaults = { 19075 /** 19076 * An array of data to use for the table, passed in at initialisation which 19077 * will be used in preference to any data which is already in the DOM. This is 19078 * particularly useful for constructing tables purely in Javascript, for 19079 * example with a custom Ajax call. 19080 * @type array 19081 * @default null 19082 * 19083 * @dtopt Option 19084 * @name DataTable.defaults.data 19085 * 19086 * @example 19087 * // Using a 2D array data source 19088 * $(document).ready( function () { 19089 * $('#example').dataTable( { 19090 * "data": [ 19091 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'], 19092 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'], 19093 * ], 19094 * "columns": [ 19095 * { "title": "Engine" }, 19096 * { "title": "Browser" }, 19097 * { "title": "Platform" }, 19098 * { "title": "Version" }, 19099 * { "title": "Grade" } 19100 * ] 19101 * } ); 19102 * } ); 19103 * 19104 * @example 19105 * // Using an array of objects as a data source (`data`) 19106 * $(document).ready( function () { 19107 * $('#example').dataTable( { 19108 * "data": [ 19109 * { 19110 * "engine": "Trident", 19111 * "browser": "Internet Explorer 4.0", 19112 * "platform": "Win 95+", 19113 * "version": 4, 19114 * "grade": "X" 19115 * }, 19116 * { 19117 * "engine": "Trident", 19118 * "browser": "Internet Explorer 5.0", 19119 * "platform": "Win 95+", 19120 * "version": 5, 19121 * "grade": "C" 19122 * } 19123 * ], 19124 * "columns": [ 19125 * { "title": "Engine", "data": "engine" }, 19126 * { "title": "Browser", "data": "browser" }, 19127 * { "title": "Platform", "data": "platform" }, 19128 * { "title": "Version", "data": "version" }, 19129 * { "title": "Grade", "data": "grade" } 19130 * ] 19131 * } ); 19132 * } ); 19133 */ 19134 "aaData": null, 19135 19136 19137 /** 19138 * If ordering is enabled, then DataTables will perform a first pass sort on 19139 * initialisation. You can define which column(s) the sort is performed 19140 * upon, and the sorting direction, with this variable. The `sorting` array 19141 * should contain an array for each column to be sorted initially containing 19142 * the column's index and a direction string ('asc' or 'desc'). 19143 * @type array 19144 * @default [[0,'asc']] 19145 * 19146 * @dtopt Option 19147 * @name DataTable.defaults.order 19148 * 19149 * @example 19150 * // Sort by 3rd column first, and then 4th column 19151 * $(document).ready( function() { 19152 * $('#example').dataTable( { 19153 * "order": [[2,'asc'], [3,'desc']] 19154 * } ); 19155 * } ); 19156 * 19157 * // No initial sorting 19158 * $(document).ready( function() { 19159 * $('#example').dataTable( { 19160 * "order": [] 19161 * } ); 19162 * } ); 19163 */ 19164 "aaSorting": [[0,'asc']], 19165 19166 19167 /** 19168 * This parameter is basically identical to the `sorting` parameter, but 19169 * cannot be overridden by user interaction with the table. What this means 19170 * is that you could have a column (visible or hidden) which the sorting 19171 * will always be forced on first - any sorting after that (from the user) 19172 * will then be performed as required. This can be useful for grouping rows 19173 * together. 19174 * @type array 19175 * @default null 19176 * 19177 * @dtopt Option 19178 * @name DataTable.defaults.orderFixed 19179 * 19180 * @example 19181 * $(document).ready( function() { 19182 * $('#example').dataTable( { 19183 * "orderFixed": [[0,'asc']] 19184 * } ); 19185 * } ) 19186 */ 19187 "aaSortingFixed": [], 19188 19189 19190 /** 19191 * DataTables can be instructed to load data to display in the table from a 19192 * Ajax source. This option defines how that Ajax call is made and where to. 19193 * 19194 * The `ajax` property has three different modes of operation, depending on 19195 * how it is defined. These are: 19196 * 19197 * * `string` - Set the URL from where the data should be loaded from. 19198 * * `object` - Define properties for `jQuery.ajax`. 19199 * * `function` - Custom data get function 19200 * 19201 * `string` 19202 * -------- 19203 * 19204 * As a string, the `ajax` property simply defines the URL from which 19205 * DataTables will load data. 19206 * 19207 * `object` 19208 * -------- 19209 * 19210 * As an object, the parameters in the object are passed to 19211 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control 19212 * of the Ajax request. DataTables has a number of default parameters which 19213 * you can override using this option. Please refer to the jQuery 19214 * documentation for a full description of the options available, although 19215 * the following parameters provide additional options in DataTables or 19216 * require special consideration: 19217 * 19218 * * `data` - As with jQuery, `data` can be provided as an object, but it 19219 * can also be used as a function to manipulate the data DataTables sends 19220 * to the server. The function takes a single parameter, an object of 19221 * parameters with the values that DataTables has readied for sending. An 19222 * object may be returned which will be merged into the DataTables 19223 * defaults, or you can add the items to the object that was passed in and 19224 * not return anything from the function. This supersedes `fnServerParams` 19225 * from DataTables 1.9-. 19226 * 19227 * * `dataSrc` - By default DataTables will look for the property `data` (or 19228 * `aaData` for compatibility with DataTables 1.9-) when obtaining data 19229 * from an Ajax source or for server-side processing - this parameter 19230 * allows that property to be changed. You can use Javascript dotted 19231 * object notation to get a data source for multiple levels of nesting, or 19232 * it my be used as a function. As a function it takes a single parameter, 19233 * the JSON returned from the server, which can be manipulated as 19234 * required, with the returned value being that used by DataTables as the 19235 * data source for the table. This supersedes `sAjaxDataProp` from 19236 * DataTables 1.9-. 19237 * 19238 * * `success` - Should not be overridden it is used internally in 19239 * DataTables. To manipulate / transform the data returned by the server 19240 * use `ajax.dataSrc`, or use `ajax` as a function (see below). 19241 * 19242 * `function` 19243 * ---------- 19244 * 19245 * As a function, making the Ajax call is left up to yourself allowing 19246 * complete control of the Ajax request. Indeed, if desired, a method other 19247 * than Ajax could be used to obtain the required data, such as Web storage 19248 * or an AIR database. 19249 * 19250 * The function is given four parameters and no return is required. The 19251 * parameters are: 19252 * 19253 * 1. _object_ - Data to send to the server 19254 * 2. _function_ - Callback function that must be executed when the required 19255 * data has been obtained. That data should be passed into the callback 19256 * as the only parameter 19257 * 3. _object_ - DataTables settings object for the table 19258 * 19259 * Note that this supersedes `fnServerData` from DataTables 1.9-. 19260 * 19261 * @type string|object|function 19262 * @default null 19263 * 19264 * @dtopt Option 19265 * @name DataTable.defaults.ajax 19266 * @since 1.10.0 19267 * 19268 * @example 19269 * // Get JSON data from a file via Ajax. 19270 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default). 19271 * $('#example').dataTable( { 19272 * "ajax": "data.json" 19273 * } ); 19274 * 19275 * @example 19276 * // Get JSON data from a file via Ajax, using `dataSrc` to change 19277 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`) 19278 * $('#example').dataTable( { 19279 * "ajax": { 19280 * "url": "data.json", 19281 * "dataSrc": "tableData" 19282 * } 19283 * } ); 19284 * 19285 * @example 19286 * // Get JSON data from a file via Ajax, using `dataSrc` to read data 19287 * // from a plain array rather than an array in an object 19288 * $('#example').dataTable( { 19289 * "ajax": { 19290 * "url": "data.json", 19291 * "dataSrc": "" 19292 * } 19293 * } ); 19294 * 19295 * @example 19296 * // Manipulate the data returned from the server - add a link to data 19297 * // (note this can, should, be done using `render` for the column - this 19298 * // is just a simple example of how the data can be manipulated). 19299 * $('#example').dataTable( { 19300 * "ajax": { 19301 * "url": "data.json", 19302 * "dataSrc": function ( json ) { 19303 * for ( var i=0, ien=json.length ; i<ien ; i++ ) { 19304 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>'; 19305 * } 19306 * return json; 19307 * } 19308 * } 19309 * } ); 19310 * 19311 * @example 19312 * // Add data to the request 19313 * $('#example').dataTable( { 19314 * "ajax": { 19315 * "url": "data.json", 19316 * "data": function ( d ) { 19317 * return { 19318 * "extra_search": $('#extra').val() 19319 * }; 19320 * } 19321 * } 19322 * } ); 19323 * 19324 * @example 19325 * // Send request as POST 19326 * $('#example').dataTable( { 19327 * "ajax": { 19328 * "url": "data.json", 19329 * "type": "POST" 19330 * } 19331 * } ); 19332 * 19333 * @example 19334 * // Get the data from localStorage (could interface with a form for 19335 * // adding, editing and removing rows). 19336 * $('#example').dataTable( { 19337 * "ajax": function (data, callback, settings) { 19338 * callback( 19339 * JSON.parse( localStorage.getItem('dataTablesData') ) 19340 * ); 19341 * } 19342 * } ); 19343 */ 19344 "ajax": null, 19345 19346 19347 /** 19348 * This parameter allows you to readily specify the entries in the length drop 19349 * down menu that DataTables shows when pagination is enabled. It can be 19350 * either a 1D array of options which will be used for both the displayed 19351 * option and the value, or a 2D array which will use the array in the first 19352 * position as the value, and the array in the second position as the 19353 * displayed options (useful for language strings such as 'All'). 19354 * 19355 * Note that the `pageLength` property will be automatically set to the 19356 * first value given in this array, unless `pageLength` is also provided. 19357 * @type array 19358 * @default [ 10, 25, 50, 100 ] 19359 * 19360 * @dtopt Option 19361 * @name DataTable.defaults.lengthMenu 19362 * 19363 * @example 19364 * $(document).ready( function() { 19365 * $('#example').dataTable( { 19366 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]] 19367 * } ); 19368 * } ); 19369 */ 19370 "aLengthMenu": [ 10, 25, 50, 100 ], 19371 19372 19373 /** 19374 * The `columns` option in the initialisation parameter allows you to define 19375 * details about the way individual columns behave. For a full list of 19376 * column options that can be set, please see 19377 * {@link DataTable.defaults.column}. Note that if you use `columns` to 19378 * define your columns, you must have an entry in the array for every single 19379 * column that you have in your table (these can be null if you don't which 19380 * to specify any options). 19381 * @member 19382 * 19383 * @name DataTable.defaults.column 19384 */ 19385 "aoColumns": null, 19386 19387 /** 19388 * Very similar to `columns`, `columnDefs` allows you to target a specific 19389 * column, multiple columns, or all columns, using the `targets` property of 19390 * each object in the array. This allows great flexibility when creating 19391 * tables, as the `columnDefs` arrays can be of any length, targeting the 19392 * columns you specifically want. `columnDefs` may use any of the column 19393 * options available: {@link DataTable.defaults.column}, but it _must_ 19394 * have `targets` defined in each object in the array. Values in the `targets` 19395 * array may be: 19396 * <ul> 19397 * <li>a string - class name will be matched on the TH for the column</li> 19398 * <li>0 or a positive integer - column index counting from the left</li> 19399 * <li>a negative integer - column index counting from the right</li> 19400 * <li>the string "_all" - all columns (i.e. assign a default)</li> 19401 * </ul> 19402 * @member 19403 * 19404 * @name DataTable.defaults.columnDefs 19405 */ 19406 "aoColumnDefs": null, 19407 19408 19409 /** 19410 * Basically the same as `search`, this parameter defines the individual column 19411 * filtering state at initialisation time. The array must be of the same size 19412 * as the number of columns, and each element be an object with the parameters 19413 * `search` and `escapeRegex` (the latter is optional). 'null' is also 19414 * accepted and the default will be used. 19415 * @type array 19416 * @default [] 19417 * 19418 * @dtopt Option 19419 * @name DataTable.defaults.searchCols 19420 * 19421 * @example 19422 * $(document).ready( function() { 19423 * $('#example').dataTable( { 19424 * "searchCols": [ 19425 * null, 19426 * { "search": "My filter" }, 19427 * null, 19428 * { "search": "^[0-9]", "escapeRegex": false } 19429 * ] 19430 * } ); 19431 * } ) 19432 */ 19433 "aoSearchCols": [], 19434 19435 19436 /** 19437 * An array of CSS classes that should be applied to displayed rows. This 19438 * array may be of any length, and DataTables will apply each class 19439 * sequentially, looping when required. 19440 * @type array 19441 * @default null <i>Will take the values determined by the `oClasses.stripe*` 19442 * options</i> 19443 * 19444 * @dtopt Option 19445 * @name DataTable.defaults.stripeClasses 19446 * 19447 * @example 19448 * $(document).ready( function() { 19449 * $('#example').dataTable( { 19450 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ] 19451 * } ); 19452 * } ) 19453 */ 19454 "asStripeClasses": null, 19455 19456 19457 /** 19458 * Enable or disable automatic column width calculation. This can be disabled 19459 * as an optimisation (it takes some time to calculate the widths) if the 19460 * tables widths are passed in using `columns`. 19461 * @type boolean 19462 * @default true 19463 * 19464 * @dtopt Features 19465 * @name DataTable.defaults.autoWidth 19466 * 19467 * @example 19468 * $(document).ready( function () { 19469 * $('#example').dataTable( { 19470 * "autoWidth": false 19471 * } ); 19472 * } ); 19473 */ 19474 "bAutoWidth": true, 19475 19476 19477 /** 19478 * Deferred rendering can provide DataTables with a huge speed boost when you 19479 * are using an Ajax or JS data source for the table. This option, when set to 19480 * true, will cause DataTables to defer the creation of the table elements for 19481 * each row until they are needed for a draw - saving a significant amount of 19482 * time. 19483 * @type boolean 19484 * @default false 19485 * 19486 * @dtopt Features 19487 * @name DataTable.defaults.deferRender 19488 * 19489 * @example 19490 * $(document).ready( function() { 19491 * $('#example').dataTable( { 19492 * "ajax": "sources/arrays.txt", 19493 * "deferRender": true 19494 * } ); 19495 * } ); 19496 */ 19497 "bDeferRender": false, 19498 19499 19500 /** 19501 * Replace a DataTable which matches the given selector and replace it with 19502 * one which has the properties of the new initialisation object passed. If no 19503 * table matches the selector, then the new DataTable will be constructed as 19504 * per normal. 19505 * @type boolean 19506 * @default false 19507 * 19508 * @dtopt Options 19509 * @name DataTable.defaults.destroy 19510 * 19511 * @example 19512 * $(document).ready( function() { 19513 * $('#example').dataTable( { 19514 * "srollY": "200px", 19515 * "paginate": false 19516 * } ); 19517 * 19518 * // Some time later.... 19519 * $('#example').dataTable( { 19520 * "filter": false, 19521 * "destroy": true 19522 * } ); 19523 * } ); 19524 */ 19525 "bDestroy": false, 19526 19527 19528 /** 19529 * Enable or disable filtering of data. Filtering in DataTables is "smart" in 19530 * that it allows the end user to input multiple words (space separated) and 19531 * will match a row containing those words, even if not in the order that was 19532 * specified (this allow matching across multiple columns). Note that if you 19533 * wish to use filtering in DataTables this must remain 'true' - to remove the 19534 * default filtering input box and retain filtering abilities, please use 19535 * {@link DataTable.defaults.dom}. 19536 * @type boolean 19537 * @default true 19538 * 19539 * @dtopt Features 19540 * @name DataTable.defaults.searching 19541 * 19542 * @example 19543 * $(document).ready( function () { 19544 * $('#example').dataTable( { 19545 * "searching": false 19546 * } ); 19547 * } ); 19548 */ 19549 "bFilter": true, 19550 19551 19552 /** 19553 * Enable or disable the table information display. This shows information 19554 * about the data that is currently visible on the page, including information 19555 * about filtered data if that action is being performed. 19556 * @type boolean 19557 * @default true 19558 * 19559 * @dtopt Features 19560 * @name DataTable.defaults.info 19561 * 19562 * @example 19563 * $(document).ready( function () { 19564 * $('#example').dataTable( { 19565 * "info": false 19566 * } ); 19567 * } ); 19568 */ 19569 "bInfo": true, 19570 19571 19572 /** 19573 * Allows the end user to select the size of a formatted page from a select 19574 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`). 19575 * @type boolean 19576 * @default true 19577 * 19578 * @dtopt Features 19579 * @name DataTable.defaults.lengthChange 19580 * 19581 * @example 19582 * $(document).ready( function () { 19583 * $('#example').dataTable( { 19584 * "lengthChange": false 19585 * } ); 19586 * } ); 19587 */ 19588 "bLengthChange": true, 19589 19590 19591 /** 19592 * Enable or disable pagination. 19593 * @type boolean 19594 * @default true 19595 * 19596 * @dtopt Features 19597 * @name DataTable.defaults.paging 19598 * 19599 * @example 19600 * $(document).ready( function () { 19601 * $('#example').dataTable( { 19602 * "paging": false 19603 * } ); 19604 * } ); 19605 */ 19606 "bPaginate": true, 19607 19608 19609 /** 19610 * Enable or disable the display of a 'processing' indicator when the table is 19611 * being processed (e.g. a sort). This is particularly useful for tables with 19612 * large amounts of data where it can take a noticeable amount of time to sort 19613 * the entries. 19614 * @type boolean 19615 * @default false 19616 * 19617 * @dtopt Features 19618 * @name DataTable.defaults.processing 19619 * 19620 * @example 19621 * $(document).ready( function () { 19622 * $('#example').dataTable( { 19623 * "processing": true 19624 * } ); 19625 * } ); 19626 */ 19627 "bProcessing": false, 19628 19629 19630 /** 19631 * Retrieve the DataTables object for the given selector. Note that if the 19632 * table has already been initialised, this parameter will cause DataTables 19633 * to simply return the object that has already been set up - it will not take 19634 * account of any changes you might have made to the initialisation object 19635 * passed to DataTables (setting this parameter to true is an acknowledgement 19636 * that you understand this). `destroy` can be used to reinitialise a table if 19637 * you need. 19638 * @type boolean 19639 * @default false 19640 * 19641 * @dtopt Options 19642 * @name DataTable.defaults.retrieve 19643 * 19644 * @example 19645 * $(document).ready( function() { 19646 * initTable(); 19647 * tableActions(); 19648 * } ); 19649 * 19650 * function initTable () 19651 * { 19652 * return $('#example').dataTable( { 19653 * "scrollY": "200px", 19654 * "paginate": false, 19655 * "retrieve": true 19656 * } ); 19657 * } 19658 * 19659 * function tableActions () 19660 * { 19661 * var table = initTable(); 19662 * // perform API operations with oTable 19663 * } 19664 */ 19665 "bRetrieve": false, 19666 19667 19668 /** 19669 * When vertical (y) scrolling is enabled, DataTables will force the height of 19670 * the table's viewport to the given height at all times (useful for layout). 19671 * However, this can look odd when filtering data down to a small data set, 19672 * and the footer is left "floating" further down. This parameter (when 19673 * enabled) will cause DataTables to collapse the table's viewport down when 19674 * the result set will fit within the given Y height. 19675 * @type boolean 19676 * @default false 19677 * 19678 * @dtopt Options 19679 * @name DataTable.defaults.scrollCollapse 19680 * 19681 * @example 19682 * $(document).ready( function() { 19683 * $('#example').dataTable( { 19684 * "scrollY": "200", 19685 * "scrollCollapse": true 19686 * } ); 19687 * } ); 19688 */ 19689 "bScrollCollapse": false, 19690 19691 19692 /** 19693 * Configure DataTables to use server-side processing. Note that the 19694 * `ajax` parameter must also be given in order to give DataTables a 19695 * source to obtain the required data for each draw. 19696 * @type boolean 19697 * @default false 19698 * 19699 * @dtopt Features 19700 * @dtopt Server-side 19701 * @name DataTable.defaults.serverSide 19702 * 19703 * @example 19704 * $(document).ready( function () { 19705 * $('#example').dataTable( { 19706 * "serverSide": true, 19707 * "ajax": "xhr.php" 19708 * } ); 19709 * } ); 19710 */ 19711 "bServerSide": false, 19712 19713 19714 /** 19715 * Enable or disable sorting of columns. Sorting of individual columns can be 19716 * disabled by the `sortable` option for each column. 19717 * @type boolean 19718 * @default true 19719 * 19720 * @dtopt Features 19721 * @name DataTable.defaults.ordering 19722 * 19723 * @example 19724 * $(document).ready( function () { 19725 * $('#example').dataTable( { 19726 * "ordering": false 19727 * } ); 19728 * } ); 19729 */ 19730 "bSort": true, 19731 19732 19733 /** 19734 * Enable or display DataTables' ability to sort multiple columns at the 19735 * same time (activated by shift-click by the user). 19736 * @type boolean 19737 * @default true 19738 * 19739 * @dtopt Options 19740 * @name DataTable.defaults.orderMulti 19741 * 19742 * @example 19743 * // Disable multiple column sorting ability 19744 * $(document).ready( function () { 19745 * $('#example').dataTable( { 19746 * "orderMulti": false 19747 * } ); 19748 * } ); 19749 */ 19750 "bSortMulti": true, 19751 19752 19753 /** 19754 * Allows control over whether DataTables should use the top (true) unique 19755 * cell that is found for a single column, or the bottom (false - default). 19756 * This is useful when using complex headers. 19757 * @type boolean 19758 * @default false 19759 * 19760 * @dtopt Options 19761 * @name DataTable.defaults.orderCellsTop 19762 * 19763 * @example 19764 * $(document).ready( function() { 19765 * $('#example').dataTable( { 19766 * "orderCellsTop": true 19767 * } ); 19768 * } ); 19769 */ 19770 "bSortCellsTop": false, 19771 19772 19773 /** 19774 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and 19775 * `sorting\_3` to the columns which are currently being sorted on. This is 19776 * presented as a feature switch as it can increase processing time (while 19777 * classes are removed and added) so for large data sets you might want to 19778 * turn this off. 19779 * @type boolean 19780 * @default true 19781 * 19782 * @dtopt Features 19783 * @name DataTable.defaults.orderClasses 19784 * 19785 * @example 19786 * $(document).ready( function () { 19787 * $('#example').dataTable( { 19788 * "orderClasses": false 19789 * } ); 19790 * } ); 19791 */ 19792 "bSortClasses": true, 19793 19794 19795 /** 19796 * Enable or disable state saving. When enabled HTML5 `localStorage` will be 19797 * used to save table display information such as pagination information, 19798 * display length, filtering and sorting. As such when the end user reloads 19799 * the page the display display will match what thy had previously set up. 19800 * 19801 * Due to the use of `localStorage` the default state saving is not supported 19802 * in IE6 or 7. If state saving is required in those browsers, use 19803 * `stateSaveCallback` to provide a storage solution such as cookies. 19804 * @type boolean 19805 * @default false 19806 * 19807 * @dtopt Features 19808 * @name DataTable.defaults.stateSave 19809 * 19810 * @example 19811 * $(document).ready( function () { 19812 * $('#example').dataTable( { 19813 * "stateSave": true 19814 * } ); 19815 * } ); 19816 */ 19817 "bStateSave": false, 19818 19819 19820 /** 19821 * This function is called when a TR element is created (and all TD child 19822 * elements have been inserted), or registered if using a DOM source, allowing 19823 * manipulation of the TR element (adding classes etc). 19824 * @type function 19825 * @param {node} row "TR" element for the current row 19826 * @param {array} data Raw data array for this row 19827 * @param {int} dataIndex The index of this row in the internal aoData array 19828 * 19829 * @dtopt Callbacks 19830 * @name DataTable.defaults.createdRow 19831 * 19832 * @example 19833 * $(document).ready( function() { 19834 * $('#example').dataTable( { 19835 * "createdRow": function( row, data, dataIndex ) { 19836 * // Bold the grade for all 'A' grade browsers 19837 * if ( data[4] == "A" ) 19838 * { 19839 * $('td:eq(4)', row).html( '<b>A</b>' ); 19840 * } 19841 * } 19842 * } ); 19843 * } ); 19844 */ 19845 "fnCreatedRow": null, 19846 19847 19848 /** 19849 * This function is called on every 'draw' event, and allows you to 19850 * dynamically modify any aspect you want about the created DOM. 19851 * @type function 19852 * @param {object} settings DataTables settings object 19853 * 19854 * @dtopt Callbacks 19855 * @name DataTable.defaults.drawCallback 19856 * 19857 * @example 19858 * $(document).ready( function() { 19859 * $('#example').dataTable( { 19860 * "drawCallback": function( settings ) { 19861 * alert( 'DataTables has redrawn the table' ); 19862 * } 19863 * } ); 19864 * } ); 19865 */ 19866 "fnDrawCallback": null, 19867 19868 19869 /** 19870 * Identical to fnHeaderCallback() but for the table footer this function 19871 * allows you to modify the table footer on every 'draw' event. 19872 * @type function 19873 * @param {node} foot "TR" element for the footer 19874 * @param {array} data Full table data (as derived from the original HTML) 19875 * @param {int} start Index for the current display starting point in the 19876 * display array 19877 * @param {int} end Index for the current display ending point in the 19878 * display array 19879 * @param {array int} display Index array to translate the visual position 19880 * to the full data array 19881 * 19882 * @dtopt Callbacks 19883 * @name DataTable.defaults.footerCallback 19884 * 19885 * @example 19886 * $(document).ready( function() { 19887 * $('#example').dataTable( { 19888 * "footerCallback": function( tfoot, data, start, end, display ) { 19889 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start; 19890 * } 19891 * } ); 19892 * } ) 19893 */ 19894 "fnFooterCallback": null, 19895 19896 19897 /** 19898 * When rendering large numbers in the information element for the table 19899 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers 19900 * to have a comma separator for the 'thousands' units (e.g. 1 million is 19901 * rendered as "1,000,000") to help readability for the end user. This 19902 * function will override the default method DataTables uses. 19903 * @type function 19904 * @member 19905 * @param {int} toFormat number to be formatted 19906 * @returns {string} formatted string for DataTables to show the number 19907 * 19908 * @dtopt Callbacks 19909 * @name DataTable.defaults.formatNumber 19910 * 19911 * @example 19912 * // Format a number using a single quote for the separator (note that 19913 * // this can also be done with the language.thousands option) 19914 * $(document).ready( function() { 19915 * $('#example').dataTable( { 19916 * "formatNumber": function ( toFormat ) { 19917 * return toFormat.toString().replace( 19918 * /\B(?=(\d{3})+(?!\d))/g, "'" 19919 * ); 19920 * }; 19921 * } ); 19922 * } ); 19923 */ 19924 "fnFormatNumber": function ( toFormat ) { 19925 return toFormat.toString().replace( 19926 /\B(?=(\d{3})+(?!\d))/g, 19927 this.oLanguage.sThousands 19928 ); 19929 }, 19930 19931 19932 /** 19933 * This function is called on every 'draw' event, and allows you to 19934 * dynamically modify the header row. This can be used to calculate and 19935 * display useful information about the table. 19936 * @type function 19937 * @param {node} head "TR" element for the header 19938 * @param {array} data Full table data (as derived from the original HTML) 19939 * @param {int} start Index for the current display starting point in the 19940 * display array 19941 * @param {int} end Index for the current display ending point in the 19942 * display array 19943 * @param {array int} display Index array to translate the visual position 19944 * to the full data array 19945 * 19946 * @dtopt Callbacks 19947 * @name DataTable.defaults.headerCallback 19948 * 19949 * @example 19950 * $(document).ready( function() { 19951 * $('#example').dataTable( { 19952 * "fheaderCallback": function( head, data, start, end, display ) { 19953 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records"; 19954 * } 19955 * } ); 19956 * } ) 19957 */ 19958 "fnHeaderCallback": null, 19959 19960 19961 /** 19962 * The information element can be used to convey information about the current 19963 * state of the table. Although the internationalisation options presented by 19964 * DataTables are quite capable of dealing with most customisations, there may 19965 * be times where you wish to customise the string further. This callback 19966 * allows you to do exactly that. 19967 * @type function 19968 * @param {object} oSettings DataTables settings object 19969 * @param {int} start Starting position in data for the draw 19970 * @param {int} end End position in data for the draw 19971 * @param {int} max Total number of rows in the table (regardless of 19972 * filtering) 19973 * @param {int} total Total number of rows in the data set, after filtering 19974 * @param {string} pre The string that DataTables has formatted using it's 19975 * own rules 19976 * @returns {string} The string to be displayed in the information element. 19977 * 19978 * @dtopt Callbacks 19979 * @name DataTable.defaults.infoCallback 19980 * 19981 * @example 19982 * $('#example').dataTable( { 19983 * "infoCallback": function( settings, start, end, max, total, pre ) { 19984 * return start +" to "+ end; 19985 * } 19986 * } ); 19987 */ 19988 "fnInfoCallback": null, 19989 19990 19991 /** 19992 * Called when the table has been initialised. Normally DataTables will 19993 * initialise sequentially and there will be no need for this function, 19994 * however, this does not hold true when using external language information 19995 * since that is obtained using an async XHR call. 19996 * @type function 19997 * @param {object} settings DataTables settings object 19998 * @param {object} json The JSON object request from the server - only 19999 * present if client-side Ajax sourced data is used 20000 * 20001 * @dtopt Callbacks 20002 * @name DataTable.defaults.initComplete 20003 * 20004 * @example 20005 * $(document).ready( function() { 20006 * $('#example').dataTable( { 20007 * "initComplete": function(settings, json) { 20008 * alert( 'DataTables has finished its initialisation.' ); 20009 * } 20010 * } ); 20011 * } ) 20012 */ 20013 "fnInitComplete": null, 20014 20015 20016 /** 20017 * Called at the very start of each table draw and can be used to cancel the 20018 * draw by returning false, any other return (including undefined) results in 20019 * the full draw occurring). 20020 * @type function 20021 * @param {object} settings DataTables settings object 20022 * @returns {boolean} False will cancel the draw, anything else (including no 20023 * return) will allow it to complete. 20024 * 20025 * @dtopt Callbacks 20026 * @name DataTable.defaults.preDrawCallback 20027 * 20028 * @example 20029 * $(document).ready( function() { 20030 * $('#example').dataTable( { 20031 * "preDrawCallback": function( settings ) { 20032 * if ( $('#test').val() == 1 ) { 20033 * return false; 20034 * } 20035 * } 20036 * } ); 20037 * } ); 20038 */ 20039 "fnPreDrawCallback": null, 20040 20041 20042 /** 20043 * This function allows you to 'post process' each row after it have been 20044 * generated for each table draw, but before it is rendered on screen. This 20045 * function might be used for setting the row class name etc. 20046 * @type function 20047 * @param {node} row "TR" element for the current row 20048 * @param {array} data Raw data array for this row 20049 * @param {int} displayIndex The display index for the current table draw 20050 * @param {int} displayIndexFull The index of the data in the full list of 20051 * rows (after filtering) 20052 * 20053 * @dtopt Callbacks 20054 * @name DataTable.defaults.rowCallback 20055 * 20056 * @example 20057 * $(document).ready( function() { 20058 * $('#example').dataTable( { 20059 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) { 20060 * // Bold the grade for all 'A' grade browsers 20061 * if ( data[4] == "A" ) { 20062 * $('td:eq(4)', row).html( '<b>A</b>' ); 20063 * } 20064 * } 20065 * } ); 20066 * } ); 20067 */ 20068 "fnRowCallback": null, 20069 20070 20071 /** 20072 * __Deprecated__ The functionality provided by this parameter has now been 20073 * superseded by that provided through `ajax`, which should be used instead. 20074 * 20075 * This parameter allows you to override the default function which obtains 20076 * the data from the server so something more suitable for your application. 20077 * For example you could use POST data, or pull information from a Gears or 20078 * AIR database. 20079 * @type function 20080 * @member 20081 * @param {string} source HTTP source to obtain the data from (`ajax`) 20082 * @param {array} data A key/value pair object containing the data to send 20083 * to the server 20084 * @param {function} callback to be called on completion of the data get 20085 * process that will draw the data on the page. 20086 * @param {object} settings DataTables settings object 20087 * 20088 * @dtopt Callbacks 20089 * @dtopt Server-side 20090 * @name DataTable.defaults.serverData 20091 * 20092 * @deprecated 1.10. Please use `ajax` for this functionality now. 20093 */ 20094 "fnServerData": null, 20095 20096 20097 /** 20098 * __Deprecated__ The functionality provided by this parameter has now been 20099 * superseded by that provided through `ajax`, which should be used instead. 20100 * 20101 * It is often useful to send extra data to the server when making an Ajax 20102 * request - for example custom filtering information, and this callback 20103 * function makes it trivial to send extra information to the server. The 20104 * passed in parameter is the data set that has been constructed by 20105 * DataTables, and you can add to this or modify it as you require. 20106 * @type function 20107 * @param {array} data Data array (array of objects which are name/value 20108 * pairs) that has been constructed by DataTables and will be sent to the 20109 * server. In the case of Ajax sourced data with server-side processing 20110 * this will be an empty array, for server-side processing there will be a 20111 * significant number of parameters! 20112 * @returns {undefined} Ensure that you modify the data array passed in, 20113 * as this is passed by reference. 20114 * 20115 * @dtopt Callbacks 20116 * @dtopt Server-side 20117 * @name DataTable.defaults.serverParams 20118 * 20119 * @deprecated 1.10. Please use `ajax` for this functionality now. 20120 */ 20121 "fnServerParams": null, 20122 20123 20124 /** 20125 * Load the table state. With this function you can define from where, and how, the 20126 * state of a table is loaded. By default DataTables will load from `localStorage` 20127 * but you might wish to use a server-side database or cookies. 20128 * @type function 20129 * @member 20130 * @param {object} settings DataTables settings object 20131 * @param {object} callback Callback that can be executed when done. It 20132 * should be passed the loaded state object. 20133 * @return {object} The DataTables state object to be loaded 20134 * 20135 * @dtopt Callbacks 20136 * @name DataTable.defaults.stateLoadCallback 20137 * 20138 * @example 20139 * $(document).ready( function() { 20140 * $('#example').dataTable( { 20141 * "stateSave": true, 20142 * "stateLoadCallback": function (settings, callback) { 20143 * $.ajax( { 20144 * "url": "/state_load", 20145 * "dataType": "json", 20146 * "success": function (json) { 20147 * callback( json ); 20148 * } 20149 * } ); 20150 * } 20151 * } ); 20152 * } ); 20153 */ 20154 "fnStateLoadCallback": function ( settings ) { 20155 try { 20156 return JSON.parse( 20157 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem( 20158 'DataTables_'+settings.sInstance+'_'+location.pathname 20159 ) 20160 ); 20161 } catch (e) {} 20162 }, 20163 20164 20165 /** 20166 * Callback which allows modification of the saved state prior to loading that state. 20167 * This callback is called when the table is loading state from the stored data, but 20168 * prior to the settings object being modified by the saved state. Note that for 20169 * plug-in authors, you should use the `stateLoadParams` event to load parameters for 20170 * a plug-in. 20171 * @type function 20172 * @param {object} settings DataTables settings object 20173 * @param {object} data The state object that is to be loaded 20174 * 20175 * @dtopt Callbacks 20176 * @name DataTable.defaults.stateLoadParams 20177 * 20178 * @example 20179 * // Remove a saved filter, so filtering is never loaded 20180 * $(document).ready( function() { 20181 * $('#example').dataTable( { 20182 * "stateSave": true, 20183 * "stateLoadParams": function (settings, data) { 20184 * data.oSearch.sSearch = ""; 20185 * } 20186 * } ); 20187 * } ); 20188 * 20189 * @example 20190 * // Disallow state loading by returning false 20191 * $(document).ready( function() { 20192 * $('#example').dataTable( { 20193 * "stateSave": true, 20194 * "stateLoadParams": function (settings, data) { 20195 * return false; 20196 * } 20197 * } ); 20198 * } ); 20199 */ 20200 "fnStateLoadParams": null, 20201 20202 20203 /** 20204 * Callback that is called when the state has been loaded from the state saving method 20205 * and the DataTables settings object has been modified as a result of the loaded state. 20206 * @type function 20207 * @param {object} settings DataTables settings object 20208 * @param {object} data The state object that was loaded 20209 * 20210 * @dtopt Callbacks 20211 * @name DataTable.defaults.stateLoaded 20212 * 20213 * @example 20214 * // Show an alert with the filtering value that was saved 20215 * $(document).ready( function() { 20216 * $('#example').dataTable( { 20217 * "stateSave": true, 20218 * "stateLoaded": function (settings, data) { 20219 * alert( 'Saved filter was: '+data.oSearch.sSearch ); 20220 * } 20221 * } ); 20222 * } ); 20223 */ 20224 "fnStateLoaded": null, 20225 20226 20227 /** 20228 * Save the table state. This function allows you to define where and how the state 20229 * information for the table is stored By default DataTables will use `localStorage` 20230 * but you might wish to use a server-side database or cookies. 20231 * @type function 20232 * @member 20233 * @param {object} settings DataTables settings object 20234 * @param {object} data The state object to be saved 20235 * 20236 * @dtopt Callbacks 20237 * @name DataTable.defaults.stateSaveCallback 20238 * 20239 * @example 20240 * $(document).ready( function() { 20241 * $('#example').dataTable( { 20242 * "stateSave": true, 20243 * "stateSaveCallback": function (settings, data) { 20244 * // Send an Ajax request to the server with the state object 20245 * $.ajax( { 20246 * "url": "/state_save", 20247 * "data": data, 20248 * "dataType": "json", 20249 * "method": "POST" 20250 * "success": function () {} 20251 * } ); 20252 * } 20253 * } ); 20254 * } ); 20255 */ 20256 "fnStateSaveCallback": function ( settings, data ) { 20257 try { 20258 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem( 20259 'DataTables_'+settings.sInstance+'_'+location.pathname, 20260 JSON.stringify( data ) 20261 ); 20262 } catch (e) {} 20263 }, 20264 20265 20266 /** 20267 * Callback which allows modification of the state to be saved. Called when the table 20268 * has changed state a new state save is required. This method allows modification of 20269 * the state saving object prior to actually doing the save, including addition or 20270 * other state properties or modification. Note that for plug-in authors, you should 20271 * use the `stateSaveParams` event to save parameters for a plug-in. 20272 * @type function 20273 * @param {object} settings DataTables settings object 20274 * @param {object} data The state object to be saved 20275 * 20276 * @dtopt Callbacks 20277 * @name DataTable.defaults.stateSaveParams 20278 * 20279 * @example 20280 * // Remove a saved filter, so filtering is never saved 20281 * $(document).ready( function() { 20282 * $('#example').dataTable( { 20283 * "stateSave": true, 20284 * "stateSaveParams": function (settings, data) { 20285 * data.oSearch.sSearch = ""; 20286 * } 20287 * } ); 20288 * } ); 20289 */ 20290 "fnStateSaveParams": null, 20291 20292 20293 /** 20294 * Duration for which the saved state information is considered valid. After this period 20295 * has elapsed the state will be returned to the default. 20296 * Value is given in seconds. 20297 * @type int 20298 * @default 7200 <i>(2 hours)</i> 20299 * 20300 * @dtopt Options 20301 * @name DataTable.defaults.stateDuration 20302 * 20303 * @example 20304 * $(document).ready( function() { 20305 * $('#example').dataTable( { 20306 * "stateDuration": 60*60*24; // 1 day 20307 * } ); 20308 * } ) 20309 */ 20310 "iStateDuration": 7200, 20311 20312 20313 /** 20314 * When enabled DataTables will not make a request to the server for the first 20315 * page draw - rather it will use the data already on the page (no sorting etc 20316 * will be applied to it), thus saving on an XHR at load time. `deferLoading` 20317 * is used to indicate that deferred loading is required, but it is also used 20318 * to tell DataTables how many records there are in the full table (allowing 20319 * the information element and pagination to be displayed correctly). In the case 20320 * where a filtering is applied to the table on initial load, this can be 20321 * indicated by giving the parameter as an array, where the first element is 20322 * the number of records available after filtering and the second element is the 20323 * number of records without filtering (allowing the table information element 20324 * to be shown correctly). 20325 * @type int | array 20326 * @default null 20327 * 20328 * @dtopt Options 20329 * @name DataTable.defaults.deferLoading 20330 * 20331 * @example 20332 * // 57 records available in the table, no filtering applied 20333 * $(document).ready( function() { 20334 * $('#example').dataTable( { 20335 * "serverSide": true, 20336 * "ajax": "scripts/server_processing.php", 20337 * "deferLoading": 57 20338 * } ); 20339 * } ); 20340 * 20341 * @example 20342 * // 57 records after filtering, 100 without filtering (an initial filter applied) 20343 * $(document).ready( function() { 20344 * $('#example').dataTable( { 20345 * "serverSide": true, 20346 * "ajax": "scripts/server_processing.php", 20347 * "deferLoading": [ 57, 100 ], 20348 * "search": { 20349 * "search": "my_filter" 20350 * } 20351 * } ); 20352 * } ); 20353 */ 20354 "iDeferLoading": null, 20355 20356 20357 /** 20358 * Number of rows to display on a single page when using pagination. If 20359 * feature enabled (`lengthChange`) then the end user will be able to override 20360 * this to a custom setting using a pop-up menu. 20361 * @type int 20362 * @default 10 20363 * 20364 * @dtopt Options 20365 * @name DataTable.defaults.pageLength 20366 * 20367 * @example 20368 * $(document).ready( function() { 20369 * $('#example').dataTable( { 20370 * "pageLength": 50 20371 * } ); 20372 * } ) 20373 */ 20374 "iDisplayLength": 10, 20375 20376 20377 /** 20378 * Define the starting point for data display when using DataTables with 20379 * pagination. Note that this parameter is the number of records, rather than 20380 * the page number, so if you have 10 records per page and want to start on 20381 * the third page, it should be "20". 20382 * @type int 20383 * @default 0 20384 * 20385 * @dtopt Options 20386 * @name DataTable.defaults.displayStart 20387 * 20388 * @example 20389 * $(document).ready( function() { 20390 * $('#example').dataTable( { 20391 * "displayStart": 20 20392 * } ); 20393 * } ) 20394 */ 20395 "iDisplayStart": 0, 20396 20397 20398 /** 20399 * By default DataTables allows keyboard navigation of the table (sorting, paging, 20400 * and filtering) by adding a `tabindex` attribute to the required elements. This 20401 * allows you to tab through the controls and press the enter key to activate them. 20402 * The tabindex is default 0, meaning that the tab follows the flow of the document. 20403 * You can overrule this using this parameter if you wish. Use a value of -1 to 20404 * disable built-in keyboard navigation. 20405 * @type int 20406 * @default 0 20407 * 20408 * @dtopt Options 20409 * @name DataTable.defaults.tabIndex 20410 * 20411 * @example 20412 * $(document).ready( function() { 20413 * $('#example').dataTable( { 20414 * "tabIndex": 1 20415 * } ); 20416 * } ); 20417 */ 20418 "iTabIndex": 0, 20419 20420 20421 /** 20422 * Classes that DataTables assigns to the various components and features 20423 * that it adds to the HTML table. This allows classes to be configured 20424 * during initialisation in addition to through the static 20425 * {@link DataTable.ext.oStdClasses} object). 20426 * @namespace 20427 * @name DataTable.defaults.classes 20428 */ 20429 "oClasses": {}, 20430 20431 20432 /** 20433 * All strings that DataTables uses in the user interface that it creates 20434 * are defined in this object, allowing you to modified them individually or 20435 * completely replace them all as required. 20436 * @namespace 20437 * @name DataTable.defaults.language 20438 */ 20439 "oLanguage": { 20440 /** 20441 * Strings that are used for WAI-ARIA labels and controls only (these are not 20442 * actually visible on the page, but will be read by screenreaders, and thus 20443 * must be internationalised as well). 20444 * @namespace 20445 * @name DataTable.defaults.language.aria 20446 */ 20447 "oAria": { 20448 /** 20449 * ARIA label that is added to the table headers when the column may be 20450 * sorted ascending by activing the column (click or return when focused). 20451 * Note that the column header is prefixed to this string. 20452 * @type string 20453 * @default : activate to sort column ascending 20454 * 20455 * @dtopt Language 20456 * @name DataTable.defaults.language.aria.sortAscending 20457 * 20458 * @example 20459 * $(document).ready( function() { 20460 * $('#example').dataTable( { 20461 * "language": { 20462 * "aria": { 20463 * "sortAscending": " - click/return to sort ascending" 20464 * } 20465 * } 20466 * } ); 20467 * } ); 20468 */ 20469 "sSortAscending": ": activate to sort column ascending", 20470 20471 /** 20472 * ARIA label that is added to the table headers when the column may be 20473 * sorted descending by activing the column (click or return when focused). 20474 * Note that the column header is prefixed to this string. 20475 * @type string 20476 * @default : activate to sort column ascending 20477 * 20478 * @dtopt Language 20479 * @name DataTable.defaults.language.aria.sortDescending 20480 * 20481 * @example 20482 * $(document).ready( function() { 20483 * $('#example').dataTable( { 20484 * "language": { 20485 * "aria": { 20486 * "sortDescending": " - click/return to sort descending" 20487 * } 20488 * } 20489 * } ); 20490 * } ); 20491 */ 20492 "sSortDescending": ": activate to sort column descending" 20493 }, 20494 20495 /** 20496 * Pagination string used by DataTables for the built-in pagination 20497 * control types. 20498 * @namespace 20499 * @name DataTable.defaults.language.paginate 20500 */ 20501 "oPaginate": { 20502 /** 20503 * Text to use when using the 'full_numbers' type of pagination for the 20504 * button to take the user to the first page. 20505 * @type string 20506 * @default First 20507 * 20508 * @dtopt Language 20509 * @name DataTable.defaults.language.paginate.first 20510 * 20511 * @example 20512 * $(document).ready( function() { 20513 * $('#example').dataTable( { 20514 * "language": { 20515 * "paginate": { 20516 * "first": "First page" 20517 * } 20518 * } 20519 * } ); 20520 * } ); 20521 */ 20522 "sFirst": "First", 20523 20524 20525 /** 20526 * Text to use when using the 'full_numbers' type of pagination for the 20527 * button to take the user to the last page. 20528 * @type string 20529 * @default Last 20530 * 20531 * @dtopt Language 20532 * @name DataTable.defaults.language.paginate.last 20533 * 20534 * @example 20535 * $(document).ready( function() { 20536 * $('#example').dataTable( { 20537 * "language": { 20538 * "paginate": { 20539 * "last": "Last page" 20540 * } 20541 * } 20542 * } ); 20543 * } ); 20544 */ 20545 "sLast": "Last", 20546 20547 20548 /** 20549 * Text to use for the 'next' pagination button (to take the user to the 20550 * next page). 20551 * @type string 20552 * @default Next 20553 * 20554 * @dtopt Language 20555 * @name DataTable.defaults.language.paginate.next 20556 * 20557 * @example 20558 * $(document).ready( function() { 20559 * $('#example').dataTable( { 20560 * "language": { 20561 * "paginate": { 20562 * "next": "Next page" 20563 * } 20564 * } 20565 * } ); 20566 * } ); 20567 */ 20568 "sNext": "Next", 20569 20570 20571 /** 20572 * Text to use for the 'previous' pagination button (to take the user to 20573 * the previous page). 20574 * @type string 20575 * @default Previous 20576 * 20577 * @dtopt Language 20578 * @name DataTable.defaults.language.paginate.previous 20579 * 20580 * @example 20581 * $(document).ready( function() { 20582 * $('#example').dataTable( { 20583 * "language": { 20584 * "paginate": { 20585 * "previous": "Previous page" 20586 * } 20587 * } 20588 * } ); 20589 * } ); 20590 */ 20591 "sPrevious": "Previous" 20592 }, 20593 20594 /** 20595 * This string is shown in preference to `zeroRecords` when the table is 20596 * empty of data (regardless of filtering). Note that this is an optional 20597 * parameter - if it is not given, the value of `zeroRecords` will be used 20598 * instead (either the default or given value). 20599 * @type string 20600 * @default No data available in table 20601 * 20602 * @dtopt Language 20603 * @name DataTable.defaults.language.emptyTable 20604 * 20605 * @example 20606 * $(document).ready( function() { 20607 * $('#example').dataTable( { 20608 * "language": { 20609 * "emptyTable": "No data available in table" 20610 * } 20611 * } ); 20612 * } ); 20613 */ 20614 "sEmptyTable": "No data available in table", 20615 20616 20617 /** 20618 * This string gives information to the end user about the information 20619 * that is current on display on the page. The following tokens can be 20620 * used in the string and will be dynamically replaced as the table 20621 * display updates. This tokens can be placed anywhere in the string, or 20622 * removed as needed by the language requires: 20623 * 20624 * * `\_START\_` - Display index of the first record on the current page 20625 * * `\_END\_` - Display index of the last record on the current page 20626 * * `\_TOTAL\_` - Number of records in the table after filtering 20627 * * `\_MAX\_` - Number of records in the table without filtering 20628 * * `\_PAGE\_` - Current page number 20629 * * `\_PAGES\_` - Total number of pages of data in the table 20630 * 20631 * @type string 20632 * @default Showing _START_ to _END_ of _TOTAL_ entries 20633 * 20634 * @dtopt Language 20635 * @name DataTable.defaults.language.info 20636 * 20637 * @example 20638 * $(document).ready( function() { 20639 * $('#example').dataTable( { 20640 * "language": { 20641 * "info": "Showing page _PAGE_ of _PAGES_" 20642 * } 20643 * } ); 20644 * } ); 20645 */ 20646 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries", 20647 20648 20649 /** 20650 * Display information string for when the table is empty. Typically the 20651 * format of this string should match `info`. 20652 * @type string 20653 * @default Showing 0 to 0 of 0 entries 20654 * 20655 * @dtopt Language 20656 * @name DataTable.defaults.language.infoEmpty 20657 * 20658 * @example 20659 * $(document).ready( function() { 20660 * $('#example').dataTable( { 20661 * "language": { 20662 * "infoEmpty": "No entries to show" 20663 * } 20664 * } ); 20665 * } ); 20666 */ 20667 "sInfoEmpty": "Showing 0 to 0 of 0 entries", 20668 20669 20670 /** 20671 * When a user filters the information in a table, this string is appended 20672 * to the information (`info`) to give an idea of how strong the filtering 20673 * is. The variable _MAX_ is dynamically updated. 20674 * @type string 20675 * @default (filtered from _MAX_ total entries) 20676 * 20677 * @dtopt Language 20678 * @name DataTable.defaults.language.infoFiltered 20679 * 20680 * @example 20681 * $(document).ready( function() { 20682 * $('#example').dataTable( { 20683 * "language": { 20684 * "infoFiltered": " - filtering from _MAX_ records" 20685 * } 20686 * } ); 20687 * } ); 20688 */ 20689 "sInfoFiltered": "(filtered from _MAX_ total entries)", 20690 20691 20692 /** 20693 * If can be useful to append extra information to the info string at times, 20694 * and this variable does exactly that. This information will be appended to 20695 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are 20696 * being used) at all times. 20697 * @type string 20698 * @default <i>Empty string</i> 20699 * 20700 * @dtopt Language 20701 * @name DataTable.defaults.language.infoPostFix 20702 * 20703 * @example 20704 * $(document).ready( function() { 20705 * $('#example').dataTable( { 20706 * "language": { 20707 * "infoPostFix": "All records shown are derived from real information." 20708 * } 20709 * } ); 20710 * } ); 20711 */ 20712 "sInfoPostFix": "", 20713 20714 20715 /** 20716 * This decimal place operator is a little different from the other 20717 * language options since DataTables doesn't output floating point 20718 * numbers, so it won't ever use this for display of a number. Rather, 20719 * what this parameter does is modify the sort methods of the table so 20720 * that numbers which are in a format which has a character other than 20721 * a period (`.`) as a decimal place will be sorted numerically. 20722 * 20723 * Note that numbers with different decimal places cannot be shown in 20724 * the same table and still be sortable, the table must be consistent. 20725 * However, multiple different tables on the page can use different 20726 * decimal place characters. 20727 * @type string 20728 * @default 20729 * 20730 * @dtopt Language 20731 * @name DataTable.defaults.language.decimal 20732 * 20733 * @example 20734 * $(document).ready( function() { 20735 * $('#example').dataTable( { 20736 * "language": { 20737 * "decimal": "," 20738 * "thousands": "." 20739 * } 20740 * } ); 20741 * } ); 20742 */ 20743 "sDecimal": "", 20744 20745 20746 /** 20747 * DataTables has a build in number formatter (`formatNumber`) which is 20748 * used to format large numbers that are used in the table information. 20749 * By default a comma is used, but this can be trivially changed to any 20750 * character you wish with this parameter. 20751 * @type string 20752 * @default , 20753 * 20754 * @dtopt Language 20755 * @name DataTable.defaults.language.thousands 20756 * 20757 * @example 20758 * $(document).ready( function() { 20759 * $('#example').dataTable( { 20760 * "language": { 20761 * "thousands": "'" 20762 * } 20763 * } ); 20764 * } ); 20765 */ 20766 "sThousands": ",", 20767 20768 20769 /** 20770 * Detail the action that will be taken when the drop down menu for the 20771 * pagination length option is changed. The '_MENU_' variable is replaced 20772 * with a default select list of 10, 25, 50 and 100, and can be replaced 20773 * with a custom select box if required. 20774 * @type string 20775 * @default Show _MENU_ entries 20776 * 20777 * @dtopt Language 20778 * @name DataTable.defaults.language.lengthMenu 20779 * 20780 * @example 20781 * // Language change only 20782 * $(document).ready( function() { 20783 * $('#example').dataTable( { 20784 * "language": { 20785 * "lengthMenu": "Display _MENU_ records" 20786 * } 20787 * } ); 20788 * } ); 20789 * 20790 * @example 20791 * // Language and options change 20792 * $(document).ready( function() { 20793 * $('#example').dataTable( { 20794 * "language": { 20795 * "lengthMenu": 'Display <select>'+ 20796 * '<option value="10">10</option>'+ 20797 * '<option value="20">20</option>'+ 20798 * '<option value="30">30</option>'+ 20799 * '<option value="40">40</option>'+ 20800 * '<option value="50">50</option>'+ 20801 * '<option value="-1">All</option>'+ 20802 * '</select> records' 20803 * } 20804 * } ); 20805 * } ); 20806 */ 20807 "sLengthMenu": "Show _MENU_ entries", 20808 20809 20810 /** 20811 * When using Ajax sourced data and during the first draw when DataTables is 20812 * gathering the data, this message is shown in an empty row in the table to 20813 * indicate to the end user the the data is being loaded. Note that this 20814 * parameter is not used when loading data by server-side processing, just 20815 * Ajax sourced data with client-side processing. 20816 * @type string 20817 * @default Loading... 20818 * 20819 * @dtopt Language 20820 * @name DataTable.defaults.language.loadingRecords 20821 * 20822 * @example 20823 * $(document).ready( function() { 20824 * $('#example').dataTable( { 20825 * "language": { 20826 * "loadingRecords": "Please wait - loading..." 20827 * } 20828 * } ); 20829 * } ); 20830 */ 20831 "sLoadingRecords": "Loading...", 20832 20833 20834 /** 20835 * Text which is displayed when the table is processing a user action 20836 * (usually a sort command or similar). 20837 * @type string 20838 *
20838 @default Processing... 20839 * 20840 * @dtopt Language 20841 * @name DataTable.defaults.language.processing 20842 * 20843 * @example 20844 * $(document).ready( function() { 20845 * $('#example').dataTable( { 20846 * "language": { 20847 * "processing": "DataTables is currently busy" 20848 * } 20849 * } ); 20850 * } ); 20851 */ 20852 "sProcessing": "Processing...
vendor: 42,942 bytes, lines 20852-22146
20852", 20853 20854 20855 /** 20856 * Details the actions that will be taken when the user types into the 20857 * filtering input text box. The variable "_INPUT_", if used in the string, 20858 * is replaced with the HTML text box for the filtering input allowing 20859 * control over where it appears in the string. If "_INPUT_" is not given 20860 * then the input box is appended to the string automatically. 20861 * @type string 20862 * @default Search: 20863 * 20864 * @dtopt Language 20865 * @name DataTable.defaults.language.search 20866 * 20867 * @example 20868 * // Input text box will be appended at the end automatically 20869 * $(document).ready( function() { 20870 * $('#example').dataTable( { 20871 * "language": { 20872 * "search": "Filter records:" 20873 * } 20874 * } ); 20875 * } ); 20876 * 20877 * @example 20878 * // Specify where the filter should appear 20879 * $(document).ready( function() { 20880 * $('#example').dataTable( { 20881 * "language": { 20882 * "search": "Apply filter _INPUT_ to table" 20883 * } 20884 * } ); 20885 * } ); 20886 */ 20887 "sSearch": "Search:", 20888 20889 20890 /** 20891 * Assign a `placeholder` attribute to the search `input` element 20892 * @type string 20893 * @default 20894 * 20895 * @dtopt Language 20896 * @name DataTable.defaults.language.searchPlaceholder 20897 */ 20898 "sSearchPlaceholder": "", 20899 20900 20901 /** 20902 * All of the language information can be stored in a file on the 20903 * server-side, which DataTables will look up if this parameter is passed. 20904 * It must store the URL of the language file, which is in a JSON format, 20905 * and the object has the same properties as the oLanguage object in the 20906 * initialiser object (i.e. the above parameters). Please refer to one of 20907 * the example language files to see how this works in action. 20908 * @type string 20909 * @default <i>Empty string - i.e. disabled</i> 20910 * 20911 * @dtopt Language 20912 * @name DataTable.defaults.language.url 20913 * 20914 * @example 20915 * $(document).ready( function() { 20916 * $('#example').dataTable( { 20917 * "language": { 20918 * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt" 20919 * } 20920 * } ); 20921 * } ); 20922 */ 20923 "sUrl": "", 20924 20925 20926 /** 20927 * Text shown inside the table records when the is no information to be 20928 * displayed after filtering. `emptyTable` is shown when there is simply no 20929 * information in the table at all (regardless of filtering). 20930 * @type string 20931 * @default No matching records found 20932 * 20933 * @dtopt Language 20934 * @name DataTable.defaults.language.zeroRecords 20935 * 20936 * @example 20937 * $(document).ready( function() { 20938 * $('#example').dataTable( { 20939 * "language": { 20940 * "zeroRecords": "No records to display" 20941 * } 20942 * } ); 20943 * } ); 20944 */ 20945 "sZeroRecords": "No matching records found" 20946 }, 20947 20948 20949 /** 20950 * This parameter allows you to have define the global filtering state at 20951 * initialisation time. As an object the `search` parameter must be 20952 * defined, but all other parameters are optional. When `regex` is true, 20953 * the search string will be treated as a regular expression, when false 20954 * (default) it will be treated as a straight string. When `smart` 20955 * DataTables will use it's smart filtering methods (to word match at 20956 * any point in the data), when false this will not be done. 20957 * @namespace 20958 * @extends DataTable.models.oSearch 20959 * 20960 * @dtopt Options 20961 * @name DataTable.defaults.search 20962 * 20963 * @example 20964 * $(document).ready( function() { 20965 * $('#example').dataTable( { 20966 * "search": {"search": "Initial search"} 20967 * } ); 20968 * } ) 20969 */ 20970 "oSearch": $.extend( {}, DataTable.models.oSearch ), 20971 20972 20973 /** 20974 * __Deprecated__ The functionality provided by this parameter has now been 20975 * superseded by that provided through `ajax`, which should be used instead. 20976 * 20977 * By default DataTables will look for the property `data` (or `aaData` for 20978 * compatibility with DataTables 1.9-) when obtaining data from an Ajax 20979 * source or for server-side processing - this parameter allows that 20980 * property to be changed. You can use Javascript dotted object notation to 20981 * get a data source for multiple levels of nesting. 20982 * @type string 20983 * @default data 20984 * 20985 * @dtopt Options 20986 * @dtopt Server-side 20987 * @name DataTable.defaults.ajaxDataProp 20988 * 20989 * @deprecated 1.10. Please use `ajax` for this functionality now. 20990 */ 20991 "sAjaxDataProp": "data", 20992 20993 20994 /** 20995 * __Deprecated__ The functionality provided by this parameter has now been 20996 * superseded by that provided through `ajax`, which should be used instead. 20997 * 20998 * You can instruct DataTables to load data from an external 20999 * source using this parameter (use aData if you want to pass data in you 21000 * already have). Simply provide a url a JSON object can be obtained from. 21001 * @type string 21002 * @default null 21003 * 21004 * @dtopt Options 21005 * @dtopt Server-side 21006 * @name DataTable.defaults.ajaxSource 21007 * 21008 * @deprecated 1.10. Please use `ajax` for this functionality now. 21009 */ 21010 "sAjaxSource": null, 21011 21012 21013 /** 21014 * This initialisation variable allows you to specify exactly where in the 21015 * DOM you want DataTables to inject the various controls it adds to the page 21016 * (for example you might want the pagination controls at the top of the 21017 * table). DIV elements (with or without a custom class) can also be added to 21018 * aid styling. The follow syntax is used: 21019 * <ul> 21020 * <li>The following options are allowed: 21021 * <ul> 21022 * <li>'l' - Length changing</li> 21023 * <li>'f' - Filtering input</li> 21024 * <li>'t' - The table!</li> 21025 * <li>'i' - Information</li> 21026 * <li>'p' - Pagination</li> 21027 * <li>'r' - pRocessing</li> 21028 * </ul> 21029 * </li> 21030 * <li>The following constants are allowed: 21031 * <ul> 21032 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li> 21033 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li> 21034 * </ul> 21035 * </li> 21036 * <li>The following syntax is expected: 21037 * <ul> 21038 * <li>'<' and '>' - div elements</li> 21039 * <li>'<"class" and '>' - div with a class</li> 21040 * <li>'<"#id" and '>' - div with an ID</li> 21041 * </ul> 21042 * </li> 21043 * <li>Examples: 21044 * <ul> 21045 * <li>'<"wrapper"flipt>'</li> 21046 * <li>'<lf<t>ip>'</li> 21047 * </ul> 21048 * </li> 21049 * </ul> 21050 * @type string 21051 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b> 21052 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i> 21053 * 21054 * @dtopt Options 21055 * @name DataTable.defaults.dom 21056 * 21057 * @example 21058 * $(document).ready( function() { 21059 * $('#example').dataTable( { 21060 * "dom": '<"top"i>rt<"bottom"flp><"clear">' 21061 * } ); 21062 * } ); 21063 */ 21064 "sDom": "lfrtip", 21065 21066 21067 /** 21068 * Search delay option. This will throttle full table searches that use the 21069 * DataTables provided search input element (it does not effect calls to 21070 * `dt-api search()`, providing a delay before the search is made. 21071 * @type integer 21072 * @default 0 21073 * 21074 * @dtopt Options 21075 * @name DataTable.defaults.searchDelay 21076 * 21077 * @example 21078 * $(document).ready( function() { 21079 * $('#example').dataTable( { 21080 * "searchDelay": 200 21081 * } ); 21082 * } ) 21083 */ 21084 "searchDelay": null, 21085 21086 21087 /** 21088 * DataTables features six different built-in options for the buttons to 21089 * display for pagination control: 21090 * 21091 * * `numbers` - Page number buttons only 21092 * * `simple` - 'Previous' and 'Next' buttons only 21093 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers 21094 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons 21095 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers 21096 * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers 21097 * 21098 * Further methods can be added using {@link DataTable.ext.oPagination}. 21099 * @type string 21100 * @default simple_numbers 21101 * 21102 * @dtopt Options 21103 * @name DataTable.defaults.pagingType 21104 * 21105 * @example 21106 * $(document).ready( function() { 21107 * $('#example').dataTable( { 21108 * "pagingType": "full_numbers" 21109 * } ); 21110 * } ) 21111 */ 21112 "sPaginationType": "simple_numbers", 21113 21114 21115 /** 21116 * Enable horizontal scrolling. When a table is too wide to fit into a 21117 * certain layout, or you have a large number of columns in the table, you 21118 * can enable x-scrolling to show the table in a viewport, which can be 21119 * scrolled. This property can be `true` which will allow the table to 21120 * scroll horizontally when needed, or any CSS unit, or a number (in which 21121 * case it will be treated as a pixel measurement). Setting as simply `true` 21122 * is recommended. 21123 * @type boolean|string 21124 * @default <i>blank string - i.e. disabled</i> 21125 * 21126 * @dtopt Features 21127 * @name DataTable.defaults.scrollX 21128 * 21129 * @example 21130 * $(document).ready( function() { 21131 * $('#example').dataTable( { 21132 * "scrollX": true, 21133 * "scrollCollapse": true 21134 * } ); 21135 * } ); 21136 */ 21137 "sScrollX": "", 21138 21139 21140 /** 21141 * This property can be used to force a DataTable to use more width than it 21142 * might otherwise do when x-scrolling is enabled. For example if you have a 21143 * table which requires to be well spaced, this parameter is useful for 21144 * "over-sizing" the table, and thus forcing scrolling. This property can by 21145 * any CSS unit, or a number (in which case it will be treated as a pixel 21146 * measurement). 21147 * @type string 21148 * @default <i>blank string - i.e. disabled</i> 21149 * 21150 * @dtopt Options 21151 * @name DataTable.defaults.scrollXInner 21152 * 21153 * @example 21154 * $(document).ready( function() { 21155 * $('#example').dataTable( { 21156 * "scrollX": "100%", 21157 * "scrollXInner": "110%" 21158 * } ); 21159 * } ); 21160 */ 21161 "sScrollXInner": "", 21162 21163 21164 /** 21165 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable 21166 * to the given height, and enable scrolling for any data which overflows the 21167 * current viewport. This can be used as an alternative to paging to display 21168 * a lot of data in a small area (although paging and scrolling can both be 21169 * enabled at the same time). This property can be any CSS unit, or a number 21170 * (in which case it will be treated as a pixel measurement). 21171 * @type string 21172 * @default <i>blank string - i.e. disabled</i> 21173 * 21174 * @dtopt Features 21175 * @name DataTable.defaults.scrollY 21176 * 21177 * @example 21178 * $(document).ready( function() { 21179 * $('#example').dataTable( { 21180 * "scrollY": "200px", 21181 * "paginate": false 21182 * } ); 21183 * } ); 21184 */ 21185 "sScrollY": "", 21186 21187 21188 /** 21189 * __Deprecated__ The functionality provided by this parameter has now been 21190 * superseded by that provided through `ajax`, which should be used instead. 21191 * 21192 * Set the HTTP method that is used to make the Ajax call for server-side 21193 * processing or Ajax sourced data. 21194 * @type string 21195 * @default GET 21196 * 21197 * @dtopt Options 21198 * @dtopt Server-side 21199 * @name DataTable.defaults.serverMethod 21200 * 21201 * @deprecated 1.10. Please use `ajax` for this functionality now. 21202 */ 21203 "sServerMethod": "GET", 21204 21205 21206 /** 21207 * DataTables makes use of renderers when displaying HTML elements for 21208 * a table. These renderers can be added or modified by plug-ins to 21209 * generate suitable mark-up for a site. For example the Bootstrap 21210 * integration plug-in for DataTables uses a paging button renderer to 21211 * display pagination buttons in the mark-up required by Bootstrap. 21212 * 21213 * For further information about the renderers available see 21214 * DataTable.ext.renderer 21215 * @type string|object 21216 * @default null 21217 * 21218 * @name DataTable.defaults.renderer 21219 * 21220 */ 21221 "renderer": null, 21222 21223 21224 /** 21225 * Set the data property name that DataTables should use to get a row's id 21226 * to set as the `id` property in the node. 21227 * @type string 21228 * @default DT_RowId 21229 * 21230 * @name DataTable.defaults.rowId 21231 */ 21232 "rowId": "DT_RowId" 21233 }; 21234 21235 _fnHungarianMap( DataTable.defaults ); 21236 21237 21238 21239 /* 21240 * Developer note - See note in model.defaults.js about the use of Hungarian 21241 * notation and camel case. 21242 */ 21243 21244 /** 21245 * Column options that can be given to DataTables at initialisation time. 21246 * @namespace 21247 */ 21248 DataTable.defaults.column = { 21249 /** 21250 * Define which column(s) an order will occur on for this column. This 21251 * allows a column's ordering to take multiple columns into account when 21252 * doing a sort or use the data from a different column. For example first 21253 * name / last name columns make sense to do a multi-column sort over the 21254 * two columns. 21255 * @type array|int 21256 * @default null <i>Takes the value of the column index automatically</i> 21257 * 21258 * @name DataTable.defaults.column.orderData 21259 * @dtopt Columns 21260 * 21261 * @example 21262 * // Using `columnDefs` 21263 * $(document).ready( function() { 21264 * $('#example').dataTable( { 21265 * "columnDefs": [ 21266 * { "orderData": [ 0, 1 ], "targets": [ 0 ] }, 21267 * { "orderData": [ 1, 0 ], "targets": [ 1 ] }, 21268 * { "orderData": 2, "targets": [ 2 ] } 21269 * ] 21270 * } ); 21271 * } ); 21272 * 21273 * @example 21274 * // Using `columns` 21275 * $(document).ready( function() { 21276 * $('#example').dataTable( { 21277 * "columns": [ 21278 * { "orderData": [ 0, 1 ] }, 21279 * { "orderData": [ 1, 0 ] }, 21280 * { "orderData": 2 }, 21281 * null, 21282 * null 21283 * ] 21284 * } ); 21285 * } ); 21286 */ 21287 "aDataSort": null, 21288 "iDataSort": -1, 21289 21290 21291 /** 21292 * You can control the default ordering direction, and even alter the 21293 * behaviour of the sort handler (i.e. only allow ascending ordering etc) 21294 * using this parameter. 21295 * @type array 21296 * @default [ 'asc', 'desc' ] 21297 * 21298 * @name DataTable.defaults.column.orderSequence 21299 * @dtopt Columns 21300 * 21301 * @example 21302 * // Using `columnDefs` 21303 * $(document).ready( function() { 21304 * $('#example').dataTable( { 21305 * "columnDefs": [ 21306 * { "orderSequence": [ "asc" ], "targets": [ 1 ] }, 21307 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] }, 21308 * { "orderSequence": [ "desc" ], "targets": [ 3 ] } 21309 * ] 21310 * } ); 21311 * } ); 21312 * 21313 * @example 21314 * // Using `columns` 21315 * $(document).ready( function() { 21316 * $('#example').dataTable( { 21317 * "columns": [ 21318 * null, 21319 * { "orderSequence": [ "asc" ] }, 21320 * { "orderSequence": [ "desc", "asc", "asc" ] }, 21321 * { "orderSequence": [ "desc" ] }, 21322 * null 21323 * ] 21324 * } ); 21325 * } ); 21326 */ 21327 "asSorting": [ 'asc', 'desc' ], 21328 21329 21330 /** 21331 * Enable or disable filtering on the data in this column. 21332 * @type boolean 21333 * @default true 21334 * 21335 * @name DataTable.defaults.column.searchable 21336 * @dtopt Columns 21337 * 21338 * @example 21339 * // Using `columnDefs` 21340 * $(document).ready( function() { 21341 * $('#example').dataTable( { 21342 * "columnDefs": [ 21343 * { "searchable": false, "targets": [ 0 ] } 21344 * ] } ); 21345 * } ); 21346 * 21347 * @example 21348 * // Using `columns` 21349 * $(document).ready( function() { 21350 * $('#example').dataTable( { 21351 * "columns": [ 21352 * { "searchable": false }, 21353 * null, 21354 * null, 21355 * null, 21356 * null 21357 * ] } ); 21358 * } ); 21359 */ 21360 "bSearchable": true, 21361 21362 21363 /** 21364 * Enable or disable ordering on this column. 21365 * @type boolean 21366 * @default true 21367 * 21368 * @name DataTable.defaults.column.orderable 21369 * @dtopt Columns 21370 * 21371 * @example 21372 * // Using `columnDefs` 21373 * $(document).ready( function() { 21374 * $('#example').dataTable( { 21375 * "columnDefs": [ 21376 * { "orderable": false, "targets": [ 0 ] } 21377 * ] } ); 21378 * } ); 21379 * 21380 * @example 21381 * // Using `columns` 21382 * $(document).ready( function() { 21383 * $('#example').dataTable( { 21384 * "columns": [ 21385 * { "orderable": false }, 21386 * null, 21387 * null, 21388 * null, 21389 * null 21390 * ] } ); 21391 * } ); 21392 */ 21393 "bSortable": true, 21394 21395 21396 /** 21397 * Enable or disable the display of this column. 21398 * @type boolean 21399 * @default true 21400 * 21401 * @name DataTable.defaults.column.visible 21402 * @dtopt Columns 21403 * 21404 * @example 21405 * // Using `columnDefs` 21406 * $(document).ready( function() { 21407 * $('#example').dataTable( { 21408 * "columnDefs": [ 21409 * { "visible": false, "targets": [ 0 ] } 21410 * ] } ); 21411 * } ); 21412 * 21413 * @example 21414 * // Using `columns` 21415 * $(document).ready( function() { 21416 * $('#example').dataTable( { 21417 * "columns": [ 21418 * { "visible": false }, 21419 * null, 21420 * null, 21421 * null, 21422 * null 21423 * ] } ); 21424 * } ); 21425 */ 21426 "bVisible": true, 21427 21428 21429 /** 21430 * Developer definable function that is called whenever a cell is created (Ajax source, 21431 * etc) or processed for input (DOM source). This can be used as a compliment to mRender 21432 * allowing you to modify the DOM element (add background colour for example) when the 21433 * element is available. 21434 * @type function 21435 * @param {element} td The TD node that has been created 21436 * @param {*} cellData The Data for the cell 21437 * @param {array|object} rowData The data for the whole row 21438 * @param {int} row The row index for the aoData data store 21439 * @param {int} col The column index for aoColumns 21440 * 21441 * @name DataTable.defaults.column.createdCell 21442 * @dtopt Columns 21443 * 21444 * @example 21445 * $(document).ready( function() { 21446 * $('#example').dataTable( { 21447 * "columnDefs": [ { 21448 * "targets": [3], 21449 * "createdCell": function (td, cellData, rowData, row, col) { 21450 * if ( cellData == "1.7" ) { 21451 * $(td).css('color', 'blue') 21452 * } 21453 * } 21454 * } ] 21455 * }); 21456 * } ); 21457 */ 21458 "fnCreatedCell": null, 21459 21460 21461 /** 21462 * This parameter has been replaced by `data` in DataTables to ensure naming 21463 * consistency. `dataProp` can still be used, as there is backwards 21464 * compatibility in DataTables for this option, but it is strongly 21465 * recommended that you use `data` in preference to `dataProp`. 21466 * @name DataTable.defaults.column.dataProp 21467 */ 21468 21469 21470 /** 21471 * This property can be used to read data from any data source property, 21472 * including deeply nested objects / properties. `data` can be given in a 21473 * number of different ways which effect its behaviour: 21474 * 21475 * * `integer` - treated as an array index for the data source. This is the 21476 * default that DataTables uses (incrementally increased for each column). 21477 * * `string` - read an object property from the data source. There are 21478 * three 'special' options that can be used in the string to alter how 21479 * DataTables reads the data from the source object: 21480 * * `.` - Dotted Javascript notation. Just as you use a `.` in 21481 * Javascript to read from nested objects, so to can the options 21482 * specified in `data`. For example: `browser.version` or 21483 * `browser.name`. If your object parameter name contains a period, use 21484 * `\\` to escape it - i.e. `first\\.name`. 21485 * * `[]` - Array notation. DataTables can automatically combine data 21486 * from and array source, joining the data with the characters provided 21487 * between the two brackets. For example: `name[, ]` would provide a 21488 * comma-space separated list from the source array. If no characters 21489 * are provided between the brackets, the original array source is 21490 * returned. 21491 * * `()` - Function notation. Adding `()` to the end of a parameter will 21492 * execute a function of the name given. For example: `browser()` for a 21493 * simple function on the data source, `browser.version()` for a 21494 * function in a nested property or even `browser().version` to get an 21495 * object property if the function called returns an object. Note that 21496 * function notation is recommended for use in `render` rather than 21497 * `data` as it is much simpler to use as a renderer. 21498 * * `null` - use the original data source for the row rather than plucking 21499 * data directly from it. This action has effects on two other 21500 * initialisation options: 21501 * * `defaultContent` - When null is given as the `data` option and 21502 * `defaultContent` is specified for the column, the value defined by 21503 * `defaultContent` will be used for the cell. 21504 * * `render` - When null is used for the `data` option and the `render` 21505 * option is specified for the column, the whole data source for the 21506 * row is used for the renderer. 21507 * * `function` - the function given will be executed whenever DataTables 21508 * needs to set or get the data for a cell in the column. The function 21509 * takes three parameters: 21510 * * Parameters: 21511 * * `{array|object}` The data source for the row 21512 * * `{string}` The type call data requested - this will be 'set' when 21513 * setting data or 'filter', 'display', 'type', 'sort' or undefined 21514 * when gathering data. Note that when `undefined` is given for the 21515 * type DataTables expects to get the raw data for the object back< 21516 * * `{*}` Data to set when the second parameter is 'set'. 21517 * * Return: 21518 * * The return value from the function is not required when 'set' is 21519 * the type of call, but otherwise the return is what will be used 21520 * for the data requested. 21521 * 21522 * Note that `data` is a getter and setter option. If you just require 21523 * formatting of data for output, you will likely want to use `render` which 21524 * is simply a getter and thus simpler to use. 21525 * 21526 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The 21527 * name change reflects the flexibility of this property and is consistent 21528 * with the naming of mRender. If 'mDataProp' is given, then it will still 21529 * be used by DataTables, as it automatically maps the old name to the new 21530 * if required. 21531 * 21532 * @type string|int|function|null 21533 * @default null <i>Use automatically calculated column index</i> 21534 * 21535 * @name DataTable.defaults.column.data 21536 * @dtopt Columns 21537 * 21538 * @example 21539 * // Read table data from objects 21540 * // JSON structure for each row: 21541 * // { 21542 * // "engine": {value}, 21543 * // "browser": {value}, 21544 * // "platform": {value}, 21545 * // "version": {value}, 21546 * // "grade": {value} 21547 * // } 21548 * $(document).ready( function() { 21549 * $('#example').dataTable( { 21550 * "ajaxSource": "sources/objects.txt", 21551 * "columns": [ 21552 * { "data": "engine" }, 21553 * { "data": "browser" }, 21554 * { "data": "platform" }, 21555 * { "data": "version" }, 21556 * { "data": "grade" } 21557 * ] 21558 * } ); 21559 * } ); 21560 * 21561 * @example 21562 * // Read information from deeply nested objects 21563 * // JSON structure for each row: 21564 * // { 21565 * // "engine": {value}, 21566 * // "browser": {value}, 21567 * // "platform": { 21568 * // "inner": {value} 21569 * // }, 21570 * // "details": [ 21571 * // {value}, {value} 21572 * // ] 21573 * // } 21574 * $(document).ready( function() { 21575 * $('#example').dataTable( { 21576 * "ajaxSource": "sources/deep.txt", 21577 * "columns": [ 21578 * { "data": "engine" }, 21579 * { "data": "browser" }, 21580 * { "data": "platform.inner" }, 21581 * { "data": "details.0" }, 21582 * { "data": "details.1" } 21583 * ] 21584 * } ); 21585 * } ); 21586 * 21587 * @example 21588 * // Using `data` as a function to provide different information for 21589 * // sorting, filtering and display. In this case, currency (price) 21590 * $(document).ready( function() { 21591 * $('#example').dataTable( { 21592 * "columnDefs": [ { 21593 * "targets": [ 0 ], 21594 * "data": function ( source, type, val ) { 21595 * if (type === 'set') { 21596 * source.price = val; 21597 * // Store the computed dislay and filter values for efficiency 21598 * source.price_display = val=="" ? "" : "$"+numberFormat(val); 21599 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val; 21600 * return; 21601 * } 21602 * else if (type === 'display') { 21603 * return source.price_display; 21604 * } 21605 * else if (type === 'filter') { 21606 * return source.price_filter; 21607 * } 21608 * // 'sort', 'type' and undefined all just use the integer 21609 * return source.price; 21610 * } 21611 * } ] 21612 * } ); 21613 * } ); 21614 * 21615 * @example 21616 * // Using default content 21617 * $(document).ready( function() { 21618 * $('#example').dataTable( { 21619 * "columnDefs": [ { 21620 * "targets": [ 0 ], 21621 * "data": null, 21622 * "defaultContent": "Click to edit" 21623 * } ] 21624 * } ); 21625 * } ); 21626 * 21627 * @example 21628 * // Using array notation - outputting a list from an array 21629 * $(document).ready( function() { 21630 * $('#example').dataTable( { 21631 * "columnDefs": [ { 21632 * "targets": [ 0 ], 21633 * "data": "name[, ]" 21634 * } ] 21635 * } ); 21636 * } ); 21637 * 21638 */ 21639 "mData": null, 21640 21641 21642 /** 21643 * This property is the rendering partner to `data` and it is suggested that 21644 * when you want to manipulate data for display (including filtering, 21645 * sorting etc) without altering the underlying data for the table, use this 21646 * property. `render` can be considered to be the the read only companion to 21647 * `data` which is read / write (then as such more complex). Like `data` 21648 * this option can be given in a number of different ways to effect its 21649 * behaviour: 21650 * 21651 * * `integer` - treated as an array index for the data source. This is the 21652 * default that DataTables uses (incrementally increased for each column). 21653 * * `string` - read an object property from the data source. There are 21654 * three 'special' options that can be used in the string to alter how 21655 * DataTables reads the data from the source object: 21656 * * `.` - Dotted Javascript notation. Just as you use a `.` in 21657 * Javascript to read from nested objects, so to can the options 21658 * specified in `data`. For example: `browser.version` or 21659 * `browser.name`. If your object parameter name contains a period, use 21660 * `\\` to escape it - i.e. `first\\.name`. 21661 * * `[]` - Array notation. DataTables can automatically combine data 21662 * from and array source, joining the data with the characters provided 21663 * between the two brackets. For example: `name[, ]` would provide a 21664 * comma-space separated list from the source array. If no characters 21665 * are provided between the brackets, the original array source is 21666 * returned. 21667 * * `()` - Function notation. Adding `()` to the end of a parameter will 21668 * execute a function of the name given. For example: `browser()` for a 21669 * simple function on the data source, `browser.version()` for a 21670 * function in a nested property or even `browser().version` to get an 21671 * object property if the function called returns an object. 21672 * * `object` - use different data for the different data types requested by 21673 * DataTables ('filter', 'display', 'type' or 'sort'). The property names 21674 * of the object is the data type the property refers to and the value can 21675 * defined using an integer, string or function using the same rules as 21676 * `render` normally does. Note that an `_` option _must_ be specified. 21677 * This is the default value to use if you haven't specified a value for 21678 * the data type requested by DataTables. 21679 * * `function` - the function given will be executed whenever DataTables 21680 * needs to set or get the data for a cell in the column. The function 21681 * takes three parameters: 21682 * * Parameters: 21683 * * {array|object} The data source for the row (based on `data`) 21684 * * {string} The type call data requested - this will be 'filter', 21685 * 'display', 'type' or 'sort'. 21686 * * {array|object} The full data source for the row (not based on 21687 * `data`) 21688 * * Return: 21689 * * The return value from the function is what will be used for the 21690 * data requested. 21691 * 21692 * @type string|int|function|object|null 21693 * @default null Use the data source value. 21694 * 21695 * @name DataTable.defaults.column.render 21696 * @dtopt Columns 21697 * 21698 * @example 21699 * // Create a comma separated list from an array of objects 21700 * $(document).ready( function() { 21701 * $('#example').dataTable( { 21702 * "ajaxSource": "sources/deep.txt", 21703 * "columns": [ 21704 * { "data": "engine" }, 21705 * { "data": "browser" }, 21706 * { 21707 * "data": "platform", 21708 * "render": "[, ].name" 21709 * } 21710 * ] 21711 * } ); 21712 * } ); 21713 * 21714 * @example 21715 * // Execute a function to obtain data 21716 * $(document).ready( function() { 21717 * $('#example').dataTable( { 21718 * "columnDefs": [ { 21719 * "targets": [ 0 ], 21720 * "data": null, // Use the full data source object for the renderer's source 21721 * "render": "browserName()" 21722 * } ] 21723 * } ); 21724 * } ); 21725 * 21726 * @example 21727 * // As an object, extracting different data for the different types 21728 * // This would be used with a data source such as: 21729 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" } 21730 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter` 21731 * // (which has both forms) is used for filtering for if a user inputs either format, while 21732 * // the formatted phone number is the one that is shown in the table. 21733 * $(document).ready( function() { 21734 * $('#example').dataTable( { 21735 * "columnDefs": [ { 21736 * "targets": [ 0 ], 21737 * "data": null, // Use the full data source object for the renderer's source 21738 * "render": { 21739 * "_": "phone", 21740 * "filter": "phone_filter", 21741 * "display": "phone_display" 21742 * } 21743 * } ] 21744 * } ); 21745 * } ); 21746 * 21747 * @example 21748 * // Use as a function to create a link from the data source 21749 * $(document).ready( function() { 21750 * $('#example').dataTable( { 21751 * "columnDefs": [ { 21752 * "targets": [ 0 ], 21753 * "data": "download_link", 21754 * "render": function ( data, type, full ) { 21755 * return '<a href="'+data+'">Download</a>'; 21756 * } 21757 * } ] 21758 * } ); 21759 * } ); 21760 */ 21761 "mRender": null, 21762 21763 21764 /** 21765 * Change the cell type created for the column - either TD cells or TH cells. This 21766 * can be useful as TH cells have semantic meaning in the table body, allowing them 21767 * to act as a header for a row (you may wish to add scope='row' to the TH elements). 21768 * @type string 21769 * @default td 21770 * 21771 * @name DataTable.defaults.column.cellType 21772 * @dtopt Columns 21773 * 21774 * @example 21775 * // Make the first column use TH cells 21776 * $(document).ready( function() { 21777 * $('#example').dataTable( { 21778 * "columnDefs": [ { 21779 * "targets": [ 0 ], 21780 * "cellType": "th" 21781 * } ] 21782 * } ); 21783 * } ); 21784 */ 21785 "sCellType": "td", 21786 21787 21788 /** 21789 * Class to give to each cell in this column. 21790 * @type string 21791 * @default <i>Empty string</i> 21792 * 21793 * @name DataTable.defaults.column.class 21794 * @dtopt Columns 21795 * 21796 * @example 21797 * // Using `columnDefs` 21798 * $(document).ready( function() { 21799 * $('#example').dataTable( { 21800 * "columnDefs": [ 21801 * { "class": "my_class", "targets": [ 0 ] } 21802 * ] 21803 * } ); 21804 * } ); 21805 * 21806 * @example 21807 * // Using `columns` 21808 * $(document).ready( function() { 21809 * $('#example').dataTable( { 21810 * "columns": [ 21811 * { "class": "my_class" }, 21812 * null, 21813 * null, 21814 * null, 21815 * null 21816 * ] 21817 * } ); 21818 * } ); 21819 */ 21820 "sClass": "", 21821 21822 /** 21823 * When DataTables calculates the column widths to assign to each column, 21824 * it finds the longest string in each column and then constructs a 21825 * temporary table and reads the widths from that. The problem with this 21826 * is that "mmm" is much wider then "iiii", but the latter is a longer 21827 * string - thus the calculation can go wrong (doing it properly and putting 21828 * it into an DOM object and measuring that is horribly(!) slow). Thus as 21829 * a "work around" we provide this option. It will append its value to the 21830 * text that is found to be the longest string for the column - i.e. padding. 21831 * Generally you shouldn't need this! 21832 * @type string 21833 * @default <i>Empty string<i> 21834 * 21835 * @name DataTable.defaults.column.contentPadding 21836 * @dtopt Columns 21837 * 21838 * @example 21839 * // Using `columns` 21840 * $(document).ready( function() { 21841 * $('#example').dataTable( { 21842 * "columns": [ 21843 * null, 21844 * null, 21845 * null, 21846 * { 21847 * "contentPadding": "mmm" 21848 * } 21849 * ] 21850 * } ); 21851 * } ); 21852 */ 21853 "sContentPadding": "", 21854 21855 21856 /** 21857 * Allows a default value to be given for a column's data, and will be used 21858 * whenever a null data source is encountered (this can be because `data` 21859 * is set to null, or because the data source itself is null). 21860 * @type string 21861 * @default null 21862 * 21863 * @name DataTable.defaults.column.defaultContent 21864 * @dtopt Columns 21865 * 21866 * @example 21867 * // Using `columnDefs` 21868 * $(document).ready( function() { 21869 * $('#example').dataTable( { 21870 * "columnDefs": [ 21871 * { 21872 * "data": null, 21873 * "defaultContent": "Edit", 21874 * "targets": [ -1 ] 21875 * } 21876 * ] 21877 * } ); 21878 * } ); 21879 * 21880 * @example 21881 * // Using `columns` 21882 * $(document).ready( function() { 21883 * $('#example').dataTable( { 21884 * "columns": [ 21885 * null, 21886 * null, 21887 * null, 21888 * { 21889 * "data": null, 21890 * "defaultContent": "Edit" 21891 * } 21892 * ] 21893 * } ); 21894 * } ); 21895 */ 21896 "sDefaultContent": null, 21897 21898 21899 /** 21900 * This parameter is only used in DataTables' server-side processing. It can 21901 * be exceptionally useful to know what columns are being displayed on the 21902 * client side, and to map these to database fields. When defined, the names 21903 * also allow DataTables to reorder information from the server if it comes 21904 * back in an unexpected order (i.e. if you switch your columns around on the 21905 * client-side, your server-side code does not also need updating). 21906 * @type string 21907 * @default <i>Empty string</i> 21908 * 21909 * @name DataTable.defaults.column.name 21910 * @dtopt Columns 21911 * 21912 * @example 21913 * // Using `columnDefs` 21914 * $(document).ready( function() { 21915 * $('#example').dataTable( { 21916 * "columnDefs": [ 21917 * { "name": "engine", "targets": [ 0 ] }, 21918 * { "name": "browser", "targets": [ 1 ] }, 21919 * { "name": "platform", "targets": [ 2 ] }, 21920 * { "name": "version", "targets": [ 3 ] }, 21921 * { "name": "grade", "targets": [ 4 ] } 21922 * ] 21923 * } ); 21924 * } ); 21925 * 21926 * @example 21927 * // Using `columns` 21928 * $(document).ready( function() { 21929 * $('#example').dataTable( { 21930 * "columns": [ 21931 * { "name": "engine" }, 21932 * { "name": "browser" }, 21933 * { "name": "platform" }, 21934 * { "name": "version" }, 21935 * { "name": "grade" } 21936 * ] 21937 * } ); 21938 * } ); 21939 */ 21940 "sName": "", 21941 21942 21943 /** 21944 * Defines a data source type for the ordering which can be used to read 21945 * real-time information from the table (updating the internally cached 21946 * version) prior to ordering. This allows ordering to occur on user 21947 * editable elements such as form inputs. 21948 * @type string 21949 * @default std 21950 * 21951 * @name DataTable.defaults.column.orderDataType 21952 * @dtopt Columns 21953 * 21954 * @example 21955 * // Using `columnDefs` 21956 * $(document).ready( function() { 21957 * $('#example').dataTable( { 21958 * "columnDefs": [ 21959 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] }, 21960 * { "type": "numeric", "targets": [ 3 ] }, 21961 * { "orderDataType": "dom-select", "targets": [ 4 ] }, 21962 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] } 21963 * ] 21964 * } ); 21965 * } ); 21966 * 21967 * @example 21968 * // Using `columns` 21969 * $(document).ready( function() { 21970 * $('#example').dataTable( { 21971 * "columns": [ 21972 * null, 21973 * null, 21974 * { "orderDataType": "dom-text" }, 21975 * { "orderDataType": "dom-text", "type": "numeric" }, 21976 * { "orderDataType": "dom-select" }, 21977 * { "orderDataType": "dom-checkbox" } 21978 * ] 21979 * } ); 21980 * } ); 21981 */ 21982 "sSortDataType": "std", 21983 21984 21985 /** 21986 * The title of this column. 21987 * @type string 21988 * @default null <i>Derived from the 'TH' value for this column in the 21989 * original HTML table.</i> 21990 * 21991 * @name DataTable.defaults.column.title 21992 * @dtopt Columns 21993 * 21994 * @example 21995 * // Using `columnDefs` 21996 * $(document).ready( function() { 21997 * $('#example').dataTable( { 21998 * "columnDefs": [ 21999 * { "title": "My column title", "targets": [ 0 ] } 22000 * ] 22001 * } ); 22002 * } ); 22003 * 22004 * @example 22005 * // Using `columns` 22006 * $(document).ready( function() { 22007 * $('#example').dataTable( { 22008 * "columns": [ 22009 * { "title": "My column title" }, 22010 * null, 22011 * null, 22012 * null, 22013 * null 22014 * ] 22015 * } ); 22016 * } ); 22017 */ 22018 "sTitle": null, 22019 22020 22021 /** 22022 * The type allows you to specify how the data for this column will be 22023 * ordered. Four types (string, numeric, date and html (which will strip 22024 * HTML tags before ordering)) are currently available. Note that only date 22025 * formats understood by Javascript's Date() object will be accepted as type 22026 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 22027 * 'numeric', 'date' or 'html' (by default). Further types can be adding 22028 * through plug-ins. 22029 * @type string 22030 * @default null <i>Auto-detected from raw data</i> 22031 * 22032 * @name DataTable.defaults.column.type 22033 * @dtopt Columns 22034 * 22035 * @example 22036 * // Using `columnDefs` 22037 * $(document).ready( function() { 22038 * $('#example').dataTable( { 22039 * "columnDefs": [ 22040 * { "type": "html", "targets": [ 0 ] } 22041 * ] 22042 * } ); 22043 * } ); 22044 * 22045 * @example 22046 * // Using `columns` 22047 * $(document).ready( function() { 22048 * $('#example').dataTable( { 22049 * "columns": [ 22050 * { "type": "html" }, 22051 * null, 22052 * null, 22053 * null, 22054 * null 22055 * ] 22056 * } ); 22057 * } ); 22058 */ 22059 "sType": null, 22060 22061 22062 /** 22063 * Defining the width of the column, this parameter may take any CSS value 22064 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not 22065 * been given a specific width through this interface ensuring that the table 22066 * remains readable. 22067 * @type string 22068 * @default null <i>Automatic</i> 22069 * 22070 * @name DataTable.defaults.column.width 22071 * @dtopt Columns 22072 * 22073 * @example 22074 * // Using `columnDefs` 22075 * $(document).ready( function() { 22076 * $('#example').dataTable( { 22077 * "columnDefs": [ 22078 * { "width": "20%", "targets": [ 0 ] } 22079 * ] 22080 * } ); 22081 * } ); 22082 * 22083 * @example 22084 * // Using `columns` 22085 * $(document).ready( function() { 22086 * $('#example').dataTable( { 22087 * "columns": [ 22088 * { "width": "20%" }, 22089 * null, 22090 * null, 22091 * null, 22092 * null 22093 * ] 22094 * } ); 22095 * } ); 22096 */ 22097 "sWidth": null 22098 }; 22099 22100 _fnHungarianMap( DataTable.defaults.column ); 22101 22102 22103 22104 /** 22105 * DataTables settings object - this holds all the information needed for a 22106 * given table, including configuration, data and current application of the 22107 * table options. DataTables does not have a single instance for each DataTable 22108 * with the settings attached to that instance, but rather instances of the 22109 * DataTable "class" are created on-the-fly as needed (typically by a 22110 * $().dataTable() call) and the settings object is then applied to that 22111 * instance. 22112 * 22113 * Note that this object is related to {@link DataTable.defaults} but this 22114 * one is the internal data store for DataTables's cache of columns. It should 22115 * NOT be manipulated outside of DataTables. Any configuration should be done 22116 * through the initialisation options. 22117 * @namespace 22118 * @todo Really should attach the settings object to individual instances so we 22119 * don't need to create new instances on each $().dataTable() call (if the 22120 * table already exists). It would also save passing oSettings around and 22121 * into every single function. However, this is a very significant 22122 * architecture change for DataTables and will almost certainly break 22123 * backwards compatibility with older installations. This is something that 22124 * will be done in 2.0. 22125 */ 22126 DataTable.models.oSettings = { 22127 /** 22128 * Primary features of DataTables and their enablement state. 22129 * @namespace 22130 */ 22131 "oFeatures": { 22132 22133 /** 22134 * Flag to say if DataTables should automatically try to calculate the 22135 * optimum table and columns widths (true) or not (false). 22136 * Note that this parameter will be set by the initialisation routine. To 22137 * set a default use {@link DataTable.defaults}. 22138 * @type boolean 22139 */ 22140 "bAutoWidth": null, 22141 22142 /** 22143 * Delay the creation of TR and TD elements until they are actually 22144 * needed by a driven page draw. This can give a significant speed 22145 * increase for Ajax source and Javascript source data, but makes no 22146 * difference at all f
22146ro
vendor: 14,836 bytes, lines 22146-22723
22146 DOM and server-side processing tables. 22147 * Note that this parameter will be set by the initialisation routine. To 22148 * set a default use {@link DataTable.defaults}. 22149 * @type boolean 22150 */ 22151 "bDeferRender": null, 22152 22153 /** 22154 * Enable filtering on the table or not. Note that if this is disabled 22155 * then there is no filtering at all on the table, including fnFilter. 22156 * To just remove the filtering input use sDom and remove the 'f' option. 22157 * Note that this parameter will be set by the initialisation routine. To 22158 * set a default use {@link DataTable.defaults}. 22159 * @type boolean 22160 */ 22161 "bFilter": null, 22162 22163 /** 22164 * Table information element (the 'Showing x of y records' div) enable 22165 * flag. 22166 * Note that this parameter will be set by the initialisation routine. To 22167 * set a default use {@link DataTable.defaults}. 22168 * @type boolean 22169 */ 22170 "bInfo": null, 22171 22172 /** 22173 * Present a user control allowing the end user to change the page size 22174 * when pagination is enabled. 22175 * Note that this parameter will be set by the initialisation routine. To 22176 * set a default use {@link DataTable.defaults}. 22177 * @type boolean 22178 */ 22179 "bLengthChange": null, 22180 22181 /** 22182 * Pagination enabled or not. Note that if this is disabled then length 22183 * changing must also be disabled. 22184 * Note that this parameter will be set by the initialisation routine. To 22185 * set a default use {@link DataTable.defaults}. 22186 * @type boolean 22187 */ 22188 "bPaginate": null, 22189 22190 /** 22191 * Processing indicator enable flag whenever DataTables is enacting a 22192 * user request - typically an Ajax request for server-side processing. 22193 * Note that this parameter will be set by the initialisation routine. To 22194 * set a default use {@link DataTable.defaults}. 22195 * @type boolean 22196 */ 22197 "bProcessing": null, 22198 22199 /** 22200 * Server-side processing enabled flag - when enabled DataTables will 22201 * get all data from the server for every draw - there is no filtering, 22202 * sorting or paging done on the client-side. 22203 * Note that this parameter will be set by the initialisation routine. To 22204 * set a default use {@link DataTable.defaults}. 22205 * @type boolean 22206 */ 22207 "bServerSide": null, 22208 22209 /** 22210 * Sorting enablement flag. 22211 * Note that this parameter will be set by the initialisation routine. To 22212 * set a default use {@link DataTable.defaults}. 22213 * @type boolean 22214 */ 22215 "bSort": null, 22216 22217 /** 22218 * Multi-column sorting 22219 * Note that this parameter will be set by the initialisation routine. To 22220 * set a default use {@link DataTable.defaults}. 22221 * @type boolean 22222 */ 22223 "bSortMulti": null, 22224 22225 /** 22226 * Apply a class to the columns which are being sorted to provide a 22227 * visual highlight or not. This can slow things down when enabled since 22228 * there is a lot of DOM interaction. 22229 * Note that this parameter will be set by the initialisation routine. To 22230 * set a default use {@link DataTable.defaults}. 22231 * @type boolean 22232 */ 22233 "bSortClasses": null, 22234 22235 /** 22236 * State saving enablement flag. 22237 * Note that this parameter will be set by the initialisation routine. To 22238 * set a default use {@link DataTable.defaults}. 22239 * @type boolean 22240 */ 22241 "bStateSave": null 22242 }, 22243 22244 22245 /** 22246 * Scrolling settings for a table. 22247 * @namespace 22248 */ 22249 "oScroll": { 22250 /** 22251 * When the table is shorter in height than sScrollY, collapse the 22252 * table container down to the height of the table (when true). 22253 * Note that this parameter will be set by the initialisation routine. To 22254 * set a default use {@link DataTable.defaults}. 22255 * @type boolean 22256 */ 22257 "bCollapse": null, 22258 22259 /** 22260 * Width of the scrollbar for the web-browser's platform. Calculated 22261 * during table initialisation. 22262 * @type int 22263 * @default 0 22264 */ 22265 "iBarWidth": 0, 22266 22267 /** 22268 * Viewport width for horizontal scrolling. Horizontal scrolling is 22269 * disabled if an empty string. 22270 * Note that this parameter will be set by the initialisation routine. To 22271 * set a default use {@link DataTable.defaults}. 22272 * @type string 22273 */ 22274 "sX": null, 22275 22276 /** 22277 * Width to expand the table to when using x-scrolling. Typically you 22278 * should not need to use this. 22279 * Note that this parameter will be set by the initialisation routine. To 22280 * set a default use {@link DataTable.defaults}. 22281 * @type string 22282 * @deprecated 22283 */ 22284 "sXInner": null, 22285 22286 /** 22287 * Viewport height for vertical scrolling. Vertical scrolling is disabled 22288 * if an empty string. 22289 * Note that this parameter will be set by the initialisation routine. To 22290 * set a default use {@link DataTable.defaults}. 22291 * @type string 22292 */ 22293 "sY": null 22294 }, 22295 22296 /** 22297 * Language information for the table. 22298 * @namespace 22299 * @extends DataTable.defaults.oLanguage 22300 */ 22301 "oLanguage": { 22302 /** 22303 * Information callback function. See 22304 * {@link DataTable.defaults.fnInfoCallback} 22305 * @type function 22306 * @default null 22307 */ 22308 "fnInfoCallback": null 22309 }, 22310 22311 /** 22312 * Browser support parameters 22313 * @namespace 22314 */ 22315 "oBrowser": { 22316 /** 22317 * Indicate if the browser incorrectly calculates width:100% inside a 22318 * scrolling element (IE6/7) 22319 * @type boolean 22320 * @default false 22321 */ 22322 "bScrollOversize": false, 22323 22324 /** 22325 * Determine if the vertical scrollbar is on the right or left of the 22326 * scrolling container - needed for rtl language layout, although not 22327 * all browsers move the scrollbar (Safari). 22328 * @type boolean 22329 * @default false 22330 */ 22331 "bScrollbarLeft": false, 22332 22333 /** 22334 * Flag for if `getBoundingClientRect` is fully supported or not 22335 * @type boolean 22336 * @default false 22337 */ 22338 "bBounding": false, 22339 22340 /** 22341 * Browser scrollbar width 22342 * @type integer 22343 * @default 0 22344 */ 22345 "barWidth": 0 22346 }, 22347 22348 22349 "ajax": null, 22350 22351 22352 /** 22353 * Array referencing the nodes which are used for the features. The 22354 * parameters of this object match what is allowed by sDom - i.e. 22355 * <ul> 22356 * <li>'l' - Length changing</li> 22357 * <li>'f' - Filtering input</li> 22358 * <li>'t' - The table!</li> 22359 * <li>'i' - Information</li> 22360 * <li>'p' - Pagination</li> 22361 * <li>'r' - pRocessing</li> 22362 * </ul> 22363 * @type array 22364 * @default [] 22365 */ 22366 "aanFeatures": [], 22367 22368 /** 22369 * Store data information - see {@link DataTable.models.oRow} for detailed 22370 * information. 22371 * @type array 22372 * @default [] 22373 */ 22374 "aoData": [], 22375 22376 /** 22377 * Array of indexes which are in the current display (after filtering etc) 22378 * @type array 22379 * @default [] 22380 */ 22381 "aiDisplay": [], 22382 22383 /** 22384 * Array of indexes for display - no filtering 22385 * @type array 22386 * @default [] 22387 */ 22388 "aiDisplayMaster": [], 22389 22390 /** 22391 * Map of row ids to data indexes 22392 * @type object 22393 * @default {} 22394 */ 22395 "aIds": {}, 22396 22397 /** 22398 * Store information about each column that is in use 22399 * @type array 22400 * @default [] 22401 */ 22402 "aoColumns": [], 22403 22404 /** 22405 * Store information about the table's header 22406 * @type array 22407 * @default [] 22408 */ 22409 "aoHeader": [], 22410 22411 /** 22412 * Store information about the table's footer 22413 * @type array 22414 * @default [] 22415 */ 22416 "aoFooter": [], 22417 22418 /** 22419 * Store the applied global search information in case we want to force a 22420 * research or compare the old search to a new one. 22421 * Note that this parameter will be set by the initialisation routine. To 22422 * set a default use {@link DataTable.defaults}. 22423 * @namespace 22424 * @extends DataTable.models.oSearch 22425 */ 22426 "oPreviousSearch": {}, 22427 22428 /** 22429 * Store the applied search for each column - see 22430 * {@link DataTable.models.oSearch} for the format that is used for the 22431 * filtering information for each column. 22432 * @type array 22433 * @default [] 22434 */ 22435 "aoPreSearchCols": [], 22436 22437 /** 22438 * Sorting that is applied to the table. Note that the inner arrays are 22439 * used in the following manner: 22440 * <ul> 22441 * <li>Index 0 - column number</li> 22442 * <li>Index 1 - current sorting direction</li> 22443 * </ul> 22444 * Note that this parameter will be set by the initialisation routine. To 22445 * set a default use {@link DataTable.defaults}. 22446 * @type array 22447 * @todo These inner arrays should really be objects 22448 */ 22449 "aaSorting": null, 22450 22451 /** 22452 * Sorting that is always applied to the table (i.e. prefixed in front of 22453 * aaSorting). 22454 * Note that this parameter will be set by the initialisation routine. To 22455 * set a default use {@link DataTable.defaults}. 22456 * @type array 22457 * @default [] 22458 */ 22459 "aaSortingFixed": [], 22460 22461 /** 22462 * Classes to use for the striping of a table. 22463 * Note that this parameter will be set by the initialisation routine. To 22464 * set a default use {@link DataTable.defaults}. 22465 * @type array 22466 * @default [] 22467 */ 22468 "asStripeClasses": null, 22469 22470 /** 22471 * If restoring a table - we should restore its striping classes as well 22472 * @type array 22473 * @default [] 22474 */ 22475 "asDestroyStripes": [], 22476 22477 /** 22478 * If restoring a table - we should restore its width 22479 * @type int 22480 * @default 0 22481 */ 22482 "sDestroyWidth": 0, 22483 22484 /** 22485 * Callback functions array for every time a row is inserted (i.e. on a draw). 22486 * @type array 22487 * @default [] 22488 */ 22489 "aoRowCallback": [], 22490 22491 /** 22492 * Callback functions for the header on each draw. 22493 * @type array 22494 * @default [] 22495 */ 22496 "aoHeaderCallback": [], 22497 22498 /** 22499 * Callback function for the footer on each draw. 22500 * @type array 22501 * @default [] 22502 */ 22503 "aoFooterCallback": [], 22504 22505 /** 22506 * Array of callback functions for draw callback functions 22507 * @type array 22508 * @default [] 22509 */ 22510 "aoDrawCallback": [], 22511 22512 /** 22513 * Array of callback functions for row created function 22514 * @type array 22515 * @default [] 22516 */ 22517 "aoRowCreatedCallback": [], 22518 22519 /** 22520 * Callback functions for just before the table is redrawn. A return of 22521 * false will be used to cancel the draw. 22522 * @type array 22523 * @default [] 22524 */ 22525 "aoPreDrawCallback": [], 22526 22527 /** 22528 * Callback functions for when the table has been initialised. 22529 * @type array 22530 * @default [] 22531 */ 22532 "aoInitComplete": [], 22533 22534 22535 /** 22536 * Callbacks for modifying the settings to be stored for state saving, prior to 22537 * saving state. 22538 * @type array 22539 * @default [] 22540 */ 22541 "aoStateSaveParams": [], 22542 22543 /** 22544 * Callbacks for modifying the settings that have been stored for state saving 22545 * prior to using the stored values to restore the state. 22546 * @type array 22547 * @default [] 22548 */ 22549 "aoStateLoadParams": [], 22550 22551 /** 22552 * Callbacks for operating on the settings object once the saved state has been 22553 * loaded 22554 * @type array 22555 * @default [] 22556 */ 22557 "aoStateLoaded": [], 22558 22559 /** 22560 * Cache the table ID for quick access 22561 * @type string 22562 * @default <i>Empty string</i> 22563 */ 22564 "sTableId": "", 22565 22566 /** 22567 * The TABLE node for the main table 22568 * @type node 22569 * @default null 22570 */ 22571 "nTable": null, 22572 22573 /** 22574 * Permanent ref to the thead element 22575 * @type node 22576 * @default null 22577 */ 22578 "nTHead": null, 22579 22580 /** 22581 * Permanent ref to the tfoot element - if it exists 22582 * @type node 22583 * @default null 22584 */ 22585 "nTFoot": null, 22586 22587 /** 22588 * Permanent ref to the tbody element 22589 * @type node 22590 * @default null 22591 */ 22592 "nTBody": null, 22593 22594 /** 22595 * Cache the wrapper node (contains all DataTables controlled elements) 22596 * @type node 22597 * @default null 22598 */ 22599 "nTableWrapper": null, 22600 22601 /** 22602 * Indicate if when using server-side processing the loading of data 22603 * should be deferred until the second draw. 22604 * Note that this parameter will be set by the initialisation routine. To 22605 * set a default use {@link DataTable.defaults}. 22606 * @type boolean 22607 * @default false 22608 */ 22609 "bDeferLoading": false, 22610 22611 /** 22612 * Indicate if all required information has been read in 22613 * @type boolean 22614 * @default false 22615 */ 22616 "bInitialised": false, 22617 22618 /** 22619 * Information about open rows. Each object in the array has the parameters 22620 * 'nTr' and 'nParent' 22621 * @type array 22622 * @default [] 22623 */ 22624 "aoOpenRows": [], 22625 22626 /** 22627 * Dictate the positioning of DataTables' control elements - see 22628 * {@link DataTable.model.oInit.sDom}. 22629 * Note that this parameter will be set by the initialisation routine. To 22630 * set a default use {@link DataTable.defaults}. 22631 * @type string 22632 * @default null 22633 */ 22634 "sDom": null, 22635 22636 /** 22637 * Search delay (in mS) 22638 * @type integer 22639 * @default null 22640 */ 22641 "searchDelay": null, 22642 22643 /** 22644 * Which type of pagination should be used. 22645 * Note that this parameter will be set by the initialisation routine. To 22646 * set a default use {@link DataTable.defaults}. 22647 * @type string 22648 * @default two_button 22649 */ 22650 "sPaginationType": "two_button", 22651 22652 /** 22653 * The state duration (for `stateSave`) in seconds. 22654 * Note that this parameter will be set by the initialisation routine. To 22655 * set a default use {@link DataTable.defaults}. 22656 * @type int 22657 * @default 0 22658 */ 22659 "iStateDuration": 0, 22660 22661 /** 22662 * Array of callback functions for state saving. Each array element is an 22663 * object with the following parameters: 22664 * <ul> 22665 * <li>function:fn - function to call. Takes two parameters, oSettings 22666 * and the JSON string to save that has been thus far created. Returns 22667 * a JSON string to be inserted into a json object 22668 * (i.e. '"param": [ 0, 1, 2]')</li> 22669 * <li>string:sName - name of callback</li> 22670 * </ul> 22671 * @type array 22672 * @default [] 22673 */ 22674 "aoStateSave": [], 22675 22676 /** 22677 * Array of callback functions for state loading. Each array element is an 22678 * object with the following parameters: 22679 * <ul> 22680 * <li>function:fn - function to call. Takes two parameters, oSettings 22681 * and the object stored. May return false to cancel state loading</li> 22682 * <li>string:sName - name of callback</li> 22683 * </ul> 22684 * @type array 22685 * @default [] 22686 */ 22687 "aoStateLoad": [], 22688 22689 /** 22690 * State that was saved. Useful for back reference 22691 * @type object 22692 * @default null 22693 */ 22694 "oSavedState": null, 22695 22696 /** 22697 * State that was loaded. Useful for back reference 22698 * @type object 22699 * @default null 22700 */ 22701 "oLoadedState": null, 22702 22703 /** 22704 * Source url for AJAX data for the table. 22705 * Note that this parameter will be set by the initialisation routine. To 22706 * set a default use {@link DataTable.defaults}. 22707 * @type string 22708 * @default null 22709 */ 22710 "sAjaxSource": null, 22711 22712 /** 22713 * Property from a given object from which to read the table data from. This 22714 * can be an empty string (when not server-side processing), in which case 22715 * it is assumed an an array is given directly. 22716 * Note that this parameter will be set by the initialisation routine. To 22717 * set a default use {@link DataTable.defaults}. 22718 * @type string 22719 */ 22720 "sAjaxDataProp": null, 22721 22722 /** 22723 *
22723Note if draw should be blocked while getting data 22724 * @type boolean 22725 * @default true 22726 */ 22727 "bAjaxDataGet": true, 22728 22729 /** 22730 * The last jQuery XHR object that was used for server-side data gathering. 22731 * This can be used for working with the XHR information in one of the 22732 * callbacks 22733 * @type object 22734 * @default null 22735 */ 22736 "jqXHR": null, 22737 22738 /** 22739 * JSON returned from the server in the last Ajax request 22740 * @type object 22741 * @default undefined 22742 */ 22743 "json": undefined, 22744 22745 /** 22746 * Data submitted as part of the last Ajax request 22747 * @type object 22748 * @default undefined 22749 */ 22750 "oAjaxData": undefined, 22751 22752 /** 22753 * Function to get the server-side data. 22754 * Note that this parameter will be set by the initialisation routine. To 22755 * set a default use {@link DataTable.defaults}. 22756 * @type function 22757 */ 22758 "fnServerData": null, 22759 22760 /** 22761 * Functions which are called prior to sending an Ajax request so extra 22762 * parameters can easily be sent to the server 22763 * @type array 22764 * @default [] 22765 */ 22766 "aoServerParams": [], 22767 22768 /** 22769 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if 22770 * required). 22771 * Note that this parameter will be set by the initialisation routine. To 22772 * set a default use {@link DataTable.defaults}. 22773 * @type string 22774 */ 22775 "sServerMethod": null, 22776 22777 /** 22778 * Format numbers for display. 22779 * Note that this parameter will be set by the initialisation routine. To 22780 * set a default use {@link DataTable.defaults}. 22781 * @type function 22782 */ 22783 "fnFormatNumber": null, 22784 22785 /** 22786 * List of options that can be used for the user selectable length menu. 22787 * Note that this parameter will be set by the initialisation routine. To 22788 * set a default use {@link DataTable.defaults}. 22789 * @type array 22790 * @default [] 22791 */ 22792 "aLengthMenu": null, 22793 22794 /** 22795 * Counter for the draws that the table does. Also used as a tracker for 22796 * server-side processing 22797 * @type int 22798 * @default 0 22799 */ 22800 "iDraw": 0, 22801 22802 /** 22803 * Indicate if a redraw is being done - useful for Ajax 22804 * @type boolean 22805 * @default false 22806 */ 22807 "bDrawing": false, 22808 22809 /** 22810 * Draw index (iDraw) of the last error when parsing the returned data 22811 * @type int 22812 * @default -1 22813 */ 22814 "iDrawError": -1, 22815 22816 /** 22817 * Paging display length 22818 * @type int 22819 * @default 10 22820 */ 22821 "_iDisplayLength": 10, 22822 22823 /** 22824 * Paging start point - aiDisplay index 22825 * @type int 22826 * @default 0 22827 */ 22828 "_iDisplayStart": 0, 22829 22830 /** 22831 * Server-side processing - number of records in the result set 22832 * (i.e. before filtering), Use fnRecordsTotal rather than 22833 * this property to get the value of the number of records, regardless of 22834 * the server-side processing setting. 22835 * @type int 22836 * @default 0 22837 * @private 22838 */ 22839 "_iRecordsTotal": 0, 22840 22841 /** 22842 * Server-side processing - number of records in the current display set 22843 * (i.e. after filtering). Use fnRecordsDisplay rather than 22844 * this property to get the value of the number of records, regardless of 22845 * the server-side processing setting. 22846 * @type boolean 22847 * @default 0 22848 * @private 22849 */ 22850 "_iRecordsDisplay": 0, 22851 22852 /** 22853 * The classes to use for the table 22854 * @type object 22855 * @default {} 22856 */
vendor: 4,924 bytes, lines 22857-23065
22857 "oClasses": {}, 22858 22859 /** 22860 * Flag attached to the settings object so you can check in the draw 22861 * callback if filtering has been done in the draw. Deprecated in favour of 22862 * events. 22863 * @type boolean 22864 * @default false 22865 * @deprecated 22866 */ 22867 "bFiltered": false, 22868 22869 /** 22870 * Flag attached to the settings object so you can check in the draw 22871 * callback if sorting has been done in the draw. Deprecated in favour of 22872 * events. 22873 * @type boolean 22874 * @default false 22875 * @deprecated 22876 */ 22877 "bSorted": false, 22878 22879 /** 22880 * Indicate that if multiple rows are in the header and there is more than 22881 * one unique cell per column, if the top one (true) or bottom one (false) 22882 * should be used for sorting / title by DataTables. 22883 * Note that this parameter will be set by the initialisation routine. To 22884 * set a default use {@link DataTable.defaults}. 22885 * @type boolean 22886 */ 22887 "bSortCellsTop": null, 22888 22889 /** 22890 * Initialisation object that is used for the table 22891 * @type object 22892 * @default null 22893 */ 22894 "oInit": null, 22895 22896 /** 22897 * Destroy callback functions - for plug-ins to attach themselves to the 22898 * destroy so they can clean up markup and events. 22899 * @type array 22900 * @default [] 22901 */ 22902 "aoDestroyCallback": [], 22903 22904 22905 /** 22906 * Get the number of records in the current record set, before filtering 22907 * @type function 22908 */ 22909 "fnRecordsTotal": function () 22910 { 22911 return _fnDataSource( this ) == 'ssp' ? 22912 this._iRecordsTotal * 1 : 22913 this.aiDisplayMaster.length; 22914 }, 22915 22916 /** 22917 * Get the number of records in the current record set, after filtering 22918 * @type function 22919 */ 22920 "fnRecordsDisplay": function () 22921 { 22922 return _fnDataSource( this ) == 'ssp' ? 22923 this._iRecordsDisplay * 1 : 22924 this.aiDisplay.length; 22925 }, 22926 22927 /** 22928 * Get the display end point - aiDisplay index 22929 * @type function 22930 */ 22931 "fnDisplayEnd": function () 22932 { 22933 var 22934 len = this._iDisplayLength, 22935 start = this._iDisplayStart, 22936 calc = start + len, 22937 records = this.aiDisplay.length, 22938 features = this.oFeatures, 22939 paginate = features.bPaginate; 22940 22941 if ( features.bServerSide ) { 22942 return paginate === false || len === -1 ? 22943 start + records : 22944 Math.min( start+len, this._iRecordsDisplay ); 22945 } 22946 else { 22947 return ! paginate || calc>records || len===-1 ? 22948 records : 22949 calc; 22950 } 22951 }, 22952 22953 /** 22954 * The DataTables object for this table 22955 * @type object 22956 * @default null 22957 */ 22958 "oInstance": null, 22959 22960 /** 22961 * Unique identifier for each instance of the DataTables object. If there 22962 * is an ID on the table node, then it takes that value, otherwise an 22963 * incrementing internal counter is used. 22964 * @type string 22965 * @default null 22966 */ 22967 "sInstance": null, 22968 22969 /** 22970 * tabindex attribute value that is added to DataTables control elements, allowing 22971 * keyboard navigation of the table and its controls. 22972 */ 22973 "iTabIndex": 0, 22974 22975 /** 22976 * DIV container for the footer scrolling table if scrolling 22977 */ 22978 "nScrollHead": null, 22979 22980 /** 22981 * DIV container for the footer scrolling table if scrolling 22982 */ 22983 "nScrollFoot": null, 22984 22985 /** 22986 * Last applied sort 22987 * @type array 22988 * @default [] 22989 */ 22990 "aLastSort": [], 22991 22992 /** 22993 * Stored plug-in instances 22994 * @type object 22995 * @default {} 22996 */ 22997 "oPlugins": {}, 22998 22999 /** 23000 * Function used to get a row's id from the row's data 23001 * @type function 23002 * @default null 23003 */ 23004 "rowIdFn": null, 23005 23006 /** 23007 * Data location where to store a row's id 23008 * @type string 23009 * @default null 23010 */ 23011 "rowId": null 23012 }; 23013 23014 /** 23015 * Extension object for DataTables that is used to provide all extension 23016 * options. 23017 * 23018 * Note that the `DataTable.ext` object is available through 23019 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is 23020 * also aliased to `jQuery.fn.dataTableExt` for historic reasons. 23021 * @namespace 23022 * @extends DataTable.models.ext 23023 */ 23024 23025 23026 /** 23027 * DataTables extensions 23028 * 23029 * This namespace acts as a collection area for plug-ins that can be used to 23030 * extend DataTables capabilities. Indeed many of the build in methods 23031 * use this method to provide their own capabilities (sorting methods for 23032 * example). 23033 * 23034 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy 23035 * reasons 23036 * 23037 * @namespace 23038 */ 23039 DataTable.ext = _ext = { 23040 /** 23041 * Buttons. For use with the Buttons extension for DataTables. This is 23042 * defined here so other extensions can define buttons regardless of load 23043 * order. It is _not_ used by DataTables core. 23044 * 23045 * @type object 23046 * @default {} 23047 */ 23048 buttons: {}, 23049 23050 23051 /** 23052 * Element class names 23053 * 23054 * @type object 23055 * @default {} 23056 */ 23057 classes: {}, 23058 23059 23060 /** 23061 * DataTables build type (expanded by the download builder) 23062 * 23063 * @type string 23064 */ 23065 build:"bs/jszip-2.5.0/dt-1.10.18/b-1.5.4/b-colvis-1.5.4/b-html5-1.5.4/cr-1.5.0/fh-3.1.4/r-2.2.2/rg-1.1.0/sc-1.5.0/sl-1.2.6
vendor: 15,138 bytes, lines 23065-23511
23065", 23066 23067 23068 /** 23069 * Error reporting. 23070 * 23071 * How should DataTables report an error. Can take the value 'alert', 23072 * 'throw', 'none' or a function. 23073 * 23074 * @type string|function 23075 * @default alert 23076 */ 23077 errMode: "alert", 23078 23079 23080 /** 23081 * Feature plug-ins. 23082 * 23083 * This is an array of objects which describe the feature plug-ins that are 23084 * available to DataTables. These feature plug-ins are then available for 23085 * use through the `dom` initialisation option. 23086 * 23087 * Each feature plug-in is described by an object which must have the 23088 * following properties: 23089 * 23090 * * `fnInit` - function that is used to initialise the plug-in, 23091 * * `cFeature` - a character so the feature can be enabled by the `dom` 23092 * instillation option. This is case sensitive. 23093 * 23094 * The `fnInit` function has the following input parameters: 23095 * 23096 * 1. `{object}` DataTables settings object: see 23097 * {@link DataTable.models.oSettings} 23098 * 23099 * And the following return is expected: 23100 * 23101 * * {node|null} The element which contains your feature. Note that the 23102 * return may also be void if your plug-in does not require to inject any 23103 * DOM elements into DataTables control (`dom`) - for example this might 23104 * be useful when developing a plug-in which allows table control via 23105 * keyboard entry 23106 * 23107 * @type array 23108 * 23109 * @example 23110 * $.fn.dataTable.ext.features.push( { 23111 * "fnInit": function( oSettings ) { 23112 * return new TableTools( { "oDTSettings": oSettings } ); 23113 * }, 23114 * "cFeature": "T" 23115 * } ); 23116 */ 23117 feature: [], 23118 23119 23120 /** 23121 * Row searching. 23122 * 23123 * This method of searching is complimentary to the default type based 23124 * searching, and a lot more comprehensive as it allows you complete control 23125 * over the searching logic. Each element in this array is a function 23126 * (parameters described below) that is called for every row in the table, 23127 * and your logic decides if it should be included in the searching data set 23128 * or not. 23129 * 23130 * Searching functions have the following input parameters: 23131 * 23132 * 1. `{object}` DataTables settings object: see 23133 * {@link DataTable.models.oSettings} 23134 * 2. `{array|object}` Data for the row to be processed (same as the 23135 * original format that was passed in as the data source, or an array 23136 * from a DOM data source 23137 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which 23138 * can be useful to retrieve the `TR` element if you need DOM interaction. 23139 * 23140 * And the following return is expected: 23141 * 23142 * * {boolean} Include the row in the searched result set (true) or not 23143 * (false) 23144 * 23145 * Note that as with the main search ability in DataTables, technically this 23146 * is "filtering", since it is subtractive. However, for consistency in 23147 * naming we call it searching here. 23148 * 23149 * @type array 23150 * @default [] 23151 * 23152 * @example 23153 * // The following example shows custom search being applied to the 23154 * // fourth column (i.e. the data[3] index) based on two input values 23155 * // from the end-user, matching the data in a certain range. 23156 * $.fn.dataTable.ext.search.push( 23157 * function( settings, data, dataIndex ) { 23158 * var min = document.getElementById('min').value * 1; 23159 * var max = document.getElementById('max').value * 1; 23160 * var version = data[3] == "-" ? 0 : data[3]*1; 23161 * 23162 * if ( min == "" && max == "" ) { 23163 * return true; 23164 * } 23165 * else if ( min == "" && version < max ) { 23166 * return true; 23167 * } 23168 * else if ( min < version && "" == max ) { 23169 * return true; 23170 * } 23171 * else if ( min < version && version < max ) { 23172 * return true; 23173 * } 23174 * return false; 23175 * } 23176 * ); 23177 */ 23178 search: [], 23179 23180 23181 /** 23182 * Selector extensions 23183 * 23184 * The `selector` option can be used to extend the options available for the 23185 * selector modifier options (`selector-modifier` object data type) that 23186 * each of the three built in selector types offer (row, column and cell + 23187 * their plural counterparts). For example the Select extension uses this 23188 * mechanism to provide an option to select only rows, columns and cells 23189 * that have been marked as selected by the end user (`{selected: true}`), 23190 * which can be used in conjunction with the existing built in selector 23191 * options. 23192 * 23193 * Each property is an array to which functions can be pushed. The functions 23194 * take three attributes: 23195 * 23196 * * Settings object for the host table 23197 * * Options object (`selector-modifier` object type) 23198 * * Array of selected item indexes 23199 * 23200 * The return is an array of the resulting item indexes after the custom 23201 * selector has been applied. 23202 * 23203 * @type object 23204 */ 23205 selector: { 23206 cell: [], 23207 column: [], 23208 row: [] 23209 }, 23210 23211 23212 /** 23213 * Internal functions, exposed for used in plug-ins. 23214 * 23215 * Please note that you should not need to use the internal methods for 23216 * anything other than a plug-in (and even then, try to avoid if possible). 23217 * The internal function may change between releases. 23218 * 23219 * @type object 23220 * @default {} 23221 */ 23222 internal: {}, 23223 23224 23225 /** 23226 * Legacy configuration options. Enable and disable legacy options that 23227 * are available in DataTables. 23228 * 23229 * @type object 23230 */ 23231 legacy: { 23232 /** 23233 * Enable / disable DataTables 1.9 compatible server-side processing 23234 * requests 23235 * 23236 * @type boolean 23237 * @default null 23238 */ 23239 ajax: null 23240 }, 23241 23242 23243 /** 23244 * Pagination plug-in methods. 23245 * 23246 * Each entry in this object is a function and defines which buttons should 23247 * be shown by the pagination rendering method that is used for the table: 23248 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the 23249 * buttons are displayed in the document, while the functions here tell it 23250 * what buttons to display. This is done by returning an array of button 23251 * descriptions (what each button will do). 23252 * 23253 * Pagination types (the four built in options and any additional plug-in 23254 * options defined here) can be used through the `paginationType` 23255 * initialisation parameter. 23256 * 23257 * The functions defined take two parameters: 23258 * 23259 * 1. `{int} page` The current page index 23260 * 2. `{int} pages` The number of pages in the table 23261 * 23262 * Each function is expected to return an array where each element of the 23263 * array can be one of: 23264 * 23265 * * `first` - Jump to first page when activated 23266 * * `last` - Jump to last page when activated 23267 * * `previous` - Show previous page when activated 23268 * * `next` - Show next page when activated 23269 * * `{int}` - Show page of the index given 23270 * * `{array}` - A nested array containing the above elements to add a 23271 * containing 'DIV' element (might be useful for styling). 23272 * 23273 * Note that DataTables v1.9- used this object slightly differently whereby 23274 * an object with two functions would be defined for each plug-in. That 23275 * ability is still supported by DataTables 1.10+ to provide backwards 23276 * compatibility, but this option of use is now decremented and no longer 23277 * documented in DataTables 1.10+. 23278 * 23279 * @type object 23280 * @default {} 23281 * 23282 * @example 23283 * // Show previous, next and current page buttons only 23284 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) { 23285 * return [ 'previous', page, 'next' ]; 23286 * }; 23287 */ 23288 pager: {}, 23289 23290 23291 renderer: { 23292 pageButton: {}, 23293 header: {} 23294 }, 23295 23296 23297 /** 23298 * Ordering plug-ins - custom data source 23299 * 23300 * The extension options for ordering of data available here is complimentary 23301 * to the default type based ordering that DataTables typically uses. It 23302 * allows much greater control over the the data that is being used to 23303 * order a column, but is necessarily therefore more complex. 23304 * 23305 * This type of ordering is useful if you want to do ordering based on data 23306 * live from the DOM (for example the contents of an 'input' element) rather 23307 * than just the static string that DataTables knows of. 23308 * 23309 * The way these plug-ins work is that you create an array of the values you 23310 * wish to be ordering for the column in question and then return that 23311 * array. The data in the array much be in the index order of the rows in 23312 * the table (not the currently ordering order!). Which order data gathering 23313 * function is run here depends on the `dt-init columns.orderDataType` 23314 * parameter that is used for the column (if any). 23315 * 23316 * The functions defined take two parameters: 23317 * 23318 * 1. `{object}` DataTables settings object: see 23319 * {@link DataTable.models.oSettings} 23320 * 2. `{int}` Target column index 23321 * 23322 * Each function is expected to return an array: 23323 * 23324 * * `{array}` Data for the column to be ordering upon 23325 * 23326 * @type array 23327 * 23328 * @example 23329 * // Ordering using `input` node values 23330 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col ) 23331 * { 23332 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) { 23333 * return $('input', td).val(); 23334 * } ); 23335 * } 23336 */ 23337 order: {}, 23338 23339 23340 /** 23341 * Type based plug-ins. 23342 * 23343 * Each column in DataTables has a type assigned to it, either by automatic 23344 * detection or by direct assignment using the `type` option for the column. 23345 * The type of a column will effect how it is ordering and search (plug-ins 23346 * can also make use of the column type if required). 23347 * 23348 * @namespace 23349 */ 23350 type: { 23351 /** 23352 * Type detection functions. 23353 * 23354 * The functions defined in this object are used to automatically detect 23355 * a column's type, making initialisation of DataTables super easy, even 23356 * when complex data is in the table. 23357 * 23358 * The functions defined take two parameters: 23359 * 23360 * 1. `{*}` Data from the column cell to be analysed 23361 * 2. `{settings}` DataTables settings object. This can be used to 23362 * perform context specific type detection - for example detection 23363 * based on language settings such as using a comma for a decimal 23364 * place. Generally speaking the options from the settings will not 23365 * be required 23366 * 23367 * Each function is expected to return: 23368 * 23369 * * `{string|null}` Data type detected, or null if unknown (and thus 23370 * pass it on to the other type detection functions. 23371 * 23372 * @type array 23373 * 23374 * @example 23375 * // Currency type detection plug-in: 23376 * $.fn.dataTable.ext.type.detect.push( 23377 * function ( data, settings ) { 23378 * // Check the numeric part 23379 * if ( ! data.substring(1).match(/[0-9]/) ) { 23380 * return null; 23381 * } 23382 * 23383 * // Check prefixed by currency 23384 * if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) { 23385 * return 'currency'; 23386 * } 23387 * return null; 23388 * } 23389 * ); 23390 */ 23391 detect: [], 23392 23393 23394 /** 23395 * Type based search formatting. 23396 * 23397 * The type based searching functions can be used to pre-format the 23398 * data to be search on. For example, it can be used to strip HTML 23399 * tags or to de-format telephone numbers for numeric only searching. 23400 * 23401 * Note that is a search is not defined for a column of a given type, 23402 * no search formatting will be performed. 23403 * 23404 * Pre-processing of searching data plug-ins - When you assign the sType 23405 * for a column (or have it automatically detected for you by DataTables 23406 * or a type detection plug-in), you will typically be using this for 23407 * custom sorting, but it can also be used to provide custom searching 23408 * by allowing you to pre-processing the data and returning the data in 23409 * the format that should be searched upon. This is done by adding 23410 * functions this object with a parameter name which matches the sType 23411 * for that target column. This is the corollary of <i>afnSortData</i> 23412 * for searching data. 23413 * 23414 * The functions defined take a single parameter: 23415 * 23416 * 1. `{*}` Data from the column cell to be prepared for searching 23417 * 23418 * Each function is expected to return: 23419 * 23420 * * `{string|null}` Formatted string that will be used for the searching. 23421 * 23422 * @type object 23423 * @default {} 23424 * 23425 * @example 23426 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) { 23427 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" ); 23428 * } 23429 */ 23430 search: {}, 23431 23432 23433 /** 23434 * Type based ordering. 23435 * 23436 * The column type tells DataTables what ordering to apply to the table 23437 * when a column is sorted upon. The order for each type that is defined, 23438 * is defined by the functions available in this object. 23439 * 23440 * Each ordering option can be described by three properties added to 23441 * this object: 23442 * 23443 * * `{type}-pre` - Pre-formatting function 23444 * * `{type}-asc` - Ascending order function 23445 * * `{type}-desc` - Descending order function 23446 * 23447 * All three can be used together, only `{type}-pre` or only 23448 * `{type}-asc` and `{type}-desc` together. It is generally recommended 23449 * that only `{type}-pre` is used, as this provides the optimal 23450 * implementation in terms of speed, although the others are provided 23451 * for compatibility with existing Javascript sort functions. 23452 * 23453 * `{type}-pre`: Functions defined take a single parameter: 23454 * 23455 * 1. `{*}` Data from the column cell to be prepared for ordering 23456 * 23457 * And return: 23458 * 23459 * * `{*}` Data to be sorted upon 23460 * 23461 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort 23462 * functions, taking two parameters: 23463 * 23464 * 1. `{*}` Data to compare to the second parameter 23465 * 2. `{*}` Data to compare to the first parameter 23466 * 23467 * And returning: 23468 * 23469 * * `{*}` Ordering match: <0 if first parameter should be sorted lower 23470 * than the second parameter, ===0 if the two parameters are equal and 23471 * >0 if the first parameter should be sorted height than the second 23472 * parameter. 23473 * 23474 * @type object 23475 * @default {} 23476 * 23477 * @example 23478 * // Numeric ordering of formatted numbers with a pre-formatter 23479 * $.extend( $.fn.dataTable.ext.type.order, { 23480 * "string-pre": function(x) { 23481 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" ); 23482 * return parseFloat( a ); 23483 * } 23484 * } ); 23485 * 23486 * @example 23487 * // Case-sensitive string ordering, with no pre-formatting method 23488 * $.extend( $.fn.dataTable.ext.order, { 23489 * "string-case-asc": function(x,y) { 23490 * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 23491 * }, 23492 * "string-case-desc": function(x,y) { 23493 * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 23494 * } 23495 * } ); 23496 */ 23497 order: {} 23498 }, 23499 23500 /** 23501 * Unique DataTables instance counter 23502 * 23503 * @type int 23504 * @private 23505 */ 23506 _unique: 0, 23507 23508 23509 // 23510 // Depreciated 23511 // The following properties are retained for backwards compatib
vendor: 3,168 bytes, lines 23511-23648
23511lity only. 23512 // The should not be used in new projects and will be removed in a future 23513 // version 23514 // 23515 23516 /** 23517 * Version check function. 23518 * @type function 23519 * @depreciated Since 1.10 23520 */ 23521 fnVersionCheck: DataTable.fnVersionCheck, 23522 23523 23524 /** 23525 * Index for what 'this' index API functions should use 23526 * @type int 23527 * @deprecated Since v1.10 23528 */ 23529 iApiIndex: 0, 23530 23531 23532 /** 23533 * jQuery UI class container 23534 * @type object 23535 * @deprecated Since v1.10 23536 */ 23537 oJUIClasses: {}, 23538 23539 23540 /** 23541 * Software version 23542 * @type string 23543 * @deprecated Since v1.10 23544 */ 23545 sVersion: DataTable.version 23546 }; 23547 23548 23549 // 23550 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts 23551 // 23552 $.extend( _ext, { 23553 afnFiltering: _ext.search, 23554 aTypes: _ext.type.detect, 23555 ofnSearch: _ext.type.search, 23556 oSort: _ext.type.order, 23557 afnSortData: _ext.order, 23558 aoFeatures: _ext.feature, 23559 oApi: _ext.internal, 23560 oStdClasses: _ext.classes, 23561 oPagination: _ext.pager 23562 } ); 23563 23564 23565 $.extend( DataTable.ext.classes, { 23566 "sTable": "dataTable", 23567 "sNoFooter": "no-footer", 23568 23569 /* Paging buttons */ 23570 "sPageButton": "paginate_button", 23571 "sPageButtonActive": "current", 23572 "sPageButtonDisabled": "disabled", 23573 23574 /* Striping classes */ 23575 "sStripeOdd": "odd", 23576 "sStripeEven": "even", 23577 23578 /* Empty row */ 23579 "sRowEmpty": "dataTables_empty", 23580 23581 /* Features */ 23582 "sWrapper": "dataTables_wrapper", 23583 "sFilter": "dataTables_filter", 23584 "sInfo": "dataTables_info", 23585 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */ 23586 "sLength": "dataTables_length", 23587 "sProcessing": "dataTables_processing", 23588 23589 /* Sorting */ 23590 "sSortAsc": "sorting_asc", 23591 "sSortDesc": "sorting_desc", 23592 "sSortable": "sorting", /* Sortable in both directions */ 23593 "sSortableAsc": "sorting_asc_disabled", 23594 "sSortableDesc": "sorting_desc_disabled", 23595 "sSortableNone": "sorting_disabled", 23596 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */ 23597 23598 /* Filtering */ 23599 "sFilterInput": "", 23600 23601 /* Page length */ 23602 "sLengthSelect": "", 23603 23604 /* Scrolling */ 23605 "sScrollWrapper": "dataTables_scroll", 23606 "sScrollHead": "dataTables_scrollHead", 23607 "sScrollHeadInner": "dataTables_scrollHeadInner", 23608 "sScrollBody": "dataTables_scrollBody", 23609 "sScrollFoot": "dataTables_scrollFoot", 23610 "sScrollFootInner": "dataTables_scrollFootInner", 23611 23612 /* Misc */ 23613 "sHeaderTH": "", 23614 "sFooterTH": "", 23615 23616 // Deprecated 23617 "sSortJUIAsc": "", 23618 "sSortJUIDesc": "", 23619 "sSortJUI": "", 23620 "sSortJUIAscAllowed": "", 23621 "sSortJUIDescAllowed": "", 23622 "sSortJUIWrapper": "", 23623 "sSortIcon": "", 23624 "sJUIHeader": "", 23625 "sJUIFooter": "" 23626 } ); 23627 23628 23629 var extPagination = DataTable.ext.pager; 23630 23631 function _numbers ( page, pages ) { 23632 var 23633 numbers = [], 23634 buttons = extPagination.numbers_length, 23635 half = Math.floor( buttons / 2 ), 23636 i = 1; 23637 23638 if ( pages <= buttons ) { 23639 numbers = _range( 0, pages ); 23640 } 23641 else if ( page <= half ) { 23642 numbers = _range( 0, buttons-2 ); 23643 numbers.push( 'ellipsis' ); 23644 numbers.push( pages-1 ); 23645 } 23646 else if ( page >= pages - 1 - half ) { 23647 numbers = _range( pages-(buttons-2), pages ); 23648 numbers.splice( 0, 0, 'ellipsis' );
23648 // no unshift in ie6 23649 numbers.splice( 0, 0, 0 ); 23650 } 23651 else { 23652 numbers = _range( page-half+2, page+half-1 ); 23653 numbers.push( 'ellipsis' ); 23654 numbers.push( pages-1 ); 23655 numbers.splice( 0, 0, 'ellipsis' ); 23656 numbers.splice( 0, 0, 0 ); 23657 } 23658 23659 numbers.DT_el = 'span'; 23660 return numbers; 23661 } 23662 23663 23664 $.extend( extPagination, { 23665 simple: function ( page, pages ) { 23666 return [ 'previous', 'next' ]; 23667 }, 23668 23669 full: function ( page, pages ) { 23670 return [ 'first', 'previous', 'next', 'last' ]; 23671 }, 23672 23673 numbers: function ( page, pages ) { 23674 return [ _numbers(page, pages) ]; 23675 }, 23676 23677 simple_numbers: function ( page, pages ) { 23678 return [ 'previous', _numbers(page, pages), 'next' ]; 23679 }, 23680 23681 full_numbers: function ( page, pages ) { 23682 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ]; 23683 }, 23684 23685 first_last_numbers: function (page, pages) { 23686 return ['first', _numbers(page, pages), 'last']; 23687 }, 23688 23689 // For testing and plug-ins to use 23690 _numbers: _numbers, 23691 23692 // Number of number buttons (including ellipsis) to show. _Must be odd!_ 23693 numbers_length: 7 23694 } ); 23695 23696 23697 $.extend( true, DataTable.ext.renderer, { 23698 pageButton: { 23699 _: function ( settings, host, idx, buttons, page, pages ) { 23700 var classes = settings.oClasses; 23701 var lang = settings.oLanguage.oPaginate; 23702 var aria = settings.oLanguage.oAria.paginate || {}; 23703 var btnDisplay, btnClass, counter=0; 23704 23705 var attach = function( container, buttons ) { 23706 var i, ien, node, button; 23707 var clickHandler = function ( e ) { 23708 _fnPageChange( settings, e.data.action, true ); 23709 }; 23710 23711 for ( i=0, ien=buttons.length ; i<ien ; i++ ) { 23712 button = buttons[i]; 23713 23714 if ( $.isArray( button ) ) { 23715 var inner = $( '<'+(button.DT_el || 'div')+'/>' ) 23716 .appendTo( container ); 23717 attach( inner, button ); 23718 } 23719 else { 23720 btnDisplay = null; 23721 btnClass = ''; 23722 23723 switch ( button ) { 23724 case 'ellipsis': 23725 container.append('<span class="ellipsis">…</span>'); 23726 break; 23727 23728 case 'first': 23729 btnDisplay = lang.sFirst; 23730 btnClass = button + (page > 0 ? 23731 '' : ' '+classes.sPageButtonDisabled); 23732 break; 23733 23734 case 'previous': 23735 btnDisplay = lang.sPrevious; 23736 btnClass = button + (page > 0 ? 23737 '' : ' '+classes.sPageButtonDisabled); 23738 break; 23739 23740 case 'next': 23741 btnDisplay = lang.sNext; 23742 btnClass = button + (page < pages-1 ? 23743 '' : ' '+classes.sPageButtonDisabled); 23744 break; 23745 23746 case 'last': 23747 btnDisplay = lang.sLast; 23748 btnClass = button + (page < pages-1 ? 23749 '' : ' '+classes.sPageButtonDisabled); 23750 break; 23751 23752 default: 23753 btnDisplay = button + 1; 23754 btnClass = page === button ? 23755 classes.sPageButtonActive : ''; 23756 break; 23757 } 23758 23759 if ( btnDisplay !== null ) { 23760 node = $('<a>', { 23761 'class': classes.sPageButton+' '+btnClass, 23762 'aria-controls': settings.sTableId, 23763 'aria-label': aria[ button ], 23764 'data-dt-idx': counter, 23765 'tabindex': settings.iTabIndex, 23766 'id': idx === 0 && typeof button === 'string' ? 23767 settings.sTableId +'_'+ button : 23768 null 23769 } ) 23770 .html( btnDisplay ) 23771 .appendTo( container ); 23772 23773 _fnBindAction( 23774 node, {action: button}, clickHandler 23775 ); 23776 23777 counter++; 23778 } 23779 } 23780 } 23781 }; 23782 23783 // IE9 throws an 'unknown error' if document.activeElement is used 23784 // inside an iframe or frame. Try / catch the error. Not good for 23785 // accessibility, but neither are frames. 23786 var activeEl; 23787 23788 try { 23789 // Because this approach is destroying and recreating the paging 23790 // elements, focus is lost on the select button which is bad for 23791 // accessibility. So we want to restore focus once the draw has 23792 // completed 23793 activeEl = $(host).find(document.activeElement).data('dt-idx'); 23794 } 23795 catch (e) {} 23796 23797 attach( $(host).empty(), buttons ); 23798 23799 if ( activeEl !== undefined ) { 23800 $(host).find( '[data-dt-idx='+activeEl+']' ).focus(); 23801 } 23802 } 23803 } 23804 } ); 23805 23806 23807 23808 // Built in type detection. See model.ext.aTypes for information about 23809 // what is required from this methods. 23810 $.extend( DataTable.ext.type.detect, [
vendor: 18,210 bytes, lines 23811-24407
23811 // Plain numbers - first since V8 detects some plain numbers as dates 23812 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...). 23813 function ( d, settings ) 23814 { 23815 var decimal = settings.oLanguage.sDecimal; 23816 return _isNumber( d, decimal ) ? 'num'+decimal : null; 23817 }, 23818 23819 // Dates (only those recognised by the browser's Date.parse) 23820 function ( d, settings ) 23821 { 23822 // V8 tries _very_ hard to make a string passed into `Date.parse()` 23823 // valid, so we need to use a regex to restrict date formats. Use a 23824 // plug-in for anything other than ISO8601 style strings 23825 if ( d && !(d instanceof Date) && ! _re_date.test(d) ) { 23826 return null; 23827 } 23828 var parsed = Date.parse(d); 23829 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null; 23830 }, 23831 23832 // Formatted numbers 23833 function ( d, settings ) 23834 { 23835 var decimal = settings.oLanguage.sDecimal; 23836 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null; 23837 }, 23838 23839 // HTML numeric 23840 function ( d, settings ) 23841 { 23842 var decimal = settings.oLanguage.sDecimal; 23843 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null; 23844 }, 23845 23846 // HTML numeric, formatted 23847 function ( d, settings ) 23848 { 23849 var decimal = settings.oLanguage.sDecimal; 23850 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null; 23851 }, 23852 23853 // HTML (this is strict checking - there must be html) 23854 function ( d, settings ) 23855 { 23856 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ? 23857 'html' : null; 23858 } 23859 ] ); 23860 23861 23862 23863 // Filter formatting functions. See model.ext.ofnSearch for information about 23864 // what is required from these methods. 23865 // 23866 // Note that additional search methods are added for the html numbers and 23867 // html formatted numbers by `_addNumericSort()` when we know what the decimal 23868 // place is 23869 23870 23871 $.extend( DataTable.ext.type.search, { 23872 html: function ( data ) { 23873 return _empty(data) ? 23874 data : 23875 typeof data === 'string' ? 23876 data 23877 .replace( _re_new_lines, " " ) 23878 .replace( _re_html, "" ) : 23879 ''; 23880 }, 23881 23882 string: function ( data ) { 23883 return _empty(data) ? 23884 data : 23885 typeof data === 'string' ? 23886 data.replace( _re_new_lines, " " ) : 23887 data; 23888 } 23889 } ); 23890 23891 23892 23893 var __numericReplace = function ( d, decimalPlace, re1, re2 ) { 23894 if ( d !== 0 && (!d || d === '-') ) { 23895 return -Infinity; 23896 } 23897 23898 // If a decimal place other than `.` is used, it needs to be given to the 23899 // function so we can detect it and replace with a `.` which is the only 23900 // decimal place Javascript recognises - it is not locale aware. 23901 if ( decimalPlace ) { 23902 d = _numToDecimal( d, decimalPlace ); 23903 } 23904 23905 if ( d.replace ) { 23906 if ( re1 ) { 23907 d = d.replace( re1, '' ); 23908 } 23909 23910 if ( re2 ) { 23911 d = d.replace( re2, '' ); 23912 } 23913 } 23914 23915 return d * 1; 23916 }; 23917 23918 23919 // Add the numeric 'deformatting' functions for sorting and search. This is done 23920 // in a function to provide an easy ability for the language options to add 23921 // additional methods if a non-period decimal place is used. 23922 function _addNumericSort ( decimalPlace ) { 23923 $.each( 23924 { 23925 // Plain numbers 23926 "num": function ( d ) { 23927 return __numericReplace( d, decimalPlace ); 23928 }, 23929 23930 // Formatted numbers 23931 "num-fmt": function ( d ) { 23932 return __numericReplace( d, decimalPlace, _re_formatted_numeric ); 23933 }, 23934 23935 // HTML numeric 23936 "html-num": function ( d ) { 23937 return __numericReplace( d, decimalPlace, _re_html ); 23938 }, 23939 23940 // HTML numeric, formatted 23941 "html-num-fmt": function ( d ) { 23942 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric ); 23943 } 23944 }, 23945 function ( key, fn ) { 23946 // Add the ordering method 23947 _ext.type.order[ key+decimalPlace+'-pre' ] = fn; 23948 23949 // For HTML types add a search formatter that will strip the HTML 23950 if ( key.match(/^html\-/) ) { 23951 _ext.type.search[ key+decimalPlace ] = _ext.type.search.html; 23952 } 23953 } 23954 ); 23955 } 23956 23957 23958 // Default sort methods 23959 $.extend( _ext.type.order, { 23960 // Dates 23961 "date-pre": function ( d ) { 23962 var ts = Date.parse( d ); 23963 return isNaN(ts) ? -Infinity : ts; 23964 }, 23965 23966 // html 23967 "html-pre": function ( a ) { 23968 return _empty(a) ? 23969 '' : 23970 a.replace ? 23971 a.replace( /<.*?>/g, "" ).toLowerCase() : 23972 a+''; 23973 }, 23974 23975 // string 23976 "string-pre": function ( a ) { 23977 // This is a little complex, but faster than always calling toString, 23978 // http://jsperf.com/tostring-v-check 23979 return _empty(a) ? 23980 '' : 23981 typeof a === 'string' ? 23982 a.toLowerCase() : 23983 ! a.toString ? 23984 '' : 23985 a.toString(); 23986 }, 23987 23988 // string-asc and -desc are retained only for compatibility with the old 23989 // sort methods 23990 "string-asc": function ( x, y ) { 23991 return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 23992 }, 23993 23994 "string-desc": function ( x, y ) { 23995 return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 23996 } 23997 } ); 23998 23999 24000 // Numeric sorting types - order doesn't matter here 24001 _addNumericSort( '' ); 24002 24003 24004 $.extend( true, DataTable.ext.renderer, { 24005 header: { 24006 _: function ( settings, cell, column, classes ) { 24007 // No additional mark-up required 24008 // Attach a sort listener to update on sort - note that using the 24009 // `DT` namespace will allow the event to be removed automatically 24010 // on destroy, while the `dt` namespaced event is the one we are 24011 // listening for 24012 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { 24013 if ( settings !== ctx ) { // need to check this this is the host 24014 return; // table, not a nested one 24015 } 24016 24017 var colIdx = column.idx; 24018 24019 cell 24020 .removeClass( 24021 column.sSortingClass +' '+ 24022 classes.sSortAsc +' '+ 24023 classes.sSortDesc 24024 ) 24025 .addClass( columns[ colIdx ] == 'asc' ? 24026 classes.sSortAsc : columns[ colIdx ] == 'desc' ? 24027 classes.sSortDesc : 24028 column.sSortingClass 24029 ); 24030 } ); 24031 }, 24032 24033 jqueryui: function ( settings, cell, column, classes ) { 24034 $('<div/>') 24035 .addClass( classes.sSortJUIWrapper ) 24036 .append( cell.contents() ) 24037 .append( $('<span/>') 24038 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI ) 24039 ) 24040 .appendTo( cell ); 24041 24042 // Attach a sort listener to update on sort 24043 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { 24044 if ( settings !== ctx ) { 24045 return; 24046 } 24047 24048 var colIdx = column.idx; 24049 24050 cell 24051 .removeClass( classes.sSortAsc +" "+classes.sSortDesc ) 24052 .addClass( columns[ colIdx ] == 'asc' ? 24053 classes.sSortAsc : columns[ colIdx ] == 'desc' ? 24054 classes.sSortDesc : 24055 column.sSortingClass 24056 ); 24057 24058 cell 24059 .find( 'span.'+classes.sSortIcon ) 24060 .removeClass( 24061 classes.sSortJUIAsc +" "+ 24062 classes.sSortJUIDesc +" "+ 24063 classes.sSortJUI +" "+ 24064 classes.sSortJUIAscAllowed +" "+ 24065 classes.sSortJUIDescAllowed 24066 ) 24067 .addClass( columns[ colIdx ] == 'asc' ? 24068 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ? 24069 classes.sSortJUIDesc : 24070 column.sSortingClassJUI 24071 ); 24072 } ); 24073 } 24074 } 24075 } ); 24076 24077 /* 24078 * Public helper functions. These aren't used internally by DataTables, or 24079 * called by any of the options passed into DataTables, but they can be used 24080 * externally by developers working with DataTables. They are helper functions 24081 * to make working with DataTables a little bit easier. 24082 */ 24083 24084 var __htmlEscapeEntities = function ( d ) { 24085 return typeof d === 'string' ? 24086 d.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"') : 24087 d; 24088 }; 24089 24090 /** 24091 * Helpers for `columns.render`. 24092 * 24093 * The options defined here can be used with the `columns.render` initialisation 24094 * option to provide a display renderer. The following functions are defined: 24095 * 24096 * * `number` - Will format numeric data (defined by `columns.data`) for 24097 * display, retaining the original unformatted data for sorting and filtering. 24098 * It takes 5 parameters: 24099 * * `string` - Thousands grouping separator 24100 * * `string` - Decimal point indicator 24101 * * `integer` - Number of decimal points to show 24102 * * `string` (optional) - Prefix. 24103 * * `string` (optional) - Postfix (/suffix). 24104 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional 24105 * parameters. 24106 * 24107 * @example 24108 * // Column definition using the number renderer 24109 * { 24110 * data: "salary", 24111 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' ) 24112 * } 24113 * 24114 * @namespace 24115 */ 24116 DataTable.render = { 24117 number: function ( thousands, decimal, precision, prefix, postfix ) { 24118 return { 24119 display: function ( d ) { 24120 if ( typeof d !== 'number' && typeof d !== 'string' ) { 24121 return d; 24122 } 24123 24124 var negative = d < 0 ? '-' : ''; 24125 var flo = parseFloat( d ); 24126 24127 // If NaN then there isn't much formatting that we can do - just 24128 // return immediately, escaping any HTML (this was supposed to 24129 // be a number after all) 24130 if ( isNaN( flo ) ) { 24131 return __htmlEscapeEntities( d ); 24132 } 24133 24134 flo = flo.toFixed( precision ); 24135 d = Math.abs( flo ); 24136 24137 var intPart = parseInt( d, 10 ); 24138 var floatPart = precision ? 24139 decimal+(d - intPart).toFixed( precision ).substring( 2 ): 24140 ''; 24141 24142 return negative + (prefix||'') + 24143 intPart.toString().replace( 24144 /\B(?=(\d{3})+(?!\d))/g, thousands 24145 ) + 24146 floatPart + 24147 (postfix||''); 24148 } 24149 }; 24150 }, 24151 24152 text: function () { 24153 return { 24154 display: __htmlEscapeEntities 24155 }; 24156 } 24157 }; 24158 24159 24160 /* 24161 * This is really a good bit rubbish this method of exposing the internal methods 24162 * publicly... - To be fixed in 2.0 using methods on the prototype 24163 */ 24164 24165 24166 /** 24167 * Create a wrapper function for exporting an internal functions to an external API. 24168 * @param {string} fn API function name 24169 * @returns {function} wrapped function 24170 * @memberof DataTable#internal 24171 */ 24172 function _fnExternApiFunc (fn) 24173 { 24174 return function() { 24175 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat( 24176 Array.prototype.slice.call(arguments) 24177 ); 24178 return DataTable.ext.internal[fn].apply( this, args ); 24179 }; 24180 } 24181 24182 24183 /** 24184 * Reference to internal functions for use by plug-in developers. Note that 24185 * these methods are references to internal functions and are considered to be 24186 * private. If you use these methods, be aware that they are liable to change 24187 * between versions. 24188 * @namespace 24189 */ 24190 $.extend( DataTable.ext.internal, { 24191 _fnExternApiFunc: _fnExternApiFunc, 24192 _fnBuildAjax: _fnBuildAjax, 24193 _fnAjaxUpdate: _fnAjaxUpdate, 24194 _fnAjaxParameters: _fnAjaxParameters, 24195 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw, 24196 _fnAjaxDataSrc: _fnAjaxDataSrc, 24197 _fnAddColumn: _fnAddColumn, 24198 _fnColumnOptions: _fnColumnOptions, 24199 _fnAdjustColumnSizing: _fnAdjustColumnSizing, 24200 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex, 24201 _fnColumnIndexToVisible: _fnColumnIndexToVisible, 24202 _fnVisbleColumns: _fnVisbleColumns, 24203 _fnGetColumns: _fnGetColumns, 24204 _fnColumnTypes: _fnColumnTypes, 24205 _fnApplyColumnDefs: _fnApplyColumnDefs, 24206 _fnHungarianMap: _fnHungarianMap, 24207 _fnCamelToHungarian: _fnCamelToHungarian, 24208 _fnLanguageCompat: _fnLanguageCompat, 24209 _fnBrowserDetect: _fnBrowserDetect, 24210 _fnAddData: _fnAddData, 24211 _fnAddTr: _fnAddTr, 24212 _fnNodeToDataIndex: _fnNodeToDataIndex, 24213 _fnNodeToColumnIndex: _fnNodeToColumnIndex, 24214 _fnGetCellData: _fnGetCellData, 24215 _fnSetCellData: _fnSetCellData, 24216 _fnSplitObjNotation: _fnSplitObjNotation, 24217 _fnGetObjectDataFn: _fnGetObjectDataFn, 24218 _fnSetObjectDataFn: _fnSetObjectDataFn, 24219 _fnGetDataMaster: _fnGetDataMaster, 24220 _fnClearTable: _fnClearTable, 24221 _fnDeleteIndex: _fnDeleteIndex, 24222 _fnInvalidate: _fnInvalidate, 24223 _fnGetRowElements: _fnGetRowElements, 24224 _fnCreateTr: _fnCreateTr, 24225 _fnBuildHead: _fnBuildHead, 24226 _fnDrawHead: _fnDrawHead, 24227 _fnDraw: _fnDraw, 24228 _fnReDraw: _fnReDraw, 24229 _fnAddOptionsHtml: _fnAddOptionsHtml, 24230 _fnDetectHeader: _fnDetectHeader, 24231 _fnGetUniqueThs: _fnGetUniqueThs, 24232 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter, 24233 _fnFilterComplete: _fnFilterComplete, 24234 _fnFilterCustom: _fnFilterCustom, 24235 _fnFilterColumn: _fnFilterColumn, 24236 _fnFilter: _fnFilter, 24237 _fnFilterCreateSearch: _fnFilterCreateSearch, 24238 _fnEscapeRegex: _fnEscapeRegex, 24239 _fnFilterData: _fnFilterData, 24240 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo, 24241 _fnUpdateInfo: _fnUpdateInfo, 24242 _fnInfoMacros: _fnInfoMacros, 24243 _fnInitialise: _fnInitialise, 24244 _fnInitComplete: _fnInitComplete, 24245 _fnLengthChange: _fnLengthChange, 24246 _fnFeatureHtmlLength: _fnFeatureHtmlLength, 24247 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate, 24248 _fnPageChange: _fnPageChange, 24249 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing, 24250 _fnProcessingDisplay: _fnProcessingDisplay, 24251 _fnFeatureHtmlTable: _fnFeatureHtmlTable, 24252 _fnScrollDraw: _fnScrollDraw, 24253 _fnApplyToChildren: _fnApplyToChildren, 24254 _fnCalculateColumnWidths: _fnCalculateColumnWidths, 24255 _fnThrottle: _fnThrottle, 24256 _fnConvertToWidth: _fnConvertToWidth, 24257 _fnGetWidestNode: _fnGetWidestNode, 24258 _fnGetMaxLenString: _fnGetMaxLenString, 24259 _fnStringToCss: _fnStringToCss, 24260 _fnSortFlatten: _fnSortFlatten, 24261 _fnSort: _fnSort, 24262 _fnSortAria: _fnSortAria, 24263 _fnSortListener: _fnSortListener, 24264 _fnSortAttachListener: _fnSortAttachListener, 24265 _fnSortingClasses: _fnSortingClasses, 24266 _fnSortData: _fnSortData, 24267 _fnSaveState: _fnSaveState, 24268 _fnLoadState: _fnLoadState, 24269 _fnSettingsFromNode: _fnSettingsFromNode, 24270 _fnLog: _fnLog, 24271 _fnMap: _fnMap, 24272 _fnBindAction: _fnBindAction, 24273 _fnCallbackReg: _fnCallbackReg, 24274 _fnCallbackFire: _fnCallbackFire, 24275 _fnLengthOverflow: _fnLengthOverflow, 24276 _fnRenderer: _fnRenderer, 24277 _fnDataSource: _fnDataSource, 24278 _fnRowAttributes: _fnRowAttributes, 24279 _fnExtend: _fnExtend, 24280 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant 24281 // in 1.10, so this dead-end function is 24282 // added to prevent errors 24283 } ); 24284 24285 24286 // jQuery access 24287 $.fn.dataTable = DataTable; 24288 24289 // Provide access to the host jQuery object (circular reference) 24290 DataTable.$ = $; 24291 24292 // Legacy aliases 24293 $.fn.dataTableSettings = DataTable.settings; 24294 $.fn.dataTableExt = DataTable.ext; 24295 24296 // With a capital `D` we return a DataTables API instance rather than a 24297 // jQuery object 24298 $.fn.DataTable = function ( opts ) { 24299 return $(this).dataTable( opts ).api(); 24300 }; 24301 24302 // All properties that are available to $.fn.dataTable should also be 24303 // available on $.fn.DataTable 24304 $.each( DataTable, function ( prop, val ) { 24305 $.fn.DataTable[ prop ] = val; 24306 } ); 24307 24308 24309 // Information about events fired by DataTables - for documentation. 24310 /** 24311 * Draw event, fired whenever the table is redrawn on the page, at the same 24312 * point as fnDrawCallback. This may be useful for binding events or 24313 * performing calculations when the table is altered at all. 24314 * @name DataTable#draw.dt 24315 * @event 24316 * @param {event} e jQuery event object 24317 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 24318 */ 24319 24320 /** 24321 * Search event, fired when the searching applied to the table (using the 24322 * built-in global search, or column filters) is altered. 24323 * @name DataTable#search.dt 24324 * @event 24325 * @param {event} e jQuery event object 24326 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 24327 */ 24328 24329 /** 24330 * Page change event, fired when the paging of the table is altered. 24331 * @name DataTable#page.dt 24332 * @event 24333 * @param {event} e jQuery event object 24334 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 24335 */ 24336 24337 /** 24338 * Order event, fired when the ordering applied to the table is altered. 24339 * @name DataTable#order.dt 24340 * @event 24341 * @param {event} e jQuery event object 24342 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 24343 */ 24344 24345 /** 24346 * DataTables initialisation complete event, fired when the table is fully 24347 * drawn, including Ajax data loaded, if Ajax data is required. 24348 * @name DataTable#init.dt 24349 * @event 24350 * @param {event} e jQuery event object 24351 * @param {object} oSettings DataTables settings object 24352 * @param {object} json The JSON object request from the server - only 24353 * present if client-side Ajax sourced data is used</li></ol> 24354 */ 24355 24356 /** 24357 * State save event, fired when the table has changed state a new state save 24358 * is required. This event allows modification of the state saving object 24359 * prior to actually doing the save, including addition or other state 24360 * properties (for plug-ins) or modification of a DataTables core property. 24361 * @name DataTable#stateSaveParams.dt 24362 * @event 24363 * @param {event} e jQuery event object 24364 * @param {object} oSettings DataTables settings object 24365 * @param {object} json The state information to be saved 24366 */ 24367 24368 /** 24369 * State load event, fired when the table is loading state from the stored 24370 * data, but prior to the settings object being modified by the saved state 24371 * - allowing modification of the saved state is required or loading of 24372 * state for a plug-in. 24373 * @name DataTable#stateLoadParams.dt 24374 * @event 24375 * @param {event} e jQuery event object 24376 * @param {object} oSettings DataTables settings object 24377 * @param {object} json The saved state information 24378 */ 24379 24380 /** 24381 * State loaded event, fired when state has been loaded from stored data and 24382 * the settings object has been modified by the loaded data. 24383 * @name DataTable#stateLoaded.dt 24384 * @event 24385 * @param {event} e jQuery event object 24386 * @param {object} oSettings DataTables settings object 24387 * @param {object} json The saved state information 24388 */ 24389 24390 /** 24391 * Processing event, fired when DataTables is doing some kind of processing 24392 * (be it, order, searcg or anything else). It can be used to indicate to 24393 * the end user that there is something happening, or that something has 24394 * finished. 24395 * @name DataTable#processing.dt 24396 * @event 24397 * @param {event} e jQuery event object 24398 * @param {object} oSettings DataTables settings object 24399 * @param {boolean} bShow Flag for if DataTables is doing processing or not 24400 */ 24401 24402 /** 24403 * Ajax (XHR) event, fired whenever an Ajax request is completed from a 24404 * request to made to the server for new data. This event is called before 24405 * DataTables processed the returned data, so it can also be used to pre- 24406 * process the data returned from the server, if needed. 24407 *
24408 * Note that this trigger is called in `fnServerData`, if you override 24409 * `fnServerData` and which to use this event, you need to trigger it in you 24410 * success function. 24411 * @name DataTable#xhr.dt 24412 * @event 24413 * @param {event} e jQuery event object 24414 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 24415 * @param {object} json JSON returned from the server 24416 * 24417 * @example 24418 * // Use a custom property returned from the server in another DOM element 24419 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) { 24420 * $('#status').html( json.status ); 24421 * } ); 24422 * 24423 * @example 24424 * // Pre-process the data returned from the server 24425 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) { 24426 * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) { 24427 * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two; 24428 * } 24429 * // Note no return - manipulate the data directly in the JSON object. 24430 * } ); 24431 */ 24432 24433 /** 24434 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy 24435 * or passing the bDestroy:true parameter in the initialisation object. This 24436 * can be used to remove bound events, added DOM nodes, etc. 24437 * @name DataTable#destroy.dt 24438 * @event 24439 * @param {event} e jQuery event object 24440 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 24441 */ 24442 24443 /** 24444 * Page length change event, fired when number of records to show on each 24445 * page (the length) is changed. 24446 * @name DataTable#length.dt 24447 * @event 24448 * @param {event} e jQuery event object 24449 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 24450 * @param {integer} len New length 24451 */ 24452 24453 /** 24454 * Column sizing has changed. 24455 * @name DataTable#column-sizing.dt 24456 * @event 24457 * @param {event} e jQuery event object 24458 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 24459 */ 24460 24461 /** 24462 * Column visibility has changed. 24463 * @name DataTable#column-visibility.dt 24464 * @event 24465 * @param {event} e jQuery event object 24466 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 24467 * @param {int} column Column index 24468 * @param {bool} vis `false` if column now hidden, or `true` if visible 24469 */ 24470 24471 return $.fn.dataTable; 24472})); 24473 24474 24475/*! DataTables Bootstrap 3 integration 24476 * ©2011-2015 SpryMedia Ltd - datatables.net/license 24477 */ 24478 24479/** 24480 * DataTables integration for Bootstrap 3. This requires Bootstrap 3 and 24481 * DataTables 1.10 or newer. 24482 * 24483 * This file sets the defaults and adds options to DataTables to style its 24484 * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap 24485 * for further information. 24486 */ 24487(function( factory ){ 24488 if ( typeof define === 'function' && define.amd ) { 24489 // AMD 24490 define( ['jquery', 'datatables.net'], function ( $ ) { 24491 return factory( $, window, document ); 24492 } ); 24493 } 24494 else if ( typeof exports === 'object' ) { 24495 // CommonJS 24496 module.exports = function (root, $) { 24497 if ( ! root ) { 24498 root = window; 24499 } 24500 24501 if ( ! $ || ! $.fn.dataTable ) { 24502 // Require DataTables, which attaches to jQuery, including 24503 // jQuery if needed and have a $ property so we can access the 24504 // jQuery object that is used 24505 $ = require('datatables.net')(root, $).$; 24506 } 24507 24508 return factory( $, root, root.document ); 24509 }; 24510 } 24511 else { 24512 // Browser 24513 factory( jQuery, window, document ); 24514 } 24515}(function( $, window, document, undefined ) { 24516'use strict'; 24517var DataTable = $.fn.dataTable; 24518 24519 24520/* Set the defaults for DataTables initialisation */ 24521$.extend( true, DataTable.defaults, { 24522 dom: 24523 "<'row'<'col-sm-6'l><'col-sm-6'f>>" + 24524 "<'row'<'col-sm-12'tr>>" + 24525 "<'row'<'col-sm-5'i><'col-sm-7'p>>", 24526 renderer: 'bootstrap' 24527} ); 24528 24529 24530/* Default class modification */ 24531$.extend( DataTable.ext.classes, { 24532 sWrapper: "dataTables_wrapper form-inline dt-bootstrap", 24533 sFilterInput: "form-control input-sm", 24534 sLengthSelect: "form-control input-sm", 24535 sProcessing: "dataTables_processing panel panel-default" 24536} ); 24537 24538 24539/* Bootstrap paging button renderer */ 24540DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, buttons, page, pages ) { 24541 var api = new DataTable.Api( settings ); 24542 var classes = settings.oClasses; 24543 var lang = settings.oLanguage.oPaginate; 24544 var aria = settings.oLanguage.oAria.paginate || {}; 24545 var btnDisplay, btnClass, counter=0; 24546 24547 var attach = function( container, buttons ) { 24548 var i, ien, node, button; 24549 var clickHandler = function ( e ) { 24550 e.preventDefault(); 24551 if ( !$(e.currentTarget).hasClass('disabled') && api.page() != e.data.action ) { 24552 api.page( e.data.action ).draw( 'page' ); 24553 } 24554 }; 24555 24556 for ( i=0, ien=buttons.length ; i<ien ; i++ ) { 24557 button = buttons[i]; 24558 24559 if ( $.isArray( button ) ) { 24560 attach( container, button ); 24561 } 24562 else { 24563 btnDisplay = ''; 24564 btnClass = ''; 24565 24566 switch ( button ) { 24567 case 'ellipsis': 24568 btnDisplay = '…'; 24569 btnClass = 'disabled'; 24570 break; 24571 24572 case 'first': 24573 btnDisplay = lang.sFirst; 24574 btnClass = button + (page > 0 ? 24575 '' : ' disabled'); 24576 break; 24577 24578 case 'previous': 24579 btnDisplay = lang.sPrevious; 24580 btnClass = button + (page > 0 ? 24581 '' : ' disabled'); 24582 break; 24583 24584 case 'next': 24585 btnDisplay = lang.sNext; 24586 btnClass = button + (page < pages-1 ? 24587 '' : ' disabled'); 24588 break; 24589 24590 case 'last': 24591 btnDisplay = lang.sLast; 24592 btnClass = button + (page < pages-1 ? 24593 '' : ' disabled'); 24594 break; 24595 24596 default: 24597 btnDisplay = button + 1; 24598 btnClass = page === button ? 24599 'active' : ''; 24600 break; 24601 } 24602 24603 if ( btnDisplay ) { 24604 node = $('<li>', { 24605 'class': classes.sPageButton+' '+btnClass, 24606 'id': idx === 0 && typeof button === 'string' ? 24607 settings.sTableId +'_'+ button : 24608 null 24609 } ) 24610 .append( $('<a>', { 24611 'href': '#', 24612 'aria-controls': settings.sTableId, 24613 'aria-label': aria[ button ], 24614 'data-dt-idx': counter, 24615 'tabindex': settings.iTabIndex 24616 } ) 24617 .html( btnDisplay ) 24618 ) 24619 .appendTo( container ); 24620 24621 settings.oApi._fnBindAction( 24622 node, {action: button}, clickHandler 24623 ); 24624 24625 counter++; 24626 } 24627 } 24628 } 24629 }; 24630 24631 // IE9 throws an 'unknown error' if document.activeElement is used 24632 // inside an iframe or frame. 24633 var activeEl; 24634 24635 try { 24636 // Because this approach is destroying and recreating the paging 24637 // elements, focus is lost on the select button which is bad for 24638 // accessibility. So we want to restore focus once the draw has 24639 // completed 24640 activeEl = $(host).find(document.activeElement).data('dt-idx'); 24641 } 24642 catch (e) {} 24643 24644 attach( 24645 $(host).empty().html('<ul class="pagination"/>').children('ul'), 24646 buttons 24647 ); 24648 24649 if ( activeEl !== undefined ) { 24650 $(host).find( '[data-dt-idx='+activeEl+']' ).focus(); 24651 } 24652}; 24653 24654 24655return DataTable; 24656})); 24657 24658 24659/*! Buttons for DataTables 1.5.4 24660 * ©2016-2018 SpryMedia Ltd - datatables.net/license 24661 */ 24662 24663(function( factory ){ 24664 if ( typeof define === 'function' && define.amd ) { 24665 // AMD 24666 define( ['jquery', 'datatables.net'], function ( $ ) { 24667 return factory( $, window, document ); 24668 } ); 24669 } 24670 else if ( typeof exports === 'object' ) { 24671 // CommonJS 24672 module.exports = function (root, $) { 24673 if ( ! root ) { 24674 root = window; 24675 } 24676 24677 if ( ! $ || ! $.fn.dataTable ) { 24678 $ = require('datatables.net')(root, $).$; 24679 } 24680 24681 return factory( $, root, root.document ); 24682 }; 24683 } 24684 else { 24685 // Browser 24686 factory( jQuery, window, document ); 24687 } 24688}(function( $, window, document, undefined ) { 24689'use strict'; 24690var DataTable = $.fn.dataTable; 24691 24692 24693// Used for namespacing events added to the document by each instance, so they 24694// can be removed on destroy 24695var _instCounter = 0; 24696 24697// Button namespacing counter for namespacing events on individual buttons 24698var _buttonCounter = 0; 24699 24700var _dtButtons = DataTable.ext.buttons; 24701 24702/** 24703 * [Buttons description] 24704 * @param {[type]} 24705 * @param {[type]} 24706 */ 24707var Buttons = function( dt, config ) 24708{ 24709 // If there is no config set it to an empty object 24710 if ( typeof( config ) === 'undefined' ) { 24711 config = {}; 24712 } 24713 24714 // Allow a boolean true for defaults 24715 if ( config === true ) { 24716 config = {}; 24717 } 24718 24719 // For easy configuration of buttons an array can be given 24720 if ( $.isArray( config ) ) { 24721 config = { buttons: config }; 24722 } 24723 24724 this.c = $.extend( true, {}, Buttons.defaults, config ); 24725 24726 // Don't want a deep copy for the buttons 24727 if ( config.buttons ) { 24728 this.c.buttons = config.buttons; 24729 } 24730 24731 this.s = { 24732 dt: new DataTable.Api( dt ), 24733 buttons: [], 24734 listenKeys: '', 24735 namespace: 'dtb'+(_instCounter++) 24736 }; 24737 24738 this.dom = { 24739 container: $('<'+this.c.dom.container.tag+'/>') 24740 .addClass( this.c.dom.container.className ) 24741 }; 24742 24743 this._constructor(); 24744}; 24745 24746 24747$.extend( Buttons.prototype, { 24748 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 24749 * Public methods 24750 */ 24751 24752 /** 24753 * Get the action of a button 24754 * @param {int|string} Button index 24755 * @return {function} 24756 *//** 24757 * Set the action of a button 24758 * @param {node} node Button element 24759 * @param {function} action Function to set 24760 * @return {Buttons} Self for chaining 24761 */ 24762 action: function ( node, action ) 24763 { 24764 var button = this._nodeToButton( node ); 24765 24766 if ( action === undefined ) { 24767 return button.conf.action; 24768 } 24769 24770 button.conf.action = action; 24771 24772 return this; 24773 }, 24774 24775 /** 24776 * Add an active class to the button to make to look active or get current 24777 * active state. 24778 * @param {node} node Button element 24779 * @param {boolean} [flag] Enable / disable flag 24780 * @return {Buttons} Self for chaining or boolean for getter 24781 */ 24782 active: function ( node, flag ) { 24783 var button = this._nodeToButton( node ); 24784 var klass = this.c.dom.button.active; 24785 var jqNode = $(button.node); 24786 24787 if ( flag === undefined ) { 24788 return jqNode.hasClass( klass ); 24789 } 24790 24791 jqNode.toggleClass( klass, flag === undefined ? true : flag ); 24792 24793 return this; 24794 }, 24795 24796 /** 24797 * Add a new button 24798 * @param {object} config Button configuration object, base string name or function 24799 * @param {int|string} [idx] Button index for where to insert the button 24800 * @return {Buttons} Self for chaining 24801 */ 24802 add: function ( config, idx ) 24803 { 24804 var buttons = this.s.buttons; 24805 24806 if ( typeof idx === 'string' ) { 24807 var split = idx.split('-'); 24808 var base = this.s; 24809 24810 for ( var i=0, ien=split.length-1 ; i<ien ; i++ ) { 24811 base = base.buttons[ split[i]*1 ]; 24812 } 24813 24814 buttons = base.buttons; 24815 idx = split[ split.length-1 ]*1; 24816 } 24817 24818 this._expandButton( buttons, config, false, idx ); 24819 this._draw(); 24820 24821 return this; 24822 }, 24823 24824 /** 24825 * Get the container node for the buttons 24826 * @return {jQuery} Buttons node 24827 */ 24828 container: function () 24829 { 24830 return this.dom.container; 24831 }, 24832 24833 /** 24834 * Disable a button 24835 * @param {node} node Button node 24836 * @return {Buttons} Self for chaining 24837 */ 24838 disable: function ( node ) { 24839 var button = this._nodeToButton( node ); 24840 24841 $(button.node).addClass( this.c.dom.button.disabled ); 24842 24843 return this; 24844 }, 24845 24846 /** 24847 * Destroy the instance, cleaning up event handlers and removing DOM 24848 * elements 24849 * @return {Buttons} Self for chaining 24850 */ 24851 destroy: function () 24852 { 24853 // Key event listener 24854 $('body').off( 'keyup.'+this.s.namespace ); 24855 24856 // Individual button destroy (so they can remove their own events if 24857 // needed). Take a copy as the array is modified by `remove` 24858 var buttons = this.s.buttons.slice(); 24859 var i, ien; 24860 24861 for ( i=0, ien=buttons.length ; i<ien ; i++ ) { 24862 this.remove( buttons[i].node ); 24863 } 24864 24865 // Container 24866 this.dom.container.remove(); 24867
24868 // Remove from the settings object collection 24869 var buttonInsts = this.s.dt.settings()[0]; 24870 24871 for ( i=0, ien=buttonInsts.length ; i<ien ; i++ ) { 24872 if ( buttonInsts.inst === this ) { 24873 buttonInsts.splice( i, 1 ); 24874 break; 24875 } 24876 } 24877 24878 return this; 24879 }, 24880 24881 /** 24882 * Enable / disable a button 24883 * @param {node} node Button node 24884 * @param {boolean} [flag=true] Enable / disable flag 24885 * @return {Buttons} Self for chaining 24886 */ 24887 enable: function ( node, flag ) 24888 { 24889 if ( flag === false ) { 24890 return this.disable( node ); 24891 } 24892 24893 var button = this._nodeToButton( node ); 24894 $(button.node).removeClass( this.c.dom.button.disabled ); 24895 24896 return this; 24897 }, 24898 24899 /** 24900 * Get the instance name for the button set selector 24901 * @return {string} Instance name 24902 */ 24903 name: function () 24904 { 24905 return this.c.name; 24906 }, 24907 24908 /** 24909 * Get a button's node 24910 * @param {node} node Button node 24911 * @return {jQuery} Button element 24912 */ 24913 node: function ( node ) 24914 { 24915 var button = this._nodeToButton( node ); 24916 return $(button.node); 24917 }, 24918 24919 /** 24920 * Set / get a processing class on the selected button 24921 * @param {boolean} flag true to add, false to remove, undefined to get 24922 * @return {boolean|Buttons} Getter value or this if a setter. 24923 */ 24924 processing: function ( node, flag ) 24925 { 24926 var button = this._nodeToButton( node ); 24927 24928 if ( flag === undefined ) { 24929 return $(button.node).hasClass( 'processing' ); 24930 } 24931 24932 $(button.node).toggleClass( 'processing', flag ); 24933 24934 return this; 24935 }, 24936 24937 /** 24938 * Remove a button. 24939 * @param {node} node Button node 24940 * @return {Buttons} Self for chaining 24941 */ 24942 remove: function ( node ) 24943 { 24944 var button = this._nodeToButton( node ); 24945 var host = this._nodeToHost( node ); 24946 var dt = this.s.dt; 24947 24948 // Remove any child buttons first 24949 if ( button.buttons.length ) { 24950 for ( var i=button.buttons.length-1 ; i>=0 ; i-- ) { 24951 this.remove( button.buttons[i].node ); 24952 } 24953 } 24954 24955 // Allow the button to remove event handlers, etc 24956 if ( button.conf.destroy ) { 24957 button.conf.destroy.call( dt.button(node), dt, $(node), button.conf ); 24958 } 24959 24960 this._removeKey( button.conf ); 24961 24962 $(button.node).remove(); 24963 24964 var idx = $.inArray( button, host ); 24965 host.splice( idx, 1 ); 24966 24967 return this; 24968 }, 24969 24970 /** 24971 * Get the text for a button 24972 * @param {int|string} node Button index 24973 * @return {string} Button text 24974 *//** 24975 * Set the text for a button 24976 * @param {int|string|function} node Button index 24977 * @param {string} label Text 24978 * @return {Buttons} Self for chaining 24979 */ 24980 text: function ( node, label ) 24981 { 24982 var button = this._nodeToButton( node ); 24983 var buttonLiner = this.c.dom.collection.buttonLiner; 24984 var linerTag = button.inCollection && buttonLiner && buttonLiner.tag ? 24985 buttonLiner.tag : 24986 this.c.dom.buttonLiner.tag; 24987 var dt = this.s.dt; 24988 var jqNode = $(button.node); 24989 var text = function ( opt ) { 24990 return typeof opt === 'function' ? 24991 opt( dt, jqNode, button.conf ) : 24992 opt; 24993 }; 24994 24995 if ( label === undefined ) { 24996 return text( button.conf.text ); 24997 } 24998 24999 button.conf.text = label; 25000 25001 if ( linerTag ) { 25002 jqNode.children( linerTag ).html( text(label) ); 25003 } 25004 else { 25005 jqNode.html( text(label) ); 25006 } 25007 25008 return this; 25009 }, 25010 25011 25012 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 25013 * Constructor 25014 */ 25015 25016 /** 25017 * Buttons constructor 25018 * @private 25019 */ 25020 _constructor: function () 25021 { 25022 var that = this; 25023 var dt = this.s.dt; 25024 var dtSettings = dt.settings()[0]; 25025 var buttons = this.c.buttons; 25026 25027 if ( ! dtSettings._buttons ) { 25028 dtSettings._buttons = []; 25029 } 25030 25031 dtSettings._buttons.push( { 25032 inst: this, 25033 name: this.c.name 25034 } ); 25035 25036 for ( var i=0, ien=buttons.length ; i<ien ; i++ ) { 25037 this.add( buttons[i] ); 25038 } 25039 25040 dt.on( 'destroy', function ( e, settings ) { 25041 if ( settings === dtSettings ) { 25042 that.destroy(); 25043 } 25044 } ); 25045 25046 // Global key event binding to listen for button keys 25047 $('body').on( 'keyup.'+this.s.namespace, function ( e ) { 25048 if ( ! document.activeElement || document.activeElement === document.body ) { 25049 // SUse a string of characters for fast lookup of if we need to 25050 // handle this 25051 var character = String.fromCharCode(e.keyCode).toLowerCase(); 25052 25053 if ( that.s.listenKeys.toLowerCase().indexOf( character ) !== -1 ) { 25054 that._keypress( character, e ); 25055 } 25056 } 25057 } ); 25058 }, 25059 25060 25061 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 25062 * Private methods 25063 */ 25064 25065 /** 25066 * Add a new button to the key press listener 25067 * @param {object} conf Resolved button configuration object 25068 * @private 25069 */ 25070 _addKey: function ( conf ) 25071 { 25072 if ( conf.key ) { 25073 this.s.listenKeys += $.isPlainObject( conf.key ) ? 25074 conf.key.key : 25075 conf.key; 25076 } 25077 }, 25078 25079 /**
25080 * Insert the buttons into the container. Call without parameters! 25081 * @param {node} [container] Recursive only - Insert point 25082 * @param {array} [buttons] Recursive only - Buttons array 25083 * @private 25084 */ 25085 _draw: function ( container, buttons ) 25086 { 25087 if ( ! container ) { 25088 container = this.dom.container; 25089 buttons = this.s.buttons; 25090 } 25091 25092 container.children().detach(); 25093 25094 for ( var i=0, ien=buttons.length ; i<ien ; i++ ) { 25095 container.append( buttons[i].inserter ); 25096 container.append( ' ' ); 25097 25098 if ( buttons[i].buttons && buttons[i].buttons.length ) { 25099 this._draw( buttons[i].collection, buttons[i].buttons ); 25100 } 25101 } 25102 }, 25103 25104 /** 25105 * Create buttons from an array of buttons 25106 * @param {array} attachTo Buttons array to attach to 25107 * @param {object} button Button definition 25108 * @param {boolean} inCollection true if the button is in a collection 25109 * @private 25110 */ 25111 _expandButton: function ( attachTo, button, inCollection, attachPoint ) 25112 { 25113 var dt = this.s.dt; 25114 var buttonCounter = 0; 25115 var buttons = ! $.isArray( button ) ? 25116 [ button ] : 25117 button; 25118 25119 for ( var i=0, ien=buttons.length ; i<ien ; i++ ) { 25120 var conf = this._resolveExtends( buttons[i] ); 25121 25122 if ( ! conf ) { 25123 continue; 25124 } 25125 25126 // If the configuration is an array, then expand the buttons at this 25127 // point 25128 if ( $.isArray( conf ) ) { 25129 this._expandButton( attachTo, conf, inCollection, attachPoint ); 25130 continue; 25131 } 25132 25133 var built = this._buildButton( conf, inCollection ); 25134 if ( ! built ) { 25135 continue; 25136 } 25137 25138 if ( attachPoint !== undefined ) { 25139 attachTo.splice( attachPoint, 0, built ); 25140 attachPoint++; 25141 } 25142 else { 25143 attachTo.push( built ); 25144 } 25145 25146 if ( built.conf.buttons ) { 25147 var collectionDom = this.c.dom.collection; 25148 built.collection = $('<'+collectionDom.tag+'/>') 25149 .addClass( collectionDom.className ) 25150 .attr( 'role', 'menu' ) ; 25151 built.conf._collection = built.collection; 25152 25153 this._expandButton( built.buttons, built.conf.buttons, true, attachPoint ); 25154 } 25155 25156 // init call is made here, rather than buildButton as it needs to 25157 // be selectable, and for that it needs to be in the buttons array 25158 if ( conf.init ) { 25159 conf.init.call( dt.button( built.node ), dt, $(built.node), conf ); 25160 } 25161 25162 buttonCounter++; 25163 } 25164 }, 25165 25166 /** 25167 * Create an individual button 25168 * @param {object} config Resolved button configuration 25169 * @param {boolean} inCollection `true` if a collection button 25170 * @return {jQuery} Created button node (jQuery) 25171 * @private 25172 */ 25173 _buildButton: function ( config, inCollection ) 25174 { 25175 var buttonDom = this.c.dom.button; 25176 var linerDom = this.c.dom.buttonLiner; 25177 var collectionDom = this.c.dom.collection; 25178 var dt = this.s.dt; 25179 var text = function ( opt ) { 25180 return typeof opt === 'function' ? 25181 opt( dt, button, config ) : 25182 opt; 25183 }; 25184 25185 if ( inCollection && collectionDom.button ) { 25186 buttonDom = collectionDom.button; 25187 } 25188 25189 if ( inCollection && collectionDom.buttonLiner ) { 25190 linerDom = collectionDom.buttonLiner; 25191 } 25192 25193 // Make sure that the button is available based on whatever requirements 25194 // it has. For example, Flash buttons require Flash 25195 if ( config.available && ! config.available( dt, config ) ) { 25196 return false; 25197 } 25198 25199 var action = function ( e, dt, button, config ) { 25200 config.action.call( dt.button( button ), e, dt, button, config ); 25201 25202 $(dt.table().node()).triggerHandler( 'buttons-action.dt', [ 25203 dt.button( button ), dt, button, config 25204 ] ); 25205 }; 25206 25207 var tag = config.tag || buttonDom.tag; 25208 var button = $('<'+tag+'/>') 25209 .addClass( buttonDom.className ) 25210 .attr( 'tabindex', this.s.dt.settings()[0].iTabIndex ) 25211 .attr( 'aria-controls', this.s.dt.table().node().id ) 25212 .on( 'click.dtb', function (e) { 25213 e.preventDefault(); 25214 25215 if ( ! button.hasClass( buttonDom.disabled ) && config.action ) { 25216 action( e, dt, button, config ); 25217 } 25218 25219 button.blur(); 25220 } ) 25221 .on( 'keyup.dtb', function (e) { 25222 if ( e.keyCode === 13 ) { 25223 if ( ! button.hasClass( buttonDom.disabled ) && config.action ) { 25224 action( e, dt, button, config ); 25225 } 25226 } 25227 } ); 25228 25229 // Make `a` tags act like a link 25230 if ( tag.toLowerCase() === 'a' ) { 25231 button.attr( 'href', '#' ); 25232 } 25233 25234 // Button tags should have `type=button` so they don't have any default behaviour 25235 if ( tag.toLowerCase() === 'button' ) { 25236 button.attr( 'type', 'button' ); 25237 } 25238 25239 if ( linerDom.tag ) { 25240 var liner = $('<'+linerDom.tag+'/>') 25241 .html( text( config.text ) ) 25242 .addClass( linerDom.className ); 25243 25244 if ( linerDom.tag.toLowerCase() === 'a' ) { 25245 liner.attr( 'href', '#' ); 25246 } 25247 25248 button.append( liner ); 25249 } 25250 else { 25251 button.html( text( config.text ) ); 25252 } 25253 25254 if ( config.enabled === false ) { 25255 button.addClass( buttonDom.disabled ); 25256 } 25257 25258 if ( config.className ) { 25259 button.addClass( config.className ); 25260 } 25261 25262 if ( config.titleAttr ) { 25263 button.attr( 'title', text( config.titleAttr ) ); 25264 } 25265 25266 if ( config.attr ) { 25267 button.attr( config.attr ); 25268 } 25269 25270 if ( ! config.namespace ) { 25271 config.namespace = '.dt-button-'+(_buttonCounter++); 25272 } 25273 25274 var buttonContainer = this.c.dom.buttonContainer; 25275 var inserter; 25276 if ( buttonContainer && buttonContainer.tag ) { 25277 inserter = $('<'+buttonContainer.tag+'/>') 25278 .addClass( buttonContainer.className ) 25279 .append( button ); 25280 } 25281 else { 25282 inserter = button; 25283 } 25284 25285 this._addKey( config ); 25286 25287 return { 25288 conf: config, 25289 node: button.get(0), 25290 inserter: inserter, 25291 buttons: [], 25292 inCollection: inCollection, 25293 collection: null 25294 }; 25295 }, 25296 25297 /** 25298 * Get the button object from a node (recursive) 25299 * @param {node} node Button node 25300 * @param {array} [buttons] Button array, uses base if not defined 25301 * @return {object} Button object 25302 * @private 25303 */ 25304 _nodeToButton: function ( node, buttons ) 25305 { 25306 if ( ! buttons ) { 25307 buttons = this.s.buttons; 25308 } 25309 25310 for ( var i=0, ien=buttons.length ; i<ien ; i++ ) { 25311 if ( buttons[i].node === node ) { 25312 return buttons[i]; 25313 } 25314 25315 if ( buttons[i].buttons.length ) { 25316 var ret = this._nodeToButton( node, buttons[i].buttons ); 25317 25318 if ( ret ) { 25319 return ret; 25320 } 25321 } 25322 } 25323 }, 25324 25325 /** 25326 * Get container array for a button from a button node (recursive) 25327 * @param {node} node Button node 25328 * @param {array} [buttons] Button array, uses base if not defined 25329 * @return {array} Button's host array 25330 * @private 25331 */ 25332 _nodeToHost: function ( node, buttons ) 25333 { 25334 if ( ! buttons ) { 25335 buttons = this.s.buttons; 25336 } 25337 25338 for ( var i=0, ien=buttons.length ; i<ien ; i++ ) { 25339 if ( buttons[i].node === node ) { 25340 return buttons; 25341 } 25342 25343 if ( buttons[i].buttons.length ) { 25344 var ret = this._nodeToHost( node, buttons[i].buttons ); 25345 25346 if ( ret ) { 25347 return ret; 25348 } 25349 } 25350 } 25351 }, 25352 25353 /** 25354 * Handle a key press - determine if any button's key configured matches 25355 * what was typed and trigger the action if so. 25356 * @param {string} character The character pressed 25357 * @param {object} e Key event that triggered this call 25358 * @private 25359 */ 25360 _keypress: function ( character, e ) 25361 { 25362 // Check if this button press already activated on another instance of Buttons 25363 if ( e._buttonsHandled ) { 25364 return; 25365 } 25366 25367 var run = function ( conf, node ) { 25368 if ( ! conf.key ) { 25369 return; 25370 } 25371 25372 if ( conf.key === character ) { 25373 e._buttonsHandled = true; 25374 $(node).click(); 25375 } 25376 else if ( $.isPlainObject( conf.key ) ) { 25377 if ( conf.key.key !== character ) { 25378 return; 25379 } 25380
25381 if ( conf.key.shiftKey && ! e.shiftKey ) { 25382 return; 25383 } 25384 25385 if ( conf.key.altKey && ! e.altKey ) { 25386 return; 25387 } 25388 25389 if ( conf.key.ctrlKey && ! e.ctrlKey ) { 25390 return; 25391 } 25392 25393 if ( conf.key.metaKey && ! e.metaKey ) { 25394 return; 25395 } 25396 25397 // Made it this far - it is good 25398 e._buttonsHandled = true; 25399 $(node).click(); 25400 } 25401 }; 25402 25403 var recurse = function ( a ) { 25404 for ( var i=0, ien=a.length ; i<ien ; i++ ) { 25405 run( a[i].conf, a[i].node ); 25406 25407 if ( a[i].buttons.length ) { 25408 recurse( a[i].buttons ); 25409 } 25410 } 25411 }; 25412 25413 recurse( this.s.buttons ); 25414 }, 25415 25416 /** 25417 * Remove a key from the key listener for this instance (to be used when a 25418 * button is removed) 25419 * @param {object} conf Button configuration 25420 * @private 25421 */ 25422 _removeKey: function ( conf ) 25423 { 25424 if ( conf.key ) { 25425 var character = $.isPlainObject( conf.key ) ? 25426 conf.key.key : 25427 conf.key; 25428 25429 // Remove only one character, as multiple buttons could have the 25430 // same listening key 25431 var a = this.s.listenKeys.split(''); 25432 var idx = $.inArray( character, a ); 25433 a.splice( idx, 1 ); 25434 this.s.listenKeys = a.join(''); 25435 } 25436 }, 25437 25438 /** 25439 * Resolve a button configuration 25440 * @param {string|function|object} conf Button config to resolve 25441 * @return {object} Button configuration 25442 * @private 25443 */ 25444 _resolveExtends: function ( conf ) 25445 { 25446 var dt = this.s.dt; 25447 var i, ien; 25448 var toConfObject = function ( base ) { 25449 var loop = 0; 25450 25451 // Loop until we have resolved to a button configuration, or an 25452 // array of button configurations (which will be iterated 25453 // separately) 25454 while ( ! $.isPlainObject(base) && ! $.isArray(base) ) { 25455 if ( base === undefined ) { 25456 return; 25457 } 25458 25459 if ( typeof base === 'function' ) { 25460 base = base( dt, conf ); 25461 25462 if ( ! base ) { 25463 return false; 25464 } 25465 } 25466 else if ( typeof base === 'string' ) { 25467 if ( ! _dtButtons[ base ] ) { 25468 throw 'Unknown button type: '+base; 25469 } 25470 25471 base = _dtButtons[ base ]; 25472 } 25473 25474 loop++; 25475 if ( loop > 30 ) { 25476 // Protect against misconfiguration killing the browser 25477 throw 'Buttons: Too many iterations'; 25478 } 25479 } 25480 25481 return $.isArray( base ) ? 25482 base : 25483 $.extend( {}, base ); 25484 }; 25485 25486 conf = toConfObject( conf ); 25487 25488 while ( conf && conf.extend ) { 25489 // Use `toConfObject` in case the button definition being extended 25490 // is itself a string or a function 25491 if ( ! _dtButtons[ conf.extend ] ) { 25492 throw 'Cannot extend unknown button type: '+conf.extend; 25493 } 25494 25495 var objArray = toConfObject( _dtButtons[ conf.extend ] ); 25496 if ( $.isArray( objArray ) ) { 25497 return objArray; 25498 } 25499 else if ( ! objArray ) { 25500 // This is a little brutal as it might be possible to have a 25501 // valid button without the extend, but if there is no extend 25502 // then the host button would be acting in an undefined state 25503 return false; 25504 } 25505 25506 // Stash the current class name 25507 var originalClassName = objArray.className; 25508 25509 conf = $.extend( {}, objArray, conf ); 25510 25511 // The extend will have overwritten the original class name if the 25512 // `conf` object also assigned a class, but we want to concatenate 25513 // them so they are list that is combined from all extended buttons 25514 if ( originalClassName && conf.className !== originalClassName ) { 25515 conf.className = originalClassName+' '+conf.className; 25516 } 25517 25518 // Buttons to be added to a collection -gives the ability to define 25519 // if buttons should be added to the start or end of a collection 25520 var postfixButtons = conf.postfixButtons; 25521 if ( postfixButtons ) { 25522 if ( ! conf.buttons ) { 25523 conf.buttons = []; 25524 } 25525 25526 for ( i=0, ien=postfixButtons.length ; i<ien ; i++ ) { 25527 conf.buttons.push( postfixButtons[i] ); 25528 } 25529 25530 conf.postfixButtons = null; 25531 } 25532 25533 var prefixButtons = conf.prefixButtons; 25534 if ( prefixButtons ) { 25535 if ( ! conf.buttons ) { 25536 conf.buttons = []; 25537 } 25538 25539 for ( i=0, ien=prefixButtons.length ; i<ien ; i++ ) { 25540 conf.buttons.splice( i, 0, prefixButtons[i] ); 25541 } 25542 25543 conf.prefixButtons = null; 25544 } 25545 25546 // Although we want the `conf` object to overwrite almost all of 25547 // the properties of the object being extended, the `extend` 25548 // property should come from the object being extended 25549 conf.extend = objArray.extend; 25550 } 25551 25552 return conf; 25553 } 25554} ); 25555 25556 25557 25558/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 25559 * Statics 25560 */ 25561 25562/** 25563 * Show / hide a background layer behind a collection 25564 * @param {boolean} Flag to indicate if the background should be shown or 25565 * hidden 25566 * @param {string} Class to assign to the background 25567 * @static 25568 */ 25569Buttons.background = function ( show, className, fade, insertPoint ) { 25570 if ( fade === undefined ) { 25571 fade = 400; 25572 } 25573 if ( ! insertPoint ) { 25574 insertPoint = document.body; 25575 } 25576 25577 if ( show ) { 25578 $('<div/>') 25579 .addClass( className ) 25580 .css( 'display', 'none' ) 25581 .insertAfter( insertPoint ) 25582 .fadeIn( fade ); 25583 } 25584 else { 25585 $('div.'+className) 25586 .fadeOut( fade, function () { 25587 $(this) 25588 .removeClass( className ) 25589 .remove(); 25590 } ); 25591 } 25592}; 25593 25594/** 25595 * Instance selector - select Buttons instances based on an instance selector 25596 * value from the buttons assigned to a DataTable. This is only useful if 25597 * multiple instances are attached to a DataTable. 25598 * @param {string|int|array} Instance selector - see `instance-selector` 25599 * documentation on the DataTables site 25600 * @param {array} Button instance array that was attached to the DataTables 25601 * settings object 25602 * @return {array} Buttons instances 25603 * @static 25604 */ 25605Buttons.instanceSelector = function ( group, buttons ) 25606{ 25607 if ( ! group ) { 25608 return $.map( buttons, function ( v ) { 25609 return v.inst; 25610 } ); 25611 } 25612 25613 var ret = []; 25614 var names = $.map( buttons, function ( v ) { 25615 return v.name; 25616 } ); 25617 25618 // Flatten the group selector into an array of single options 25619 var process = function ( input ) { 25620 if ( $.isArray( input ) ) { 25621 for ( var i=0, ien=input.length ; i<ien ; i++ ) { 25622 process( input[i] ); 25623 } 25624 return; 25625 } 25626 25627 if ( typeof input === 'string' ) { 25628 if ( input.indexOf( ',' ) !== -1 ) { 25629 // String selector, list of names 25630 process( input.split(',') ); 25631 } 25632 else { 25633 // String selector individual name 25634 var idx = $.inArray( $.trim(input), names ); 25635 25636 if ( idx !== -1 ) {
25637 ret.push( buttons[ idx ].inst ); 25638 } 25639 } 25640 } 25641 else if ( typeof input === 'number' ) { 25642 // Index selector 25643 ret.push( buttons[ input ].inst ); 25644 } 25645 }; 25646 25647 process( group ); 25648 25649 return ret; 25650}; 25651 25652/** 25653 * Button selector - select one or more buttons from a selector input so some 25654 * operation can be performed on them. 25655 * @param {array} Button instances array that the selector should operate on 25656 * @param {string|int|node|jQuery|array} Button selector - see 25657 * `button-selector` documentation on the DataTables site 25658 * @return {array} Array of objects containing `inst` and `idx` properties of 25659 * the selected buttons so you know which instance each button belongs to. 25660 * @static 25661 */ 25662Buttons.buttonSelector = function ( insts, selector ) 25663{ 25664 var ret = []; 25665 var nodeBuilder = function ( a, buttons, baseIdx ) { 25666 var button; 25667 var idx; 25668 25669 for ( var i=0, ien=buttons.length ; i<ien ; i++ ) { 25670 button = buttons[i]; 25671 25672 if ( button ) { 25673 idx = baseIdx !== undefined ? 25674 baseIdx+i : 25675 i+''; 25676 25677 a.push( { 25678 node: button.node, 25679 name: button.conf.name, 25680 idx: idx 25681 } ); 25682 25683 if ( button.buttons ) { 25684 nodeBuilder( a, button.buttons, idx+'-' ); 25685 } 25686 } 25687 } 25688 }; 25689 25690 var run = function ( selector, inst ) { 25691 var i, ien; 25692 var buttons = []; 25693 nodeBuilder( buttons, inst.s.buttons ); 25694 25695 var nodes = $.map( buttons, function (v) { 25696 return v.node; 25697 } ); 25698 25699 if ( $.isArray( selector ) || selector instanceof $ ) { 25700 for ( i=0, ien=selector.length ; i<ien ; i++ ) { 25701 run( selector[i], inst ); 25702 } 25703 return; 25704 } 25705 25706 if ( selector === null || selector === undefined || selector === '*' ) { 25707 // Select all 25708 for ( i=0, ien=buttons.length ; i<ien ; i++ ) { 25709 ret.push( { 25710 inst: inst, 25711 node: buttons[i].node 25712 } ); 25713 } 25714 } 25715 else if ( typeof selector === 'number' ) { 25716 // Main button index selector 25717 ret.push( { 25718 inst: inst, 25719 node: inst.s.buttons[ selector ].node 25720 } ); 25721 } 25722 else if ( typeof selector === 'string' ) { 25723 if ( selector.indexOf( ',' ) !== -1 ) { 25724 // Split 25725 var a = selector.split(','); 25726 25727 for ( i=0, ien=a.length ; i<ien ; i++ ) { 25728 run( $.trim(a[i]), inst ); 25729 } 25730 } 25731 else if ( selector.match( /^\d+(\-\d+)*$/ ) ) { 25732 // Sub-button index selector 25733 var indexes = $.map( buttons, function (v) { 25734 return v.idx; 25735 } ); 25736 25737 ret.push( { 25738 inst: inst, 25739 node: buttons[ $.inArray( selector, indexes ) ].node 25740 } ); 25741 } 25742 else if ( selector.indexOf( ':name' ) !== -1 ) { 25743 // Button name selector 25744 var name = selector.replace( ':name', '' ); 25745 25746 for ( i=0, ien=buttons.length ; i<ien ; i++ ) { 25747 if ( buttons[i].name === name ) { 25748 ret.push( { 25749 inst: inst, 25750 node: buttons[i].node 25751 } ); 25752 } 25753 } 25754 } 25755 else { 25756 // jQuery selector on the nodes 25757 $( nodes ).filter( selector ).each( function () { 25758 ret.push( { 25759 inst: inst, 25760 node: this 25761 } ); 25762 } ); 25763 } 25764 } 25765 else if ( typeof selector === 'object' && selector.nodeName ) { 25766 // Node selector 25767 var idx = $.inArray( selector, nodes ); 25768 25769 if ( idx !== -1 ) { 25770 ret.push( { 25771 inst: inst, 25772 node: nodes[ idx ] 25773 } ); 25774 } 25775 } 25776 }; 25777 25778 25779 for ( var i=0, ien=insts.length ; i<ien ; i++ ) { 25780 var inst = insts[i]; 25781 25782 run( selector, inst ); 25783 } 25784 25785 return ret; 25786}; 25787 25788 25789/** 25790 * Buttons defaults. For full documentation, please refer to the docs/option 25791 * directory or the DataTables site. 25792 * @type {Object} 25793 * @static 25794 */ 25795Buttons.defaults = { 25796 buttons: [ 'copy', 'excel', 'csv', 'pdf', 'print' ], 25797 name: 'main', 25798 tabIndex: 0, 25799 dom: { 25800 container: { 25801 tag: 'div', 25802 className: 'dt-buttons' 25803 }, 25804 collection: { 25805 tag: 'div', 25806 className: 'dt-button-collection' 25807 }, 25808 button: { 25809 // Flash buttons will not work with `<button>` in IE - it has to be `<a>` 25810 tag: 'ActiveXObject' in window ? 25811 'a' : 25812 'button', 25813 className: 'dt-button', 25814 active: 'active', 25815 disabled: 'disabled' 25816 }, 25817 buttonLiner: { 25818 tag: 'span', 25819 className: '' 25820 } 25821 } 25822}; 25823 25824/** 25825 * Version information 25826 * @type {string} 25827 * @static 25828 */ 25829Buttons.version = '1.5.4'; 25830 25831 25832$.extend( _dtButtons, { 25833 collection: { 25834 text: function ( dt ) { 25835 return dt.i18n( 'buttons.collection', 'Collection' ); 25836 }, 25837 className: 'buttons-collection', 25838 action: function ( e, dt, button, config ) { 25839 var host = button; 25840 var collectionParent = $(button).parents('div.dt-button-collection'); 25841 var hostPosition = host.position(); 25842 var tableContainer = $( dt.table().container() ); 25843 var multiLevel = false;
25844 var insertPoint = host; 25845 25846 // Remove any old collection 25847 if ( collectionParent.length ) { 25848 multiLevel = $('.dt-button-collection').position(); 25849 insertPoint = collectionParent; 25850 $('body').trigger( 'click.dtb-collection' ); 25851 } 25852 25853 if ( insertPoint.parents('body')[0] !== document.body ) { 25854 insertPoint = document.body.lastChild; 25855 } 25856 25857 config._collection.find('.dt-button-collection-title').remove(); 25858 config._collection.prepend('<div class="dt-button-collection-title">'+config.collectionTitle+'</div>'); 25859 25860 config._collection 25861 .addClass( config.collectionLayout ) 25862 .css( 'display', 'none' ) 25863 .insertAfter( insertPoint ) 25864 .fadeIn( config.fade ); 25865 25866 var position = config._collection.css( 'position' ); 25867 25868 if ( multiLevel && position === 'absolute' ) { 25869 config._collection.css( { 25870 top: multiLevel.top, 25871 left: multiLevel.left 25872 } ); 25873 } 25874 else if ( position === 'absolute' ) { 25875 config._collection.css( { 25876 top: hostPosition.top + host.outerHeight(), 25877 left: hostPosition.left 25878 } ); 25879 25880 // calculate overflow when positioned beneath 25881 var tableBottom = tableContainer.offset().top + tableContainer.height(); 25882 var listBottom = hostPosition.top + host.outerHeight() + config._collection.outerHeight(); 25883 var bottomOverflow = listBottom - tableBottom; 25884 25885 // calculate overflow when positioned above 25886 var listTop = hostPosition.top - config._collection.outerHeight(); 25887 var tableTop = tableContainer.offset().top; 25888 var topOverflow = tableTop - listTop; 25889 25890 // if bottom overflow is larger, move to the top because it fits better, or if dropup is requested 25891 if (bottomOverflow > topOverflow || config.dropup) { 25892 config._collection.css( 'top', hostPosition.top - config._collection.outerHeight() - 5); 25893 } 25894 25895 // Right alignment is enabled on a class, e.g. bootstrap: 25896 // $.fn.dataTable.Buttons.defaults.dom.collection.className += " dropdown-menu-right"; 25897 if ( config._collection.hasClass( config.rightAlignClassName ) ) { 25898 config._collection.css( 'left', hostPosition.left + host.outerWidth() - config._collection.outerWidth() ); 25899 } 25900 25901 // Right alignment in table container 25902 var listRight = hostPosition.left + config._collection.outerWidth(); 25903 var tableRight = tableContainer.offset().left + tableContainer.width(); 25904 if ( listRight > tableRight ) { 25905 config._collection.css( 'left', hostPosition.left - ( listRight - tableRight ) ); 25906 } 25907 25908 // Right alignment to window 25909 var listOffsetRight = host.offset().left + config._collection.outerWidth(); 25910 if ( listOffsetRight > $(window).width() ) { 25911 config._collection.css( 'left', hostPosition.left - (listOffsetRight-$(window).width()) ); 25912 } 25913 } 25914 else { 25915 // Fix position - centre on screen 25916 var top = config._collection.height() / 2; 25917 if ( top > $(window).height() / 2 ) { 25918 top = $(window).height() / 2; 25919 } 25920 25921 config._collection.css( 'marginTop', top*-1 ); 25922 } 25923 25924 if ( config.background ) { 25925 Buttons.background( true, config.backgroundClassName, config.fade, insertPoint ); 25926 } 25927 25928 var close = function () { 25929 config._collection 25930 .fadeOut( config.fade, function () { 25931 config._collection.detach(); 25932 } ); 25933 25934 $('div.dt-button-background').off( 'click.dtb-collection' ); 25935 Buttons.background( false, config.backgroundClassName, config.fade, insertPoint ); 25936 25937 $('body').off( '.dtb-collection' ); 25938 dt.off( 'buttons-action.b-internal' ); 25939 }; 25940 25941 // Need to break the 'thread' for the collection button being 25942 // activated by a click - it would also trigger this event 25943 setTimeout( function () { 25944 // This is bonkers, but if we don't have a click listener on the 25945 // background element, iOS Safari will ignore the body click 25946 // listener below. An empty function here is all that is 25947 // required to make it work... 25948 $('div.dt-button-background').on( 'click.dtb-collection', function () {} ); 25949 25950 $('body') 25951 .on( 'click.dtb-collection', function (e) { 25952 // andSelf is deprecated in jQ1.8, but we want 1.7 compat 25953 var back = $.fn.addBack ? 'addBack' : 'andSelf'; 25954 25955 if ( ! $(e.target).parents()[back]().filter( config._collection ).length ) { 25956 close(); 25957 } 25958 } ) 25959 .on( 'keyup.dtb-collection', function (e) { 25960 if ( e.keyCode === 27 ) { 25961 close(); 25962 } 25963 } ); 25964 25965 if ( config.autoClose ) { 25966 dt.on( 'buttons-action.b-internal', function () { 25967 close(); 25968 } ); 25969 } 25970 }, 10 ); 25971 }, 25972 background: true, 25973 collectionLayout: '', 25974 collectionTitle: '', 25975 backgroundClassName: 'dt-button-background', 25976 rightAlignClassName: 'dt-button-right', 25977 autoClose: false, 25978 fade: 400, 25979 attr: { 25980 'aria-haspopup': true 25981 } 25982 }, 25983 copy: function ( dt, conf ) { 25984 if ( _dtButtons.copyHtml5 ) { 25985 return 'copyHtml5'; 25986 } 25987 if ( _dtButtons.copyFlash && _dtButtons.copyFlash.available( dt, conf ) ) { 25988 return 'copyFlash'; 25989 } 25990 }, 25991 csv: function ( dt, conf ) { 25992 // Common option that will use the HTML5 or Flash export buttons 25993 if ( _dtButtons.csvHtml5 && _dtButtons.csvHtml5.available( dt, conf ) ) { 25994 return 'csvHtml5'; 25995 } 25996 if ( _dtButtons.csvFlash && _dtButtons.csvFlash.available( dt, conf ) ) { 25997 return 'csvFlash'; 25998 } 25999 }, 26000 excel: function ( dt, conf ) { 26001 // Common option that will use the HTML5 or Flash export buttons 26002 if ( _dtButtons.excelHtml5 && _dtButtons.excelHtml5.available( dt, conf ) ) { 26003 return 'excelHtml5'; 26004 } 26005 if ( _dtButtons.excelFlash && _dtButtons.excelFlash.available( dt, conf ) ) { 26006 return 'excelFlash'; 26007 } 26008 }, 26009 pdf: function ( dt, conf ) { 26010 // Common option that will use the HTML5 or Flash export buttons 26011 if ( _dtButtons.pdfHtml5 && _dtButtons.pdfHtml5.available( dt, conf ) ) { 26012 return 'pdfHtml5'; 26013 } 26014 if ( _dtButtons.pdfFlash && _dtButtons.pdfFlash.available( dt, conf ) ) { 26015 return 'pdfFlash'; 26016 } 26017 }, 26018 pageLength: function ( dt ) { 26019 var lengthMenu = dt.settings()[0].aLengthMenu; 26020 var vals = $.isArray( lengthMenu[0] ) ? lengthMenu[0] : lengthMenu; 26021 var lang = $.isArray( lengthMenu[0] ) ? lengthMenu[1] : lengthMenu; 26022 var text = function ( dt ) { 26023 return dt.i18n( 'buttons.pageLength', { 26024 "-1": 'Show all rows', 26025 _: 'Show %d rows' 26026 }, dt.page.len() ); 26027 }; 26028 26029 return { 26030 extend: 'collection', 26031 text: text, 26032 className: 'buttons-page-length', 26033 autoClose: true, 26034 buttons: $.map( vals, function ( val, i ) { 26035 return { 26036 text: lang[i], 26037 className: 'button-page-length', 26038 action: function ( e, dt ) { 26039 dt.page.len( val ).draw(); 26040 }, 26041 init: function ( dt, node, conf ) { 26042 var that = this; 26043 var fn = function () { 26044 that.active( dt.page.len() === val ); 26045 }; 26046 26047 dt.on( 'length.dt'+conf.namespace, fn ); 26048 fn(); 26049 }, 26050 destroy: function ( dt, node, conf ) { 26051 dt.off( 'length.dt'+conf.namespace ); 26052 } 26053 }; 26054 } ), 26055 init: function ( dt, node, conf ) { 26056 var that = this; 26057 dt.on( 'length.dt'+conf.namespace, function () { 26058 that.text( text( dt ) ); 26059 } ); 26060 }, 26061 destroy: function ( dt, node, conf ) { 26062 dt.off( 'length.dt'+conf.namespace ); 26063 } 26064 }; 26065 } 26066} ); 26067 26068 26069/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 26070 * DataTables API 26071 * 26072 * For complete documentation, please refer to the docs/api directory or the 26073 * DataTables site 26074 */ 26075 26076// Buttons group and individual button selector 26077DataTable.Api.register( 'buttons()', function ( group, selector ) { 26078 // Argument shifting 26079 if ( selector === undefined ) { 26080 selector = group; 26081 group = undefined; 26082 } 26083 26084 this.selector.buttonGroup = group; 26085 26086 var res = this.iterator( true, 'table', function ( ctx ) { 26087 if ( ctx._buttons ) { 26088 return Buttons.buttonSelector( 26089 Buttons.instanceSelector( group, ctx._buttons ), 26090 selector 26091 ); 26092 } 26093 }, true ); 26094 26095 res._groupSelector = group; 26096 return res; 26097} ); 26098 26099// Individual button selector 26100DataTable.Api.register( 'button()', function ( group, selector ) { 26101 // just run buttons() and truncate 26102 var buttons = this.buttons( group, selector ); 26103 26104 if ( buttons.length > 1 ) { 26105 buttons.splice( 1, buttons.length ); 26106 } 26107 26108 return buttons; 26109} ); 26110 26111// Active buttons 26112DataTable.Api.registerPlural( 'buttons().active()', 'button().active()', function ( flag ) { 26113 if ( flag === undefined ) { 26114 return this.map( function ( set ) { 26115 return set.inst.active( set.node ); 26116 } ); 26117 } 26118 26119 return this.each( function ( set ) { 26120 set.inst.active( set.node, flag ); 26121 } ); 26122} ); 26123 26124// Get / set button action 26125DataTable.Api.registerPlural( 'buttons().action()', 'button().action()', function ( action ) { 26126 if ( action === undefined ) { 26127 return this.map( function ( set ) { 26128 return set.inst.action( set.node ); 26129 } ); 26130 } 26131 26132 return this.each( function ( set ) { 26133 set.inst.action( set.node, action ); 26134 } ); 26135} ); 26136 26137// Enable / disable buttons 26138DataTable.Api.register( ['buttons().enable()', 'button().enable()'], function ( flag ) { 26139 return this.each( function ( set ) { 26140 set.inst.enable( set.node, flag ); 26141 } ); 26142} ); 26143 26144// Disable buttons 26145DataTable.Api.register( ['buttons().disable()', 'button().disable()'], function () { 26146 return this.each( function ( set ) { 26147 set.inst.disable( set.node ); 26148 } ); 26149} ); 26150 26151// Get button nodes 26152DataTable.Api.registerPlural( 'buttons().nodes()', 'button().node()', function () { 26153 var jq = $(); 26154 26155 // jQuery will automatically reduce duplicates to a single entry 26156 $( this.each( function ( set ) {
26157 jq = jq.add( set.inst.node( set.node ) ); 26158 } ) ); 26159 26160 return jq; 26161} ); 26162 26163// Get / set button processing state 26164DataTable.Api.registerPlural( 'buttons().processing()', 'button().processing()', function ( flag ) { 26165 if ( flag === undefined ) { 26166 return this.map( function ( set ) { 26167 return set.inst.processing( set.node ); 26168 } ); 26169 } 26170 26171 return this.each( function ( set ) { 26172 set.inst.processing( set.node, flag ); 26173 } ); 26174} ); 26175 26176// Get / set button text (i.e. the button labels) 26177DataTable.Api.registerPlural( 'buttons().text()', 'button().text()', function ( label ) { 26178 if ( label === undefined ) { 26179 return this.map( function ( set ) { 26180 return set.inst.text( set.node ); 26181 } ); 26182 } 26183 26184 return this.each( function ( set ) { 26185 set.inst.text( set.node, label ); 26186 } ); 26187} ); 26188 26189// Trigger a button's action 26190DataTable.Api.registerPlural( 'buttons().trigger()', 'button().trigger()', function () { 26191 return this.each( function ( set ) { 26192 set.inst.node( set.node ).trigger( 'click' ); 26193 } ); 26194} ); 26195 26196// Get the container elements 26197DataTable.Api.registerPlural( 'buttons().containers()', 'buttons().container()', function () { 26198 var jq = $(); 26199 var groupSelector = this._groupSelector; 26200 26201 // We need to use the group selector directly, since if there are no buttons 26202 // the result set will be empty 26203 this.iterator( true, 'table', function ( ctx ) { 26204 if ( ctx._buttons ) { 26205 var insts = Buttons.instanceSelector( groupSelector, ctx._buttons ); 26206 26207 for ( var i=0, ien=insts.length ; i<ien ; i++ ) { 26208 jq = jq.add( insts[i].container() ); 26209 } 26210 } 26211 } ); 26212 26213 return jq; 26214} ); 26215 26216// Add a new button 26217DataTable.Api.register( 'button().add()', function ( idx, conf ) { 26218 var ctx = this.context; 26219 26220 // Don't use `this` as it could be empty - select the instances directly 26221 if ( ctx.length ) { 26222 var inst = Buttons.instanceSelector( this._groupSelector, ctx[0]._buttons ); 26223 26224 if ( inst.length ) { 26225 inst[0].add( conf, idx ); 26226 } 26227 } 26228 26229 return this.button( this._groupSelector, idx ); 26230} ); 26231 26232// Destroy the button sets selected 26233DataTable.Api.register( 'buttons().destroy()', function () { 26234 this.pluck( 'inst' ).unique().each( function ( inst ) { 26235 inst.destroy(); 26236 } ); 26237 26238 return this; 26239} ); 26240 26241// Remove a button 26242DataTable.Api.registerPlural( 'buttons().remove()', 'buttons().remove()', function () { 26243 this.each( function ( set ) { 26244 set.inst.remove( set.node ); 26245 } ); 26246 26247 return this; 26248} ); 26249 26250// Information box that can be used by buttons 26251var _infoTimer; 26252DataTable.Api.register( 'buttons.info()', function ( title, message, time ) { 26253 var that = this; 26254 26255 if ( title === false ) { 26256 $('#datatables_buttons_info').fadeOut( function () { 26257 $(this).remove(); 26258 } ); 26259 clearTimeout( _infoTimer ); 26260 _infoTimer = null; 26261 26262 return this; 26263 } 26264 26265 if ( _infoTimer ) { 26266 clearTimeout( _infoTimer ); 26267 } 26268 26269 if ( $('#datatables_buttons_info').length ) { 26270 $('#datatables_buttons_info').remove(); 26271 } 26272 26273 title = title ? '<h2>'+title+'</h2>' : ''; 26274 26275 $('<div id="datatables_buttons_info" class="dt-button-info"/>') 26276 .html( title ) 26277 .append( $('<div/>')[ typeof message === 'string' ? 'html' : 'append' ]( message ) ) 26278 .css( 'display', 'none' ) 26279 .appendTo( 'body' ) 26280 .fadeIn(); 26281 26282 if ( time !== undefined && time !== 0 ) { 26283 _infoTimer = setTimeout( function () { 26284 that.buttons.info( false ); 26285 }, time ); 26286 } 26287 26288 return this; 26289} ); 26290 26291// Get data from the table for export - this is common to a number of plug-in 26292// buttons so it is included in the Buttons core library 26293DataTable.Api.register( 'buttons.exportData()', function ( options ) { 26294 if ( this.context.length ) { 26295 return _exportData( new DataTable.Api( this.context[0] ), options ); 26296 } 26297} ); 26298 26299// Get information about the export that is common to many of the export data 26300// types (DRY) 26301DataTable.Api.register( 'buttons.exportInfo()', function ( conf ) { 26302 if ( ! conf ) { 26303 conf = {}; 26304 } 26305 26306 return { 26307 filename: _filename( conf ), 26308 title: _title( conf ), 26309 messageTop: _message(this, conf.message || conf.messageTop, 'top'), 26310 messageBottom: _message(this, conf.messageBottom, 'bottom') 26311 }; 26312} ); 26313 26314 26315 26316/** 26317 * Get the file name for an exported file. 26318 * 26319 * @param {object} config Button configuration 26320 * @param {boolean} incExtension Include the file name extension 26321 */ 26322var _filename = function ( config ) 26323{ 26324 // Backwards compatibility 26325 var filename = config.filename === '*' && config.title !== '*' && config.title !== undefined && config.title !== null && config.title !== '' ? 26326 config.title : 26327 config.filename; 26328 26329 if ( typeof filename === 'function' ) { 26330 filename = filename(); 26331 } 26332 26333 if ( filename === undefined || filename === null ) { 26334 return null; 26335 } 26336 26337 if ( filename.indexOf( '*' ) !== -1 ) { 26338 filename = $.trim( filename.replace( '*', $('head > title').text() ) ); 26339 } 26340 26341 // Strip characters which the OS will object to 26342 filename = filename.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g, ""); 26343 26344 var extension = _stringOrFunction( config.extension ); 26345 if ( ! extension ) { 26346 extension = ''; 26347 } 26348 26349 return filename + extension; 26350}; 26351 26352/** 26353 * Simply utility method to allow parameters to be given as a function 26354 * 26355 * @param {undefined|string|function} option Option 26356 * @return {null|string} Resolved value 26357 */ 26358var _stringOrFunction = function ( option ) 26359{ 26360 if ( option === null || option === undefined ) { 26361 return null; 26362 } 26363 else if ( typeof option === 'function' ) { 26364 return option(); 26365 } 26366 return option; 26367}; 26368 26369/** 26370 * Get the title for an exported file. 26371 * 26372 * @param {object} config Button configuration 26373 */ 26374var _title = function ( config ) 26375{ 26376 var title = _stringOrFunction( config.title ); 26377 26378 return title === null ? 26379 null : title.indexOf( '*' ) !== -1 ? 26380 title.replace( '*', $('head > title').text() || 'Exported data' ) : 26381 title; 26382}; 26383 26384var _message = function ( dt, option, position ) 26385{ 26386 var message = _stringOrFunction( option ); 26387 if ( message === null ) { 26388 return null; 26389 } 26390 26391 var caption = $('caption', dt.table().container()).eq(0); 26392 if ( message === '*' ) { 26393 var side = caption.css( 'caption-side' ); 26394 if ( side !== position ) { 26395 return null; 26396 } 26397 26398 return caption.length ? 26399 caption.text() : 26400 ''; 26401 } 26402 26403 return message; 26404}; 26405 26406 26407 26408 26409 26410 26411 26412var _exportTextarea = $('<textarea/>')[0]; 26413var _exportData = function ( dt, inOpts ) 26414{ 26415 var config = $.extend( true, {}, { 26416 rows: null, 26417 columns: '', 26418 modifier: { 26419 search: 'applied', 26420 order: 'applied' 26421 }, 26422 orthogonal: 'display', 26423 stripHtml: true, 26424 stripNewlines: true, 26425 decodeEntities: true, 26426 trim: true, 26427 format: { 26428 header: function ( d ) { 26429 return strip( d ); 26430 }, 26431 footer: function ( d ) { 26432 return strip( d ); 26433 }, 26434 body: function ( d ) { 26435 return strip( d ); 26436 } 26437 }, 26438 customizeData: null 26439 }, inOpts ); 26440 26441 var strip = function ( str ) { 26442 if ( typeof str !== 'string' ) { 26443 return str; 26444 } 26445 26446 // Always remove script tags 26447 str = str.replace( /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '' ); 26448 26449 // Always remove comments 26450 str = str.replace( /<!\-\-.*?\-\->/g, '' ); 26451 26452 if ( config.stripHtml ) { 26453 str = str.replace( /<[^>]*>/g, '' ); 26454 } 26455 26456 if ( config.trim ) { 26457 str = str.replace( /^\s+|\s+$/g, '' ); 26458 } 26459 26460 if ( config.stripNewlines ) { 26461 str = str.replace( /\n/g, ' ' ); 26462 } 26463 26464 if ( config.decodeEntities ) { 26465 _exportTextarea.innerHTML = str; 26466 str = _exportTextarea.value; 26467 } 26468 26469 return str; 26470 }; 26471 26472 26473 var header = dt.columns( config.columns ).indexes().map( function (idx) { 26474 var el = dt.column( idx ).header(); 26475 return config.format.header( el.innerHTML, idx, el ); 26476 } ).toArray(); 26477 26478 var footer = dt.table().footer() ? 26479 dt.columns( config.columns ).indexes().map( function (idx) { 26480 var el = dt.column( idx ).footer(); 26481 return config.format.footer( el ? el.innerHTML : '', idx, el ); 26482 } ).toArray() : 26483 null; 26484 26485 // If Select is available on this table, and any rows are selected, limit the export 26486 // to the selected rows. If no rows are selected, all rows will be exported. Specify 26487 // a `selected` modifier to control directly. 26488 var modifier = $.extend( {}, config.modifier ); 26489 if ( dt.select && typeof dt.select.info === 'function' && modifier.selected === undefined ) { 26490 if ( dt.rows( config.rows, $.extend( { selected: true }, modifier ) ).any() ) { 26491 $.extend( modifier, { selected: true } ) 26492 } 26493 } 26494 26495 var rowIndexes = dt.rows( config.rows, modifier ).indexes().toArray(); 26496 var selectedCells = dt.cells( rowIndexes, config.columns ); 26497 var cells = selectedCells 26498 .render( config.orthogonal ) 26499 .toArray(); 26500 var cellNodes = selectedCells 26501 .nodes() 26502 .toArray(); 26503 26504 var columns = header.length; 26505 var rows = columns > 0 ? cells.length / columns : 0; 26506 var body = []; 26507 var cellCounter = 0; 26508 26509 for ( var i=0, ien=rows ; i<ien ; i++ ) { 26510 var row = [ columns ]; 26511 26512 for ( var j=0 ; j<columns ; j++ ) { 26513 row[j] = config.format.body( cells[ cellCounter ], i, j, cellNodes[ cellCounter ] ); 26514 cellCounter++; 26515 } 26516 26517 body[i] = row; 26518 } 26519 26520 var data = { 26521 header: header, 26522 footer: footer, 26523 body: body 26524 }; 26525 26526 if ( config.customizeData ) { 26527 config.customizeData( data ); 26528 } 26529 26530 return data; 26531}; 26532 26533 26534/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 26535 * DataTables interface 26536 */ 26537 26538// Attach to DataTables objects for global access 26539$.fn.dataTable.Buttons = Buttons; 26540$.fn.DataTable.Buttons = Buttons; 26541 26542 26543 26544// DataTables creation - check if the buttons have been defined for this table, 26545// they will have been if the `B` option was used in `dom`, otherwise we should 26546// create the buttons instance here so they can be inserted into the document 26547// using the API. Listen for `init` for compatibility with pre 1.10.10, but to 26548// be removed in future. 26549$(document).on( 'init.dt plugin-init.dt', function (e, settings) { 26550 if ( e.namespace !== 'dt' ) { 26551 return; 26552 } 26553 26554 var opts = settings.oInit.buttons || DataTable.defaults.buttons; 26555 26556 if ( opts && ! settings._buttons ) { 26557 new Buttons( settings, opts ).container(); 26558 } 26559} ); 26560 26561// DataTables `dom` feature option 26562DataTable.ext.feature.push( { 26563 fnInit: function( settings ) { 26564 var api = new DataTable.Api( settings ); 26565 var opts = api.init().buttons || DataTable.defaults.buttons; 26566 26567 return new Buttons( api, opts ).container(); 26568 }, 26569 cFeature: "B" 26570} ); 26571 26572 26573return Buttons; 26574})); 26575 26576 26577/*! Bootstrap integration for DataTables' Buttons 26578 * ©2016 SpryMedia Ltd - datatables.net/license 26579 */ 26580 26581(function( factory ){ 26582 if ( typeof define === 'function' && define.amd ) { 26583 // AMD 26584 define( ['jquery', 'datatables.net-bs', 'datatables.net-buttons'], function ( $ ) { 26585 return factory( $, window, document ); 26586 } ); 26587 } 26588 else if ( typeof exports === 'object' ) { 26589 // CommonJS 26590 module.exports = function (root, $) { 26591 if ( ! root ) { 26592 root = window; 26593 } 26594 26595 if ( ! $ || ! $.fn.dataTable ) { 26596 $ = require('datatables.net-bs')(root, $).$; 26597 } 26598 26599 if ( ! $.fn.dataTable.Buttons ) { 26600 require('datatables.net-buttons')(root, $); 26601 } 26602 26603 return factory( $, root, root.document ); 26604 }; 26605 } 26606 else { 26607 // Browser 26608 factory( jQuery, window, document ); 26609 } 26610}(function( $, window, document, undefined ) { 26611'use strict'; 26612var DataTable = $.fn.dataTable; 26613 26614 26615$.extend( true, DataTable.Buttons.defaults, { 26616 dom: { 26617 container: { 26618 className: 'dt-buttons btn-group' 26619 }, 26620 button: { 26621 className: 'btn btn-default' 26622 }, 26623 collection: { 26624 tag: 'ul', 26625 className: 'dt-button-collection dropdown-menu', 26626 button: { 26627 tag: 'li', 26628 className: 'dt-button', 26629 active: 'active', 26630 disabled: 'disabled' 26631 }, 26632 buttonLiner: { 26633 tag: 'a', 26634 className: '' 26635 } 26636 } 26637 } 26638} ); 26639 26640DataTable.ext.buttons.collection.text = function ( dt ) { 26641 return dt.i18n('buttons.collection', 'Collection <span class="caret"/>'); 26642}; 26643 26644 26645return DataTable.Buttons; 26646})); 26647 26648 26649/*! 26650 * Column visibility buttons for Buttons and DataTables. 26651 * 2016 SpryMedia Ltd - datatables.net/license 26652 */ 26653 26654(function( factory ){ 26655 if ( typeof define === 'function' && define.amd ) { 26656 // AMD 26657 define( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) { 26658 return factory( $, window, document ); 26659 } ); 26660 } 26661 else if ( typeof exports === 'object' ) { 26662 // CommonJS 26663 module.exports = function (root, $) { 26664 if ( ! root ) { 26665 root = window; 26666 } 26667 26668 if ( ! $ || ! $.fn.dataTable ) { 26669 $ = require('datatables.net')(root, $).$; 26670 } 26671 26672 if ( ! $.fn.dataTable.Buttons ) { 26673 require('datatables.net-buttons')(root, $); 26674 } 26675 26676 return factory( $, root, root.document ); 26677 }; 26678 } 26679 else { 26680 // Browser 26681 factory( jQuery, window, document ); 26682 } 26683}(function( $, window, document, undefined ) { 26684'use strict'; 26685var DataTable = $.fn.dataTable; 26686 26687 26688$.extend( DataTable.ext.buttons, { 26689 // A collection of column visibility buttons 26690 colvis: function ( dt, conf ) { 26691 return { 26692 extend: 'collection', 26693 text: function ( dt ) { 26694 return dt.i18n( 'buttons.colvis', 'Column visibility' ); 26695 }, 26696 className: 'buttons-colvis', 26697 buttons: [ { 26698 extend: 'columnsToggle', 26699 columns: conf.columns, 26700 columnText: conf.columnText 26701 } ] 26702 }; 26703 }, 26704 26705 // Selected columns with individual buttons - toggle column visibility 26706 columnsToggle: function ( dt, conf ) { 26707 var columns = dt.columns( conf.columns ).indexes().map( function ( idx ) { 26708 return { 26709 extend: 'columnToggle', 26710 columns: idx, 26711 columnText: conf.columnText 26712 }; 26713 } ).toArray(); 26714 26715 return columns; 26716 }, 26717 26718 // Single button to toggle column visibility 26719 columnToggle: function ( dt, conf ) { 26720 return { 26721 extend: 'columnVisibility', 26722 columns: conf.columns, 26723 columnText: conf.columnText 26724 }; 26725 }, 26726 26727 // Selected columns with individual buttons - set column visibility 26728 columnsVisibility: function ( dt, conf ) { 26729 var columns = dt.columns( conf.columns ).indexes().map( function ( idx ) { 26730 return { 26731 extend: 'columnVisibility', 26732 columns: idx, 26733 visibility: conf.visibility, 26734 columnText: conf.columnText 26735 }; 26736 } ).toArray(); 26737 26738 return columns; 26739 }, 26740 26741 // Single button to set column visibility 26742 columnVisibility: { 26743 columns: undefined, // column selector 26744 text: function ( dt, button, conf ) { 26745 return conf._columnText( dt, conf ); 26746 }, 26747 className: 'buttons-columnVisibility', 26748 action: function ( e, dt, button, conf ) { 26749 var col = dt.columns( conf.columns ); 26750 var curr = col.visible(); 26751 26752 col.visible( conf.visibility !== undefined ? 26753 conf.visibility : 26754 ! (curr.length ? curr[0] : false ) 26755 ); 26756 }, 26757 init: function ( dt, button, conf ) { 26758 var that = this; 26759 button.attr( 'data-cv-idx', conf.columns ); 26760 26761 dt 26762 .on( 'column-visibility.dt'+conf.namespace, function (e, settings) { 26763 if ( ! settings.bDestroying && settings.nTable == dt.settings()[0].nTable ) { 26764 that.active( dt.column( conf.columns ).visible() ); 26765 } 26766 } ) 26767 .on( 'column-reorder.dt'+conf.namespace, function (e, settings, details) { 26768 // Don't rename buttons based on column name if the button 26769 // controls more than one column! 26770 if ( dt.columns( conf.columns ).count() !== 1 ) { 26771 return; 26772 } 26773 26774 conf.columns = $.inArray( conf.columns, details.mapping ); 26775 button.attr( 'data-cv-idx', conf.columns ); 26776 26777 // Reorder buttons for new table order 26778 button 26779 .parent() 26780 .children('[data-cv-idx]') 26781 .sort( function (a, b) { 26782 return (a.getAttribute('data-cv-idx')*1) - (b.getAttribute('data-cv-idx')*1); 26783 } ) 26784 .appendTo(button.parent()); 26785 } ); 26786 26787 this.active( dt.column( conf.columns ).visible() ); 26788 }, 26789 destroy: function ( dt, button, conf ) { 26790 dt 26791 .off( 'column-visibility.dt'+conf.namespace ) 26792 .off( 'column-reorder.dt'+conf.namespace ); 26793 }, 26794 26795 _columnText: function ( dt, conf ) { 26796 // Use DataTables' internal data structure until this is presented 26797 // is a public API. The other option is to use 26798 // `$( column(col).node() ).text()` but the node might not have been 26799 // populated when Buttons is constructed. 26800 var idx = dt.column( conf.columns ).index(); 26801 var title = dt.settings()[0].aoColumns[ idx ].sTitle 26802 .replace(/\n/g," ") // remove new lines 26803 .replace(/<br\s*\/?>/gi, " ") // replace line breaks with spaces 26804 .replace(/<select(.*?)<\/select>/g, "") // remove select tags, including options text 26805 .replace(/<!\-\-.*?\-\->/g, "") // strip HTML comments 26806 .replace(/<.*?>/g, "") // strip HTML 26807 .replace(/^\s+|\s+$/g,""); // trim 26808 26809 return conf.columnText ? 26810 conf.columnText( dt, idx, title ) : 26811 title; 26812 } 26813 }, 26814 26815 26816 colvisRestore: { 26817 className: 'buttons-colvisRestore', 26818 26819 text: function ( dt ) { 26820 return dt.i18n( 'buttons.colvisRestore', 'Restore visibility' ); 26821 }, 26822 26823 init: function ( dt, button, conf ) { 26824 conf._visOriginal
26824= dt.columns().indexes().map( function ( idx ) { 26825 return dt.column( idx ).visible(); 26826 } ).toArray(); 26827 }, 26828 26829 action: function ( e, dt, button, conf ) { 26830 dt.columns().every( function ( i ) { 26831 // Take into account that ColReorder might have disrupted our 26832 // indexes 26833 var idx = dt.colReorder && dt.colReorder.transpose ? 26834 dt.colReorder.transpose( i, 'toOriginal' ) : 26835 i; 26836 26837 this.visible( conf._visOriginal[ idx ] ); 26838 } ); 26839 } 26840 }, 26841 26842 26843 colvisGroup: { 26844 className: 'buttons-colvisGroup', 26845 26846 action: function ( e, dt, button, conf ) { 26847 dt.columns( conf.show ).visible( true, false ); 26848 dt.columns( conf.hide ).visible( false, false ); 26849 26850 dt.columns.adjust(); 26851 }, 26852 26853 show: [], 26854 26855 hide: [] 26856 } 26857} ); 26858 26859 26860return DataTable.Buttons; 26861})); 26862 26863 26864/*! 26865 * HTML5 export buttons for Buttons and DataTables. 26866 * 2016 SpryMedia Ltd - datatables.net/license 26867 * 26868 * FileSaver.js (1.3.3) - MIT license 26869 * Copyright © 2016 Eli Grey - http://eligrey.com 26870 */ 26871 26872(function( factory ){ 26873 if ( typeof define === 'function' && define.amd ) { 26874 // AMD 26875 define( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) { 26876 return factory( $, window, document ); 26877 } ); 26878 } 26879 else if ( typeof exports === 'object' ) { 26880 // CommonJS 26881 module.exports = function (root, $, jszip, pdfmake) { 26882 if ( ! root ) { 26883 root = window; 26884 } 26885 26886 if ( ! $ || ! $.fn.dataTable ) { 26887 $ = require('datatables.net')(root, $).$; 26888 } 26889 26890 if ( ! $.fn.dataTable.Buttons ) { 26891 require('datatables.net-buttons')(root, $); 26892 } 26893 26894 return factory( $, root, root.document, jszip, pdfmake ); 26895 }; 26896 } 26897 else { 26898 // Browser 26899 factory( jQuery, window, document ); 26900 } 26901}(function( $, window, document, jszip, pdfmake, undefined ) { 26902'use strict'; 26903var DataTable = $.fn.dataTable; 26904 26905// Allow the constructor to pass in JSZip and PDFMake from external requires. 26906// Otherwise, use globally defined variables, if they are available. 26907function _jsZip () { 26908 return jszip || window.JSZip; 26909} 26910function _pdfMake () { 26911 return pdfmake || window.pdfMake; 26912} 26913 26914DataTable.Buttons.pdfMake = function (_) { 26915 if ( ! _ ) { 26916 return _pdfMake(); 26917 } 26918 pdfmake = m_ake; 26919} 26920 26921DataTable.Buttons.jszip = function (_) { 26922 if ( ! _ ) { 26923 return _jsZip(); 26924 } 26925 jszip = _; 26926} 26927 26928 26929/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 26930 * FileSaver.js dependency 26931 */ 26932 26933/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ 26934 26935var _saveAs = (function(view) { 26936 "use strict"; 26937 // IE <10 is explicitly unsupported 26938 if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) { 26939 return; 26940 } 26941 var 26942 doc = view.document 26943 // only get URL when necessary in case Blob.js hasn't overridden it yet 26944 , get_URL = function() { 26945 return view.URL || view.webkitURL || view; 26946 } 26947 , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") 26948 , can_use_save_link = "download" in save_link 26949 , click = function(node) { 26950 var event = new MouseEvent("click"); 26951 node.dispatchEvent(event); 26952 } 26953 , is_safari = /constructor/i.test(view.HTMLElement) || view.safari 26954 , is_chrome_ios =/CriOS\/[\d]+/.test(navigator.userAgent) 26955 , throw_outside = function(ex) { 26956 (view.setImmediate || view.setTimeout)(function() { 26957 throw ex; 26958 }, 0); 26959 } 26960 , force_saveable_type = "application/octet-stream" 26961 // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to 26962 , arbitrary_revoke_timeout = 1000 * 40 // in ms 26963 , revoke = function(file) { 26964 var revoker = function() { 26965 if (typeof file === "string") { // file is an object URL 26966 get_URL().revokeObjectURL(file); 26967 } else { // file is a File 26968 file.remove(); 26969 } 26970 }; 26971 setTimeout(revoker, arbitrary_revoke_timeout); 26972 } 26973 , dispatch = function(filesaver, event_types, event) { 26974 event_types = [].concat(event_types); 26975 var i = event_types.length; 26976 while (i--) { 26977 var listener = filesaver["on" + event_types[i]]; 26978 if (typeof listener === "function") { 26979 try { 26980 listener.call(filesaver, event || filesaver); 26981 } catch (ex) { 26982 throw_outside(ex); 26983 } 26984 } 26985 } 26986 } 26987 , auto_bom = function(blob) { 26988 // prepend BOM for UTF-8 XML and text/* types (including HTML) 26989 // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF 26990 if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { 26991 return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type}); 26992 } 26993 return blob; 26994 } 26995 , FileSaver = function(blob, name, no_auto_bom) { 26996 if (!no_auto_bom) { 26997 blob = auto_bom(blob); 26998 } 26999 // First try a.download, then web filesystem, then object URLs 27000 var 27001 filesaver = this 27002 , type = blob.type 27003 , force = type === force_saveable_type 27004 , object_url 27005 , dispatch_all = function() { 27006 dispatch(filesaver, "writestart progress write writeend".split(" ")); 27007 } 27008 // on any filesys errors revert to saving with object URLs 27009 , fs_error = function() { 27010 if ((is_chrome_ios || (force && is_safari)) && view.FileReader) { 27011 // Safari doesn't allow downloading of blob urls 27012 var reader = new FileReader(); 27013 reader.onloadend = function() { 27014 var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;'); 27015 var popup = view.open(url, '_blank'); 27016 if(!popup) view.location.href = url; 27017 url=undefined; // release reference before dispatching 27018 filesaver.readyState = filesaver.DONE; 27019 dispatch_all(); 27020 };
27021 reader.readAsDataURL(blob); 27022 filesaver.readyState = filesaver.INIT; 27023 return; 27024 } 27025 // don't create more object URLs than needed 27026 if (!object_url) { 27027 object_url = get_URL().createObjectURL(blob); 27028 } 27029 if (force) { 27030 view.location.href = object_url; 27031 } else { 27032 var opened = view.open(object_url, "_blank"); 27033 if (!opened) { 27034 // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html 27035 view.location.href = object_url; 27036 } 27037 } 27038 filesaver.readyState = filesaver.DONE; 27039 dispatch_all(); 27040 revoke(object_url); 27041 } 27042 ; 27043 filesaver.readyState = filesaver.INIT; 27044 27045 if (can_use_save_link) { 27046 object_url = get_URL().createObjectURL(blob); 27047 setTimeout(function() { 27048 save_link.href = object_url; 27049 save_link.download = name; 27050 click(save_link); 27051 dispatch_all(); 27052 revoke(object_url); 27053 filesaver.readyState = filesaver.DONE; 27054 }); 27055 return; 27056 } 27057 27058 fs_error(); 27059 } 27060 , FS_proto = FileSaver.prototype 27061 , saveAs = function(blob, name, no_auto_bom) { 27062 return new FileSaver(blob, name || blob.name || "download", no_auto_bom); 27063 } 27064 ; 27065 // IE 10+ (native saveAs) 27066 if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) { 27067 return function(blob, name, no_auto_bom) { 27068 name = name || blob.name || "download"; 27069 27070 if (!no_auto_bom) { 27071 blob = auto_bom(blob); 27072 } 27073 return navigator.msSaveOrOpenBlob(blob, name); 27074 }; 27075 } 27076 27077 FS_proto.abort = function(){}; 27078 FS_proto.readyState = FS_proto.INIT = 0; 27079 FS_proto.WRITING = 1; 27080 FS_proto.DONE = 2; 27081 27082 FS_proto.error = 27083 FS_proto.onwritestart = 27084 FS_proto.onprogress = 27085 FS_proto.onwrite = 27086 FS_proto.onabort = 27087 FS_proto.onerror = 27088 FS_proto.onwriteend = 27089 null; 27090 27091 return saveAs; 27092}( 27093 typeof self !== "undefined" && self 27094 || typeof window !== "undefined" && window 27095 || this.content 27096)); 27097 27098 27099// Expose file saver on the DataTables API. Can't attach to `DataTables.Buttons` 27100// since this file can be loaded before Button's core! 27101DataTable.fileSave = _saveAs; 27102 27103 27104/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 27105 * Local (private) functions 27106 */ 27107 27108/** 27109 * Get the sheet name for Excel exports. 27110 * 27111 * @param {object} config Button configuration 27112 */ 27113var _sheetname = function ( config ) 27114{ 27115 var sheetName = 'Sheet1'; 27116 27117 if ( config.sheetName ) { 27118 sheetName = config.sheetName.replace(/[\[\]\*\/\\\?\:]/g, ''); 27119 } 27120 27121 return sheetName; 27122}; 27123 27124/** 27125 * Get the newline character(s) 27126 * 27127 * @param {object} config Button configuration 27128 * @return {string} Newline character 27129 */ 27130var _newLine = function ( config ) 27131{ 27132 return config.newline ? 27133 config.newline : 27134 navigator.userAgent.match(/Windows/) ? 27135 '\r\n' : 27136 '\n'; 27137}; 27138 27139/** 27140 * Combine the data from the `buttons.exportData` method into a string that 27141 * will be used in the export file. 27142 * 27143 * @param {DataTable.Api} dt DataTables API instance 27144 * @param {object} config Button configuration 27145 * @return {object} The data to export 27146 */ 27147var _exportData = function ( dt, config ) 27148{ 27149 var newLine = _newLine( config ); 27150 var data = dt.buttons.exportData( config.exportOptions ); 27151 var boundary = config.fieldBoundary; 27152 var separator = config.fieldSeparator; 27153 var reBoundary = new RegExp( boundary, 'g' ); 27154 var escapeChar = config.escapeChar !== undefined ? 27155 config.escapeChar : 27156 '\\'; 27157 var join = function ( a ) { 27158 var s = ''; 27159 27160 // If there is a field boundary, then we might need to escape it in 27161 // the source data 27162 for ( var i=0, ien=a.length ; i<ien ; i++ ) { 27163 if ( i > 0 ) { 27164 s += separator; 27165 } 27166 27167 s += boundary ? 27168 boundary + ('' + a[i]).replace( reBoundary, escapeChar+boundary ) + boundary : 27169 a[i]; 27170 } 27171 27172 return s; 27173 }; 27174 27175 var header = config.header ? join( data.header )+newLine : ''; 27176 var footer = config.footer && data.footer ? newLine+join( data.footer ) : ''; 27177 var body = []; 27178 27179 for ( var i=0, ien=data.body.length ; i<ien ; i++ ) { 27180 body.push( join( data.body[i] ) ); 27181 } 27182 27183 return { 27184 str: header + body.join( newLine ) + footer, 27185 rows: body.length 27186 }; 27187}; 27188 27189/** 27190 * Older versions of Safari (prior to tech preview 18) don't support the 27191 * download option required. 27192 * 27193 * @return {Boolean} `true` if old Safari 27194 */ 27195var _isDuffSafari = function () 27196{ 27197 var safari = navigator.userAgent.indexOf('Safari') !== -1 && 27198 navigator.userAgent.indexOf('Chrome') === -1 && 27199 navigator.userAgent.indexOf('Opera') === -1; 27200 27201 if ( ! safari ) { 27202 return false;
27203 } 27204 27205 var version = navigator.userAgent.match( /AppleWebKit\/(\d+\.\d+)/ ); 27206 if ( version && version.length > 1 && version[1]*1 < 603.1 ) { 27207 return true; 27208 } 27209 27210 return false; 27211}; 27212 27213/** 27214 * Convert from numeric position to letter for column names in Excel 27215 * @param {int} n Column number 27216 * @return {string} Column letter(s) name 27217 */ 27218function createCellPos( n ){ 27219 var ordA = 'A'.charCodeAt(0); 27220 var ordZ = 'Z'.charCodeAt(0); 27221 var len = ordZ - ordA + 1; 27222 var s = ""; 27223 27224 while( n >= 0 ) { 27225 s = String.fromCharCode(n % len + ordA) + s; 27226 n = Math.floor(n / len) - 1; 27227 } 27228 27229 return s; 27230} 27231 27232try { 27233 var _serialiser = new XMLSerializer(); 27234 var _ieExcel; 27235} 27236catch (t) {} 27237 27238/** 27239 * Recursively add XML files from an object's structure to a ZIP file. This 27240 * allows the XSLX file to be easily defined with an object's structure matching 27241 * the files structure. 27242 * 27243 * @param {JSZip} zip ZIP package 27244 * @param {object} obj Object to add (recursive) 27245 */ 27246function _addToZip( zip, obj ) { 27247 if ( _ieExcel === undefined ) { 27248 // Detect if we are dealing with IE's _awful_ serialiser by seeing if it 27249 // drop attributes 27250 _ieExcel = _serialiser 27251 .serializeToString( 27252 $.parseXML( excelStrings['xl/worksheets/sheet1.xml'] ) 27253 ) 27254 .indexOf( 'xmlns:r' ) === -1; 27255 } 27256 27257 $.each( obj, function ( name, val ) { 27258 if ( $.isPlainObject( val ) ) { 27259 var newDir = zip.folder( name ); 27260 _addToZip( newDir, val ); 27261 } 27262 else { 27263 if ( _ieExcel ) { 27264 // IE's XML serialiser will drop some name space attributes from 27265 // from the root node, so we need to save them. Do this by 27266 // replacing the namespace nodes with a regular attribute that 27267 // we convert back when serialised. Edge does not have this 27268 // issue 27269 var worksheet = val.childNodes[0]; 27270 var i, ien; 27271 var attrs = []; 27272 27273 for ( i=worksheet.attributes.length-1 ; i>=0 ; i-- ) { 27274 var attrName = worksheet.attributes[i].nodeName; 27275 var attrValue = worksheet.attributes[i].nodeValue; 27276 27277 if ( attrName.indexOf( ':' ) !== -1 ) { 27278 attrs.push( { name: attrName, value: attrValue } ); 27279 27280 worksheet.removeAttribute( attrName ); 27281 } 27282 } 27283 27284 for ( i=0, ien=attrs.length ; i<ien ; i++ ) { 27285 var attr = val.createAttribute( attrs[i].name.replace( ':', '_dt_b_namespace_token_' ) ); 27286 attr.value = attrs[i].value; 27287 worksheet.setAttributeNode( attr ); 27288 } 27289 } 27290 27291 var str = _serialiser.serializeToString(val); 27292 27293 // Fix IE's XML 27294 if ( _ieExcel ) { 27295 // IE doesn't include the XML declaration 27296 if ( str.indexOf( '<?xml' ) === -1 ) { 27297 str = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+str; 27298 } 27299 27300 // Return namespace attributes to being as such 27301 str = str.replace( /_dt_b_namespace_token_/g, ':' ); 27302 27303 // Remove testing name space that IE puts into the space preserve attr 27304 str = str.replace( /xmlns:NS[\d]+="" NS[\d]+:/g, '' ); 27305 } 27306 27307 // Safari, IE and Edge will put empty name space attributes onto 27308 // various elements making them useless. This strips them out 27309 str = str.replace( /<([^<>]*?) xmlns=""([^<>]*?)>/g, '<$1 $2>' ); 27310 27311 zip.file( name, str ); 27312 } 27313 } ); 27314} 27315 27316/** 27317 * Create an XML node and add any children, attributes, etc without needing to 27318 * be verbose in the DOM. 27319 * 27320 * @param {object} doc XML document 27321 * @param {string} nodeName Node name 27322 * @param {object} opts Options - can be `attr` (attributes), `children` 27323 * (child nodes) and `text` (text content) 27324 * @return {node} Created node 27325 */ 27326function _createNode( doc, nodeName, opts ) { 27327 var tempNode = doc.createElement( nodeName ); 27328 27329 if ( opts ) { 27330 if ( opts.attr ) { 27331 $(tempNode).attr( opts.attr ); 27332 } 27333 27334 if ( opts.children ) { 27335 $.each( opts.children, function ( key, value ) { 27336 tempNode.appendChild( value ); 27337 } ); 27338 } 27339 27340 if ( opts.text !== null && opts.text !== undefined ) { 27341 tempNode.appendChild( doc.createTextNode( opts.text ) ); 27342 } 27343 } 27344 27345 return tempNode; 27346} 27347 27348/** 27349 * Get the width for an Excel column based on the contents of that column 27350 * @param {object} data Data for export 27351 * @param {int} col Column index 27352 * @return {int} Column width 27353 */ 27354function _excelColWidth( data, col ) { 27355 var max = data.header[col].length; 27356 var len, lineSplit, str; 27357 27358 if ( data.footer && data.footer[col].length > max ) { 27359 max = data.footer[col].length; 27360 } 27361 27362 for ( var i=0, ien=data.body.length ; i<ien ; i++ ) { 27363 var point = data.body[i][col]; 27364 str = point !== null && point !== undefined ? 27365 point.toString() : 27366 ''; 27367 27368 // If there is a newline character, workout the width of the column 27369 // based on the longest line in the string 27370 if ( str.indexOf('\n') !== -1 ) { 27371 lineSplit = str.split('\n'); 27372 lineSplit.sort( function (a, b) { 27373 return b.length - a.length; 27374 } ); 27375 27376 len = lineSplit[0].length; 27377 } 27378 else { 27379 len = str.length; 27380 } 27381 27382 if ( len > max ) { 27383 max = len; 27384 } 27385 27386 // Max width rather than having potentially massive column widths 27387 if ( max > 40 ) { 27388 return 54; // 40 * 1.35 27389 } 27390 } 27391 27392 max *= 1.35; 27393 27394 // And a min width 27395 return max > 6 ? max : 6; 27396} 27397 27398// Excel - Pre-defined strings to build a basic XLSX file 27399var excelStrings = { 27400 "_rels/.rels": 27401 '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+ 27402 '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'+ 27403 '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>'+ 27404 '</Relationships>', 27405 27406 "xl/_rels/workbook.xml.rels": 27407 '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+ 27408 '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'+ 27409 '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>'+ 27410 '<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>'+ 27411 '</Relationships>', 27412 27413 "[Content_Types].xml": 27414 '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+ 27415 '<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">'+ 27416 '<Default Extension="xml" ContentType="application/xml" />'+ 27417 '<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml" />'+ 27418 '<Default Extension="jpeg" ContentType="image/jpeg" />'+
27419 '<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" />'+ 27420 '<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" />'+ 27421 '<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml" />'+ 27422 '</Types>', 27423 27424 "xl/workbook.xml": 27425 '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+ 27426 '<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">'+ 27427 '<fileVersion appName="xl" lastEdited="5" lowestEdited="5" rupBuild="24816"/>'+ 27428 '<workbookPr showInkAnnotation="0" autoCompressPictures="0"/>'+ 27429 '<bookViews>'+ 27430 '<workbookView xWindow="0" yWindow="0" windowWidth="25600" windowHeight="19020" tabRatio="500"/>'+ 27431 '</bookViews>'+ 27432 '<sheets>'+ 27433 '<sheet name="Sheet1" sheetId="1" r:id="rId1"/>'+ 27434 '</sheets>'+ 27435 '<definedNames/>'+ 27436 '</workbook>', 27437 27438 "xl/worksheets/sheet1.xml": 27439 '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+ 27440 '<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">'+ 27441 '<sheetData/>'+ 27442 '<mergeCells count="0"/>'+ 27443 '</worksheet>', 27444 27445 "xl/styles.xml": 27446 '<?xml version="1.0" encoding="UTF-8"?>'+ 27447 '<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">'+ 27448 '<numFmts count="6">'+ 27449 '<numFmt numFmtId="164" formatCode="#,##0.00_-\ [$$-45C]"/>'+ 27450 '<numFmt numFmtId="165" formatCode=""£"#,##0.00"/>'+ 27451 '<numFmt numFmtId="166" formatCode="[$â¬-2]\ #,##0.00"/>'+ 27452 '<numFmt numFmtId="167" formatCode="0.0%"/>'+ 27453 '<numFmt numFmtId="168" formatCode="#,##0;(#,##0)"/>'+ 27454 '<numFmt numFmtId="169" formatCode="#,##0.00;(#,##0.00)"/>'+ 27455 '</numFmts>'+ 27456 '<fonts count="5" x14ac:knownFonts="1">'+ 27457 '<font>'+ 27458 '<sz val="11" />'+ 27459 '<name val="Calibri" />'+ 27460 '</font>'+ 27461 '<font>'+ 27462 '<sz val="11" />'+ 27463 '<name val="Calibri" />'+ 27464 '<color rgb="FFFFFFFF" />'+ 27465 '</font>'+ 27466 '<font>'+ 27467 '<sz val="11" />'+ 27468 '<name val="Calibri" />'+ 27469 '<b />'+ 27470 '</font>'+ 27471 '<font>'+ 27472 '<sz val="11" />'+ 27473 '<name val="Calibri" />'+ 27474 '<i />'+ 27475 '</font>'+ 27476 '<font>'+ 27477 '<sz val="11" />'+ 27478 '<name val="Calibri" />'+ 27479 '<u />'+ 27480 '</font>'+ 27481 '</fonts>'+ 27482 '<fills count="6">'+ 27483 '<fill>'+ 27484 '<patternFill patternType="none" />'+ 27485 '</fill>'+ 27486 '<fill>'+ // Excel appears to use this as a dotted background regardless of values but 27487 '<patternFill patternType="none" />'+ // to be valid to the schema, use a patternFill 27488 '</fill>'+ 27489 '<fill>'+ 27490 '<patternFill patternType="solid">'+ 27491 '<fgColor rgb="FFD9D9D9" />'+ 27492 '<bgColor indexed="64" />'+ 27493 '</patternFill>'+ 27494 '</fill>'+ 27495 '<fill>'+ 27496 '<patternFill patternType="solid">'+ 27497 '<fgColor rgb="FFD99795" />'+ 27498 '<bgColor indexed="64" />'+ 27499 '</patternFill>'+ 27500 '</fill>'+ 27501 '<fill>'+ 27502 '<patternFill patternType="solid">'+ 27503 '<fgColor rgb="ffc6efce" />'+ 27504 '<bgColor indexed="64" />'+ 27505 '</patternFill>'+ 27506 '</fill>'+ 27507 '<fill>'+ 27508 '<patternFill patternType="solid">'+ 27509 '<fgColor rgb="ffc6cfef" />'+ 27510 '<bgColor indexed="64" />'+ 27511 '</patternFill>'+ 27512 '</fill>'+ 27513 '</fills>'+ 27514 '<borders count="2">'+ 27515 '<border>'+ 27516 '<left />'+ 27517 '<right />'+ 27518 '<top />'+ 27519 '<bottom />'+ 27520 '<diagonal />'+ 27521 '</border>'+ 27522 '<border diagonalUp="false" diagonalDown="false">'+ 27523 '<left style="thin">'+ 27524 '<color auto="1" />'+ 27525 '</left>'+ 27526 '<right style="thin">'+ 27527 '<color auto="1" />'+ 27528 '</right>'+ 27529 '<top style="thin">'+ 27530 '<color auto="1" />'+ 27531 '</top>'+ 27532 '<bottom style="thin">'+ 27533 '<color auto="1" />'+ 27534 '</bottom>'+ 27535 '<diagonal />'+ 27536 '</border>'+ 27537 '</borders>'+ 27538 '<cellStyleXfs count="1">'+ 27539 '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" />'+ 27540 '</cellStyleXfs>'+ 27541 '<cellXfs count="67">'+ 27542 '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27543 '<xf numFmtId="0" fontId="1" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27544 '<xf numFmtId="0" fontId="2" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27545 '<xf numFmtId="0" fontId="3" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27546 '<xf numFmtId="0" fontId="4" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27547 '<xf numFmtId="0" fontId="0" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27548 '<xf numFmtId="0" fontId="1" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27549 '<xf numFmtId="0" fontId="2" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27550 '<xf numFmtId="0" fontId="3" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27551 '<xf numFmtId="0" fontId="4" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27552 '<xf numFmtId="0" fontId="0" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27553 '<xf numFmtId="0" fontId="1" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27554 '<xf numFmtId="0" fontId="2" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27555 '<xf numFmtId="0" fontId="3" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27556 '<xf numFmtId="0" fontId="4" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27557 '<xf numFmtId="0" fontId="0" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27558 '<xf numFmtId="0" fontId="1" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27559 '<xf numFmtId="0" fontId="2" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27560 '<xf numFmtId="0" fontId="3" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27561 '<xf numFmtId="0" fontId="4" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27562 '<xf numFmtId="0" fontId="0" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27563 '<xf numFmtId="0" fontId="1" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27564 '<xf numFmtId="0" fontId="2" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27565 '<xf numFmtId="0" fontId="3" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27566 '<xf numFmtId="0" fontId="4" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27567 '<xf numFmtId="0" fontId="0" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27568 '<xf numFmtId="0" fontId="1" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27569 '<xf numFmtId="0" fontId="2" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27570 '<xf numFmtId="0" fontId="3" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27571 '<xf numFmtId="0" fontId="4" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27572 '<xf numFmtId="0" fontId="0" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27573 '<xf numFmtId="0" fontId="1" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27574 '<xf numFmtId="0" fontId="2" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27575 '<xf numFmtId="0" fontId="3" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27576 '<xf numFmtId="0" fontId="4" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27577 '<xf numFmtId="0" fontId="0" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27578 '<xf numFmtId="0" fontId="1" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27579 '<xf numFmtId="0" fontId="2" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27580 '<xf numFmtId="0" fontId="3" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27581 '<xf numFmtId="0" fontId="4" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27582 '<xf numFmtId="0" fontId="0" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27583 '<xf numFmtId="0" fontId="1" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27584 '<xf numFmtId="0" fontId="2" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27585 '<xf numFmtId="0" fontId="3" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27586 '<xf numFmtId="0" fontId="4" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27587 '<xf numFmtId="0" fontId="0" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27588 '<xf numFmtId="0" fontId="1" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27589 '<xf numFmtId="0" fontId="2" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27590 '<xf numFmtId="0" fontId="3" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27591 '<xf numFmtId="0" fontId="4" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+ 27592 '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+ 27593 '<alignment horizontal="left"/>'+ 27594 '</xf>'+ 27595 '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+ 27596 '<alignment horizontal="center"/>'+ 27597 '</xf>'+ 27598 '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+ 27599 '<alignment horizontal="right"/>'+ 27600 '</xf>'+ 27601 '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+ 27602 '<alignment horizontal="fill"/>'+ 27603 '</xf>'+ 27604 '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+ 27605 '<alignment textRotation="90"/>'+ 27606 '</xf>'+ 27607 '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+ 27608 '<alignment wrapText="1"/>'+ 27609 '</xf>'+ 27610 '<xf numFmtId="9" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+ 27611 '<xf numFmtId="164" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+ 27612 '<xf numFmtId="165" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+ 27613 '<xf numFmtId="166" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+ 27614 '<xf numFmtId="167" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+ 27615 '<xf numFmtId="168" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+ 27616 '<xf numFmtId="169" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+ 27617 '<xf numFmtId="3" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+ 27618 '<xf numFmtId="4" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+ 27619 '<xf numFmtId="1" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+ 27620 '<xf numFmtId="2" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+ 27621 '</cellXfs>'+ 27622 '<cellStyles count="1">'+ 27623 '<cellStyle name="Normal" xfId="0" builtinId="0" />'+ 27624 '</cellStyles>'+ 27625 '<dxfs count="0" />'+ 27626 '<tableStyles count="0" defaultTableStyle="TableStyleMedium9" defaultPivotStyle="PivotStyleMedium4" />'+ 27627 '</styleSheet>' 27628}; 27629// Note we could use 3 `for` loops for the styles, but when gzipped there is
27630// virtually no difference in size, since the above can be easily compressed 27631 27632// Pattern matching for special number formats. Perhaps this should be exposed 27633// via an API in future? 27634// Ref: section 3.8.30 - built in formatters in open spreadsheet 27635// https://www.ecma-international.org/news/TC45_current_work/Office%20Open%20XML%20Part%204%20-%20Markup%20Language%20Reference.pdf 27636var _excelSpecials = [ 27637 { match: /^\-?\d+\.\d%$/, style: 60, fmt: function (d) { return d/100; } }, // Precent with d.p. 27638 { match: /^\-?\d+\.?\d*%$/, style: 56, fmt: function (d) { return d/100; } }, // Percent 27639 { match: /^\-?\$[\d,]+.?\d*$/, style: 57 }, // Dollars 27640 { match: /^\-?£[\d,]+.?\d*$/, style: 58 }, // Pounds 27641 { match: /^\-?â¬[\d,]+.?\d*$/, style: 59 }, // Euros 27642 { match: /^\-?\d+$/, style: 65 }, // Numbers without thousand separators 27643 { match: /^\-?\d+\.\d{2}$/, style: 66 }, // Numbers 2 d.p. without thousands separators 27644 { match: /^\([\d,]+\)$/, style: 61, fmt: function (d) { return -1 * d.replace(/[\(\)]/g, ''); } }, // Negative numbers indicated by brackets 27645 { match: /^\([\d,]+\.\d{2}\)$/, style: 62, fmt: function (d) { return -1 * d.replace(/[\(\)]/g, ''); } }, // Negative numbers indicated by brackets - 2d.p. 27646 { match: /^\-?[\d,]+$/, style: 63 }, // Numbers with thousand separators 27647 { match: /^\-?[\d,]+\.\d{2}$/, style: 64 } // Numbers with 2 d.p. and thousands separators 27648]; 27649 27650 27651 27652/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 27653 * Buttons 27654 */ 27655 27656// 27657// Copy to clipboard 27658// 27659DataTable.ext.buttons.copyHtml5 = { 27660 className: 'buttons-copy buttons-html5', 27661 27662 text: function ( dt ) { 27663 return dt.i18n( 'buttons.copy', 'Copy' ); 27664 }, 27665 27666 action: function ( e, dt, button, config ) { 27667 this.processing( true ); 27668 27669 var that = this; 27670 var exportData = _exportData( dt, config ); 27671 var info = dt.buttons.exportInfo( config ); 27672 var newline = _newLine(config); 27673 var output = exportData.str; 27674 var hiddenDiv = $('<div/>') 27675 .css( { 27676 height: 1, 27677 width: 1, 27678 overflow: 'hidden', 27679 position: 'fixed', 27680 top: 0, 27681 left: 0 27682 } ); 27683 27684 if ( info.title ) { 27685 output = info.title + newline + newline + output; 27686 } 27687 27688 if ( info.messageTop ) { 27689 output = info.messageTop + newline + newline + output; 27690 } 27691 27692 if ( info.messageBottom ) { 27693 output = output + newline + newline + info.messageBottom; 27694 } 27695 27696 if ( config.customize ) { 27697 output = config.customize( output, config, dt ); 27698 } 27699 27700 var textarea = $('<textarea readonly/>') 27701 .val( output ) 27702 .appendTo( hiddenDiv ); 27703 27704 // For browsers that support the copy execCommand, try to use it 27705 if ( document.queryCommandSupported('copy') ) { 27706 hiddenDiv.appendTo( dt.table().container() ); 27707 textarea[0].focus(); 27708 textarea[0].select(); 27709 27710 try { 27711 var successful = document.execCommand( 'copy' ); 27712 hiddenDiv.remove(); 27713 27714 if (successful) { 27715 dt.buttons.info( 27716 dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ), 27717 dt.i18n( 'buttons.copySuccess', { 27718 1: 'Copied one row to clipboard', 27719 _: 'Copied %d rows to clipboard' 27720 }, exportData.rows ), 27721 2000 27722 ); 27723 27724 this.processing( false ); 27725 return; 27726 } 27727 } 27728 catch (t) {} 27729 } 27730 27731 // Otherwise we show the text box and instruct the user to use it 27732 var message = $('<span>'+dt.i18n( 'buttons.copyKeys', 27733 'Press <i>ctrl</i> or <i>\u2318</i> + <i>C</i> to copy the table data<br>to your system clipboard.<br><br>'+ 27734 'To cancel, click this message or press escape.' )+'</span>' 27735 ) 27736 .append( hiddenDiv ); 27737 27738 dt.buttons.info( dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ), message, 0 ); 27739 27740 // Select the text so when the user activates their system clipboard 27741 // it will copy that text 27742 textarea[0].focus(); 27743 textarea[0].select(); 27744 27745 // Event to hide the message when the user is done 27746 var container = $(message).closest('.dt-button-info'); 27747 var close = function () { 27748 container.off( 'click.buttons-copy' ); 27749 $(document).off( '.buttons-copy' ); 27750 dt.buttons.info( false ); 27751 }; 27752 27753 container.on( 'click.buttons-copy', close ); 27754 $(document) 27755 .on( 'keydown.buttons-copy', function (e) { 27756 if ( e.keyCode === 27 ) { // esc 27757 close(); 27758 that.processing( false ); 27759 } 27760 } ) 27761 .on( 'copy.buttons-copy cut.buttons-copy', function () { 27762 close(); 27763 that.processing( false ); 27764 } ); 27765 }, 27766 27767 exportOptions: {}, 27768 27769 fieldSeparator: '\t', 27770 27771 fieldBoundary: '', 27772 27773 header: true, 27774
27775 footer: false, 27776 27777 title: '*', 27778 27779 messageTop: '*', 27780 27781 messageBottom: '*' 27782}; 27783 27784// 27785// CSV export 27786// 27787DataTable.ext.buttons.csvHtml5 = { 27788 bom: false, 27789 27790 className: 'buttons-csv buttons-html5', 27791 27792 available: function () { 27793 return window.FileReader !== undefined && window.Blob; 27794 }, 27795 27796 text: function ( dt ) { 27797 return dt.i18n( 'buttons.csv', 'CSV' ); 27798 }, 27799 27800 action: function ( e, dt, button, config ) { 27801 this.processing( true ); 27802 27803 // Set the text 27804 var output = _exportData( dt, config ).str; 27805 var info = dt.buttons.exportInfo(config); 27806 var charset = config.charset; 27807 27808 if ( config.customize ) { 27809 output = config.customize( output, config, dt ); 27810 } 27811 27812 if ( charset !== false ) { 27813 if ( ! charset ) { 27814 charset = document.characterSet || document.charset; 27815 } 27816 27817 if ( charset ) { 27818 charset = ';charset='+charset; 27819 } 27820 } 27821 else { 27822 charset = ''; 27823 } 27824 27825 if ( config.bom ) { 27826 output = '\ufeff' + output; 27827 } 27828 27829 _saveAs( 27830 new Blob( [output], {type: 'text/csv'+charset} ), 27831 info.filename, 27832 true 27833 ); 27834 27835 this.processing( false ); 27836 }, 27837 27838 filename: '*', 27839 27840 extension: '.csv', 27841 27842 exportOptions: {}, 27843 27844 fieldSeparator: ',', 27845 27846 fieldBoundary: '"', 27847 27848 escapeChar: '"', 27849 27850 charset: null, 27851 27852 header: true, 27853 27854 footer: false 27855}; 27856 27857// 27858// Excel (xlsx) export 27859// 27860DataTable.ext.buttons.excelHtml5 = { 27861 className: 'buttons-excel buttons-html5', 27862 27863 available: function () { 27864 return window.FileReader !== undefined && _jsZip() !== undefined && ! _isDuffSafari() && _serialiser; 27865 }, 27866 27867 text: function ( dt ) { 27868 return dt.i18n( 'buttons.excel', 'Excel' ); 27869 }, 27870 27871 action: function ( e, dt, button, config ) { 27872 this.processing( true ); 27873 27874 var that = this; 27875 var rowPos = 0; 27876 var dataStartRow, dataEndRow; 27877 var getXml = function ( type ) { 27878 var str = excelStrings[ type ]; 27879 27880 //str = str.replace( /xmlns:/g, 'xmlns_' ).replace( /mc:/g, 'mc_' ); 27881 27882 return $.parseXML( str ); 27883 }; 27884 var rels = getXml('xl/worksheets/sheet1.xml'); 27885 var relsGet = rels.getElementsByTagName( "sheetData" )[0]; 27886 27887 var xlsx = { 27888 _rels: { 27889 ".rels": getXml('_rels/.rels') 27890 }, 27891 xl: { 27892 _rels: { 27893 "workbook.xml.rels": getXml('xl/_rels/workbook.xml.rels') 27894 }, 27895 "workbook.xml": getXml('xl/workbook.xml'), 27896 "styles.xml": getXml('xl/styles.xml'), 27897 "worksheets": { 27898 "sheet1.xml": rels 27899 } 27900 27901 }, 27902 "[Content_Types].xml": getXml('[Content_Types].xml') 27903 }; 27904 27905 var data = dt.buttons.exportData( config.exportOptions ); 27906 var currentRow, rowNode; 27907 var addRow = function ( row ) { 27908 currentRow = rowPos+1; 27909 rowNode = _createNode( rels, "row", { attr: {r:currentRow} } ); 27910 27911 for ( var i=0, ien=row.length ; i<ien ; i++ ) { 27912 // Concat both the Cell Columns as a letter and the Row of the cell. 27913 var cellId = createCellPos(i) + '' + currentRow; 27914 var cell = null; 27915 27916 // For null, undefined of blank cell, continue so it doesn't create the _createNode 27917 if ( row[i] === null || row[i] === undefined || row[i] === '' ) { 27918 if ( config.createEmptyCells === true ) { 27919 row[i] = ''; 27920 } 27921 else { 27922 continue; 27923 } 27924 } 27925 27926 var originalContent = row[i]; 27927 row[i] = $.trim( row[i] ); 27928 27929 // Special number formatting options 27930 for ( var j=0, jen=_excelSpecials.length ; j<jen ; j++ ) { 27931 var special = _excelSpecials[j]; 27932 27933 // TODO Need to provide the ability for the specials to say 27934 // if they are returning a string, since at the moment it is 27935 // assumed to be a number 27936 if ( row[i].match && ! row[i].match(/^0\d+/) && row[i].match( special.match ) ) { 27937 var val = row[i].replace(/[^\d\.\-]/g, ''); 27938 27939 if ( special.fmt ) { 27940 val = special.fmt( val ); 27941 } 27942 27943 cell = _createNode( rels, 'c', { 27944 attr: { 27945 r: cellId, 27946 s: special.style 27947 }, 27948 children: [ 27949 _createNode( rels, 'v', { text: val } ) 27950 ] 27951 } ); 27952 27953 break; 27954 } 27955 } 27956 27957 if ( ! cell ) { 27958 if ( typeof row[i] === 'number' || ( 27959 row[i].match && 27960 row[i].match(/^-?\d+(\.\d+)?$/) && 27961 ! row[i].match(/^0\d+/) ) 27962 ) { 27963 // Detect numbers - don't match numbers with leading zeros 27964 // or a negative anywhere but the start 27965 cell = _createNode( rels, 'c', { 27966 attr: { 27967 t: 'n', 27968 r: cellId 27969 }, 27970 children: [ 27971 _createNode( rels, 'v', { text: row[i] } ) 27972 ] 27973 } ); 27974 } 27975 else { 27976 // String output - replace non standard characters for text output 27977 var text = ! originalContent.replace ? 27978 originalContent : 27979 originalContent.replace(/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, ''); 27980 27981 cell = _createNode( rels, 'c', { 27982 attr: { 27983 t: 'inlineStr', 27984 r: cellId 27985 }, 27986 children:{ 27987 row: _createNode( rels, 'is', { 27988 children: { 27989 row: _createNode( rels, 't', { 27990 text: text, 27991 attr: { 27992 'xml:space': 'preserve' 27993 } 27994 } ) 27995 } 27996 } ) 27997 } 27998 } ); 27999 } 28000 } 28001 28002 rowNode.appendChild( cell ); 28003 } 28004 28005 relsGet.appendChild(rowNode); 28006 rowPos++; 28007 }; 28008 28009 if ( config.customizeData ) { 28010 config.customizeData( data ); 28011 } 28012 28013 var mergeCells = function ( row, colspan ) { 28014 var mergeCells = $('mergeCells', rels); 28015 28016 mergeCells[0].appendChild( _createNode( rels, 'mergeCell', { 28017 attr: { 28018 ref: 'A'+row+':'+createCellPos(colspan)+row 28019 } 28020 } ) ); 28021 mergeCells.attr( 'count', parseFloat(mergeCells.attr( 'count' ))+1 ); 28022 $('row:eq('+(row-1)+') c', rels).attr( 's', '51' ); // centre 28023 }; 28024 28025 // Title and top messages 28026 var exportInfo = dt.buttons.exportInfo( config ); 28027 if ( exportInfo.title ) { 28028 addRow( [exportInfo.title], rowPos ); 28029 mergeCells( rowPos, data.header.length-1 ); 28030 } 28031 28032 if ( exportInfo.messageTop ) { 28033 addRow( [exportInfo.messageTop], rowPos ); 28034 mergeCells( rowPos, data.header.length-1 ); 28035 } 28036 28037 28038 // Table itself 28039 if ( config.header ) { 28040 addRow( data.header, rowPos ); 28041 $('row:last c', rels).attr( 's', '2' ); // bold 28042 } 28043 28044 dataStartRow = rowPos; 28045 28046 for ( var n=0, ie=data.body.length ; n<ie ; n++ ) { 28047 addRow( data.body[n], rowPos ); 28048 } 28049 28050 dataEndRow = rowPos; 28051 28052 if ( config.footer && data.footer ) { 28053 addRow( data.footer, rowPos); 28054 $('row:last c', rels).attr( 's', '2' ); // bold 28055 } 28056 28057 // Below the table 28058 if ( exportInfo.messageBottom ) { 28059 addRow( [exportInfo.messageBottom], rowPos ); 28060 mergeCells( rowPos, data.header.length-1 ); 28061 } 28062 28063 // Set column widths 28064 var cols = _createNode( rels, 'cols' ); 28065 $('worksheet', rels).prepend( cols ); 28066 28067 for ( var i=0, ien=data.header.length ; i<ien ; i++ ) { 28068 cols.appendChild( _createNode( rels, 'col', { 28069 attr: { 28070 min: i+1, 28071 max: i+1, 28072 width: _excelColWidth( data, i ), 28073 customWidth: 1 28074 } 28075 } ) ); 28076 } 28077 28078 // Auto filter for columns 28079 $('mergeCells', rels).before( _createNode( rels, 'autoFilter', { 28080 attr: { 28081 ref: 'A'+dataStartRow+':'+createCellPos(data.header.length-1)+dataEndRow 28082 } 28083 } ) ); 28084 28085 // Workbook modifications 28086 var workbook = xlsx.xl['workbook.xml']; 28087 28088 $( 'sheets sheet', workbook ).attr( 'name', _sheetname( config ) ); 28089 28090 if ( config.autoFilter ) { 28091 $('definedNames', workbook).append( _createNode( workbook, 'definedName', { 28092 attr: { 28093 name: '_xlnm._FilterDatabase', 28094 localSheetId: '0', 28095 hidden: 1 28096 }, 28097 text: _sheetname(config)+'!$A$'+dataStartRow+':'+createCellPos(data.header.length-1)+dataEndRow 28098 } ) ); 28099 } 28100 28101 // Let the developer customise the document if they want to 28102 if ( config.customize ) { 28103 config.customize( xlsx, config, dt ); 28104 } 28105 28106 // Excel doesn't like an empty mergeCells tag 28107 if ( $('mergeCells', rels).children().length === 0 ) { 28108 $('mergeCells', rels).remove(); 28109 } 28110 28111 var jszip = _jsZip(); 28112 var zip = new jszip(); 28113 var zipConfig = { 28114 type: 'blob', 28115 mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' 28116 }; 28117 28118 _addToZip( zip, xlsx ); 28119 28120 if ( zip.generateAsync ) { 28121 // JSZip 3+ 28122 zip 28123 .generateAsync( zipConfig ) 28124 .then( function ( blob ) { 28125 _saveAs( blob, exportInfo.filename ); 28126 that.processing( false ); 28127 } ); 28128 } 28129 else { 28130 // JSZip 2.5 28131 _saveAs( 28132 zip.generate( zipConfig ), 28133 exportInfo.filename 28134 ); 28135 this.processing( false ); 28136 } 28137 }, 28138 28139 filename: '*', 28140 28141 extension: '.xlsx', 28142 28143 exportOptions: {}, 28144 28145 header: true, 28146
28147 footer: false, 28148 28149 title: '*', 28150 28151 messageTop: '*', 28152 28153 messageBottom: '*', 28154 28155 createEmptyCells: false, 28156 28157 autoFilter: false, 28158 28159 sheetName: '' 28160}; 28161 28162// 28163// PDF export - using pdfMake - http://pdfmake.org 28164// 28165DataTable.ext.buttons.pdfHtml5 = { 28166 className: 'buttons-pdf buttons-html5', 28167 28168 available: function () { 28169 return window.FileReader !== undefined && _pdfMake(); 28170 }, 28171 28172 text: function ( dt ) { 28173 return dt.i18n( 'buttons.pdf', 'PDF' ); 28174 }, 28175 28176 action: function ( e, dt, button, config ) { 28177 this.processing( true ); 28178 28179 var that = this; 28180 var data = dt.buttons.exportData( config.exportOptions ); 28181 var info = dt.buttons.exportInfo( config ); 28182 var rows = []; 28183 28184 if ( config.header ) { 28185 rows.push( $.map( data.header, function ( d ) { 28186 return { 28187 text: typeof d === 'string' ? d : d+'', 28188 style: 'tableHeader' 28189 }; 28190 } ) ); 28191 } 28192 28193 for ( var i=0, ien=data.body.length ; i<ien ; i++ ) { 28194 rows.push( $.map( data.body[i], function ( d ) { 28195 if ( d === null || d === undefined ) { 28196 d = ''; 28197 } 28198 return { 28199 text: typeof d === 'string' ? d : d+'', 28200 style: i % 2 ? 'tableBodyEven' : 'tableBodyOdd' 28201 }; 28202 } ) ); 28203 } 28204 28205 if ( config.footer && data.footer) { 28206 rows.push( $.map( data.footer, function ( d ) { 28207 return { 28208 text: typeof d === 'string' ? d : d+'', 28209 style: 'tableFooter' 28210 }; 28211 } ) ); 28212 } 28213 28214 var doc = { 28215 pageSize: config.pageSize, 28216 pageOrientation: config.orientation, 28217 content: [ 28218 { 28219 table: { 28220 headerRows: 1, 28221 body: rows 28222 }, 28223 layout: 'noBorders' 28224 } 28225 ], 28226 styles: { 28227 tableHeader: { 28228 bold: true, 28229 fontSize: 11, 28230 color: 'white', 28231 fillColor: '#2d4154', 28232 alignment: 'center' 28233 }, 28234 tableBodyEven: {}, 28235 tableBodyOdd: { 28236 fillColor: '#f3f3f3' 28237 }, 28238 tableFooter: { 28239 bold: true, 28240 fontSize: 11, 28241 color: 'white', 28242 fillColor: '#2d4154' 28243 }, 28244 title: { 28245 alignment: 'center', 28246 fontSize: 15 28247 }, 28248 message: {} 28249 }, 28250 defaultStyle: { 28251 fontSize: 10 28252 } 28253 }; 28254 28255 if ( info.messageTop ) { 28256 doc.content.unshift( { 28257 text: info.messageTop, 28258 style: 'message', 28259 margin: [ 0, 0, 0, 12 ] 28260 } ); 28261 } 28262 28263 if ( info.messageBottom ) { 28264 doc.content.push( { 28265 text: info.messageBottom, 28266 style: 'message', 28267 margin: [ 0, 0, 0, 12 ] 28268 } ); 28269 } 28270 28271 if ( info.title ) { 28272 doc.content.unshift( { 28273 text: info.title, 28274 style: 'title', 28275 margin: [ 0, 0, 0, 12 ] 28276 } ); 28277 } 28278 28279 if ( config.customize ) { 28280 config.customize( doc, config, dt ); 28281 } 28282 28283 var pdf = _pdfMake().createPdf( doc ); 28284 28285 if ( config.download === 'open' && ! _isDuffSafari() ) { 28286 pdf.open(); 28287 } 28288 else { 28289 pdf.download( info.filename ); 28290 } 28291 28292 this.processing( false ); 28293 }, 28294 28295 title: '*', 28296 28297 filename: '*', 28298 28299 extension: '.pdf', 28300 28301 exportOptions: {}, 28302 28303 orientation: 'portrait', 28304 28305 pageSize: 'A4', 28306 28307 header: true, 28308 28309 footer: false, 28310 28311 messageTop: '*', 28312 28313 messageBottom: '*', 28314 28315 customize: null, 28316 28317 download: 'download' 28318}; 28319 28320 28321return DataTable.Buttons; 28322})); 28323 28324 28325/*! ColReorder 1.5.0 28326 * ©2010-2018 SpryMedia Ltd - datatables.net/license 28327 */ 28328 28329/** 28330 * @summary ColReorder 28331 * @description Provide the ability to reorder columns in a DataTable 28332 * @version 1.5.0 28333 * @file dataTables.colReorder.js 28334 * @author SpryMedia Ltd (www.sprymedia.co.uk) 28335 * @contact www.sprymedia.co.uk/contact 28336 * @copyright Copyright 2010-2018 SpryMedia Ltd. 28337 * 28338 * This source file is free software, available under the following license: 28339 * MIT license - http://datatables.net/license/mit 28340 * 28341 * This source file is distributed in the hope that it will be useful, but 28342 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 28343 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. 28344 * 28345 * For details please refer to: http://www.datatables.net 28346 */ 28347(function( factory ){ 28348 if ( typeof define === 'function' && define.amd ) { 28349 // AMD 28350 define( ['jquery', 'datatables.net'], function ( $ ) { 28351 return factory( $, window, document ); 28352 } ); 28353 } 28354 else if ( typeof exports === 'object' ) { 28355 // CommonJS 28356 module.exports = function (root, $) { 28357 if ( ! root ) { 28358 root = window; 28359 } 28360 28361 if ( ! $ || ! $.fn.dataTable ) { 28362 $ = require('datatables.net')(root, $).$; 28363 } 28364 28365 return factory( $, root, root.document ); 28366 }; 28367 } 28368 else { 28369 // Browser 28370 factory( jQuery, window, document ); 28371 } 28372}(function( $, window, document, undefined ) { 28373'use strict'; 28374var DataTable = $.fn.dataTable; 28375 28376 28377/** 28378 * Switch the key value pairing of an index array to be value key (i.e. the old value is now the 28379 * key). For example consider [ 2, 0, 1 ] this would be returned as [ 1, 2, 0 ]. 28380 * @method fnInvertKeyValues 28381 * @param array aIn Array to switch around 28382 * @returns array 28383 */ 28384function fnInvertKeyValues( aIn ) 28385{ 28386 var aRet=[]; 28387 for ( var i=0, iLen=aIn.length ; i<iLen ; i++ ) 28388 { 28389 aRet[ aIn[i] ] = i; 28390 } 28391 return aRet; 28392} 28393 28394 28395/** 28396 * Modify an array by switching the position of two elements 28397 * @method fnArraySwitch 28398 * @param array aArray Array to consider, will be modified by reference (i.e. no return) 28399 * @param int iFrom From point 28400 * @param int iTo Insert point 28401 * @returns void 28402 */ 28403function fnArraySwitch( aArray, iFrom, iTo ) 28404{ 28405 var mStore = aArray.splice( iFrom, 1 )[0]; 28406 aArray.splice( iTo, 0, mStore ); 28407} 28408 28409 28410/** 28411 * Switch the positions of nodes in a parent node (note this is specifically designed for 28412 * table rows). Note this function considers all element nodes under the parent! 28413 * @method fnDomSwitch 28414 * @param string sTag Tag to consider 28415 * @param int iFrom Element to move 28416 * @param int Point to element the element to (before this point), can be null for append 28417 * @returns void 28418 */ 28419function fnDomSwitch( nParent, iFrom, iTo ) 28420{ 28421 var anTags = []; 28422 for ( var i=0, iLen=nParent.childNodes.length ; i<iLen ; i++ ) 28423 { 28424 if ( nParent.childNodes[i].nodeType == 1 ) 28425 { 28426 anTags.push( nParent.childNodes[i] ); 28427 } 28428 } 28429 var nStore = anTags[ iFrom ]; 28430 28431 if ( iTo !== null ) 28432 { 28433 nParent.insertBefore( nStore, anTags[iTo] ); 28434 } 28435 else 28436 { 28437 nParent.appendChild( nStore ); 28438 } 28439} 28440 28441 28442/**
28443 * Plug-in for DataTables which will reorder the internal column structure by taking the column 28444 * from one position (iFrom) and insert it into a given point (iTo). 28445 * @method $.fn.dataTableExt.oApi.fnColReorder 28446 * @param object oSettings DataTables settings object - automatically added by DataTables! 28447 * @param int iFrom Take the column to be repositioned from this point 28448 * @param int iTo and insert it into this point 28449 * @param bool drop Indicate if the reorder is the final one (i.e. a drop) 28450 * not a live reorder 28451 * @param bool invalidateRows speeds up processing if false passed 28452 * @returns void 28453 */ 28454$.fn.dataTableExt.oApi.fnColReorder = function ( oSettings, iFrom, iTo, drop, invalidateRows ) 28455{ 28456 var i, iLen, j, jLen, jen, iCols=oSettings.aoColumns.length, nTrs, oCol; 28457 var attrMap = function ( obj, prop, mapping ) { 28458 if ( ! obj[ prop ] || typeof obj[ prop ] === 'function' ) { 28459 return; 28460 } 28461 28462 var a = obj[ prop ].split('.'); 28463 var num = a.shift(); 28464 28465 if ( isNaN( num*1 ) ) { 28466 return; 28467 } 28468 28469 obj[ prop ] = mapping[ num*1 ]+'.'+a.join('.'); 28470 }; 28471 28472 /* Sanity check in the input */ 28473 if ( iFrom == iTo ) 28474 { 28475 /* Pointless reorder */ 28476 return; 28477 } 28478 28479 if ( iFrom < 0 || iFrom >= iCols ) 28480 { 28481 this.oApi._fnLog( oSettings, 1, "ColReorder 'from' index is out of bounds: "+iFrom ); 28482 return; 28483 } 28484 28485 if ( iTo < 0 || iTo >= iCols ) 28486 { 28487 this.oApi._fnLog( oSettings, 1, "ColReorder 'to' index is out of bounds: "+iTo ); 28488 return; 28489 } 28490 28491 /* 28492 * Calculate the new column array index, so we have a mapping between the old and new 28493 */ 28494 var aiMapping = []; 28495 for ( i=0, iLen=iCols ; i<iLen ; i++ ) 28496 { 28497 aiMapping[i] = i; 28498 } 28499 fnArraySwitch( aiMapping, iFrom, iTo ); 28500 var aiInvertMapping = fnInvertKeyValues( aiMapping ); 28501 28502 28503 /* 28504 * Convert all internal indexing to the new column order indexes 28505 */ 28506 /* Sorting */ 28507 for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ ) 28508 { 28509 oSettings.aaSorting[i][0] = aiInvertMapping[ oSettings.aaSorting[i][0] ]; 28510 } 28511 28512 /* Fixed sorting */ 28513 if ( oSettings.aaSortingFixed !== null ) 28514 { 28515 for ( i=0, iLen=oSettings.aaSortingFixed.length ; i<iLen ; i++ ) 28516 { 28517 oSettings.aaSortingFixed[i][0] = aiInvertMapping[ oSettings.aaSortingFixed[i][0] ]; 28518 } 28519 } 28520 28521 /* Data column sorting (the column which the sort for a given column should take place on) */ 28522 for ( i=0, iLen=iCols ; i<iLen ; i++ ) 28523 { 28524 oCol = oSettings.aoColumns[i]; 28525 for ( j=0, jLen=oCol.aDataSort.length ; j<jLen ; j++ ) 28526 { 28527 oCol.aDataSort[j] = aiInvertMapping[ oCol.aDataSort[j] ]; 28528 } 28529 28530 // Update the column indexes 28531 oCol.idx = aiInvertMapping[ oCol.idx ]; 28532 } 28533 28534 // Update 1.10 optimised sort class removal variable 28535 $.each( oSettings.aLastSort, function (i, val) { 28536 oSettings.aLastSort[i].src = aiInvertMapping[ val.src ]; 28537 } ); 28538 28539 /* Update the Get and Set functions for each column */ 28540 for ( i=0, iLen=iCols ; i<iLen ; i++ ) 28541 { 28542 oCol = oSettings.aoColumns[i]; 28543 28544 if ( typeof oCol.mData == 'number' ) { 28545 oCol.mData = aiInvertMapping[ oCol.mData ]; 28546 } 28547 else if ( $.isPlainObject( oCol.mData ) ) { 28548 // HTML5 data sourced 28549 attrMap( oCol.mData, '_', aiInvertMapping ); 28550 attrMap( oCol.mData, 'filter', aiInvertMapping ); 28551 attrMap( oCol.mData, 'sort', aiInvertMapping ); 28552 attrMap( oCol.mData, 'type', aiInvertMapping ); 28553 } 28554 } 28555 28556 /* 28557 * Move the DOM elements 28558 */ 28559 if ( oSettings.aoColumns[iFrom].bVisible ) 28560 { 28561 /* Calculate the current visible index and the point to insert the node before. The insert 28562 * before needs to take into account that there might not be an element to insert before, 28563 * in which case it will be null, and an appendChild should be used 28564 */ 28565 var iVisibleIndex = this.oApi._fnColumnIndexToVisible( oSettings, iFrom ); 28566 var iInsertBeforeIndex = null; 28567 28568 i = iTo < iFrom ? iTo : iTo + 1; 28569 while ( iInsertBeforeIndex === null && i < iCols ) 28570 { 28571 iInsertBeforeIndex = this.oApi._fnColumnIndexToVisible( oSettings, i ); 28572 i++; 28573 } 28574 28575 /* Header */ 28576 nTrs = oSettings.nTHead.getElementsByTagName('tr'); 28577 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 28578 { 28579 fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex ); 28580 } 28581 28582 /* Footer */ 28583 if ( oSettings.nTFoot !== null ) 28584 { 28585 nTrs = oSettings.nTFoot.getElementsByTagName('tr'); 28586 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 28587 {
28588 fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex ); 28589 } 28590 } 28591 28592 /* Body */ 28593 for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ ) 28594 { 28595 if ( oSettings.aoData[i].nTr !== null ) 28596 { 28597 fnDomSwitch( oSettings.aoData[i].nTr, iVisibleIndex, iInsertBeforeIndex ); 28598 } 28599 } 28600 } 28601 28602 /* 28603 * Move the internal array elements 28604 */ 28605 /* Columns */ 28606 fnArraySwitch( oSettings.aoColumns, iFrom, iTo ); 28607 28608 // regenerate the get / set functions 28609 for ( i=0, iLen=iCols ; i<iLen ; i++ ) { 28610 oSettings.oApi._fnColumnOptions( oSettings, i, {} ); 28611 } 28612 28613 /* Search columns */ 28614 fnArraySwitch( oSettings.aoPreSearchCols, iFrom, iTo ); 28615 28616 /* Array array - internal data anodes cache */ 28617 for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ ) 28618 { 28619 var data = oSettings.aoData[i]; 28620 var cells = data.anCells; 28621 28622 if ( cells ) { 28623 fnArraySwitch( cells, iFrom, iTo ); 28624 28625 // Longer term, should this be moved into the DataTables' invalidate 28626 // methods? 28627 for ( j=0, jen=cells.length ; j<jen ; j++ ) { 28628 if ( cells[j] && cells[j]._DT_CellIndex ) { 28629 cells[j]._DT_CellIndex.column = j; 28630 } 28631 } 28632 } 28633 28634 // For DOM sourced data, the invalidate will reread the cell into 28635 // the data array, but for data sources as an array, they need to 28636 // be flipped 28637 if ( data.src !== 'dom' && $.isArray( data._aData ) ) { 28638 fnArraySwitch( data._aData, iFrom, iTo ); 28639 } 28640 } 28641 28642 /* Reposition the header elements in the header layout array */ 28643 for ( i=0, iLen=oSettings.aoHeader.length ; i<iLen ; i++ ) 28644 { 28645 fnArraySwitch( oSettings.aoHeader[i], iFrom, iTo ); 28646 } 28647 28648 if ( oSettings.aoFooter !== null ) 28649 { 28650 for ( i=0, iLen=oSettings.aoFooter.length ; i<iLen ; i++ ) 28651 { 28652 fnArraySwitch( oSettings.aoFooter[i], iFrom, iTo ); 28653 } 28654 } 28655 28656 if ( invalidateRows || invalidateRows === undefined ) 28657 { 28658 $.fn.dataTable.Api( oSettings ).rows().invalidate(); 28659 } 28660 28661 /* 28662 * Update DataTables' event handlers 28663 */ 28664 28665 /* Sort listener */ 28666 for ( i=0, iLen=iCols ; i<iLen ; i++ ) 28667 { 28668 $(oSettings.aoColumns[i].nTh).off('.DT'); 28669 this.oApi._fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i ); 28670 } 28671 28672 28673 /* Fire an event so other plug-ins can update */ 28674 $(oSettings.oInstance).trigger( 'column-reorder.dt', [ oSettings, { 28675 from: iFrom, 28676 to: iTo, 28677 mapping: aiInvertMapping, 28678 drop: drop, 28679 28680 // Old style parameters for compatibility 28681 iFrom: iFrom, 28682 iTo: iTo, 28683 aiInvertMapping: aiInvertMapping 28684 } ] ); 28685}; 28686 28687/** 28688 * ColReorder provides column visibility control for DataTables 28689 * @class ColReorder 28690 * @constructor 28691 * @param {object} dt DataTables settings object 28692 * @param {object} opts ColReorder options 28693 */ 28694var ColReorder = function( dt, opts ) 28695{ 28696 var settings = new $.fn.dataTable.Api( dt ).settings()[0]; 28697 28698 // Ensure that we can't initialise on the same table twice 28699 if ( settings._colReorder ) { 28700 return settings._colReorder; 28701 } 28702 28703 // Allow the options to be a boolean for defaults 28704 if ( opts === true ) { 28705 opts = {}; 28706 } 28707 28708 // Convert from camelCase to Hungarian, just as DataTables does 28709 var camelToHungarian = $.fn.dataTable.camelToHungarian; 28710 if ( camelToHungarian ) { 28711 camelToHungarian( ColReorder.defaults, ColReorder.defaults, true ); 28712 camelToHungarian( ColReorder.defaults, opts || {} ); 28713 } 28714 28715 28716 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 28717 * Public class variables 28718 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 28719 28720 /** 28721 * @namespace Settings object which contains customisable information for ColReorder instance 28722 */ 28723 this.s = { 28724 /** 28725 * DataTables settings object 28726 * @property dt 28727 * @type Object 28728 * @default null 28729 */ 28730 "dt": null, 28731 28732 /** 28733 * Enable flag 28734 * @property dt 28735 * @type Object 28736 * @default null 28737 */ 28738 "enable": null, 28739 28740 /** 28741 * Initialisation object used for this instance 28742 * @property init 28743 * @type object 28744 * @default {} 28745 */ 28746 "init": $.extend( true, {}, ColReorder.defaults, opts ), 28747 28748 /** 28749 * Number of columns to fix (not allow to be reordered) 28750 * @property fixed 28751 * @type int 28752 * @default 0 28753 */ 28754 "fixed": 0, 28755 28756 /** 28757 * Number of columns to fix counting from right (not allow to be reordered) 28758 * @property fixedRight 28759 * @type int 28760 * @default 0 28761 */ 28762 "fixedRight": 0, 28763 28764 /** 28765 * Callback function for once the reorder has been done 28766 * @property reorderCallback 28767 * @type function 28768 * @default null 28769 */ 28770 "reorderCallback": null, 28771 28772 /** 28773 * @namespace Information used for the mouse drag 28774 */ 28775 "mouse": { 28776 "startX": -1, 28777 "startY": -1, 28778 "offsetX": -1, 28779 "offsetY": -1, 28780 "target": -1, 28781 "targetIndex": -1, 28782 "fromIndex": -1 28783 }, 28784 28785 /** 28786 * Information which is used for positioning the insert cusor and knowing where to do the 28787 * insert. Array of objects with the properties: 28788 * x: x-axis position 28789 * to: insert point 28790 * @property aoTargets 28791 * @type array 28792 * @default [] 28793 */ 28794 "aoTargets": [] 28795 }; 28796 28797 28798 /** 28799 * @namespace Common and useful DOM elements for the class instance 28800 */ 28801 this.dom = { 28802 /** 28803 * Dragging element (the one the mouse is moving) 28804 * @property drag 28805 * @type element 28806 * @default null 28807 */ 28808 "drag": null, 28809 28810 /** 28811 * The insert cursor 28812 * @property pointer 28813 * @type element 28814 * @default null 28815 */ 28816 "pointer": null 28817 }; 28818 28819 /* Constructor logic */ 28820 this.s.enable = this.s.init.bEnable; 28821 this.s.dt = settings; 28822 this.s.dt._colReorder = this; 28823 this._fnConstruct(); 28824 28825 return this; 28826}; 28827 28828 28829 28830$.extend( ColReorder.prototype, { 28831 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 28832 * Public methods 28833 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 28834 28835 /** 28836 * Enable / disable end user interaction 28837 */ 28838 fnEnable: function ( flag ) 28839 { 28840 if ( flag === false ) { 28841 return fnDisable(); 28842 } 28843 28844 this.s.enable = true; 28845 }, 28846 28847 /** 28848 * Disable end user interaction 28849 */ 28850 fnDisable: function () 28851 { 28852 this.s.enable = false;
28853 }, 28854 28855 /** 28856 * Reset the column ordering to the original ordering that was detected on 28857 * start up. 28858 * @return {this} Returns `this` for chaining. 28859 * 28860 * @example 28861 * // DataTables initialisation with ColReorder 28862 * var table = $('#example').dataTable( { 28863 * "sDom": 'Rlfrtip' 28864 * } ); 28865 * 28866 * // Add click event to a button to reset the ordering 28867 * $('#resetOrdering').click( function (e) { 28868 * e.preventDefault(); 28869 * $.fn.dataTable.ColReorder( table ).fnReset(); 28870 * } ); 28871 */ 28872 "fnReset": function () 28873 { 28874 this._fnOrderColumns( this.fnOrder() ); 28875 28876 return this; 28877 }, 28878 28879 /** 28880 * `Deprecated` - Get the current order of the columns, as an array. 28881 * @return {array} Array of column identifiers 28882 * @deprecated `fnOrder` should be used in preference to this method. 28883 * `fnOrder` acts as a getter/setter. 28884 */ 28885 "fnGetCurrentOrder": function () 28886 { 28887 return this.fnOrder(); 28888 }, 28889 28890 /** 28891 * Get the current order of the columns, as an array. Note that the values 28892 * given in the array are unique identifiers for each column. Currently 28893 * these are the original ordering of the columns that was detected on 28894 * start up, but this could potentially change in future. 28895 * @return {array} Array of column identifiers 28896 * 28897 * @example 28898 * // Get column ordering for the table 28899 * var order = $.fn.dataTable.ColReorder( dataTable ).fnOrder(); 28900 *//** 28901 * Set the order of the columns, from the positions identified in the 28902 * ordering array given. Note that ColReorder takes a brute force approach 28903 * to reordering, so it is possible multiple reordering events will occur 28904 * before the final order is settled upon. 28905 * @param {array} [set] Array of column identifiers in the new order. Note 28906 * that every column must be included, uniquely, in this array. 28907 * @return {this} Returns `this` for chaining. 28908 * 28909 * @example 28910 * // Swap the first and second columns 28911 * $.fn.dataTable.ColReorder( dataTable ).fnOrder( [1, 0, 2, 3, 4] ); 28912 * 28913 * @example 28914 * // Move the first column to the end for the table `#example` 28915 * var curr = $.fn.dataTable.ColReorder( '#example' ).fnOrder(); 28916 * var first = curr.shift(); 28917 * curr.push( first ); 28918 * $.fn.dataTable.ColReorder( '#example' ).fnOrder( curr ); 28919 * 28920 * @example 28921 * // Reverse the table's order 28922 * $.fn.dataTable.ColReorder( '#example' ).fnOrder( 28923 * $.fn.dataTable.ColReorder( '#example' ).fnOrder().reverse() 28924 * ); 28925 */ 28926 "fnOrder": function ( set, original ) 28927 { 28928 var a = [], i, ien, j, jen; 28929 var columns = this.s.dt.aoColumns; 28930 28931 if ( set === undefined ){ 28932 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 28933 a.push( columns[i]._ColReorder_iOrigCol ); 28934 } 28935 28936 return a; 28937 } 28938 28939 // The order given is based on the original indexes, rather than the 28940 // existing ones, so we need to translate from the original to current 28941 // before then doing the order 28942 if ( original ) { 28943 var order = this.fnOrder(); 28944 28945 for ( i=0, ien=set.length ; i<ien ; i++ ) { 28946 a.push( $.inArray( set[i], order ) ); 28947 } 28948 28949 set = a; 28950 } 28951 28952 this._fnOrderColumns( fnInvertKeyValues( set ) ); 28953 28954 return this; 28955 }, 28956 28957 28958 /** 28959 * Convert from the original column index, to the original 28960 * 28961 * @param {int|array} idx Index(es) to convert 28962 * @param {string} dir Transpose direction - `fromOriginal` / `toCurrent` 28963 * or `'toOriginal` / `fromCurrent` 28964 * @return {int|array} Converted values 28965 */ 28966 fnTranspose: function ( idx, dir ) 28967 { 28968 if ( ! dir ) { 28969 dir = 'toCurrent'; 28970 } 28971 28972 var order = this.fnOrder(); 28973 var columns = this.s.dt.aoColumns; 28974 28975 if ( dir === 'toCurrent' ) { 28976 // Given an original index, want the current 28977 return ! $.isArray( idx ) ? 28978 $.inArray( idx, order ) : 28979 $.map( idx, function ( index ) { 28980 return $.inArray( index, order ); 28981 } ); 28982 } 28983 else { 28984 // Given a current index, want the original 28985 return ! $.isArray( idx ) ? 28986 columns[idx]._ColReorder_iOrigCol : 28987 $.map( idx, function ( index ) { 28988 return columns[index]._ColReorder_iOrigCol; 28989 } ); 28990 } 28991 }, 28992 28993 28994 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 28995 * Private methods (they are of course public in JS, but recommended as private) 28996 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 28997 28998 /** 28999 * Constructor logic 29000 * @method _fnConstruct 29001 * @returns void 29002 * @private 29003 */ 29004 "_fnConstruct": function () 29005 { 29006 var that = this; 29007 var iLen = this.s.dt.aoColumns.length; 29008 var table = this.s.dt.nTable; 29009 var i; 29010 29011 /* Columns discounted from reordering - counting left to right */ 29012 if ( this.s.init.iFixedColumns ) 29013 { 29014 this.s.fixed = this.s.init.iFixedColumns; 29015 } 29016 29017 if ( this.s.init.iFixedColumnsLeft ) 29018 { 29019 this.s.fixed = this.s.init.iFixedColumnsLeft; 29020 } 29021 29022 /* Columns discounted from reordering - counting right to left */ 29023 this.s.fixedRight = this.s.init.iFixedColumnsRight ? 29024 this.s.init.iFixedColumnsRight : 29025 0; 29026 29027 /* Drop callback initialisation option */ 29028 if ( this.s.init.fnReorderCallback ) 29029 { 29030 this.s.reorderCallback = this.s.init.fnReorderCallback; 29031 } 29032 29033 /* Add event handlers for the drag and drop, and also mark the original column order */ 29034 for ( i = 0; i < iLen; i++ ) 29035 { 29036 if ( i > this.s.fixed-1 && i < iLen - this.s.fixedRight ) 29037 { 29038 this._fnMouseListener( i, this.s.dt.aoColumns[i].nTh ); 29039 } 29040 29041 /* Mark the original column order for later reference */ 29042 this.s.dt.aoColumns[i]._ColReorder_iOrigCol = i; 29043 } 29044
29045 /* State saving */ 29046 this.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) { 29047 that._fnStateSave.call( that, oData ); 29048 }, "ColReorder_State" ); 29049 29050 /* An initial column order has been specified */ 29051 var aiOrder = null; 29052 if ( this.s.init.aiOrder ) 29053 { 29054 aiOrder = this.s.init.aiOrder.slice(); 29055 } 29056 29057 /* State loading, overrides the column order given */ 29058 if ( this.s.dt.oLoadedState && typeof this.s.dt.oLoadedState.ColReorder != 'undefined' && 29059 this.s.dt.oLoadedState.ColReorder.length == this.s.dt.aoColumns.length ) 29060 { 29061 aiOrder = this.s.dt.oLoadedState.ColReorder; 29062 } 29063 29064 /* If we have an order to apply - do so */ 29065 if ( aiOrder ) 29066 { 29067 /* We might be called during or after the DataTables initialisation. If before, then we need 29068 * to wait until the draw is done, if after, then do what we need to do right away 29069 */ 29070 if ( !that.s.dt._bInitComplete ) 29071 { 29072 var bDone = false; 29073 $(table).on( 'draw.dt.colReorder', function () { 29074 if ( !that.s.dt._bInitComplete && !bDone ) 29075 { 29076 bDone = true; 29077 var resort = fnInvertKeyValues( aiOrder ); 29078 that._fnOrderColumns.call( that, resort ); 29079 } 29080 } ); 29081 } 29082 else 29083 { 29084 var resort = fnInvertKeyValues( aiOrder ); 29085 that._fnOrderColumns.call( that, resort ); 29086 } 29087 } 29088 else { 29089 this._fnSetColumnIndexes(); 29090 } 29091 29092 // Destroy clean up 29093 $(table).on( 'destroy.dt.colReorder', function () { 29094 $(table).off( 'destroy.dt.colReorder draw.dt.colReorder' ); 29095 29096 $.each( that.s.dt.aoColumns, function (i, column) { 29097 $(column.nTh).off('.ColReorder'); 29098 $(column.nTh).removeAttr('data-column-index'); 29099 } ); 29100 29101 that.s.dt._colReorder = null; 29102 that.s = null; 29103 } ); 29104 }, 29105 29106 29107 /** 29108 * Set the column order from an array 29109 * @method _fnOrderColumns 29110 * @param array a An array of integers which dictate the column order that should be applied 29111 * @returns void 29112 * @private 29113 */ 29114 "_fnOrderColumns": function ( a ) 29115 { 29116 var changed = false; 29117 29118 if ( a.length != this.s.dt.aoColumns.length ) 29119 { 29120 this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "ColReorder - array reorder does not "+ 29121 "match known number of columns. Skipping." ); 29122 return; 29123 } 29124 29125 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) 29126 { 29127 var currIndex = $.inArray( i, a ); 29128 if ( i != currIndex ) 29129 { 29130 /* Reorder our switching array */ 29131 fnArraySwitch( a, currIndex, i ); 29132 29133 /* Do the column reorder in the table */ 29134 this.s.dt.oInstance.fnColReorder( currIndex, i, true, false ); 29135 29136 changed = true; 29137 } 29138 } 29139 29140 this._fnSetColumnIndexes(); 29141 29142 // Has anything actually changed? If not, then nothing else to do 29143 if ( ! changed ) { 29144 return; 29145 } 29146 29147 $.fn.dataTable.Api( this.s.dt ).rows().invalidate(); 29148 29149 /* When scrolling we need to recalculate the column sizes to allow for the shift */ 29150 if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" ) 29151 { 29152 this.s.dt.oInstance.fnAdjustColumnSizing( false ); 29153 } 29154 29155 /* Save the state */ 29156 this.s.dt.oInstance.oApi._fnSaveState( this.s.dt ); 29157 29158 if ( this.s.reorderCallback !== null ) 29159 { 29160 this.s.reorderCallback.call( this ); 29161 } 29162 }, 29163 29164 29165 /** 29166 * Because we change the indexes of columns in the table, relative to their starting point 29167 * we need to reorder the state columns to what they are at the starting point so we can 29168 * then rearrange them again on state load! 29169 * @method _fnStateSave 29170 * @param object oState DataTables state 29171 * @returns string JSON encoded cookie string for DataTables 29172 * @private 29173 */ 29174 "_fnStateSave": function ( oState ) 29175 { 29176 var i, iLen, aCopy, iOrigColumn; 29177 var oSettings = this.s.dt; 29178 var columns = oSettings.aoColumns; 29179 29180 oState.ColReorder = []; 29181 29182 /* Sorting */ 29183 if ( oState.aaSorting ) { 29184 // 1.10.0- 29185 for ( i=0 ; i<oState.aaSorting.length ; i++ ) { 29186 oState.aaSorting[i][0] = columns[ oState.aaSorting[i][0] ]._ColReorder_iOrigCol; 29187 } 29188 29189 var aSearchCopy = $.extend( true, [], oState.aoSearchCols ); 29190 29191 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) 29192 { 29193 iOrigColumn = columns[i]._ColReorder_iOrigCol; 29194 29195 /* Column filter */ 29196 oState.aoSearchCols[ iOrigColumn ] = aSearchCopy[i]; 29197 29198 /* Visibility */ 29199 oState.abVisCols[ iOrigColumn ] = columns[i].bVisible; 29200 29201 /* Column reordering */ 29202 oState.ColReorder.push( iOrigColumn ); 29203 } 29204 } 29205 else if ( oState.order ) { 29206 // 1.10.1+ 29207 for ( i=0 ; i<oState.order.length ; i++ ) { 29208 oState.order[i][0] = columns[ oState.order[i][0] ]._ColReorder_iOrigCol; 29209 } 29210 29211 var stateColumnsCopy = $.extend( true, [], oState.columns ); 29212 29213 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) 29214 { 29215 iOrigColumn = columns[i]._ColReorder_iOrigCol; 29216 29217 /* Columns */ 29218 oState.columns[ iOrigColumn ] = stateColumnsCopy[i]; 29219 29220 /* Column reordering */ 29221 oState.ColReorder.push( iOrigColumn ); 29222 } 29223 } 29224 }, 29225 29226 29227 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 29228 * Mouse drop and drag 29229 */ 29230 29231 /** 29232 * Add a mouse down listener to a particluar TH element 29233 * @method _fnMouseListener 29234 * @param int i Column index 29235 * @param element nTh TH element clicked on 29236 * @returns void 29237 * @private 29238 */ 29239 "_fnMouseListener": function ( i, nTh ) 29240 { 29241 var that = this; 29242 $(nTh) 29243 .on( 'mousedown.ColReorder', function (e) { 29244 if ( that.s.enable ) { 29245 that._fnMouseDown.call( that, e, nTh ); 29246 } 29247 } ) 29248 .on( 'touchstart.ColReorder', function (e) { 29249 if ( that.s.enable ) { 29250 that._fnMouseDown.call( that, e, nTh ); 29251 } 29252 } ); 29253 }, 29254 29255 29256 /** 29257 * Mouse down on a TH element in the table header 29258 * @method _fnMouseDown 29259 * @param event e Mouse event 29260 * @param element nTh TH element to be dragged 29261 * @returns void 29262 * @private 29263 */ 29264 "_fnMouseDown": function ( e, nTh ) 29265 { 29266 var that = this; 29267 29268 /* Store information about the mouse position */ 29269 var target = $(e.target).closest('th, td'); 29270 var offset = target.offset(); 29271 var idx = parseInt( $(nTh).attr('data-column-index'), 10 ); 29272 29273 if ( idx === undefined ) { 29274 return; 29275 } 29276 29277 this.s.mouse.startX = this._fnCursorPosition( e, 'pageX' ); 29278 this.s.mouse.startY = this._fnCursorPosition( e, 'pageY' ); 29279 this.s.mouse.offsetX = this._fnCursorPosition( e, 'pageX' ) - offset.left; 29280 this.s.mouse.offsetY = this._fnCursorPosition( e, 'pageY' ) - offset.top; 29281 this.s.mouse.target = this.s.dt.aoColumns[ idx ].nTh;//target[0]; 29282 this.s.mouse.targetIndex = idx; 29283 this.s.mouse.fromIndex = idx; 29284 29285 this._fnRegions(); 29286 29287 /* Add event handlers to the document */ 29288 $(document) 29289 .on( 'mousemove.ColReorder touchmove.ColReorder', function (e) { 29290 that._fnMouseMove.call( that, e ); 29291 } ) 29292 .on( 'mouseup.ColReorder touchend.ColReorder', function (e) { 29293 that._fnMouseUp.call( that, e ); 29294 } ); 29295 }, 29296 29297 29298 /** 29299 * Deal with a mouse move event while dragging a node 29300 * @method _fnMouseMove 29301 * @param event e Mouse event 29302 * @returns void 29303 * @private 29304 */ 29305 "_fnMouseMove": function ( e ) 29306 { 29307 var that = this; 29308 29309 if ( this.dom.drag === null ) 29310 { 29311 /* Only create the drag element if the mouse has moved a specific distance from the start 29312 * point - this allows the user to make small mouse movements when sorting and not have a 29313 * possibly confusing drag element showing up 29314 */ 29315 if ( Math.pow( 29316 Math.pow(this._fnCursorPosition( e, 'pageX') - this.s.mouse.startX, 2) + 29317 Math.pow(this._fnCursorPosition( e, 'pageY') - this.s.mouse.startY, 2), 0.5 ) < 5 ) 29318 { 29319 return; 29320 } 29321 this._fnCreateDragNode(); 29322 } 29323 29324 /* Position the element - we respect where in the element the click occured */ 29325 this.dom.drag.css( { 29326 left: this._fnCursorPosition( e, 'pageX' ) - this.s.mouse.offsetX, 29327 top: this._fnCursorPosition( e, 'pageY' ) - this.s.mouse.offsetY 29328 } ); 29329 29330 /* Based on the current mouse position, calculate where the insert should go */ 29331 var bSet = false;
29332 var lastToIndex = this.s.mouse.toIndex; 29333 29334 for ( var i=1, iLen=this.s.aoTargets.length ; i<iLen ; i++ ) 29335 { 29336 if ( this._fnCursorPosition(e, 'pageX') < this.s.aoTargets[i-1].x + ((this.s.aoTargets[i].x-this.s.aoTargets[i-1].x)/2) ) 29337 { 29338 this.dom.pointer.css( 'left', this.s.aoTargets[i-1].x ); 29339 this.s.mouse.toIndex = this.s.aoTargets[i-1].to; 29340 bSet = true; 29341 break; 29342 } 29343 } 29344 29345 // The insert element wasn't positioned in the array (less than 29346 // operator), so we put it at the end 29347 if ( !bSet ) 29348 { 29349 this.dom.pointer.css( 'left', this.s.aoTargets[this.s.aoTargets.length-1].x ); 29350 this.s.mouse.toIndex = this.s.aoTargets[this.s.aoTargets.length-1].to; 29351 } 29352 29353 // Perform reordering if realtime updating is on and the column has moved 29354 if ( this.s.init.bRealtime && lastToIndex !== this.s.mouse.toIndex ) { 29355 this.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex ); 29356 this.s.mouse.fromIndex = this.s.mouse.toIndex; 29357 29358 // Not great for performance, but required to keep everything in alignment 29359 if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" ) 29360 { 29361 this.s.dt.oInstance.fnAdjustColumnSizing( false ); 29362 } 29363 29364 this._fnRegions(); 29365 } 29366 }, 29367 29368 29369 /** 29370 * Finish off the mouse drag and insert the column where needed 29371 * @method _fnMouseUp 29372 * @param event e Mouse event 29373 * @returns void 29374 * @private 29375 */ 29376 "_fnMouseUp": function ( e ) 29377 { 29378 var that = this; 29379 29380 $(document).off( '.ColReorder' ); 29381 29382 if ( this.dom.drag !== null ) 29383 { 29384 /* Remove the guide elements */ 29385 this.dom.drag.remove(); 29386 this.dom.pointer.remove(); 29387 this.dom.drag = null; 29388 this.dom.pointer = null; 29389 29390 /* Actually do the reorder */ 29391 this.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex, true ); 29392 this._fnSetColumnIndexes(); 29393 29394 /* When scrolling we need to recalculate the column sizes to allow for the shift */ 29395 if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" ) 29396 { 29397 this.s.dt.oInstance.fnAdjustColumnSizing( false ); 29398 } 29399 29400 /* Save the state */ 29401 this.s.dt.oInstance.oApi._fnSaveState( this.s.dt ); 29402 29403 if ( this.s.reorderCallback !== null ) 29404 { 29405 this.s.reorderCallback.call( this ); 29406 } 29407 } 29408 }, 29409 29410 29411 /** 29412 * Calculate a cached array with the points of the column inserts, and the 29413 * 'to' points 29414 * @method _fnRegions 29415 * @returns void 29416 * @private 29417 */ 29418 "_fnRegions": function () 29419 { 29420 var aoColumns = this.s.dt.aoColumns; 29421 29422 this.s.aoTargets.splice( 0, this.s.aoTargets.length ); 29423 29424 this.s.aoTargets.push( { 29425 "x": $(this.s.dt.nTable).offset().left, 29426 "to": 0 29427 } ); 29428 29429 var iToPoint = 0; 29430 var total = this.s.aoTargets[0].x; 29431 29432 for ( var i=0, iLen=aoColumns.length ; i<iLen ; i++ ) 29433 { 29434 /* For the column / header in question, we want it's position to remain the same if the 29435 * position is just to it's immediate left or right, so we only increment the counter for 29436 * other columns 29437 */ 29438 if ( i != this.s.mouse.fromIndex ) 29439 { 29440 iToPoint++; 29441 } 29442 29443 if ( aoColumns[i].bVisible && aoColumns[i].nTh.style.display !=='none' ) 29444 { 29445 total += $(aoColumns[i].nTh).outerWidth(); 29446 29447 this.s.aoTargets.push( { 29448 "x": total, 29449 "to": iToPoint 29450 } ); 29451 } 29452 } 29453 29454 /* Disallow columns for being reordered by drag and drop, counting right to left */ 29455 if ( this.s.fixedRight !== 0 ) 29456 { 29457 this.s.aoTargets.splice( this.s.aoTargets.length - this.s.fixedRight ); 29458 } 29459 29460 /* Disallow columns for being reordered by drag and drop, counting left to right */ 29461 if ( this.s.fixed !== 0 ) 29462 { 29463 this.s.aoTargets.splice( 0, this.s.fixed ); 29464 } 29465 }, 29466 29467 29468 /** 29469 * Copy the TH element that is being drags so the user has the idea that they are actually 29470 * moving it around the page. 29471 * @method _fnCreateDragNode 29472 * @returns void 29473 * @private 29474 */ 29475 "_fnCreateDragNode": function () 29476 { 29477 var scrolling = this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== ""; 29478 29479 var origCell = this.s.dt.aoColumns[ this.s.mouse.targetIndex ].nTh; 29480 var origTr = origCell.parentNode; 29481 var origThead = origTr.parentNode; 29482 var origTable = origThead.parentNode; 29483 var cloneCell = $(origCell).clone(); 29484 29485 // This is a slightly odd combination of jQuery and DOM, but it is the 29486 // fastest and least resource intensive way I could think of cloning 29487 // the table with just a single header cell in it. 29488 this.dom.drag = $(origTable.cloneNode(false)) 29489 .addClass( 'DTCR_clonedTable' ) 29490 .append( 29491 $(origThead.cloneNode(false)).append( 29492 $(origTr.cloneNode(false)).append( 29493 cloneCell[0] 29494 ) 29495 ) 29496 ) 29497 .css( { 29498 position: 'absolute', 29499 top: 0, 29500 left: 0, 29501 width: $(origCell).outerWidth(), 29502 height: $(origCell).outerHeight() 29503 } ) 29504 .appendTo( 'body' ); 29505
29506 this.dom.pointer = $('<div></div>') 29507 .addClass( 'DTCR_pointer' ) 29508 .css( { 29509 position: 'absolute', 29510 top: scrolling ? 29511 $('div.dataTables_scroll', this.s.dt.nTableWrapper).offset().top : 29512 $(this.s.dt.nTable).offset().top, 29513 height : scrolling ? 29514 $('div.dataTables_scroll', this.s.dt.nTableWrapper).height() : 29515 $(this.s.dt.nTable).height() 29516 } ) 29517 .appendTo( 'body' ); 29518 }, 29519 29520 29521 /** 29522 * Add a data attribute to the column headers, so we know the index of 29523 * the row to be reordered. This allows fast detection of the index, and 29524 * for this plug-in to work with FixedHeader which clones the nodes. 29525 * @private 29526 */ 29527 "_fnSetColumnIndexes": function () 29528 { 29529 $.each( this.s.dt.aoColumns, function (i, column) { 29530 $(column.nTh).attr('data-column-index', i); 29531 } ); 29532 }, 29533 29534 29535 /** 29536 * Get cursor position regardless of mouse or touch input 29537 * @param {Event} e jQuery Event 29538 * @param {string} prop Property to get 29539 * @return {number} Value 29540 */ 29541 _fnCursorPosition: function ( e, prop ) { 29542 if ( e.type.indexOf('touch') !== -1 ) { 29543 return e.originalEvent.touches[0][ prop ]; 29544 } 29545 return e[ prop ]; 29546 } 29547} ); 29548 29549 29550 29551 29552 29553/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 29554 * Static parameters 29555 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 29556 29557 29558/** 29559 * ColReorder default settings for initialisation 29560 * @namespace 29561 * @static 29562 */ 29563ColReorder.defaults = { 29564 /** 29565 * Predefined ordering for the columns that will be applied automatically 29566 * on initialisation. If not specified then the order that the columns are 29567 * found to be in the HTML is the order used. 29568 * @type array 29569 * @default null 29570 * @static 29571 */ 29572 aiOrder: null, 29573 29574 /** 29575 * ColReorder enable on initialisation 29576 * @type boolean 29577 * @default true 29578 * @static 29579 */ 29580 bEnable: true, 29581 29582 /** 29583 * Redraw the table's column ordering as the end user draws the column 29584 * (`true`) or wait until the mouse is released (`false` - default). Note 29585 * that this will perform a redraw on each reordering, which involves an 29586 * Ajax request each time if you are using server-side processing in 29587 * DataTables. 29588 * @type boolean 29589 * @default false 29590 * @static 29591 */ 29592 bRealtime: true, 29593 29594 /** 29595 * Indicate how many columns should be fixed in position (counting from the 29596 * left). This will typically be 1 if used, but can be as high as you like. 29597 * @type int 29598 * @default 0 29599 * @static 29600 */ 29601 iFixedColumnsLeft: 0, 29602 29603 /** 29604 * As `iFixedColumnsRight` but counting from the right. 29605 * @type int 29606 * @default 0 29607 * @static 29608 */ 29609 iFixedColumnsRight: 0, 29610 29611 /** 29612 * Callback function that is fired when columns are reordered. The `column- 29613 * reorder` event is preferred over this callback 29614 * @type function():void 29615 * @default null 29616 * @static 29617 */ 29618 fnReorderCallback: null 29619}; 29620 29621 29622 29623/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 29624 * Constants 29625 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 29626 29627/** 29628 * ColReorder version 29629 * @constant version 29630 * @type String 29631 * @default As code 29632 */ 29633ColReorder.version = "1.5.0"; 29634 29635 29636 29637/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 29638 * DataTables interfaces 29639 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 29640 29641// Expose 29642$.fn.dataTable.ColReorder = ColReorder; 29643$.fn.DataTable.ColReorder = ColReorder; 29644 29645 29646// Register a new feature with DataTables 29647if ( typeof $.fn.dataTable == "function" && 29648 typeof $.fn.dataTableExt.fnVersionCheck == "function" && 29649 $.fn.dataTableExt.fnVersionCheck('1.10.8') ) 29650{ 29651 $.fn.dataTableExt.aoFeatures.push( { 29652 "fnInit": function( settings ) { 29653 var table = settings.oInstance; 29654 29655 if ( ! settings._colReorder ) { 29656 var dtInit = settings.oInit; 29657 var opts = dtInit.colReorder || dtInit.oColReorder || {}; 29658 29659 new ColReorder( settings, opts ); 29660 } 29661 else { 29662 table.oApi._fnLog( settings, 1, "ColReorder attempted to initialise twice. Ignoring second" ); 29663 } 29664 29665 return null; /* No node for DataTables to insert */ 29666 }, 29667 "cFeature": "R", 29668 "sFeature": "ColReorder" 29669 } ); 29670} 29671else { 29672 alert( "Warning: ColReorder requires DataTables 1.10.8 or greater - www.datatables.net/download"); 29673} 29674 29675 29676// Attach a listener to the document which listens for DataTables initialisation 29677// events so we can automatically initialise 29678$(document).on( 'preInit.dt.colReorder', function (e, settings) { 29679 if ( e.namespace !== 'dt' ) { 29680 return; 29681 } 29682 29683 var init = settings.oInit.colReorder; 29684 var defaults = DataTable.defaults.colReorder; 29685 29686 if ( init || defaults ) { 29687 var opts = $.extend( {}, init, defaults ); 29688 29689 if ( init !== false ) { 29690 new ColReorder( settings, opts ); 29691 } 29692 } 29693} ); 29694 29695 29696// API augmentation 29697$.fn.dataTable.Api.register( 'colReorder.reset()', function () { 29698 return this.iterator( 'table', function ( ctx ) { 29699 ctx._colReorder.fnReset(); 29700 } ); 29701} ); 29702 29703$.fn.dataTable.Api.register( 'colReorder.order()', function ( set, original ) { 29704 if ( set ) { 29705 return this.iterator( 'table', function ( ctx ) { 29706 ctx._colReorder.fnOrder( set, original ); 29707 } ); 29708 } 29709 29710 return this.context.length ? 29711 this.context[0]._colReorder.fnOrder() : 29712 null; 29713} ); 29714 29715$.fn.dataTable.Api.register( 'colReorder.transpose()', function ( idx, dir ) { 29716 return this.context.length && this.context[0]._colReorder ? 29717 this.context[0]._colReorder.fnTranspose( idx, dir ) : 29718 idx; 29719} ); 29720 29721$.fn.dataTable.Api.register( 'colReorder.move()', function( from, to, drop, invalidateRows ) { 29722 if (this.context.length) { 29723 this.context[0]._colReorder.s.dt.oInstance.fnColReorder( from, to, drop, invalidateRows ); 29724 } 29725 return this; 29726} ); 29727 29728$.fn.dataTable.Api.register( 'colReorder.enable()', function( flag ) { 29729 return this.iterator( 'table', function ( ctx ) { 29730 if ( ctx._colReorder ) { 29731 ctx._colReorder.fnEnable( flag ); 29732 } 29733 } ); 29734} ); 29735 29736$.fn.dataTable.Api.register( 'colReorder.disable()', function() { 29737 return this.iterator( 'table', function ( ctx ) { 29738 if ( ctx._colReorder ) { 29739 ctx._colReorder.fnDisable(); 29740 } 29741 } ); 29742} ); 29743 29744 29745return ColReorder; 29746})); 29747 29748 29749/*! FixedHeader 3.1.4
29750 * ©2009-2018 SpryMedia Ltd - datatables.net/license 29751 */ 29752 29753/** 29754 * @summary FixedHeader 29755 * @description Fix a table's header or footer, so it is always visible while 29756 * scrolling 29757 * @version 3.1.4 29758 * @file dataTables.fixedHeader.js 29759 * @author SpryMedia Ltd (www.sprymedia.co.uk) 29760 * @contact www.sprymedia.co.uk/contact 29761 * @copyright Copyright 2009-2018 SpryMedia Ltd. 29762 * 29763 * This source file is free software, available under the following license: 29764 * MIT license - http://datatables.net/license/mit 29765 * 29766 * This source file is distributed in the hope that it will be useful, but 29767 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 29768 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. 29769 * 29770 * For details please refer to: http://www.datatables.net 29771 */ 29772 29773(function( factory ){ 29774 if ( typeof define === 'function' && define.amd ) { 29775 // AMD 29776 define( ['jquery', 'datatables.net'], function ( $ ) { 29777 return factory( $, window, document ); 29778 } ); 29779 } 29780 else if ( typeof exports === 'object' ) { 29781 // CommonJS 29782 module.exports = function (root, $) { 29783 if ( ! root ) { 29784 root = window; 29785 } 29786 29787 if ( ! $ || ! $.fn.dataTable ) { 29788 $ = require('datatables.net')(root, $).$; 29789 } 29790 29791 return factory( $, root, root.document ); 29792 }; 29793 } 29794 else { 29795 // Browser 29796 factory( jQuery, window, document ); 29797 } 29798}(function( $, window, document, undefined ) { 29799'use strict'; 29800var DataTable = $.fn.dataTable; 29801 29802 29803var _instCounter = 0; 29804 29805var FixedHeader = function ( dt, config ) { 29806 // Sanity check - you just know it will happen 29807 if ( ! (this instanceof FixedHeader) ) { 29808 throw "FixedHeader must be initialised with the 'new' keyword."; 29809 } 29810 29811 // Allow a boolean true for defaults 29812 if ( config === true ) { 29813 config = {}; 29814 } 29815 29816 dt = new DataTable.Api( dt ); 29817 29818 this.c = $.extend( true, {}, FixedHeader.defaults, config ); 29819 29820 this.s = { 29821 dt: dt, 29822 position: { 29823 theadTop: 0, 29824 tbodyTop: 0, 29825 tfootTop: 0, 29826 tfootBottom: 0, 29827 width: 0, 29828 left: 0, 29829 tfootHeight: 0, 29830 theadHeight: 0, 29831 windowHeight: $(window).height(), 29832 visible: true 29833 }, 29834 headerMode: null, 29835 footerMode: null, 29836 autoWidth: dt.settings()[0].oFeatures.bAutoWidth, 29837 namespace: '.dtfc'+(_instCounter++), 29838 scrollLeft: { 29839 header: -1, 29840 footer: -1 29841 }, 29842 enable: true 29843 }; 29844 29845 this.dom = { 29846 floatingHeader: null, 29847 thead: $(dt.table().header()), 29848 tbody: $(dt.table().body()), 29849 tfoot: $(dt.table().footer()), 29850 header: { 29851 host: null, 29852 floating: null, 29853 placeholder: null 29854 }, 29855 footer: { 29856 host: null, 29857 floating: null, 29858 placeholder: null 29859 } 29860 }; 29861 29862 this.dom.header.host = this.dom.thead.parent(); 29863 this.dom.footer.host = this.dom.tfoot.parent(); 29864 29865 var dtSettings = dt.settings()[0]; 29866 if ( dtSettings._fixedHeader ) { 29867 throw "FixedHeader already initialised on table "+dtSettings.nTable.id; 29868 } 29869 29870 dtSettings._fixedHeader = this; 29871 29872 this._constructor(); 29873}; 29874 29875 29876/* 29877 * Variable: FixedHeader 29878 * Purpose: Prototype for FixedHeader 29879 * Scope: global 29880 */ 29881$.extend( FixedHeader.prototype, { 29882 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 29883 * API methods 29884 */ 29885 29886 /** 29887 * Enable / disable the fixed elements 29888 * 29889 * @param {boolean} enable `true` to enable, `false` to disable 29890 */ 29891 enable: function ( enable ) 29892 { 29893 this.s.enable = enable; 29894 29895 if ( this.c.header ) { 29896 this._modeChange( 'in-place', 'header', true ); 29897 } 29898 29899 if ( this.c.footer && this.dom.tfoot.length ) { 29900 this._modeChange( 'in-place', 'footer', true ); 29901 } 29902 29903 this.update(); 29904 }, 29905 29906 /** 29907 * Set header offset 29908 * 29909 * @param {int} new value for headerOffset 29910 */ 29911 headerOffset: function ( offset ) 29912 { 29913 if ( offset !== undefined ) { 29914 this.c.headerOffset = offset; 29915 this.update(); 29916 } 29917 29918 return this.c.headerOffset; 29919 }, 29920 29921 /** 29922 * Set footer offset 29923 * 29924 * @param {int} new value for footerOffset 29925 */ 29926 footerOffset: function ( offset ) 29927 { 29928 if ( offset !== undefined ) { 29929 this.c.footerOffset = offset; 29930 this.update(); 29931 } 29932 29933 return this.c.footerOffset; 29934 }, 29935 29936 29937 /** 29938 * Recalculate the position of the fixed elements and force them into place 29939 */ 29940 update: function () 29941 { 29942 this._positions(); 29943 this._scroll( true ); 29944 }, 29945 29946 29947 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 29948 * Constructor 29949 */ 29950 29951 /** 29952 * FixedHeader constructor - adding the required event listeners and 29953 * simple initialisation 29954 * 29955 * @private 29956 */ 29957 _constructor: function () 29958 { 29959 var that = this; 29960 var dt = this.s.dt; 29961 29962 $(window) 29963 .on( 'scroll'+this.s.namespace, function () { 29964 that._scroll(); 29965 } ) 29966 .on( 'resize'+this.s.namespace, DataTable.util.throttle( function () { 29967 that.s.position.windowHeight = $(window).height();
29968 that.update(); 29969 }, 50 ) ); 29970 29971 var autoHeader = $('.fh-fixedHeader'); 29972 if ( ! this.c.headerOffset && autoHeader.length ) { 29973 this.c.headerOffset = autoHeader.outerHeight(); 29974 } 29975 29976 var autoFooter = $('.fh-fixedFooter'); 29977 if ( ! this.c.footerOffset && autoFooter.length ) { 29978 this.c.footerOffset = autoFooter.outerHeight(); 29979 } 29980 29981 dt.on( 'column-reorder.dt.dtfc column-visibility.dt.dtfc draw.dt.dtfc column-sizing.dt.dtfc responsive-display.dt.dtfc', function () { 29982 that.update(); 29983 } ); 29984 29985 dt.on( 'destroy.dtfc', function () { 29986 if ( that.c.header ) { 29987 that._modeChange( 'in-place', 'header', true ); 29988 } 29989 29990 if ( that.c.footer && that.dom.tfoot.length ) { 29991 that._modeChange( 'in-place', 'footer', true ); 29992 } 29993 29994 dt.off( '.dtfc' ); 29995 $(window).off( that.s.namespace ); 29996 } ); 29997 29998 this._positions(); 29999 this._scroll(); 30000 }, 30001 30002 30003 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 30004 * Private methods 30005 */ 30006 30007 /** 30008 * Clone a fixed item to act as a place holder for the original element 30009 * which is moved into a clone of the table element, and moved around the 30010 * document to give the fixed effect. 30011 * 30012 * @param {string} item 'header' or 'footer' 30013 * @param {boolean} force Force the clone to happen, or allow automatic 30014 * decision (reuse existing if available) 30015 * @private 30016 */ 30017 _clone: function ( item, force ) 30018 { 30019 var dt = this.s.dt; 30020 var itemDom = this.dom[ item ]; 30021 var itemElement = item === 'header' ? 30022 this.dom.thead : 30023 this.dom.tfoot; 30024 30025 if ( ! force && itemDom.floating ) { 30026 // existing floating element - reuse it 30027 itemDom.floating.removeClass( 'fixedHeader-floating fixedHeader-locked' ); 30028 } 30029 else { 30030 if ( itemDom.floating ) { 30031 itemDom.placeholder.remove(); 30032 this._unsize( item ); 30033 itemDom.floating.children().detach(); 30034 itemDom.floating.remove(); 30035 } 30036 30037 itemDom.floating = $( dt.table().node().cloneNode( false ) ) 30038 .css( 'table-layout', 'fixed' ) 30039 .attr( 'aria-hidden', 'true' ) 30040 .removeAttr( 'id' ) 30041 .append( itemElement ) 30042 .appendTo( 'body' ); 30043 30044 // Insert a fake thead/tfoot into the DataTable to stop it jumping around 30045 itemDom.placeholder = itemElement.clone( false ) 30046 itemDom.placeholder 30047 .find( '*[id]' ) 30048 .removeAttr( 'id' ); 30049 30050 itemDom.host.prepend( itemDom.placeholder ); 30051 30052 // Clone widths 30053 this._matchWidths( itemDom.placeholder, itemDom.floating ); 30054 } 30055 }, 30056 30057 /** 30058 * Copy widths from the cells in one element to another. This is required 30059 * for the footer as the footer in the main table takes its sizes from the 30060 * header columns. That isn't present in the footer so to have it still 30061 * align correctly, the sizes need to be copied over. It is also required 30062 * for the header when auto width is not enabled 30063 * 30064 * @param {jQuery} from Copy widths from 30065 * @param {jQuery} to Copy widths to 30066 * @private 30067 */ 30068 _matchWidths: function ( from, to ) { 30069 var get = function ( name ) { 30070 return $(name, from) 30071 .map( function () { 30072 return $(this).width(); 30073 } ).toArray(); 30074 }; 30075 30076 var set = function ( name, toWidths ) { 30077 $(name, to).each( function ( i ) { 30078 $(this).css( { 30079 width: toWidths[i], 30080 minWidth: toWidths[i] 30081 } ); 30082 } ); 30083 }; 30084 30085 var thWidths = get( 'th' ); 30086 var tdWidths = get( 'td' ); 30087 30088 set( 'th', thWidths ); 30089 set( 'td', tdWidths ); 30090 }, 30091 30092 /** 30093 * Remove assigned widths from the cells in an element. This is required 30094 * when inserting the footer back into the main table so the size is defined 30095 * by the header columns and also when auto width is disabled in the 30096 * DataTable. 30097 * 30098 * @param {string} item The `header` or `footer` 30099 * @private 30100 */ 30101 _unsize: function ( item ) { 30102 var el = this.dom[ item ].floating; 30103 30104 if ( el && (item === 'footer' || (item === 'header' && ! this.s.autoWidth)) ) { 30105 $('th, td', el).css( { 30106 width: '', 30107 minWidth: '' 30108 } ); 30109 } 30110 else if ( el && item === 'header' ) { 30111 $('th, td', el).css( 'min-width', '' ); 30112 } 30113 }, 30114 30115 /** 30116 * Reposition the floating elements to take account of horizontal page 30117 * scroll 30118 * 30119 * @param {string} item The `header` or `footer` 30120 * @param {int} scrollLeft Document scrollLeft 30121 * @private 30122 */ 30123 _horizontal: function ( item, scrollLeft ) 30124 { 30125 var itemDom = this.dom[ item ]; 30126 var position = this.s.position; 30127 var lastScrollLeft = this.s.scrollLeft; 30128 30129 if ( itemDom.floating && lastScrollLeft[ item ] !== scrollLeft ) { 30130 itemDom.floating.css( 'left', position.left - scrollLeft ); 30131 30132 lastScrollLeft[ item ] = scrollLeft; 30133 } 30134 }, 30135 30136 /** 30137 * Change from one display mode to another. Each fixed item can be in one 30138 * of: 30139 * 30140 * * `in-place` - In the main DataTable 30141 * * `in` - Floating over the DataTable 30142 * * `below` - (Header only) Fixed to the bottom of the table body 30143 * * `above` - (Footer only) Fixed to the top of the table body 30144 * 30145 * @param {string} mode Mode that the item should be shown in 30146 * @param {string} item 'header' or 'footer' 30147 * @param {boolean} forceChange Force a redraw of the mode, even if already 30148 * in that mode. 30149 * @private 30150 */ 30151 _modeChange: function ( mode, item, forceChange ) 30152 { 30153 var dt = this.s.dt; 30154 var itemDom = this.dom[ item ]; 30155 var position = this.s.position; 30156 30157 // Record focus. Browser's will cause input elements to loose focus if 30158 // they are inserted else where in the doc 30159 var tablePart = this.dom[ item==='footer' ? 'tfoot' : 'thead' ]; 30160 var focus = $.contains( tablePart[0], document.activeElement ) ? 30161 document.activeElement : 30162 null; 30163
30164 if ( focus ) { 30165 focus.blur(); 30166 } 30167 30168 if ( mode === 'in-place' ) { 30169 // Insert the header back into the table's real header 30170 if ( itemDom.placeholder ) { 30171 itemDom.placeholder.remove(); 30172 itemDom.placeholder = null; 30173 } 30174 30175 this._unsize( item ); 30176 30177 if ( item === 'header' ) { 30178 itemDom.host.prepend( tablePart ); 30179 } 30180 else { 30181 itemDom.host.append( tablePart ); 30182 } 30183 30184 if ( itemDom.floating ) { 30185 itemDom.floating.remove(); 30186 itemDom.floating = null; 30187 } 30188 } 30189 else if ( mode === 'in' ) { 30190 // Remove the header from the read header and insert into a fixed 30191 // positioned floating table clone 30192 this._clone( item, forceChange ); 30193 30194 itemDom.floating 30195 .addClass( 'fixedHeader-floating' ) 30196 .css( item === 'header' ? 'top' : 'bottom', this.c[item+'Offset'] ) 30197 .css( 'left', position.left+'px' ) 30198 .css( 'width', position.width+'px' ); 30199 30200 if ( item === 'footer' ) { 30201 itemDom.floating.css( 'top', '' ); 30202 } 30203 } 30204 else if ( mode === 'below' ) { // only used for the header 30205 // Fix the position of the floating header at base of the table body 30206 this._clone( item, forceChange ); 30207 30208 itemDom.floating 30209 .addClass( 'fixedHeader-locked' ) 30210 .css( 'top', position.tfootTop - position.theadHeight ) 30211 .css( 'left', position.left+'px' ) 30212 .css( 'width', position.width+'px' ); 30213 } 30214 else if ( mode === 'above' ) { // only used for the footer 30215 // Fix the position of the floating footer at top of the table body 30216 this._clone( item, forceChange ); 30217 30218 itemDom.floating 30219 .addClass( 'fixedHeader-locked' ) 30220 .css( 'top', position.tbodyTop ) 30221 .css( 'left', position.left+'px' ) 30222 .css( 'width', position.width+'px' ); 30223 } 30224 30225 // Restore focus if it was lost 30226 if ( focus && focus !== document.activeElement ) { 30227 setTimeout( function () { 30228 focus.focus(); 30229 }, 10 ); 30230 } 30231 30232 this.s.scrollLeft.header = -1; 30233 this.s.scrollLeft.footer = -1; 30234 this.s[item+'Mode'] = mode; 30235 }, 30236 30237 /** 30238 * Cache the positional information that is required for the mode 30239 * calculations that FixedHeader performs. 30240 * 30241 * @private 30242 */ 30243 _positions: function () 30244 { 30245 var dt = this.s.dt; 30246 var table = dt.table(); 30247 var position = this.s.position; 30248 var dom = this.dom; 30249 var tableNode = $(table.node()); 30250 30251 // Need to use the header and footer that are in the main table, 30252 // regardless of if they are clones, since they hold the positions we 30253 // want to measure from 30254 var thead = tableNode.children('thead'); 30255 var tfoot = tableNode.children('tfoot'); 30256 var tbody = dom.tbody; 30257 30258 position.visible = tableNode.is(':visible'); 30259 position.width = tableNode.outerWidth(); 30260 position.left = tableNode.offset().left; 30261 position.theadTop = thead.offset().top; 30262 position.tbodyTop = tbody.offset().top; 30263 position.theadHeight = position.tbodyTop - position.theadTop; 30264 30265 if ( tfoot.length ) { 30266 position.tfootTop = tfoot.offset().top; 30267 position.tfootBottom = position.tfootTop + tfoot.outerHeight(); 30268 position.tfootHeight = position.tfootBottom - position.tfootTop; 30269 } 30270 else { 30271 position.tfootTop = position.tbodyTop + tbody.outerHeight(); 30272 position.tfootBottom = position.tfootTop; 30273 position.tfootHeight = position.tfootTop; 30274 } 30275 }, 30276 30277 30278 /** 30279 * Mode calculation - determine what mode the fixed items should be placed 30280 * into. 30281 * 30282 * @param {boolean} forceChange Force a redraw of the mode, even if already 30283 * in that mode. 30284 * @private 30285 */ 30286 _scroll: function ( forceChange ) 30287 { 30288 var windowTop = $(document).scrollTop(); 30289 var windowLeft = $(document).scrollLeft(); 30290 var position = this.s.position; 30291 var headerMode, footerMode; 30292 30293 if ( ! this.s.enable ) { 30294 return; 30295 } 30296 30297 if ( this.c.header ) { 30298 if ( ! position.visible || windowTop <= position.theadTop - this.c.headerOffset ) { 30299 headerMode = 'in-place'; 30300 } 30301 else if ( windowTop <= position.tfootTop - position.theadHeight - this.c.headerOffset ) { 30302 headerMode = 'in'; 30303 } 30304 else { 30305 headerMode = 'below'; 30306 } 30307 30308 if ( forceChange || headerMode !== this.s.headerMode ) { 30309 this._modeChange( headerMode, 'header', forceChange ); 30310 } 30311 30312 this._horizontal( 'header', windowLeft ); 30313 } 30314 30315 if ( this.c.footer && this.dom.tfoot.length ) { 30316 if ( ! position.visible || windowTop + position.windowHeight >= position.tfootBottom + this.c.footerOffset ) { 30317 footerMode = 'in-place'; 30318 } 30319 else if ( position.windowHeight + windowTop > position.tbodyTop + position.tfootHeight + this.c.footerOffset ) { 30320 footerMode = 'in'; 30321 } 30322 else { 30323 footerMode = 'above'; 30324 } 30325 30326 if ( forceChange || footerMode !== this.s.footerMode ) { 30327 this._modeChange( footerMode, 'footer', forceChange ); 30328 } 30329 30330 this._horizontal( 'footer', windowLeft ); 30331 } 30332 } 30333} ); 30334 30335 30336/** 30337 * Version 30338 * @type {String} 30339 * @static 30340 */ 30341FixedHeader.version = "3.1.4"; 30342 30343/** 30344 * Defaults 30345 * @type {Object} 30346 * @static 30347 */ 30348FixedHeader.defaults = { 30349 header: true, 30350 footer: false, 30351 headerOffset: 0, 30352 footerOffset: 0 30353}; 30354 30355 30356/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 30357 * DataTables interfaces 30358 */ 30359 30360// Attach for constructor access 30361$.fn.dataTable.FixedHeader = FixedHeader; 30362$.fn.DataTable.FixedHeader = FixedHeader; 30363 30364 30365// DataTables creation - check if the FixedHeader option has been defined on the 30366// table and if so, initialise 30367$(document).on( 'init.dt.dtfh', function (e, settings, json) { 30368 if ( e.namespace !== 'dt' ) { 30369 return; 30370 } 30371 30372 var init = settings.oInit.fixedHeader; 30373 var defaults = DataTable.defaults.fixedHeader; 30374 30375 if ( (init || defaults) && ! settings._fixedHeader ) { 30376 var opts = $.extend( {}, defaults, init ); 30377 30378 if ( init !== false ) { 30379 new FixedHeader( settings, opts ); 30380 } 30381 } 30382} ); 30383 30384// DataTables API methods 30385DataTable.Api.register( 'fixedHeader()', function () {} ); 30386 30387DataTable.Api.register( 'fixedHeader.adjust()', function () { 30388 return this.iterator( 'table', function ( ctx ) { 30389 var fh = ctx._fixedHeader; 30390 30391 if ( fh ) { 30392 fh.update(); 30393 } 30394 } ); 30395} ); 30396 30397DataTable.Api.register( 'fixedHeader.enable()', function ( flag ) { 30398 return this.iterator( 'table', function ( ctx ) { 30399 var fh = ctx._fixedHeader; 30400 30401 flag = ( flag !== undefined ? flag : true ); 30402 if ( fh && flag !== fh.s.enable ) { 30403 fh.enable( flag ); 30404 } 30405 } ); 30406} ); 30407 30408DataTable.Api.register( 'fixedHeader.disable()', function ( ) { 30409 return this.iterator( 'table', function ( ctx ) { 30410 var fh = ctx._fixedHeader; 30411 30412 if ( fh && fh.s.enable ) { 30413 fh.enable( false ); 30414 } 30415 } ); 30416} ); 30417 30418$.each( ['header', 'footer'], function ( i, el ) { 30419 DataTable.Api.register( 'fixedHeader.'+el+'Offset()', function ( offset ) { 30420 var ctx = this.context; 30421 30422 if ( offset === undefined ) { 30423 return ctx.length && ctx[0]._fixedHeader ? 30424 ctx[0]._fixedHeader[el +'Offset']() : 30425 undefined; 30426 } 30427 30428 return this.iterator( 'table', function ( ctx ) { 30429 var fh = ctx._fixedHeader; 30430 30431 if ( fh ) { 30432 fh[ el +'Offset' ]( offset ); 30433 } 30434 } ); 30435 } ); 30436} ); 30437 30438 30439return FixedHeader; 30440})); 30441 30442 30443/*! Responsive 2.2.2 30444 * 2014-2018 SpryMedia Ltd - datatables.net/license 30445 */ 30446 30447/** 30448 * @summary Responsive 30449 * @description Responsive tables plug-in for DataTables 30450 * @version 2.2.2 30451 * @file dataTables.responsive.js 30452 * @author SpryMedia Ltd (www.sprymedia.co.uk) 30453 * @contact www.sprymedia.co.uk/contact 30454 * @copyright Copyright 2014-2018 SpryMedia Ltd. 30455 * 30456 * This source file is free software, available under the following license:
30457 * MIT license - http://datatables.net/license/mit 30458 * 30459 * This source file is distributed in the hope that it will be useful, but 30460 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 30461 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. 30462 * 30463 * For details please refer to: http://www.datatables.net 30464 */ 30465(function( factory ){ 30466 if ( typeof define === 'function' && define.amd ) { 30467 // AMD 30468 define( ['jquery', 'datatables.net'], function ( $ ) { 30469 return factory( $, window, document ); 30470 } ); 30471 } 30472 else if ( typeof exports === 'object' ) { 30473 // CommonJS 30474 module.exports = function (root, $) { 30475 if ( ! root ) { 30476 root = window; 30477 } 30478 30479 if ( ! $ || ! $.fn.dataTable ) { 30480 $ = require('datatables.net')(root, $).$; 30481 } 30482 30483 return factory( $, root, root.document ); 30484 }; 30485 } 30486 else { 30487 // Browser 30488 factory( jQuery, window, document ); 30489 } 30490}(function( $, window, document, undefined ) { 30491'use strict'; 30492var DataTable = $.fn.dataTable; 30493 30494 30495/** 30496 * Responsive is a plug-in for the DataTables library that makes use of 30497 * DataTables' ability to change the visibility of columns, changing the 30498 * visibility of columns so the displayed columns fit into the table container. 30499 * The end result is that complex tables will be dynamically adjusted to fit 30500 * into the viewport, be it on a desktop, tablet or mobile browser. 30501 * 30502 * Responsive for DataTables has two modes of operation, which can used 30503 * individually or combined: 30504 * 30505 * * Class name based control - columns assigned class names that match the 30506 * breakpoint logic can be shown / hidden as required for each breakpoint. 30507 * * Automatic control - columns are automatically hidden when there is no 30508 * room left to display them. Columns removed from the right. 30509 * 30510 * In additional to column visibility control, Responsive also has built into 30511 * options to use DataTables' child row display to show / hide the information 30512 * from the table that has been hidden. There are also two modes of operation 30513 * for this child row display: 30514 * 30515 * * Inline - when the control element that the user can use to show / hide 30516 * child rows is displayed inside the first column of the table. 30517 * * Column - where a whole column is dedicated to be the show / hide control. 30518 * 30519 * Initialisation of Responsive is performed by: 30520 * 30521 * * Adding the class `responsive` or `dt-responsive` to the table. In this case 30522 * Responsive will automatically be initialised with the default configuration 30523 * options when the DataTable is created. 30524 * * Using the `responsive` option in the DataTables configuration options. This 30525 * can also be used to specify the configuration options, or simply set to 30526 * `true` to use the defaults. 30527 * 30528 * @class 30529 * @param {object} settings DataTables settings object for the host table 30530 * @param {object} [opts] Configuration options 30531 * @requires jQuery 1.7+ 30532 * @requires DataTables 1.10.3+ 30533 * 30534 * @example 30535 * $('#example').DataTable( { 30536 * responsive: true 30537 * } ); 30538 * } ); 30539 */ 30540var Responsive = function ( settings, opts ) { 30541 // Sanity check that we are using DataTables 1.10 or newer 30542 if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.10' ) ) { 30543 throw 'DataTables Responsive requires DataTables 1.10.10 or newer'; 30544 } 30545 30546 this.s = { 30547 dt: new DataTable.Api( settings ), 30548 columns: [], 30549 current: [] 30550 }; 30551 30552 // Check if responsive has already been initialised on this table 30553 if ( this.s.dt.settings()[0].responsive ) { 30554 return; 30555 } 30556 30557 // details is an object, but for simplicity the user can give it as a string 30558 // or a boolean 30559 if ( opts && typeof opts.details === 'string' ) { 30560 opts.details = { type: opts.details }; 30561 } 30562 else if ( opts && opts.details === false ) { 30563 opts.details = { type: false }; 30564 } 30565 else if ( opts && opts.details === true ) { 30566 opts.details = { type: 'inline' }; 30567 } 30568 30569 this.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts ); 30570 settings.responsive = this; 30571 this._constructor(); 30572}; 30573 30574$.extend( Responsive.prototype, { 30575 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 30576 * Constructor 30577 */ 30578 30579 /** 30580 * Initialise the Responsive instance 30581 * 30582 * @private 30583 */ 30584 _constructor: function () 30585 { 30586 var that = this; 30587 var dt = this.s.dt; 30588 var dtPrivateSettings = dt.settings()[0]; 30589 var oldWindowWidth = $(window).width(); 30590 30591 dt.settings()[0]._responsive = this; 30592 30593 // Use DataTables' throttle function to avoid processor thrashing on 30594 // resize 30595 $(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () { 30596 // iOS has a bug whereby resize can fire when only scrolling 30597 // See: http://stackoverflow.com/questions/8898412 30598 var width = $(window).width(); 30599 30600 if ( width !== oldWindowWidth ) { 30601 that._resize(); 30602 oldWindowWidth = width; 30603 } 30604 } ) ); 30605 30606 // DataTables doesn't currently trigger an event when a row is added, so 30607 // we need to hook into its private API to enforce the hidden rows when 30608 // new data is added 30609 dtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) { 30610 if ( $.inArray( false, that.s.current ) !== -1 ) { 30611 $('>td, >th', tr).each( function ( i ) { 30612 var idx = dt.column.index( 'toData', i ); 30613 30614 if ( that.s.current[idx] === false ) { 30615 $(this).css('display', 'none'); 30616 } 30617 } ); 30618 } 30619 } ); 30620 30621 // Destroy event handler 30622 dt.on( 'destroy.dtr', function () { 30623 dt.off( '.dtr' ); 30624 $( dt.table().body() ).off( '.dtr' ); 30625 $(window).off( 'resize.dtr orientationchange.dtr' ); 30626 30627 // Restore the columns that we've hidden
30628 $.each( that.s.current, function ( i, val ) { 30629 if ( val === false ) { 30630 that._setColumnVis( i, true ); 30631 } 30632 } ); 30633 } ); 30634 30635 // Reorder the breakpoints array here in case they have been added out 30636 // of order 30637 this.c.breakpoints.sort( function (a, b) { 30638 return a.width < b.width ? 1 : 30639 a.width > b.width ? -1 : 0; 30640 } ); 30641 30642 this._classLogic(); 30643 this._resizeAuto(); 30644 30645 // Details handler 30646 var details = this.c.details; 30647 30648 if ( details.type !== false ) { 30649 that._detailsInit(); 30650 30651 // DataTables will trigger this event on every column it shows and 30652 // hides individually 30653 dt.on( 'column-visibility.dtr', function () { 30654 // Use a small debounce to allow multiple columns to be set together 30655 if ( that._timer ) { 30656 clearTimeout( that._timer ); 30657 } 30658 30659 that._timer = setTimeout( function () { 30660 that._timer = null; 30661 30662 that._classLogic(); 30663 that._resizeAuto(); 30664 that._resize(); 30665 30666 that._redrawChildren(); 30667 }, 100 ); 30668 } ); 30669 30670 // Redraw the details box on each draw which will happen if the data 30671 // has changed. This is used until DataTables implements a native 30672 // `updated` event for rows 30673 dt.on( 'draw.dtr', function () { 30674 that._redrawChildren(); 30675 } ); 30676 30677 $(dt.table().node()).addClass( 'dtr-'+details.type ); 30678 } 30679 30680 dt.on( 'column-reorder.dtr', function (e, settings, details) { 30681 that._classLogic(); 30682 that._resizeAuto(); 30683 that._resize(); 30684 } ); 30685 30686 // Change in column sizes means we need to calc 30687 dt.on( 'column-sizing.dtr', function () { 30688 that._resizeAuto(); 30689 that._resize(); 30690 }); 30691 30692 // On Ajax reload we want to reopen any child rows which are displayed 30693 // by responsive 30694 dt.on( 'preXhr.dtr', function () { 30695 var rowIds = []; 30696 dt.rows().every( function () { 30697 if ( this.child.isShown() ) { 30698 rowIds.push( this.id(true) ); 30699 } 30700 } ); 30701 30702 dt.one( 'draw.dtr', function () { 30703 that._resizeAuto(); 30704 that._resize(); 30705 30706 dt.rows( rowIds ).every( function () { 30707 that._detailsDisplay( this, false ); 30708 } ); 30709 } ); 30710 }); 30711 30712 dt.on( 'init.dtr', function (e, settings, details) { 30713 that._resizeAuto(); 30714 that._resize(); 30715 30716 // If columns were hidden, then DataTables needs to adjust the 30717 // column sizing 30718 if ( $.inArray( false, that.s.current ) ) { 30719 dt.columns.adjust(); 30720 } 30721 } ); 30722 30723 // First pass - draw the table for the current viewport size 30724 this._resize(); 30725 }, 30726 30727 30728 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 30729 * Private methods 30730 */ 30731 30732 /** 30733 * Calculate the visibility for the columns in a table for a given 30734 * breakpoint. The result is pre-determined based on the class logic if 30735 * class names are used to control all columns, but the width of the table 30736 * is also used if there are columns which are to be automatically shown 30737 * and hidden. 30738 * 30739 * @param {string} breakpoint Breakpoint name to use for the calculation 30740 * @return {array} Array of boolean values initiating the visibility of each 30741 * column. 30742 * @private 30743 */ 30744 _columnsVisiblity: function ( breakpoint ) 30745 { 30746 var dt = this.s.dt; 30747 var columns = this.s.columns; 30748 var i, ien; 30749 30750 // Create an array that defines the column ordering based first on the 30751 // column's priority, and secondly the column index. This allows the 30752 // columns to be removed from the right if the priority matches 30753 var order = columns 30754 .map( function ( col, idx ) { 30755 return { 30756 columnIdx: idx, 30757 priority: col.priority 30758 }; 30759 } ) 30760 .sort( function ( a, b ) { 30761 if ( a.priority !== b.priority ) { 30762 return a.priority - b.priority; 30763 } 30764 return a.columnIdx - b.columnIdx; 30765 } ); 30766 30767 // Class logic - determine which columns are in this breakpoint based 30768 // on the classes. If no class control (i.e. `auto`) then `-` is used 30769 // to indicate this to the rest of the function 30770 var display = $.map( columns, function ( col, i ) { 30771 if ( dt.column(i).visible() === false ) { 30772 return 'not-visible'; 30773 } 30774 return col.auto && col.minWidth === null ? 30775 false : 30776 col.auto === true ? 30777 '-' : 30778 $.inArray( breakpoint, col.includeIn ) !== -1; 30779 } ); 30780 30781 // Auto column control - first pass: how much width is taken by the 30782 // ones that must be included from the non-auto columns 30783 var requiredWidth = 0; 30784 for ( i=0, ien=display.length ; i<ien ; i++ ) { 30785 if ( display[i] === true ) { 30786 requiredWidth += columns[i].minWidth; 30787 } 30788 } 30789 30790 // Second pass, use up any remaining width for other columns. For 30791 // scrolling tables we need to subtract the width of the scrollbar. It
30792 // may not be requires which makes this sub-optimal, but it would 30793 // require another full redraw to make complete use of those extra few 30794 // pixels 30795 var scrolling = dt.settings()[0].oScroll; 30796 var bar = scrolling.sY || scrolling.sX ? scrolling.iBarWidth : 0; 30797 var widthAvailable = dt.table().container().offsetWidth - bar; 30798 var usedWidth = widthAvailable - requiredWidth; 30799 30800 // Control column needs to always be included. This makes it sub- 30801 // optimal in terms of using the available with, but to stop layout 30802 // thrashing or overflow. Also we need to account for the control column 30803 // width first so we know how much width is available for the other 30804 // columns, since the control column might not be the first one shown 30805 for ( i=0, ien=display.length ; i<ien ; i++ ) { 30806 if ( columns[i].control ) { 30807 usedWidth -= columns[i].minWidth; 30808 } 30809 } 30810 30811 // Allow columns to be shown (counting by priority and then right to 30812 // left) until we run out of room 30813 var empty = false; 30814 for ( i=0, ien=order.length ; i<ien ; i++ ) { 30815 var colIdx = order[i].columnIdx; 30816 30817 if ( display[colIdx] === '-' && ! columns[colIdx].control && columns[colIdx].minWidth ) { 30818 // Once we've found a column that won't fit we don't let any 30819 // others display either, or columns might disappear in the 30820 // middle of the table 30821 if ( empty || usedWidth - columns[colIdx].minWidth < 0 ) { 30822 empty = true; 30823 display[colIdx] = false; 30824 } 30825 else { 30826 display[colIdx] = true; 30827 } 30828 30829 usedWidth -= columns[colIdx].minWidth; 30830 } 30831 } 30832 30833 // Determine if the 'control' column should be shown (if there is one). 30834 // This is the case when there is a hidden column (that is not the 30835 // control column). The two loops look inefficient here, but they are 30836 // trivial and will fly through. We need to know the outcome from the 30837 // first , before the action in the second can be taken 30838 var showControl = false; 30839 30840 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 30841 if ( ! columns[i].control && ! columns[i].never && display[i] === false ) { 30842 showControl = true; 30843 break; 30844 } 30845 } 30846 30847 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 30848 if ( columns[i].control ) { 30849 display[i] = showControl; 30850 } 30851 30852 // Replace not visible string with false from the control column detection above 30853 if ( display[i] === 'not-visible' ) { 30854 display[i] = false; 30855 } 30856 } 30857 30858 // Finally we need to make sure that there is at least one column that 30859 // is visible 30860 if ( $.inArray( true, display ) === -1 ) { 30861 display[0] = true; 30862 } 30863
30864 return display; 30865 }, 30866 30867 30868 /** 30869 * Create the internal `columns` array with information about the columns 30870 * for the table. This includes determining which breakpoints the column 30871 * will appear in, based upon class names in the column, which makes up the 30872 * vast majority of this method. 30873 * 30874 * @private 30875 */ 30876 _classLogic: function () 30877 { 30878 var that = this; 30879 var calc = {}; 30880 var breakpoints = this.c.breakpoints; 30881 var dt = this.s.dt; 30882 var columns = dt.columns().eq(0).map( function (i) { 30883 var column = this.column(i); 30884 var className = column.header().className; 30885 var priority = dt.settings()[0].aoColumns[i].responsivePriority; 30886 30887 if ( priority === undefined ) { 30888 var dataPriority = $(column.header()).data('priority'); 30889 30890 priority = dataPriority !== undefined ? 30891 dataPriority * 1 : 30892 10000; 30893 } 30894 30895 return { 30896 className: className, 30897 includeIn: [], 30898 auto: false, 30899 control: false, 30900 never: className.match(/\bnever\b/) ? true : false, 30901 priority: priority 30902 }; 30903 } ); 30904 30905 // Simply add a breakpoint to `includeIn` array, ensuring that there are 30906 // no duplicates 30907 var add = function ( colIdx, name ) { 30908 var includeIn = columns[ colIdx ].includeIn; 30909 30910 if ( $.inArray( name, includeIn ) === -1 ) { 30911 includeIn.push( name ); 30912 } 30913 }; 30914 30915 var column = function ( colIdx, name, operator, matched ) { 30916 var size, i, ien; 30917 30918 if ( ! operator ) { 30919 columns[ colIdx ].includeIn.push( name ); 30920 } 30921 else if ( operator === 'max-' ) { 30922 // Add this breakpoint and all smaller 30923 size = that._find( name ).width; 30924 30925 for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) { 30926 if ( breakpoints[i].width <= size ) { 30927 add( colIdx, breakpoints[i].name ); 30928 } 30929 } 30930 } 30931 else if ( operator === 'min-' ) { 30932 // Add this breakpoint and all larger 30933 size = that._find( name ).width; 30934 30935 for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) { 30936 if ( breakpoints[i].width >= size ) { 30937 add( colIdx, breakpoints[i].name ); 30938 } 30939 } 30940 } 30941 else if ( operator === 'not-' ) { 30942 // Add all but this breakpoint 30943 for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) { 30944 if ( breakpoints[i].name.indexOf( matched ) === -1 ) { 30945 add( colIdx, breakpoints[i].name ); 30946 } 30947 } 30948 } 30949 }; 30950 30951 // Loop over each column and determine if it has a responsive control 30952 // class 30953 columns.each( function ( col, i ) { 30954 var classNames = col.className.split(' '); 30955 var hasClass = false; 30956 30957 // Split the class name up so multiple rules can be applied if needed 30958 for ( var k=0, ken=classNames.length ; k<ken ; k++ ) { 30959 var className = $.trim( classNames[k] ); 30960 30961 if ( className === 'all' ) { 30962 // Include in all 30963 hasClass = true; 30964 col.includeIn = $.map( breakpoints, function (a) { 30965 return a.name; 30966 } ); 30967 return; 30968 } 30969 else if ( className === 'none' || col.never ) { 30970 // Include in none (default) and no auto 30971 hasClass = true; 30972 return; 30973 } 30974 else if ( className === 'control' ) { 30975 // Special column that is only visible, when one of the other 30976 // columns is hidden. This is used for the details control 30977 hasClass = true; 30978 col.control = true; 30979 return; 30980 } 30981 30982 $.each( breakpoints, function ( j, breakpoint ) { 30983 // Does this column have a class that matches this breakpoint? 30984 var brokenPoint = breakpoint.name.split('-'); 30985 var re = new RegExp( '(min\\-|max\\-|not\\-)?('+brokenPoint[0]+')(\\-[_a-zA-Z0-9])?' ); 30986 var match = className.match( re ); 30987 30988 if ( match ) { 30989 hasClass = true; 30990 30991 if ( match[2] === brokenPoint[0] && match[3] === '-'+brokenPoint[1] ) { 30992 // Class name matches breakpoint name fully 30993 column( i, breakpoint.name, match[1], match[2]+match[3] ); 30994 } 30995 else if ( match[2] === brokenPoint[0] && ! match[3] ) { 30996 // Class name matched primary breakpoint name with no qualifier 30997 column( i, breakpoint.name, match[1], match[2] ); 30998 } 30999 } 31000 } ); 31001 } 31002 31003 // If there was no control class, then automatic sizing is used 31004 if ( ! hasClass ) { 31005 col.auto = true; 31006 } 31007 } ); 31008 31009 this.s.columns = columns; 31010 }, 31011 31012 31013 /** 31014 * Show the details for the child row 31015 * 31016 * @param {DataTables.Api} row API instance for the row 31017 * @param {boolean} update Update flag 31018 * @private 31019 */ 31020 _detailsDisplay: function ( row, update ) 31021 { 31022 var that = this; 31023 var dt = this.s.dt; 31024 var details = this.c.details; 31025 31026 if ( details && details.type !== false ) { 31027 var res = details.display( row, update, function () { 31028 return details.renderer( 31029 dt, row[0], that._detailsObj(row[0]) 31030 ); 31031 } ); 31032 31033 if ( res === true || res === false ) { 31034 $(dt.table().node()).triggerHandler( 'responsive-display.dt', [dt, row, res, update] ); 31035 } 31036 } 31037 }, 31038 31039 31040 /** 31041 * Initialisation for the details handler 31042 * 31043 * @private 31044 */ 31045 _detailsInit: function () 31046 { 31047 var that = this; 31048 var dt = this.s.dt; 31049 var details = this.c.details; 31050 31051 // The inline type always uses the first child as the target 31052 if ( details.type === 'inline' ) { 31053 details.target = 'td:first-child, th:first-child'; 31054 } 31055 31056 // Keyboard accessibility 31057 dt.on( 'draw.dtr', function () { 31058 that._tabIndexes(); 31059 } ); 31060 that._tabIndexes(); // Initial draw has already happened 31061 31062 $( dt.table().body() ).on( 'keyup.dtr', 'td, th', function (e) { 31063 if ( e.keyCode === 13 && $(this).data('dtr-keyboard') ) { 31064 $(this).click(); 31065 } 31066 } ); 31067 31068 // type.target can be a string jQuery selector or a column index 31069 var target = details.target; 31070 var selector = typeof target === 'string' ? target : 'td, th'; 31071 31072 // Click handler to show / hide the details rows when they are available 31073 $( dt.table().body() ) 31074 .on( 'click.dtr mousedown.dtr mouseup.dtr', selector, function (e) { 31075 // If the table is not collapsed (i.e. there is no hidden columns) 31076 // then take no action 31077 if ( ! $(dt.table().node()).hasClass('collapsed' ) ) { 31078 return; 31079 } 31080 31081 // Check that the row is actually a DataTable's controlled node 31082 if ( $.inArray( $(this).closest('tr').get(0), dt.rows().nodes().toArray() ) === -1 ) { 31083 return; 31084 } 31085 31086 // For column index, we determine if we should act or not in the 31087 // handler - otherwise it is already okay 31088 if ( typeof target === 'number' ) { 31089 var targetIdx = target < 0 ? 31090 dt.columns().eq(0).length + target : 31091 target; 31092 31093 if ( dt.cell( this ).index().column !== targetIdx ) { 31094 return; 31095 } 31096 } 31097
31098 // $().closest() includes itself in its check 31099 var row = dt.row( $(this).closest('tr') ); 31100 31101 // Check event type to do an action 31102 if ( e.type === 'click' ) { 31103 // The renderer is given as a function so the caller can execute it 31104 // only when they need (i.e. if hiding there is no point is running 31105 // the renderer) 31106 that._detailsDisplay( row, false ); 31107 } 31108 else if ( e.type === 'mousedown' ) { 31109 // For mouse users, prevent the focus ring from showing 31110 $(this).css('outline', 'none'); 31111 } 31112 else if ( e.type === 'mouseup' ) { 31113 // And then re-allow at the end of the click 31114 $(this).blur().css('outline', ''); 31115 } 31116 } ); 31117 }, 31118 31119 31120 /** 31121 * Get the details to pass to a renderer for a row 31122 * @param {int} rowIdx Row index 31123 * @private 31124 */ 31125 _detailsObj: function ( rowIdx ) 31126 { 31127 var that = this; 31128 var dt = this.s.dt; 31129 31130 return $.map( this.s.columns, function( col, i ) { 31131 // Never and control columns should not be passed to the renderer 31132 if ( col.never || col.control ) { 31133 return; 31134 } 31135 31136 return { 31137 title: dt.settings()[0].aoColumns[ i ].sTitle, 31138 data: dt.cell( rowIdx, i ).render( that.c.orthogonal ), 31139 hidden: dt.column( i ).visible() && !that.s.current[ i ], 31140 columnIndex: i, 31141 rowIndex: rowIdx 31142 }; 31143 } ); 31144 }, 31145 31146 31147 /** 31148 * Find a breakpoint object from a name 31149 * 31150 * @param {string} name Breakpoint name to find 31151 * @return {object} Breakpoint description object 31152 * @private 31153 */ 31154 _find: function ( name ) 31155 { 31156 var breakpoints = this.c.breakpoints; 31157 31158 for ( var i=0, ien=breakpoints.length ; i<ien ; i++ ) { 31159 if ( breakpoints[i].name === name ) { 31160 return breakpoints[i]; 31161 } 31162 } 31163 }, 31164 31165 31166 /** 31167 * Re-create the contents of the child rows as the display has changed in 31168 * some way. 31169 * 31170 * @private 31171 */ 31172 _redrawChildren: function () 31173 { 31174 var that = this; 31175 var dt = this.s.dt; 31176 31177 dt.rows( {page: 'current'} ).iterator( 'row', function ( settings, idx ) { 31178 var row = dt.row( idx ); 31179 31180 that._detailsDisplay( dt.row( idx ), true ); 31181 } ); 31182 }, 31183 31184 31185 /** 31186 * Alter the table display for a resized viewport. This involves first 31187 * determining what breakpoint the window currently is in, getting the 31188 * column visibilities to apply and then setting them. 31189 * 31190 * @private 31191 */ 31192 _resize: function () 31193 { 31194 var that = this; 31195 var dt = this.s.dt; 31196 var width = $(window).width(); 31197 var breakpoints = this.c.breakpoints; 31198 var breakpoint = breakpoints[0].name; 31199 var columns = this.s.columns; 31200 var i, ien; 31201 var oldVis = this.s.current.slice(); 31202 31203 // Determine what breakpoint we are currently at 31204 for ( i=breakpoints.length-1 ; i>=0 ; i-- ) { 31205 if ( width <= breakpoints[i].width ) { 31206 breakpoint = breakpoints[i].name; 31207 break; 31208 } 31209 } 31210 31211 // Show the columns for that break point 31212 var columnsVis = this._columnsVisiblity( breakpoint ); 31213 this.s.current = columnsVis; 31214 31215 // Set the class before the column visibility is changed so event 31216 // listeners know what the state is. Need to determine if there are 31217 // any columns that are not visible but can be shown 31218 var collapsedClass = false; 31219 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 31220 if ( columnsVis[i] === false && ! columns[i].never && ! columns[i].control && ! dt.column(i).visible() === false ) { 31221 collapsedClass = true; 31222 break; 31223 } 31224 } 31225 31226 $( dt.table().node() ).toggleClass( 'collapsed', collapsedClass ); 31227 31228 var changed = false; 31229 var visible = 0; 31230 31231 dt.columns().eq(0).each( function ( colIdx, i ) { 31232 if ( columnsVis[i] === true ) { 31233 visible++; 31234 } 31235 31236 if ( columnsVis[i] !== oldVis[i] ) { 31237 changed = true; 31238 that._setColumnVis( colIdx, columnsVis[i] ); 31239 } 31240 } ); 31241 31242 if ( changed ) { 31243 this._redrawChildren(); 31244 31245 // Inform listeners of the change 31246 $(dt.table().node()).trigger( 'responsive-resize.dt', [dt, this.s.current] ); 31247 31248 // If no records, update the "No records" display element 31249 if ( dt.page.info().recordsDisplay === 0 ) { 31250 $('td', dt.table().body()).eq(0).attr('colspan', visible); 31251 } 31252 } 31253 }, 31254 31255 31256 /** 31257 * Determine the width of each column in the table so the auto column hiding 31258 * has that information to work with. This method is never going to be 100% 31259 * perfect since column widths can change slightly per page, but without 31260 * seriously compromising performance this is quite effective. 31261 * 31262 * @private 31263 */ 31264 _resizeAuto: function () 31265 { 31266 var dt = this.s.dt; 31267 var columns = this.s.columns; 31268 31269 // Are we allowed to do auto sizing? 31270 if ( ! this.c.auto ) { 31271 return; 31272 } 31273 31274 // Are there any columns that actually need auto-sizing, or do they all 31275 // have classes defined 31276 if ( $.inArray( true, $.map( columns, function (c) { return c.auto; }
31276 ) ) === -1 ) { 31277 return; 31278 } 31279 31280 // Need to restore all children. They will be reinstated by a re-render 31281 if ( ! $.isEmptyObject( _childNodeStore ) ) { 31282 $.each( _childNodeStore, function ( key ) { 31283 var idx = key.split('-'); 31284 31285 _childNodesRestore( dt, idx[0]*1, idx[1]*1 ); 31286 } ); 31287 } 31288 31289 // Clone the table with the current data in it 31290 var tableWidth = dt.table().node().offsetWidth; 31291 var columnWidths = dt.columns; 31292 var clonedTable = dt.table().node().cloneNode( false ); 31293 var clonedHeader = $( dt.table().header().cloneNode( false ) ).appendTo( clonedTable ); 31294 var clonedBody = $( dt.table().body() ).clone( false, false ).empty().appendTo( clonedTable ); // use jQuery because of IE8 31295 31296 // Header 31297 var headerCells = dt.columns() 31298 .header() 31299 .filter( function (idx) { 31300 return dt.column(idx).visible(); 31301 } ) 31302 .to$() 31303 .clone( false ) 31304 .css( 'display', 'table-cell' ) 31305 .css( 'min-width', 0 ); 31306 31307 // Body rows - we don't need to take account of DataTables' column 31308 // visibility since we implement our own here (hence the `display` set) 31309 $(clonedBody) 31310 .append( $(dt.rows( { page: 'current' } ).nodes()).clone( false ) ) 31311 .find( 'th, td' ).css( 'display', '' ); 31312 31313 // Footer 31314 var footer = dt.table().footer(); 31315 if ( footer ) { 31316 var clonedFooter = $( footer.cloneNode( false ) ).appendTo( clonedTable ); 31317 var footerCells = dt.columns() 31318 .footer() 31319 .filter( function (idx) { 31320 return dt.column(idx).visible(); 31321 } ) 31322 .to$() 31323 .clone( false ) 31324 .css( 'display', 'table-cell' ); 31325 31326 $('<tr/>') 31327 .append( footerCells ) 31328 .appendTo( clonedFooter ); 31329 } 31330 31331 $('<tr/>') 31332 .append( headerCells ) 31333 .appendTo( clonedHeader ); 31334 31335 // In the inline case extra padding is applied to the first column to 31336 // give space for the show / hide icon. We need to use this in the 31337 // calculation 31338 if ( this.c.details.type === 'inline' ) { 31339 $(clonedTable).addClass( 'dtr-inline collapsed' ); 31340 } 31341 31342 // It is unsafe to insert elements with the same name into the DOM 31343 // multiple times. For example, cloning and inserting a checked radio 31344 // clears the chcecked state of the original radio. 31345 $( clonedTable ).find( '[name]' ).removeAttr( 'name' ); 31346 31347 // A position absolute table would take the table out of the flow of 31348 // our container element, bypassing the height and width (Scroller) 31349 $( clonedTable ).css( 'position', 'relative' ) 31350 31351 var inserted = $('<div/>') 31352 .css( { 31353 width: 1, 31354 height: 1, 31355 overflow: 'hidden', 31356 clear: 'both' 31357 } ) 31358 .append( clonedTable ); 31359 31360 inserted.insertBefore( dt.table().node() ); 31361 31362 // The cloned header now contains the smallest that each column can be 31363 headerCells.each( function (i) { 31364 var idx = dt.column.index( 'fromVisible', i ); 31365 columns[ idx ].minWidth = this.offsetWidth || 0; 31366 } ); 31367 31368 inserted.remove(); 31369 }, 31370 31371 /** 31372 * Set a column's visibility. 31373 * 31374 * We don't use DataTables' column visibility controls in order to ensure 31375 * that column visibility can Responsive can no-exist. Since only IE8+ is 31376 * supported (and all evergreen browsers of course) the control of the 31377 * display attribute works well. 31378 * 31379 * @param {integer} col Column index 31380 * @param {boolean} showHide Show or hide (true or false) 31381 * @private 31382 */ 31383 _setColumnVis: function ( col, showHide ) 31384 { 31385 var dt = this.s.dt; 31386 var display = showHide ? '' : 'none'; // empty string will remove the attr 31387 31388 $( dt.column( col ).header() ).css( 'display', display ); 31389 $( dt.column( col ).footer() ).css( 'display', display ); 31390 dt.column( col ).nodes().to$().css( 'display', display ); 31391 31392 // If the are child nodes stored, we might need to reinsert them 31393 if ( ! $.isEmptyObject( _childNodeStore ) ) { 31394 dt.cells( null, col ).indexes().each( function (idx) { 31395 _childNodesRestore( dt, idx.row, idx.column ); 31396 } ); 31397 } 31398 }, 31399 31400 31401 /** 31402 * Update the cell tab indexes for keyboard accessibility. This is called on 31403 * every table draw - that is potentially inefficient, but also the least 31404 * complex option given that column visibility can change on the fly. Its a 31405 * shame user-focus was removed from CSS 3 UI, as it would have solved this 31406 * issue with a single CSS statement. 31407 * 31408 * @private 31409 */ 31410 _tabIndexes: function () 31411 { 31412 var dt = this.s.dt; 31413 var cells = dt.cells( { page: 'current' } ).nodes().to$(); 31414 var ctx = dt.settings()[0]; 31415 var target = this.c.details.target; 31416 31417 cells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' ); 31418 31419 if ( typeof target === 'number' ) { 31420 dt.cells( null, target, { page: 'current' } ).nodes().to$() 31421 .attr( 'tabIndex', ctx.iTabIndex ) 31422 .data( 'dtr-keyboard', 1 ); 31423 } 31424 else { 31425 // This is a bit of a hack - we need to limit the selected nodes to just 31426 // those of this table 31427 if ( target === 'td:first-child, th:first-child' ) { 31428 target = '>td:first-child, >th:first-child'; 31429 } 31430 31431 $( target, dt.rows( { page: 'current' } ).nodes() ) 31432 .attr( 'tabIndex', ctx.iTabIndex ) 31433 .data( 'dtr-keyboard', 1 ); 31434 } 31435 } 31436} ); 31437 31438 31439/** 31440 * List of default breakpoints. Each item in the array is an object with two 31441 * properties: 31442 * 31443 * * `name` - the breakpoint name. 31444 * * `width` - the breakpoint width 31445 * 31446 * @name Responsive.breakpoints 31447 * @static 31448 */ 31449Responsive.breakpoints = [ 31450 { name: 'desktop', width: Infinity }, 31451 { name: 'tablet-l', width: 1024 }, 31452 { name: 'tablet-p', width: 768 }, 31453 { name: 'mobile-l', width: 480 }, 31454 { name: 'mobile-p', width: 320 } 31455]; 31456 31457 31458/** 31459 * Display methods - functions which define how the hidden data should be shown 31460 * in the table. 31461 * 31462 * @namespace 31463 * @name Responsive.defaults 31464 * @static 31465 */ 31466Responsive.display = { 31467 childRow: function ( row, update, render ) { 31468 if ( update ) { 31469 if ( $(row.node()).hasClass('parent') ) { 31470 row.child( render(), 'child' ).show(); 31471 31472 return true; 31473 } 31474 } 31475 else { 31476 if ( ! row.child.isShown() ) { 31477 row.child( render(), 'child' ).show(); 31478 $( row.node() ).addClass( 'parent' ); 31479 31480 return true; 31481 } 31482 else { 31483 row.child( false ); 31484 $( row.node() ).removeClass( 'parent' ); 31485 31486 return false;
31487 } 31488 } 31489 }, 31490 31491 childRowImmediate: function ( row, update, render ) { 31492 if ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) { 31493 // User interaction and the row is show, or nothing to show 31494 row.child( false ); 31495 $( row.node() ).removeClass( 'parent' ); 31496 31497 return false; 31498 } 31499 else { 31500 // Display 31501 row.child( render(), 'child' ).show(); 31502 $( row.node() ).addClass( 'parent' ); 31503 31504 return true; 31505 } 31506 }, 31507 31508 // This is a wrapper so the modal options for Bootstrap and jQuery UI can 31509 // have options passed into them. This specific one doesn't need to be a 31510 // function but it is for consistency in the `modal` name 31511 modal: function ( options ) { 31512 return function ( row, update, render ) { 31513 if ( ! update ) { 31514 // Show a modal 31515 var close = function () { 31516 modal.remove(); // will tidy events for us 31517 $(document).off( 'keypress.dtr' ); 31518 }; 31519 31520 var modal = $('<div class="dtr-modal"/>') 31521 .append( $('<div class="dtr-modal-display"/>') 31522 .append( $('<div class="dtr-modal-content"/>') 31523 .append( render() ) 31524 ) 31525 .append( $('<div class="dtr-modal-close">×</div>' ) 31526 .click( function () { 31527 close(); 31528 } ) 31529 ) 31530 ) 31531 .append( $('<div class="dtr-modal-background"/>') 31532 .click( function () { 31533 close(); 31534 } ) 31535 ) 31536 .appendTo( 'body' ); 31537 31538 $(document).on( 'keyup.dtr', function (e) { 31539 if ( e.keyCode === 27 ) { 31540 e.stopPropagation(); 31541 31542 close(); 31543 } 31544 } ); 31545 } 31546 else { 31547 $('div.dtr-modal-content') 31548 .empty() 31549 .append( render() ); 31550 } 31551 31552 if ( options && options.header ) { 31553 $('div.dtr-modal-content').prepend( 31554 '<h2>'+options.header( row )+'</h2>' 31555 ); 31556 } 31557 }; 31558 } 31559}; 31560 31561 31562var _childNodeStore = {}; 31563 31564function _childNodes( dt, row, col ) { 31565 var name = row+'-'+col; 31566 31567 if ( _childNodeStore[ name ] ) { 31568 return _childNodeStore[ name ]; 31569 } 31570 31571 // https://jsperf.com/childnodes-array-slice-vs-loop 31572 var nodes = []; 31573 var children = dt.cell( row, col ).node().childNodes; 31574 for ( var i=0, ien=children.length ; i<ien ; i++ ) { 31575 nodes.push( children[i] ); 31576 } 31577 31578 _childNodeStore[ name ] = nodes; 31579 31580 return nodes; 31581} 31582 31583function _childNodesRestore( dt, row, col ) { 31584 var name = row+'-'+col; 31585 31586 if ( ! _childNodeStore[ name ] ) { 31587 return; 31588 } 31589 31590 var node = dt.cell( row, col ).node(); 31591 var store = _childNodeStore[ name ]; 31592 var parent = store[0].parentNode; 31593 var parentChildren = parent.childNodes; 31594 var a = []; 31595 31596 for ( var i=0, ien=parentChildren.length ; i<ien ; i++ ) { 31597 a.push( parentChildren[i] ); 31598 } 31599 31600 for ( var j=0, jen=a.length ; j<jen ; j++ ) { 31601 node.appendChild( a[j] ); 31602 } 31603 31604 _childNodeStore[ name ] = undefined; 31605} 31606 31607 31608/** 31609 * Display methods - functions which define how the hidden data should be shown 31610 * in the table. 31611 * 31612 * @namespace 31613 * @name Responsive.defaults 31614 * @static 31615 */ 31616Responsive.renderer = { 31617 listHiddenNodes: function () { 31618 return function ( api, rowIdx, columns ) { 31619 var ul = $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>'); 31620 var found = false; 31621 31622 var data = $.each( columns, function ( i, col ) { 31623 if ( col.hidden ) { 31624 $( 31625 '<li data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+ 31626 '<span class="dtr-title">'+ 31627 col.title+ 31628 '</span> '+ 31629 '</li>' 31630 ) 31631 .append( $('<span class="dtr-data"/>').append( _childNodes( api, col.rowIndex, col.columnIndex ) ) )// api.cell( col.rowIndex, col.columnIndex ).node().childNodes ) ) 31632 .appendTo( ul ); 31633 31634 found = true; 31635 } 31636 } ); 31637 31638 return found ? 31639 ul : 31640 false; 31641 }; 31642 }, 31643 31644 listHidden: function () { 31645 return function ( api, rowIdx, columns ) { 31646 var data = $.map( columns, function ( col ) { 31647 return col.hidden ? 31648 '<li data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+ 31649 '<span class="dtr-title">'+ 31650 col.title+ 31651 '</span> '+ 31652 '<span class="dtr-data">'+ 31653 col.data+ 31654 '</span>'+ 31655 '</li>' : 31656 ''; 31657 } ).join(''); 31658 31659 return data ? 31660 $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>').append( data ) : 31661 false; 31662 } 31663 }, 31664 31665 tableAll: function ( options ) { 31666 options = $.extend( { 31667 tableClass: '' 31668 }, options ); 31669 31670 return function ( api, rowIdx, columns ) { 31671 var data = $.map( columns, function ( col ) { 31672 return '<tr data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+ 31673 '<td>'+col.title+':'+'</td> '+ 31674 '<td>'+col.data+'</td>'+ 31675 '</tr>'; 31676 } ).join(''); 31677 31678 return $('<table class="'+options.tableClass+' dtr-details" width="100%"/>').append( data ); 31679 } 31680 } 31681}; 31682 31683/** 31684 * Responsive default settings for initialisation 31685 * 31686 * @namespace 31687 * @name Responsive.defaults 31688 * @static 31689 */ 31690Responsive.defaults = { 31691 /** 31692 * List of breakpoints for the instance. Note that this means that each 31693 * instance can have its own breakpoints. Additionally, the breakpoints 31694 * cannot be changed once an instance has been creased. 31695 * 31696 * @type {Array} 31697 * @default Takes the value of `Responsive.breakpoints` 31698 */ 31699 breakpoints: Responsive.breakpoints, 31700 31701 /** 31702 * Enable / disable auto hiding calculations. It can help to increase 31703 * performance slightly if you disable this option, but all columns would 31704 * need to have breakpoint classes assigned to them 31705 * 31706 * @type {Boolean} 31707 * @default `true` 31708 */ 31709 auto: true, 31710 31711 /** 31712 * Details control. If given as a string value, the `type` property of the 31713 * default object is set to that value, and the defaults used for the rest 31714 * of the object - this is for ease of implementation. 31715 *
31716 * The object consists of the following properties: 31717 * 31718 * * `display` - A function that is used to show and hide the hidden details 31719 * * `renderer` - function that is called for display of the child row data. 31720 * The default function will show the data from the hidden columns 31721 * * `target` - Used as the selector for what objects to attach the child 31722 * open / close to 31723 * * `type` - `false` to disable the details display, `inline` or `column` 31724 * for the two control types 31725 * 31726 * @type {Object|string} 31727 */ 31728 details: { 31729 display: Responsive.display.childRow, 31730 31731 renderer: Responsive.renderer.listHidden(), 31732 31733 target: 0, 31734 31735 type: 'inline' 31736 }, 31737 31738 /** 31739 * Orthogonal data request option. This is used to define the data type 31740 * requested when Responsive gets the data to show in the child row. 31741 * 31742 * @type {String} 31743 */ 31744 orthogonal: 'display' 31745}; 31746 31747 31748/* 31749 * API 31750 */ 31751var Api = $.fn.dataTable.Api; 31752 31753// Doesn't do anything - work around for a bug in DT... Not documented 31754Api.register( 'responsive()', function () { 31755 return this; 31756} ); 31757 31758Api.register( 'responsive.index()', function ( li ) { 31759 li = $(li); 31760 31761 return { 31762 column: li.data('dtr-index'), 31763 row: li.parent().data('dtr-index') 31764 }; 31765} ); 31766 31767Api.register( 'responsive.rebuild()', function () { 31768 return this.iterator( 'table', function ( ctx ) { 31769 if ( ctx._responsive ) { 31770 ctx._responsive._classLogic(); 31771 } 31772 } ); 31773} ); 31774 31775Api.register( 'responsive.recalc()', function () { 31776 return this.iterator( 'table', function ( ctx ) { 31777 if ( ctx._responsive ) { 31778 ctx._responsive._resizeAuto(); 31779 ctx._responsive._resize(); 31780 } 31781 } ); 31782} ); 31783 31784Api.register( 'responsive.hasHidden()', function () { 31785 var ctx = this.context[0]; 31786 31787 return ctx._responsive ? 31788 $.inArray( false, ctx._responsive.s.current ) !== -1 : 31789 false; 31790} ); 31791 31792Api.registerPlural( 'columns().responsiveHidden()', 'column().responsiveHidden()', function () { 31793 return this.iterator( 'column', function ( settings, column ) { 31794 return settings._responsive ? 31795 settings._responsive.s.current[ column ] : 31796 false; 31797 }, 1 ); 31798} ); 31799 31800 31801/** 31802 * Version information 31803 * 31804 * @name Responsive.version 31805 * @static 31806 */ 31807Responsive.version = '2.2.2'; 31808 31809 31810$.fn.dataTable.Responsive = Responsive; 31811$.fn.DataTable.Responsive = Responsive; 31812 31813// Attach a listener to the document which listens for DataTables initialisation 31814// events so we can automatically initialise 31815$(document).on( 'preInit.dt.dtr', function (e, settings, json) { 31816 if ( e.namespace !== 'dt' ) { 31817 return; 31818 } 31819 31820 if ( $(settings.nTable).hasClass( 'responsive' ) || 31821 $(settings.nTable).hasClass( 'dt-responsive' ) || 31822 settings.oInit.responsive || 31823 DataTable.defaults.responsive 31824 ) { 31825 var init = settings.oInit.responsive; 31826 31827 if ( init !== false ) { 31828 new Responsive( settings, $.isPlainObject( init ) ? init : {} ); 31829 } 31830 } 31831} ); 31832 31833 31834return Responsive; 31835})); 31836 31837 31838/*! RowGroup 1.1.0 31839 * ©2017-2018 SpryMedia Ltd - datatables.net/license 31840 */ 31841 31842/** 31843 * @summary RowGroup 31844 * @description RowGrouping for DataTables 31845 * @version 1.1.0 31846 * @file dataTables.rowGroup.js 31847 * @author SpryMedia Ltd (www.sprymedia.co.uk) 31848 * @contact datatables.net 31849 * @copyright Copyright 2017-2018 SpryMedia Ltd. 31850 * 31851 * This source file is free software, available under the following license: 31852 * MIT license - http://datatables.net/license/mit 31853 * 31854 * This source file is distributed in the hope that it will be useful, but 31855 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 31856 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. 31857 * 31858 * For details please refer to: http://www.datatables.net 31859 */ 31860 31861(function( factory ){ 31862 if ( typeof define === 'function' && define.amd ) { 31863 // AMD 31864 define( ['jquery', 'datatables.net'], function ( $ ) { 31865 return factory( $, window, document ); 31866 } ); 31867 } 31868 else if ( typeof exports === 'object' ) { 31869 // CommonJS 31870 module.exports = function (root, $) { 31871 if ( ! root ) { 31872 root = window; 31873 } 31874 31875 if ( ! $ || ! $.fn.dataTable ) { 31876 $ = require('datatables.net')(root, $).$; 31877 } 31878 31879 return factory( $, root, root.document ); 31880 }; 31881 } 31882 else { 31883 // Browser 31884 factory( jQuery, window, document ); 31885 } 31886}(function( $, window, document, undefined ) { 31887'use strict'; 31888var DataTable = $.fn.dataTable; 31889 31890 31891var RowGroup = function ( dt, opts ) { 31892 // Sanity check that we are using DataTables 1.10 or newer
31893 if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) { 31894 throw 'RowGroup requires DataTables 1.10.8 or newer'; 31895 } 31896 31897 // User and defaults configuration object 31898 this.c = $.extend( true, {}, 31899 DataTable.defaults.rowGroup, 31900 RowGroup.defaults, 31901 opts 31902 ); 31903 31904 // Internal settings 31905 this.s = { 31906 dt: new DataTable.Api( dt ) 31907 }; 31908 31909 // DOM items 31910 this.dom = { 31911 31912 }; 31913 31914 // Check if row grouping has already been initialised on this table 31915 var settings = this.s.dt.settings()[0]; 31916 var existing = settings.rowGroup; 31917 if ( existing ) { 31918 return existing; 31919 } 31920 31921 settings.rowGroup = this; 31922 this._constructor(); 31923}; 31924 31925 31926$.extend( RowGroup.prototype, { 31927 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 31928 * API methods for DataTables API interface 31929 */ 31930 31931 /** 31932 * Get/set the grouping data source - need to call draw after this is 31933 * executed as a setter 31934 * @returns string~RowGroup 31935 */ 31936 dataSrc: function ( val ) 31937 { 31938 if ( val === undefined ) { 31939 return this.c.dataSrc; 31940 } 31941 31942 var dt = this.s.dt; 31943 31944 this.c.dataSrc = val; 31945 31946 $(dt.table().node()).triggerHandler( 'rowgroup-datasrc.dt', [ dt, val ] ); 31947 31948 return this; 31949 }, 31950 31951 /** 31952 * Disable - need to call draw after this is executed 31953 * @returns RowGroup 31954 */ 31955 disable: function () 31956 { 31957 this.c.enable = false; 31958 return this; 31959 }, 31960 31961 /** 31962 * Enable - need to call draw after this is executed 31963 * @returns RowGroup 31964 */ 31965 enable: function ( flag ) 31966 { 31967 if ( flag === false ) { 31968 return this.disable(); 31969 } 31970 31971 this.c.enable = true; 31972 return this; 31973 }, 31974 31975 31976 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 31977 * Constructor 31978 */ 31979 _constructor: function () 31980 { 31981 var that = this; 31982 var dt = this.s.dt; 31983 31984 dt.on( 'draw.dtrg', function () { 31985 if ( that.c.enable ) { 31986 that._draw(); 31987 } 31988 } ); 31989 31990 dt.on( 'column-visibility.dt.dtrg responsive-resize.dt.dtrg', function () { 31991 that._adjustColspan(); 31992 } ); 31993 31994 dt.on( 'destroy', function () { 31995 dt.off( '.dtrg' ); 31996 } ); 31997 31998 dt.on('responsive-resize.dt', function () { 31999 that._adjustColspan(); 32000 }) 32001 }, 32002 32003 32004 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 32005 * Private methods 32006 */ 32007 32008 /** 32009 * Adjust column span when column visibility changes 32010 * @private 32011 */ 32012 _adjustColspan: function () 32013 { 32014 $( 'tr.'+this.c.className, this.s.dt.table().body() ).find('td') 32015 .attr( 'colspan', this._colspan() ); 32016 }, 32017 32018 /** 32019 * Get the number of columns that a grouping row should span 32020 * @private 32021 */ 32022 _colspan: function () 32023 { 32024 return this.s.dt.columns().visible().reduce( function (a, b) { 32025 return a + b; 32026 }, 0 ); 32027 }, 32028 32029 32030 /** 32031 * Update function that is called whenever we need to draw the grouping rows. 32032 * This is basically a bootstrap for the self iterative _group and _groupDisplay 32033 * methods 32034 * @private 32035 */ 32036 _draw: function () 32037 { 32038 var dt = this.s.dt; 32039 var groupedRows = this._group( 0, dt.rows( { page: 'current' } ).indexes() ); 32040 32041 this._groupDisplay( 0, groupedRows ); 32042 }, 32043 32044 /** 32045 * Get the grouping information from a data set (index) of rows 32046 * @param {number} level Nesting level 32047 * @param {DataTables.Api} rows API of the rows to consider for this group 32048 * @returns {object[]} Nested grouping information - it is structured like this: 32049 * { 32050 * dataPoint: 'Edinburgh', 32051 * rows: [ 1,2,3,4,5,6,7 ], 32052 * children: [ { 32053 * dataPoint: 'developer' 32054 * rows: [ 1, 2, 3 ] 32055 * }, 32056 * { 32057 * dataPoint: 'support', 32058 * rows: [ 4, 5, 6, 7 ] 32059 * } ] 32060 * } 32061 * @private 32062 */ 32063 _group: function ( level, rows ) { 32064 var fns = $.isArray( this.c.dataSrc ) ? this.c.dataSrc : [ this.c.dataSrc ]; 32065 var fn = DataTable.ext.oApi._fnGetObjectDataFn( fns[ level ] ); 32066 var dt = this.s.dt; 32067 var group, last; 32068 var data = []; 32069 32070 for ( var i=0, ien=rows.length ; i<ien ; i++ ) { 32071 var rowIndex = rows[i]; 32072 var rowData = dt.row( rowIndex ).data(); 32073 var group = fn( rowData ); 32074 32075 if ( group === null || group === undefined ) { 32076 group = that.c.emptyDataGroup; 32077 } 32078 32079 if ( last === undefined || group !== last ) { 32080 data.push( { 32081 dataPoint: group, 32082 rows: [] 32083 } ); 32084 32085 last = group; 32086 } 32087 32088 data[ data.length-1 ].rows.push( rowIndex ); 32089 } 32090 32091 if ( fns[ level+1 ] !== undefined ) { 32092 for ( var i=0, ien=data.length ; i<ien ; i++ ) {
32093 data[i].children = this._group( level+1, data[i].rows ); 32094 } 32095 } 32096 32097 return data; 32098 }, 32099 32100 /** 32101 * Row group display - insert the rows into the document 32102 * @param {number} level Nesting level 32103 * @param {object[]} groups Takes the nested array from `_group` 32104 * @private 32105 */ 32106 _groupDisplay: function ( level, groups ) 32107 { 32108 var dt = this.s.dt; 32109 var display; 32110 32111 for ( var i=0, ien=groups.length ; i<ien ; i++ ) { 32112 var group = groups[i]; 32113 var groupName = group.dataPoint; 32114 var row; 32115 var rows = group.rows; 32116 32117 if ( this.c.startRender ) { 32118 display = this.c.startRender.call( this, dt.rows(rows), groupName, level ); 32119 row = this._rowWrap( display, this.c.startClassName, level ); 32120 32121 if ( row ) { 32122 row.insertBefore( dt.row( rows[0] ).node() ); 32123 } 32124 } 32125 32126 if ( this.c.endRender ) { 32127 display = this.c.endRender.call( this, dt.rows(rows), groupName, level ); 32128 row = this._rowWrap( display, this.c.endClassName, level ); 32129 32130 if ( row ) { 32131 row.insertAfter( dt.row( rows[ rows.length-1 ] ).node() ); 32132 } 32133 } 32134 32135 if ( group.children ) { 32136 this._groupDisplay( level+1, group.children ); 32137 } 32138 } 32139 }, 32140 32141 /** 32142 * Take a rendered value from an end user and make it suitable for display 32143 * as a row, by wrapping it in a row, or detecting that it is a row. 32144 * @param {node|jQuery|string} display Display value 32145 * @param {string} className Class to add to the row 32146 * @param {array} group 32147 * @param {number} group level 32148 * @private 32149 */ 32150 _rowWrap: function ( display, className, level ) 32151 { 32152 var row; 32153 32154 if ( display === null || display === '' ) { 32155 display = this.c.emptyDataGroup; 32156 } 32157 32158 if ( display === undefined ) { 32159 return null; 32160 } 32161 32162 if ( typeof display === 'object' && display.nodeName && display.nodeName.toLowerCase() === 'tr') { 32163 row = $(display); 32164 } 32165 else if (display instanceof $ && display.length && display[0].nodeName.toLowerCase() === 'tr') { 32166 row = display; 32167 } 32168 else { 32169 row = $('<tr/>') 32170 .append( 32171 $('<td/>') 32172 .attr( 'colspan', this._colspan() ) 32173 .append( display ) 32174 ); 32175 } 32176 32177 return row 32178 .addClass( this.c.className ) 32179 .addClass( className ) 32180 .addClass( 'dtrg-level-'+level ); 32181 } 32182} ); 32183 32184 32185/** 32186 * RowGroup default settings for initialisation 32187 * 32188 * @namespace 32189 * @name RowGroup.defaults 32190 * @static 32191 */ 32192RowGroup.defaults = { 32193 /** 32194 * Class to apply to grouping rows - applied to both the start and 32195 * end grouping rows. 32196 * @type string 32197 */ 32198 className: 'dtrg-group', 32199 32200 /** 32201 * Data property from which to read the grouping information 32202 * @type string|integer|array 32203 */ 32204 dataSrc: 0, 32205 32206 /** 32207 * Text to show if no data is found for a group 32208 * @type string 32209 */ 32210 emptyDataGroup: 'No group', 32211 32212 /** 32213 * Initial enablement state 32214 * @boolean 32215 */ 32216 enable: true, 32217 32218 /** 32219 * Class name to give to the end grouping row 32220 * @type string 32221 */ 32222 endClassName: 'dtrg-end', 32223 32224 /** 32225 * End grouping label function 32226 * @function 32227 */ 32228 endRender: null, 32229 32230 /** 32231 * Class name to give to the start grouping row 32232 * @type string 32233 */ 32234 startClassName: 'dtrg-start', 32235 32236 /** 32237 * Start grouping label function 32238 * @function 32239 */ 32240 startRender: function ( rows, group ) { 32241 return group; 32242 } 32243}; 32244 32245 32246RowGroup.version = "1.1.0"; 32247 32248 32249$.fn.dataTable.RowGroup = RowGroup; 32250$.fn.DataTable.RowGroup = RowGroup; 32251 32252 32253DataTable.Api.register( 'rowGroup()', function () { 32254 return this; 32255} ); 32256 32257DataTable.Api.register( 'rowGroup().disable()', function () { 32258 return this.iterator( 'table', function (ctx) { 32259 if ( ctx.rowGroup ) { 32260 ctx.rowGroup.enable( false ); 32261 } 32262 } ); 32263} ); 32264 32265DataTable.Api.register( 'rowGroup().enable()', function ( opts ) { 32266 return this.iterator( 'table', function (ctx) { 32267 if ( ctx.rowGroup ) { 32268 ctx.rowGroup.enable( opts === undefined ? true : opts ); 32269 } 32270 } ); 32271} ); 32272 32273DataTable.Api.register( 'rowGroup().dataSrc()', function ( val ) { 32274 if ( val === undefined ) { 32275 return this.context[0].rowGroup.dataSrc(); 32276 } 32277 32278 return this.iterator( 'table', function (ctx) { 32279 if ( ctx.rowGroup ) { 32280 ctx.rowGroup.dataSrc( val ); 32281 } 32282 } ); 32283} ); 32284 32285 32286// Attach a listener to the document which listens for DataTables initialisation 32287// events so we can automatically initialise 32288$(document).on( 'preInit.dt.dtrg', function (e, settings, json) { 32289 if ( e.namespace !== 'dt' ) { 32290 return; 32291 } 32292 32293 var init = settings.oInit.rowGroup; 32294 var defaults = DataTable.defaults.rowGroup; 32295 32296 if ( init || defaults ) { 32297 var opts = $.extend( {}, defaults, init ); 32298 32299 if ( init !== false ) { 32300 new RowGroup( settings, opts ); 32301 } 32302 } 32303} ); 32304 32305 32306return RowGroup; 32307 32308})); 32309 32310 32311/*! Scroller 1.5.0 32312 * ©2011-2018 SpryMedia Ltd - datatables.net/license 32313 */ 32314 32315/** 32316 * @summary Scroller 32317 * @description Virtual rendering for DataTables 32318 * @version 1.5.0 32319 * @file dataTables.scroller.js 32320 * @author SpryMedia Ltd (www.sprymedia.co.uk) 32321 * @contact www.sprymedia.co.uk/contact 32322 * @copyright Copyright 2011-2018 SpryMedia Ltd. 32323 * 32324 * This source file is free software, available under the following license:
32325 * MIT license - http://datatables.net/license/mit 32326 * 32327 * This source file is distributed in the hope that it will be useful, but 32328 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 32329 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. 32330 * 32331 * For details please refer to: http://www.datatables.net 32332 */ 32333 32334(function( factory ){ 32335 if ( typeof define === 'function' && define.amd ) { 32336 // AMD 32337 define( ['jquery', 'datatables.net'], function ( $ ) { 32338 return factory( $, window, document ); 32339 } ); 32340 } 32341 else if ( typeof exports === 'object' ) { 32342 // CommonJS 32343 module.exports = function (root, $) { 32344 if ( ! root ) { 32345 root = window; 32346 } 32347 32348 if ( ! $ || ! $.fn.dataTable ) { 32349 $ = require('datatables.net')(root, $).$; 32350 } 32351 32352 return factory( $, root, root.document ); 32353 }; 32354 } 32355 else { 32356 // Browser 32357 factory( jQuery, window, document ); 32358 } 32359}(function( $, window, document, undefined ) { 32360'use strict'; 32361var DataTable = $.fn.dataTable; 32362 32363 32364/** 32365 * Scroller is a virtual rendering plug-in for DataTables which allows large 32366 * datasets to be drawn on screen every quickly. What the virtual rendering means 32367 * is that only the visible portion of the table (and a bit to either side to make 32368 * the scrolling smooth) is drawn, while the scrolling container gives the 32369 * visual impression that the whole table is visible. This is done by making use 32370 * of the pagination abilities of DataTables and moving the table around in the 32371 * scrolling container DataTables adds to the page. The scrolling container is 32372 * forced to the height it would be for the full table display using an extra 32373 * element. 32374 * 32375 * Note that rows in the table MUST all be the same height. Information in a cell 32376 * which expands on to multiple lines will cause some odd behaviour in the scrolling. 32377 * 32378 * Scroller is initialised by simply including the letter 'S' in the sDom for the 32379 * table you want to have this feature enabled on. Note that the 'S' must come 32380 * AFTER the 't' parameter in `dom`. 32381 * 32382 * Key features include: 32383 * <ul class="limit_length"> 32384 * <li>Speed! The aim of Scroller for DataTables is to make rendering large data sets fast</li> 32385 * <li>Full compatibility with deferred rendering in DataTables for maximum speed</li> 32386 * <li>Display millions of rows</li> 32387 * <li>Integration with state saving in DataTables (scrolling position is saved)</li> 32388 * <li>Easy to use</li> 32389 * </ul> 32390 * 32391 * @class 32392 * @constructor 32393 * @global 32394 * @param {object} dt DataTables settings object or API instance 32395 * @param {object} [opts={}] Configuration object for FixedColumns. Options 32396 * are defined by {@link Scroller.defaults} 32397 * 32398 * @requires jQuery 1.7+ 32399 * @requires DataTables 1.10.0+ 32400 * 32401 * @example 32402 * $(document).ready(function() { 32403 * $('#example').DataTable( { 32404 * "scrollY": "200px", 32405 * "ajax": "media/dataset/large.txt", 32406 * "dom": "frtiS", 32407 * "deferRender": true 32408 * } ); 32409 * } ); 32410 */ 32411var Scroller = function ( dt, opts ) { 32412 /* Sanity check - you just know it will happen */ 32413 if ( ! (this instanceof Scroller) ) { 32414 alert( "Scroller warning: Scroller must be initialised with the 'new' keyword." ); 32415 return; 32416 } 32417 32418 if ( opts === undefined ) { 32419 opts = {}; 32420 } 32421 32422 var dtApi = $.fn.dataTable.Api( dt ); 32423 32424 /** 32425 * Settings object which contains customisable information for the Scroller instance 32426 * @namespace 32427 * @private 32428 * @extends Scroller.defaults 32429 */ 32430 this.s = { 32431 /** 32432 * DataTables settings object 32433 * @type object 32434 * @default Passed in as first parameter to constructor 32435 */ 32436 "dt": dtApi.settings()[0], 32437 32438 /** 32439 * DataTables API instance 32440 * @type DataTable.Api 32441 */ 32442 "dtApi": dtApi, 32443 32444 /** 32445 * Pixel location of the top of the drawn table in the viewport 32446 * @type int 32447 * @default 0 32448 */ 32449 "tableTop": 0, 32450 32451 /** 32452 * Pixel location of the bottom of the drawn table in the viewport 32453 * @type int 32454 * @default 0 32455 */ 32456 "tableBottom": 0, 32457 32458 /** 32459 * Pixel location of the boundary for when the next data set should be loaded and drawn 32460 * when scrolling up the way. 32461 * @type int 32462 * @default 0 32463 * @private 32464 */ 32465 "redrawTop": 0, 32466 32467 /** 32468 * Pixel location of the boundary for when the next data set should be loaded and drawn 32469 * when scrolling down the way. Note that this is actually calculated as the offset from 32470 * the top. 32471 * @type int 32472 * @default 0 32473 * @private 32474 */ 32475 "redrawBottom": 0, 32476 32477 /** 32478 * Auto row height or not indicator 32479 * @type bool 32480 * @default 0 32481 */ 32482 "autoHeight": true, 32483 32484 /** 32485 * Number of rows calculated as visible in the visible viewport 32486 * @type int 32487 * @default 0 32488 */ 32489 "viewportRows": 0, 32490 32491 /** 32492 * setTimeout reference for state saving, used when state saving is enabled in the DataTable 32493 * and when the user scrolls the viewport in order to stop the cookie set taking too much 32494 * CPU! 32495 * @type int 32496 * @default 0 32497 */ 32498 "stateTO": null, 32499 32500 /** 32501 * setTimeout reference for the redraw, used when server-side processing is enabled in the 32502 * DataTables in order to prevent DoSing the server 32503 * @type int 32504 * @default null 32505 */ 32506 "drawTO": null, 32507 32508 heights: { 32509 jump: null, 32510 page: null, 32511 virtual: null, 32512 scroll: null, 32513 32514 /** 32515 * Height of rows in the table 32516 * @type int 32517 * @default 0 32518 */ 32519 row: null, 32520 32521 /** 32522 * Pixel height of the viewport 32523 * @type int 32524 * @default 0 32525 */ 32526 viewport: null 32527 }, 32528 32529 topRowFloat: 0, 32530 scrollDrawDiff: null, 32531 loaderVisible: false, 32532 forceReposition: false 32533 }; 32534 32535 // @todo The defaults should extend a `c` property and the internal settings
32536 // only held in the `s` property. At the moment they are mixed 32537 this.s = $.extend( this.s, Scroller.oDefaults, opts ); 32538 32539 // Workaround for row height being read from height object (see above comment) 32540 this.s.heights.row = this.s.rowHeight; 32541 32542 /** 32543 * DOM elements used by the class instance 32544 * @private 32545 * @namespace 32546 * 32547 */ 32548 this.dom = { 32549 "force": document.createElement('div'), 32550 "scroller": null, 32551 "table": null, 32552 "loader": null 32553 }; 32554 32555 // Attach the instance to the DataTables instance so it can be accessed in 32556 // future. Don't initialise Scroller twice on the same table 32557 if ( this.s.dt.oScroller ) { 32558 return; 32559 } 32560 32561 this.s.dt.oScroller = this; 32562 32563 /* Let's do it */ 32564 this._fnConstruct(); 32565}; 32566 32567 32568 32569$.extend( Scroller.prototype, { 32570 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 32571 * Public methods 32572 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 32573 32574 /** 32575 * Calculate the pixel position from the top of the scrolling container for 32576 * a given row 32577 * @param {int} iRow Row number to calculate the position of 32578 * @returns {int} Pixels 32579 * @example 32580 * $(document).ready(function() { 32581 * $('#example').dataTable( { 32582 * "sScrollY": "200px", 32583 * "sAjaxSource": "media/dataset/large.txt", 32584 * "sDom": "frtiS", 32585 * "bDeferRender": true, 32586 * "fnInitComplete": function (o) { 32587 * // Find where row 25 is 32588 * alert( o.oScroller.fnRowToPixels( 25 ) ); 32589 * } 32590 * } ); 32591 * } ); 32592 */ 32593 "fnRowToPixels": function ( rowIdx, intParse, virtual ) 32594 { 32595 var pixels; 32596 var diff = rowIdx - this.s.baseRowTop; 32597 32598 if ( virtual ) { 32599 pixels = this._domain( 'virtualToPhysical', this.s.baseScrollTop ); 32600 pixels += diff * this.s.heights.row; 32601 } 32602 else { 32603 pixels = this.s.baseScrollTop; 32604 pixels += diff * this.s.heights.row; 32605 } 32606 32607 return intParse || intParse === undefined ? 32608 parseInt( pixels, 10 ) : 32609 pixels; 32610 }, 32611 32612 32613 /** 32614 * Calculate the row number that will be found at the given pixel position 32615 * (y-scroll). 32616 * 32617 * Please note that when the height of the full table exceeds 1 million 32618 * pixels, Scroller switches into a non-linear mode for the scrollbar to fit 32619 * all of the records into a finite area, but this function returns a linear 32620 * value (relative to the last non-linear positioning). 32621 * @param {int} iPixels Offset from top to calculate the row number of 32622 * @param {int} [intParse=true] If an integer value should be returned 32623 * @param {int} [virtual=false] Perform the calculations in the virtual domain 32624 * @returns {int} Row index 32625 * @example 32626 * $(document).ready(function() { 32627 * $('#example').dataTable( { 32628 * "sScrollY": "200px", 32629 * "sAjaxSource": "media/dataset/large.txt", 32630 * "sDom": "frtiS", 32631 * "bDeferRender": true, 32632 * "fnInitComplete": function (o) { 32633 * // Find what row number is at 500px 32634 * alert( o.oScroller.fnPixelsToRow( 500 ) ); 32635 * } 32636 * } ); 32637 * } ); 32638 */ 32639 "fnPixelsToRow": function ( pixels, intParse, virtual ) 32640 { 32641 var diff = pixels - this.s.baseScrollTop; 32642 var row = virtual ? 32643 (this._domain( 'physicalToVirtual', this.s.baseScrollTop ) + diff) / this.s.heights.row : 32644 ( diff / this.s.heights.row ) + this.s.baseRowTop; 32645 32646 return intParse || intParse === undefined ? 32647 parseInt( row, 10 ) : 32648 row; 32649 }, 32650 32651 32652 /** 32653 * Calculate the row number that will be found at the given pixel position (y-scroll) 32654 * @param {int} iRow Row index to scroll to 32655 * @param {bool} [bAnimate=true] Animate the transition or not 32656 * @returns {void} 32657 * @example 32658 * $(document).ready(function() { 32659 * $('#example').dataTable( { 32660 * "sScrollY": "200px", 32661 * "sAjaxSource": "media/dataset/large.txt", 32662 * "sDom": "frtiS", 32663 * "bDeferRender": true, 32664 * "fnInitComplete": function (o) { 32665 * // Immediately scroll to row 1000 32666 * o.oScroller.fnScrollToRow( 1000 ); 32667 * } 32668 * } ); 32669 * 32670 * // Sometime later on use the following to scroll to row 500... 32671 * var oSettings = $('#example').dataTable().fnSettings(); 32672 * oSettings.oScroller.fnScrollToRow( 500 ); 32673 * } ); 32674 */ 32675 "fnScrollToRow": function ( iRow, bAnimate ) 32676 { 32677 var that = this; 32678 var ani = false;
32679 var px = this.fnRowToPixels( iRow ); 32680 32681 // We need to know if the table will redraw or not before doing the 32682 // scroll. If it will not redraw, then we need to use the currently 32683 // displayed table, and scroll with the physical pixels. Otherwise, we 32684 // need to calculate the table's new position from the virtual 32685 // transform. 32686 var preRows = ((this.s.displayBuffer-1)/2) * this.s.viewportRows; 32687 var drawRow = iRow - preRows; 32688 if ( drawRow < 0 ) { 32689 drawRow = 0; 32690 } 32691 32692 if ( (px > this.s.redrawBottom || px < this.s.redrawTop) && this.s.dt._iDisplayStart !== drawRow ) { 32693 ani = true; 32694 px = this._domain( 'virtualToPhysical', iRow * this.s.heights.row ); 32695 32696 // If we need records outside the current draw region, but the new 32697 // scrolling position is inside that (due to the non-linear nature 32698 // for larger numbers of records), we need to force position update. 32699 if ( this.s.redrawTop < px && px < this.s.redrawBottom ) { 32700 this.s.forceReposition = true; 32701 bAnimate = false; 32702 } 32703 } 32704 32705 if ( typeof bAnimate == 'undefined' || bAnimate ) 32706 { 32707 this.s.ani = ani; 32708 $(this.dom.scroller).animate( { 32709 "scrollTop": px 32710 }, function () { 32711 // This needs to happen after the animation has completed and 32712 // the final scroll event fired 32713 setTimeout( function () { 32714 that.s.ani = false; 32715 }, 25 ); 32716 } ); 32717 } 32718 else 32719 { 32720 $(this.dom.scroller).scrollTop( px ); 32721 } 32722 }, 32723 32724 32725 /** 32726 * Calculate and store information about how many rows are to be displayed 32727 * in the scrolling viewport, based on current dimensions in the browser's 32728 * rendering. This can be particularly useful if the table is initially 32729 * drawn in a hidden element - for example in a tab. 32730 * @param {bool} [bRedraw=true] Redraw the table automatically after the recalculation, with 32731 * the new dimensions forming the basis for the draw. 32732 * @returns {void} 32733 * @example 32734 * $(document).ready(function() { 32735 * // Make the example container hidden to throw off the browser's sizing 32736 * document.getElementById('container').style.display = "none"; 32737 * var oTable = $('#example').dataTable( { 32738 * "sScrollY": "200px", 32739 * "sAjaxSource": "media/dataset/large.txt", 32740 * "sDom": "frtiS", 32741 * "bDeferRender": true, 32742 * "fnInitComplete": function (o) { 32743 * // Immediately scroll to row 1000 32744 * o.oScroller.fnScrollToRow( 1000 ); 32745 * } 32746 * } ); 32747 * 32748 * setTimeout( function () { 32749 * // Make the example container visible and recalculate the scroller sizes 32750 * document.getElementById('container').style.display = "block"; 32751 * oTable.fnSettings().oScroller.fnMeasure(); 32752 * }, 3000 ); 32753 */ 32754 "fnMeasure": function ( bRedraw ) 32755 { 32756 if ( this.s.autoHeight ) 32757 { 32758 this._fnCalcRowHeight(); 32759 } 32760 32761 var heights = this.s.heights; 32762 32763 if ( heights.row ) { 32764 heights.viewport = $.contains(document, this.dom.scroller) ? 32765 $(this.dom.scroller).height() : 32766 this._parseHeight($(this.dom.scroller).css('height')); 32767 32768 // If collapsed (no height) use the max-height parameter 32769 if ( ! heights.viewport ) { 32770 heights.viewport = this._parseHeight($(this.dom.scroller).css('max-height')); 32771 } 32772 32773 this.s.viewportRows = parseInt( heights.viewport / heights.row, 10 )+1; 32774 this.s.dt._iDisplayLength = this.s.viewportRows * this.s.displayBuffer; 32775 } 32776 32777 if ( bRedraw === undefined || bRedraw ) 32778 { 32779 this.s.dt.oInstance.fnDraw( false ); 32780 } 32781 }, 32782 32783 32784 /** 32785 * Get information about current displayed record range. This corresponds to 32786 * the information usually displayed in the "Info" block of the table. 32787 * 32788 * @returns {object} info as an object: 32789 * { 32790 * start: {int}, // the 0-indexed record at the top of the viewport 32791 * end: {int}, // the 0-indexed record at the bottom of the viewport 32792 * } 32793 */ 32794 "fnPageInfo": function() 32795 { 32796 var 32797 dt = this.s.dt, 32798 iScrollTop = this.dom.scroller.scrollTop, 32799 iTotal = dt.fnRecordsDisplay(), 32800 iPossibleEnd = Math.ceil(this.fnPixelsToRow(iScrollTop + this.s.heights.viewport, false, this.s.ani)); 32801 32802 return { 32803 start: Math.floor(this.fnPixelsToRow(iScrollTop, false, this.s.ani)), 32804 end: iTotal < iPossibleEnd ? iTotal-1 : iPossibleEnd-1 32805 }; 32806 }, 32807 32808 32809 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 32810 * Private methods (they are of course public in JS, but recommended as private) 32811 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 32812 32813 /** 32814 * Initialisation for Scroller 32815 * @returns {void} 32816 * @private 32817 */ 32818 "_fnConstruct": function () 32819 { 32820 var that = this; 32821 var dt = this.s.dtApi; 32822 32823 /* Sanity check */ 32824 if ( !this.s.dt.oFeatures.bPaginate ) { 32825 this.s.dt.oApi._fnLog( this.s.dt, 0, 'Pagination must be enabled for Scroller' ); 32826 return; 32827 } 32828 32829 /* Insert a div element that we can use to force the DT scrolling container to 32830 * the height that would be required if the whole table was being displayed 32831 */ 32832 this.dom.force.style.position = "relative"; 32833 this.dom.force.style.top = "0px";
32834 this.dom.force.style.left = "0px"; 32835 this.dom.force.style.width = "1px"; 32836 32837 this.dom.scroller = $('div.'+this.s.dt.oClasses.sScrollBody, this.s.dt.nTableWrapper)[0]; 32838 this.dom.scroller.appendChild( this.dom.force ); 32839 this.dom.scroller.style.position = "relative"; 32840 32841 this.dom.table = $('>table', this.dom.scroller)[0]; 32842 this.dom.table.style.position = "absolute"; 32843 this.dom.table.style.top = "0px"; 32844 this.dom.table.style.left = "0px"; 32845 32846 // Add class to 'announce' that we are a Scroller table 32847 $(dt.table().container()).addClass('DTS'); 32848 32849 // Add a 'loading' indicator 32850 if ( this.s.loadingIndicator ) 32851 { 32852 this.dom.loader = $('<div class="dataTables_processing DTS_Loading">'+this.s.dt.oLanguage.sLoadingRecords+'</div>') 32853 .css('display', 'none'); 32854 32855 $(this.dom.scroller.parentNode) 32856 .css('position', 'relative') 32857 .append( this.dom.loader ); 32858 } 32859 32860 /* Initial size calculations */ 32861 if ( this.s.heights.row && this.s.heights.row != 'auto' ) 32862 { 32863 this.s.autoHeight = false; 32864 } 32865 this.fnMeasure( false ); 32866 32867 // Scrolling callback to see if a page change is needed - use a throttled 32868 // function for the save save callback so we aren't hitting it on every 32869 // scroll 32870 this.s.ingnoreScroll = true; 32871 this.s.stateSaveThrottle = this.s.dt.oApi._fnThrottle( function () { 32872 that.s.dtApi.state.save(); 32873 }, 500 ); 32874 $(this.dom.scroller).on( 'scroll.dt-scroller', function (e) { 32875 that._fnScroll.call( that ); 32876 } ); 32877 32878 // In iOS we catch the touchstart event in case the user tries to scroll 32879 // while the display is already scrolling 32880 $(this.dom.scroller).on('touchstart.dt-scroller', function () { 32881 that._fnScroll.call( that ); 32882 } ); 32883 32884 // On resize, update the information element, since the number of rows shown might change 32885 $(window).on( 'resize.dt-scroller', function () { 32886 that.fnMeasure( false ); 32887 that._fnInfo(); 32888 } ); 32889 32890 // Add a state saving parameter to the DT state saving so we can restore the exact 32891 // position of the scrolling. Slightly surprisingly the scroll position isn't actually 32892 // stored, but rather tha base units which are needed to calculate it. This allows for 32893 // virtual scrolling as well. 32894 var initialStateSave = true; 32895 var loadedState = dt.state.loaded(); 32896 32897 dt.on( 'stateSaveParams.scroller', function ( e, settings, data ) { 32898 // Need to used the saved position on init 32899 data.scroller = { 32900 topRow: initialStateSave && loadedState && loadedState.scroller ? 32901 loadedState.scroller.topRow : 32902 that.s.topRowFloat, 32903 baseScrollTop: that.s.baseScrollTop, 32904 baseRowTop: that.s.baseRowTop 32905 }; 32906 32907 initialStateSave = false; 32908 } ); 32909 32910 if ( loadedState && loadedState.scroller ) { 32911 this.s.topRowFloat = loadedState.scroller.topRow; 32912 this.s.baseScrollTop = loadedState.scroller.baseScrollTop; 32913 this.s.baseRowTop = loadedState.scroller.baseRowTop; 32914 } 32915 32916 dt.on( 'init.scroller', function () { 32917 that.fnMeasure( false ); 32918 32919 that._fnDrawCallback(); 32920 32921 // Update the scroller when the DataTable is redrawn 32922 dt.on( 'draw.scroller', function () { 32923 that._fnDrawCallback(); 32924 }); 32925 } ); 32926 32927 // Set height before the draw happens, allowing everything else to update 32928 // on draw complete without worry for roder. 32929 dt.on( 'preDraw.dt.scroller', function () { 32930 that._fnScrollForce(); 32931 } ); 32932 32933 // Destructor 32934 dt.on( 'destroy.scroller', function () { 32935 $(window).off( 'resize.dt-scroller' ); 32936 $(that.dom.scroller).off('.dt-scroller'); 32937 $(that.s.dt.nTable).off( '.scroller' ); 32938 32939 $(that.s.dt.nTableWrapper).removeClass('DTS'); 32940 $('div.DTS_Loading', that.dom.scroller.parentNode).remove(); 32941 32942 that.dom.table.style.position = ""; 32943 that.dom.table.style.top = ""; 32944 that.dom.table.style.left = ""; 32945 } ); 32946 }, 32947 32948 32949 /** 32950 * Scrolling function - fired whenever the scrolling position is changed. 32951 * This method needs to use the stored values to see if the table should be 32952 * redrawn as we are moving towards the end of the information that is 32953 * currently drawn or not. If needed, then it will redraw the table based on 32954 * the new position. 32955 * @returns {void} 32956 * @private 32957 */ 32958 "_fnScroll": function () 32959 { 32960 var 32961 that = this, 32962 heights = this.s.heights, 32963 iScrollTop = this.dom.scroller.scrollTop, 32964 iTopRow; 32965 32966 if ( this.s.skip ) { 32967 return; 32968 } 32969 32970 if ( this.s.ingnoreScroll ) { 32971 return; 32972 } 32973 32974 /* If the table has been sorted or filtered, then we use the redraw that 32975 * DataTables as done, rather than performing our own 32976 */ 32977 if ( this.s.dt.bFiltered || this.s.dt.bSorted ) { 32978 this.s.lastScrollTop = 0; 32979 return; 32980 } 32981 32982 /* Update the table's information display for what is now in the viewport */ 32983 this._fnInfo(); 32984 32985 /* We don't want to state save on every scroll event - that's heavy 32986 * handed, so use a timeout to update the state saving only when the 32987 * scrolling has finished 32988 */ 32989 clearTimeout( this.s.stateTO ); 32990 this.s.stateTO = setTimeout( function () { 32991 that.s.dtApi.state.save(); 32992 }, 250 ); 32993 32994 /* Check if the scroll point is outside the trigger boundary which w
32994ould required 32995 * a DataTables redraw 32996 */ 32997 if ( this.s.forceReposition || iScrollTop < this.s.redrawTop || iScrollTop > this.s.redrawBottom ) { 32998 32999 var preRows = Math.ceil( ((this.s.displayBuffer-1)/2) * this.s.viewportRows ); 33000 33001 iTopRow = parseInt(this._domain( 'physicalToVirtual', iScrollTop ) / heights.row, 10) - preRows; 33002 this.s.topRowFloat = this._domain( 'physicalToVirtual', iScrollTop ) / heights.row; 33003 this.s.forceReposition = false; 33004 33005 if ( iTopRow <= 0 ) { 33006 /* At the start of the table */ 33007 iTopRow = 0; 33008 } 33009 else if ( iTopRow + this.s.dt._iDisplayLength > this.s.dt.fnRecordsDisplay() ) { 33010 /* At the end of the table */ 33011 iTopRow = this.s.dt.fnRecordsDisplay() - this.s.dt._iDisplayLength; 33012 if ( iTopRow < 0 ) { 33013 iTopRow = 0; 33014 } 33015 } 33016 else if ( iTopRow % 2 !== 0 ) { 33017 // For the row-striping classes (odd/even) we want only to start 33018 // on evens otherwise the stripes will change between draws and 33019 // look rubbish 33020 iTopRow++; 33021 } 33022 33023 if ( iTopRow != this.s.dt._iDisplayStart ) { 33024 /* Cache the new table position for quick lookups */ 33025 this.s.tableTop = $(this.s.dt.nTable).offset().top; 33026 this.s.tableBottom = $(this.s.dt.nTable).height() + this.s.tableTop; 33027 33028 var draw = function () { 33029 if ( that.s.scrollDrawReq === null ) { 33030 that.s.scrollDrawReq = iScrollTop; 33031 } 33032 33033 that.s.dt._iDisplayStart = iTopRow; 33034 that.s.dt.oApi._fnDraw( that.s.dt ); 33035 }; 33036 33037 /* Do the DataTables redraw based on the calculated start point - note that when 33038 * using server-side processing we introduce a small delay to not DoS the server... 33039 */ 33040 if ( this.s.dt.oFeatures.bServerSide ) { 33041 clearTimeout( this.s.drawTO ); 33042 this.s.drawTO = setTimeout( draw, this.s.serverWait ); 33043 } 33044 else { 33045 draw(); 33046 } 33047 33048 if ( this.dom.loader && ! this.s.loaderVisible ) { 33049 this.dom.loader.css( 'display', 'block' ); 33050 this.s.loaderVisible = true; 33051 } 33052 } 33053 } 33054 else { 33055 this.s.topRowFloat = this.fnPixelsToRow( iScrollTop, false, true ); 33056 } 33057 33058 this.s.lastScrollTop = iScrollTop; 33059 this.s.stateSaveThrottle(); 33060 }, 33061 33062 33063 /** 33064 * Convert from one domain to another. The physical domain is the actual 33065 * pixel count on the screen, while the virtual is if we had browsers which 33066 * had scrolling containers of infinite height (i.e. the absolute value) 33067 * 33068 * @param {string} dir Domain transform direction, `virtualToPhysical` or 33069 * `physicalToVirtual` 33070 * @returns {number} Calculated transform 33071 * @private 33072 */ 33073 _domain: function ( dir, val ) 33074 { 33075 var heights = this.s.heights; 33076 var coeff; 33077 33078 // If the virtual and physical height match, then we use a linear 33079 // transform between the two, allowing the scrollbar to be linear 33080 if ( heights.virtual === heights.scroll ) { 33081 return val; 33082 } 33083 33084 // Otherwise, we want a non-linear scrollbar to take account of the 33085 // redrawing regions at the start and end of the table, otherwise these 33086 // can stutter badly - on large tables 30px (for example) scroll might 33087 // be hundreds of rows, so the table would be redrawing every few px at 33088 // the start and end. Use a simple quadratic to stop this. It does mean 33089 // the scrollbar is non-linear, but with such massive data sets, the 33090 // scrollbar is going to be a best guess anyway 33091 var xMax = (heights.scroll - heights.viewport) / 2; 33092 var yMax = (heights.virtual - heights.viewport) / 2; 33093 33094 coeff = yMax / ( xMax * xMax ); 33095 33096 if ( dir === 'virtualToPhysical' ) { 33097 if ( val < yMax ) { 33098 return Math.pow(val / coeff, 0.5); 33099 } 33100 else { 33101 val = (yMax*2) - val; 33102 return val < 0 ? 33103 heights.scroll : 33104 (xMax*2) - Math.pow(val / coeff, 0.5); 33105 } 33106 } 33107 else if ( dir === 'physicalToVirtual' ) { 33108 if ( val < xMax ) { 33109 return val * val * coeff; 33110 } 33111 else { 33112 val = (xMax*2) - val; 33113 return val < 0 ? 33114 heights.virtual : 33115 (yMax*2) - (val * val * coeff); 33116 } 33117 } 33118 }, 33119 33120 /** 33121 * Parse CSS height property string as number 33122 * 33123 * An attempt is made to parse the string as a number. Currently supported units are 'px', 33124 * 'vh', and 'rem'. 'em' is partially supported; it works as long as the parent element's 33125 * font size matches the body element. Zero is returned for unrecognized strings. 33126 * @param {string} cssHeight CSS height property string 33127 * @returns {number} height 33128 * @private 33129 */ 33130 _parseHeight: function(cssHeight) { 33131 var height; 33132 var matches = /^([+-]?(?:\d+(?:\.\d+)?|\.\d+))(px|em|rem|vh)$/.exec(cssHeight); 33133 33134 if (matches === null) { 33135 return 0; 33136 } 33137 33138 var value = parseFloat(matches[1]); 33139 var unit = matches[2]; 33140 33141 if ( unit === 'px' ) { 33142 height = value; 33143 } 33144 else if ( unit === 'vh' ) { 33145 height = ( value / 100 ) * $(window).height(); 33146 } 33147 else if ( unit === 'rem' ) { 33148 height = value * parseFloat($(':root').css('font-size')); 33149 } 33150 else if ( unit === 'em' ) { 33151 height = value * parseFloat($('body').css('font-size')); 33152 } 33153 33154 return height ? 33155 height : 33156 0; 33157 }, 33158 33159 33160 /**
33161 * Draw callback function which is fired when the DataTable is redrawn. The main function of 33162 * this method is to position the drawn table correctly the scrolling container for the rows 33163 * that is displays as a result of the scrolling position. 33164 * @returns {void} 33165 * @private 33166 */ 33167 "_fnDrawCallback": function () 33168 { 33169 var 33170 that = this, 33171 heights = this.s.heights, 33172 iScrollTop = this.dom.scroller.scrollTop, 33173 iActualScrollTop = iScrollTop, 33174 iScrollBottom = iScrollTop + heights.viewport, 33175 iTableHeight = $(this.s.dt.nTable).height(), 33176 displayStart = this.s.dt._iDisplayStart, 33177 displayLen = this.s.dt._iDisplayLength, 33178 displayEnd = this.s.dt.fnRecordsDisplay(); 33179 33180 // Disable the scroll event listener while we are updating the DOM 33181 this.s.skip = true; 33182 33183 // If paging is reset 33184 if ( (this.s.dt.bSorted || this.s.dt.bFiltered) && displayStart === 0 ) { 33185 this.s.topRowFloat = 0; 33186 } 33187 33188 // Reposition the scrolling for the updated virtual position if needed 33189 if ( displayStart === 0 ) { 33190 // Linear calculation at the top of the table 33191 iScrollTop = this.s.topRowFloat * heights.row; 33192 } 33193 else if ( displayStart + displayLen >= displayEnd ) { 33194 // Linear calculation that the bottom as well 33195 iScrollTop = heights.scroll - ((displayEnd - this.s.topRowFloat) * heights.row); 33196 } 33197 else { 33198 // Domain scaled in the middle 33199 iScrollTop = this._domain( 'virtualToPhysical', this.s.topRowFloat * heights.row ); 33200 } 33201 33202 this.dom.scroller.scrollTop = iScrollTop; 33203 33204 // Store positional information so positional calculations can be based 33205 // upon the current table draw position 33206 this.s.baseScrollTop = iScrollTop; 33207 this.s.baseRowTop = this.s.topRowFloat; 33208 33209 // Position the table in the virtual scroller 33210 var tableTop = iScrollTop - ((this.s.topRowFloat - displayStart) * heights.row); 33211 if ( displayStart === 0 ) { 33212 tableTop = 0; 33213 } 33214 else if ( displayStart + displayLen >= displayEnd ) { 33215 tableTop = heights.scroll - iTableHeight; 33216 } 33217 33218 this.dom.table.style.top = tableTop+'px'; 33219 33220 /* Cache some information for the scroller */ 33221 this.s.tableTop = tableTop; 33222 this.s.tableBottom = iTableHeight + this.s.tableTop; 33223 33224 // Calculate the boundaries for where a redraw will be triggered by the 33225 // scroll event listener 33226 var boundaryPx = (iScrollTop - this.s.tableTop) * this.s.boundaryScale; 33227 this.s.redrawTop = iScrollTop - boundaryPx; 33228 this.s.redrawBottom = iScrollTop + boundaryPx > heights.scroll - heights.viewport - heights.row ? 33229 heights.scroll - heights.viewport - heights.row : 33230 iScrollTop + boundaryPx; 33231 33232 this.s.skip = false; 33233 33234 // Restore the scrolling position that was saved by DataTable's state 33235 // saving Note that this is done on the second draw when data is Ajax 33236 // sourced, and the first draw when DOM soured 33237 if ( this.s.dt.oFeatures.bStateSave && this.s.dt.oLoadedState !== null && 33238 typeof this.s.dt.oLoadedState.iScroller != 'undefined' ) 33239 { 33240 // A quirk of DataTables is that the draw callback will occur on an 33241 // empty set if Ajax sourced, but not if server-side processing. 33242 var ajaxSourced = (this.s.dt.sAjaxSource || that.s.dt.ajax) && ! this.s.dt.oFeatures.bServerSide ? 33243 true : 33244 false; 33245 33246 if ( ( ajaxSourced && this.s.dt.iDraw == 2) || 33247 (!ajaxSourced && this.s.dt.iDraw == 1) ) 33248 { 33249 setTimeout( function () { 33250 $(that.dom.scroller).scrollTop( that.s.dt.oLoadedState.iScroller ); 33251 that.s.redrawTop = that.s.dt.oLoadedState.iScroller - (heights.viewport/2); 33252 33253 // In order to prevent layout thrashing we need another 33254 // small delay 33255 setTimeout( function () { 33256 that.s.ingnoreScroll = false; 33257 }, 0 ); 33258 }, 0 ); 33259 } 33260 } 33261 else { 33262 that.s.ingnoreScroll = false; 33263 } 33264 33265 // Because of the order of the DT callbacks, the info update will 33266 // take precedence over the one we want here. So a 'thread' break is 33267 // needed. Only add the thread break if bInfo is set 33268 if ( this.s.dt.oFeatures.bInfo ) { 33269 setTimeout( function () { 33270 that._fnInfo.call( that ); 33271 }, 0 ); 33272 } 33273 33274 // Hide the loading indicator 33275 if ( this.dom.loader && this.s.loaderVisible ) { 33276 this.dom.loader.css( 'display', 'none' ); 33277 this.s.loaderVisible = false;
33278 } 33279 }, 33280 33281 33282 /** 33283 * Force the scrolling container to have height beyond that of just the 33284 * table that has been drawn so the user can scroll the whole data set. 33285 * 33286 * Note that if the calculated required scrolling height exceeds a maximum 33287 * value (1 million pixels - hard-coded) the forcing element will be set 33288 * only to that maximum value and virtual / physical domain transforms will 33289 * be used to allow Scroller to display tables of any number of records. 33290 * @returns {void} 33291 * @private 33292 */ 33293 _fnScrollForce: function () 33294 { 33295 var heights = this.s.heights; 33296 var max = 1000000; 33297 33298 heights.virtual = heights.row * this.s.dt.fnRecordsDisplay(); 33299 heights.scroll = heights.virtual; 33300 33301 if ( heights.scroll > max ) { 33302 heights.scroll = max; 33303 } 33304 33305 // Minimum height so there is always a row visible (the 'no rows found' 33306 // if reduced to zero filtering) 33307 this.dom.force.style.height = heights.scroll > this.s.heights.row ? 33308 heights.scroll+'px' : 33309 this.s.heights.row+'px'; 33310 }, 33311 33312 33313 /** 33314 * Automatic calculation of table row height. This is just a little tricky here as using 33315 * initialisation DataTables has tale the table out of the document, so we need to create 33316 * a new table and insert it into the document, calculate the row height and then whip the 33317 * table out. 33318 * @returns {void} 33319 * @private 33320 */ 33321 "_fnCalcRowHeight": function () 33322 { 33323 var dt = this.s.dt; 33324 var origTable = dt.nTable; 33325 var nTable = origTable.cloneNode( false ); 33326 var tbody = $('<tbody/>').appendTo( nTable ); 33327 var container = $( 33328 '<div class="'+dt.oClasses.sWrapper+' DTS">'+ 33329 '<div class="'+dt.oClasses.sScrollWrapper+'">'+ 33330 '<div class="'+dt.oClasses.sScrollBody+'"></div>'+ 33331 '</div>'+ 33332 '</div>' 33333 ); 33334 33335 // Want 3 rows in the sizing table so :first-child and :last-child 33336 // CSS styles don't come into play - take the size of the middle row 33337 $('tbody tr:lt(4)', origTable).clone().appendTo( tbody ); 33338 while( $('tr', tbody).length < 3 ) { 33339 tbody.append( '<tr><td> </td></tr>' ); 33340 } 33341 33342 $('div.'+dt.oClasses.sScrollBody, container).append( nTable ); 33343 33344 // If initialised using `dom`, use the holding element as the insert point 33345 var insertEl = this.s.dt.nHolding || origTable.parentNode; 33346 33347 if ( ! $(insertEl).is(':visible') ) { 33348 insertEl = 'body'; 33349 } 33350 33351 container.appendTo( insertEl ); 33352 this.s.heights.row = $('tr', tbody).eq(1).outerHeight(); 33353 33354 container.remove(); 33355 }, 33356 33357 33358 /** 33359 * Update any information elements that are controlled by the DataTable based on the scrolling 33360 * viewport and what rows are visible in it. This function basically acts in the same way as 33361 * _fnUpdateInfo in DataTables, and effectively replaces that function. 33362 * @returns {void} 33363 * @private 33364 */ 33365 "_fnInfo": function () 33366 { 33367 if ( !this.s.dt.oFeatures.bInfo ) 33368 { 33369 return; 33370 } 33371 33372 var 33373 dt = this.s.dt, 33374 language = dt.oLanguage, 33375 iScrollTop = this.dom.scroller.scrollTop, 33376 iStart = Math.floor( this.fnPixelsToRow(iScrollTop, false, this.s.ani)+1 ), 33377 iMax = dt.fnRecordsTotal(), 33378 iTotal = dt.fnRecordsDisplay(), 33379 iPossibleEnd = Math.ceil( this.fnPixelsToRow(iScrollTop+this.s.heights.viewport, false, this.s.ani) ), 33380 iEnd = iTotal < iPossibleEnd ? iTotal : iPossibleEnd, 33381 sStart = dt.fnFormatNumber( iStart ), 33382 sEnd = dt.fnFormatNumber( iEnd ), 33383 sMax = dt.fnFormatNumber( iMax ), 33384 sTotal = dt.fnFormatNumber( iTotal ), 33385 sOut; 33386 33387 if ( dt.fnRecordsDisplay() === 0 && 33388 dt.fnRecordsDisplay() == dt.fnRecordsTotal() ) 33389 { 33390 /* Empty record set */ 33391 sOut = language.sInfoEmpty+ language.sInfoPostFix; 33392 } 33393 else if ( dt.fnRecordsDisplay() === 0 ) 33394 { 33395 /* Empty record set after filtering */ 33396 sOut = language.sInfoEmpty +' '+ 33397 language.sInfoFiltered.replace('_MAX_', sMax)+ 33398 language.sInfoPostFix; 33399 } 33400 else if ( dt.fnRecordsDisplay() == dt.fnRecordsTotal() ) 33401 { 33402 /* Normal record set */ 33403 sOut = language.sInfo. 33404 replace('_START_', sStart). 33405 replace('_END_', sEnd). 33406 replace('_MAX_', sMax). 33407 replace('_TOTAL_', sTotal)+ 33408 language.sInfoPostFix; 33409 } 33410 else 33411 { 33412 /* Record set after filtering */ 33413 sOut = language.sInfo. 33414 replace('_START_', sStart). 33415 replace('_END_', sEnd). 33416 replace('_MAX_', sMax). 33417 replace('_TOTAL_', sTotal) +' '+ 33418 language.sInfoFiltered.replace( 33419 '_MAX_', 33420 dt.fnFormatNumber(dt.fnRecordsTotal()) 33421 )+ 33422 language.sInfoPostFix; 33423 } 33424 33425 var callback = language.fnInfoCallback; 33426 if ( callback ) { 33427 sOut = callback.call( dt.oInstance, 33428 dt, iStart, iEnd, iMax, iTotal, sOut 33429 ); 33430 } 33431 33432 var n = dt.aanFeatures.i; 33433 if ( typeof n != 'undefined' ) 33434 { 33435 for ( var i=0, iLen=n.length ; i<iLen ; i++ ) 33436 { 33437 $(n[i]).html( sOut ); 33438 } 33439 } 33440 33441 // DT doesn't actually (yet) trigger this event, but it will in future 33442 $(dt.nTable).triggerHandler( 'info.dt' ); 33443 } 33444} ); 33445 33446 33447 33448/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 33449 * Statics 33450 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 33451 33452 33453/** 33454 * Scroller default settings for initialisation 33455 * @namespace 33456 * @name Scroller.defaults 33457 * @static 33458 */ 33459Scroller.defaults = /** @lends Scroller.defaults */{ 33460 /** 33461 * Indicate if Scroller show show trace information on the console or not. This can be 33462 * useful when debugging Scroller or if just curious as to what it is doing, but should 33463 * be turned off for production. 33464 * @type bool 33465 * @default false 33466 * @static 33467 * @example 33468 * var oTable = $('#example').dataTable( { 33469 * "sScrollY": "200px", 33470 * "sDom": "frtiS", 33471 * "bDeferRender": true, 33472 * "oScroller": { 33473 * "trace": true 33474 * } 33475 * } ); 33476 */ 33477 "trace": false, 33478 33479 /** 33480 * Scroller will attempt to automatically calculate the height of rows for it's internal 33481 * calculations. However the height that is used can be overridden using this parameter. 33482 * @type int|string 33483 * @default auto 33484 * @static 33485 * @example 33486 * var oTable = $('#example').dataTable( { 33487 * "sScrollY": "200px", 33488 * "sDom": "frtiS", 33489 * "bDeferRender": true, 33490 * "oScroller": { 33491 * "rowHeight": 30 33492 * } 33493 * } ); 33494 */ 33495 "rowHeight": "auto", 33496 33497 /** 33498 * When using server-side processing, Scroller will wait a small amount of time to allow 33499 * the scrolling to finish before requesting more data from the server. This prevents 33500 * you from DoSing your own server! The wait time can be configured by this parameter. 33501 * @type int 33502 * @default 200 33503 * @static 33504 * @example 33505 * var oTable = $('#example').dataTable( { 33506 * "sScrollY": "200px", 33507 * "sDom": "frtiS", 33508 * "bDeferRender": true, 33509 * "oScroller": { 33510 * "serverWait": 100 33511 * } 33512 * } ); 33513 */ 33514 "serverWait": 200, 33515 33516 /** 33517 * The display buffer is what Scroller uses to calculate how many rows it should pre-fetch 33518 * for scrolling. Scroller automatically adjusts DataTables' display length to pre-fetch 33519 * rows that will be shown in "near scrolling" (i.e. just beyond the current display area). 33520 * The value is based upon the number of rows that can be displayed in the viewport (i.e.
33521 * a value of 1), and will apply the display range to records before before and after the 33522 * current viewport - i.e. a factor of 3 will allow Scroller to pre-fetch 1 viewport's worth 33523 * of rows before the current viewport, the current viewport's rows and 1 viewport's worth 33524 * of rows after the current viewport. Adjusting this value can be useful for ensuring 33525 * smooth scrolling based on your data set. 33526 * @type int 33527 * @default 7 33528 * @static 33529 * @example 33530 * var oTable = $('#example').dataTable( { 33531 * "sScrollY": "200px", 33532 * "sDom": "frtiS", 33533 * "bDeferRender": true, 33534 * "oScroller": { 33535 * "displayBuffer": 10 33536 * } 33537 * } ); 33538 */ 33539 "displayBuffer": 9, 33540 33541 /** 33542 * Scroller uses the boundary scaling factor to decide when to redraw the table - which it 33543 * typically does before you reach the end of the currently loaded data set (in order to 33544 * allow the data to look continuous to a user scrolling through the data). If given as 0 33545 * then the table will be redrawn whenever the viewport is scrolled, while 1 would not 33546 * redraw the table until the currently loaded data has all been shown. You will want 33547 * something in the middle - the default factor of 0.5 is usually suitable. 33548 * @type float 33549 * @default 0.5 33550 * @static 33551 * @example 33552 * var oTable = $('#example').dataTable( { 33553 * "sScrollY": "200px", 33554 * "sDom": "frtiS", 33555 * "bDeferRender": true, 33556 * "oScroller": { 33557 * "boundaryScale": 0.75 33558 * } 33559 * } ); 33560 */ 33561 "boundaryScale": 0.5, 33562 33563 /** 33564 * Show (or not) the loading element in the background of the table. Note that you should 33565 * include the dataTables.scroller.css file for this to be displayed correctly. 33566 * @type boolean 33567 * @default false 33568 * @static 33569 * @example 33570 * var oTable = $('#example').dataTable( { 33571 * "sScrollY": "200px", 33572 * "sDom": "frtiS", 33573 * "bDeferRender": true, 33574 * "oScroller": { 33575 * "loadingIndicator": true 33576 * } 33577 * } ); 33578 */ 33579 "loadingIndicator": false 33580}; 33581 33582Scroller.oDefaults = Scroller.defaults; 33583 33584 33585 33586/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 33587 * Constants 33588 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 33589 33590/** 33591 * Scroller version 33592 * @type String 33593 * @default See code 33594 * @name Scroller.version 33595 * @static 33596 */ 33597Scroller.version = "1.5.0"; 33598 33599 33600 33601/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 33602 * Initialisation 33603 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 33604 33605// Legacy `dom` parameter initialisation support 33606if ( typeof $.fn.dataTable == "function" && 33607 typeof $.fn.dataTableExt.fnVersionCheck == "function" && 33608 $.fn.dataTableExt.fnVersionCheck('1.10.0') ) 33609{ 33610 $.fn.dataTableExt.aoFeatures.push( { 33611 "fnInit": function( oDTSettings ) { 33612 var init = oDTSettings.oInit; 33613 var opts = init.scroller || init.oScroller || {}; 33614 33615 new Scroller( oDTSettings, opts ); 33616 }, 33617 "cFeature": "S", 33618 "sFeature": "Scroller" 33619 } ); 33620} 33621else 33622{ 33623 alert( "Warning: Scroller requires DataTables 1.10.0 or greater - www.datatables.net/download"); 33624} 33625 33626// Attach a listener to the document which listens for DataTables initialisation 33627// events so we can automatically initialise 33628$(document).on( 'preInit.dt.dtscroller', function (e, settings) { 33629 if ( e.namespace !== 'dt' ) { 33630 return; 33631 } 33632 33633 var init = settings.oInit.scroller; 33634 var defaults = DataTable.defaults.scroller; 33635 33636 if ( init || defaults ) { 33637 var opts = $.extend( {}, init, defaults ); 33638 33639 if ( init !== false ) { 33640 new Scroller( settings, opts ); 33641 } 33642 } 33643} ); 33644 33645 33646// Attach Scroller to DataTables so it can be accessed as an 'extra' 33647$.fn.dataTable.Scroller = Scroller; 33648$.fn.DataTable.Scroller = Scroller; 33649 33650 33651// DataTables 1.10 API method aliases 33652var Api = $.fn.dataTable.Api; 33653 33654Api.register( 'scroller()', function () { 33655 return this; 33656} ); 33657 33658// Undocumented and deprecated - is it actually useful at all? 33659Api.register( 'scroller().rowToPixels()', function ( rowIdx, intParse, virtual ) { 33660 var ctx = this.context; 33661 33662 if ( ctx.length && ctx[0].oScroller ) { 33663 return ctx[0].oScroller.fnRowToPixels( rowIdx, intParse, virtual ); 33664 } 33665 // undefined 33666} ); 33667 33668// Undocumented and deprecated - is it actually useful at all? 33669Api.register( 'scroller().pixelsToRow()', function ( pixels, intParse, virtual ) { 33670 var ctx = this.context; 33671 33672 if ( ctx.length && ctx[0].oScroller ) { 33673 return ctx[0].oScroller.fnPixelsToRow( pixels, intParse, virtual ); 33674 } 33675 // undefined 33676} ); 33677 33678// `scroller().scrollToRow()` is undocumented and deprecated. Use `scroller.toPosition() 33679Api.register( ['scroller().scrollToRow()', 'scroller.toPosition()'], function ( idx, ani ) { 33680 this.iterator( 'table', function ( ctx ) { 33681 if ( ctx.oScroller ) { 33682 ctx.oScroller.fnScrollToRow( idx, ani ); 33683 } 33684 } ); 33685 33686 return this; 33687} ); 33688 33689Api.register( 'row().scrollTo()', function ( ani ) { 33690 var that = this; 33691 33692 this.iterator( 'row', function ( ctx, rowIdx ) { 33693 if ( ctx.oScroller ) { 33694 var displayIdx = that 33695 .rows( { order: 'applied', search: 'applied' } ) 33696 .indexes() 33697 .indexOf( rowIdx ); 33698 33699 ctx.oScroller.fnScrollToRow( displayIdx, ani ); 33700 } 33701 } ); 33702 33703 return this; 33704} ); 33705 33706Api.register( 'scroller.measure()', function ( redraw ) { 33707 this.iterator( 'table', function ( ctx ) { 33708 if ( ctx.oScroller ) { 33709 ctx.oScroller.fnMeasure( redraw ); 33710 } 33711 } ); 33712 33713 return this; 33714} ); 33715 33716Api.register( 'scroller.page()', function() { 33717 var ctx = this.context; 33718 33719 if ( ctx.length && ctx[0].oScroller ) { 33720 return ctx[0].oScroller.fnPageInfo(); 33721 } 33722 // undefined 33723} ); 33724 33725return Scroller; 33726})); 33727 33728 33729/*! Select for DataTables 1.2.6
33730 * 2015-2018 SpryMedia Ltd - datatables.net/license/mit 33731 */ 33732 33733/** 33734 * @summary Select for DataTables 33735 * @description A collection of API methods, events and buttons for DataTables 33736 * that provides selection options of the items in a DataTable 33737 * @version 1.2.6 33738 * @file dataTables.select.js 33739 * @author SpryMedia Ltd (www.sprymedia.co.uk) 33740 * @contact datatables.net/forums 33741 * @copyright Copyright 2015-2018 SpryMedia Ltd. 33742 * 33743 * This source file is free software, available under the following license: 33744 * MIT license - http://datatables.net/license/mit 33745 * 33746 * This source file is distributed in the hope that it will be useful, but 33747 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 33748 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. 33749 * 33750 * For details please refer to: http://www.datatables.net/extensions/select 33751 */ 33752(function( factory ){ 33753 if ( typeof define === 'function' && define.amd ) { 33754 // AMD 33755 define( ['jquery', 'datatables.net'], function ( $ ) { 33756 return factory( $, window, document ); 33757 } ); 33758 } 33759 else if ( typeof exports === 'object' ) { 33760 // CommonJS 33761 module.exports = function (root, $) { 33762 if ( ! root ) { 33763 root = window; 33764 } 33765 33766 if ( ! $ || ! $.fn.dataTable ) { 33767 $ = require('datatables.net')(root, $).$; 33768 } 33769 33770 return factory( $, root, root.document ); 33771 }; 33772 } 33773 else { 33774 // Browser 33775 factory( jQuery, window, document ); 33776 } 33777}(function( $, window, document, undefined ) { 33778'use strict'; 33779var DataTable = $.fn.dataTable; 33780 33781 33782// Version information for debugger 33783DataTable.select = {}; 33784 33785DataTable.select.version = '1.2.6'; 33786 33787DataTable.select.init = function ( dt ) { 33788 var ctx = dt.settings()[0]; 33789 var init = ctx.oInit.select; 33790 var defaults = DataTable.defaults.select; 33791 var opts = init === undefined ? 33792 defaults : 33793 init; 33794 33795 // Set defaults 33796 var items = 'row'; 33797 var style = 'api'; 33798 var blurable = false; 33799 var info = true; 33800 var selector = 'td, th'; 33801 var className = 'selected'; 33802 var setStyle = false; 33803 33804 ctx._select = {}; 33805 33806 // Initialisation customisations 33807 if ( opts === true ) { 33808 style = 'os'; 33809 setStyle = true; 33810 } 33811 else if ( typeof opts === 'string' ) { 33812 style = opts; 33813 setStyle = true; 33814 } 33815 else if ( $.isPlainObject( opts ) ) { 33816 if ( opts.blurable !== undefined ) { 33817 blurable = opts.blurable; 33818 } 33819 33820 if ( opts.info !== undefined ) { 33821 info = opts.info; 33822 } 33823 33824 if ( opts.items !== undefined ) { 33825 items = opts.items; 33826 } 33827 33828 if ( opts.style !== undefined ) { 33829 style = opts.style; 33830 setStyle = true; 33831 } 33832 33833 if ( opts.selector !== undefined ) { 33834 selector = opts.selector; 33835 } 33836 33837 if ( opts.className !== undefined ) { 33838 className = opts.className; 33839 } 33840 } 33841 33842 dt.select.selector( selector ); 33843 dt.select.items( items ); 33844 dt.select.style( style ); 33845 dt.select.blurable( blurable ); 33846 dt.select.info( info ); 33847 ctx._select.className = className; 33848 33849 33850 // Sort table based on selected rows. Requires Select Datatables extension 33851 $.fn.dataTable.ext.order['select-checkbox'] = function ( settings, col ) { 33852 return this.api().column( col, {order: 'index'} ).nodes().map( function ( td ) { 33853 if ( settings._select.items === 'row' ) { 33854 return $( td ).parent().hasClass( settings._select.className ); 33855 } else if ( settings._select.items === 'cell' ) { 33856 return $( td ).hasClass( settings._select.className ); 33857 } 33858 return false; 33859 }); 33860 }; 33861 33862 // If the init options haven't enabled select, but there is a selectable 33863 // class name, then enable 33864 if ( ! setStyle && $( dt.table().node() ).hasClass( 'selectable' ) ) { 33865 dt.select.style( 'os' ); 33866 } 33867}; 33868 33869/* 33870 33871Select is a collection of API methods, event handlers, event emitters and 33872buttons (for the `Buttons` extension) for DataTables. It provides the following 33873features, with an overview of how they are implemented: 33874 33875## Selection of rows, columns and cells. Whether an item is selected or not is 33876 stored in: 33877 33878* rows: a `_select_selected` property which contains a boolean value of the 33879 DataTables' `aoData` object for each row 33880* columns: a `_select_selected` property which contains a boolean value of the 33881 DataTables' `aoColumns` object for each column 33882* cells: a `_selected_cells` property which contains an array of boolean values 33883 of the `aoData` object for each row. The array is the same length as the 33884 columns array, with each element of it representing a cell. 33885 33886This method of using boolean flags allows Select to operate when nodes have not 33887been created for rows / cells (DataTables' defer rendering feature). 33888 33889## API methods 33890 33891A range of API methods are available for triggering selection and de-selection 33892of rows. Methods are also available to configure the selection events that can 33893be triggered by an end user (such as which items are to be selected). To a large 33894extent, these of API methods *is* Select. It is basically a collection of helper 33895functions that can be used to select items in a DataTable. 33896 33897Configuration of select is held in the object `_select` which is attached to the 33898DataTables settings object on initialisation. Select being available on a table 33899is not optional when Select is loaded, but its default is for selection only to 33900be available via the API - so the end user wouldn't be able to select rows 33901without additional configuration. 33902
33903The `_select` object contains the following properties: 33904 33905``` 33906{ 33907 items:string - Can be `rows`, `columns` or `cells`. Defines what item 33908 will be selected if the user is allowed to activate row 33909 selection using the mouse. 33910 style:string - Can be `none`, `single`, `multi` or `os`. Defines the 33911 interaction style when selecting items 33912 blurable:boolean - If row selection can be cleared by clicking outside of 33913 the table 33914 info:boolean - If the selection summary should be shown in the table 33915 information elements 33916} 33917``` 33918 33919In addition to the API methods, Select also extends the DataTables selector 33920options for rows, columns and cells adding a `selected` option to the selector 33921options object, allowing the developer to select only selected items or 33922unselected items. 33923 33924## Mouse selection of items 33925 33926Clicking on items can be used to select items. This is done by a simple event 33927handler that will select the items using the API methods. 33928 33929 */ 33930 33931 33932/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 33933 * Local functions 33934 */ 33935 33936/** 33937 * Add one or more cells to the selection when shift clicking in OS selection 33938 * style cell selection. 33939 * 33940 * Cell range is more complicated than row and column as we want to select 33941 * in the visible grid rather than by index in sequence. For example, if you 33942 * click first in cell 1-1 and then shift click in 2-2 - cells 1-2 and 2-1 33943 * should also be selected (and not 1-3, 1-4. etc) 33944 * 33945 * @param {DataTable.Api} dt DataTable 33946 * @param {object} idx Cell index to select to 33947 * @param {object} last Cell index to select from 33948 * @private 33949 */ 33950function cellRange( dt, idx, last ) 33951{ 33952 var indexes; 33953 var columnIndexes; 33954 var rowIndexes; 33955 var selectColumns = function ( start, end ) { 33956 if ( start > end ) { 33957 var tmp = end; 33958 end = start; 33959 start = tmp; 33960 } 33961 33962 var record = false; 33963 return dt.columns( ':visible' ).indexes().filter( function (i) { 33964 if ( i === start ) { 33965 record = true; 33966 } 33967 33968 if ( i === end ) { // not else if, as start might === end 33969 record = false; 33970 return true; 33971 } 33972 33973 return record; 33974 } ); 33975 }; 33976 33977 var selectRows = function ( start, end ) { 33978 var indexes = dt.rows( { search: 'applied' } ).indexes(); 33979 33980 // Which comes first - might need to swap 33981 if ( indexes.indexOf( start ) > indexes.indexOf( end ) ) { 33982 var tmp = end; 33983 end = start; 33984 start = tmp; 33985 } 33986 33987 var record = false; 33988 return indexes.filter( function (i) { 33989 if ( i === start ) { 33990 record = true; 33991 } 33992 33993 if ( i === end ) { 33994 record = false; 33995 return true; 33996 } 33997 33998 return record; 33999 } ); 34000 }; 34001 34002 if ( ! dt.cells( { selected: true } ).any() && ! last ) { 34003 // select from the top left cell to this one 34004 columnIndexes = selectColumns( 0, idx.column ); 34005 rowIndexes = selectRows( 0 , idx.row ); 34006 } 34007 else { 34008 // Get column indexes between old and new 34009 columnIndexes = selectColumns( last.column, idx.column ); 34010 rowIndexes = selectRows( last.row , idx.row ); 34011 } 34012 34013 indexes = dt.cells( rowIndexes, columnIndexes ).flatten(); 34014 34015 if ( ! dt.cells( idx, { selected: true } ).any() ) { 34016 // Select range 34017 dt.cells( indexes ).select(); 34018 } 34019 else { 34020 // Deselect range 34021 dt.cells( indexes ).deselect(); 34022 } 34023} 34024 34025/** 34026 * Disable mouse selection by removing the selectors 34027 * 34028 * @param {DataTable.Api} dt DataTable to remove events from 34029 * @private 34030 */ 34031function disableMouseSelection( dt ) 34032{ 34033 var ctx = dt.settings()[0]; 34034 var selector = ctx._select.selector; 34035 34036 $( dt.table().container() ) 34037 .off( 'mousedown.dtSelect', selector ) 34038 .off( 'mouseup.dtSelect', selector ) 34039 .off( 'click.dtSelect', selector ); 34040 34041 $('body').off( 'click.dtSelect' + dt.table().node().id ); 34042} 34043 34044/** 34045 * Attach mouse listeners to the table to allow mouse selection of items 34046 * 34047 * @param {DataTable.Api} dt DataTable to remove events from 34048 * @private 34049 */ 34050function enableMouseSelection ( dt ) 34051{ 34052 var container = $( dt.table().container() ); 34053 var ctx = dt.settings()[0]; 34054 var selector = ctx._select.selector; 34055 var matchSelection; 34056 34057 container 34058 .on( 'mousedown.dtSelect', selector, function(e) { 34059 // Disallow text selection for shift clicking on the table so multi 34060 // element selection doesn't look terrible! 34061 if ( e.shiftKey || e.metaKey || e.ctrlKey ) { 34062 container 34063 .css( '-moz-user-select', 'none' ) 34064 .one('selectstart.dtSelect', selector, function () { 34065 return false;
34066 } ); 34067 } 34068 34069 if ( window.getSelection ) { 34070 matchSelection = window.getSelection(); 34071 } 34072 } ) 34073 .on( 'mouseup.dtSelect', selector, function() { 34074 // Allow text selection to occur again, Mozilla style (tested in FF 34075 // 35.0.1 - still required) 34076 container.css( '-moz-user-select', '' ); 34077 } ) 34078 .on( 'click.dtSelect', selector, function ( e ) { 34079 var items = dt.select.items(); 34080 var idx; 34081 34082 // If text was selected (click and drag), then we shouldn't change 34083 // the row's selected state 34084 if ( window.getSelection ) { 34085 var selection = window.getSelection(); 34086 34087 // If the element that contains the selection is not in the table, we can ignore it 34088 // This can happen if the developer selects text from the click event 34089 if ( ! selection.anchorNode || $(selection.anchorNode).closest('table')[0] === dt.table().node() ) { 34090 if ( selection !== matchSelection ) { 34091 return; 34092 } 34093 } 34094 } 34095 34096 var ctx = dt.settings()[0]; 34097 var wrapperClass = dt.settings()[0].oClasses.sWrapper.replace(/ /g, '.'); 34098 34099 // Ignore clicks inside a sub-table 34100 if ( $(e.target).closest('div.'+wrapperClass)[0] != dt.table().container() ) { 34101 return; 34102 } 34103 34104 var cell = dt.cell( $(e.target).closest('td, th') ); 34105 34106 // Check the cell actually belongs to the host DataTable (so child 34107 // rows, etc, are ignored) 34108 if ( ! cell.any() ) { 34109 return; 34110 } 34111 34112 var event = $.Event('user-select.dt'); 34113 eventTrigger( dt, event, [ items, cell, e ] ); 34114 34115 if ( event.isDefaultPrevented() ) { 34116 return; 34117 } 34118 34119 var cellIndex = cell.index(); 34120 if ( items === 'row' ) { 34121 idx = cellIndex.row; 34122 typeSelect( e, dt, ctx, 'row', idx ); 34123 } 34124 else if ( items === 'column' ) { 34125 idx = cell.index().column; 34126 typeSelect( e, dt, ctx, 'column', idx ); 34127 } 34128 else if ( items === 'cell' ) { 34129 idx = cell.index(); 34130 typeSelect( e, dt, ctx, 'cell', idx ); 34131 } 34132 34133 ctx._select_lastCell = cellIndex; 34134 } ); 34135 34136 // Blurable 34137 $('body').on( 'click.dtSelect' + dt.table().node().id, function ( e ) { 34138 if ( ctx._select.blurable ) { 34139 // If the click was inside the DataTables container, don't blur 34140 if ( $(e.target).parents().filter( dt.table().container() ).length ) { 34141 return; 34142 } 34143 34144 // Ignore elements which have been removed from the DOM (i.e. paging 34145 // buttons) 34146 if ( $(e.target).parents('html').length === 0 ) { 34147 return; 34148 } 34149 34150 // Don't blur in Editor form 34151 if ( $(e.target).parents('div.DTE').length ) { 34152 return; 34153 } 34154 34155 clear( ctx, true ); 34156 } 34157 } ); 34158} 34159 34160/** 34161 * Trigger an event on a DataTable 34162 * 34163 * @param {DataTable.Api} api DataTable to trigger events on 34164 * @param {boolean} selected true if selected, false if deselected 34165 * @param {string} type Item type acting on 34166 * @param {boolean} any Require that there are values before 34167 * triggering 34168 * @private 34169 */ 34170function eventTrigger ( api, type, args, any ) 34171{ 34172 if ( any && ! api.flatten().length ) { 34173 return; 34174 } 34175 34176 if ( typeof type === 'string' ) { 34177 type = type +'.dt'; 34178 } 34179 34180 args.unshift( api ); 34181 34182 $(api.table().node()).trigger( type, args ); 34183} 34184 34185/** 34186 * Update the information element of the DataTable showing information about the 34187 * items selected. This is done by adding tags to the existing text 34188 * 34189 * @param {DataTable.Api} api DataTable to update 34190 * @private 34191 */ 34192function info ( api ) 34193{ 34194 var ctx = api.settings()[0]; 34195 34196 if ( ! ctx._select.info || ! ctx.aanFeatures.i ) { 34197 return; 34198 } 34199 34200 if ( api.select.style() === 'api' ) { 34201 return; 34202 } 34203 34204 var rows = api.rows( { selected: true } ).flatten().length; 34205 var columns = api.columns( { selected: true } ).flatten().length; 34206 var cells = api.cells( { selected: true } ).flatten().length; 34207 34208 var add = function ( el, name, num ) { 34209 el.append( $('<span class="select-item"/>').append( api.i18n( 34210 'select.'+name+'s', 34211 { _: '%d '+name+'s selected', 0: '', 1: '1 '+name+' selected' }, 34212 num 34213 ) ) ); 34214 }; 34215 34216 // Internal knowledge of DataTables to loop over all information elements 34217 $.each( ctx.aanFeatures.i, function ( i, el ) { 34218 el = $(el); 34219 34220 var output = $('<span class="select-info"/>'); 34221 add( output, 'row', rows ); 34222 add( output, 'column', columns ); 34223 add( output, 'cell', cells ); 34224 34225 var exisiting = el.children('span.select-info'); 34226 if ( exisiting.length ) { 34227 exisiting.remove(); 34228 } 34229 34230 if ( output.text() !== '' ) { 34231 el.append( output ); 34232 } 34233 } ); 34234} 34235 34236/** 34237 * Initialisation of a new table. Attach event handlers and callbacks to allow 34238 * Select to operate correctly. 34239 * 34240 * This will occur _after_ the initial DataTables initialisation, although 34241 * before Ajax data is rendered, if there is ajax data 34242 * 34243 * @param {DataTable.settings} ctx Settings object to operate on 34244 * @private 34245 */ 34246function init ( ctx ) { 34247 var api = new DataTable.Api( ctx ); 34248 34249 // Row callback so that classes can be added to rows and cells if the item 34250 // was selected before the element was created. This will happen with the 34251 // `deferRender` option enabled. 34252 // 34253 // This method of attaching to `aoRowCreatedCallback` is a hack until 34254 // DataTables has proper events for row manipulation If you are reviewing 34255 // this code to create your own plug-ins, please do not do this! 34256 ctx.aoRowCreatedCallback.push( { 34257 fn: function ( row, data, index ) { 34258 var i, ien; 34259 var d = ctx.aoData[ index ]; 34260 34261 // Row 34262 if ( d._select_selected ) { 34263 $( row ).addClass( ctx._select.className ); 34264 } 34265 34266 // Cells and columns - if separated out, we would need to do two 34267 // loops, so it makes sense to combine them into a single one 34268 for ( i=0, ien=ctx.aoColumns.length ; i<ien ; i++ ) { 34269 if ( ctx.aoColumns[i]._select_selected || (d._selected_cells && d._selected_cells[i]) ) { 34270 $(d.anCells[i]).addClass( ctx._select.className ); 34271 } 34272 } 34273 }, 34274 sName: 'select-deferRender' 34275 } ); 34276 34277 // On Ajax reload we want to reselect all rows which are currently selected, 34278 // if there is an rowId (i.e. a unique value to identify each row with) 34279 api.on( 'preXhr.dt.dtSelect', function () { 34280 // note that column selection doesn't need to be cached and then 34281 // reselected, as they are already selected 34282 var rows = api.rows( { selected: true } ).ids( true ).filter( function ( d ) { 34283 return d !== undefined; 34284 } ); 34285 34286 var cells = api.cells( { selected: true } ).eq(0).map( function ( cellIdx ) { 34287 var id = api.row( cellIdx.row ).id( true ); 34288 return id ? 34289 { row: id, column: cellIdx.column } : 34290 undefined; 34291 } ).filter( function ( d ) { 34292 return d !== undefined; 34293 } ); 34294 34295 // On the next draw, reselect the currently selected items 34296 api.one( 'draw.dt.dtSelect', function () { 34297 api.rows( rows ).select(); 34298 34299 // `cells` is not a cell index selector, so it needs a loop 34300 if ( cells.any() ) { 34301 cells.each( function ( id ) { 34302 api.cells( id.row, id.column ).select(); 34303 } ); 34304 } 34305 } ); 34306 } ); 34307 34308 // Update the table information element with selected item summary 34309 api.on( 'draw.dtSelect.dt select.dtSelect.dt deselect.dtSelect.dt info.dt', function () {
34310 info( api ); 34311 } ); 34312 34313 // Clean up and release 34314 api.on( 'destroy.dtSelect', function () { 34315 disableMouseSelection( api ); 34316 api.off( '.dtSelect' ); 34317 } ); 34318} 34319 34320/** 34321 * Add one or more items (rows or columns) to the selection when shift clicking 34322 * in OS selection style 34323 * 34324 * @param {DataTable.Api} dt DataTable 34325 * @param {string} type Row or column range selector 34326 * @param {object} idx Item index to select to 34327 * @param {object} last Item index to select from 34328 * @private 34329 */ 34330function rowColumnRange( dt, type, idx, last ) 34331{ 34332 // Add a range of rows from the last selected row to this one 34333 var indexes = dt[type+'s']( { search: 'applied' } ).indexes(); 34334 var idx1 = $.inArray( last, indexes ); 34335 var idx2 = $.inArray( idx, indexes ); 34336 34337 if ( ! dt[type+'s']( { selected: true } ).any() && idx1 === -1 ) { 34338 // select from top to here - slightly odd, but both Windows and Mac OS 34339 // do this 34340 indexes.splice( $.inArray( idx, indexes )+1, indexes.length ); 34341 } 34342 else { 34343 // reverse so we can shift click 'up' as well as down 34344 if ( idx1 > idx2 ) { 34345 var tmp = idx2; 34346 idx2 = idx1; 34347 idx1 = tmp; 34348 } 34349 34350 indexes.splice( idx2+1, indexes.length ); 34351 indexes.splice( 0, idx1 ); 34352 } 34353 34354 if ( ! dt[type]( idx, { selected: true } ).any() ) { 34355 // Select range 34356 dt[type+'s']( indexes ).select(); 34357 } 34358 else { 34359 // Deselect range - need to keep the clicked on row selected 34360 indexes.splice( $.inArray( idx, indexes ), 1 ); 34361 dt[type+'s']( indexes ).deselect(); 34362 } 34363} 34364 34365/** 34366 * Clear all selected items 34367 * 34368 * @param {DataTable.settings} ctx Settings object of the host DataTable 34369 * @param {boolean} [force=false] Force the de-selection to happen, regardless 34370 * of selection style 34371 * @private 34372 */ 34373function clear( ctx, force ) 34374{ 34375 if ( force || ctx._select.style === 'single' ) { 34376 var api = new DataTable.Api( ctx ); 34377 34378 api.rows( { selected: true } ).deselect(); 34379 api.columns( { selected: true } ).deselect(); 34380 api.cells( { selected: true } ).deselect(); 34381 } 34382} 34383 34384/** 34385 * Select items based on the current configuration for style and items. 34386 * 34387 * @param {object} e Mouse event object 34388 * @param {DataTables.Api} dt DataTable 34389 * @param {DataTable.settings} ctx Settings object of the host DataTable 34390 * @param {string} type Items to select 34391 * @param {int|object} idx Index of the item to select 34392 * @private 34393 */ 34394function typeSelect ( e, dt, ctx, type, idx ) 34395{ 34396 var style = dt.select.style(); 34397 var isSelected = dt[type]( idx, { selected: true } ).any(); 34398 34399 if ( style === 'os' ) { 34400 if ( e.ctrlKey || e.metaKey ) { 34401 // Add or remove from the selection 34402 dt[type]( idx ).select( ! isSelected ); 34403 } 34404 else if ( e.shiftKey ) { 34405 if ( type === 'cell' ) { 34406 cellRange( dt, idx, ctx._select_lastCell || null ); 34407 } 34408 else { 34409 rowColumnRange( dt, type, idx, ctx._select_lastCell ? 34410 ctx._select_lastCell[type] : 34411 null 34412 ); 34413 } 34414 } 34415 else { 34416 // No cmd or shift click - deselect if selected, or select 34417 // this row only 34418 var selected = dt[type+'s']( { selected: true } ); 34419 34420 if ( isSelected && selected.flatten().length === 1 ) { 34421 dt[type]( idx ).deselect(); 34422 } 34423 else { 34424 selected.deselect(); 34425 dt[type]( idx ).select(); 34426 } 34427 } 34428 } else if ( style == 'multi+shift' ) { 34429 if ( e.shiftKey ) { 34430 if ( type === 'cell' ) { 34431 cellRange( dt, idx, ctx._select_lastCell || null ); 34432 } 34433 else { 34434 rowColumnRange( dt, type, idx, ctx._select_lastCell ? 34435 ctx._select_lastCell[type] : 34436 null 34437 ); 34438 } 34439 } 34440 else { 34441 dt[ type ]( idx ).select( ! isSelected ); 34442 } 34443 } 34444 else { 34445 dt[ type ]( idx ).select( ! isSelected ); 34446 } 34447} 34448 34449 34450 34451/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 34452 * DataTables selectors 34453 */ 34454 34455// row and column are basically identical just assigned to different properties 34456// and checking a different array, so we can dynamically create the functions to 34457// reduce the code size 34458$.each( [ 34459 { type: 'row', prop: 'aoData' }, 34460 { type: 'column', prop: 'aoColumns' } 34461], function ( i, o ) { 34462 DataTable.ext.selector[ o.type ].push( function ( settings, opts, indexes ) { 34463 var selected = opts.selected; 34464 var data; 34465 var out = []; 34466 34467 if ( selected !== true && selected !== false ) { 34468 return indexes; 34469 } 34470
34471 for ( var i=0, ien=indexes.length ; i<ien ; i++ ) { 34472 data = settings[ o.prop ][ indexes[i] ]; 34473 34474 if ( (selected === true && data._select_selected === true) || 34475 (selected === false && ! data._select_selected ) 34476 ) { 34477 out.push( indexes[i] ); 34478 } 34479 } 34480 34481 return out; 34482 } ); 34483} ); 34484 34485DataTable.ext.selector.cell.push( function ( settings, opts, cells ) { 34486 var selected = opts.selected; 34487 var rowData; 34488 var out = []; 34489 34490 if ( selected === undefined ) { 34491 return cells; 34492 } 34493 34494 for ( var i=0, ien=cells.length ; i<ien ; i++ ) { 34495 rowData = settings.aoData[ cells[i].row ]; 34496 34497 if ( (selected === true && rowData._selected_cells && rowData._selected_cells[ cells[i].column ] === true) || 34498 (selected === false && ( ! rowData._selected_cells || ! rowData._selected_cells[ cells[i].column ] ) ) 34499 ) { 34500 out.push( cells[i] ); 34501 } 34502 } 34503 34504 return out; 34505} ); 34506 34507 34508 34509/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 34510 * DataTables API 34511 * 34512 * For complete documentation, please refer to the docs/api directory or the 34513 * DataTables site 34514 */ 34515 34516// Local variables to improve compression 34517var apiRegister = DataTable.Api.register; 34518var apiRegisterPlural = DataTable.Api.registerPlural; 34519 34520apiRegister( 'select()', function () { 34521 return this.iterator( 'table', function ( ctx ) { 34522 DataTable.select.init( new DataTable.Api( ctx ) ); 34523 } ); 34524} ); 34525 34526apiRegister( 'select.blurable()', function ( flag ) { 34527 if ( flag === undefined ) { 34528 return this.context[0]._select.blurable; 34529 } 34530 34531 return this.iterator( 'table', function ( ctx ) { 34532 ctx._select.blurable = flag; 34533 } ); 34534} ); 34535 34536apiRegister( 'select.info()', function ( flag ) { 34537 if ( info === undefined ) { 34538 return this.context[0]._select.info; 34539 } 34540 34541 return this.iterator( 'table', function ( ctx ) { 34542 ctx._select.info = flag; 34543 } ); 34544} ); 34545 34546apiRegister( 'select.items()', function ( items ) { 34547 if ( items === undefined ) { 34548 return this.context[0]._select.items; 34549 } 34550 34551 return this.iterator( 'table', function ( ctx ) { 34552 ctx._select.items = items; 34553 34554 eventTrigger( new DataTable.Api( ctx ), 'selectItems', [ items ] ); 34555 } ); 34556} ); 34557 34558// Takes effect from the _next_ selection. None disables future selection, but 34559// does not clear the current selection. Use the `deselect` methods for that 34560apiRegister( 'select.style()', function ( style ) { 34561 if ( style === undefined ) { 34562 return this.context[0]._select.style; 34563 } 34564 34565 return this.iterator( 'table', function ( ctx ) { 34566 ctx._select.style = style; 34567 34568 if ( ! ctx._select_init ) { 34569 init( ctx ); 34570 } 34571 34572 // Add / remove mouse event handlers. They aren't required when only 34573 // API selection is available 34574 var dt = new DataTable.Api( ctx ); 34575 disableMouseSelection( dt ); 34576 34577 if ( style !== 'api' ) { 34578 enableMouseSelection( dt ); 34579 } 34580 34581 eventTrigger( new DataTable.Api( ctx ), 'selectStyle', [ style ] ); 34582 } ); 34583} ); 34584 34585apiRegister( 'select.selector()', function ( selector ) { 34586 if ( selector === undefined ) { 34587 return this.context[0]._select.selector; 34588 } 34589 34590 return this.iterator( 'table', function ( ctx ) { 34591 disableMouseSelection( new DataTable.Api( ctx ) ); 34592 34593 ctx._select.selector = selector; 34594 34595 if ( ctx._select.style !== 'api' ) { 34596 enableMouseSelection( new DataTable.Api( ctx ) ); 34597 } 34598 } ); 34599} ); 34600 34601 34602 34603apiRegisterPlural( 'rows().select()', 'row().select()', function ( select ) { 34604 var api = this; 34605 34606 if ( select === false ) { 34607 return this.deselect(); 34608 } 34609 34610 this.iterator( 'row', function ( ctx, idx ) { 34611 clear( ctx ); 34612 34613 ctx.aoData[ idx ]._select_selected = true; 34614 $( ctx.aoData[ idx ].nTr ).addClass( ctx._select.className ); 34615 } ); 34616 34617 this.iterator( 'table', function ( ctx, i ) { 34618 eventTrigger( api, 'select', [ 'row', api[i] ], true ); 34619 } ); 34620 34621 return this; 34622} ); 34623 34624apiRegisterPlural( 'columns().select()', 'column().select()', function ( select ) { 34625 var api = this; 34626 34627 if ( select === false ) { 34628 return this.deselect(); 34629 } 34630 34631 this.iterator( 'column', function ( ctx, idx ) { 34632 clear( ctx ); 34633 34634 ctx.aoColumns[ idx ]._select_selected = true; 34635 34636 var column = new DataTable.Api( ctx ).column( idx ); 34637 34638 $( column.header() ).addClass( ctx._select.className ); 34639 $( column.footer() ).addClass( ctx._select.className ); 34640 34641 column.nodes().to$().addClass( ctx._select.className ); 34642 } ); 34643 34644 this.iterator( 'table', function ( ctx, i ) { 34645 eventTrigger( api, 'select', [ 'column', api[i] ], true ); 34646 } ); 34647 34648 return this; 34649} ); 34650 34651apiRegisterPlural( 'cells().select()', 'cell().select()', function ( select ) { 34652 var api = this; 34653 34654 if ( select === false ) { 34655 return this.deselect(); 34656 } 34657 34658 this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) { 34659 clear( ctx ); 34660 34661 var data = ctx.aoData[ rowIdx ]; 34662 34663 if ( data._selected_cells === undefined ) { 34664 data._selected_cells = []; 34665 } 34666 34667 data._selected_cells[ colIdx ] = true; 34668 34669 if ( data.anCells ) {
34670 $( data.anCells[ colIdx ] ).addClass( ctx._select.className ); 34671 } 34672 } ); 34673 34674 this.iterator( 'table', function ( ctx, i ) { 34675 eventTrigger( api, 'select', [ 'cell', api[i] ], true ); 34676 } ); 34677 34678 return this; 34679} ); 34680 34681 34682apiRegisterPlural( 'rows().deselect()', 'row().deselect()', function () { 34683 var api = this; 34684 34685 this.iterator( 'row', function ( ctx, idx ) { 34686 ctx.aoData[ idx ]._select_selected = false; 34687 $( ctx.aoData[ idx ].nTr ).removeClass( ctx._select.className ); 34688 } ); 34689 34690 this.iterator( 'table', function ( ctx, i ) { 34691 eventTrigger( api, 'deselect', [ 'row', api[i] ], true ); 34692 } ); 34693 34694 return this; 34695} ); 34696 34697apiRegisterPlural( 'columns().deselect()', 'column().deselect()', function () { 34698 var api = this; 34699 34700 this.iterator( 'column', function ( ctx, idx ) { 34701 ctx.aoColumns[ idx ]._select_selected = false; 34702 34703 var api = new DataTable.Api( ctx ); 34704 var column = api.column( idx ); 34705 34706 $( column.header() ).removeClass( ctx._select.className ); 34707 $( column.footer() ).removeClass( ctx._select.className ); 34708 34709 // Need to loop over each cell, rather than just using 34710 // `column().nodes()` as cells which are individually selected should 34711 // not have the `selected` class removed from them 34712 api.cells( null, idx ).indexes().each( function (cellIdx) { 34713 var data = ctx.aoData[ cellIdx.row ]; 34714 var cellSelected = data._selected_cells; 34715 34716 if ( data.anCells && (! cellSelected || ! cellSelected[ cellIdx.column ]) ) { 34717 $( data.anCells[ cellIdx.column ] ).removeClass( ctx._select.className ); 34718 } 34719 } ); 34720 } ); 34721 34722 this.iterator( 'table', function ( ctx, i ) { 34723 eventTrigger( api, 'deselect', [ 'column', api[i] ], true ); 34724 } ); 34725 34726 return this; 34727} ); 34728 34729apiRegisterPlural( 'cells().deselect()', 'cell().deselect()', function () { 34730 var api = this; 34731 34732 this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) { 34733 var data = ctx.aoData[ rowIdx ]; 34734 34735 data._selected_cells[ colIdx ] = false; 34736 34737 // Remove class only if the cells exist, and the cell is not column 34738 // selected, in which case the class should remain (since it is selected 34739 // in the column) 34740 if ( data.anCells && ! ctx.aoColumns[ colIdx ]._select_selected ) { 34741 $( data.anCells[ colIdx ] ).removeClass( ctx._select.className ); 34742 } 34743 } ); 34744 34745 this.iterator( 'table', function ( ctx, i ) { 34746 eventTrigger( api, 'deselect', [ 'cell', api[i] ], true ); 34747 } ); 34748 34749 return this; 34750} ); 34751 34752 34753 34754/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 34755 * Buttons 34756 */ 34757function i18n( label, def ) { 34758 return function (dt) { 34759 return dt.i18n( 'buttons.'+label, def ); 34760 }; 34761} 34762 34763// Common events with suitable namespaces 34764function namespacedEvents ( config ) { 34765 var unique = config._eventNamespace; 34766 34767 return 'draw.dt.DT'+unique+' select.dt.DT'+unique+' deselect.dt.DT'+unique; 34768} 34769 34770function enabled ( dt, config ) { 34771 if ( $.inArray( 'rows', config.limitTo ) !== -1 && dt.rows( { selected: true } ).any() ) { 34772 return true; 34773 } 34774 34775 if ( $.inArray( 'columns', config.limitTo ) !== -1 && dt.columns( { selected: true } ).any() ) { 34776 return true; 34777 } 34778 34779 if ( $.inArray( 'cells', config.limitTo ) !== -1 && dt.cells( { selected: true } ).any() ) { 34780 return true; 34781 } 34782 34783 return false; 34784} 34785 34786var _buttonNamespace = 0; 34787 34788$.extend( DataTable.ext.buttons, { 34789 selected: { 34790 text: i18n( 'selected', 'Selected' ), 34791 className: 'buttons-selected', 34792 limitTo: [ 'rows', 'columns', 'cells' ], 34793 init: function ( dt, node, config ) { 34794 var that = this; 34795 config._eventNamespace = '.select'+(_buttonNamespace++); 34796 34797 // .DT namespace listeners are removed by DataTables automatically 34798 // on table destroy 34799 dt.on( namespacedEvents(config), function () { 34800 that.enable( enabled(dt, config) ); 34801 } ); 34802 34803 this.disable(); 34804 }, 34805 destroy: function ( dt, node, config ) { 34806 dt.off( config._eventNamespace ); 34807 } 34808 }, 34809 selectedSingle: { 34810 text: i18n( 'selectedSingle', 'Selected single' ), 34811 className: 'buttons-selected-single', 34812 init: function ( dt, node, config ) { 34813 var that = this; 34814 config._eventNamespace = '.select'+(_buttonNamespace++); 34815 34816 dt.on( namespacedEvents(config), function () { 34817 var count = dt.rows( { selected: true } ).flatten().length + 34818 dt.columns( { selected: true } ).flatten().length + 34819 dt.cells( { selected: true } ).flatten().length; 34820 34821 that.enable( count === 1 ); 34822 } ); 34823 34824 this.disable(); 34825 }, 34826 destroy: function ( dt, node, config ) { 34827 dt.off( config._eventNamespace ); 34828 } 34829 }, 34830 selectAll: { 34831 text: i18n( 'selectAll', 'Select all' ), 34832 className: 'buttons-select-all', 34833 action: function () { 34834 var items = this.select.items(); 34835 this[ items+'s' ]().select(); 34836 } 34837 }, 34838 selectNone: { 34839 text: i18n( 'selectNone', 'Deselect all' ), 34840 className: 'buttons-select-none', 34841 action: function () { 34842 clear( this.settings()[0], true ); 34843 }, 34844 init: function ( dt, node, config ) { 34845 var that = this; 34846 config._eventNamespace = '.select'+(_buttonNamespace++); 34847 34848 dt.on( namespacedEvents(config), function () { 34849 var count = dt.rows( { selected: true } ).flatten().length + 34850 dt.columns( { selected: true } ).flatten().length + 34851 dt.cells( { selected: true } ).flatten().length; 34852 34853 that.enable( count > 0 ); 34854 } ); 34855 34856 this.disable(); 34857 }, 34858 destroy: function ( dt, node, config ) { 34859 dt.off( config._eventNamespace ); 34860 } 34861 } 34862} ); 34863 34864$.each( [ 'Row', 'Column', 'Cell' ], function ( i, item ) { 34865 var lc = item.toLowerCase(); 34866 34867 DataTable.ext.buttons[ 'select'+item+'s' ] = { 34868 text: i18n( 'select'+item+'s', 'Select '+lc+'s' ), 34869 className: 'buttons-select-'+lc+'s', 34870 action: function () { 34871 this.select.items( lc ); 34872 }, 34873 init: function ( dt ) { 34874 var that = this; 34875 34876 dt.on( 'selectItems.dt.DT', function ( e, ctx, items ) { 34877 that.active( items === lc ); 34878 } ); 34879 } 34880 }; 34881} ); 34882 34883 34884 34885/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 34886 * Initialisation 34887 */ 34888 34889// DataTables creation - check if select has been defined in the options. Note 34890// this required that the table be in the document! If it isn't then something 34891// needs to trigger this method unfortunately. The next major release of 34892// DataTables will rework the events and address this. 34893$(document).on( 'preInit.dt.dtSelect', function (e, ctx) { 34894 if ( e.namespace !== 'dt' ) { 34895 return; 34896 } 34897 34898 DataTable.select.init( new DataTable.Api( ctx ) ); 34899} ); 34900 34901 34902return DataTable.select; 34903})); 34904 34905
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.