Line 3: |
Line 3: |
| * | | * |
| * Description: | | * Description: |
− | * Adds row highlighting to tables | + | * Adds highlighting to tables |
| * | | * |
− | * Version 1.0: Row highlighting - Quarenon | + | * History: |
− | * Version 1.1: Update from pengLocations.js v1.0 - Quarenon | + | * - 1.0: Row highlighting - Quarenon |
− | * Version 2.0: pengLocations v2.1, Granular cookie - Saftzie | + | * - 1.1: Update from pengLocations.js v1.0 - Quarenon |
− | * Version 2.1: Made compatible with jquery.tablesorter - Cqm | + | * - 2.0: pengLocations v2.1, Granular cookie - Saftzie |
| + | * - 2.1: Made compatible with jquery.tablesorter - Cqm |
| + | * - 2.2: Switch to localStorage - Cqm |
| + | * - 3.0: Allow cell highlighting - mejrs |
| + | * |
| + | * @todo Allow the stored data to be coupled to the table in question. Currently the data is stored |
| + | * on the page itself, so if any tables are shuffled, the highlighting doesn't follow. For |
| + | * the same reason tables hosted on other pages are not synchronized. |
| + | */ |
| + | |
| + | /** |
| + | * DATA STORAGE STRUCTURE |
| + | * ---------------------- |
| + | * |
| + | * In its raw, uncompressed format, the stored data is as follows: |
| + | * { |
| + | * hashedPageName1: [ |
| + | * [0, 1, 0, 1, 0, 1], |
| + | * [1, 0, 1, 0, 1, 0], |
| + | * [0, 0, 0, 0, 0, 0] |
| + | * ], |
| + | * hashedPageName2: [ |
| + | * [0, 1, 0, 1, 0, 1], |
| + | * [1, 0, 1, 0, 1, 0], |
| + | * [0, 0, 0, 0, 0, 0] |
| + | * ] |
| + | * } |
| + | * |
| + | * Where `hashedPageNameX` is the value of wgPageName passed through our `hashString` function, |
| + | * the arrays of numbers representing tables on a page (from top to bottom) and the numbers |
| + | * representing whether a row is highlighted or not, depending on if it is 1 or 0 respectively. |
| + | * |
| + | * During compression, these numbers are collected into groups of 6 and converted to base64. |
| + | * For example: |
| + | * |
| + | * 1. [0, 1, 0, 1, 0, 1] |
| + | * 2. 0x010101 (1 + 4 + 16 = 21) |
| + | * 3. BASE_64_URL[21] (U) |
| + | * |
| + | * Once each table's rows have been compressed into strings, they are concatenated using `.` as a |
| + | * delimiter. The hashed page name (which is guaranteed to be 8 characters long) is then prepended |
| + | * to this string to look something like the following: |
| + | * |
| + | * XXXXXXXXab.dc.ef |
| + | * |
| + | * |
| + | * The first character of a hashed page name is then used to form the object that is actually |
| + | * stored. As the hashing function uses hexadecimal, this gives us 16 possible characters (0-9A-Z). |
| + | * |
| + | * { |
| + | * A: ... |
| + | * B: ... |
| + | * C: ... |
| + | * // etc. |
| + | * } |
| + | * |
| + | * The final step of compression is to merge each page's data together under it's respective top |
| + | * level key. this is done by concatenation again, separated by a `!`. |
| + | * |
| + | * The resulting object is then converted to a string and persisted in local storage. When |
| + | * uncompressing data, simply perform the following steps in reverse. |
| + | * |
| + | * For the implementation of this algorithm, see: |
| + | * - `compress` |
| + | * - `parse` |
| + | * - `hashString` |
| + | * |
| + | * Note that while rows could theoretically be compressed further by using all ASCII characters, |
| + | * eventually we'd start using characters outside printable ASCII which makes debugging painful. |
| */ | | */ |
| | | |
− | ;(function ($, mw) {
| + | /*jshint bitwise:false, camelcase:true, curly:true, eqeqeq:true, es3:false, |
| + | forin:true, immed:true, indent:4, latedef:true, newcap:true, |
| + | noarg:true, noempty:true, nonew:true, plusplus:true, quotmark:single, |
| + | undef:true, unused:true, strict:true, trailing:true, |
| + | browser:true, devel:false, jquery:true, |
| + | onevar:true |
| + | */ |
| | | |
| + | (function($, mw, OO, rs) { |
| 'use strict'; | | 'use strict'; |
| | | |
− | function highlightTable() { | + | // constants |
| + | var STORAGE_KEY = 'rs:lightTable', |
| + | TABLE_CLASS = 'lighttable', |
| + | LIGHT_ON_CLASS = 'highlight-on', |
| + | MOUSE_OVER_CLASS = 'highlight-over', |
| + | BASE_64_URL = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', |
| + | PAGE_SEPARATOR = '!', |
| + | TABLE_SEPARATOR = '.', |
| + | CASTAGNOLI_POLYNOMIAL = 0x04c11db7, |
| + | UINT32_MAX = 0xffffffff, |
| + | |
| + | self = { |
| + | /* |
| + | * Stores the current uncompressed data for the current page. |
| + | */ |
| + | data: null, |
| + | |
| + | /* |
| + | * Perform initial checks on the page and browser. |
| + | */ |
| + | init: function() { |
| + | var $tables = $('table.' + TABLE_CLASS), |
| + | hashedPageName = self.hashString(mw.config.get('wgPageName')); |
| + | |
| + | // check we have some tables to interact with |
| + | if (!$tables.length) { |
| + | return; |
| + | } |
| + | // check the browser supports local storage |
| + | if (!rs.hasLocalStorage()) { |
| + | return; |
| + | } |
| + | |
| + | self.data = self.load(hashedPageName, $tables.length); |
| + | self.initTables(hashedPageName, $tables); |
| + | }, |
| | | |
− | // requires CSS classes named in lightOnClass and mouseOverClass
| + | /* |
− | var wgPageName = mw.config.get('wgPageName'),
| + | * Initialise table highlighting. |
− | cookiePrefix = 'lightTable',
| + | * |
− | tableClass = 'lighttable',
| + | * @param hashedPageName The current page name as a hash. |
− | lightOnClass = 'highlight-on',
| + | * @param $tables A list of highlightable tables on the current page. |
− | mouseOverClass = 'highlight-over',
| + | */ |
− | base64url = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_',
| + | initTables: function(hashedPageName, $tables) { |
− | pageSeparator = '!',
| + | $tables.each(function(tIndex) { |
− | tableSeparator = '.',
| + | var $this = $(this), |
− | hashPageName,
| + | // data cells |
− | rows = [],
| + | $cells = $this.find('td'), |
− | columns,
| + | $rows = $this.find('tr:has(td)'), |
− | tables,
| + | // don't rely on headers to find number of columns |
− | cookie;
| + | // count them dynamically |
| + | columns = 1, |
| + | tableData = self.data[tIndex], |
| + | mode = 'cells'; |
| | | |
− | // hash a string into a 32-bit hex string, msb first
| + | // Switching between either highlighting rows or cells |
− | function crc32c(s) {
| + | if (!$this.hasClass('individual')) { |
− | var polynomial = 0x04C11DB7, // Castagnoli polynomial
| + | mode = 'rows'; |
− | retVal,
| + | $cells = $rows; |
− | table = [],
| + | } |
− | i,
| |
− | j,
| |
− | k;
| |
| | | |
− | // guarantee 8-bit chars
| + | // initialise rows if necessary |
− | s = window.unescape(window.encodeURI(s));
| + | while ($cells.length > tableData.length) { |
| + | tableData.push(0); |
| + | } |
| | | |
− | // calculate the crc for all 8-bit data
| + | // counting the column count |
− | // bit-wise operations discard anything left of bit 31
| + | // necessary to determine colspan of reset button |
− | for (i = 0; i < 256; i += 1) {
| + | $rows.each(function() { |
− | k = (i << 24);
| + | var $this = $(this); |
− | for (j = 0; j < 8; j += 1) {
| + | columns = Math.max(columns, $this.children('th,td').length); |
− | k = (k << 1) ^ ((k >>> 31) * polynomial); | + | }); |
| + | |
| + | $cells.each(function(cIndex) { |
| + | var $this = $(this), |
| + | cellData = tableData[cIndex]; |
| + | |
| + | // forbid highlighting any cells/rows that have class nohighlight |
| + | if (!$this.hasClass('nohighlight')) { |
| + | // initialize highlighting based on the cookie |
| + | self.setHighlight($this, cellData); |
| + | |
| + | // set mouse events |
| + | $this |
| + | .mouseover(function() { |
| + | self.setHighlight($this, 2); |
| + | }) |
| + | .mouseout(function() { |
| + | self.setHighlight($this, tableData[cIndex]); |
| + | }) |
| + | .click(function(e) { |
| + | // don't toggle highlight when clicking links |
| + | if ((e.target.tagName !== 'A') && (e.target.tagName !== 'IMG')) { |
| + | // 1 -> 0 |
| + | // 0 -> 1 |
| + | tableData[cIndex] = 1 - tableData[cIndex]; |
| + | |
| + | self.setHighlight($this, tableData[cIndex]); |
| + | self.save(hashedPageName); |
| + | } |
| + | }); |
| + | } |
| + | }); |
| + | |
| + | // add a button for reset |
| + | var button = new OO.ui.ButtonWidget({ |
| + | label: (mode === 'rows') ? |
| + | 'Clear highlighted rows' : |
| + | 'Clear highlighted cells', |
| + | icon: 'clear', |
| + | title: 'Removes all highlights from the table', |
| + | classes: ['ht-reset'] // this class is targeted by other gadgets, be careful removing it |
| + | }); |
| + | |
| + | |
| + | button.$element.click(function() { |
| + | $cells.each(function(cIndex) { |
| + | tableData[cIndex] = 0; |
| + | self.setHighlight($(this), 0); |
| + | }); |
| + | |
| + | self.save(hashedPageName, $tables.length); |
| + | }); |
| + | |
| + | $this.append( |
| + | $('<tfoot>') |
| + | .append( |
| + | $('<tr>') |
| + | .append( |
| + | $('<th>') |
| + | .attr('colspan', columns) |
| + | .append(button.$element) |
| + | ) |
| + | ) |
| + | ); |
| + | }); |
| + | }, |
| + | |
| + | /* |
| + | * Change the cell background color based on mouse events. |
| + | * |
| + | * @param $cell The cell element. |
| + | * @param val The value to control what class to add (if any). |
| + | * 0 -> light off (no class) |
| + | * 1 -> light on |
| + | * 2 -> mouse over |
| + | */ |
| + | setHighlight: function($cell, val) { |
| + | $cell.removeClass(MOUSE_OVER_CLASS); |
| + | $cell.removeClass(LIGHT_ON_CLASS); |
| + | |
| + | switch (val) { |
| + | // light on |
| + | case 1: |
| + | $cell.addClass(LIGHT_ON_CLASS); |
| + | break; |
| + | |
| + | // mouse-over |
| + | case 2: |
| + | $cell.addClass(MOUSE_OVER_CLASS); |
| + | break; |
| + | } |
| + | }, |
| + | |
| + | /* |
| + | * Merge the updated data for the current page into the data for other pages into local storage. |
| + | * |
| + | * @param hashedPageName A hash of the current page name. |
| + | */ |
| + | save: function(hashedPageName) { |
| + | // load the existing data so we know where to save it |
| + | var curData = localStorage.getItem(STORAGE_KEY), |
| + | compressedData; |
| + | |
| + | if (curData === null) { |
| + | curData = {}; |
| + | } else { |
| + | curData = JSON.parse(curData); |
| + | curData = self.parse(curData); |
| } | | } |
− | table[i] = k;
| |
− | }
| |
| | | |
− | // the actual calculation
| + | // merge in our updated data and compress it |
− | retVal = 0;
| + | curData[hashedPageName] = self.data; |
− | for (i = 0; i < s.length; i += 1) {
| + | compressedData = self.compress(curData); |
− | retVal = (retVal << 8) ^ table[(retVal >>> 24) ^ s.charCodeAt(i)]; | + | |
− | }
| + | // convert to a string and save to localStorage |
| + | compressedData = JSON.stringify(compressedData); |
| + | localStorage.setItem(STORAGE_KEY, compressedData); |
| + | }, |
| + | |
| + | /* |
| + | * Compress the entire data set using tha algoritm documented at the top of the page. |
| + | * |
| + | * @param data The data to compress. |
| + | * |
| + | * @return the compressed data. |
| + | */ |
| + | compress: function(data) { |
| + | var ret = {}; |
| + | |
| + | Object.keys(data).forEach(function(hashedPageName) { |
| + | var pageData = data[hashedPageName], |
| + | pageKey = hashedPageName.charAt(0); |
| + | |
| + | if (!ret.hasOwnProperty(pageKey)) { |
| + | ret[pageKey] = {}; |
| + | } |
| | | |
− | // make negative numbers unsigned
| + | ret[pageKey][hashedPageName] = []; |
− | if (retVal < 0) {
| |
− | retVal += 4294967296;
| |
− | }
| |
− | // 32-bit hex string, padded on the left
| |
− | retVal = '0000000' + retVal.toString(16).toUpperCase();
| |
− | retVal = retVal.substr(retVal.length - 8);
| |
| | | |
− | return retVal;
| + | pageData.forEach(function(tableData) { |
− | }
| + | var compressedTableData = '', |
| + | i, j, k; |
| | | |
− | // change the row bg color based on mouse events
| + | for (i = 0; i < Math.ceil(tableData.length / 6); i += 1) { |
− | function setHighlight(el, val) {
| + | k = tableData[6 * i]; |
− | $(el).removeClass(mouseOverClass).removeClass(lightOnClass);
| |
− | switch (val) {
| |
− | case 1: // light on
| |
− | $(el).addClass(lightOnClass);
| |
− | break;
| |
− | case 2: // mouse-over
| |
− | $(el).addClass(mouseOverClass);
| |
− | break;
| |
− | default: // same as case 0, light off
| |
− | }
| |
− | }
| |
| | | |
− | // load the cookie and parse it for the page
| + | for (j = 1; j < 6; j += 1) { |
− | // cookie info is saved in 1 of 16 browser cookies, based on page name hash
| + | k = 2 * k + ((6 * i + j < tableData.length) ? tableData[6 * i + j] : 0); |
− | // global cookie[][] supports multiple tables and multiple pages
| + | } |
− | // uses global hashPageName
| |
− | function loadCookie(numTables) {
| |
− | var cookieName = cookiePrefix + '-' + hashPageName.charAt(0),
| |
− | pageCookies,
| |
− | tableCookies,
| |
− | iPage,
| |
− | iTable,
| |
− | i,
| |
− | j,
| |
− | k;
| |
| | | |
− | cookie = [];
| + | compressedTableData += BASE_64_URL.charAt(k); |
− | if ($.cookie(cookieName) !== null) {
| |
− | pageCookies = $.cookie(cookieName).split(pageSeparator);
| |
− | for (iPage = 0; iPage < pageCookies.length; iPage += 1) {
| |
− | if (hashPageName === pageCookies[iPage].substr(0, 8)) {
| |
− | tableCookies = pageCookies[iPage].substr(8).split(tableSeparator);
| |
− | // trim the cookie array of arrays, if needed
| |
− | while (tableCookies.length > numTables) {
| |
− | tableCookies.pop();
| |
| } | | } |
− | // extract the row info per table | + | |
− | // use Base64url to compress 6 rows to 1 character
| + | ret[pageKey][hashedPageName].push(compressedTableData); |
− | for (iTable = 0; iTable < tableCookies.length; iTable += 1) { | + | }); |
− | cookie[iTable] = []; | + | |
− | for (i = 0; i < tableCookies[iTable].length; i += 1) { | + | ret[pageKey][hashedPageName] = ret[pageKey][hashedPageName].join(TABLE_SEPARATOR); |
− | k = base64url.indexOf(tableCookies[iTable].charAt(i)); | + | }); |
− | if (k < 0) { // input validation | + | |
| + | Object.keys(ret).forEach(function(pageKey) { |
| + | var hashKeys = Object.keys(ret[pageKey]), |
| + | hashedData = []; |
| + | |
| + | hashKeys.forEach(function(key) { |
| + | var pageData = ret[pageKey][key]; |
| + | hashedData.push(key + pageData); |
| + | }); |
| + | |
| + | hashedData = hashedData.join(PAGE_SEPARATOR); |
| + | ret[pageKey] = hashedData; |
| + | }); |
| + | |
| + | return ret; |
| + | }, |
| + | |
| + | /* |
| + | * Get the existing data for the current page. |
| + | * |
| + | * @param hashedPageName A hash of the current page name. |
| + | * @param numTables The number of tables on the current page. Used to ensure the loaded |
| + | * data matches the number of tables on the page thus handling cases |
| + | * where tables have been added or removed. This does not check the |
| + | * amount of rows in the given tables. |
| + | * |
| + | * @return The data for the current page. |
| + | */ |
| + | load: function(hashedPageName, numTables) { |
| + | var data = localStorage.getItem(STORAGE_KEY), |
| + | pageData; |
| + | |
| + | if (data === null) { |
| + | pageData = []; |
| + | } else { |
| + | data = JSON.parse(data); |
| + | data = self.parse(data); |
| + | |
| + | if (data.hasOwnProperty(hashedPageName)) { |
| + | pageData = data[hashedPageName]; |
| + | } else { |
| + | pageData = []; |
| + | } |
| + | } |
| + | |
| + | // if more tables were added |
| + | // add extra arrays to store the data in |
| + | // also populates if no existing data was found |
| + | while (numTables > pageData.length) { |
| + | pageData.push([]); |
| + | } |
| + | |
| + | // if tables were removed, remove data from the end of the list |
| + | // as there's no way to tell which was removed |
| + | while (numTables < pageData.length) { |
| + | pageData.pop(); |
| + | } |
| + | |
| + | return pageData; |
| + | }, |
| + | |
| + | /* |
| + | * Parse the compressed data as loaded from local storage using the algorithm desribed |
| + | * at the top of the page. |
| + | * |
| + | * @param data The data to parse. |
| + | * |
| + | * @return the parsed data. |
| + | */ |
| + | parse: function(data) { |
| + | var ret = {}; |
| + | |
| + | Object.keys(data).forEach(function(pageKey) { |
| + | var pageData = data[pageKey].split(PAGE_SEPARATOR); |
| + | |
| + | pageData.forEach(function(tableData) { |
| + | var hashedPageName = tableData.substr(0, 8); |
| + | |
| + | tableData = tableData.substr(8).split(TABLE_SEPARATOR); |
| + | ret[hashedPageName] = []; |
| + | |
| + | tableData.forEach(function(rowData, index) { |
| + | var i, j, k; |
| + | |
| + | ret[hashedPageName].push([]); |
| + | |
| + | for (i = 0; i < rowData.length; i += 1) { |
| + | k = BASE_64_URL.indexOf(rowData.charAt(i)); |
| + | |
| + | // input validation |
| + | if (k < 0) { |
| k = 0; | | k = 0; |
| } | | } |
| + | |
| for (j = 5; j >= 0; j -= 1) { | | for (j = 5; j >= 0; j -= 1) { |
− | cookie[iTable][6 * i + j] = (k & 0x1); | + | ret[hashedPageName][index][6 * i + j] = (k & 0x1); |
| k >>= 1; | | k >>= 1; |
| } | | } |
| } | | } |
− | } | + | }); |
− | } | + | }); |
− | } | + | |
− | } | + | }); |
| + | |
| + | return ret; |
| + | }, |
| + | |
| + | /* |
| + | * Hash a string into a big endian 32 bit hex string. Used to hash page names. |
| + | * |
| + | * @param input The string to hash. |
| + | * |
| + | * @return the result of the hash. |
| + | */ |
| + | hashString: function(input) { |
| + | var ret = 0, |
| + | table = [], |
| + | i, j, k; |
| | | |
− | // initialize the cookie array of arrays, if needed
| + | // guarantee 8-bit chars |
− | while (cookie.length < numTables) {
| + | input = window.unescape(window.encodeURI(input)); |
− | cookie.push([]);
| |
− | }
| |
− | }
| |
| | | |
− | // save/update the cookie for page reloads
| + | // calculate the crc (cyclic redundancy check) for all 8-bit data |
− | // cookie info is saved in 1 of 16 browser cookies, based on page name hash
| + | // bit-wise operations discard anything left of bit 31 |
− | // global cookie[][] supports multiple tables and multiple pages
| + | for (i = 0; i < 256; i += 1) { |
− | // uses global hashPageName
| + | k = (i << 24); |
− | function saveCookie() {
| |
− | var cookieName = cookiePrefix + '-' + hashPageName.charAt(0),
| |
− | pageCookies,
| |
− | tableCookies,
| |
− | iPage,
| |
− | iTable,
| |
− | i,
| |
− | j,
| |
− | k,
| |
− | updated;
| |
| | | |
− | // create the cookie for the tables on the current page
| + | for (j = 0; j < 8; j += 1) { |
− | // use Base64url to compress 6 rows to 1 character
| + | k = (k << 1) ^ ((k >>> 31) * CASTAGNOLI_POLYNOMIAL); |
− | tableCookies = hashPageName;
| |
− | for (iTable = 0; iTable < cookie.length; iTable += 1) {
| |
− | if (iTable > 0) {
| |
− | tableCookies += tableSeparator; | |
− | }
| |
− | for (i = 0; i < Math.ceil(cookie[iTable].length / 6); i += 1) {
| |
− | k = cookie[iTable][6 * i];
| |
− | for (j = 1; j < 6; j += 1) {
| |
− | k = 2 * k + ((6 * i + j < cookie[iTable].length) ? cookie[iTable][6 * i + j] : 0);
| |
| } | | } |
− | tableCookies += base64url.charAt(k); | + | table[i] = k; |
| } | | } |
− | }
| |
| | | |
− | updated = 0;
| + | // the actual calculation |
− | pageCookies = [];
| + | for (i = 0; i < input.length; i += 1) { |
− | if ($.cookie(cookieName) !== null) {
| + | ret = (ret << 8) ^ table[(ret >>> 24) ^ input.charCodeAt(i)]; |
− | // get all the page cookies | |
− | // another page might have updated them since this page
| |
− | pageCookies = $.cookie(cookieName).split(pageSeparator);
| |
− | // update the page cookie if it already exists
| |
− | for (iPage = 0; iPage < pageCookies.length; iPage += 1) { | |
− | if (hashPageName === pageCookies[iPage].substr(0, 8)) { | |
− | updated = 1;
| |
− | pageCookies[iPage] = tableCookies;
| |
− | }
| |
| } | | } |
− | }
| |
− | // add the page cookie if it doesn't exist yet
| |
− | if (updated === 0) {
| |
− | pageCookies.push(tableCookies);
| |
− | }
| |
| | | |
− | // set path to / so it works for /wiki/, /index.php, etc
| + | // make negative numbers unsigned |
− | $.cookie(cookieName, pageCookies.join(pageSeparator), {
| + | if (ret < 0) { |
− | expires: 7,
| + | ret += UINT32_MAX; |
− | path: '/' | + | } |
− | });
| |
− | }
| |
| | | |
− | tables = $('table.' + tableClass);
| + | // 32-bit hex string, padded on the left |
− | // don't bother doing anything unless there's really something to do
| + | ret = '0000000' + ret.toString(16).toUpperCase(); |
− | if (tables.length > 0) {
| + | ret = ret.substr(ret.length - 8); |
− | // hash the page name to an 8-char hex string
| |
− | hashPageName = crc32c(wgPageName);
| |
− | loadCookie(tables.length);
| |
| | | |
− | tables.each(function (iTable) { | + | return ret; |
− | rows[iTable] = $(this).find('tr:has(td)'); // data rows
| + | } |
| + | }; |
| | | |
− | // init or trim the cookie array of rows, if needed
| + | $(self.init); |
− | while (cookie[iTable].length < rows[iTable].length) {
| |
− | cookie[iTable].push(0);
| |
− | }
| |
− | while (cookie[iTable].length > rows[iTable].length) {
| |
− | cookie[iTable].pop();
| |
− | }
| |
| | | |
− | // don't rely on headers to find # of columns
| + | /* |
− | // count them dynamically
| + | // sample data for testing the algorithm used |
− | columns = 1;
| + | var data = { |
| + | // page1 |
| + | '0FF47C63': [ |
| + | [0, 1, 1, 0, 1, 0], |
| + | [0, 1, 1, 0, 1, 0, 1, 1, 1], |
| + | [0, 0, 0, 0, 1, 1, 0, 0] |
| + | ], |
| + | // page2 |
| + | '02B75ABA': [ |
| + | [0, 1, 0, 1, 1, 0], |
| + | [1, 1, 1, 0, 1, 0, 1, 1, 0], |
| + | [0, 0, 1, 1, 0, 0, 0, 0] |
| + | ], |
| + | // page3 |
| + | '0676470D': [ |
| + | [1, 0, 0, 1, 0, 1], |
| + | [1, 0, 0, 1, 0, 1, 0, 0, 0], |
| + | [1, 1, 1, 1, 0, 0, 1, 1] |
| + | ] |
| + | }; |
| | | |
− | rows[iTable].each(function (iRow) {
| + | console.log('input', data); |
− | // update column count as we go
| |
− | // a smarter approach would count colspans, but this is good for now
| |
− | columns = Math.max(columns, $(this).children('th,td').length);
| |
| | | |
− | // initialize highlighting based on the cookie
| + | var compressedData = self.compress(data); |
− | setHighlight(this, cookie[iTable][iRow]);
| + | console.log('compressed', compressedData); |
− | | |
− | // set mouse events
| |
− | $(this).mouseover(function () {
| |
− | setHighlight(this, 2);
| |
− | }).mouseout(function () {
| |
− | setHighlight(this, cookie[iTable][iRow]);
| |
− | }).click(function (e) {
| |
− | // don't toggle highlight when clicking links
| |
− | if ((e.target.tagName !== 'A') && (e.target.tagName !== 'IMG')) {
| |
− | cookie[iTable][iRow] = 1 - cookie[iTable][iRow];
| |
− | setHighlight(this, cookie[iTable][iRow]);
| |
− | saveCookie();
| |
− | }
| |
− | });
| |
− | });
| |
− | | |
− | // add a button for reset
| |
− | $(this).append(
| |
− | $('<tfoot/>')
| |
− | .append(
| |
− | $('<tr/>')
| |
− | .append(
| |
− | $('<th/>')
| |
− | .attr('colspan', columns)
| |
− | .append(
| |
− | $('<input>')
| |
− | .attr({
| |
− | 'type': 'button',
| |
− | 'value': 'Reset'
| |
− | })
| |
− | .click(function () {
| |
− | rows[iTable].each(function (iRow) {
| |
− | cookie[iTable][iRow] = 0;
| |
− | setHighlight(this, 0);
| |
− | });
| |
− | saveCookie();
| |
− | })
| |
− | )
| |
− | )
| |
− | )
| |
− | );
| |
− | });
| |
− | }
| |
− | }
| |
| | | |
− | $(highlightTable); | + | var parsedData = self.parse(compressedData); |
| + | console.log(parsedData); |
| + | */ |
| | | |
− | }(this.jQuery, this.mediaWiki)); | + | }(this.jQuery, this.mediaWiki, this.OO, this.rswiki)); |
| | | |
− | /* </pre> */ | + | // </pre> |