1/*! Tablesaw - v2.0.1 - 2015-10-09 2* https://github.com/filamentgroup/tablesaw 3* Copyright (c) 2015 Filament Group; Licensed MIT */ 4/* 5* tablesaw: A set of plugins for responsive tables 6* Stack and Column Toggle tables 7* Copyright (c) 2013 Filament Group, Inc. 8* MIT License 9*/ 10 11if( typeof Tablesaw === "undefined" ) { 12 Tablesaw = { 13 i18n: { 14 modes: [ 'Stack', 'Swipe', 'Toggle' ], 15 columns: 'Col<span class=\"a11y-sm\">umn</span>s', 16 columnBtnText: 'Columns', 17 columnsDialogError: 'No eligible columns.', 18 sort: 'Sort' 19 }, 20 // cut the mustard 21 mustard: 'querySelector' in document && 22 ( !window.blackberry || window.WebKitPoint ) && 23 !window.operamini 24 }; 25} 26if( !Tablesaw.config ) { 27 Tablesaw.config = {}; 28} 29if( Tablesaw.mustard ) { 30 jQuery( document.documentElement ).addClass( 'tablesaw-enhanced' ); 31} 32 33;(function( $ ) { 34 var pluginName = "table", 35 classes = { 36 toolbar: "tablesaw-bar" 37 }, 38 events = { 39 create: "tablesawcreate", 40 destroy: "tablesawdestroy", 41 refresh: "tablesawrefresh" 42 }, 43 defaultMode = "stack", 44 initSelector = "table[data-tablesaw-mode],table[data-tablesaw-sortable]"; 45 46 var Table = function( element ) { 47 if( !element ) { 48 throw new Error( "Tablesaw requires an element." ); 49 } 50 51 this.table = element; 52 this.$table = $( element ); 53 54 this.mode = this.$table.attr( "data-tablesaw-mode" ) || defaultMode; 55 56 this.init(); 57 }; 58 59 Table.prototype.init = function() { 60 // assign an id if there is none 61 if ( !this.$table.attr( "id" ) ) { 62 this.$table.attr( "id", pluginName + "-" + Math.round( Math.random() * 10000 ) ); 63 } 64 65 this.createToolbar(); 66 67 var colstart = this._initCells(); 68 69 this.$table.trigger( events.create, [ this, colstart ] ); 70 }; 71 72 Table.prototype._initCells = function() { 73 var colstart, 74 thrs = this.table.querySelectorAll( "thead tr" ), 75 self = this; 76 77 $( thrs ).each( function(){ 78 var coltally = 0; 79 80 $( this ).children().each( function(){ 81 var span = parseInt( this.getAttribute( "colspan" ), 10 ), 82 sel = ":nth-child(" + ( coltally + 1 ) + ")"; 83 84 colstart = coltally + 1; 85 86 if( span ){ 87 for( var k = 0; k < span - 1; k++ ){ 88 coltally++; 89 sel += ", :nth-child(" + ( coltally + 1 ) + ")"; 90 } 91 } 92 93 // Store "cells" data on header as a reference to all cells in the same column as this TH 94 this.cells = self.$table.find("tr").not( thrs[0] ).not( this ).children().filter( sel ); 95 coltally++; 96 }); 97 }); 98 99 return colstart; 100 }; 101 102 Table.prototype.refresh = function() { 103 this._initCells(); 104 105 this.$table.trigger( events.refresh ); 106 }; 107 108 Table.prototype.createToolbar = function() { 109 // Insert the toolbar 110 // TODO move this into a separate component 111 var $toolbar = this.$table.prev().filter( '.' + classes.toolbar ); 112 if( !$toolbar.length ) { 113 $toolbar = $( '<div>' ) 114 .addClass( classes.toolbar ) 115 .insertBefore( this.$table ); 116 } 117 this.$toolbar = $toolbar; 118 119 if( this.mode ) { 120 this.$toolbar.addClass( 'mode-' + this.mode ); 121 } 122 }; 123 124 Table.prototype.destroy = function() { 125 // Donât remove the toolbar. Some of the table features are not yet destroy-friendly. 126 this.$table.prev().filter( '.' + classes.toolbar ).each(function() { 127 this.className = this.className.replace( /\bmode\-\w*\b/gi, '' ); 128 }); 129 130 var tableId = this.$table.attr( 'id' ); 131 $( document ).unbind( "." + tableId ); 132 $( window ).unbind( "." + tableId ); 133 134 // other plugins 135 this.$table.trigger( events.destroy, [ this ] ); 136 137 this.$table.removeAttr( 'data-tablesaw-mode' ); 138 139 this.$table.removeData( pluginName ); 140 }; 141 142 // Collection method. 143 $.fn[ pluginName ] = function() { 144 return this.each( function() { 145 var $t = $( this ); 146 147 if( $t.data( pluginName ) ){ 148 return; 149 } 150 151 var table = new Table( this ); 152 $t.data( pluginName, table ); 153 }); 154 }; 155 156 $( document ).on( "enhance.tablesaw", function( e ) { 157 // Cut the mustard 158 if( Tablesaw.mustard ) { 159 $( e.target ).find( initSelector )[ pluginName ](); 160 } 161 }); 162 163}( jQuery )); 164 165;(function( win, $, undefined ){ 166 167 var classes = { 168 stackTable: 'tablesaw-stack', 169 cellLabels: 'tablesaw-cell-label', 170 cellContentLabels: 'tablesaw-cell-content' 171 }; 172 173 var data = { 174 obj: 'tablesaw-stack' 175 }; 176 177 var attrs = { 178 labelless: 'data-tablesaw-no-labels', 179 hideempty: 'data-tablesaw-hide-empty' 180 }; 181 182 var Stack = function( element ) { 183 184 this.$table = $( element ); 185 186 this.labelless = this.$table.is( '[' + attrs.labelless + ']' ); 187 this.hideempty = this.$table.is( '[' + attrs.hideempty + ']' ); 188 189 if( !this.labelless ) { 190 // allHeaders references headers, plus all THs in the thead, which may include several rows, or not 191 this.allHeaders = this.$table.find( "th" ); 192 } 193 194 this.$table.data( data.obj, this ); 195 }; 196 197 Stack.prototype.init = function( colstart ) { 198 this.$table.addClass( classes.stackTable ); 199 200 if( this.labelless ) { 201 return; 202 } 203 204 // get headers in reverse order so that top-level headers are appended last 205 var reverseHeaders = $( this.allHeaders ); 206 var hideempty = this.hideempty; 207 208 // create the hide/show toggles 209 reverseHeaders.each(function(){ 210 var $t = $( this ), 211 $cells = $( this.cells ).filter(function() { 212 return !$( this ).parent().is( "[" + attrs.labelless + "]" ) && ( !hideempty || !$( this ).is( ":empty" ) ); 213 }), 214 hierarchyClass = $cells.not( this ).filter( "thead th" ).length && " tablesaw-cell-label-top", 215 // TODO reduce coupling with sortable
216 $sortableButton = $t.find( ".tablesaw-sortable-btn" ), 217 html = $sortableButton.length ? $sortableButton.html() : $t.html(); 218 219 if( html !== "" ){ 220 if( hierarchyClass ){ 221 var iteration = parseInt( $( this ).attr( "colspan" ), 10 ), 222 filter = ""; 223 224 if( iteration ){ 225 filter = "td:nth-child("+ iteration +"n + " + ( colstart ) +")"; 226 } 227 $cells.filter( filter ).prepend( "<b class='" + classes.cellLabels + hierarchyClass + "'>" + html + "</b>" ); 228 } else { 229 $cells.wrapInner( "<span class='" + classes.cellContentLabels + "'></span>" ); 230 $cells.prepend( "<b class='" + classes.cellLabels + "'>" + html + "</b>" ); 231 } 232 } 233 }); 234 }; 235 236 Stack.prototype.destroy = function() { 237 this.$table.removeClass( classes.stackTable ); 238 this.$table.find( '.' + classes.cellLabels ).remove(); 239 this.$table.find( '.' + classes.cellContentLabels ).each(function() { 240 $( this ).replaceWith( this.childNodes ); 241 }); 242 }; 243 244 // on tablecreate, init 245 $( document ).on( "tablesawcreate", function( e, Tablesaw, colstart ){ 246 if( Tablesaw.mode === 'stack' ){ 247 var table = new Stack( Tablesaw.table ); 248 table.init( colstart ); 249 } 250 251 } ); 252 253 $( document ).on( "tablesawdestroy", function( e, Tablesaw ){ 254 255 if( Tablesaw.mode === 'stack' ){ 256 $( Tablesaw.table ).data( data.obj ).destroy(); 257 } 258 259 } ); 260 261}( this, jQuery )); 262;(function( $ ) { 263 var pluginName = "tablesawbtn", 264 methods = { 265 _create: function(){ 266 return $( this ).each(function() { 267 $( this ) 268 .trigger( "beforecreate." + pluginName ) 269 [ pluginName ]( "_init" ) 270 .trigger( "create." + pluginName ); 271 }); 272 }, 273 _init: function(){ 274 var oEl = $( this ), 275 sel = this.getElementsByTagName( "select" )[ 0 ]; 276 277 if( sel ) { 278 $( this ) 279 .addClass( "btn-select" ) 280 [ pluginName ]( "_select", sel ); 281 } 282 return oEl; 283 }, 284 _select: function( sel ) { 285 var update = function( oEl, sel ) { 286 var opts = $( sel ).find( "option" ), 287 label, el, children; 288 289 opts.each(function() { 290 var opt = this; 291 if( opt.selected ) { 292 label = document.createTextNode( opt.text ); 293 } 294 }); 295 296 children = oEl.childNodes; 297 if( opts.length > 0 ){ 298 for( var i = 0, l = children.length; i < l; i++ ) { 299 el = children[ i ]; 300 301 if( el && el.nodeType === 3 ) { 302 oEl.replaceChild( label, el ); 303 } 304 } 305 } 306 }; 307 308 update( this, sel ); 309 $( this ).bind( "change refresh", function() { 310 update( this, sel ); 311 }); 312 } 313 }; 314 315 // Collection method. 316 $.fn[ pluginName ] = function( arrg, a, b, c ) { 317 return this.each(function() { 318 319 // if it's a method 320 if( arrg && typeof( arrg ) === "string" ){ 321 return $.fn[ pluginName ].prototype[ arrg ].call( this, a, b, c ); 322 } 323 324 // don't re-init 325 if( $( this ).data( pluginName + "active" ) ){ 326 return $( this ); 327 } 328 329 // otherwise, init 330 331 $( this ).data( pluginName + "active", true ); 332 $.fn[ pluginName ].prototype._create.call( this ); 333 }); 334 }; 335 336 // add methods 337 $.extend( $.fn[ pluginName ].prototype, methods ); 338 339}( jQuery )); 340;(function( win, $, undefined ){ 341 342 var ColumnToggle = function( element ) { 343 344 this.$table = $( element ); 345 346 this.classes = { 347 columnToggleTable: 'tablesaw-columntoggle', 348 columnBtnContain: 'tablesaw-columntoggle-btnwrap tablesaw-advance', 349 columnBtn: 'tablesaw-columntoggle-btn tablesaw-nav-btn down', 350 popup: 'tablesaw-columntoggle-popup', 351 priorityPrefix: 'tablesaw-priority-', 352 // TODO duplicate class, also in tables.js 353 toolbar: 'tablesaw-bar' 354 }; 355 356 // Expose headers and allHeaders properties on the widget 357 // headers references the THs within the first TR in the table 358 this.headers = this.$table.find( 'tr:first > th' ); 359 360 this.$table.data( 'tablesaw-coltoggle', this ); 361 }; 362 363 ColumnToggle.prototype.init = function() { 364 365 var tableId, 366 id, 367 $menuButton, 368 $popup, 369 $menu, 370 $btnContain, 371 self = this; 372 373 this.$table.addClass( this.classes.columnToggleTable ); 374 375 tableId = this.$table.attr( "id" ); 376 id = tableId + "-popup"; 377 $btnContain = $( "<div class='" + this.classes.columnBtnContain + "'></div>" ); 378 $menuButton = $( "<a href='#" + id + "' class='btn btn-micro " + this.classes.columnBtn +"' data-popup-link>" + 379 "<span>" + Tablesaw.i18n.columnBtnText + "</span></a>" ); 380 $popup = $( "<div class='dialog-table-coltoggle " + this.classes.popup + "' id='" + id + "'></div>" ); 381 $menu = $( "<div class='btn-group'></div>" ); 382 383 var hasNonPersistentHeaders = false;
384 $( this.headers ).not( "td" ).each( function() { 385 var $this = $( this ), 386 priority = $this.attr("data-tablesaw-priority"), 387 $cells = $this.add( this.cells ); 388 389 if( priority && priority !== "persist" ) { 390 $cells.addClass( self.classes.priorityPrefix + priority ); 391 392 $("<label><input type='checkbox' checked>" + $this.text() + "</label>" ) 393 .appendTo( $menu ) 394 .children( 0 ) 395 .data( "cells", $cells ); 396 397 hasNonPersistentHeaders = true; 398 } 399 }); 400 401 if( !hasNonPersistentHeaders ) { 402 $menu.append( '<label>' + Tablesaw.i18n.columnsDialogError + '</label>' ); 403 } 404 405 $menu.appendTo( $popup ); 406 407 // bind change event listeners to inputs - TODO: move to a private method? 408 $menu.find( 'input[type="checkbox"]' ).on( "change", function(e) { 409 var checked = e.target.checked; 410 411 $( e.target ).data( "cells" ) 412 .toggleClass( "tablesaw-cell-hidden", !checked ) 413 .toggleClass( "tablesaw-cell-visible", checked ); 414 415 self.$table.trigger( 'tablesawcolumns' ); 416 }); 417 418 $menuButton.appendTo( $btnContain ); 419 $btnContain.appendTo( this.$table.prev().filter( '.' + this.classes.toolbar ) ); 420 421 var closeTimeout; 422 function openPopup() { 423 $btnContain.addClass( 'visible' ); 424 $menuButton.removeClass( 'down' ).addClass( 'up' ); 425 426 $( document ).unbind( 'click.' + tableId, closePopup ); 427 428 window.clearTimeout( closeTimeout ); 429 closeTimeout = window.setTimeout(function() { 430 $( document ).one( 'click.' + tableId, closePopup ); 431 }, 15 ); 432 } 433 434 function closePopup( event ) { 435 // Click came from inside the popup, ignore. 436 if( event && $( event.target ).closest( "." + self.classes.popup ).length ) { 437 return; 438 } 439 440 $( document ).unbind( 'click.' + tableId ); 441 $menuButton.removeClass( 'up' ).addClass( 'down' ); 442 $btnContain.removeClass( 'visible' ); 443 } 444 445 $menuButton.on( "click.tablesaw", function( event ) { 446 event.preventDefault(); 447 448 if( !$btnContain.is( ".visible" ) ) { 449 openPopup(); 450 } else { 451 closePopup(); 452 } 453 }); 454 455 $popup.appendTo( $btnContain ); 456 457 this.$menu = $menu; 458 459 $(window).on( "resize." + tableId, function(){ 460 self.refreshToggle(); 461 }); 462 463 this.refreshToggle(); 464 }; 465 466 ColumnToggle.prototype.refreshToggle = function() { 467 this.$menu.find( "input" ).each( function() { 468 var $this = $( this ); 469 470 this.checked = $this.data( "cells" ).eq( 0 ).css( "display" ) === "table-cell"; 471 }); 472 }; 473 474 ColumnToggle.prototype.refreshPriority = function(){ 475 var self = this; 476 $(this.headers).not( "td" ).each( function() { 477 var $this = $( this ), 478 priority = $this.attr("data-tablesaw-priority"), 479 $cells = $this.add( this.cells ); 480 481 if( priority && priority !== "persist" ) { 482 $cells.addClass( self.classes.priorityPrefix + priority ); 483 } 484 }); 485 }; 486 487 ColumnToggle.prototype.destroy = function() { 488 // table toolbars, document and window .tableId events 489 // removed in parent tables.js destroy method 490 491 this.$table.removeClass( this.classes.columnToggleTable ); 492 this.$table.find( 'th, td' ).each(function() { 493 var $cell = $( this ); 494 $cell.removeClass( 'tablesaw-cell-hidden' ) 495 .removeClass( 'tablesaw-cell-visible' ); 496 497 this.className = this.className.replace( /\bui\-table\-priority\-\d\b/g, '' ); 498 }); 499 }; 500 501 // on tablecreate, init 502 $( document ).on( "tablesawcreate", function( e, Tablesaw ){ 503 504 if( Tablesaw.mode === 'columntoggle' ){ 505 var table = new ColumnToggle( Tablesaw.table ); 506 table.init(); 507 } 508 509 } ); 510 511 $( document ).on( "tablesawdestroy", function( e, Tablesaw ){ 512 if( Tablesaw.mode === 'columntoggle' ){ 513 $( Tablesaw.table ).data( 'tablesaw-coltoggle' ).destroy(); 514 } 515 } ); 516 517}( this, jQuery )); 518;(function( win, $, undefined ){ 519 520 $.extend( Tablesaw.config, { 521 swipe: { 522 horizontalThreshold: 15, 523 verticalThreshold: 30 524 } 525 }); 526 527 function isIE8() { 528 var div = document.createElement('div'), 529 all = div.getElementsByTagName('i'); 530 531 div.innerHTML = '<!--[if lte IE 8]><i></i><![endif]-->'; 532 533 return !!all.length; 534 } 535 536 function createSwipeTable( $table ){ 537 538 var $btns = $( "<div class='tablesaw-advance'></div>" ), 539 $prevBtn = $( "<a href='#' class='tablesaw-nav-btn btn btn-micro left' title='Previous Column'></a>" ).appendTo( $btns ), 540 $nextBtn = $( "<a href='#' class='tablesaw-nav-btn btn btn-micro right' title='Next Column'></a>" ).appendTo( $btns ), 541 hideBtn = 'disabled',
542 persistWidths = 'tablesaw-fix-persist', 543 $headerCells = $table.find( "thead th" ), 544 $headerCellsNoPersist = $headerCells.not( '[data-tablesaw-priority="persist"]' ), 545 headerWidths = [], 546 $head = $( document.head || 'head' ), 547 tableId = $table.attr( 'id' ), 548 // TODO switch this to an nth-child feature test 549 supportsNthChild = !isIE8(); 550 551 if( !$headerCells.length ) { 552 //throw new Error( "tablesaw swipe: no header cells found. Are you using <th> inside of <thead>?" ); 553 } 554 555 // Calculate initial widths 556 $table.css('width', 'auto'); 557 $headerCells.each(function() { 558 headerWidths.push( $( this ).outerWidth() ); 559 }); 560 $table.css( 'width', '' ); 561 562 $btns.appendTo( $table.prev().filter( '.tablesaw-bar' ) ); 563 564 $table.addClass( "tablesaw-swipe" ); 565 566 if( !tableId ) { 567 tableId = 'tableswipe-' + Math.round( Math.random() * 10000 ); 568 $table.attr( 'id', tableId ); 569 } 570 571 function $getCells( headerCell ) { 572 return $( headerCell.cells ).add( headerCell ); 573 } 574 575 function showColumn( headerCell ) { 576 $getCells( headerCell ).removeClass( 'tablesaw-cell-hidden' ); 577 } 578 579 function hideColumn( headerCell ) { 580 $getCells( headerCell ).addClass( 'tablesaw-cell-hidden' ); 581 } 582 583 function persistColumn( headerCell ) { 584 $getCells( headerCell ).addClass( 'tablesaw-cell-persist' ); 585 } 586 587 function isPersistent( headerCell ) { 588 return $( headerCell ).is( '[data-tablesaw-priority="persist"]' ); 589 } 590 591 function unmaintainWidths() { 592 $table.removeClass( persistWidths ); 593 $( '#' + tableId + '-persist' ).remove(); 594 } 595 596 function maintainWidths() { 597 var prefix = '#' + tableId + '.tablesaw-swipe ', 598 styles = [], 599 tableWidth = $table.width(), 600 hash = [], 601 newHash; 602 603 $headerCells.each(function( index ) { 604 var width; 605 if( isPersistent( this ) ) { 606 width = $( this ).outerWidth(); 607 608 // Only save width on non-greedy columns (take up less than 75% of table width) 609 if( width < tableWidth * 0.75 ) { 610 hash.push( index + '-' + width ); 611 styles.push( prefix + ' .tablesaw-cell-persist:nth-child(' + ( index + 1 ) + ') { width: ' + width + 'px; }' ); 612 } 613 } 614 }); 615 newHash = hash.join( '_' ); 616 617 $table.addClass( persistWidths ); 618 619 var $style = $( '#' + tableId + '-persist' ); 620 // If style element not yet added OR if the widths have changed 621 if( !$style.length || $style.data( 'hash' ) !== newHash ) { 622 // Remove existing 623 $style.remove(); 624 625 if( styles.length ) { 626 $( '<style>' + styles.join( "\n" ) + '</style>' ) 627 .attr( 'id', tableId + '-persist' ) 628 .data( 'hash', newHash ) 629 .appendTo( $head ); 630 } 631 } 632 } 633 634 function getNext(){ 635 var next = [], 636 checkFound; 637 638 $headerCellsNoPersist.each(function( i ) { 639 var $t = $( this ), 640 isHidden = $t.css( "display" ) === "none" || $t.is( ".tablesaw-cell-hidden" ); 641 642 if( !isHidden && !checkFound ) { 643 checkFound = true; 644 next[ 0 ] = i; 645 } else if( isHidden && checkFound ) { 646 next[ 1 ] = i; 647 648 return false; 649 } 650 }); 651 652 return next; 653 } 654 655 function getPrev(){ 656 var next = getNext(); 657 return [ next[ 1 ] - 1 , next[ 0 ] - 1 ]; 658 } 659 660 function nextpair( fwd ){ 661 return fwd ? getNext() : getPrev(); 662 } 663 664 function canAdvance( pair ){ 665 return pair[ 1 ] > -1 && pair[ 1 ] < $headerCellsNoPersist.length; 666 } 667 668 function matchesMedia() { 669 var matchMedia = $table.attr( "data-tablesaw-swipe-media" );
670 return !matchMedia || ( "matchMedia" in win ) && win.matchMedia( matchMedia ).matches; 671 } 672 673 function fakeBreakpoints() { 674 if( !matchesMedia() ) { 675 return; 676 } 677 678 var extraPaddingPixels = 20, 679 containerWidth = $table.parent().width(), 680 persist = [], 681 sum = 0, 682 sums = [], 683 visibleNonPersistantCount = $headerCells.length; 684 685 $headerCells.each(function( index ) { 686 var $t = $( this ), 687 isPersist = $t.is( '[data-tablesaw-priority="persist"]' ); 688 689 persist.push( isPersist ); 690 691 sum += headerWidths[ index ] + ( isPersist ? 0 : extraPaddingPixels ); 692 sums.push( sum ); 693 694 // is persistent or is hidden 695 if( isPersist || sum > containerWidth ) { 696 visibleNonPersistantCount--; 697 } 698 }); 699 700 var needsNonPersistentColumn = visibleNonPersistantCount === 0; 701 702 $headerCells.each(function( index ) { 703 if( persist[ index ] ) { 704 705 // for visual box-shadow 706 persistColumn( this ); 707 return; 708 } 709 710 if( sums[ index ] <= containerWidth || needsNonPersistentColumn ) { 711 needsNonPersistentColumn = false; 712 showColumn( this ); 713 } else { 714 hideColumn( this ); 715 } 716 }); 717 718 if( supportsNthChild ) { 719 unmaintainWidths(); 720 } 721 $table.trigger( 'tablesawcolumns' ); 722 } 723 724 function advance( fwd ){ 725 var pair = nextpair( fwd ); 726 if( canAdvance( pair ) ){ 727 if( isNaN( pair[ 0 ] ) ){ 728 if( fwd ){ 729 pair[0] = 0; 730 } 731 else { 732 pair[0] = $headerCellsNoPersist.length - 1; 733 } 734 } 735 736 if( supportsNthChild ) { 737 maintainWidths(); 738 } 739 740 hideColumn( $headerCellsNoPersist.get( pair[ 0 ] ) ); 741 showColumn( $headerCellsNoPersist.get( pair[ 1 ] ) ); 742 743 $table.trigger( 'tablesawcolumns' ); 744 } 745 } 746 747 $prevBtn.add( $nextBtn ).click(function( e ){ 748 advance( !!$( e.target ).closest( $nextBtn ).length ); 749 e.preventDefault(); 750 }); 751 752 function getCoord( event, key ) { 753 return ( event.touches || event.originalEvent.touches )[ 0 ][ key ]; 754 } 755 756 $table 757 .bind( "touchstart.swipetoggle", function( e ){ 758 var originX = getCoord( e, 'pageX' ), 759 originY = getCoord( e, 'pageY' ), 760 x, 761 y; 762 763 $( win ).off( "resize", fakeBreakpoints ); 764 765 $( this ) 766 .bind( "touchmove", function( e ){ 767 x = getCoord( e, 'pageX' ); 768 y = getCoord( e, 'pageY' ); 769 var cfg = Tablesaw.config.swipe; 770 if( Math.abs( x - originX ) > cfg.horizontalThreshold && Math.abs( y - originY ) < cfg.verticalThreshold ) { 771 e.preventDefault(); 772 } 773 }) 774 .bind( "touchend.swipetoggle", function(){ 775 var cfg = Tablesaw.config.swipe; 776 if( Math.abs( y - originY ) < cfg.verticalThreshold ) { 777 if( x - originX < -1 * cfg.horizontalThreshold ){ 778 advance( true ); 779 } 780 if( x - originX > cfg.horizontalThreshold ){ 781 advance( false ); 782 } 783 } 784 785 window.setTimeout(function() { 786 $( win ).on( "resize", fakeBreakpoints ); 787 }, 300); 788 $( this ).unbind( "touchmove touchend" ); 789 }); 790 791 }) 792 .bind( "tablesawcolumns.swipetoggle", function(){ 793 $prevBtn[ canAdvance( getPrev() ) ? "removeClass" : "addClass" ]( hideBtn ); 794 $nextBtn[ canAdvance( getNext() ) ? "removeClass" : "addClass" ]( hideBtn ); 795 }) 796 .bind( "tablesawnext.swipetoggle", function(){ 797 advance( true ); 798 } ) 799 .bind( "tablesawprev.swipetoggle", function(){ 800 advance( false ); 801 } ) 802 .bind( "tablesawdestroy.swipetoggle", function(){ 803 var $t = $( this ); 804 805 $t.removeClass( 'tablesaw-swipe' ); 806 $t.prev().filter( '.tablesaw-bar' ).find( '.tablesaw-advance' ).remove(); 807 $( win ).off( "resize", fakeBreakpoints ); 808 809 $t.unbind( ".swipetoggle" ); 810 }); 811 812 fakeBreakpoints(); 813 $( win ).on( "resize", fakeBreakpoints ); 814 } 815 816 817 818 // on tablecreate, init 819 $( document ).on( "tablesawcreate", function( e, Tablesaw ){ 820 821 if( Tablesaw.mode === 'swipe' ){ 822 createSwipeTable( Tablesaw.$table ); 823 } 824 825 } ); 826 827}( this, jQuery )); 828 829;(function( $ ) { 830 function getSortValue( cell ) { 831 return $.map( cell.childNodes, function( el ) { 832 var $el = $( el ); 833 if( $el.is( 'input, select' ) ) { 834 return $el.val(); 835 } else if( $el.hasClass( 'tablesaw-cell-label' ) ) { 836 return; 837 } 838 return $.trim( $el.text() ); 839 }).join( '' ); 840 } 841 842 var pluginName = "tablesaw-sortable", 843 initSelector = "table[data-" + pluginName + "]", 844 sortableSwitchSelector = "[data-" + pluginName + "-switch]", 845 attrs = { 846 defaultCol: "data-tablesaw-sortable-default-col" 847 }, 848 classes = { 849 head: pluginName + "-head", 850 ascend: pluginName + "-ascending", 851 descend: pluginName + "-descending", 852 switcher: pluginName + "-switch", 853 tableToolbar: 'tablesaw-toolbar', 854 sortButton: pluginName + "-btn" 855 }, 856 methods = { 857 _create: function( o ){ 858 return $( this ).each(function() { 859 var init = $( this ).data( "init" + pluginName ); 860 if( init ) { 861 return false;
862 } 863 $( this ) 864 .data( "init"+ pluginName, true ) 865 .trigger( "beforecreate." + pluginName ) 866 [ pluginName ]( "_init" , o ) 867 .trigger( "create." + pluginName ); 868 }); 869 }, 870 _init: function(){ 871 var el = $( this ), 872 heads, 873 $switcher; 874 875 var addClassToTable = function(){ 876 el.addClass( pluginName ); 877 }, 878 addClassToHeads = function( h ){ 879 $.each( h , function( i , v ){ 880 $( v ).addClass( classes.head ); 881 }); 882 }, 883 makeHeadsActionable = function( h , fn ){ 884 $.each( h , function( i , v ){ 885 var b = $( "<button class='" + classes.sortButton + "'/>" ); 886 b.bind( "click" , { col: v } , fn ); 887 $( v ).wrapInner( b ); 888 }); 889 }, 890 clearOthers = function( sibs ){ 891 $.each( sibs , function( i , v ){ 892 var col = $( v ); 893 col.removeAttr( attrs.defaultCol ); 894 col.removeClass( classes.ascend ); 895 col.removeClass( classes.descend ); 896 }); 897 }, 898 headsOnAction = function( e ){ 899 if( $( e.target ).is( 'a[href]' ) ) { 900 return; 901 } 902 903 e.stopPropagation(); 904 var head = $( this ).parent(), 905 v = e.data.col, 906 newSortValue = heads.index( head ); 907 908 clearOthers( head.siblings() ); 909 if( head.hasClass( classes.descend ) ){ 910 el[ pluginName ]( "sortBy" , v , true); 911 newSortValue += '_asc'; 912 } else { 913 el[ pluginName ]( "sortBy" , v ); 914 newSortValue += '_desc'; 915 } 916 if( $switcher ) { 917 $switcher.find( 'select' ).val( newSortValue ).trigger( 'refresh' ); 918 } 919 920 e.preventDefault(); 921 }, 922 handleDefault = function( heads ){ 923 $.each( heads , function( idx , el ){ 924 var $el = $( el ); 925 if( $el.is( "[" + attrs.defaultCol + "]" ) ){ 926 if( !$el.hasClass( classes.descend ) ) { 927 $el.addClass( classes.ascend ); 928 } 929 } 930 }); 931 }, 932 addSwitcher = function( heads ){ 933 $switcher = $( '<div>' ).addClass( classes.switcher ).addClass( classes.tableToolbar ).html(function() { 934 var html = [ '<label>' + Tablesaw.i18n.sort + ':' ]; 935 936 html.push( '<span class="btn btn-small"> <select>' ); 937 heads.each(function( j ) { 938 var $t = $( this ), 939 isDefaultCol = $t.is( "[" + attrs.defaultCol + "]" ), 940 isDescending = $t.hasClass( classes.descend ), 941 isNumeric = false; 942 943 // Check only the first three rows to see if the column is numbers. 944 $( this.cells ).slice( 0, 3 ).each(function() { 945 if( !isNaN( parseInt( getSortValue( this ), 10 ) ) ) { 946 isNumeric = true; 947 return false; 948 } 949 }); 950 951 html.push( '<option' + ( isDefaultCol && !isDescending ? ' selected' : '' ) + ' value="' + j + '_asc">' + $t.text() + ' ' + ( isNumeric ? '↑' : '(A-Z)' ) + '</option>' ); 952 html.push( '<option' + ( isDefaultCol && isDescending ? ' selected' : '' ) + ' value="' + j + '_desc">' + $t.text() + ' ' + ( isNumeric ? '↓' : '(Z-A)' ) + '</option>' ); 953 }); 954 html.push( '</select></span></label>' ); 955 956 return html.join(''); 957 }); 958 959 var $toolbar = el.prev().filter( '.tablesaw-bar' ), 960 $firstChild = $toolbar.children().eq( 0 ); 961 962 if( $firstChild.length ) { 963 $switcher.insertBefore( $firstChild ); 964 } else { 965 $switcher.appendTo( $toolbar ); 966 } 967 $switcher.find( '.btn' ).tablesawbtn(); 968 $switcher.find( 'select' ).on( 'change', function() { 969 var val = $( this ).val().split( '_' ), 970 head = heads.eq( val[ 0 ] ); 971 972 clearOthers( head.siblings() ); 973 el[ pluginName ]( 'sortBy', head.get( 0 ), val[ 1 ] === 'asc' ); 974 }); 975 }; 976 977 addClassToTable(); 978 heads = el.find( "thead th[data-" + pluginName + "-col]" ); 979 addClassToHeads( heads ); 980 makeHeadsActionable( heads , headsOnAction ); 981 handleDefault( heads ); 982 983 if( el.is( sortableSwitchSelector ) ) { 984 addSwitcher( heads, el.find('tbody tr:nth-child(-n+3)') ); 985 } 986 }, 987 getColumnNumber: function( col ){ 988 return $( col ).prevAll().length; 989 }, 990 getTableRows: function(){ 991 return $( this ).find( "tbody tr" ); 992 }, 993 sortRows: function( rows , colNum , ascending, col ){ 994 var cells, fn, sorted; 995 var getCells = function( rows ){ 996 var cells = []; 997 $.each( rows , function( i , r ){ 998 cells.push({ 999 cell: getSortValue( $( r ).children().get( colNum ) ), 1000 rowNum: i 1001 }); 1002 }); 1003 return cells; 1004 }, 1005 getSortFxn = function( ascending, forceNumeric ){ 1006 var fn, 1007 regex = /[^\-\+\d\.]/g; 1008 if( ascending ){ 1009 fn = function( a , b ){ 1010 if( forceNumeric || !isNaN( parseFloat( a.cell ) ) ) { 1011 return parseFloat( a.cell.replace( regex, '' ) ) - parseFloat( b.cell.replace( regex, '' ) ); 1012 } else { 1013 return a.cell.toLowerCase() > b.cell.toLowerCase() ? 1 : -1; 1014 } 1015 }; 1016 } else { 1017 fn = function( a , b ){ 1018 if( forceNumeric || !isNaN( parseFloat( a.cell ) ) ) { 1019 return parseFloat( b.cell.replace( regex, '' ) ) - parseFloat( a.cell.replace( regex, '' ) ); 1020 } else { 1021 return a.cell.toLowerCase() < b.cell.toLowerCase() ? 1 : -1; 1022 } 1023 }; 1024 } 1025 return fn; 1026 }, 1027 applyToRows = function( sorted , rows ){ 1028 var newRows = [], i, l, cur; 1029 for( i = 0, l = sorted.length ; i < l ; i++ ){ 1030 cur = sorted[ i ].rowNum; 1031 newRows.push( rows[cur] ); 1032 } 1033 return newRows; 1034 }; 1035 1036 cells = getCells( rows ); 1037 var customFn = $( col ).data( 'tablesaw-sort' ); 1038 fn = ( customFn && typeof customFn === "function" ? customFn( ascending ) : false ) || 1039 getSortFxn( ascending, $( col ).is( '[data-sortable-numeric]' ) ); 1040 sorted = cells.sort( fn ); 1041 rows = applyToRows( sorted , rows ); 1042 return rows; 1043 }, 1044 replaceTableRows: function( rows ){ 1045 var el = $( this ), 1046 body = el.find( "tbody" ); 1047 body.html( rows ); 1048 }, 1049 makeColDefault: function( col , a ){ 1050 var c = $( col ); 1051 c.attr( attrs.defaultCol , "true" ); 1052 if( a ){ 1053 c.removeClass( classes.descend ); 1054 c.addClass( classes.ascend ); 1055 } else { 1056 c.removeClass( classes.ascend ); 1057 c.addClass( classes.descend ); 1058 } 1059 }, 1060 sortBy: function( col , ascending ){
1061 var el = $( this ), colNum, rows; 1062 1063 colNum = el[ pluginName ]( "getColumnNumber" , col ); 1064 rows = el[ pluginName ]( "getTableRows" ); 1065 rows = el[ pluginName ]( "sortRows" , rows , colNum , ascending, col ); 1066 el[ pluginName ]( "replaceTableRows" , rows ); 1067 el[ pluginName ]( "makeColDefault" , col , ascending ); 1068 } 1069 }; 1070 1071 // Collection method. 1072 $.fn[ pluginName ] = function( arrg ) { 1073 var args = Array.prototype.slice.call( arguments , 1), 1074 returnVal; 1075 1076 // if it's a method 1077 if( arrg && typeof( arrg ) === "string" ){ 1078 returnVal = $.fn[ pluginName ].prototype[ arrg ].apply( this[0], args ); 1079 return (typeof returnVal !== "undefined")? returnVal:$(this); 1080 } 1081 // check init 1082 if( !$( this ).data( pluginName + "data" ) ){ 1083 $( this ).data( pluginName + "active", true ); 1084 $.fn[ pluginName ].prototype._create.call( this , arrg ); 1085 } 1086 return $(this); 1087 }; 1088 // add methods 1089 $.extend( $.fn[ pluginName ].prototype, methods ); 1090 1091 $( document ).on( "tablesawcreate", function( e, Tablesaw ) { 1092 if( Tablesaw.$table.is( initSelector ) ) { 1093 Tablesaw.$table[ pluginName ](); 1094 } 1095 }); 1096 1097}( jQuery )); 1098 1099;(function( win, $, undefined ){ 1100 1101 var MM = { 1102 attr: { 1103 init: 'data-tablesaw-minimap' 1104 } 1105 }; 1106 1107 function createMiniMap( $table ){ 1108 1109 var $btns = $( '<div class="tablesaw-advance minimap">' ), 1110 $dotNav = $( '<ul class="tablesaw-advance-dots">' ).appendTo( $btns ), 1111 hideDot = 'tablesaw-advance-dots-hide', 1112 $headerCells = $table.find( 'thead th' ); 1113 1114 // populate dots 1115 $headerCells.each(function(){ 1116 $dotNav.append( '<li><i></i></li>' ); 1117 }); 1118 1119 $btns.appendTo( $table.prev().filter( '.tablesaw-bar' ) ); 1120 1121 function showMinimap( $table ) { 1122 var mq = $table.attr( MM.attr.init ); 1123 return !mq || win.matchMedia && win.matchMedia( mq ).matches; 1124 } 1125 1126 function showHideNav(){ 1127 if( !showMinimap( $table ) ) { 1128 $btns.hide(); 1129 return; 1130 } 1131 $btns.show(); 1132 1133 // show/hide dots 1134 var dots = $dotNav.find( "li" ).removeClass( hideDot ); 1135 $table.find( "thead th" ).each(function(i){ 1136 if( $( this ).css( "display" ) === "none" ){ 1137 dots.eq( i ).addClass( hideDot ); 1138 } 1139 }); 1140 } 1141 1142 // run on init and resize 1143 showHideNav(); 1144 $( win ).on( "resize", showHideNav ); 1145 1146 1147 $table 1148 .bind( "tablesawcolumns.minimap", function(){ 1149 showHideNav(); 1150 }) 1151 .bind( "tablesawdestroy.minimap", function(){ 1152 var $t = $( this ); 1153 1154 $t.prev().filter( '.tablesaw-bar' ).find( '.tablesaw-advance' ).remove(); 1155 $( win ).off( "resize", showHideNav ); 1156 1157 $t.unbind( ".minimap" ); 1158 }); 1159 } 1160 1161 1162 1163 // on tablecreate, init 1164 $( document ).on( "tablesawcreate", function( e, Tablesaw ){ 1165 1166 if( ( Tablesaw.mode === 'swipe' || Tablesaw.mode === 'columntoggle' ) && Tablesaw.$table.is( '[ ' + MM.attr.init + ']' ) ){ 1167 createMiniMap( Tablesaw.$table ); 1168 } 1169 1170 } ); 1171 1172}( this, jQuery )); 1173 1174;(function( win, $ ) { 1175 1176 var S = { 1177 selectors: { 1178 init: 'table[data-tablesaw-mode-switch]' 1179 }, 1180 attributes: { 1181 excludeMode: 'data-tablesaw-mode-exclude' 1182 }, 1183 classes: { 1184 main: 'tablesaw-modeswitch', 1185 toolbar: 'tablesaw-toolbar' 1186 }, 1187 modes: [ 'stack', 'swipe', 'columntoggle' ], 1188 init: function( table ) { 1189 var $table = $( table ), 1190 ignoreMode = $table.attr( S.attributes.excludeMode ), 1191 $toolbar = $table.prev().filter( '.tablesaw-bar' ), 1192 modeVal = '', 1193 $switcher = $( '<div>' ).addClass( S.classes.main + ' ' + S.classes.toolbar ).html(function() { 1194 var html = [ '<label>' + Tablesaw.i18n.columns + ':' ], 1195 dataMode = $table.attr( 'data-tablesaw-mode' ), 1196 isSelected; 1197 1198 html.push( '<span class="btn btn-small"> <select>' ); 1199 for( var j=0, k = S.modes.length; j<k; j++ ) { 1200 if( ignoreMode && ignoreMode.toLowerCase() === S.modes[ j ] ) { 1201 continue; 1202 } 1203 1204 isSelected = dataMode === S.modes[ j ]; 1205 1206 if( isSelected ) { 1207 modeVal = S.modes[ j ]; 1208 } 1209 1210 html.push( '<option' + 1211 ( isSelected ? ' selected' : '' ) + 1212 ' value="' + S.modes[ j ] + '">' + Tablesaw.i18n.modes[ j ] + '</option>' ); 1213 } 1214 html.push( '</select></span></label>' ); 1215 1216 return html.join(''); 1217 }); 1218 1219 var $otherToolbarItems = $toolbar.find( '.tablesaw-advance' ).eq( 0 ); 1220 if( $otherToolbarItems.length ) { 1221 $switcher.insertBefore( $otherToolbarItems ); 1222 } else { 1223 $switcher.appendTo( $toolbar ); 1224 } 1225 1226 $switcher.find( '.btn' ).tablesawbtn(); 1227 $switcher.find( 'select' ).bind( 'change', S.onModeChange ); 1228 }, 1229 onModeChange: function() { 1230 var $t = $( this ), 1231 $switcher = $t.closest( '.' + S.classes.main ), 1232 $table = $t.closest( '.tablesaw-bar' ).nextUntil( $table ).eq( 0 ), 1233 val = $t.val(); 1234 1235 $switcher.remove(); 1236 $table.data( 'table' ).destroy(); 1237 1238 $table.attr( 'data-tablesaw-mode', val ); 1239 $table.table(); 1240 } 1241 }; 1242 1243 $( win.document ).on( "tablesawcreate", function( e, Tablesaw ) { 1244 if( Tablesaw.$table.is( S.selectors.init ) ) { 1245 S.init( Tablesaw.table ); 1246 } 1247 }); 1248 1249})( this, jQuery );
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.