MediaWiki:Gadget-checkboxList-core.js: Difference between revisions
Created page with "→* <pre> * Adds support for checkbox lists ([[Template:Checklist]]) * * * History: * - 1.0: Original implementation - Cqm: /* * DATA STORAGE STRUCTURE * ----------..." |
mNo edit summary |
||
| Line 1: | Line 1: | ||
/** <pre> | /** <pre> | ||
* | * highlightTable.js | ||
* | * | ||
* Description: | |||
* Adds highlighting to tables | |||
* | * | ||
* History: | * History: | ||
* - 1.0: | * - 1.0: Row highlighting - Quarenon | ||
* - 1.1: Update from pengLocations.js v1.0 - Quarenon | |||
* - 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 | * DATA STORAGE STRUCTURE | ||
* ---------------------- | * ---------------------- | ||
| Line 75: | Line 86: | ||
onevar:true | onevar:true | ||
*/ | */ | ||
(function($, mw, OO, gs) { | |||
'use strict'; | 'use strict'; | ||
// constants | |||
var STORAGE_KEY = 'gs: | var STORAGE_KEY = 'gs:lightTable', | ||
TABLE_CLASS = 'lighttable', | |||
LIGHT_ON_CLASS = 'highlight-on', | |||
MOUSE_OVER_CLASS = 'highlight-over', | |||
BASE_64_URL = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', | BASE_64_URL = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', | ||
PAGE_SEPARATOR = '!', | PAGE_SEPARATOR = '!', | ||
TABLE_SEPARATOR = '.', | |||
CASTAGNOLI_POLYNOMIAL = 0x04c11db7, | CASTAGNOLI_POLYNOMIAL = 0x04c11db7, | ||
UINT32_MAX = 0xffffffff, | UINT32_MAX = 0xffffffff, | ||
self = { | self = { | ||
| Line 104: | Line 110: | ||
* Perform initial checks on the page and browser. | * Perform initial checks on the page and browser. | ||
*/ | */ | ||
init: function () { | init: function() { | ||
var $ | var $tables = $('table.' + TABLE_CLASS), | ||
hashedPageName = self.hashString(mw.config.get('wgPageName')); | hashedPageName = self.hashString(mw.config.get('wgPageName')); | ||
// check we have some tables to interact with | // check we have some tables to interact with | ||
if (!$ | if (!$tables.length) { | ||
return; | return; | ||
} | } | ||
// check the browser supports local storage | // check the browser supports local storage | ||
if (! | if (!gs.hasLocalStorage()) { | ||
return; | return; | ||
} | } | ||
self.data = self.load(hashedPageName, $ | self.data = self.load(hashedPageName, $tables.length); | ||
self. | self.initTables(hashedPageName, $tables); | ||
}, | }, | ||
| Line 127: | Line 131: | ||
* | * | ||
* @param hashedPageName The current page name as a hash. | * @param hashedPageName The current page name as a hash. | ||
* @param $ | * @param $tables A list of highlightable tables on the current page. | ||
*/ | */ | ||
initTables: function(hashedPageName, $tables) { | |||
$ | $tables.each(function(tIndex) { | ||
var $this = $(this), | var $this = $(this), | ||
// data cells | |||
$cells = $this.find('td'), | |||
$rows = $this.find('tr:has(td)'), | |||
// don't rely on headers to find number of columns | |||
// | // count them dynamically | ||
columns = 1, | |||
tableData = self.data[tIndex], | |||
mode = 'cells'; | |||
// | // Switching between either highlighting rows or cells | ||
if (!$this.hasClass('individual')) { | |||
mode = 'rows'; | |||
$cells = $rows; | |||
} | } | ||
$ | // initialise rows if necessary | ||
while ($cells.length > tableData.length) { | |||
tableData.push(0); | |||
} | |||
// counting the column count | |||
// necessary to determine colspan of reset button | |||
$rows.each(function() { | |||
var $this = $(this); | |||
columns = Math.max(columns, $this.children('th,td').length); | |||
}); | |||
$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); | |||
function | // 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); | ||
self. | |||
} | } | ||
}); | |||
} | |||
}); | }); | ||
// add a button for reset | // add a button for reset | ||
var button = new OO.ui.ButtonWidget( { | var button = new OO.ui.ButtonWidget({ | ||
label: ' | label: 'Clear selection', | ||
icon: ' | icon: 'clear', | ||
title: ' | 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 () { | button.$element.click(function() { | ||
$ | $cells.each(function(cIndex) { | ||
tableData[cIndex] = 0; | |||
self. | self.setHighlight($(this), 0); | ||
}); | }); | ||
self.save(hashedPageName, $ | self.save(hashedPageName, $tables.length); | ||
}); | }); | ||
$this.append( | |||
$('<tfoot>') | |||
.append( | |||
$('<tr>') | |||
.append( | |||
$('<th>') | |||
.attr('colspan', columns) | |||
.append(button.$element) | |||
) | |||
) | |||
); | |||
}); | }); | ||
}, | }, | ||
/* | /* | ||
* Change the | * Change the cell background color based on mouse events. | ||
* | * | ||
* @param $ | * @param $cell The cell element. | ||
* @param val The value to control what class to add (if any). | * @param val The value to control what class to add (if any). | ||
* 0 -> | * 0 -> light off (no class) | ||
* 1 -> light on | * 1 -> light on | ||
* 2 -> mouse over | * 2 -> mouse over | ||
*/ | */ | ||
setHighlight: function($cell, val) { | |||
$ | $cell.removeClass(MOUSE_OVER_CLASS); | ||
$cell.removeClass(LIGHT_ON_CLASS); | |||
switch (val) { | switch (val) { | ||
// | // light on | ||
case 1: | case 1: | ||
$ | $cell.addClass(LIGHT_ON_CLASS); | ||
break; | |||
// mouse-over | |||
case 2: | |||
$cell.addClass(MOUSE_OVER_CLASS); | |||
break; | break; | ||
} | } | ||
| Line 284: | Line 257: | ||
* @param hashedPageName A hash of the current page name. | * @param hashedPageName A hash of the current page name. | ||
*/ | */ | ||
save: function (hashedPageName) { | save: function(hashedPageName) { | ||
// load the existing data so we know where to save it | |||
var curData = localStorage.getItem(STORAGE_KEY), | var curData = localStorage.getItem(STORAGE_KEY), | ||
compressedData; | compressedData; | ||
| Line 312: | Line 285: | ||
* @return the compressed data. | * @return the compressed data. | ||
*/ | */ | ||
compress: function (data) { | compress: function(data) { | ||
var ret = {}; | var ret = {}; | ||
Object.keys(data).forEach(function (hashedPageName) { | Object.keys(data).forEach(function(hashedPageName) { | ||
var pageData = data[hashedPageName], | var pageData = data[hashedPageName], | ||
pageKey = hashedPageName.charAt(0); | pageKey = hashedPageName.charAt(0); | ||
| Line 325: | Line 298: | ||
ret[pageKey][hashedPageName] = []; | ret[pageKey][hashedPageName] = []; | ||
pageData.forEach(function (tableData) { | pageData.forEach(function(tableData) { | ||
var | var compressedTableData = '', | ||
i, j, k; | i, j, k; | ||
| Line 336: | Line 309: | ||
} | } | ||
compressedTableData += BASE_64_URL.charAt(k); | |||
} | } | ||
ret[pageKey][hashedPageName].push( | ret[pageKey][hashedPageName].push(compressedTableData); | ||
}); | }); | ||
ret[pageKey][hashedPageName] = ret[pageKey][hashedPageName].join( | ret[pageKey][hashedPageName] = ret[pageKey][hashedPageName].join(TABLE_SEPARATOR); | ||
}); | }); | ||
Object.keys(ret).forEach(function (pageKey) { | Object.keys(ret).forEach(function(pageKey) { | ||
var hashKeys = Object.keys(ret[pageKey]), | var hashKeys = Object.keys(ret[pageKey]), | ||
hashedData = []; | hashedData = []; | ||
hashKeys.forEach(function (key) { | hashKeys.forEach(function(key) { | ||
var pageData = ret[pageKey][key]; | var pageData = ret[pageKey][key]; | ||
hashedData.push(key + pageData); | hashedData.push(key + pageData); | ||
| Line 365: | Line 338: | ||
* | * | ||
* @param hashedPageName A hash of the current page name. | * @param hashedPageName A hash of the current page name. | ||
* @param | * @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. | * @return The data for the current page. | ||
*/ | */ | ||
load: function (hashedPageName, | load: function(hashedPageName, numTables) { | ||
var data = localStorage.getItem(STORAGE_KEY), | var data = localStorage.getItem(STORAGE_KEY), | ||
pageData; | pageData; | ||
| Line 389: | Line 362: | ||
} | } | ||
// if more | // if more tables were added | ||
// add extra arrays to store the data in | // add extra arrays to store the data in | ||
// also populates if no existing data was found | // also populates if no existing data was found | ||
while ( | while (numTables > pageData.length) { | ||
pageData.push([]); | pageData.push([]); | ||
} | } | ||
// if | // if tables were removed, remove data from the end of the list | ||
// as there's no way to tell which was removed | // as there's no way to tell which was removed | ||
while ( | while (numTables < pageData.length) { | ||
pageData.pop(); | pageData.pop(); | ||
} | } | ||
| Line 413: | Line 386: | ||
* @return the parsed data. | * @return the parsed data. | ||
*/ | */ | ||
parse: function (data) { | parse: function(data) { | ||
var ret = {}; | var ret = {}; | ||
Object.keys(data).forEach(function (pageKey) { | Object.keys(data).forEach(function(pageKey) { | ||
var pageData = data[pageKey].split(PAGE_SEPARATOR); | var pageData = data[pageKey].split(PAGE_SEPARATOR); | ||
pageData.forEach(function ( | pageData.forEach(function(tableData) { | ||
var hashedPageName = | var hashedPageName = tableData.substr(0, 8); | ||
tableData = tableData.substr(8).split(TABLE_SEPARATOR); | |||
ret[hashedPageName] = []; | ret[hashedPageName] = []; | ||
tableData.forEach(function(rowData, index) { | |||
var i, j, k; | var i, j, k; | ||
ret[hashedPageName].push([]); | ret[hashedPageName].push([]); | ||
for (i = 0; i < | for (i = 0; i < rowData.length; i += 1) { | ||
k = BASE_64_URL.indexOf( | k = BASE_64_URL.indexOf(rowData.charAt(i)); | ||
// input validation | // input validation | ||
| Line 458: | Line 431: | ||
* @return the result of the hash. | * @return the result of the hash. | ||
*/ | */ | ||
hashString: function (input) { | hashString: function(input) { | ||
var ret = 0, | var ret = 0, | ||
table = [], | table = [], | ||
| Line 495: | Line 468: | ||
}; | }; | ||
$(self.init); | |||
/* | /* | ||
| Line 531: | Line 501: | ||
console.log(parsedData); | console.log(parsedData); | ||
*/ | */ | ||
/ | |||
}(this.jQuery, this.mediaWiki, this.OO, this.gswiki)); | |||
// </pre> | |||