1/*! Tablesaw - v3.1.0 - 2018-12-10 2* https://github.com/filamentgroup/tablesaw 3* Copyright (c) 2018 Filament Group; Licensed MIT */ 4(function (root, factory) { 5 if (typeof define === 'function' && define.amd) { 6 define(["jquery"], function (jQuery) { 7 return (root.Tablesaw = factory(jQuery, root)); 8 }); 9 } else if (typeof exports === 'object') { 10 if( "document" in root ) { 11 module.exports = factory(require('jquery'), root); 12 } else { 13 // special jQuery case for CommonJS (pass in a window) 14 module.exports = factory(require('jquery')(root), root); 15 } 16 } else { 17 root.Tablesaw = factory(jQuery, root); 18 } 19}(typeof window !== "undefined" ? window : this, function ($, window) { 20 "use strict"; 21 22 var document = window.document; 23 24// Account for Tablesaw being loaded either before or after the DOMContentLoaded event is fired. 25var domContentLoadedTriggered = /complete|loaded/.test(document.readyState); 26document.addEventListener("DOMContentLoaded", function() { 27 domContentLoadedTriggered = true; 28}); 29 30var Tablesaw = { 31 i18n: { 32 modeStack: "Stack", 33 modeSwipe: "Swipe", 34 modeToggle: "Toggle", 35 modeSwitchColumnsAbbreviated: "Cols", 36 modeSwitchColumns: "Columns", 37 columnToggleButton: "Columns", 38 columnToggleError: "No eligible columns.", 39 sort: "Sort", 40 swipePreviousColumn: "Previous column", 41 swipeNextColumn: "Next column" 42 }, 43 // cut the mustard 44 mustard: 45 "head" in document && // IE9+, Firefox 4+, Safari 5.1+, Mobile Safari 4.1+, Opera 11.5+, Android 2.3+ 46 (!window.blackberry || window.WebKitPoint) && // only WebKit Blackberry (OS 6+) 47 !window.operamini, 48 $: $, 49 _init: function(element) { 50 Tablesaw.$(element || document).trigger("enhance.tablesaw"); 51 }, 52 init: function(element) { 53 // Account for Tablesaw being loaded either before or after the DOMContentLoaded event is fired. 54 domContentLoadedTriggered = 55 domContentLoadedTriggered || /complete|loaded/.test(document.readyState); 56 if (!domContentLoadedTriggered) { 57 if ("addEventListener" in document) { 58 // Use raw DOMContentLoaded instead of shoestring (may have issues in Android 2.3, exhibited by stack table) 59 document.addEventListener("DOMContentLoaded", function() { 60 Tablesaw._init(element); 61 }); 62 } 63 } else { 64 Tablesaw._init(element); 65 } 66 } 67}; 68 69$(document).on("enhance.tablesaw", function() { 70 // Extend i18n config, if one exists. 71 if (typeof TablesawConfig !== "undefined" && TablesawConfig.i18n) { 72 Tablesaw.i18n = $.extend(Tablesaw.i18n, TablesawConfig.i18n || {}); 73 } 74 75 Tablesaw.i18n.modes = [ 76 Tablesaw.i18n.modeStack, 77 Tablesaw.i18n.modeSwipe, 78 Tablesaw.i18n.modeToggle 79 ]; 80}); 81 82if (Tablesaw.mustard) { 83 $(document.documentElement).addClass("tablesaw-enhanced"); 84} 85 86(function() { 87 var pluginName = "tablesaw"; 88 var classes = { 89 toolbar: "tablesaw-bar" 90 }; 91 var events = { 92 create: "tablesawcreate", 93 destroy: "tablesawdestroy", 94 refresh: "tablesawrefresh", 95 resize: "tablesawresize" 96 }; 97 var defaultMode = "stack"; 98 var initSelector = "table"; 99 var initFilterSelector = "[data-tablesaw],[data-tablesaw-mode],[data-tablesaw-sortable]"; 100 var defaultConfig = {}; 101 102 Tablesaw.events = events; 103 104 var Table = function(element) { 105 if (!element) { 106 throw new Error("Tablesaw requires an element."); 107 } 108 109 this.table = element; 110 this.$table = $(element); 111 112 // only one <thead> and <tfoot> are allowed, per the specification 113 this.$thead = this.$table 114 .children() 115 .filter("thead") 116 .eq(0); 117 118 // multiple <tbody> are allowed, per the specification 119 this.$tbody = this.$table.children().filter("tbody"); 120 121 this.mode = this.$table.attr("data-tablesaw-mode") || defaultMode; 122 123 this.$toolbar = null; 124 125 this.attributes = { 126 subrow: "data-tablesaw-subrow", 127 ignorerow: "data-tablesaw-ignorerow" 128 }; 129 130 this.init(); 131 }; 132 133 Table.prototype.init = function() { 134 if (!this.$thead.length) { 135 throw new Error("tablesaw: a <thead> is required, but none was found."); 136 } 137 138 if (!this.$thead.find("th").length) { 139 throw new Error("tablesaw: no header cells found. Are you using <th> inside of <thead>?"); 140 } 141 142 // assign an id if there is none 143 if (!this.$table.attr("id")) { 144 this.$table.attr("id", pluginName + "-" + Math.round(Math.random() * 10000)); 145 } 146 147 this.createToolbar(); 148 149 this._initCells(); 150 151 this.$table.data(pluginName, this); 152 153 this.$table.trigger(events.create, [this]); 154 }; 155 156 Table.prototype.getConfig = function(pluginSpecificConfig) { 157 // shoestring extend doesnât support arbitrary args 158 var configs = $.extend(defaultConfig, pluginSpecificConfig || {}); 159 return $.extend(configs, typeof TablesawConfig !== "undefined" ? TablesawConfig : {}); 160 }; 161 162 Table.prototype._getPrimaryHeaderRow = function() { 163 return this._getHeaderRows().eq(0); 164 }; 165 166 Table.prototype._getHeaderRows = function() { 167 return this.$thead 168 .children() 169 .filter("tr") 170 .filter(function() { 171 return !$(this).is("[data-tablesaw-ignorerow]"); 172 }); 173 }; 174 175 Table.prototype._getRowIndex = function($row) { 176 return $row.prevAll().length; 177 }; 178 179 Table.prototype._getHeaderRowIndeces = function() { 180 var self = this; 181 var indeces = []; 182 this._getHeaderRows().each(function() { 183 indeces.push(self._getRowIndex($(this))); 184 }); 185 return indeces; 186 }; 187 188 Table.prototype._getPrimaryHeaderCells = function($row) { 189 return ($row || this._getPrimaryHeaderRow()).find("th"); 190 }; 191 192 Table.prototype._$getCells = function(th) { 193 var self = this; 194 return $(th) 195 .add(th.cells) 196 .filter(function() { 197 var $t = $(this); 198 var $row = $t.parent(); 199 var hasColspan = $t.is("[colspan]"); 200 // no subrows or ignored rows (keep cells in ignored rows that do not have a colspan) 201 return ( 202 !$row.is("[" + self.attributes.subrow + "]") && 203 (!$row.is("[" + self.attributes.ignorerow + "]") || !hasColspan) 204 ); 205 }); 206 }; 207 208 Table.prototype._getVisibleColspan = function() { 209 var colspan = 0; 210 this._getPrimaryHeaderCells().each(function() { 211 var $t = $(this); 212 if ($t.css("display") !== "none") { 213 colspan += parseInt($t.attr("colspan"), 10) || 1; 214 } 215 }); 216 return colspan; 217 }; 218 219 Table.prototype.getColspanForCell = function($cell) { 220 var visibleColspan = this._getVisibleColspan(); 221 var visibleSiblingColumns = 0; 222 if ($cell.closest("tr").data("tablesaw-rowspanned")) { 223 visibleSiblingColumns++; 224 } 225 226 $cell.siblings().each(function() { 227 var $t = $(this); 228 var colColspan = parseInt($t.attr("colspan"), 10) || 1; 229 230 if ($t.css("display") !== "none") { 231 visibleSiblingColumns += colColspan; 232 } 233 }); 234 // console.log( $cell[ 0 ], visibleColspan, visibleSiblingColumns ); 235 236 return visibleColspan - visibleSiblingColumns; 237 }; 238 239 Table.prototype.isCellInColumn = function(header, cell) { 240 return $(header) 241 .add(header.cells) 242 .filter(function() { 243 return this === cell; 244 }).length; 245 }; 246 247 Table.prototype.updateColspanCells = function(cls, header, userAction) { 248 var self = this; 249 var primaryHeaderRow = self._getPrimaryHeaderRow(); 250 251 // find persistent column rowspans
252 this.$table.find("[rowspan][data-tablesaw-priority]").each(function() { 253 var $t = $(this); 254 if ($t.attr("data-tablesaw-priority") !== "persist") { 255 return; 256 } 257 258 var $row = $t.closest("tr"); 259 var rowspan = parseInt($t.attr("rowspan"), 10); 260 if (rowspan > 1) { 261 $row = $row.next(); 262 263 $row.data("tablesaw-rowspanned", true); 264 265 rowspan--; 266 } 267 }); 268 269 this.$table 270 .find("[colspan],[data-tablesaw-maxcolspan]") 271 .filter(function() { 272 // is not in primary header row 273 return $(this).closest("tr")[0] !== primaryHeaderRow[0]; 274 }) 275 .each(function() { 276 var $cell = $(this); 277 278 if (userAction === undefined || self.isCellInColumn(header, this)) { 279 } else { 280 // if is not a user action AND the cell is not in the updating column, kill it 281 return; 282 } 283 284 var colspan = self.getColspanForCell($cell); 285 286 if (cls && userAction !== undefined) { 287 // console.log( colspan === 0 ? "addClass" : "removeClass", $cell ); 288 $cell[colspan === 0 ? "addClass" : "removeClass"](cls); 289 } 290 291 // cache original colspan 292 var maxColspan = parseInt($cell.attr("data-tablesaw-maxcolspan"), 10); 293 if (!maxColspan) { 294 $cell.attr("data-tablesaw-maxcolspan", $cell.attr("colspan")); 295 } else if (colspan > maxColspan) { 296 colspan = maxColspan; 297 } 298 299 // console.log( this, "setting colspan to ", colspan ); 300 $cell.attr("colspan", colspan); 301 }); 302 }; 303 304 Table.prototype._findPrimaryHeadersForCell = function(cell) { 305 var $headerRow = this._getPrimaryHeaderRow(); 306 var headerRowIndex = this._getRowIndex($headerRow); 307 var results = []; 308 309 for (var rowNumber = 0; rowNumber < this.headerMapping.length; rowNumber++) { 310 if (rowNumber === headerRowIndex) { 311 continue; 312 } 313 314 for (var colNumber = 0; colNumber < this.headerMapping[rowNumber].length; colNumber++) { 315 if (this.headerMapping[rowNumber][colNumber] === cell) { 316 results.push(this.headerMapping[headerRowIndex][colNumber]); 317 } 318 } 319 } 320 321 return results; 322 }; 323 324 // used by init cells 325 Table.prototype.getRows = function() { 326 var self = this; 327 return this.$table.find("tr").filter(function() { 328 return $(this) 329 .closest("table") 330 .is(self.$table); 331 }); 332 }; 333 334 // used by sortable 335 Table.prototype.getBodyRows = function(tbody) { 336 return (tbody ? $(tbody) : this.$tbody).children().filter("tr"); 337 }; 338 339 Table.prototype.getHeaderCellIndex = function(cell) { 340 var lookup = this.headerMapping[0]; 341 for (var colIndex = 0; colIndex < lookup.length; colIndex++) { 342 if (lookup[colIndex] === cell) { 343 return colIndex; 344 } 345 } 346 347 return -1; 348 }; 349 350 Table.prototype._initCells = function() { 351 // re-establish original colspans 352 this.$table.find("[data-tablesaw-maxcolspan]").each(function() { 353 var $t = $(this); 354 $t.attr("colspan", $t.attr("data-tablesaw-maxcolspan")); 355 }); 356 357 var $rows = this.getRows(); 358 var columnLookup = []; 359 360 $rows.each(function(rowNumber) { 361 columnLookup[rowNumber] = []; 362 }); 363 364 $rows.each(function(rowNumber) { 365 var coltally = 0; 366 var $t = $(this); 367 var children = $t.children(); 368 369 children.each(function() { 370 var colspan = parseInt( 371 this.getAttribute("data-tablesaw-maxcolspan") || this.getAttribute("colspan"), 372 10 373 ); 374 var rowspan = parseInt(this.getAttribute("rowspan"), 10); 375 376 // set in a previous rowspan 377 while (columnLookup[rowNumber][coltally]) { 378 coltally++; 379 } 380 381 columnLookup[rowNumber][coltally] = this; 382 383 // TODO? both colspan and rowspan 384 if (colspan) { 385 for (var k = 0; k < colspan - 1; k++) { 386 coltally++; 387 columnLookup[rowNumber][coltally] = this; 388 } 389 } 390 if (rowspan) { 391 for (var j = 1; j < rowspan; j++) { 392 columnLookup[rowNumber + j][coltally] = this; 393 } 394 } 395 396 coltally++; 397 }); 398 }); 399 400 var headerRowIndeces = this._getHeaderRowIndeces(); 401 for (var colNumber = 0; colNumber < columnLookup[0].length; colNumber++) { 402 for (var headerIndex = 0, k = headerRowIndeces.length; headerIndex < k; headerIndex++) { 403 var headerCol = columnLookup[headerRowIndeces[headerIndex]][colNumber]; 404 405 var rowNumber = headerRowIndeces[headerIndex]; 406 var rowCell; 407 408 if (!headerCol.cells) { 409 headerCol.cells = []; 410 } 411 412 while (rowNumber < columnLookup.length) { 413 rowCell = columnLookup[rowNumber][colNumber]; 414 415 if (headerCol !== rowCell) { 416 headerCol.cells.push(rowCell); 417 } 418 419 rowNumber++; 420 } 421 } 422 } 423 424 this.headerMapping = columnLookup; 425 }; 426 427 Table.prototype.refresh = function() { 428 this._initCells(); 429 430 this.$table.trigger(events.refresh, [this]); 431 }; 432 433 Table.prototype._getToolbarAnchor = function() { 434 var $parent = this.$table.parent(); 435 if ($parent.is(".tablesaw-overflow")) { 436 return $parent; 437 } 438 return this.$table; 439 }; 440 441 Table.prototype._getToolbar = function($anchor) { 442 if (!$anchor) { 443 $anchor = this._getToolbarAnchor(); 444 } 445 return $anchor.prev().filter("." + classes.toolbar); 446 }; 447 448 Table.prototype.createToolbar = function() { 449 // Insert the toolbar 450 // TODO move this into a separate component 451 var $anchor = this._getToolbarAnchor(); 452 var $toolbar = this._getToolbar($anchor); 453 if (!$toolbar.length) { 454 $toolbar = $("<div>")
455 .addClass(classes.toolbar) 456 .insertBefore($anchor); 457 } 458 this.$toolbar = $toolbar; 459 460 if (this.mode) { 461 this.$toolbar.addClass("tablesaw-mode-" + this.mode); 462 } 463 }; 464 465 Table.prototype.destroy = function() { 466 // Donât remove the toolbar, just erase the classes on it. 467 // Some of the table features are not yet destroy-friendly. 468 this._getToolbar().each(function() { 469 this.className = this.className.replace(/\btablesaw-mode\-\w*\b/gi, ""); 470 }); 471 472 var tableId = this.$table.attr("id"); 473 $(document).off("." + tableId); 474 $(window).off("." + tableId); 475 476 // other plugins 477 this.$table.trigger(events.destroy, [this]); 478 479 this.$table.removeData(pluginName); 480 }; 481 482 // Collection method. 483 $.fn[pluginName] = function() { 484 return this.each(function() { 485 var $t = $(this); 486 487 if ($t.data(pluginName)) { 488 return; 489 } 490 491 new Table(this); 492 }); 493 }; 494 495 var $doc = $(document); 496 $doc.on("enhance.tablesaw", function(e) { 497 // Cut the mustard 498 if (Tablesaw.mustard) { 499 var $target = $(e.target); 500 if ($target.parent().length) { 501 $target = $target.parent(); 502 } 503 504 $target 505 .find(initSelector) 506 .filter(initFilterSelector) 507 [pluginName](); 508 } 509 }); 510 511 // Avoid a resize during scroll: 512 // Some Mobile devices trigger a resize during scroll (sometimes when 513 // doing elastic stretch at the end of the document or from the 514 // location bar hide) 515 var isScrolling = false; 516 var scrollTimeout; 517 $doc.on("scroll.tablesaw", function() { 518 isScrolling = true; 519 520 window.clearTimeout(scrollTimeout); 521 scrollTimeout = window.setTimeout(function() { 522 isScrolling = false; 523 }, 300); // must be greater than the resize timeout below 524 }); 525 526 var resizeTimeout; 527 $(window).on("resize", function() { 528 if (!isScrolling) { 529 window.clearTimeout(resizeTimeout); 530 resizeTimeout = window.setTimeout(function() { 531 $doc.trigger(events.resize); 532 }, 150); // must be less than the scrolling timeout above. 533 } 534 }); 535 536 Tablesaw.Table = Table; 537})(); 538 539(function() { 540 var classes = { 541 stackTable: "tablesaw-stack", 542 cellLabels: "tablesaw-cell-label", 543 cellContentLabels: "tablesaw-cell-content" 544 }; 545 546 var data = { 547 key: "tablesaw-stack" 548 }; 549 550 var attrs = { 551 labelless: "data-tablesaw-no-labels", 552 hideempty: "data-tablesaw-hide-empty" 553 }; 554 555 var Stack = function(element, tablesaw) { 556 this.tablesaw = tablesaw; 557 this.$table = $(element); 558 559 this.labelless = this.$table.is("[" + attrs.labelless + "]"); 560 this.hideempty = this.$table.is("[" + attrs.hideempty + "]"); 561 562 this.$table.data(data.key, this); 563 }; 564 565 Stack.prototype.init = function() {
566 this.$table.addClass(classes.stackTable); 567 568 if (this.labelless) { 569 return; 570 } 571 572 var self = this; 573 574 this.$table 575 .find("th, td") 576 .filter(function() { 577 return !$(this).closest("thead").length; 578 }) 579 .filter(function() { 580 return ( 581 !$(this).is("[" + attrs.labelless + "]") && 582 !$(this) 583 .closest("tr") 584 .is("[" + attrs.labelless + "]") && 585 (!self.hideempty || !!$(this).html()) 586 ); 587 }) 588 .each(function() { 589 var $newHeader = $(document.createElement("b")).addClass(classes.cellLabels); 590 var $cell = $(this); 591 592 $(self.tablesaw._findPrimaryHeadersForCell(this)).each(function(index) { 593 var $header = $(this.cloneNode(true)); 594 // TODO decouple from sortable better 595 // Changed from .text() in https://github.com/filamentgroup/tablesaw/commit/b9c12a8f893ec192830ec3ba2d75f062642f935b 596 // to preserve structural html in headers, like <a> 597 var $sortableButton = $header.find(".tablesaw-sortable-btn"); 598 $header.find(".tablesaw-sortable-arrow").remove(); 599 600 // TODO decouple from checkall better 601 var $checkall = $header.find("[data-tablesaw-checkall]"); 602 $checkall.closest("label").remove(); 603 if ($checkall.length) { 604 $newHeader = $([]); 605 return; 606 } 607 608 if (index > 0) { 609 $newHeader.append(document.createTextNode(", ")); 610 } 611 612 var parentNode = $sortableButton.length ? $sortableButton[0] : $header[0]; 613 var el; 614 while ((el = parentNode.firstChild)) { 615 $newHeader[0].appendChild(el); 616 } 617 }); 618 619 if ($newHeader.length && !$cell.find("." + classes.cellContentLabels).length) { 620 $cell.wrapInner("<span class='" + classes.cellContentLabels + "'></span>"); 621 } 622 623 // Update if already exists. 624 var $label = $cell.find("." + classes.cellLabels); 625 if (!$label.length) { 626 $cell.prepend(document.createTextNode(" ")); 627 $cell.prepend($newHeader); 628 } else { 629 // only if changed 630 $label.replaceWith($newHeader); 631 } 632 }); 633 }; 634 635 Stack.prototype.destroy = function() { 636 this.$table.removeClass(classes.stackTable); 637 this.$table.find("." + classes.cellLabels).remove(); 638 this.$table.find("." + classes.cellContentLabels).each(function() { 639 $(this).replaceWith($(this.childNodes)); 640 }); 641 }; 642 643 // on tablecreate, init 644 $(document) 645 .on(Tablesaw.events.create, function(e, tablesaw) { 646 if (tablesaw.mode === "stack") { 647 var table = new Stack(tablesaw.table, tablesaw); 648 table.init(); 649 } 650 }) 651 .on(Tablesaw.events.refresh, function(e, tablesaw) { 652 if (tablesaw.mode === "stack") { 653 $(tablesaw.table) 654 .data(data.key) 655 .init(); 656 } 657 }) 658 .on(Tablesaw.events.destroy, function(e, tablesaw) { 659 if (tablesaw.mode === "stack") { 660 $(tablesaw.table) 661 .data(data.key) 662 .destroy(); 663 } 664 }); 665 666 Tablesaw.Stack = Stack; 667})(); 668 669 return Tablesaw; 670}));
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.