คุณต้องเข้าสู่ระบบหรือลงทะเบียนก่อนดำเนินการต่อ
A script for making table sortable
// // ==UserScript== // @name Table Sort for TorrentsMD // @namespace Table Sorter // @description A script for making table sortable // @include *torrentsmd.*/browse.php* // @include *torrentsmoldova.*/browse.php* // @include *torrentsmd.*/search.php* // @include *torrentsmoldova.*/search.php* // @version 0.0.1.20140607094600 // ==/UserScript== if (CODEBOX===undefined){ var CODEBOX={}; } CODEBOX.tabsorter = { 'processTable' : function(tableElement){ if ( !checkTableStructureOk(tableElement) ){ return null; } // State is initialised here var rowObjects = []; var currentSortColIndex = null; var currentSortAscending = null; var linkTds = []; var rowWithArrows, rowWithOptions; var colCount = 0; var sortTypes = { 'NONE' : { 'text' : 'none', 'fn' : sortRestore }, 'ALPHA' : { 'text' : 'alpha', 'fn' : sortColByAlpha }, 'NUM' : { 'text' : 'num', 'fn' : sortColByNum } }; var currentSortType = sortTypes.NONE; function sortRestore(){ rowObjects.sort(function(a,b){ return a.getOriginalIndex() - b.getOriginalIndex(); }); redraw(); } function sortColByAlpha(col, ascending){ if (col<colCount){ var multiplier = ascending ? 1 : -1; rowObjects.sort(function(a,b){ var aItem = a.getCellValue(col); aItem = aItem ? aItem.toLowerCase() : aItem; var bItem = b.getCellValue(col); bItem = bItem ? bItem.toLowerCase() : bItem; if (aItem){ if (bItem){ if (aItem > bItem){ return 1 * multiplier; } else if (aItem < bItem){ return -1 * multiplier; } else { return 0; } } else { return 1 * multiplier; } } else { if (bItem){ return -1 * multiplier; } else { return 0; } } CODEBOX.assert(false); }); } redraw(); } function sortColByNum(col, ascending){ function makeNumFromText(txt){ return parseFloat(txt.replace(/,/g, '').replace(/[^0-9\.+\-]+/, ' ')); } if (col<colCount){ var multiplier = ascending ? 1 : -1; rowObjects.sort(function(a,b){ var aNum = makeNumFromText(a.getCellValue(col)); if (isNaN(aNum)){ // Make non-numeric values go to the bottom of the list return Infinity; } var bNum = makeNumFromText(b.getCellValue(col)); if (isNaN(bNum)){ // Make non-numeric values go to the bottom of the list return -Infinity; } return (aNum - bNum) * multiplier; }); } redraw(); } // Populate rowObjects array CODEBOX.forEach(tableElement.getElementsByTagName("TR"), function(item, i){ var rowObject = buildRowObject(item, i); if (rowObject){ rowObjects.push(rowObject); colCount = ( (colCount < rowObject.getCellCount()) ? rowObject.getCellCount() : colCount); } }); setupSortRows(); function checkTableStructureOk(tableElement){ CODEBOX.assert(tableElement); // tables that contain other tables are not processed... var nestedTables = tableElement.getElementsByTagName("TABLE"); if (nestedTables.length > 0){ return false; } // tables that have less than 2 rows are not processed... var rows = tableElement.getElementsByTagName("TR"); if (rows.length < 2){ return false; } // tables that don't have any text nodes are not processed... function checkForTextNodeChildren(item){ CODEBOX.assert(item); var childNodes = item.childNodes; if (!childNodes){ return false; } var childNode; var TEXT_NODE_TYPE = 3; var TRIM_REGEX = /^\s+|\s+$/; for (var i=0, l=childNodes.length; i<l; i++){ childNode = childNodes[i]; if (childNode.nodeType===TEXT_NODE_TYPE){ var text = childNode.nodeValue; text = text.replace(TRIM_REGEX, ''); if (text.length > 0){ return true; } } else { if ( checkForTextNodeChildren(childNode) ){ return true; } } } return false; } if (!checkForTextNodeChildren(tableElement)){ return false; } return true; } function buildRowObject(trElement, index){ if (trElement.parentNode.tagName==='THEAD'){ // Any rows inside a header are ignored return null; } var tdElements = trElement.getElementsByTagName("TD"); if (tdElements.length===0){ // Rows without any TDs are ignored, these are usually headers with THs instead return null; } var obj = {}; obj.getTr = function(){ return trElement; }; var parent = trElement.parentNode; var cellToElementMappingArray = []; var cellIndex=0; /* Produces a mapping from 'virtual' cells to TD elements so if the third cell has colspan='3' then virtual cells 2,3 and 4 all map to TD 2 |A|B| C | [0,1,2,2,2] */ CODEBOX.forEach(tdElements, function(item, i){ var colSpan = +(item.colSpan); if (isNaN(colSpan) || colSpan===0){ colSpan = 1; } CODEBOX.assert(colSpan); for(var j=0; j<colSpan; j++){ cellToElementMappingArray[cellIndex++] = i; } }); obj.getCellCount = function(){ return cellToElementMappingArray.length; }; obj.getCellValue = function(index){ if (index >= cellToElementMappingArray.length){ return null; } else { var tdIndex = cellToElementMappingArray[index]; CODEBOX.assert( tdIndex < tdElements.length ); var cellContent = tdElements[tdIndex].innerHTML; // This might contain markup, eg <span class='tdText>cell text</span>, so clean it out var STRIP_MARKUP_REGEX = /<[^<]*>/g; cellContent = cellContent.replace(STRIP_MARKUP_REGEX, ''); return cellContent; } }; obj.getOriginalIndex = function(){ return index; }; obj.removeFromParent = function(){ parent.removeChild(trElement); }; obj.attachToParent = function(){ parent.appendChild(trElement); }; return obj; } function setSortType(sortType){ currentSortType = sortType; // Adjust the styles of the sort-type links CODEBOX.forEachObject(sortTypes, function(thisSortType){ var isSelectedSortType = (thisSortType===currentSortType); thisSortType.link.style.color = (isSelectedSortType ? 'black' : 'gray'); thisSortType.link.style.textDecoration = (isSelectedSortType ? '' : 'underline'); thisSortType.link.style.cursor = (isSelectedSortType ? '' : 'pointer' ); }); // Hide the sort arrows if we aren't sorting rowWithArrows.style.display = (sortType===sortTypes.NONE) ? 'none' : ''; // Reset any 'selected' arrow from the previous sort if (currentSortColIndex !== null){ updateLinkCell(currentSortColIndex, false, false); } } function setupSortRows(){ var firstRow = rowObjects[0].getTr(); // Add a new row for the options rowWithOptions = document.createElement("TR"); firstRow.parentNode.insertBefore(rowWithOptions, firstRow); var optionsTd = document.createElement("TD"); optionsTd.style.fontSize = '0.7em'; optionsTd.colSpan = colCount; var optionsSpan = document.createElement("SPAN"); optionsSpan.style.paddingLeft = '1em'; optionsSpan.innerHTML = 'Sort Type: '; var optionAlphaSortLink = document.createElement("A"); optionAlphaSortLink.style.paddingLeft = '0.5em'; optionAlphaSortLink.style.textDecoration = 'underline'; optionAlphaSortLink.style.cursor = 'pointer'; optionAlphaSortLink.innerHTML = 'alpha'; optionAlphaSortLink.addEventListener('click', function(e){ setSortType( sortTypes.ALPHA ); }, false); sortTypes.ALPHA.link = optionAlphaSortLink; var optionNoSortLink = document.createElement("A"); optionNoSortLink.style.paddingLeft = '0.5em'; optionNoSortLink.style.textDecoration = 'underline'; optionNoSortLink.style.cursor = 'pointer'; optionNoSortLink.innerHTML = 'none'; optionNoSortLink.addEventListener('click', function(e){ setSortType( sortTypes.NONE ); sortTypes.NONE.fn(); }, false); sortTypes.NONE.link = optionNoSortLink; var optionNumSortLink = document.createElement("A"); optionNumSortLink.style.paddingLeft = '0.5em'; optionNumSortLink.style.textDecoration = 'underline'; optionNumSortLink.style.cursor = 'pointer'; optionNumSortLink.innerHTML = 'num'; optionNumSortLink.addEventListener('click', function(e){ setSortType( sortTypes.NUM ); }, false); sortTypes.NUM.link = optionNumSortLink; optionsTd.appendChild(optionsSpan); optionsTd.appendChild(optionAlphaSortLink); optionsTd.appendChild(optionNumSortLink); optionsTd.appendChild(optionNoSortLink); rowWithOptions.appendChild(optionsTd); // Add a new row for the sort arrows rowWithArrows = document.createElement("TR"); firstRow.parentNode.insertBefore(rowWithArrows, firstRow); var linkTd, linkElement; for(var i=0; i<colCount; i++){ linkTd = document.createElement("TD"); linkTd.style.fontSize = '0.7em'; linkTd.style.fontWeight = 'bold'; linkTd.style.textAlign = 'center'; linkTds.push(linkTd); linkElement = document.createElement("A"); linkTd.appendChild(linkElement); rowWithArrows.appendChild(linkTd); setCellImages(i, false, false); } setSortType(sortTypes.NONE); } function updateLinkCell(colIndex, isAscending, isDescending){ if (currentSortColIndex === null){ // No column is currently selected, so we don't need to reset anything setCellImages(colIndex, isAscending, isDescending); } else { // There is already a column selected if ( colIndex == currentSortColIndex){ // The new column is the same as the current one... if (currentSortAscending != null && ((currentSortAscending && isAscending) || (!currentSortAscending && isDescending))){ // The new sort order the the same as the current one, so do nothing } else { // The column is the same, but the order is different setCellImages(colIndex, isAscending, isDescending); } } else { // The new column is different to the current one so reset the current one setCellImages(currentSortColIndex, false, false); // Set up the new one setCellImages(colIndex, isAscending, isDescending); } } } function setCellImages(colIndex, isAscending, isDescending){ var DATA_URL_UP = "data:image/gif;base64,R0lGODlhCAAEAPcAAAAAAPfvc/8Avf///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////yH5BAEAAAIALAAAAAAIAAQAAAgSAAUIBABAoEGCBA8iTLhwYUAAADs="; var DATA_URL_UP_FADED = "data:image/gif;base64,R0lGODlhCAAEAPcAAAAAAP8Avf///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////yH5BAEAAAEALAAAAAAIAAQAAAgWAAMIBABAoEEAAgQUHJgwYUGCECEGBAA7"; var DATA_URL_DOWN = "data:image/gif;base64,R0lGODlhCAAEAPcAAAAAAPfvc/8Avf///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////yH5BAEAAAIALAAAAAAIAAQAAAgTAAEIHChQAMGCAgwOTMgQoYCAAAA7"; var DATA_URL_DOWN_FADED = "data:image/gif;base64,R0lGODlhCAAEAPcAAAAAAP8Avf///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////yH5BAEAAAEALAAAAAAIAAQAAAgXAAEIHCgwAAABCAUACMDwoEKGEAsyDAgAOw=="; var linkCell = linkTds[colIndex]; // Remove the current images... while(linkCell.firstChild){ linkCell.removeChild(linkCell.firstChild); } var upArrowImage = document.createElement('IMG'); upArrowImage.src = (isAscending ? DATA_URL_UP : DATA_URL_UP_FADED); upArrowImage.style.cursor = 'pointer'; upArrowImage.addEventListener('click', function(e){ updateLinkCell(colIndex, true, false); currentSortColIndex = colIndex; currentSortAscending = true; currentSortType.fn(colIndex, true); }, false); var downArrowImage = document.createElement('IMG'); downArrowImage.src = (isDescending ? DATA_URL_DOWN : DATA_URL_DOWN_FADED); downArrowImage.style.cursor = 'pointer'; downArrowImage.addEventListener('click', function(e){ updateLinkCell(colIndex, false, true); currentSortColIndex = colIndex; currentSortAscending = false; currentSortType.fn(colIndex, false); }, false); linkCell.appendChild(upArrowImage); linkCell.appendChild(downArrowImage); } function redraw(){ CODEBOX.forEach(rowObjects, function(item){ item.removeFromParent(); }); CODEBOX.forEach(rowObjects, function(item){ item.attachToParent(); }); } } }; CODEBOX.addNamespace = function (namespaceName){ function addNamespaceToObject(obj, namespace){ if (!obj){ obj = CODEBOX; } if (obj[namespace]===undefined){ obj[namespace] = {}; } return obj[namespace]; } var namespaceParts = namespaceName.split('.'); var parentNamespace = null; var thisPart; for( var i=0; i<namespaceParts.length; i++) { thisPart = namespaceParts[i]; parentNamespace = addNamespaceToObject(parentNamespace, thisPart); } }; CODEBOX.addNamespace('consts'); CODEBOX.consts.assert = true; CODEBOX.consts.dialogOnAssert = true; CODEBOX.assert = function( expression, msg, location ){ if (CODEBOX.consts.assert){ if (!expression){ var errMsg = 'ASSERTION FAILED'; if (msg){ errMsg += ': ' + msg; if (location){ errMsg += ' at ' + location; } } if (CODEBOX.consts.dialogOnAssert){ alert(errMsg); } throw new Error(errMsg); } } }; CODEBOX.forEach = function(arr, fnDoThis){ var len = arr.length; for (var i=0; i < len; i++){ fnDoThis(arr[i], i); } }; CODEBOX.forEachObject = function(obj, fnDoThis){ for (var item in obj){ if (obj.hasOwnProperty(item)){ fnDoThis(obj[item]); } } }; var allTables = window.document.documentElement.getElementsByTagName("TABLE"); CODEBOX.forEach(allTables, function(table){ CODEBOX.tabsorter.processTable(table); });