MediaWiki:StickyTableHeaders.js
From Ephinea PSO Wiki
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Press Ctrl-F5.
/****************************************************** * Usage: * * - Add the `sticky` class to the table element. * * - Add the `sticky-main` class to a header row * * to define it as the main header. * * - Optionally, add the `sticky-sub` class to any * * header rows to define them as sub-headers. * * * * Example: * * {| class="wikitable sticky" * * |- class="sticky-main" * * ! Name * * ! Color * * ! Score * * * * |- class="sticky-sub" * * ! colspan=3 | Fruits * * |- * * | Banana || Yellow || 10 * * |- * * | Pear || Green || 5 * * |- * * | Apple || Red || 7 * * * * |- class="sticky-sub" * * ! colspan=3 | Vegetables * * |- * * | Carrot || Orange || 8 * * |- * * | Potato || Brown || 6 * * |- * * | Eggplant || Purple || 10 * * * * |- class="sticky-sub" * * ! colspan=3 | Candy * * |- * * | Skittles || Rainbow || 4 * * |- * * | Chocolate || Brown || 7 * * |- * * | Liquorice || Black || 8 * * |} * * * *****************************************************/ (function(){ var $window = $(window); var borderWidth = 2; /**/ function StickyTable(tableElement){ this.tableElement = tableElement; this.mainHeader = $(".sticky-main", this.tableElement).first(); if(this.mainHeader.length === 0){ throw new TypeError("Invalid sticky table: Must contain a row with class `sticky-main`."); } this.mainHeaderCells = this.mainHeader.children().map(function(){ return $(this); }); this.subHeaders = $(".sticky-sub", this.tableElement).map(function(){ return $(this); }); this.subHeaderCells = []; for(var i = 0; i < this.subHeaders.length; i++){ this.subHeaderCells[i] = this.subHeaders[i].children().map(function(){ return $(this); }); } } StickyTable.prototype.updateMain = function updateMain(scrollTop){ var tableHeight = this.tableElement.height(); var delta = scrollTop - this.mainHeader.offset().top; var y = (delta < 0 || delta > tableHeight) ? 0 : delta - borderWidth; var transformStyle = y === 0 ? "unset" : "translateY(" + y + "px)"; for(var i = 0; i < this.mainHeaderCells.length; i++){ this.mainHeaderCells[i].css("transform", y === 0 ? "unset" : "translateY(" + y + "px)"); } } StickyTable.prototype.updateSubs = function updateSub(scrollTop){ var mainHeight = this.mainHeader.height() - borderWidth; var tableTop = this.tableElement.offset().top; for(var i = 0; i < this.subHeaders.length; i++){ var subHeader = this.subHeaders[i]; var subTop = subHeader.offset().top; var tableBottom = this.tableElement.height() - subTop + tableTop; var delta = scrollTop - subTop + mainHeight; var y = (delta < 0 || delta > tableBottom) ? 0 : delta - borderWidth; var transformStyle = y === 0 ? "unset" : "translateY(" + y + "px)"; for(var j = 0; j < this.subHeaderCells[i].length; j++){ this.subHeaderCells[i][j].css("transform", transformStyle); } } } StickyTable.prototype.update = function update(scrollTop){ this.updateMain(scrollTop); this.updateSubs(scrollTop); } /**/ var tables = $("table.sticky").map(function(){ return new StickyTable($(this)); }); var updating = false; function updateTables(){ var scrollTop = $window.scrollTop() for(var i = 0; i < tables.length; i++){ var table = tables[i]; if(table.tableElement.is(":visible")) table.update(scrollTop); } updating = false; } function updateTablesThrottle(){ if(!updating){ window.requestAnimationFrame(updateTables); updating = true; } } if(tables.length > 0) $window.on("scroll", updateTablesThrottle); })(); table.sticky tr.floating > th { border-color: transparent; outline: 1px solid #aaa; }