1/* 2 * Copyright (C) 2025 chris vaughan 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 */ 18 19var ra; 20if (typeof (ra) === "undefined") { 21 ra = {}; 22} 23 24ra.paginatedTable = function (tag, userOptions = null) { 25 this.options = { 26 className: "paginatedList" 27 }; 28 this.defaultOptions = {pagination: { 29 "10 per page": 10, 30 "20 per page": 20, 31 "25 per page": 25, 32 "50 per page": 50, 33 "100 per page": 100, 34 "View all": 0 35 }, 36 itemsPerPage: 20 37 }; 38 this.cvListOptions = {...this.defaultOptions, ...userOptions}; 39 this.fields = []; 40 this.format = null; 41 this.defaultSort = []; 42 this.noColumns = 1; 43 var tags = [ 44 {name: 'home', parent: 'root', tag: 'div', attrs: {class: this.options.className}}, 45 {name: 'filtersDiv', parent: 'home', tag: 'div', attrs: {class: 'filter'}}, 46 {name: 'rapagination1', parent: 'home', tag: 'div', attrs: {class: 'pagination top'}}, 47 {name: 'items1', parent: 'rapagination1', tag: 'div'}, 48 {name: 'pagination1', parent: 'rapagination1', tag: 'div'}, 49 {name: 'itemsSelect1', parent: 'rapagination1', tag: 'div'}, 50 {name: 'table', parent: 'home', tag: 'table', attrs: {class: 'table'}}, 51 {name: 'thead', parent: 'table', tag: 'thead'}, 52 {name: 'tbody', parent: 'table', tag: 'tbody'}, 53 {name: 'blank', parent: 'home', tag: 'div'}, 54 {name: 'rapagination2', parent: 'home', tag: 'div', attrs: {class: 'pagination bottom'}}, 55 {name: 'items2', parent: 'rapagination2', tag: 'div'}, 56 {name: 'pagination2', parent: 'rapagination2', tag: 'div'}, 57 {name: 'itemsSelect2', parent: 'rapagination2', tag: 'div'} 58 ]; 59 60 this.elements = ra.html.generateTags(tag, tags); 61 62 this.list = new cvList(this.elements.tbody); 63 64 var pag = this.list.createPagination(this.cvListOptions); 65 pag.addPaginationDisplayText(this.elements.items1, 'Item {startItem} to {endItem} of {itemsNumber}'); 66 pag.addPaginationDisplayButton(this.elements.pagination1, 'paginationButtons'); 67 pag.addPaginationDisplayButton(this.elements.itemsSelect1, 'itemsPerPage'); 68 pag.addPaginationDisplayText(this.elements.items2, 'Item {startItem} to {endItem} of {itemsNumber}'); 69 pag.addPaginationDisplayButton(this.elements.pagination2, 'paginationButtons'); 70 pag.addPaginationDisplayButton(this.elements.itemsSelect2, 'itemsPerPage'); 71 var self = this; 72 this.elements.tbody.addEventListener("cvList-after-display", function (e) { 73 self._hideBlankColumns(self.elements.table); 74 }); 75 this.elements.tbody.addEventListener('cvList-reportPagination', function (e) { 76 let ev = new Event("reportPagination"); 77 ev.cvList = e.cvList; 78 tag.dispatchEvent(ev); 79 }); 80 81 this._createFields = function (format) { 82 format.forEach(item => { 83 if ('field' in item) { 84 this.fields[item.title] = this.list.createField(item.title, item.field.type); 85 } 86 }); 87 }; 88 this._createFilters = function (format) { 89 format.forEach(item => { 90 if ('field' in item) { 91 var field = item.field; 92 if (field.filter) { 93 this.fields[item.title].setFilter(this.elements.filtersDiv); 94 } 95 } 96 }); 97 }; 98// var format = [ { 99// "title": "Running No", 100// "options": { 101// "align": "right" 102// "view": "notTablet" or "notMobile" 103// "style": {"min-width":"60px",...} 104// }, 105// "field": { 106// "type": "number","text","date" 107// "filter": false, 108// "sort": true, 109// "defaultSort": 'Asc' or 'Desc' 110// }, 111// "ignore": true If set then that column is not displayed 112// view: 'notTablet' or 'notMobile' 113// }, {...} 114// ]; 115 this.tableHeading = function (format) { 116 this.format = format; 117 this._createFields(format); 118 this._createFilters(format); 119 var row = document.createElement("tr"); 120 this.noColumns = 0; 121 format.forEach(item => {
122 if ('ignore' in item) { 123 if (item.ignore) { 124 return; 125 } 126 } 127 this.noColumns += 1; 128 var th = document.createElement("th"); 129 th.innerText = item.title; 130 row.appendChild(th); 131 if ('options' in item) { 132 if ('align' in item.options) { 133 th.classList.add(item.options.align); 134 } 135 if ('view' in item.options) { 136 th.classList.add(item.options.view); 137 } 138 if ('style' in item.options) { 139 var items = item.options.style; 140 for (let item in items) { 141 th.style.setProperty(item, items[item]); 142 } 143 } 144 } 145 if ('field' in item) { 146 if (item.field.sort) { 147 var field = this.fields[item.title]; 148 field.addSortArrows(th); 149 if (item.field.defaultSort) { 150 var item = {field: field, direction: item.field.defaultSort}; 151 this.defaultSort.push(item); 152 } 153 } 154 } 155 } 156 ); 157 this.elements.thead.appendChild(row); 158 }; 159 this.tableRowStart = function () { 160 this.row = document.createElement("tr"); 161 return this.row; 162 }; 163 this.tableRowItem = function (value, item = null, sortValue = null) { 164 if (item !== null) { 165 if ('ignore' in item) { 166 if (item.ignore) { 167 return null; 168 } 169 } 170 } 171 var td = document.createElement("td"); 172 ra.html.setTag(td, value); 173 this.row.appendChild(td); 174 if (item !== null) { 175 if ('field' in item) { 176 var field = this.fields[item.title]; 177 field.setValue(td, value); 178 if (sortValue !== null) { 179 field.setSortValue(td, sortValue); 180 } 181 } 182 if ('options' in item) { 183 var options = item.options; 184 if ('align' in options) { 185 td.classList.add(options.align); 186 } 187 if ('view' in item.options) { 188 td.classList.add(item.options.view); 189 } 190 } 191 } 192 return td; 193 }; 194 this.tableRowEnd = function (extraItem = null, cssClass = '') { 195 if (extraItem !== null) { 196 var nonPaginatedItem = document.createElement('tr'); 197 if (cssClass !== '') { 198 nonPaginatedItem.setAttribute('class', cssClass); 199 } 200 var td = document.createElement('td'); 201 td.setAttribute('colspan', this.noColumns); 202 nonPaginatedItem.appendChild(td); 203 td.appendChild(extraItem); 204 this.list.addItem(this.row, nonPaginatedItem); 205 } else { 206 this.list.addItem(this.row); 207 } 208 this.row = null; 209 }; 210 this.tableEnd = function () { 211 this.list.display(); 212 if (this.list.getNumberItems() < 20) { 213 this.elements.rapagination1.style.display = 'none'; 214 this.elements.rapagination2.style.display = 'none'; 215 } 216 this.defaultSort.forEach(item => { 217 switch (item.direction) { 218 case 'Asc': 219 item.field.sort(1); 220 break; 221 case 'Desc': 222 item.field.sort(-1); 223 break; 224 default: 225 alert('order error'); 226 } 227 }); 228 }; 229 this.sort = function (param, order) { 230 var field = this.fields[param]; 231 if (field) { 232 switch (order) { 233 case 'Asc': 234 field.sort(1); 235 break; 236 case 'Desc': 237 field.sort(-1); 238 break; 239 default: 240 alert('order error'); 241 } 242 } 243 }; 244 this.getPrintAll = function () { 245 var div = document.createElement('div'); 246 div.classList.add(this.options.className); 247 var table = document.createElement('table'); 248 div.appendChild(table); 249 table.appendChild(this.elements.thead.cloneNode(true)); 250 var tbody = document.createElement('tbody'); 251 table.appendChild(tbody); 252 this.list.appendPrintItems(tbody); 253 this.resetColumnDisplay(div); 254 this._hideBlankColumns(table); 255 return div; 256 }; 257 this._hideBlankColumns = function (table) { 258 var cols = []; 259 var thead = table.childNodes[0]; 260 var tbody = table.childNodes[1]; 261 var nodeList = thead.childNodes[0].childNodes; 262 for (let i = 0; i < nodeList.length; i++) { 263 cols.push(i); 264 } 265 var trs = tbody.childNodes; 266 var len = cols.length; 267 for (let j = 0; j < len; j++) { 268 var col = len - j - 1; 269 for (let i = 0; i < trs.length; i++) { 270 var tr = trs[i]; 271 var td = tr.childNodes[col]; 272 273 if (typeof (td) !== "undefined") { 274 var value = td.innerHTML; 275 if (value !== '') { 276 cols.splice(col, 1); 277 break; 278 } 279 } 280 } 281 } 282 283 this.resetColumnDisplay(this.elements.table); 284 this._removeColumns(cols); 285 }; 286 this.resetColumnDisplay = function (tag) { 287 var elements = tag.getElementsByClassName('paginationRemoveCol'); 288 // elements is a live list! 289 for (let i = elements.length - 1; i >= 0; i--) { 290 elements[i].classList.remove('paginationRemoveCol'); 291 } 292 this.elements.blank.innerHTML = ''; 293 }; 294 this._removeColumns = function (cols) { 295 var nodeList = this.elements.thead.childNodes[0].childNodes; 296 var colNames = []; 297 for (let i = 0; i < cols.length; i++) { 298 var col = cols[i]; 299 nodeList[col].classList.add('paginationRemoveCol'); 300 colNames.push(this.format[col].title); 301 } 302 if (colNames.length > 0) { 303 this.elements.blank.innerHTML = "Blank columns not displayed: " + colNames.join(); 304 } 305 var trs = this.elements.tbody.childNodes; 306 for (let j = 0; j < trs.length; j++) { 307 var tr = trs[j]; 308 var tds = tr.childNodes; 309 for (let i = 0; i < cols.length; i++) { 310 var col = cols[i]; 311 tds[col].classList.add('paginationRemoveCol'); 312 } 313 } 314 }; 315}; 316ra.paginatedList = function (tag, userOptions = null) { 317 this.options = { 318 className: "paginatedList" 319 }; 320 this.defaultOptions = {pagination: { 321 "10 per page": 10, 322 "20 per page": 20, 323 "25 per page": 25, 324 "50 per page": 50, 325 "100 per page": 100, 326 "View all": 0 327 }, 328 itemsPerPage: 20 329 }; 330 this.cvListOptions = {...this.defaultOptions, ...userOptions}; 331 this.fields = []; 332 var tags = [ 333 {name: 'home', parent: 'root', tag: 'div', attrs: {class: this.options.className}}, 334 {name: 'filtersDiv', parent: 'home', tag: 'div', attrs: {class: 'filter'}}, 335 {name: 'rapagination1', parent: 'home', tag: 'div', attrs: {class: 'pagination top'}}, 336 {name: 'items1', parent: 'rapagination1', tag: 'div'}, 337 {name: 'pagination1', parent: 'rapagination1', tag: 'div'}, 338 {name: 'itemsSelect1', parent: 'rapagination1', tag: 'div'}, 339 {name: 'content', parent: 'home', tag: 'div'}, 340 {name: 'rapagination2', parent: 'home', tag: 'div', attrs: {class: 'pagination bottom'}}, 341 {name: 'items2', parent: 'rapagination2', tag: 'div'}, 342 {name: 'pagination2', parent: 'rapagination2', tag: 'div'}, 343 {name: 'itemsSelect2', parent: 'rapagination2', tag: 'div'} 344 ]; 345 346 this.elements = ra.html.generateTags(tag, tags); 347 348 this.list = new cvList(this.elements.content); 349 var pag = this.list.createPagination(this.cvListOptions); 350 pag.addPaginationDisplayText(this.elements.items1, 'Items {startItem} to {endItem} of {itemsNumber}'); 351 pag.addPaginationDisplayButton(this.elements.pagination1, 'paginationButtons'); 352 pag.addPaginationDisplayButton(this.elements.itemsSelect1, 'itemsPerPage'); 353 pag.addPaginationDisplayText(this.elements.items2, 'Items {startItem} to {endItem} of {itemsNumber}'); 354 pag.addPaginationDisplayButton(this.elements.pagination2, 'paginationButtons'); 355 pag.addPaginationDisplayButton(this.elements.itemsSelect2, 'itemsPerPage'); 356 this.elements.content.addEventListener('cvList-reportPagination', function (e) { 357 let ev = new Event("reportPagination"); 358 ev.cvList = e.cvList; 359 tag.dispatchEvent(ev); 360 }); 361 362 this.listItem = function (tag) { 363 this.list.addItem(tag); 364 }; 365 this.listEnd = function () { 366 this.list.display(); 367 if (this.list.getNumberItems() < 20) { 368 this.elements.rapagination1.style.display = 'none'; 369 this.elements.rapagination2.style.display = 'none'; 370 } 371 }; 372 this.getPrintAll = function () { 373 var div = document.createElement('div'); 374 div.classList.add(this.options.className); 375 this.list.appendPrintItems(div); 376 return div; 377 }; 378};
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.