1/*eslint complexity: ["error", 15]*/ 2/*eslint wrap-iife: ["error", "outside"]*/ 3/*eslint quotes: ["error", "double", { "avoidEscape": true }]*/ 4 5function select_all(e) { 6 let checkedStatus = $(e).prop("checked"); 7 8 $(".select-all ").each(function() { 9 $(this).prop("checked", checkedStatus); 10 }); 11 12 $(".alt").each(function() { 13 $(this).prop("checked", checkedStatus); 14 }); 15} 16 17/** 18 * Default Bootstrap alert function that can be used on all GPCRdb pages 19 */ 20function showAlert(message, alerttype) { 21 // Alerttype: success, info, warning, danger 22 // See https://getbootstrap.com/docs/3.3/components/#alerts 23 $("#gpcrdb_alert_placeholder").append('<div id="gpcrdb_alert" class="alert alert-' + 24 alerttype + '"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>' + 25 message + "</div>"); 26 27 setTimeout(function() { 28 $("#gpcrdb_alert").remove(); 29 }, 4000); 30} 31 32/** 33 * This Array filter function can be used to deduplicate an Array 34 */ 35function onlyUnique(value, index, self) { 36 return self.indexOf(value) === index; 37} 38 39/** 40 * This function exports a list in a separated fashion to clipboard. 41 */ 42function copyListToClipboard(selected, delimiter = " ") { 43 if (selected.length > 0) { 44 // Deduplicate and sort list 45 selected = selected.filter(onlyUnique).sort(); 46 47 // Place values in textbox and copy to clipboard 48 var copybox = $('<input type="text">'); 49 $(document.body).append(copybox); 50 copybox.val(selected.join(delimiter)); 51 copybox.select(); 52 copybox[0].setSelectionRange(0, 99999); 53 document.execCommand("copy"); 54 showAlert("The selection has been copied to your clipboard.", "info"); 55 copybox.remove(); 56 } else { 57 showAlert("There is no selection to copy to clipboard.", "warning"); 58 } 59} 60 61/** 62 * This helper function can create a range of identical YADCF filters with a single call 63 * 64 * Arg list: createYADCFfilters(start_column, num_cols, filter_type, select_type*, filter_default_label*, filter_reset_button_text*, filter_match_mode*, column_data_type*, width*, html5_data*, ignore_char*, html_data_type*, html5_data*, other*) 65 * Arguments: 66 * other: a javascript object with column parameters of Yet Another DataTables Column Filter - (yadcf) (jquery.dataTables.yadcf.js) 67 * The asterisk indicates an optional function argument 68 */ 69function createYADCFfilters(start_column, num_cols, filter_type, select_type = null, filter_default_label = "", filter_reset_button_text = false, filter_match_mode = null, column_data_type = null, width = null, html5_data = null, ignore_char = null, html_data_type = null, other = null) { 70 71 let filters = []; 72 for (let i = 0; i < num_cols; i++) { 73 let filter = { 74 "column_number": start_column + i, 75 filter_type, 76 filter_default_label, 77 filter_reset_button_text 78 }; 79 if (select_type !== null) { 80 filter["select_type"] = select_type; 81 } 82 if (filter_match_mode !== null) { 83 filter["filter_match_mode"] = filter_match_mode; 84 } 85 if (column_data_type !== null) { 86 filter["column_data_type"] = column_data_type; 87 } 88 if (width !== null) { 89 filter["select_type_options"] = { 90 width 91 }; 92 } 93 if (html5_data !== null) { 94 filter["html5_data"] = html5_data; 95 } 96 if (ignore_char !== null) { 97 filter["ignore_char"] = ignore_char; 98 } 99 if (html_data_type !== null) { 100 filter["html_data_type"] = html_data_type; 101 } 102 103 if (other !== null) { 104 $.each( other, function( key, value ) { 105 106 filter[key] = value; 107 }); 108 } 109 filters.push(filter); 110 } 111 112 return filters; 113} 114 115 116 117 118/** 119 * Exports a specified table to an Excel file. 120 * @param {string} tableId - The ID of the table element to be exported. 121 * @param {string} sheetName - The name to be given to the Excel sheet. 122 * @param {string} fileName - The name of the file to be created. 123 */ 124function GlobalTableToExcel(tableId, sheetName, fileName) { 125 // Get the table element by ID. 126 const tableElement = document.getElementById(tableId); 127 128 // If the table doesn't exist, log an error and exit the function. 129 if (!tableElement) { 130 console.error(`Table with ID "${tableId}" not found.`); 131 return; 132 } 133 134 // Create a new Excel workbook. 135 const wb = XLSX.utils.book_new(); 136 137 // Clean the table and prepare it for export. 138 const clonedTable = cleanTable(tableElement.cloneNode(true)); 139 const exportTable = prepareExportTable(clonedTable); 140 141 // Convert the prepared table to an Excel worksheet. 142 const ws_data = XLSX.utils.table_to_sheet(exportTable); 143 144 // Add the worksheet to the workbook and write it to a file.
145 XLSX.utils.book_append_sheet(wb, ws_data, sheetName); 146 XLSX.writeFile(wb, fileName, { bookSST: true }); 147} 148 149/** 150 * Cleans the table by removing unwanted elements, cleaning headers, and processing cells. 151 * @param {HTMLElement} table - The table to be cleaned. 152 * @return {HTMLElement} The cleaned table. 153 */ 154function cleanTable(table) { 155 // Remove unwanted elements, clean headers, and process cells. 156 removeUnwantedElements(table); 157 cleanTableHeaders(table); 158 processTableCells(table); 159 160 // Return the cleaned table. 161 return table; 162} 163 164/** 165 * Removes specific unwanted elements from the table. 166 * @param {HTMLElement} table - The table to be cleaned. 167 */ 168function removeUnwantedElements(table) { 169 // Remove elements with class '.yadcf-filter-wrapper' and all buttons. 170 table.querySelectorAll('.yadcf-filter-wrapper').forEach(element => element.closest('tr').remove()); 171 table.querySelectorAll('button').forEach(button => button.remove()); 172} 173 174/** 175 * Cleans the headers of the table. 176 * @param {HTMLElement} table - The table with headers to be cleaned. 177 */ 178function cleanTableHeaders(table) { 179 // Process each header, remove 'span' elements and replace 'br' with space. 180 table.querySelectorAll('th').forEach(th => { 181 const clonedTh = th.cloneNode(true); 182 clonedTh.querySelectorAll('span').forEach(span => span.remove()); 183 clonedTh.querySelectorAll('br').forEach(br => br.replaceWith(' ')); 184 th.textContent = clonedTh.textContent; 185 }); 186} 187 188/** 189 * Processes each cell in the table. 190 * @param {HTMLElement} table - The table with cells to be processed. 191 */ 192function processTableCells(table) { 193 // Iterate over each cell to remove comment nodes and process links and line breaks. 194 table.querySelectorAll('td').forEach(td => { 195 Array.from(td.childNodes).forEach(node => { 196 if (node.nodeType === Node.COMMENT_NODE) { 197 node.remove(); 198 } 199 }); 200 handleImageLinks(td); 201 replaceLineBreaks(td); 202 replaceRefinedLinks(td); 203 }); 204} 205 206/** 207 * Converts image links in a table cell to text. 208 * @param {HTMLElement} td - The table cell to process. 209 */ 210function handleImageLinks(td) { 211 // If an image within a link is found, replace its content with the link's URL. 212 const img = td.querySelector('img'); 213 if (img && img.parentNode.tagName === 'A') { 214 td.textContent = img.parentNode.href; 215 } 216} 217 218/** 219 * Replaces line breaks in a table cell and wraps content in a paragraph tag. 220 * @param {HTMLElement} td - The table cell to process. 221 */ 222function replaceLineBreaks(td) { 223 // Get specific HTML content, replace line breaks, and wrap in a paragraph tag. 224 const htmlContent = td.querySelector('a i.glyphicon.glyphicon-file.simple-popover.gpcrdb-link')?.getAttribute('data-content'); 225 if (htmlContent) { 226 let newTextContent = htmlContent.replace(/<br>/g, "_X_").replace(/<[^>]*>/g, '').replace(/_X_/g, '<br>' ); 227 td.innerHTML = `<p>${newTextContent}</p>`; 228 } 229} 230 231/** 232 * Converts refined links in a table cell to plain text. 233 * @param {HTMLElement} td - The table cell to process. 234 */ 235function replaceRefinedLinks(td) { 236 // Replace the text of certain links with their URLs. 237 td.querySelectorAll('a').forEach(a => { 238 if (a.textContent.endsWith('_refined')) { 239 a.textContent = a.href; 240 } 241 }); 242} 243 244/** 245 * Prepares the table for export, selecting specific rows or the entire table. 246 * @param {HTMLElement} clonedTable - The cloned table to be prepared for export. 247 * @return {HTMLElement} The table prepared for export. 248 */ 249function prepareExportTable(clonedTable) { 250 // Create a new table with selected rows or return the whole table. 251 const selectedRows = clonedTable.querySelectorAll('tr.alt_selected'); 252 if (selectedRows.length > 0) { 253 const exportTable = document.createElement('table'); 254 exportTable.appendChild(clonedTable.querySelector('thead').cloneNode(true)); 255 selectedRows.forEach(row => exportTable.appendChild(row.cloneNode(true))); 256 return exportTable; 257 } else { 258 return clonedTable; 259 } 260}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.