1// ExportList global.js 2 3(function () { 4 var extName = 'ExportLists'; 5 6 Jsw.namespace('PleskExt.' + extName); 7 var ext = PleskExt[extName]; 8 9 10 function escapeRegExp(str) { 11 return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"); 12 } 13 14 function replaceAll(str, find, replace) { 15 return str.replace(new RegExp(escapeRegExp(find), 'g'), replace); 16 } 17 18 function lmsg(message, data) { 19 var locale = ext.Config.locale || {}; 20 message = locale[message] || message || ''; 21 data = data || {}; 22 for (var key in data) { 23 if (data.hasOwnProperty(key)) { 24 message = replaceAll(message, '%%' + key + '%%', data[key]); 25 } 26 } 27 28 return message; 29 } 30 31 function displayWarning(message) { 32 Jsw.addStatusMessage('warning', message, { 33 title: lmsg('exportToCsv'), 34 closable: true, 35 onClose: function () { 36 this.up('.msg-box').remove(); 37 } 38 }); 39 } 40 41 function addCvsExportButton(parentElement) { 42 new Jsw.SmallButton({ 43 renderTo: parentElement, 44 renderMode: 'top', 45 cls: 's-btn sb-csv-export btn-icon-only', 46 title: lmsg('exportToCsv'), 47 description: lmsg('exportToCsvDescription'), 48 href: ext.Config.link, 49 handler: exportListToCsv 50 }); 51 } 52 53 var listElementSelector = 'div:has(> div > div.list)'; 54 55 ext.init = function() { 56 function addCsvExportButtons(list) { 57 list._componentElement.select('div.paging .paging-view').forEach(addCvsExportButton); 58 } 59 60 var listElements = $$(listElementSelector); 61 listElements.forEach(function (listElement) { 62 var listComponent = Jsw.getComponent(listElement.id); 63 if (listComponent) { 64 addCsvExportButtons(listComponent); 65 66 var oldRedrawHandler = listComponent._onRedraw; 67 listComponent._onRedraw = function () { 68 if (oldRedrawHandler) { 69 oldRedrawHandler.apply(this, Array.prototype.slice.call(arguments)); 70 } 71 addCsvExportButtons(listComponent); 72 } 73 } 74 }); 75 }; 76 77 function getUpDownElement(element, upSelector, downSelector) { 78 var sucessorElement; 79 80 var ancestorElement = element.up(upSelector); 81 if (ancestorElement) { 82 sucessorElement = ancestorElement.down(downSelector); 83 } 84 85 return sucessorElement; 86 } 87 88 function getElementText(element) { 89 var rejectedElementClasses = [ 90 'r-visible', 91 'hint', 92 'hint-info', 93 'tooltipData' 94 ]; 95 var treeWalker = document.createTreeWalker(element, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT, { 96 acceptNode: function (node) { 97 var result = NodeFilter.FILTER_REJECT; 98 99 switch(node.nodeType){ 100 case Node.ELEMENT_NODE: 101 result = rejectedElementClasses.some(node.hasClassName.bind(node)) ? 102 NodeFilter.FILTER_REJECT : 103 NodeFilter.FILTER_ACCEPT; 104 break; 105 106 case Node.TEXT_NODE: 107 result = NodeFilter.FILTER_ACCEPT; 108 break; 109 110 default: 111 result = NodeFilter.FILTER_REJECT; 112 } 113 114 return result; 115 } 116 }, false); 117 118 var textData = []; 119 while(treeWalker.nextNode()) { 120 var node = treeWalker.currentNode; 121 122 switch(node.nodeType){ 123 case Node.ELEMENT_NODE: 124 switch (node.nodeName.toLowerCase()) { 125 case 'br': 126 textData.push('\n'); 127 break; 128 129 case 'img': 130 var text = 131 (node.readAttribute('alt') || '').trim() || 132 (node.readAttribute('title') || '').trim(); 133 if (text) { 134 textData.push(text); 135 } 136 break; 137 138 default: 139 break; 140 } 141 break; 142 143 case Node.TEXT_NODE: 144 textData.push(node.nodeValue); 145 break; 146 147 default: 148 break; 149 } 150 } 151 152 var result = textData.join('') 153 .replace(/\u00A0/g, ' ') // non-breaking space 154 .replace(/[\u200B\u00AD]/g, '') // zero-width space, soft hyphen 155 ; 156 157 return result; 158 } 159 160 function getRowData(tableDataElement, selector) { 161 var result = []; 162 while (tableDataElement) { 163 result.push(getElementText(tableDataElement)); 164 tableDataElement = tableDataElement.next(selector); 165 } 166 167 return result; 168 } 169 170 function getTableHeaders(tableElement) { 171 return getRowData(tableElement.down('thead > tr > th'), 'th'); 172 } 173 174 function getTableData(tableElement, selected) { 175 var result = []; 176 var rowFilter = selected ? 'tr.selected' : 'tr'; 177 var trElement = tableElement.down('tbody > ' + rowFilter); 178 while (trElement) { 179 result.push(getRowData(trElement.down('td'), 'td')); 180 trElement = trElement.next(rowFilter); 181 } 182 183 return result; 184 } 185 186 function indexFilter(data, index) { 187 return this[index]; 188 } 189 190 function getHeadingName() { 191 var headings = $$('#page .heading-area h2'); 192 193 return (headings.length > 0) ? getElementText(headings[0]).trim() : null; 194 } 195 196 function getActiveTabNames(element) { 197 var tabNames = []; 198 199 var prevTabElement = null; 200 var tabedElement; 201 while (tabedElement = (element.up('div.tabed') || element.up('div.b-content')) ) { 202 var activeTabElement = tabedElement.down('div.tabs-area ul > li.active'); 203 if (activeTabElement && activeTabElement !== prevTabElement) { 204 tabNames.push(getElementText(activeTabElement).trim()); 205 prevTabElement = activeTabElement; 206 } 207 element = tabedElement; 208 } 209 210 return tabNames.reverse(); 211 } 212 213 function exportListToCsv(event) { 214 event.stop(); 215 216 var tableElement = getUpDownElement(this, listElementSelector, 'div.list > table'); 217 if (!tableElement) { 218 displayWarning(lmsg('unableToFetchData')); 219 220 return; 221 } 222 223 var headers = getTableHeaders(tableElement); 224 225 var headersIndexFilter = headers.map(function (header) { 226 return header.length > 0; 227 }); 228 229 var headersFiltered = headers.filter(indexFilter, headersIndexFilter); 230 if (headersFiltered.length === 0) { 231 displayWarning(lmsg('noContent')); 232 233 return; 234 } 235 236 var rows = getTableData(tableElement, true); 237 if (rows.length === 0) { 238 rows = getTableData(tableElement); 239 } 240 if (rows.length === 0) { 241 displayWarning(lmsg('noContent')); 242 243 return; 244 } 245 246 var rowsFiltered = rows.map(function (row) { 247 return row.filter(indexFilter, headersIndexFilter); 248 }); 249 250 var tabNames = getActiveTabNames(this); 251 tabNames.unshift(getHeadingName()); 252 253 var postData = { 254 exportHeaders: JSON.stringify(headersFiltered), 255 exportData: JSON.stringify(rowsFiltered), 256 exportDataTitles: tabNames 257 }; 258 259 Jsw.redirectPost(this.href, postData); 260 } 261})();
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.