1/* 2 * AKTable : Composant tableau pour Akuiteo 3 */ 4 5var AKTable = Backbone.View.extend({ 6 // Classe privée décrivant les colonnes 7 ColumnDescription : Backbone.Model.extend({ 8 property : '', 9 title : '', 10 visible : true, 11 sortable : true, 12 resizable : true, 13 initVisible : true, 14 size : -1, 15 htmlContent:null, 16 templateHtmlContent:null, 17 exportable : true 18 }), 19 20 /** 21 * Constructeur 22 */ 23 constructor : function(parentTable, rowTemplate, groupedRowTemplate) { 24 this._initVariables(); 25 this.$el = parentTable; 26 this.tableId = parentTable.attr('id'); 27 this.rowTemplate = rowTemplate.html().replace("<![CDATA[", "").replace("]]>", "").replace(/\n|\r|\t/gi,''); 28 29 if (groupedRowTemplate) { 30 this.groupedRowTemplate = groupedRowTemplate.html().replace("<![CDATA[", "").replace("]]>", "").replace(/\n|\r|\t/gi,''); 31 } else { 32 this.groupedRowTemplate = ""; 33 } 34 35 this.originalRowTemplate = this.rowTemplate; 36 this._loadParams(); 37 38 var parent = this; 39 this.selector = new AKMultiSelector(); 40 this.selector.init({ 41 title:keywords['aktable.selection.title'], 42 prefix:parentTable.attr('id') + "_param_", 43 okAction : parent._changeOrder, 44 defaultAction : parent._resetOrder, 45 parent:parent 46 }); 47 48 $(window).resize(function() { 49 parent._recreateSliders(); 50 }); 51 52 $(window).on('load', function() { 53 parent._recreateSliders(); 54 }); 55 56 this.$el.parent().on("scroll", function(event) { 57 parent._recreateSliders(); 58 }); 59 60 }, 61 62 /** 63 * Initialise les variables 64 */ 65 _initVariables : function() { 66 this.url = "", // URL indiquant le fournisseur de données 67 this.params = null; // Paramètres supplémentaires dans l'URL 68 this.page = 1; // Page courante 69 this.rownum = -1; // Nombre de lignes par page (-1=auto) 70 this.autoRownum = -1; // Nombre de lignes affichées 71 this.currentSort = ""; // Tri par défaut 72 this.numberOfPages = 1; // Nombre total de pages 73 this.numberOfRecords = 0; // Nombre total d'enregistrements 74 this.groupByProperties = null; // Propriétés de regroupement 75 this.selectionType = "none"; // Type de sélection (none, single, select) 76 this.data = null; // Données 77 this.rowTemplate = null; // Template pour l'affichage des lignes 78 this.originalRowTemplate = null; // Template original pour l'affichage des lignes (utilisé dans la réorganisation) 79 this.groupedRowTemplate = null; // Template pour les lignes groupées 80 this.columns = new Array(); // Colonnes 81 this.originalColumns = new Array(); // Colonnes à l'initialisation du tableau, utile pour la réorganisation 82 this.rendered = false; 83 this.selector = null; 84 this.originalHeader = null; 85 this.tableId = null; 86 this.multipleTableSort = false; 87 this.hasFooter = true; 88 this.categoriesExpanded = []; 89 }, 90 91 /** 92 * (privée) Chargement des paramètres de la table 93 */ 94 _loadParams : function() { 95 if (!this.$el.attr('data-url')) { 96 jQuery.error('Attribut data-url non défini'); 97 } else { 98 this.url = this.$el.attr('data-url'); 99 } 100 101 if (this.$el.attr('data-rownum')) { 102 this.rownum = this.$el.attr('data-rownum'); 103 } 104 105 if (this.$el.attr('data-default-sort')) { 106 this.currentSort = this.$el.attr('data-default-sort'); 107 } 108 109 if (this.$el.attr('data-selection-type')) { 110 this.selectionType = this.$el.attr('data-selection-type'); 111 } 112 113 if (this.$el.attr('data-no-footer')) { 114 this.hasFooter = false; 115 } 116 117 if (this.$el.attr('data-class')) { 118 var cssClass = this.$el.attr('data-class'); 119 if (cssClass !== 'none') { 120 this.$el.addClass(cssClass); 121 } 122 } else { 123 this.$el.addClass('aktable'); 124 } 125 126 // Construit les descriptions de colonnes 127 var parent = this; 128 var realColumnIndex = 0; 129 this.$el.find("tr:first th").each(function(index) { 130 var cd = new parent.ColumnDescription(); 131 var currentTH = $(this); 132 133 cd.title = currentTH.html(); 134 135 if (!currentTH.attr('data-property')) { 136 jQuery.error('Attribut data-property non défini pour la colonne #' + index); 137 } else { 138 cd.property = currentTH.attr('data-property'); 139 } 140 141 if (currentTH.attr('data-visible')) {
142 if (currentTH.attr('data-visible') === "false") { 143 // On supprime la colonne 144 currentTH.remove(); 145 parent.rowTemplate = parent._removeColumn(parent.rowTemplate, realColumnIndex); 146 parent.originalRowTemplate = parent._removeColumn(parent.originalRowTemplate, realColumnIndex); 147 return; 148 } 149 } 150 151 if (currentTH.attr('data-sortable')) { 152 cd.sortable = currentTH.attr('data-sortable') === "true"; 153 } 154 155 if (currentTH.attr('data-resizable')) { 156 cd.resizable = currentTH.attr('data-resizable') === "true"; 157 } 158 159 if (currentTH.attr('data-defaut-visible')) { 160 cd.visible = currentTH.attr('data-defaut-visible') === "true"; 161 } 162 163 if (currentTH.attr('data-exportable')) { 164 cd.exportable = currentTH.attr('data-exportable') === "true"; 165 } 166 167 parent.columns.push(cd); 168 realColumnIndex++; 169 }); 170 171 this.originalColumns = this.columns.slice(0); // C'est un "clone" du tableau 172 this.originalHeader = this.$el.find('thead tr:first')[0].outerHTML; 173 }, 174 175 /** 176 * (privée) recréation des sliders 177 */ 178 _recreateSliders : function() { 179 if (!this.hasFooter) { 180 return; 181 } 182 // On détruit les sliders, et on les re-créé 183 var _self = this; 184 $('.aktable-resize-drag-handle').remove(); 185 $.each(_self.columns,function(index,column) { 186 _self._initResizablePropertyForColumn(index, column.resizable); 187 }); 188 189 // Ensuite on réinitialise la position des sliders 190 var table = this.$el; 191 var parentWidth = table.parent().width(); 192 var newSliderPosition = table.position().left; 193 table.find(' TR:first TH').each(function(index) { 194 var th = $(this); 195 newSliderPosition += th.outerWidth(); 196 if (newSliderPosition>parentWidth) { 197 $("#slider" + _self.tableId + "_id" + index).remove(); 198 return; 199 } 200 $("#slider" + _self.tableId + "_id" + index).css({ 201 left : newSliderPosition, 202 height : th.outerHeight() + 'px' 203 }); 204 }); 205 206 207 }, 208 209 /** 210 * (privée) Suppression d'une colonne 211 */ 212 _removeColumn:function (content, i) { 213 var beginIndex = content.indexOf('<tr'); 214 var endIndex = content.indexOf('<td'); 215 216 var trDescription = content.substring(beginIndex,endIndex); 217 var templateWithoutTR = content.substring(endIndex).replace(/<\/tr>/g,''); 218 219 // Extrait les balises TD 220 var regexp = /<td\b[^>]*>([\s\S]*?)<\/td>/gm; 221 var arrayOfTD = new Array(); 222 while(match = regexp.exec(templateWithoutTR)) { 223 arrayOfTD.push(match[0]); 224 } 225 226 // Supprime l'élément d'index i 227 arrayOfTD.splice(i,1); 228 229 return trDescription + arrayOfTD.join('') + '</tr>'; 230 }, 231 232 /** 233 * (privée) Création du séparateur pour le redimensionnement des colonnes 234 */ 235 _initResizablePropertyForColumn : function(i, resizable) { 236 var parent = this; 237 var table = parent.$el; 238 var separator = $('<div class="aktable-resize-drag-handle" id="slider'+ this.tableId + "_id" + i + '"></div>') 239 .insertBefore(table).data('myindex', i); 240 241 if (resizable) { 242 separator.css('cursor', 'col-resize'); 243 var oldPos; 244 separator.draggable({ 245 axis : "x", 246 start : function(event,ui) { 247 $(this).toggleClass("dragged"); 248 $(this).css({height : $('#' + parent.tableId).height()+ 'px'}); 249 oldPos = ui.position.left; 250 }, 251 stop : function(event, ui) { 252 $(this).toggleClass("dragged"); 253 var newPos = ui.position.left; 254 var index = $(this).data("myindex"); 255 parent._resetTableSizes(parent, newPos - oldPos, index); 256 } 257 }); 258 } else { 259 separator.css('cursor', 'auto'); 260 } 261 }, 262 263 264 /** 265 * (privée) Chargement des paramètres de la table 266 */ 267 _resetTableSizes : function(parent, change, columnIndex) { 268 var table = parent.$el; 269 var currentColumnWidth = $('#' + this.tableId + ' tr th').get(columnIndex).offsetWidth; 270 var newWidth = (currentColumnWidth + change) + 'px'; 271 272 var tableWidth = $(table).width(); 273 table.css('width',(tableWidth+change)+ 'px'); 274 275 $('#' + this.tableId + ' tr').each(function() { 276 $(this).find('td').eq(columnIndex).css('width', newWidth); 277 $(this).find('th').eq(columnIndex).css('width', newWidth); 278 }); 279 280 parent.columns[columnIndex].size = currentColumnWidth + change; 281 282 parent._recreateSliders(); 283 parent._storeInCookies(); 284 table.trigger('resize'); 285 }, 286 287 /** 288 * (privée) "Décore" l'entête du tableau (ajoute le tri sur clic et les indicateurs de tri) 289 */ 290 _decorateHeaders : function() { 291 if (this.rendered) { 292 return; 293 } 294 // Ajout d'un listener sur les colonnes triables 295 var parent = this; 296 this.$el.find(' TR:first TH').each(function(index) { 297 var column = parent.columns[index]; 298 if (column.sortable) { 299 var th = $(this); 300 th.addClass('aktable-sortable'); 301 th.click(function() {
302 var isAsc = false, isDesc = false, sortIndex = -1; 303 304 if (parent.multipleTableSort) { 305 for ( var i = 1; i < 5; i++) { 306 // Cherche dans les enfants si ce n'est pas déjà trié ! 307 if (th.children('.aktable-asc' + i).length>0) { 308 th.children('.aktable-asc' + i).remove(); 309 sortIndex = i; 310 isAsc = true; 311 break; 312 } 313 if (th.children('.aktable-desc' + i).length>0) { 314 th.children('.aktable-desc' + i).remove(); 315 isDesc = true; 316 break; 317 } 318 } 319 } else { 320 if (th.children('.aktable-asc' ).length>0) { 321 th.children('.aktable-asc' ).remove(); 322 sortIndex = 0; 323 isAsc = true; 324 } 325 if (th.children('.aktable-desc').length>0) { 326 th.children('.aktable-desc').remove(); 327 isDesc = true; 328 } 329 } 330 331 332 if (isAsc) { 333 // Descendant 334 if (parent.multipleTableSort) { 335 $(th).append('<span class="aktable-desc'+ sortIndex +'"></span>'); 336 } else { 337 $(th).append('<span class="aktable-desc"></span>'); 338 } 339 parent._changeSort(column.property, 'desc'); 340 } else if (isDesc) { 341 // Vide 342 parent._changeSort(column.property, ''); 343 } else { 344 // Ascendant 345 var maxSortIndex = parent.currentSort == ''?1:(parent.currentSort.split(';').length + 1); 346 347 if (parent.multipleTableSort && maxSortIndex == 5) { 348 return; 349 } 350 351 if (!parent.multipleTableSort) { 352 maxSortIndex = ''; 353 parent.currentSort = ''; 354 } 355 356 $(th).append('<span class="aktable-asc'+ maxSortIndex +'"></span>'); 357 parent._changeSort(column.property, 'asc'); 358 } 359 parent.goToPage(1); 360 }); 361 } 362 363 }); 364 365 this._addSortIndicator(); 366 }, 367 368 /** 369 * (privée) Change les colonnes triées 370 * @param prop propriété 371 * @param direction (asc ou desc) 372 */ 373 _changeSort : function(prop, direction) { 374 375 var elements = this.currentSort.split(';'); 376 var output = []; 377 var found = false; 378 // Reconstruit la chaine currentSort 379 for ( var i = 0; i < elements.length; i++) { 380 var temp = elements[i].split(','); 381 var currentProp = temp[0]; 382 if (direction == '') { 383 if (currentProp != prop) { 384 output.push(elements[i]); 385 } 386 } else { 387 if (currentProp == prop) { 388 output.push(currentProp + ',' + direction); 389 found = true; 390 } else if (elements[i] != '') { 391 output.push(elements[i]); 392 } 393 } 394 } 395 396 if (direction != '' && !found) { 397 output.push(prop + ',' + direction); 398 } 399 400 this.currentSort = output.join(';'); 401 402 // Redessine les indicateurs de tri 403 this._addSortIndicator(); 404 }, 405 406 /** 407 * (privée) Ajoute un indicateur de tri 408 */ 409 _addSortIndicator:function() { 410 if (this.currentSort == '') { 411 return; 412 } 413 414 var elements = this.currentSort.split(';'); 415 416 // Efface les anciens indicateurs de tri 417 for ( var colIndex = 0; colIndex < this.columns.length; colIndex++) { 418 var currentCol = this.columns[colIndex]; 419 var th = this.$el.find(' TR:first TH')[colIndex]; 420 if (this.multipleTableSort) { 421 for (var j=1;j<5;j++) { 422 $(th).children('.aktable-asc' + j).remove(); 423 $(th).children('.aktable-desc' + j).remove(); 424 } 425 } else { 426 $(th).children('.aktable-asc').remove(); 427 $(th).children('.aktable-desc').remove(); 428 } 429 } 430 431 // Et "dessine" les nouveaux 432 for ( var i = 0; i < elements.length; i++) { 433 var temp = elements[i].split(','); 434 var currentProp = temp[0], currentDirection = temp[1]; 435 this.$el.find(' TR:first TH').each(function(index) { 436 var currentTH = $(this); 437 if (currentTH.attr('data-property') == currentProp) { 438 if (this.multipleTableSort) { 439 if (currentDirection == 'asc') { 440 currentTH.append('<span class="aktable-asc'+ (i+1) +'"></span>'); 441 } else { 442 currentTH.append('<span class="aktable-desc'+ (i+1) +'"></span>'); 443 } 444 } else { 445 if (currentDirection == 'asc') { 446 currentTH.append('<span class="aktable-asc"></span>'); 447 } else { 448 currentTH.append('<span class="aktable-desc"></span>'); 449 } 450 } 451 } 452 }); 453 } 454 }, 455 456 /** 457 * (privée) Génération du contenu 458 */ 459 _generateContents : function() { 460 var tbody = this.$el.find('tbody'); 461 if (tbody.length != 0) { 462 tbody.remove(); 463 } 464 465 this.$el.append("<tbody></tbody>"); 466 467 var content = ""; 468 if (this.data != null && this.data.length > 0) { 469 for ( var i = 0; i < this.data.length; i++) { 470 content += this._generateRow(this.data[i]); 471 } 472 } else { 473 // Aucune donnée trouvée 474 content += '<tr><td colspan="'+ this.columns.length +'" style="text-align:center">'; 475 content += '<br/><br/><br/><br/><br/>'; 476 content += '<b>
476' + keywords['aktable.nodatafound'] +'</b>'; 477 content += '<br/><br/><br/><br/><br/>'; 478 content += '</td></tr>'; 479 } 480 481 this.$el.find('tbody').append(content); 482 if (this.data != null && this.data.length > 0) { 483 for ( var i = 0; i < this.data.length; i++) { 484 this._decorateExpandCollapseIcon(this.data[i]); 485 } 486 487 if (this.rownum == -1) { 488 // Tronque 489 if (this.autoRownum > -1 && this.page==this.numberOfPages) { 490 // On est sur la dernière page 491 return; 492 } 493 var wholeHeight = $(window).height() - 70; // 70=marge pour le pied de tableau 494 var rows = this.$el.find("tr:gt(0)"); 495 var parent = this; 496 this.autoRownum = -1; 497 rows.each(function (index,element) { 498 var e = $(element); 499 var yPosition = getScreenCordinates(e).y; 500 if (yPosition + e.height() > wholeHeight) { 501 e.remove(); 502 } 503 }); 504 505 this.autoRownum = this.$el.find("tr:gt(0)").length; 506 } 507 508 } 509 510 }, 511 512 /** 513 * (privée) Génère une ligne du tableau 514 * @param current donnée affichée 515 */ 516 _generateRow:function(current) { 517 if (current.type=='BEAN') { 518 var compiled = _.template(this.rowTemplate, current.data); 519 return this._addIdentifier(compiled, current, false); 520 } 521 522 // Catégorie 523 var content = ""; 524 var parent = this; 525 526 // Une ligne de groupe 527 var compiled = _.template(this.groupedRowTemplate, current); 528 content += this._addIdentifier(compiled, current, true); 529 530 // Les enfants... 531 $.each(current.children, function(key, child) { 532 content += parent._generateRow(child); 533 }); 534 535 return content; 536 }, 537 538 /** 539 * (privée) Ajoute un identifiant à une ligne 540 * @param html portion de code à décorer 541 * @param row ligne courante 542 * @param category si true, on a affaire à une catégorie 543 */ 544 _addIdentifier:function(html, row, category) { 545 // On rajoute un identifiant 546 var id = row.id; 547 var wholeLine = $('<table>' + html + '</table>'); 548 wholeLine.find(' TR:first').attr('id',this.tableId + (category?"_cat_":"_row_") + id); 549 if (category) { 550 var iconId = this.tableId + "_cat_" + id + "_icon"; 551 var sClass = row.expanded ? 'aktable-collapse' : 'aktable-expand'; 552 wholeLine.find(' TR:first TD:first'). 553 prepend('<span class="' + sClass + '" style="width:9px;padding-left:10px" id="'+ iconId +'"> </span>'); 554 } else { 555 if (!row.expanded) { 556 wholeLine.find(' TR:first').hide() 557 } 558 } 559 return wholeLine.html().replace(/<tbody>|<\/tbody>/gi,''); 560 }, 561 562 /** 563 * Décore l'icône +/- d'une catégorie 564 * @param current donnée 565 */ 566 _decorateExpandCollapseIcon:function(current) { 567 if (current.type=='BEAN') { 568 return; 569 } 570 var parent = this; 571 var id = this.tableId + "_cat_" + current.id + "_icon"; 572 var button = $('span[id="'+id+'"]'); // On utilise cette syntaxe 573 if (button.length != 0) { 574 button.parent().on('click', function() { 575 if (button.hasClass('aktable-collapse')) { 576 // Collapse 577 button.removeClass('aktable-collapse'); 578 button.addClass('aktable-expand'); 579 parent._changeVisibility(parent, current,false,false); 580 parent._addOrRemoveCategoryExpanded(current.id, false); 581 } else { 582 // Expand 583 button.removeClass('aktable-expand'); 584 button.addClass('aktable-collapse'); 585 parent._changeVisibility(parent, current,true,false); 586 parent._addOrRemoveCategoryExpanded(current.id, true); 587 } 588 parent._recreateSliders(); 589 }); 590 } 591 592 593 // Les enfants... 594 $.each(current.children, function(key, child) { 595 parent._decorateExpandCollapseIcon(child); 596 }); 597 }, 598 599 _addOrRemoveCategoryExpanded: function(categoryId, addCategory) { 600 if (addCategory) { 601 this.categoriesExpanded.push(categoryId); 602 } else { 603 var idx = this.categoriesExpanded.indexOf(categoryId); 604 if (idx !== -1) { 605 this.categoriesExpanded.splice(idx, 1); 606 } 607 } 608 }, 609 610 /** 611 * Change la visibilité d'une catégorie et de ses enfants 612 * @param _self objet aktable 613 * @param current donnée courante 614 * @param show si true, on affiche les données, si false on les cache 615 * @param includeCurrentCategory est-ce qu'on affiche/cache la catégorie ? Dans tous les cas, on 616 */ 617 _changeVisibility:function(_self, current, show, includeCurrentCategory) { 618 if (current.type=='CATEGORY') { 619 if (includeCurrentCategory) { 620 var id = _self.tableId + "_cat_" + current.id; 621 if (show) { 622 $('tr[id="'+id+'"]').show(); 623 } else { 624 $('tr[id="'+id+'"]').hide(); 625 } 626 } 627 628 //var button = $('span[id="'+id+'_icon"]'); 629 if (!show || !includeCurrentCategory) { 630 $.each(current.children, function(key, child) { 631 _self._changeVisibility(_self,child,show,true); 632 }); 633 } 634 635 } else { 636 // Bean 637 var id = _self.tableId + "_row_" + current.id; 638 if (show) { 639 $('tr[id="'+id+'"]').show(); 640 } else { 641 $('tr[id="'+id+'"]').hide(); 642 } 643 } 644 }, 645 646 /** 647 * (privée) Génération du pied du tableau 648 */ 649 _addFooter : function() { 650 if (this.rendered) { 651 return; 652 } 653 var parent = this; 654 655 var content = ""; 656 content += '<div id="'+ this.tableId + '_loading" class="aktable-loading-area"></div>'; 657 658 if (!this.hasFooter) { 659 this.$el.after(content); 660 return; 661 } 662 663 content += '<div id="'+ this.tableId + '_footer" style="border-top:1px solid #DDDDDD;padding:5px;background-color: #E5E5E5;height:45px">'; 664 content += ' <table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>'; 665 content += ' <td style="width:130px"><div class="btn-group">'; 666 if (window.AKTableCanDisplayExport && window.AKTableCanDisplayExport === true) { 667 content += ' <button class="btn btn-static" id="' + this.tableId + '_footer_excel_all" title="'+ keywords['aktable.export.all.lines']+'"><i class="aktable-excel"></i></button>'; 668 } 669 content += ' <button class="btn btn-static" id="' + this.tableId + '_footer_config" title="'+ keywords['aktable.column.management']+'"><i class="icon-list-alt"></i></button>'; 670 content += ' <button class="btn btn-static" id="' + this.tableId + '_footer_reload" title="'+ keywords['aktable.reload']+'"><i class="icon-refresh"></i></button>'; 671 content += ' </div></td>'; 672 content += ' <td align="center"><div class="btn-group">'; 673 content += ' <button class="btn btn-static" id="' + this.tableId + '_footer_first" title="'+ keywords['aktable.first.page']+'"><i class="aktable-first"></i></button>'; 674 content += ' <button class="btn btn-static" id="' + this.tableId + '_footer_previous" title="'+ keywords['aktable.previous.page']+'"><i class="aktable-previous"></i></button>'; 675 content += ' <button class="btn btn-static" ><span id="' + this.tableId + '_footer_page"></span></button>'; 676 content += ' <button class="btn btn-static" id="' + this.tableId + '_footer_next" title="'+ keywords['aktable.next.page']+'"><i class="aktable-next"></i></button>'; 677 content += ' <button class="btn btn-static" id="' + this.tableId + '_footer_last" title="'+ keywords['aktable.last.page']+'"><i class="aktable-last"></i></button>'; 678 content += ' <div class="btn btn-static" ><select id="' + this.tableId + '_footer_combo" style="width:50px;height:17px;line-height:18px;margin:0;padding:0;font-size:9.5px">'; 679 680 $.each([-1,10,25,50,100,250,500],function(key,val) { 681 var selected = ''; 682 if (val == parent.rownum) { 683 selected = ' selected="selected"'; 684 } 685 686 var displayedValue = val==-1?"Auto":val; 687 content += '<option value="'+val+'"'+ selected +'>'+displayedValue+'</option>'; 688 }); 689 690 content += ' </select><span style="font-size:11px" id="' + this.tableId + '_footer_lblPerPage"></span>';
691 content += ' </div>'; 692 content += ' </div></td>'; 693 content += ' <td align="right" id="' + this.tableId + '_total"></td>'; 694 content += ' </tr></table>'; 695 content += '</div>'; 696 this.$el.after(content); 697 698 // Boutons export excel 699 $('#' + this.tableId + '_footer_excel_all').click(function() { 700 parent._exportExcel(true); 701 }); 702 703 // Bouton Config & Reload 704 $('#' + this.tableId + '_footer_config').click(function() { 705 var leftList = [], rightList = []; 706 for (var colIndex = 0; colIndex < parent.columns.length; colIndex++) { 707 var currentCol = parent.columns[colIndex]; 708 rightList.push({key:currentCol.property, value:currentCol.title}); 709 } 710 711 for (var originalColIndex = 0; originalColIndex < parent.originalColumns.length; originalColIndex++) { 712 var currentOriginalCol = parent.originalColumns[originalColIndex]; 713 if (currentOriginalCol.visible === false) { 714 leftList.push({key:currentOriginalCol.property, value:currentOriginalCol.title}); 715 } 716 } 717 718 parent.selector.open(leftList,rightList); 719 }); 720 $('#' + this.tableId + '_footer_reload').click(function() { 721 parent.loadData(); 722 }); 723 724 // Boutons first,previous,next,last 725 $('#' + this.tableId + '_footer_first').click(function() { 726 parent.goToPage(1); 727 }); 728 $('#' + this.tableId + '_footer_previous').click(function() { 729 parent.goToPage(parent.page - 1); 730 }); 731 $('#' + this.tableId + '_footer_next').click(function() { 732 parent.goToPage(parent.page + 1); 733 }); 734 $('#' + this.tableId + '_footer_last').click(function() { 735 parent.goToPage(parent.numberOfPages); 736 }); 737 738 // Combo 739 $('#' + this.tableId + '_footer_combo').change(function() { 740 parent.rownum = $('#' + parent.tableId+ '_footer_combo option:selected').val(); 741 if (parent.rownum==-1) { 742 $(window).scrollTop(0); 743 parent.autoRownum=-1; 744 } 745 parent._storeInCookies(); 746 parent.page = 1; 747 parent.loadData(); 748 }); 749 750 }, 751 752 /** 753 * (privée) rafraîchit le pied du tableau 754 */ 755 _refreshFooter : function() { 756 if (!this.hasFooter) { 757 return; 758 } 759 760 if (this.numberOfRecords == 0) { 761 $('#' + this.tableId + '_footer_excel_all').attr("disabled","disabled"); 762 $('#' + this.tableId + '_footer_first').attr("disabled","disabled"); 763 $('#' + this.tableId + '_footer_previous').attr("disabled","disabled"); 764 $('#' + this.tableId + '_footer_next').attr("disabled","disabled"); 765 $('#' + this.tableId + '_footer_last').attr("disabled","disabled"); 766 767 $('#' + this.tableId + '_footer_page').html(" "); 768 $('#' + this.tableId + '_total').text(keywords['aktable.nodata']); 769 return; 770 } 771 772 if (this.rownum == -1) { 773 // Recalcul du nombre de pages 774 if (this.autoRownum > 0) { 775 this.numberOfPages = Math.ceil(this.numberOfRecords / this.autoRownum); 776 } 777 } 778 779 $('#' + this.tableId + '_footer_excel_all').removeAttr("disabled"); 780 781 // Zone de navigation 782 $('#' + this.tableId + '_footer_page').text(this.page + " / " + this.numberOfPages); 783 784 if (this.page > 1) { 785 $('#' + this.tableId + '_footer_previous,#' + this.tableId + '_footer_first').removeAttr("disabled"); 786 } else { 787 $('#' + this.tableId + '_footer_previous,#' + this.tableId + '_footer_first').attr("disabled","disabled"); 788 } 789 790 if (this.page != this.numberOfPages) { 791 $('#' + this.tableId + '_footer_next,#' + this.tableId + '_footer_last').removeAttr("disabled"); 792 } else { 793 $('#' + this.tableId + '_footer_next,#' + this.tableId + '_footer_last').attr("disabled","disabled"); 794 } 795 796 // Libellé XXXX/page 797 $('#' + this.tableId + '_footer_lblPerPage').text(keywords[this.groupByProperties ? 'aktable.categories.per.page' : 'aktable.lines.per.page']); 798 799 // Section "1-10 sur XX" 800 var start = (this.page - 1) * (this.rownum==-1?this.autoRownum:this.rownum) + 1; 801 var end = Math.min((this.page) * (this.rownum==-1?this.autoRownum:this.rownum), this.numberOfRecords); 802 var total = start + " - " + end + " "+ keywords['aktable.on'] +" " + this.numberOfRecords; 803 $('#' + this.tableId + '_total').text(total); 804 }, 805 806 /** 807 * (privée) Export Excel 808 * @param exportAll si vrai, exporte toutes les données sinon exporte seulement la page en cours 809 */ 810 _exportExcel : function(exportAll) { 811 var exportedColumns = []; 812 813 for ( var i = 0; i < this.columns.length; i++) { 814 var currentCol = this.columns[i]; 815 if (currentCol.exportable) { 816 exportedColumns.push({ 817 property : currentCol.property, 818 visible : currentCol.visible, 819 position : currentCol.position, 820 title : currentCol.title 821 }); 822 } 823 } 824 825 if (exportAll) { 826 page = -1; 827 rowsPerPage = -1; 828 sort = ''; 829 } else { 830 page = this.page; 831 rowsPerPage = (this.rownum==-1?this.autoRownum:this.rownum); 832 sort = this.currentSort; 833 } 834 835 var jsonColumns = JSON.stringify(exportedColumns).replace(/'/g,"\\u0027"); // Remplace les quotes par le caractère unicode 836 var calledUrl = this.url + '?' ; 837 if (this.params != null && this.params.length != 0) { 838 calledUrl = calledUrl + $.param(this.params) + '&'; 839 } 840 calledUrl = calledUrl + 'exportExcel=true&ts='+ new Date().getTime(); // Pour empêcher les problèmes sous IE 841 842 // On créé un faux formulaire que l'on va soumettre 843 var content = '<input type="text" name="page" value="' + page + '" />'; 844 content += '<input type="text" name="rowsPerPage" value="' + rowsPerPage + '" />'; 845 content += '<input type="text" name="sort" value="' + sort + '" />'; 846 content += '<input type="text" name="jsonColumns" value=\'' + jsonColumns + '\'/>'; 847 848 var token = $("meta[name='_csrf']").attr("content"); 849 content += '<input type="text" name="_csrf" value="' + token+ '" />'; 850 851 852 $('<form>', { 853 "id" : "exportExcelTempForm", 854 "method" : "post", 855 "html" : content, 856 "action" : calledUrl 857 }).appendTo(document.body).submit(); 858 859 setTimeout(function() { 860 $('#exportExcelTempForm').remove(); 861 }, 100); 862 }, 863 864 865 /** 866 * (privée) Fonction appelée après réorganisation des colonnes 867 * @param parent objet aktable associé à la table 868 */ 869 _changeOrder:function(parent) { 870 parent._reorganize(parent, parent.selector.getSelection(),true); 871 }, 872 873 /** 874 * (privée) Fonction appelée après avoir cliqué sur "Valeurs par défaut" réorganisation des colonnes 875 * @param parent objet aktable associé à la table 876 */ 877 _resetOrder:function(parent) { 878 var selection = []; 879 $.each(parent.originalColumns,function(key,column) { 880 selection.push(column.property); 881 }); 882 parent._reorganize(parent, selection,true); 883 }, 884 885 /** 886 * (privée) 887 * @param _self 888 * @param selection 889 */ 890 _reorganize:function(_self, selection, goToPage) { 891 var content = _self.originalRowTemplate; 892 893 var beginIndex = content.indexOf('<tr'); 894 var endIndex = content.indexOf('<td'); 895 896 var trDescription = content.substring(beginIndex,endIndex); 897 var templateWithoutTR = content.substring(endIndex).replace(/<\/tr>/g,''); 898 899 var template = $('<table><tr>
899' + templateWithoutTR + '</tr></table>'); 900 901 // On bascule toutes les colonnes en invisible 902 $.each(_self.originalColumns,function(key,column) { 903 column.visible = false; 904 }); 905 906 // Remplit une map de données 907 var map = {}; 908 for (var i=0;i<_self.originalColumns.length;i++) { 909 var currentCol = _self.originalColumns[i]; 910 var th = $('<table>' + _self.originalHeader + '</table>').find('tr:first th')[i]; 911 currentCol.htmlContent = $(th)[0].outerHTML; 912 913 var thTemplate = template.find('td')[i]; 914 currentCol.templateHtmlContent = thTemplate?$(thTemplate)[0].outerHTML:''; 915 916 map[currentCol.property] = currentCol; 917 } 918 919 // Efface toutes les colonnes des en-têtes et du template 920 _self.$el.find('th').remove(); 921 template.find('td').remove(); 922 923 // Reconstruit le tout :) 924 var newColumns = []; 925 926 for (var i=0;i<selection.length;i++) { 927 var key = selection[i]; 928 var column = map[key]; 929 if (!column) { 930 continue; 931 } 932 column.visible = true; 933 newColumns.push(column); 934 935 // La colonne originale est marquée comme visible 936 _self._getOriginalColumn(column.property).visible = true; 937 938 // Contruite l'entête 939 _self.$el.find('tr:first').append(column.htmlContent); 940 // Et le template 941 template.find('tr:first').append(column.templateHtmlContent); 942 } 943 944 // Ok on remet en état 945 _self.columns = newColumns; 946 var htmlContent = $(template)[0].outerHTML; 947 var cleanHtmlContent = htmlContent.replace(/<table>|<\/table>/gi,'').replace(/<tbody>|<\/tbody>/gi,'').replace(/</gi,'<').replace(/>/gi,'>').replace(/<tr>|<\/tr>/gi,''); 948 _self.rowTemplate = trDescription + cleanHtmlContent + '</tr>'; 949 _self.rendered = false; 950 _self._decorateHeaders(); 951 _self.rendered = true; 952 953 _self._recreateSliders(); 954 955 if (goToPage) { 956 _self.goToPage(1); 957 } 958 _self._storeInCookies(); 959 _self.onRenderComplete(); 960 }, 961 962 /** 963 * (privée) Renvoie une propriété en fonction de la colonne 964 * @param property 965 * @returns 966 */ 967 _getOriginalColumn : function(property) { 968 var length = this.originalColumns.length; 969 for ( var i = 0; i < length; i++) { 970 var cd = this.originalColumns[i]; 971 if (cd.property == property) { 972 return cd; 973 } 974 } 975 return null; 976 }, 977 978 _storeInCookies:function() { 979 var cols = []; 980 var width = []; 981 $.each(this.columns, function (index,column) { 982 cols.push(column.property); 983 if (column.size>-1) { 984 width.push({key:column.property,value:column.size}); 985 } 986 }); 987 988 var toStore = {order:cols,width:width, rownum:this.rownum}; 989 $.cookie(this._buildCookieId(), JSON.stringify(toStore), {expires:365}); 990 }, 991 992 _retrieveFromCookies:function (goToPage) { 993 var cookie = $.cookie(this._buildCookieId()); 994 if (cookie == null || cookie == '') { 995 return; 996 } 997 998 var data = JSON.parse(cookie); 999 1000 if (data.order==null || data.order.length == 0) { 1001 return; 1002 } 1003 1004 1005 // Réorganisation des colonnes 1006 this._reorganize(this, data.order,goToPage); 1007 1008 // Et changement des tailles 1009 if (data.width.length>0) { 1010 var parent = this; 1011 $.each(data.width, function(widthPairIndex,widthPair) { 1012 parent.$el.find("tr:first th").each(function(columnIndex) { 1013 var property = $(this).attr('data-property'); 1014 if (property == widthPair.key) { 1015 var newWidth = widthPair.value + 'px'; 1016 $('#' + parent.tableId + ' tr').each(function() { 1017 $(this).find('td').eq(columnIndex).css('width', newWidth); 1018 $(this).find('th').eq(columnIndex).css('width', newWidth); 1019 }); 1020 1021 } 1022 }); 1023 }); 1024 } 1025 1026 if (typeof data.rownum !== 'undefined') { 1027 this.rownum = data.rownum; 1028 this.autoRownum=-1; 1029 if (this.hasFooter) { 1030 $('#' + this.tableId + '_footer_combo').val(data.rownum); 1031 } 1032 } 1033 this._recreateSliders(); 1034 1035 }, 1036 1037 _buildCookieId:function() { 1038 var url = window.location.pathname; 1039 var filename = url.substring(url.lastIndexOf('/')+1); 1040 return filename + "_" + this.tableId; 1041 }, 1042 1043 /********* Section publique *********/ 1044 /** 1045 * Dessin de la table 1046 */ 1047 render : function(_goToPage) { 1048 var goToPage = typeof _goToPage !== 'undefined'? _goToPage: true ; 1049 this._decorateHeaders(); 1050 this._generateContents(); 1051 this._addFooter(); 1052 this._recreateSliders(); 1053 this.rendered = true; 1054 this._retrieveFromCookies(goToPage); 1055 // Réorganisation des colonnes 1056 var selection = []; 1057 $.each(this.columns,function(key,column) { 1058 if (column.visible) { 1059 selection.push(column.property); 1060 } 1061 }); 1062 this._reorganize(this, selection,goToPage); 1063 this.onRenderComplete(); 1064 return this ; 1065 }, 1066 1067 1068 /** 1069 * Code appelé une fois le rendu terminé 1070 */ 1071 onRenderComplete:function() { 1072 1073 }, 1074 1075 /** 1076 * Chargement des données 1077 */ 1078 loadData : function() { 1079 var parent = this; 1080 1081 var rowsPerPage = this.rownum; 1082 if (this.rownum == -1) { 1083 if (this.autoRownum == -1) { 1084 rowsPerPage = 50; 1085 } else { 1086 rowsPerPage = this.autoRownum; 1087 } 1088 } 1089 1090 var settings = { 1091 page:this.page, 1092 rowsPerPage:rowsPerPage, 1093 sort:this.currentSort, 1094 categoriesExpanded: JSON.stringify( this.categoriesExpanded).replace(/\"|\[|\]/g,""), // Supprime les doubles quotes et les crochets 1095 ts:new Date().getTime() // Pour empêcher les problèmes sous IE 1096 }; 1097 1098 if (this.params != null) { 1099 $.extend(settings,this.params); 1100 } 1101 1102 var loadingId = this.$el.attr('id') + '_loading'; 1103 1104 var loadingArea = $('#' +loadingId); 1105 var table = $(this.$el); 1106 loadingArea.css("top", table.position().top); 1107 loadingArea.css("left",table.position().left); 1108 loadingArea.css("width",table.outerWidth()); 1109 loadingArea.css("height",table.outerHeight()); 1110 1111 $.ajax({
1112 type : 'GET', 1113 url : this.url + '?' + $.param(settings), 1114 contentType : 'application/json;charset=UTF-8', 1115 dataType : 'json', 1116 cache : false, 1117 beforeSend : function () { 1118 loadingArea.show(); 1119 }, 1120 success : function(_data) { 1121 loadingArea.hide(); 1122 parent.setData(_data); 1123 }, 1124 error : function(jqXHR, textStatus, errorThrown) { 1125 loadingArea.hide(); 1126 alert(keywords['aktable.error.message']); 1127 } 1128 }); 1129 return this ; 1130 }, 1131 1132 /** 1133 * Initialise les données du tableau 1134 * @param _data données du tableau 1135 */ 1136 setData:function(_data) { 1137 1138 // Initialisation des paramètres de l'objet 1139 this.numberOfPages = _data.numberOfPages; 1140 this.page = _data.currentPage; 1141 this.numberOfRecords = _data.numberOfRecords; 1142 this.data = _data.rows; 1143 this.groupByProperties = _data.groupByProperties; 1144 1145 // Génération du tableau, rafraichissement de l'entête 1146 // et des sliders pour le redimensionnement 1147 this._generateContents(); 1148 this._refreshFooter(); 1149 this.onLoadComplete(); 1150 this._recreateSliders(); 1151 }, 1152 1153 /** 1154 * Code appelé une fois le chargement de données terminé 1155 */ 1156 onLoadComplete:function() { 1157 1158 }, 1159 1160 /** 1161 * Permet de se rendre à une page donnée 1162 * 1163 * @param newPage 1164 */ 1165 goToPage : function(newPage) { 1166 this.page = newPage; 1167 this.loadData(); 1168 }, 1169 1170 /** 1171 * Permet de montrer le tableau dans la page s'il a été caché 1172 */ 1173 show : function(){ 1174 this.$el.show() ; 1175 if (this.hasFooter) { 1176 $('#' + this.tableId + '_footer').show() ; 1177 } 1178 $('.aktable-resize-drag-handle').show() ; 1179 this._recreateSliders(); 1180 return this ; 1181 }, 1182 1183 /** 1184 * Permet de cacher le tableau dans la page 1185 */ 1186 hide : function(){ 1187 this.$el.hide() ; 1188 if (this.hasFooter) { 1189 $('#' + this.tableId + '_footer').hide() ; 1190 } 1191 $('.aktable-resize-drag-handle').hide() ; 1192 return this ; 1193 }, 1194 1195 /** 1196 * Permet de cacher une colonne 1197 * @param propertyName 1198 */ 1199 hideColumn : function(propertyName) { 1200 for ( var colIndex = 0; colIndex < this.columns.length; colIndex++) { 1201 var column = this.columns[colIndex]; 1202 if (column.property == propertyName) { 1203 column.visible = false; 1204 this._updateAfterVisibilityChange(true); 1205 return; 1206 } 1207 } 1208 }, 1209 1210 _updateAfterVisibilityChange:function(goToPage) { 1211 var selection = []; 1212 $.each(this.originalColumns,function(key,column) { 1213 if (column.visible) { 1214 selection.push(column.property); 1215 } 1216 }); 1217 this._reorganize(this, selection,goToPage); 1218 }, 1219 1220 /** 1221 * Permet de cacher une colonne 1222 * @param propertyName 1223 */ 1224 showColumn : function(propertyName) { 1225 for ( var colIndex = 0; colIndex < this.columns.length; colIndex++) { 1226 var column = this.columns[colIndex]; 1227 if (column.property == propertyName) { 1228 column.visible = true; 1229 this._updateAfterVisibilityChange(true); 1230 return; 1231 } 1232 } 1233 } 1234 1235 1236});
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.