您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Changes the editions display on the work pages to a sortable grid.
// ==UserScript== // @name LibraryThing Work Editions Grid // @namespace https://gf.qytechs.cn/en/users/14131-brightcopy-edited // @description Changes the editions display on the work pages to a sortable grid. // @include http*://*.librarything.tld/work/*/editions* // @include http*://*.librarything.com/work/*/editions* // @license Public Domain // @version 5 // @grant GM_addStyle // ==/UserScript== // start: translate only this section var TRANSLATE_TITLE = 'Title'; var TRANSLATE_AUTHOR = 'Author'; var TRANSLATE_ISBN = 'ISBN'; var TRANSLATE_NUMBER = '#'; var TRANSLATE_MULTI_SORT_HINT = 'Click to allow sorting on multiple columns'; var TRANSLATE_MEDIA = 'Media'; var TRANSLATE_ENTRY = 'Entry' // end: translate only this section var SORT_ASCENDING = 0; var SORT_DESCENDING = 1; // ISBN of this book var bookISBN; try { bookISBN = document.body.getElementsByClassName('Z3988')[0].getAttribute('title').match(/rft\.isbn=([^&]+)/)[1]; } catch (e) {} // creates an editionsDiv table var editionsDiv = document.getElementById('editions'); var workSimpleHead = document.getElementsByClassName("navInfoTitle")[0].parentNode; var gridDiv = document.getElementById('ltwegMain'); var byAuthorDiv = document.getElementById('ltwegAuthor'); var byTitleDiv = document.getElementById('ltwegTitle'); var groupedDiv = document.getElementById('ltwegGrouped'); var editionsList = []; var tableBodyDiv; var FIELD_MEDIA = 0; var FIELD_TITLE = 1; var FIELD_AUTHOR = 2; var FIELD_ISBN = 3; var FIELD_COPIES = 4; var FIELD_ENTRY = 5; var fields = [ // translate: if translating, translate only the "label" value to your language {name:"Media", label:TRANSLATE_MEDIA, direction:SORT_DESCENDING, sortField:"Media"}, {name:"Title", label:TRANSLATE_TITLE, direction:SORT_ASCENDING, sortField:"ntitle"}, {name:"Author", label:TRANSLATE_AUTHOR, direction:SORT_ASCENDING, sortField:"nauthor"}, {name:"ISBN", label:TRANSLATE_ISBN, direction:SORT_ASCENDING, sortField:"nISBN"}, {name:"Copies", label:TRANSLATE_NUMBER, direction:SORT_DESCENDING, sortField:"Copies"}, {name:"EntryFormat", label:TRANSLATE_ENTRY, direction:SORT_DESCENDING, sortField:"EntryFormat"} ]; var sorts = [ FIELD_COPIES, FIELD_TITLE, FIELD_AUTHOR, FIELD_ISBN, FIELD_MEDIA, FIELD_ENTRY ]; var multisort; function setEditionStyles() { GM_addStyle('.ltwegHeader { text-align:left; border-bottom: 1px solid black; }'); GM_addStyle('#ltwegEditionsTable td, #ltwegEditionsTable th { padding-left:1em; text-indent:-1em; padding-right: 1em }'); GM_addStyle('#ltwegEditionsTable.multisort td, #ltwegEditionsTable th { padding-left:1em; text-indent:-1em; padding-right: 1em }'); GM_addStyle('.ltwegCopies { min-width:20px }'); GM_addStyle('.ltwegDup { color:#999999 }'); GM_addStyle('.ltwegRow5 { border-bottom:1px solid #B0B0B0 }'); GM_addStyle('#ltwegHeaderMultisort { text-align:center } '); GM_addStyle('.ltwegHeader { white-space: nowrap } '); GM_addStyle('#ltwegHeaderMultisortLink { display:inline-block; width:16px; height:16px; vertical-align:middle; ' + 'background:url("http://www.librarything.com/pics/c.png") no-repeat scroll -102px 0px transparent; }'); GM_addStyle('.ltwegMultisortChecked { background-position:-119px 0px !important }'); GM_addStyle('.ltwegSeparate { display:inline-block; width:20px; height:16px; vertical-align:middle; ' + 'background:url("http://www.librarything.com/pics/c.png") no-repeat scroll -21px -180px transparent; }'); GM_addStyle('#ltwegHeaderBody td a:visited, #ltwegHeaderBody a:link { color:black !important }'); GM_addStyle('#ltwegHeaderBody td.ltwegDup a:visited, #ltwegHeaderBody td.ltwegDup a:link { color:#999999 !important }'); GM_addStyle('#ltwegEditionsTable tr.selected { background: #AF9 }'); } function parseEditions() { var editionRE = /(<span class="formatnotice">[^<]*<\/span> \u2014 )?(.*?) <span class="copies">\((<span[^>]*>)?(.*?)onclick="c_sw\((\d+),(\d+).*$/; /* editionRE examples / explanations: editionRE[1] = <span class="formatnotice">Video Recording</span> — editionRE[2] = Title / Author / ISBN / Manual entry (with HTML and possible absent Author & ISBN & Manual entry) editionRE[3] = <span class="trans" id="..."> (parenthesized to add the ? after it) editionRE[4] = # of copies (or "no copies") editionRE[5] = separation number for edition editionRE[6] = separation number for work */ // Make an array of the editions. They each end in <br> var editions = editionsDiv.innerHTML.split("<br>"); for ( i=0 ; i < editions.length - 1; i++ ) { // -1 because the last one's going to be nothing/whitespace following the last <br> var matchedEdition = editions[i].match(editionRE); // Get "Video recording" or whatever (leave blank if doesn't exist) var media = matchedEdition[1] !== undefined ? matchedEdition[1] : ""; media = media.replace(/^[^>]*>/, "").replace(/<.*$/,"").replace(/ /g, " "); // Setting up some variables var author = ISBN = entryFormat = ""; var editionData = editions[i].match(editionRE)[2].split('<span class="divider">/</span>'); // The title should be the first item in the "editionData" array var title = editionData[0]; // Check if there's an entry format (e.g. Manual Entry), which gets surrounded by a <span ... class="trans"> on the non-English sites var tempLastIndex = editionData[editionData.length - 1]; var inTagRE = /^<[^>]+>([^<]*)<\/[span]+>/; if (tempLastIndex == "Manual Entry") { // What to do for other text? entryFormat = tempLastIndex; } else if (inTagRE.test(tempLastIndex)) { // <span class="trans">Entrada manual</span> or <a href="#">ISBN Record</a>, for example entryFormat = tempLastIndex.match(inTagRE)[1]; } entryFormat = entryFormat.replace(/ /g, " "); // Check if there's an ISBN if (entryFormat != "") { editionData.splice(-1, 1) } // Remove any entry format from the array var isbnMatch = false; var isbnMatch = editionData[editionData.length - 1].match(/^ISBN (\d{9,10}X?)$/); if (isbnMatch) { ISBN = isbnMatch[1]; editionData.splice(-1, 1); // Remove the ISBN from the array } // Check if there's an author author = editionData.length > 1 ? editionData[editionData.length - 1] : ""; // Get the number of copies var copies = parseInt(matchedEdition[4]) || 0; // Get the numbers needed for separation var separate = [matchedEdition[5], matchedEdition[6]]; // If media format or entry format don't exist, use "(default)" if (media == "") media = "<i>(default)</i>"; if (entryFormat == "") entryFormat = "<i>(default)</i>"; var edition = {Copies:copies, ntitle:normalize(title), nauthor:normalize(author), nISBN:normalize(ISBN), separate:separate, Media:media, EntryFormat:entryFormat}; edition.ISBNraw = ISBN; if (ISBN != '') { ISBN = '<a href="/search.php?search=' + ISBN + '&searchtype=media&searchtype=media&sortchoice=0">' + ISBN + '</a>'; } if (title != '') { title = '<a href="/search.php?search=' + ltSearchEscape(title) + '&searchtype=worktitles&searchtype=worktitles&sortchoice=0">' + title + '</a>'; } if (author != '') { author = '<a href="/search.php?search=' + ltSearchEscape(author) + '&searchtype=authorname&searchtype=authorname&sortchoice=0">' + author.replace(" ", " ") + '</a>'; // nbsp to prevent most author wrapping } edition.Title = title; edition.Author = author; edition.ISBN = ISBN; editionsList.push(edition); } } function normalize(value) { if (value == null) { return '' } else { return value.toLowerCase().replace(/[^a-z0-9]/g, ""); } } function editionsCompareWrap(b1, b2) { var result = editionsCompare(b1, b2); return result; } function editionsCompare(b1, b2) { for (var i = 0; i < (multisort && multisortChecked() ? sorts.length : 1); i++) { var field = fields[sorts[i]]; if (b1[field.sortField] < b2[field.sortField]) { if (field.direction == SORT_ASCENDING) { return -1 } else //if (field.direction == SORT_DESCENDING) { return 1 } } else if (b1[field.sortField] > b2[field.sortField]) { if (field.direction == SORT_ASCENDING) { return 1 } else //if (field.direction == SORT_DESCENDING) { return -1 } } } return 0; } function buildEditionsTable() { var i; var html = '<table style="border-collapse: collapse; min-width:80%" id="ltwegEditionsTable">' + '<thead><tr>'; for (i = 0; i < fields.length; i++) { var field = fields[i]; html += '<th class="ltwegHeader ltweg' + field.name + '">' + '<a id="ltwegHeaderLink' + i + '" class="ltwegHeaderLinkSort" href="javascript:return false;">' + field.label + '<sup> </sup>' + '<sup class="ltwegSortArrow">' + '<img id="ltwegSortArrow' + i + '" src="" style="display:none">' + '</sup>' + '<sup id="ltwegHeaderSup' + i + '" style="display:none"> </sup>' + '</a>' + '</th>' } html += '<th class="ltwegHeader" id="ltwegHeaderMultisort">' + '<a id="ltwegHeaderMultisortLink" href="javascript:return false;" title="' + TRANSLATE_MULTI_SORT_HINT + '"></a>' + '</th>'; html += '</tr></thead><tbody id="ltwegHeaderBody"></tbody></table>'; editionsDiv.style.display = 'none'; gridDiv = document.createElement('div'); editionsDiv.parentNode.appendChild(gridDiv); gridDiv.innerHTML = html; var span = document.createElement('span'); workSimpleHead.appendChild(span); span.style.cssFloat = 'right'; span.style.fontWeight = 'normal'; var gridLink = document.createElement('a'); gridLink.setAttribute('href', '#'); gridLink.appendChild(document.createTextNode('grid')); span.appendChild(gridLink); span.appendChild(document.createTextNode(' | ')); var originalLink = document.createElement('a'); originalLink.setAttribute('href', '#'); originalLink.appendChild(document.createTextNode('original')); span.appendChild(originalLink); gridLink.style.fontWeight = 'bold'; gridLink.addEventListener('click', function (e) { gridLink.style.fontWeight = 'bold'; originalLink.style.fontWeight = 'normal'; originalLink.style.display = ''; editionsDiv.style.display = 'none'; gridDiv.style.display = ''; e.preventDefault(); }, false); originalLink.addEventListener('click', function (e) { gridLink.style.fontWeight = 'normal'; originalLink.style.fontWeight = 'bold'; editionsDiv.style.display = ''; gridDiv.style.display = 'none'; e.preventDefault(); }, false); tableBodyDiv = document.getElementById('ltwegHeaderBody'); document.getElementById('ltwegHeaderLink0').addEventListener('click', function (e) { doHeaderClick(e, 0) }, false); document.getElementById('ltwegHeaderLink1').addEventListener('click', function (e) { doHeaderClick(e, 1) }, false); document.getElementById('ltwegHeaderLink2').addEventListener('click', function (e) { doHeaderClick(e, 2) }, false); document.getElementById('ltwegHeaderLink3').addEventListener('click', function (e) { doHeaderClick(e, 3) }, false); document.getElementById('ltwegHeaderLink4').addEventListener('click', function (e) { doHeaderClick(e, 4) }, false); document.getElementById('ltwegHeaderLink5').addEventListener('click', function (e) { doHeaderClick(e, 5) }, false); multisort = document.getElementById('ltwegHeaderMultisortLink'); multisort.addEventListener('click', doMultisortClick, false); syncArrows(); buildEditions(); } function buildEditions() { editionsList.sort(editionsCompareWrap); var selectedISBN = (window.location.search.match(/isbn=([^&]+)/) || []).pop(); if (selectedISBN === undefined) { selectedISBN = bookISBN; } var html = ''; var anchored = false; var lastClass = 'ltwegEven'; for (var i = 0; i < editionsList.length; i++) { var edition = editionsList[i]; html += '<tr class="' + ((edition.ISBNraw === selectedISBN) ? 'selected ' : '') + (edition.thisBook ? 'thisbook ' : '') + ((editionsList.length > 9) && (i % 5 == 4) ? 'ltwegRow5' : '') + '">'; for (var f = 0; f < fields.length; f++) { var field = fields[f]; html += '<td' + (isDup(i, field) && f != FIELD_COPIES ? ' class="ltwegDup"' : '') + '>'; if (edition.ISBNraw === selectedISBN && !anchored && window.location.search !== '') { html += '<a name="grid"></a>'; anchored = true; } html += edition[field.name] + '</td>'; } html += '<td class="' + lastClass + '"></a><a href="/work_separate.php?book=' + edition.separate[0] + '&work=' + edition.separate[1] + '"><span class="ltwegSeparate"></span></a></td>'; html += '</tr>'; } tableBodyDiv.innerHTML = html; if (anchored) { window.location.hash = '#grid'; } } function isDup(i, field) { return i != 0 && editionsList[i][field.sortField] == editionsList[i - 1][field.sortField]; } function multisortChecked() { return multisort.className != ''; } function doMultisortClick(e) { stopBubbling(e); var isMultisort = !multisortChecked(); // about to flip multisort.className = isMultisort ? 'ltwegMultisortChecked' : ''; syncArrows(); } function syncArrows() { var isMultisort = multisortChecked(); // about to flip for (i = 0; i < fields.length; i++) { var sup = document.getElementById('ltwegHeaderSup' + i); sup.style.display = isMultisort ? '' : 'none'; setTextContent(sup, sorts.indexOf(i) + 1); var arrow = document.getElementById('ltwegSortArrow' + i); arrow.style.display = (isMultisort || sorts[0] == i) ? '' : 'none'; arrow.src = (fields[i].direction == SORT_ASCENDING) ? 'http://static.librarything.com/pics/sort-up.gif' : 'http://static.librarything.com/pics/sort-down.gif'; } } function doHeaderClick(e, clickedIndex) { stopBubbling(e); var isMultisort = multisortChecked(); if (isMultisort && sorts[sorts.length - 1] == clickedIndex || !isMultisort && sorts[0] == clickedIndex) { fields[clickedIndex].direction = (fields[clickedIndex].direction == SORT_ASCENDING ? SORT_DESCENDING : SORT_ASCENDING) } else { for (var i = 0; i < sorts.length; i++) { if (sorts[i] == clickedIndex) { sorts.splice(i, 1); break; } } if (isMultisort) { sorts.push(clickedIndex) } else { fields[clickedIndex].direction = SORT_ASCENDING; sorts.unshift(clickedIndex); } } syncArrows(); buildEditions(); return false; } function stopBubbling(e) { if (!e) { e = window.event; } e.cancelBubble = true; if (e.stopPropagation) { e.stopPropagation(); } } function setTextContent(node, text) { if (node.innerText) { node.innerText = text } else if (node.textContent) { node.textContent = text; } } function ltSearchEscape(s) { return encodeURIComponent(unescapeHTML(s)) .replace(/%20/g, '+') .replace(/\(/g, '%28') .replace(/\)/g, '%29'); } function unescapeHTML(s) { return s .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>'); } try { if (editionsDiv && workSimpleHead && !gridDiv) { setEditionStyles(); parseEditions(); buildEditionsTable(); } } catch (err) { console.log(err); }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址