﻿/** <description>Représente un objet qui propose des fonctionnalités de mise en tableau avancées.</description>
* <fullName>AJAXTableau</fullName>
* <type>class</type>
*/
var AJAXTableau = Class.create()
AJAXTableau.prototype = {
    initialize: function(JSONGeneric, JSONColumns, JSONRows) {
        if (JSONGeneric) {

            this.typeOf = 'AJAXTableau'/** <description>type de de l'objet</description> <fullName>AJAXTableau.typeOf</fullName><type>property</type>*/
            this.container = $(JSONGeneric.container)/** <description>Element HTML DIV dans lequel l'AJAXTAbleau est contenu</description>  <fullName>AJAXTableau.container</fullName><type>property</type>*/
            this.name = this.container.id /** <description><![CDATA[Nom de l'objet. Tient compte des masters et autres fichirs ascx.C'est également la syntaxe à utiliser pour appeler l'objet directement en javascript]]></description><fullName>JAXTableau.name </fullName><type>property</type>*/
            this.params = null
            if (!this.container) this.container = JSONGeneric.container
            this.header = new AJAXTableauHeader(JSONGeneric.header, this)  /** <description>Entete du tableau (AJAXTableauHeader) </description><fullName>AJAXTableau.header </fullName><type>property</type>*/
            //this.rowSelector = new AJAXTableauSelectorRow(JSONGeneric.rowSelector, this)
            this.footer = new AJAXTableauFooter(JSONGeneric.footer, this)/**<description>Pied du tableau (AJAXTableauFooter)</description><fullName>AJAXTableau.footer</fullName><type>property</type>*/

            if (JSONGeneric.menu) {
                this.menu = new AJAXMenu(JSONGeneric.menu, this); /**<description>Menu du tableau (AJAXMenu)</description><fullName>AJAXTableau.menu </fullName><type>property</type>*/
                this.menu.onTableauMenuSelect = this.tableauMenuSelect
            }
            this.body = new AJAXTableauBody(JSONGeneric.body, this)/**<description>Body du tableau (AJAXTableauBody)</description><fullName>AJAXTableau.body</fullName><type>property</type>*/
            this.cellPadding = (JSONGeneric.cellPadding) ? JSONGeneric.cellPadding : '0'/**<description>Espace intérieur appliqué aux cellules (int)</description><fullName>AJAXTableau.cellPadding </fullName><type>property</type>*/
            this.cellSpacing = (JSONGeneric.cellSpacing) ? JSONGeneric.cellSpacing : '0'/**<description>Espace entre les cellules (int)</description><fullName>AJAXTableau.cellSpacing </fullName><type>property</type>*/
            this.width = (JSONGeneric.width) ? JSONGeneric.width : ''/**<description>Largeur du contrôle complet (int)</description><fullName>AJAXTableau.width </fullName><type>property</type>*/
            this.showStatusBar = (JSONGeneric.showStatusBar) ? true : false/**<description>Spécifie si la barre de status doit être montrée (boolean)</description><fullName>AJAXTableau.showStatusBar </fullName><type>property</type>*/
            this.statusBar = new AJAXTableauStatus(this)  /**<description>Barre de status (AJAXTableauStatus)</description><fullName>AJAXTableau.statusBar </fullName><type>property</type>*/
            this.fileRessource = (JSONGeneric.fileRessource) ? JSONGeneric.fileRessource : ''/** <description>Fichier au format XML qui reçoit la sérialisation (string) </description><fullName>AJAXTableau.fileRessource</fullName><type>property</type> <obsolete>true</obsolete>*/
            this.controlId = (JSONGeneric.controlId) ? JSONGeneric.controlId : '' /** <description>Nom de l'instance. Tient compte des masters et des fichiers ascx. (string) </description><fullName>AJAXTableau.controlId </fullName><type>property</type>*/
            this.pagePath = (JSONGeneric.pagePath) ? JSONGeneric.pagePath : ''/** <description>Nom de la page dans laquelle se trouve le controle au format relatif. (string) </description><fullName>AJAXTableau.pagePath </fullName><type>property</type><obsolete>true</obsolete>*/
            this.tableauPDF = (JSONGeneric.AJAXTableauPDF) ? JSONGeneric.AJAXTableauPDF : null /**<description>Définit les options d'affichage du tableau au format pdf. (JSON) </description><fullName>AJAXTableau.tableauPDF </fullName><type>property</type>*/
            this.isEditable = (JSONGeneric.isEditable) ? JSONGeneric.isEditable : false/**<description>Spécifie si le tableau peut être édité. (boolean) </description><fullName>AJAXTableau.isEditable </fullName><type>property</type>*/
            this.asynchronous = true /**<description>Spécifie si les appels au serveur sont synchrones (boolean) </description><fullName>AJAXTableau.asynchronous </fullName><type>property</type><obsolete>true</obsolete>*/
            this.groupeLinked = (JSONGeneric.groupeLinked) ? JSONGeneric.groupeLinked : undefined /**<description>Nom du groupe auquel le tableau est lié. (string) </description><fullName>AJAXTableau.groupeLinked</fullName><type>property</type>*/
            this.isVisible = true /**<description>Spécifie si le tableau est visible. (boolean) </description><fullName>AJAXTableau.isVisible </fullName><type>property</type>*/
            this.selectorColumnIndex = -1 /**<description>Index de la colonne de sélection de ligne. Vaut -1 si n'existe pas. </description><fullName>AJAXTableau.selectorColumnIndex</fullName><type>property</type>*/

            this.afterRowBinded = (JSONGeneric.afterRowBinded) ? JSONGeneric.afterRowBinded : null/**<description>Définit un handler Javascript qui se produit après qu'une ligne soit chargée.  (string) </description><fullName>AJAXTableau.afterRowBinded </fullName><type>property</type> <param name="ta">tableau (Object)</param> <param name="row">ligne construite (Object)</param>*/
            this.afterTableLoaded = (JSONGeneric.afterTableLoaded) ? JSONGeneric.afterTableLoaded : null/**<description>Définit un handler Javascript qui se produit après que le tableau soit chargé.  (string) </description><fullName>AJAXTableau.afterTableLoaded </fullName><type>property</type> <param name="ta">tableau chargé (Object)</param>*/
            this.onRowDoubleClick = (JSONGeneric.onRowDoubleClick) ? JSONGeneric.onRowDoubleClick : null/**<description>Définit un handler Javascript qui se produit après que l'utilisateur ait double cliqué sur une ligne.  (string) </description><fullName>AJAXTableau.onRowDoubleClick </fullName><type>property</type><param name="ta">tableau (Object)</param><param name="row">Ligne sur laquelle s'est produit le double clic (Object)</param><param name="e">event (prototype)</param>*/
            this.onRowClick = (JSONGeneric.onRowClick) ? JSONGeneric.onRowClick : null/**<description>Définit un handler Javascript qui se produit après que l'utilisateur ait cliqué sur une ligne.  (string) </description><fullName>AJAXTableau.onRowClick </fullName><type>property</type><param name="ta">tableau (Object)</param><param name="row">ligne sur laquelle s'est produit le clic (Object)</param><param name="e">event (prototype)</param>*/
            this.onSelectedRow = (JSONGeneric.onSelectedRow) ? JSONGeneric.onSelectedRow : null/**<description>Définit un handler Javascript qui se produit après qu'une ligne ait été sélectionnée ou activée  (string) </description><fullName>AJAXTableau.onSelectedRow </fullName><type>property</type><param name="row">Ligne sélectionnée (Object)</param>*/
            this.onTableauScroll = (JSONGeneric.onTableauScroll) ? JSONGeneric.onTableauScroll : null/**<description>Définit un handler Javascript qui se produit après que le tableau soit scrollé  (string) </description><fullName>AJAXTableau.onTableauScroll </fullName><type>property</type><param name="jsonParams">sender:Tableau, scrollTop:Position haute du scroll,scrollLeft:Position gauche du scroll</param>*/
            this.onAfterFooterBinded = (JSONGeneric.onAfterFooterBinded) ? JSONGeneric.onAfterFooterBinded : null/**<description>Définit un handler Javascript qui se produit après que le footer soit chargé  (string) </description><fullName>AJAXTableau.onAfterFooterBinded </fullName><type>property</type><obsolete>true</obsolete>*/
            this.onBeforeTableLoad = (JSONGeneric.onBeforeTableLoad) ? JSONGeneric.onBeforeTableLoad : null/**<description>Définit un handler Javascript qui se produit avant que le tableau soit chargé  (string) </description><fullName>AJAXTableau.onBeforeTableLoad </fullName><type>property</type><param name="ta">tableau (Object)</param>*/
            this.onBeforeBuildGroup = (JSONGeneric.onBeforeBuildGroup) ? JSONGeneric.onBeforeBuildGroup : null/**<description>Définit un handler Javascript qui se produit avant qu'un groupe soit chargé  (string) </description><fullName>AJAXTableau.onBeforeBuildGroup </fullName><type>property</type><param name="ta">tableau (Object)</param><param name="groupeName">Nom du groupe (string)</param>*/
            this.onAfterBuildGroup = (JSONGeneric.onAfterBuildGroup) ? JSONGeneric.onAfterBuildGroup : null/**<description>Définit un handler Javascript qui se produit après qu'un groupe soit chargé  (string) </description><fullName>AJAXTableau.onAfterBuildGroup </fullName><type>property</type><param name="ta">tableau (Object)</param><param name="groupeName">Nom du groupe (string)</param>*/
            this.onBeforeToGetPdf = (JSONGeneric.onBeforeToGetPdf) ? JSONGeneric.onBeforeToGetPdf : null/**<description>Définit un handler Javascript qui se produit avant de charger les données au format PDF.  (string) </description><fullName>AJAXTableau.onBeforeToGetPdf </fullName><type>property</type><param name="ta">tableau (Object)</param>*/
            this.onBeforeToGetCsv = (JSONGeneric.onBeforeToGetCsv) ? JSONGeneric.onBeforeToGetCsv : null/**<description>Définit un handler Javascript qui se produit avant de charger les données au format CSV.  (string) </description><fullName>AJAXTableau.onBeforeToGetCsv </fullName><type>property</type><param name="ta">tableau (Object)</param>*/
            this.onAfterGetPdf = (JSONGeneric.onAfterGetPdf) ? JSONGeneric.onAfterGetPdf : null/**<description>Définit un handler Javascript qui se produit après que les données soient chargées au format PDF.  (string) </description><fullName>AJAXTableau.onAfterGetPdf </fullName><type>property</type><param name="ta">tableau (Object)</param>*/
            this.onAfterBindingMenu = (JSONGeneric.onAfterBindingMenu) ? JSONGeneric.onAfterBindingMenu : null/**<description>Définit un handler Javascript après que le menu du tableau soit chargé.  (string) </description><fullName>AJAXTableau.onAfterBindingMenu </fullName><type>property</type><obsolete>true</obsolete>*/
            this.onMenuClick = (JSONGeneric.onMenuClick) ? JSONGeneric.onMenuClick : null/**<description>Définit un handler Javascript qui se produit après que l'utilisateur ait cliqué sur le menu.  (string) </description><fullName>AJAXTableau.onMenuClick </fullName><type>property</type><param name="ta">tableau (Object)</param><param name="menu">menu qui a génré l'évènement (Object)</param><param name="item">item du menu choisi.</param> */
            this.onAfterRowDeleted = (JSONGeneric.onAfterRowDeleted) ? JSONGeneric.onAfterRowDeleted : null/**<description>Définit un handler Javascript qui se produit après que les lignes sélectionnées aient été supprimées.  (string) </description><fullName>AJAXTableau.onAfterRowDeleted </fullName><type>property</type><param name="ta">Tableau (Object)</param>*/
            this.onAfterRowAdded = (JSONGeneric.onAfterRowAdded) ? JSONGeneric.onAfterRowAdded : null/**<description>Définit un handler Javascript qui se produit après qu'une ligne ait été ajoutée au tableau.  (string) </description><fullName>AJAXTableau.onAfterRowAdded </fullName><type>property</type><param name="ta">tableau (Object) </param><param name="row">Ligne insérée (Object)</param>*/
        }


        this.container.observe('mouseover', function(e) {
            if (_ACTIVEAJAXTABLE != this) setSelectedTable(this)
        } .bindAsEventListener(this), false)

        this.container.observe('mouseout', function(e) {
            if (e.target == this.container) delSelectedTable()
        } .bindAsEventListener(this))

        this.initAll(JSONColumns, JSONRows)

        __AJAXTablesArray__.push(this)


    },

    /** <description>Charge les données</description>
    <fullName>AJAXTableau.databind</fullName>
    <type>method</type>
    <param name="SQLDatas">Paramètres à passer au handler au format url</param>
    <param name="JSONRows">Collection de lignes au format JSON. Passée dans le cas d'un bindAsStartup</param>
    <param name="ajaxHandler">url du handler de substitution (url). Permet d'écrire son propore handler afin de modifier la requete par exemple</param>
    <param name="useFilter">Indique sur la demande utilise un filtre</param>
    <param name="loadRow">Plus utilisé. Voir pour supprimer</param>
    */
    databind: function(SQLDatas, JSONRows, ajaxHandler, useFilter, loadRow) { this.dataBind(SQLDatas, JSONRows, ajaxHandler, useFilter, loadRow) },

    dataBind: function(SQLDatas, JSONRows, ajaxHandler, useFilter, loadRow) {
        this.body.isEmpty = true

        if (this.body.groupByField) { //
            this.body.groups = new AJAXTableauGroups(this)
        }

        if (JSONRows) {
            this.params = $A(JSONRows.params)
            if (typeof this.onBeforeTableLoad == 'function') this.onBeforeTableLoad(this)
            this.body.elementBody.insert(this.columns.getColGroupeElement())
            this.body.nbRows = JSONRows.nbRows
            if (JSONRows.footerValues) { this.footer.databind(JSONRows.footerValues); this.footer.show() }
            this.body.addRows($A(JSONRows.rows));
            this.header.setOrderArrow()
            return
        }

        if (!ajaxHandler) ajaxHandler = 'ajaxtableau.ajax'

        var params = 'action=1&fr=' + this.fileRessource + '&pp=' + this.pagePath + '&cid=' + this.controlId
        if (SQLDatas) params += '&' + SQLDatas




        this.columns.each(function(c) {
            if (useFilter && c.filterType >= 0 && c.filter.value) {
                params += '&' + c.field + '=' + c.filter.value
            }
            else if (!useFilter && c.filterType > -1) {
                c.filter.value = ''
            }
        })

        if (this.body.loadOnDemand == true) {
            if (this.body.rowIndexToGet.min == -1) this.initLOD()
            params += '&min=' + this.body.rowIndexToGet.min + '&max=' + this.body.rowIndexToGet.max
            if (this.body.rowIndexToGet.min == 1) {
                this.initDataBind()
            }

        } else {
            this.initDataBind()
        }

        this.body.elementBody.show()

        var a = new Ajax.Request(ajaxHandler, {
            method: 'post',
            postBody: params,
            onLoading: function() { this.statusBar.setChargement('Loading Datas') } .bind(this),
            asynchronous: this.asychronous,
            onComplete: function(transport) {
                var el = transport.responseJSON
                if (el.nbRows) this.body.nbRows = el.nbRows
                if (!el.result) {
                    if (typeof this.afterTableLoaded == 'function') this.afterTableLoaded(this)
                    return
                }
                this.params = $A(el.params)
                if (typeof this.onBeforeTableLoad == 'function') this.onBeforeTableLoad(this)
                if (el.footerValues) { this.footer.databind(el.footerValues); this.footer.show() }
                this.body.addRows(el.rows)
                this.header.setOrderArrow()
            } .bind(this)
        })
    },

    /** <description>Initialise les éléments du tableau avant le l'appel d'un databin</description>
    <fullName>AJAXTableau.initDataBind</fullName>
    <type>method</type>
    <encapsulation>private</encapsulation>
    */
    initDataBind: function() {
        this.body.elementBody.hide()
        this.body.clear()
        this.footer.render(); this.footer.hide()
        this.statusBar.setChargement('0 ligne')
        if (this.header.isFixed) this.body.elementBody.insert(this.columns.getColGroupeElement())
    },

    /** <description>Initialise le LoadOnDemand</description>
    <fullName>AJAXTableau.initLOD</fullName>
    <type>method</type>
    */
    initLOD: function() { this.body.initLOD() },

    /** <description>Construit les éléments du tableau</description>
    <fullName>AJAXTableau.renderAll</fullName>
    <type>method</type>
    <param name="SQLDatas">Paramètres à passer au handler au format url</param>
    <param name="JSONRows">Collection de lignes au format JSON. Passée dans le cas d'un bindAsStartup</param>
    */
    renderAll: function(SQLDatas, JSONRows) {

        if (this.header && this.container) {
            if (this.menu) this.container.insert(this.menu.element)
            this.header.render()
            this.body.render()
            this.footer.render()

            this.container.appendChild(this.statusBar.element)
            if (this.showStatusBar) this.statusBar.show()
            if (JSONRows) { this.dataBind(SQLDatas, JSONRows); this.body.nbRows = JSONRows.nbRows;}

        } else { return }
    },

    /** <description><![CDATA[<P>Affiche une fenêtre au dessus du controle afin de montrer que le tableau est en train de charger.</P>
    <P>Cette fonction n'a jamais été reellement développée. A reprendre</P>]]></description>
    <fullName>AJAXTableau.showLoading</fullName>
    <type>method</type>
    <obsolete>true</obsolete>
    */
    showLoading: function() {
        if (!this.loadingElement && this.container) {
            var div = new Element('DIV')
            var dim = this.container.getDimensions()
            div.setStyle({ height: dim.height + 'px', width: '100%', backgroundColor: '#4f4c4c', display: 'none', position: 'relative', top: (dim.height * -1) + 'px', left: '0px', zIndex: '99999' })
            div.update('test')
            this.container.insert(div)
            this.loadingElement = div
        }

        if (this.loadingElement) this.loadingElement.show()
    },
    /** <description>Assigne une valeur à la propriété cellPadding et affecte la contrôles concernés.</description>
    <fullName>AJAXTableau.setCellPadding</fullName>
    <type>method</type>
    <param name="cellPading">Valeur du cellPadding (int)</param>
    */
    setCellPadding: function(cellPadding) {
        this.body.elementTable.cellPadding = cellPadding
        this.header.elementTable.cellPadding = cellPadding
        this.cellPadding = cellPadding
    },

    /** <description>Assigne une valeur à la propriété cellSpacing et affecte la contrôles concernés.</description>
    <fullName>AJAXTableau.setCellSpacing</fullName>
    <type>method</type>
    <param name="cellSpacing">Valeur du cellSpacing (int)</param>
    */
    setCellSpacing: function(cellSpacing) {
        this.body.elementTable.cellSpacing = cellSpacing
        this.header.elementTable.cellSpacing = cellSpacing
        this.cellSpacing = cellSpacing
    },

    /** <description>Modifie la largeu du tableau et affecte la propriété width</description>
    <fullName>AJAXTableau.setWidth</fullName>
    <type>method</type>
    <param name="w">largeur. Exprimé en px (10px) ou en pourcentage (10%)(string)</param>
    */
    setWidth: function(w) {
        this.body.elementTable.setStyle({ width: w })
        this.header.elementTable.setStyle({ width: w })
        this.width = w
    },

    /** <description><![CDATA[Positionnne les différents éléments du tableau dans le container.</BR>
    Se déclence au chargement du tableau et lorsque la page est redimensionnée.</BR>
    Il peut être utilise de lancer cette method avant d'afficher un tableau qui se trouve dans un surlayer masqué.]]></description>
    <fullName>AJAXTableau.setPosition</fullName>
    <type>method</type>
    <param name="cellSpacing">Valeur du cellSpacing (int)</param>
    */
    setPosition: function() {

        if (this.width.indexOf('%') > -1) {
            var i = this.width.replace('%', '')
            i = parseFloat(i)
            var w = this.container.getWidth() * i / 100
            this.body.elementTable.style.width = w + 'px'
            this.header.elementTable.style.width = w + 'px'
            if (this.footer.element) this.footer.element.style.width = w + 'px'
        }

        var h = this.container.getHeight() - this.header.elementHead.getHeight()
        if (this.menu) h -= this.menu.element.getHeight()

        if (this.statusBar.visible) h -= this.statusBar.element.getHeight()
        h -= (Prototype.Browser.IE) ? this.cellSpacing * 2 : this.cellSpacing
        if (this.header.isFixed) {
            if (h < 0) h = 10
            this.body.container.style.height = h + 'px'
        } else {
            if (this.header.elementTable.parentNode) this.header.elementTable.parentNode.style.height = h + 23 + 'px'
        }

        this.initBorder()

        if (this.menu) {
            this.menu.element.setStyle({ borderStyle: 'solid solid none solid', borderColor: '#CCCCCC', borderWidth: '1px' })
            this.header.elementDiv.setStyle({ borderStyle: 'none solid none solid', borderColor: '#CCCCCC', borderWidth: '1px' })
        } else {
            this.header.elementDiv.setStyle({ borderStyle: 'solid solid none solid', borderColor: '#CCCCCC', borderWidth: '1px' })
        }

        if (this.header.isFixed) this.body.elementDiv.setStyle({ borderStyle: 'none solid none solid', borderColor: '#CCCCCC', borderWidth: '1px' })

        if (this.statusBar.visible) {
            this.statusBar.element.setStyle({ borderStyle: 'none solid solid solid', borderColor: '#CCCCCC', borderWidth: '1px' })
        }
    },
    /** <description>Position les bordure sur le container en fonction des éléments qui compose le tableau</description>
    <fullName>AJAXTableau.initBorder</fullName>
    <type>method</type>
    */
    initBorder: function() {
        if (this.menu) { this.menu.element.setStyle({ border: 'none' }) }
        this.header.elementDiv.setStyle({ border: 'none' })
        if (this.header.isFixed) this.body.elementDiv.setStyle({ border: 'none' })
        this.statusBar.element.setStyle({ border: 'none' })
    },

    /** <description>Masque le tableau</description>
    <fullName>AJAXTableau.hide</fullName>
    <type>method</type>
    */
    hide: function() { this.container.hide(); this.isVisible = false },

    /** <description>Affiche la tableau</description>
    <fullName>AJAXTableau.show</fullName>
    <type>method</type>
    */
    show: function() { this.container.show(); this.isVisible = true },

    /** <description>Exporte le contenu du tableau au format CSV en tenant compte des filtres</description>
    <fullName>AJAXTableau.exportToCsv</fullName>
    <type>method </type>
    <param name="SQLDatas">paramètres necessaires à la requete (url string)</param>
    <param name="jaxHandler"> handler alternatif (string, non utilisé)</param>
    */
    exportToCsv: function(SQLDatas, ajaxHandler) {
        if (typeof this.onBeforeToGetCsv == 'function') { if (!this.onBeforeToGetCsv(this)) return }
        this.exportTab('2', SQLDatas, ajaxHandler)
    },

    /** <description>Exporte le contenu du tableau au format PDF en tenant compte des filtres</description>
    <fullName>AJAXTableau.exportToPdf</fullName>
    <type>method</type>
    <param name="SQLDatas">paramètres necessaires à la requete (url string)</param>
    <param name="ajaxHandler"> handler alternatif (string, non utilisé)</param>
    */
    exportToPdf: function(SQLDatas, ajaxHandler) {
        if (typeof this.onBeforeToGetPdf == 'function') { if (!this.onBeforeToGetPdf(this)) return }
        this.exportTab('3', SQLDatas, ajaxHandler)
        if (typeof this.onAfterGetPdf == 'function') this.onAfterGetPdf(this)
    },


    /** <description>Procédure d'exportation du tableau. PDF ou CSV</description>
    <fullName>AJAXTableau.exportToPdf</fullName>
    <type>method</type>
    <param name="todo">action à réaliser (string)</param>
    <param name="SQLDatas">paramètres necessaires à la requete (url string)</param>
    <param name="ajaxHandler">handler alternatif (string, non utilisé)</param>
    <encapsulation>private</encapsulation>
    */
    exportTab: function(todo, SQLDatas, ajaxHandler) {
        var params = 'todo=' + todo + '&fr=' + this.fileRessource + '&pp=' + this.pagePath + '&cid=' + this.controlId
        if (SQLDatas) params += '&' + SQLDatas

        // Récupération des paramètres + de la requete

        if (this.params) {
            this.params.each(function(node) { params += '&' + node.name + '=' + node.value })
        }
        var index = 0
        var sorted = 0

        this.columns.each(function(node) {
            if (node.sorted > 0) {
                index = this.columns.indexOf(node) - 1;
                sorted = node.sorted
            }
        } .bind(this))

        if (index > -1) params += '&sortedField=' + (index) + '' + '&sorted=' + sorted
        //params += '&shamallow=' + this.shamallow

        if (todo == '3' && this.tableauPDF) params += '&titre=' + this.tableauPDF.titre + '&sousTitre=' + this.tableauPDF.sousTitre

        if (!ajaxHandler) ajaxHandler = 'exportTableau.file'
        window.open(ajaxHandler + '?' + params, 'export')
    },

    /** <description>Lance la procédure de génération du tableau et des objets qui le composent. Est lancé au chargement du tableau</description>
    <fullName>AJAXTableau.initAll</fullName>
    <type>method</type>
    */
    initAll: function(JSONColumns, JSONRows) {
        this.container.update()
        if (JSONColumns) this.columns = new AJAXColumns(JSONColumns, this)
        this.renderAll(null, JSONRows)
    },

    /** <description><![CDATA[Handler appelé lorsque l'utilisateur clique sur l'AJAXMenu du tableau</BR>
    Le tableau contient un menu qui propose 4 choix : Export CSV, Export PDF, Ajouter une ligne, supprimer une ligne.</BR>
    Les valeur possibles renvoyées par el.value sont donc les suivantes : CSV, PDF, ADD, DEL]]></description>
    <fullName>AJAXTableau.tableauMenuSelect</fullName>
    <encapsulation>private</encapsulation>
    <type>method</type>
    <param name="sender">AJAXMenu qui a généré l'évènement</param>
    <param name="el">item de l'AJAXMenu qui a généré l'évènement</param>
    */
    tableauMenuSelect: function(sender, el) {

        var sqlDatas

        if (typeof sender.parent.onMenuClick == 'function') sqlDatas = sender.parent.onMenuClick(sender.parent, sender, el)

        if (sqlDatas == false) return

        switch (el.value) {
            case 'CSV': sender.parent.exportToCsv(); break;
            case 'PDF': sender.parent.exportToPdf(); break;
            case 'ADD':
                sender.parent.body.addDataRow(sqlDatas);
                break;
            case 'DEL': sender.parent.body.selectedRows.delRows(); break;
        }

    } .bind(this.menu),



    /** <description>Récupère la valeur affectée à goupeLinked et evalue cette valeur pour en faire une variable. Préalable à l'utilisation des groupes.</description>
    <fullName>AJAXTableau.initGroupeLinked</fullName>
    <type>method</type>
    <encapsulation>private</encapsulation>
    */
    initGroupeLinked: function() {
        if (Object.isString(this.groupeLinked)) this.groupeLinked = eval(this.groupeLinked)
    }
}


/** <description>Expose un ensemble de fonctionnalités pour gérer le body du tableau.</description>
<fullName>AJAXTableauBody</fullName>
<type>class</type>
*/
 var AJAXTableauBody = Class.create()
 AJAXTableauBody.prototype = {
     /** <description>Constructeur</description>
     <fullName>AJAXTableauBody.initialize</fullName>
     <type>method</type>
     <param name="JSONObject">Ensemble des propriétés et methodes générées par le serveur (JSON)</param>
     <param name="parent">Fait référence à l'AJAXTableau qui a générél l'objet</param>
     <encapsulation>private</encapsulation>
     */
     initialize: function(JSONObject, parent) {
         this.typeOf = 'AJAXTableauBody' /**<description>Type de l'objet (string)</description><fullName>AJAXTableauBody.typeOf</fullName><type>property</type> */
         this.elementTable = null /**<description>Element HTML TABLE dans le quel l'element HTML BODY est contenu</description><fullName>AJAXTableauBody.elementTable</fullName><type>property</type> */
         this.elementBody = null /**<description>Element HTML BODY généré par l'objet</description><fullName>AJAXTableauBody.elementBody</fullName><type>property</type> */
         this.container = null/**<description>Element HTML DIV dans lequel l'AJAXTAbleau est contenu</description><fullName>AJAXTableauBody.container</fullName><type>property</type> */
         this.parent = null /**<description>AJAXTableau dans lequel l'objet est construit</description><fullName>AJAXTableauBody.parent</fullName><type>property</type> */
         this.className = '' /**<description>Class Css affectée à l'objet HTML Body</description><fullName>AJAXTableauBody.className</fullName><type>property</type> */
         this.style = null/**<description>Styles Css affectés à l'objet HTML Body. Prend le dessus sur les classes</description><fullName>AJAXTableauBody.style</fullName><type>property</type> */
         this.rowClassName = ''/**<description>Class Css affectée aux lignes HTML.</description><fullName>AJAXTableauBody.rowClassName</fullName><type>property</type> */
         this.rowStyle = null/**<description>Styles Css affectés aux lignes HTML. Prend le dessus sur les classes</description><fullName>AJAXTableauBody.rowStyle</fullName><type>property</type> */
         this.rowOverClassName = ''/**<description>Class Css affectée aux lignes HTML au moment du survol</description><fullName>AJAXTableauBody.rowOverClassName</fullName><type>property</type> */
         this.rowOverStyle = null/**<description>Styles Css affectés aux lignes HTML au moment du survol. Prend le dessus sur les classes.</description><fullName>AJAXTableauBody.rowOverStyle</fullName><type>property</type> */
         this.rowSelectedClassName = ''/**<description>Class Css affectées aux lignes marquées sélectionnées.</description><fullName>AJAXTableauBody.rowSelectedClassName</fullName><type>property</type> */
         this.rowSelectedStyle = null/**<description>Styles Css affectés aux lignes marquées sélectionnées. Prend le dessus sur les classes.</description><fullName>AJAXTableauBody.rowSelectedStyle</fullName><type>property</type> */
         this.rowAlternateClassName = ''/**<description>Class Css affectée aux lignes marquées comme alternate (row.isAlternate == true)</description><fullName>AJAXTableauBody.rowAlternateClassName</fullName><type>property</type> */
         this.rowAlternateStyle = null/**<description>Styles Css affectés aux lignes marquées alternate. Prend le dessus sur les classes.</description><fullName>AJAXTableauBody.rowAlternateStyle</fullName><type>property</type> */
         this.allowMultiSelectRows = false/**<description>Spécifie si l'utilisateur peut sélectionner plusieurs lignes (boolean)</description><fullName>AJAXTableauBody.allowMultiSelectRows</fullName><type>property</type> */
         this.groupByField = null/**<description><![CDATA[Spécifie le champ sur lequel les lignes doivent être groupées.</BR>Incompatible avec le loadOnDemand]]></description><fullName>AJAXTableauBody.groupByField</fullName><type>property</type> */
         this.rowGroupClassName = null/**<description>Class Css appliquée sur les lignes groupés</description><fullName>AJAXTableauBody.rowGroupClassName</fullName><type>property</type> */
         this.rowGroupStyle = null/**<description>Styles css appliqués sur les lignes groupés. Prend le dessus sur les classes</description><fullName>AJAXTableauBody.rowGroupStyle</fullName><type>property</type> */
         this.groups = null // liste des groupes de rupture.
         this.smartNumber = 30  /**<description>Dans le cadre du smartDisplay, spécifie combien de lignes sont chargées à la fois dans le tableau</description><fullName>AJAXTableauBody.smartNumber</fullName><type>property</type> */
         this.smartDelay = 1000 /**<description>Dans le cadre du smartDisplay, délais entre deux chargements (ms)</description><fullName>AJAXTableauBody.smartDelay</fullName><type>property</type> */
         this.smartDisplay = -1 /**<description><![CDATA[Une valeur initialisée à 1 indique que les lignes doivent être chargées en groupe.</BR>Le nombre de ligne contenues dans chaque groupe est spécifié dans la propriété smartNumber.</BR>Incompatible avec le loadOnDemand]]></description><fullName>AJAXTableauBody.smartDisplay</fullName><type>property</type> */

         this.loadOnDemand = null /**<description><![CDATA[Spécifie que le loadOnDemand doit être utilisé.</BR>L'interface agit comme si toutes les lignes étaient chargées. En réalité, seules les lignes visibles sont chargées sur le client.</BR>
                                    A chaque mouvemement du scroller, le système calcule quelles lignes doivent être chargées et les affiche sur le client.]]></description><fullName>AJAXTableauBody.loadOnDemand</fullName><type>property</type> */
         this.loadOnDemandFillingRowClassName = null /**<description><![CDATA[Class Css appliquée sur les lignes de compensation</BR>
                                                        Les lignes de compensation sont générées afin de donner l'impression à l'internaute que toutes les lignes sont chargées.</BR>
                                                        Leur taille dépend de la propriété loadOnDemandRowHieght.</BR>]]></description><fullName>AJAXTableauBody.loadOnDemandFillingRowClassName</fullName><type>property</type> */
         this.insertRowPoint = null /**<description>Ligne AJAXTableRow avant la quelle insérer une ligne de compensation</description><fullName>AJAXTableauBody.insertRowPoint</fullName><type>property</type><encapsulation>private</encapsulation> */
         this.loadOnDemandRowHeight = 20/**<description>Taille des lignes du tableau. Cette propriété permet de calculer la taille des lignes de compensation et la liste des lignes à charger. Pour un meilleur résultat, mettre à false la propriété bodyWrap des AJAXColumn</description><fullName>AJAXTableauBody.smartNumber</fullName><type>property</type> */

         this.scrollTimer = null
         this.nbRows = null /**<description>Nombre total de lignes renvoyée par la requete select</description><fullName>AJAXTableauBody.nbRows</fullName><type>property</type> */
         this.filledRows = 0 /**<description>Nombre de lignes présentes sur le client</description><fullName>AJAXTableauBody.filledRows</fullName><type>property</type><obsolete>true</obsolete> */
         this.rowIndexToGet = { min: -1, max: -1}/**<description>Liste des lignes à remonter lors d'un LOD({min: x, max: y})</description><fullName>AJAXTableauBody.rowIndexToGet</fullName><type>property</type><encapsulation>private</encapsulation> */

         if (JSONObject) { for (var property in JSONObject) this[property] = JSONObject[property]; }
         if (parent) this.parent = parent /**<description>AJAXTableau parent du body</description><fullName>AJAXTableauBody.parent</fullName><type>property</type> */

         this.selectedRows = new AJAXTableauSelectedRows(this)/**<description>Lignes sélectionnées (AJAXTableauSelectedRows)</description><fullName>AJAXTableauBody.selectedRows</fullName><type>property</type> */
         this.rows = new AJAXTableauRows(null, this)/**<description>AJAXTableauRows contenues dans le body</description><fullName>AJAXTableauBody.rows</fullName><type>property</type> */
     },


     /**<description><![CDATA[Ajout les lignes définies dans JSONRows au body.</BR>
     Le cas des entetes fixes n'est pas finalisé.]]></description>
     *<fullName>AJAXTableauBody.addRows</fullName>
     *<param name="JSONRows">Collection de lignes au format JSON</param>
     *<type>method</type>
     */
     addRows: function(JSONRows) {
         if (!JSONRows || JSONRows.length == 0) { // tableau vide
             this.isEmpty = true
             if (this.parent.header.isFixed) this.elementBody.insert(this.parent.columns.getColGroupeElement())
             this.endOfLoading()
             //if (typeof this.parent.afterTableLoaded == 'function') this.parent.afterTableLoaded(this.parent)
             return
         }

         if (this.smartNumber > -1) {
             var min = 0
             var max = this.smartNumber - 1
             max = (JSONRows.length - 1 < max) ? JSONRows.length - 1 : max
             this.rows.addRange(JSONRows, min, max)
             this.parent.statusBar.setChargement((this.elementBody.rows.length - 1) + ' lignes')

             this.smartDisplay = window.setInterval(function() {
                 min = max + 1
                 max = max + this.smartNumber
                 max = (JSONRows.length - 1 < max) ? JSONRows.length - 1 : max

                 this.rows.addRange(JSONRows, min, max)
                 this.parent.statusBar.setChargement((this.elementBody.rows.length - 1) + ' lignes')
             } .bind(this), this.smartDelay)

             this.isEmpty = false
         } else {
            this.rows.addRange(JSONRows)
         }

     },

     /**<description><![CDATA[Se produit lorsque le body a terminé de charger les lignes.]]></description>
     *<fullName>AJAXTableauBody.endOfLoading</fullName>
     *<type>method</type>
     */
     endOfLoading: function() {
         this.parent.statusBar.setChargement(this.nbRows + ' lignes')
         if (typeof this.parent.afterTableLoaded == 'function') this.parent.afterTableLoaded(this.parent)
     },

     /**<description><![CDATA[crée une ligne vide et l'insère à l'index spécifié.]]></description>
     *<fullName>AJAXTableauBody.newRow</fullName>
     *<type>method</type>
     *<return> Une ligne aur format JSON</return>
     */
     newRow: function(specialInsert) {
         var nr = { datakey: null, cells: [] }
         this.parent.columns.each(function(c) { nr.cells.push({ value: '', text: '' }) })
         var r = this.rows.add(nr, specialInsert)
         return r
     },


     /**<description><![CDATA[Crée une ligne en base et l'ajoute dans le tableau.</BR>
     La requete d'insertion est définie sur le serveur au moyen de SQLCommand.insertRequest.</BR>
     La nouvelle ligne est systématiquement ajoutée en haut du tableau.</BR>
     La requete qui permet d'extraire la ligne nouvellent ajoutée prend en compte les filtres et autre paramètres de recherche.
     Il convient donc de les initialiser avant d'effectuer l'ajout de ligne au risque de ne pas voir la nouvelle ligne.]]></description>
     *<fullName>AJAXTableauBody.addDataRow</fullName>
     *<type>method</type>
     *<param name="SQLDatas">Paramètres à faire passer pour alimenter la requete d'insertion</param>
     *<param name="ajaxHandler">Handler alternatif</param>
     */
     addDataRow: function(SQLDatas, ajaxHandler) { //Crée une ligne en base et l'ajoute dans le tableau.

         var params = 'action=4&fr=' + this.parent.fileRessource + '&pp=' + this.parent.pagePath + '&cid=' + this.parent.controlId
         if (SQLDatas) params += '&' + SQLDatas
         if (!ajaxHandler) ajaxHandler = 'ajaxtableau.ajax'

         var a = new Ajax.Request(ajaxHandler, {
             method: 'post',
             postBody: params,
             onComplete: function(transport) {
                 var rs = transport.responseJSON
                 if (!rs.result) { alert(result.message); return }
                 if (rs.rows.length == 0) return
                 var r = this.rows[0]
                 var insertedRow = this.rows.add(rs.rows[0], { element: r, position: 'before' })
                 if (typeof this.parent.onAfterRowAdded == 'function') this.parent.onAfterRowAdded(this.parent, insertedRow)
             } .bind(this)
         })
     },

     /**<description><![CDATA[Crée les éléments HTML nécessaire au rendu du body. Crée également les différents évènements]]></description>
     *<fullName>AJAXTableauBody.render</fullName>
     *<type>method</type>
     */
     render: function() {
         this.getTableElement()

         if (this.parent.header.isFixed) {
             var d = new Element('DIV')
             this.container = d
             d.setStyle({ width: '100%', overflow: 'auto' })
             this.parent.container.appendChild(d)

             var dd = new Element('DIV')
             d.insert(dd)

             var cellMargin = (!Prototype.Browser.IE) ? (this.parent.cellSpacing * 2 * -1) + 'px' : (this.parent.cellSpacing * -1) + 'px'

             dd.setStyle({ marginTop: cellMargin })
             dd.appendChild(this.elementTable)
             this.elementDiv = d

             this.parent.setPosition()

             //prend en charge le glissement de l'entete si isFixed = true
             d.observe('scroll', function(e) {
                 var de = this.parent.container.select('DIV')[0].firstDescendant()
                 de.setStyle({ marginLeft: d.scrollLeft * -1 + 'px' })

                 if (this.loadOnDemand == true) {
                     window.clearTimeout(this.scrollTimer)
                     this.scrollTimer = window.setTimeout(function() { this.bindLoadOnDemand(d.scrollTop) } .bind(this), 600)
                 }

                 if (typeof this.parent.onTableauScroll == 'function') this.parent.onTableauScroll({ sender: this.parent, scrollLeft: d.scrollLeft, scrollTop: d.scrollTop })
             } .bindAsEventListener(this))

         }

         //prend en charge le survol des lignes
         this.elementBody.observe('mouseover', function(e) {
             var el = Event.findElement(e, 'TR')
             if (!el) return
             if (el.hasClassName(this.loadOnDemandFillingRowClassName)) return
             el.addClassName(this.rowOverClassName)
             if (this.rowOverStyle) el.setStyle(this.rowOverStyle)
         } .bind(this))

         this.disableSelect()

     },


     /**<description><![CDATA[Détermine quelles lignes sont afficher dans le LOD et lance la procédure de récupération des lignes]]></description>
     *<fullName>AJAXTableauBody.bindLoadOnDemand</fullName>
     *<type>method</type>
     */
     bindLoadOnDemand: function(scrollTop) {
         var r
         for (var i = 0; i < this.rows.length; i++) {
             r = this.rows[i]
             if (r.element.offsetTop <= scrollTop) {
                 if (i == this.rows.length - 1) break;
                 if (this.rows[i + 1].element.offsetTop > scrollTop) break;
             }
         }

         // Quelles ligne j'affiche ?

         this.rowIndexToGet = this.getIndexLinesToDisplay(r)
         if (!this.rowIndexToGet.min) return

         var params = ''
         this.parent.dataBind(params, null, null, true)

     },


     /**<description><![CDATA[Initialise le contrôle avant de lancer le LOD.]]></description>
     *<fullName>AJAXTableauBody.initLOD</fullName>
     *<type>method</type>
     *<encapsulation>private</encapsulation>
     */
     initLOD: function() { this.clear(); this.rowIndexToGet = this.getIndexLinesToDisplay(null) },


     /**<description><![CDATA[Désactive la sélection des données dans le tableau]]></description>
     *<fullName>AJAXTableauBody.disableSelect</fullName>
     *<type>method</type>
     *<encapsulation>private</encapsulation>
     */
     disableSelect: function() {
         this.elementBody.style.MozUserSelect = 'none'
         this.elementBody.style.htmlUserSelect = 'none';
         if (Prototype.Browser.IE) this.elementBody.onselectstart = function() { return false }
     },

     /**<description><![CDATA[Active la sélection des données dans le tableau]]></description>
     *<fullName>AJAXTableauBody.unableSelect</fullName>
     *<type>method</type>
     *<encapsulation>private</encapsulation>
     */
     unableSelect: function() {
         this.elementBody.style.MozUserSelect = ''
         this.elementBody.style.KhtmlUserSelect = '';
         if (Prototype.Browser.IE) this.elementBody.onselectstart = function() { return true }
     },



     /**<description><![CDATA[Génère et renvoie le Tableau HTML nécessaire au rendu du controle.]]></description>
     *<fullName>AJAXTableauBody.getTableElement</fullName>
     *<type>function</type>
     *<encapsulation>private</encapsulation>
     *<return>element HTML de type TABLE</return>
     */
     getTableElement: function() {
         if (this.elementTable) return this.elementTable

         if (!this.parent.header.isFixed) {
             this.elementTable = this.parent.header.elementTable

         } else {
             var t = new Element('TABLE', { cellPadding: this.parent.cellPadding, cellSpacing: this.parent.cellSpacing })
             t.setStyle({ width: this.parent.width, tableLayout: 'fixed' })
             this.elementTable = t
         }

         var tb = new Element('TBODY')
         tb.setStyle({ width: this.parent.width })
         if (this.className) tb.className = this.className
         if (this.style) tb.setStyle(this.style)
         this.elementBody = tb
         this.elementTable.appendChild(tb)

         return this.elementTable
     },

     /**<description><![CDATA[Affecte le style JSONStyle sur l'élément BODY du tableau et affecte la propriété style]]></description>
     *<fullName>AJAXTableauBody.setStyle</fullName>
     *<type>method</type>
     *<param name="JSONStyle">Style au format JSON</param>
     */
     setStyle: function(JSONStyle) {
         this.elementBody.setStyle(JSONStyle)
         this.style = JSONStyle
     },

     /**<description><![CDATA[Affecte la class css à l'élément BODY du tableau et affecte la propriété className]]></description>
     *<fullName>AJAXTableauBody.setClassName</fullName>
     *<type>method</type>
     *<param name="className">Nom de la classe (string)</param>
     */
     setClassName: function(className) {
         this.elementBody.className = className
         this.className = className
     },

     /**<description><![CDATA[Affecte les lignes du body avec une class Css.]]></description>
     *<fullName>AJAXTableauBody.setRowClassName</fullName>
     *<type>method</type>
     *<param name="rowClassName">Nom de la classe (string)</param>
     */
     setRowClassName: function(rowClassName) {
         this.rowClassName = rowClassName
         this.rows.refreshCss()
     },

     /**<description><![CDATA[Affecte les lignes du body avec un style Css.]]></description>
     *<fullName>AJAXTableauBody.setRowStyle</fullName>
     *<type>method</type>
     *<param name="JSONStyle">Style au format JSON</param>
     */
     setRowStyle: function(JSONStyle) {
         this.rowStyle = JSONStyle
         this.rows.refreshCss()

     },
     /**<description><![CDATA[Affecte les lignes altnernate du body avec une class Css.]]></description>
     *<fullName>AJAXTableauBody.setRowAlternateClassName</fullName>
     *<type>method</type>
     *<param name="className">Nom de la classe (string)</param>
     */
     setRowAlternateClassName: function(className) {
         this.rowAlternateClassName = className
         this.rows.refreshCss()
     },

     /**<description><![CDATA[Affecte les lignes alternate du body avec un style Css.]]></description>
     *<fullName>AJAXTableauBody.setRowAlternateStyle</fullName>
     *<type>method</type>
     *<param name="JSONStyle">Style au format JSON</param>
     */
     setRowAlternateStyle: function(JSONStyle) {
         this.rowAlternateStyle = JSONStyle
         this.rows.refreshCss()
     },

     /**<description><![CDATA[Efface le contenu du body]]></description>
     *<fullName>AJAXTableauBody.clear</fullName>
     *<type>method</type>
     */
     clear: function() {
         this.rows.clear()
         this.elementBody.update()
     },

     /**<description><![CDATA[deplace le scroller horizontal de px pixels]]></description>
     *<fullName>AJAXTableauBody.scrollHorToPix</fullName>
     *<type>method</type>
     *<param name="px">Nombre de pixels (int)</param>
     */
     scrollHorToPix: function(px) { // deplace le curseur horizontal de px pixels
         if (isNaN(px)) return
         this.container.scrollLeft = px
     },

     /**<description><![CDATA[deplace le scroller horizontal pour atteindre la colonne spécifiée]]></description>
     *<fullName>AJAXTableauBody.scrollHorToColumn</fullName>
     *<type>method</type>
     *<param name="columnFieldName">Nom du champ de la colonne à atteindre.</param>
     */
     scrollHorToColumn: function(columnFieldName) {
         if (!columnFieldName) return
         var c = this.parent.columns.getColumnByField(columnFieldName)
         var index = this.parent.columns.indexOf(c)
         var l = this.elementBody.rows[0]
         var w = 0
         for (var i = 0; i < index; i++) { w += l.cells[i].clientWidth }
         this.scrollHorToPix(w)
     },


     /**<description><![CDATA[Dans le cadre du LOD, calcul le nombre de lignes récupérer et leur index]]></description>
     *<fullName>AJAXTableauBody.getIndexLinesToDisplay</fullName>
     *<type>method</type>
     *<param name="row">Ligne JSON de référence.</param>
     *<encapsulation>private</encapsulation>
     *<return>index min et max {min:x, max:y}</return>
     */
     getIndexLinesToDisplay: function(row) {
         var h = this.elementDiv.getHeight()
         var t = this.elementDiv.scrollTop

         var s = parseInt((h / this.loadOnDemandRowHeight)) + 10
         var aList = new Array()
         var jResult

         if (!row) { // aucune ligne .. premier accès.
             jResult = { min: 1, max: s }
         } else if (row.typeOf == 'AJAXTableauFillingRow') {
             var mini = parseInt((t - row.element.clientTop) / this.loadOnDemandRowHeight)
             jResult = { min: mini, max: mini + s }
         } else {
             jResult = { min: row.rowNumber + 1, max: row.rowNumber + 1 + s }
         }

         for (var i = jResult.min; i <= jResult.max; i++) { aList.push(i) }
         aList = this.rows.getMissingRowsByRowNumber($A(aList))

         jResult.min = aList.first(); jResult.max = aList.last()

         return jResult

     }
 }
 

 
 var AJAXTableauRows = Class.create()
 AJAXTableauRows.prototype = {
     initialize: function(JSONRows, parent) {
         var a = new Array()
         Object.extend(this, $A(a))
         this['push'] = a['push']
         this['length'] = a['length']
         this['indexOf'] = a['indexOf']
         this['splice'] = a['splice']
         this['slice'] = a['slice']
         this.parent = parent // body
         if (JSONRows) this.addRange(JSONRows)

     },

     add: function(JSONRow, specialInsert) {
     
         var r = (JSONRow.typeOf) ? JSONRow : new AJAXTableauRow(JSONRow, this, specialInsert)
         if (!specialInsert) { this.push(r); return r }
         
         

         var index = this.indexOf(specialInsert.element)
         switch (specialInsert.position) {
             case 'after':
                 index++;
                 if (index == this.length - 1) { this.push(r); return r }
                 break;
             case 'before': break;
             case 'top': index = 0; break;
             case 'bottom': index = this.length; break;
         }

         var tabA = this.slice(0, index)
         tabA.push(r)
         tabB = this.splice(index, this.length)
         var tabC = $A(tabA.concat(tabB))

         this.clear()
         tabC.each(function(node) { this.push(node) } .bind(this))

         return r
     },

     addRange: function(JSONRows, min, max) {
         var l = JSONRows.length
         var sb = this.parent.parent.statusBar
         var gn //pour savoir quand on change de group de rupture
         var r
         if (!max) max = JSONRows.length - 1
         if (!min) min = 0

         var insertFillingRow
         var insertPoint

         for (var i = min; i <= max; i++) {
             var node = JSONRows[i]

             if ((node.rowNumber % 2) == 0) node.isAlternate = true

             if (this.parent.loadOnDemand == true) {
                 if (JSONRows[0].rowNumber == 1) {
                     r = this.add(node)
                 } else {
                     if (i == min) {
                        insertPoint = this.getInsertPointRow(JSONRows)
                        insertFillingRow = insertPoint.element
                     }
                     r = this.add(node, insertPoint)
                     insertFillingRow.rowNumber.from = r.rowNumber + 1
                     insertFillingRow.calcHeight()
                 }
                 
             } else {
                 r = this.add(node, insertPoint)   
             }

             if (typeof this.parent.parent.afterRowBinded == 'function') this.parent.parent.afterRowBinded(this.parent.parent, r)

             if (this.parent.groupByField) {

                 if (node.groupName) {
                     if (gn != node.groupName) {
                         if (gn) { // Après que le group soit remplis
                             if (typeof this.parent.parent.onAfterBuildGroup == 'function') this.parent.parent.onAfterBuildGroup(this.parent.parent, gn)
                         }
                         gn = node.groupName;
                         if (typeof this.parent.parent.onBeforeBuildGroup == 'function') this.parent.parent.onBeforeBuildGroup(this.parent.parent, gn) // début de remplissage de groupe  --> gn
                     }
                     this.parent.groups.add(node.groupName, r)
                 }

                 if (i == JSONRows.length - 1 && node.groupName) if (typeof this.parent.parent.onAfterBuildGroup == 'function') this.parent.parent.onAfterBuildGroup(this.parent.parent, gn)
             }
         }

         if (this.parent.loadOnDemand == true) {

             // voir comment retailler le bloc suivant.

             if (!insertFillingRow) { // si InsertFillingRow == null on est forcément en phase de création
                 var fr = new AJAXTableauFillingRow({
                     className: this.parent.loadOnDemandFillingRowClassName,
                     specialInsert: { element: r, position: 'after' },
                     rowNumber: { from: r.rowNumber + 1, to: this.parent.nbRows }
                 }, this)

                 fr.calcHeight()
             }
         }


         if (max >= JSONRows.length - 1) { window.clearInterval(this.parent.smartDisplay);this.parent.endOfLoading() }
     },

     breakFillingRow: function(fr, node) {
         var nfr = new AJAXTableauFillingRow({
             className: this.parent.loadOnDemandFillingRowClassName,
             specialInsert: { element: fr, position: 'after' },
             rowNumber: { from: node.rowNumber + 1, to: fr.rowNumber.to }
         }, this)

         fr.rowNumber.to = node.rowNumber - 1
         fr.calcHeight()
         nfr.calcHeight()

         return nfr
     },

     getInsertPointRow: function(JSONRows) {
     
        var insertPoint
     
        insertFillingRow = this.getLoadOnDemandInsertPoint(JSONRows[0].rowNumber);
        if (insertFillingRow.rowNumber.from == JSONRows[0].rowNumber) {
             // insertion avant un bloc de remplissage...  On ajoute à la suite d'une liste existante.
             insertPoint = { element: insertFillingRow, position: 'before' }
         } else {
             // insertion au milieu d'un bloc de remplissage. Il faut le scinder.
             insertFillingRow = this.breakFillingRow(insertFillingRow, JSONRows[0])
             insertPoint = { element: insertFillingRow, position: 'before' }
         }

         return insertPoint
   
     },

     refreshCss: function() {
         var i = -1
         this.each(function(c) {
             i++
             c.isAlternate = ((c.rowNumber % 2) == 0) ? true : false
             if (c.isAlternate) {
                 c.setClassName(this.parent.rowAlternateClassName)
                 c.setStyle(this.parent.rowAlternateStyle)
             } else {
                 c.setClassName(this.parent.rowClassName)
                 c.setStyle(this.parent.rowStyle)
             }
         } .bind(this))
     },

     removeRow: function(r) {
         var i = this.getIndex(r)
         if (i < 0) { throw 'une erreur s\'est produite.'; return }
         this.parent.selectedRows.remove(r)
         r.element.remove()
         this.splice(i, 1)
         this.parent.parent.statusBar.setChargement((this.parent.nbRows - 1) + ' lignes')
     },

     clear: function() { while (this.length > 0) this.remove(this[0]) },

     getIndex: function(r) { // renvoie la position de la ligne dans la collection rows du body

         for (var i = 0; i < this.length; i++) { if (r == this[i]) return i }
         return -1
     },

     getRowByDatakey: function(datakey) {
         for (var i = 0; i < this.length; i++) {
             if (this[i].datakey == datakey) return this[i]
         }

         return null
     },

     getLoadOnDemandInsertPoint: function(rowNumber) {

         for (var i = 0; i < this.length; i++) {
             var r = this[i]
             if (r.rowNumber == rowNumber) return r
             if (r.typeOf == 'AJAXTableauFillingRow') {
                 if (rowNumber >= r.rowNumber.from && rowNumber <= r.rowNumber.to) return r
             }
         }

         return
     },

     getMissingRowsByRowNumber: function(aList) {
         for (var i = 0; i < this.length; i++) {
             var r = this[i]
             aList = aList.without(r.rowNumber)
         }

         return aList
     }
 }

 AJAXTableauFillingRow = Class.create({
     initialize: function(params, parent) {
         this.typeOf = 'AJAXTableauFillingRow'
         this.parent = parent // AJAXTableauRows
         this.parentBody = this.parent.parent
         this.parentTableau = this.parentBody.parent
         this.height = 0
         this.element = null
         this.className = params.className
         this.rowNumber = params.rowNumber

         var specialInsert = params.specialInsert

         if (specialInsert) { this.render(); this.insertElement(specialInsert) }
     },

     render: function() {
         var tr = new Element('TR',  { style: 'height:' + this.height + 'px' })
         if (this.className) tr.addClassName(this.className)
         for (var i = 0; i < this.parentTableau.columns.length; i++) {
             var c = new Element('TD')
             //if (i == 0) { c.setStyle({ width: '15px', display: 'none' }) }
             tr.insert(c)
         }

         this.element = tr

     },

     setHeight: function(h) {
         if (!this.element) return
         this.height = h
         this.element.style.height = this.height + 'px'
         //$A(this.element.cells).each(function(c) { c.setStyle({ height: h + 'px' }) })
     },

     calcHeight: function() {
         var h = (this.rowNumber.to - this.rowNumber.from) * this.parentBody.loadOnDemandRowHeight
         this.height = h
         this.element.setStyle({ height: h + 'px' })
         //$A(this.element.cells).each(function(c) { c.setStyle({ height: h + 'px' }) })
     },


     insertElement: function(specialInsert) {
         // Insertion dans le Dom

         if (!specialInsert) {
             this.parentBody.element.insert(this.element)
             this.parent.push(this)
         }

         var el = specialInsert.element.element

         thisElement = this.element

         switch (specialInsert.position) {
             case 'after': el.insert({ after: thisElement }); break;
             case 'before': el.insert({ before: thisElement }); break;
             case 'top': el.insert({ top: thisElement }); break;
             case 'bottom': el.insert({ bottom: thisElement }); break;
         }

         this.parent.add(this, specialInsert) // Insertion de l'objet dans la collection de ligne

     }
 })

 /** <description>Crée et gère une ligne du tableau</description>
 * <fullName>AJAXTableauRow</fullName>
 * <type>class</type>
 */
 AJAXTableauRow = Class.create()
 AJAXTableauRow.prototype = {
     initialize: function(JSONobject, parent, specialInsert) {
         this.typeOf = 'AJAXTableauRow'/**<description>renvoi le type de l'objet</description><fullName>AJAXTableauRow.typeOf</fullName><type>property</type> */
         this.isAlternate = false /**<description>Indique si la ligne est alternée (boolean)</description><fullName>AJAXTableauRow.isAlternate</fullName><type>property</type>*/
         this.cells = null/**<description>AJAXTableauCells qui composent la ligne</description><fullName>AJAXTableauRow.cells</fullName><type>property</type>*/
         this.elementCells = null /**<description>Collection de HTMLCell qui composent la ligne</description><fullName>AJAXTableauRow.elementCells</fullName><type>property</type>*/
         this.element /**<description>HTML Row</description><fullName>AJAXTableauRow.element</fullName><type>property</type>*/
         this.isSelected = false/**<description>Indique si la ligne est sélectionnée. (boolean)</description><fullName>AJAXTableauRow.isSelected</fullName><type>property</type>*/
         this.isFooter = null/**<description>Indique si la ligne est dans le pied du tableau (boolean)</description><fullName>AJAXTableauRow.isFooter</fullName><type>property</type>*/
         this.datakey = null /**<description>Renvoie la clé primaire de la ligne</description><fullName>AJAXTableauRow.datakey</fullName><type>property</type>*/
         this.rowNumber = null /**<description>Renvoie le numéro de la ligne par rapport à l'ensemble des lignes renvoyées par la requete globale</description><fullName>AJAXTableauRow.rowNumber</fullName><type>property</type>*/
         this.parentRows = null/**<description>Fait référence à l'AJAXTableauRows qui contient la ligne</description><fullName>AJAXTableauRow.parentRows</fullName><type>property</type>*/
         this.parentBody = null/**<description>Fait référence à l'AJAXTableauBody qui contient la ligne</description><fullName>AJAXTableauRow.parentBody</fullName><type>property</type>*/
         this.className = null/**<description>Class Css appliqué à la ligne</description><fullName>AJAXTableauRow.className</fullName><type>property</type>*/
         this.isGroup = false/**<description>Spécifie si la ligne est une rupture</description><fullName>AJAXTableauRow.isGroup</fullName><type>property</type><obsolete>true</obsolete>*/
         if (JSONobject) { for (var property in JSONobject) this[property] = JSONobject[property]; }
         if (parent) { this.parentRows = parent; this.parentBody = this.parentRows.parent; this.parentTable = this.parentBody.parent }
         this.cells = new AJAXTableauCells(this)
         if (JSONobject) this.render(JSONobject, specialInsert)

     },

     getElement: function(specialInsert) {
         // specialInsert --> {element:AJAXTableauRow, position:'top', 'bottom', 'after', 'before'}

         if (this.element) return this.element
         this.element = new Element('TR')

         if (specialInsert && specialInsert.element) {
             var el = specialInsert.element.element
             try {
                 switch (specialInsert.position) {
                     case 'after': el.insert({ after: this.element }); break;
                     case 'before': el.insert({ before: this.element }); break;
                     case 'top': el.insert({ top: this.element }); break;
                     case 'bottom': el.insert({ bottom: this.element }); break;
                 }
             } catch (e) {
                 this.parentRows.parent.elementBody.insert(this.element)
             }
         } else {
             this.parentRows.parent.elementBody.insert(this.element)
         }

         if (this.isAlternate) {
             this.setClassName(this.parentBody.rowAlternateClassName)
             this.setStyle(this.parentBody.rowAlternateStyle)
         } else {
             this.setClassName(this.parentBody.rowClassName)
             this.setStyle(this.parentBody.rowStyle)
         }

         if (this.isGroup == true) {
             if (this.parentBody.rowGroupClassName) this.setClassName(this.parentBody.rowGroupClassName)
             if (this.parentBody.rowGroupStyle) this.setStyle(this.parentBody.rowGroupStyle)
         }

         this.element.observe('mouseout', function(e) {

             this.element.removeClassName(this.parentBody.rowOverClassName)

             if (this.isSelected) {
                 this.setStyle(this.parentBody.rowSelectedStyle);
                 return
             }

             if (this.isAlternate) {
                 this.setStyle(this.parentBody.rowAlternateStyle)
             } else {
                 this.setStyle(this.parentBody.rowStyle)
             }
         } .bindAsEventListener(this))


         this.element.observe('dblclick', function(e) {
             if (typeof this.parentBody.parent.onRowDoubleClick == 'function') {
                 if (this.isGroup == false) this.activate(e)
             }

             if (this.parentTable.isEditable) {
                 var el = $(e.target)
                 if (el.tagName != 'TD') el = e.findElement('TD')
                 var index = $A(this.element.cells).indexOf(el)
                 var cell = this.cells[index]
                 var col = cell.column
                 if (col.format) col.format.editor.render(cell)

             }

             if (typeof this.parentBody.parent.onRowDoubleClick == 'function') this.parentBody.parent.onRowDoubleClick(this.parentBody.parent, this, e)

         } .bindAsEventListener(this))

         this.element.observe('click', function(e) {

             if (typeof this.parentBody.parent.onRowClick == 'function') this.parentBody.parent.onRowClick(this.parentBody.parent, this, e)

             if (this.isGroup == false && !this.isFooter) this.activate(e)

         } .bindAsEventListener(this))

         return this.element
     },

     activate: function(e) {

         this.parentTable.initGroupeLinked()

         var ctrl = ''
         if (e) {
             if (e.shiftKey) ctrl = 'SHIFT'
             if (e.ctrlKey) ctrl = 'CTRL'
         }


         if (!this.parentBody.allowMultiSelectRows) {
             this.parentBody.selectedRows.setRow(this)
             return
         }

         if (e) { if (e.target.tagName == 'IMG' && e.target.name == '__selector__' && !e.shiftKey) ctrl = 'CTRL' }

         if (ctrl == 'SHIFT') {
             this.parentBody.selectedRows.shiftAdd(this)
         } else if (ctrl == 'CTRL') {
             this.parentBody.selectedRows.add(this)
         } else {
             this.parentBody.selectedRows.setRow(this)
         }
     },

     render: function(JSONObject, specialInsert) {
         if (this.isGroup == true) {
             this.element = this.parentBody.groups.getGroupRow(this);
             return
         }
         
         this.getElement(specialInsert)
         this.cells.addRange(JSONObject.cells)
         
         if (this.parentBody.selectedRows) {
             if (this.parentBody.selectedRows.selectAll == true) {
                 this.element.addClassName(this.parentBody.rowSelectedClassName)
                 if (this.parentBody.rowSelectedStyle) this.element.setStyle(this.parentBody.rowSelectedStyle)
                 if (this.parentBody.parent.selectorColumnIndex > -1) this.cells[this.parentBody.parent.selectorColumnIndex].displayControl.setCheck(true)
             }
         }
     },

     setClassName: function(className) {
         if (!className) className = ''
         this.element.className = className;
         this.className = className
     },

     setStyle: function(JSONStyle) {
         if (!JSONStyle) return
         this.style = JSONStyle;
         this.element.setStyle(this.style)
     },

     select: function(selector) {
         return this.element.select(selector)
     },

     remove: function() {
         this.parentRows.removeRow(this)
     },

     hide: function() { this.element.hide() },
     show: function() { this.element.show() },

     syncAjaxControl: function(ac, values) {
         // Synchronise l'une des cellule de la ligne avec les valeurs de ac -- AjaxControl
         var c
         ac.fields.each(function(el) {
             c = this.cells.getCellByField(el.value)
             if (c) return
         } .bind(this))

         if (!c) return
         c.setValue(values)
     }
 }

AJAXTableauCells = Class.create()
AJAXTableauCells.prototype = {
initialize: function(parent) {
    this.typeOf = 'AJAXTableauCells'
    var a = new Array() 
    Object.extend(this,$A(a))
    this['push'] = a['push']
    this['length'] = a['length']
    this['indexOf'] = a['indexOf']
    this.parentRow = null
    if(parent){ this.parent = parent } //parent est la ligne
    this.parentRow = parent
},

add:function(JSONCell){
    this.push(new AJAXTableauCell(JSONCell, this))    
},

addRange:function(JSONCells){

//   var c = {value:'th'}
//   this.add(new AJAXTableauCell(c, this, this.parentRow.parentBody.parent.columns[0])) 
  
    for (var i=0;i< JSONCells.length; i++){
        this.add(new AJAXTableauCell(JSONCells[i], this, this.parentRow.parentBody.parent.columns[i]))
    }
},

getCellByField:function(field){
    field = field.toLowerCase()
    for (var i=1; i<this.length; i++){
        try {
            if (this[i].column.field.toLowerCase() == field) return this[i]
        } catch(e){}
    }
    return undefined
 },
 
 getColumnByField:function(field){
    for (var i=0; i<this.length; i++){if (this[i].column.field == field) return this[i].column}
    return undefined
 }
}
 
 var AJAXTableauCell = Class.create()
 AJAXTableauCell.prototype = {
     initialize: function(JSONObject, parent, AJAXColumn) {
         this.typeOf = 'AJAXTableauCell'
         this.column = AJAXColumn
         this.text = null
         this.value = null
         this.values = null
         this.element = null
         this.parentCells = null
         this.colspan = null
         if (JSONObject) { for (var property in JSONObject) this[property] = JSONObject[property]; }
         if (parent) { this.parentCells = parent; this.parentRow = this.parentCells.parentRow; this.parentBody = this.parentRow.parentBody; this.parentTable = this.parentBody.parent }
         if (this.column) {
             this.className = this.column.className
             this.style = this.column.style
             this.wrap = this.column.bodyWrap
         }

         if (JSONObject) this.values = $H(JSONObject)

         if (JSONObject) this.getElement()
     },

     getElement: function(cIndex) {
         
         if (this.element) return this.element
         if (!cIndex) cIndex = -1

         var ta = this.parentCells.parentRow.parentBody.parent
         var td

         td = $(this.parentCells.parentRow.element.insertCell(cIndex))
         //if (this.colspan) td.colSpan = this.colspan
         if (this.column.bodyClassName) td.className = this.column.bodyClassName
         if (this.column.bodyStyle) td.setStyle(this.column.bodyStyle)
         td.style.overflow = 'hidden'

         if (this.column.field && (this.column.field == this.parentBody.groupByField) && this.parentRow.isGroup == true) { td.colSpan = this.column.parent.length - 1 }

         if (this.column.isVisible == false) td.setStyle({ display: 'none', width: '0px' })

         if (this.column.field) {
             if (this.column.field == this.parentBody.groupByField && this.parentRow.isGroup == false) td.setStyle({ display: 'none', width: '0px' })
         }

         this.element = td

         this.setValue(this.values)
         
         return this.element
     },

     setValue: function(el) {

         if (!Object.isHash(el)) el = $H(el)



         if (this.column.format) { // Affichage pris en compte par les Format
             this.values = el

             if (!this.displayControl) {
                 this.setDisplayControl(el)
             } else {
                 this.displayControl.setValue(el)
             }

         } else { // pas de format.
             if (!el && !this.values) return
             //if (el) {this.value = el.value; this.text = el.text} else {this.value='';this.text = ''} // Affectation des valeurs si pas de format !
             if (el) {
                 this.values = el;
                 this.value = this.values.get('value');
                 this.text = this.values.get('text');
             } else {
                 this.values.set('text', '');
                 this.values.set('value', '');
                 this.text = ''; this.value = '';
             }

             if (!this.editMode) this.element.update()

             if (this.column.bodyWrap == false) {
                 var nbr = document.createElement('NOBR')
                 nbr.appendChild(document.createTextNode(this.values.get('text')))
                 this.element.appendChild(nbr)
                 this.element.title = this.values.get('text')
             } else {
                 this.element.appendChild(document.createTextNode(this.values.get('text')))
             }
             this.editMode = false
         }

     },

     setValues: this.setValue,

     syncWithGroupe: function() {

         if (this.parentTable.groupeLinked) {
             this.parentTable.initGroupeLinked() // synchronise les infos entre le la ligne et le groupe.
             this.parentTable.groupeLinked.syncFromTable(this)
         }
     },

     select: function(selector) {
         return this.element.select(selector)
     },

     setColspan: function(colspan) {
         if (!colspan) { this.element.colspan = ''; this.colspan = ''; return }
         this.colspan = colspan
         this.element.colspan = colspan
     },

     setDisplayControl: function(el) {
         this.displayControl = this.column.format.getDisplayControl(el, this)
     },

     getNextEditableCell: function() {
         var c = this.getNextCell()
         if (!c) return
         while (!c.column.format || c.column.isReadOnly == true) {
             c = c.getNextCell()
         }
         return c
     },

     getNextCell: function() {
         var index = this.getIndex()
         if (index < this.parentCells.length - 1) {
             return this.parentCells[index += 1]
         } else {
             var rs = this.parentRow.parentRows
             var indexRow = rs.getIndex(this.parentRow)
             if (indexRow == rs.length - 1) return null
             indexRow += 1
             return rs[indexRow].cells[1]
         }
     },

     getIndex: function() { return this.parentCells.indexOf(this) },


     clear: function() { this.element.update() }

 }



 /**<description>Construit et gère les entetes de tableau</description>
 * <fullName>AJAXTableauHeader</fullName>
 * <type>class</type>
 */ 
var AJAXTableauHeader = Class.create()
AJAXTableauHeader.prototype = {
    initialize: function(JSONObject, parent) {
        this.className = null
        this.rowClassName = null
        this.rowStyle = null
        this.style = null
        this.isFixed = false
        for (var property in JSONObject) this[property] = JSONObject[property];
        if (parent) this.parent = parent // Parent est objet principal
        this.elementHead = null
        this.elementTable = null
        this.elementDiv // element contenant le header.
        this.elementRow = null // Ligne qui contient réellement l'entete
    },

    render: function() {

        this.getTableElement()

        this.elementTable.observe('click', function(e) {
            if (!e.findElement('THEAD')) return
            var td = e.findElement('TD')
            if (!td) return

            if (e.target.tagName == 'INPUT') return  // on clique dans un textBox.
            if (e.target.tagName == 'IMG' && e.target.name == 'filter') return // on click sur le filtre
            if (e.target.tagName == 'IMG' && e.target.name == '__selector__') return // click sur un selector

            var index = $A(this.elementTable.rows[1].cells).indexOf(td)
            var c = this.parent.columns[index]

            if (!c.isSortable) return
            if (c.sorted > 0) { c.sorted = (c.sorted == 1) ? 2 : 1 } else c.sorted = 1
            this.parent.columns.each(function(node) { if (node != c) node.sorted = 0 })

            var params = 'sortedField=' + (index) + '' + '&sorted=' + c.sorted

            if (this.parent.body.loadOnDemand == true) this.parent.initLOD()

            this.parent.dataBind(params, null, null, true)

        } .bindAsEventListener(this))

        var d1 = new Element('DIV')
        d1.setStyle({ width: '100%', overflow: (!this.isFixed) ? 'auto' : 'hidden', display: 'block', clear: 'both' })

        var cellMargin = (!Prototype.Browser.IE) ? (this.parent.cellSpacing * 2 * -1) + 'px' : (this.parent.cellSpacing * -1) + 'px'

        if (this.isFixed) {

            var d2 = new Element('DIV')

            d1.appendChild(d2)
            var t = this.elementTable
            d2.appendChild(this.elementTable)
            d2.setStyle({ marginTop: cellMargin })
            this.elementDiv = d1

        } else {// l'entete n'est pas fixe
            d1.appendChild(this.elementTable)
            d1.setStyle({ marginTop: cellMargin })
            this.parent.container.setStyle({ overflow: 'auto' })
            this.elementDiv = d1
        }

        this.parent.container.appendChild(d1)
    },

    getTableElement: function() {
        if (this.elemenTable) return this.elementTable

        t = new Element('TABLE', { cellPadding: this.parent.cellPadding, cellSpacing: this.parent.cellSpacing })
        t.setStyle({ width: this.parent.width, tableLayout: 'fixed' })

        var th = new Element('THEAD', { className: (this.className) ? this.className : '' })
        t.insert(th)
        th.insert(this.parent.columns.getColGroupeElement())
        if (this.style) th.setStyle(this.style)
        this.elementHead = th


        var tr = $(th.insertRow(-1))
        if (this.rowClassName) tr.className = this.rowClassName
        if (this.rowStyle) tr.setStyle(this.rowStyle)
        tr.setStyle({ cursor: 'pointer' })
        this.elementRow = tr

        this.parent.columns.each(function(node) {
            var td = $(tr.insertCell(-1))
            if (node.headerClassName) td.className = node.headerClassName
            if (node.headerStyle) td.setStyle(node.headerStyle)
            if (node.isVisible == false) td.setStyle({ display: 'none' })
            if (node.field && (!node.isVisible || node.field == this.parent.body.groupByField)) td.setStyle({ display: 'none' })

            // si le format de la colonne est ajaxselector --> obtenir la checkbox !
            var tx
            var flag = true
            if (node.format) {
                if (node.format.typeOf == 'AJAXSelectorFormat') {
                    tx = node.format.getHeaderElement(node);
                    this.parent.selectorColumnIndex = node.getIndex()
                    this.parent.body.allowMultiSelectRows = true
                    flag = false
                }
            }

            if (flag == true) tx = new Element('NOBR').update(node.caption)
            
            td.insert(tx)
            tr.insert(td)
            if (node.filterType > -1) td.insert(node.filter.render())
        } .bind(this))

        this.elementTable = t
        return t
    },

    setOrderArrow: function() {
        // Positionne la fleche _AT_SORT... en dans la bonne entete en fonction de la colonne triée !

        if (!this.elementTable.select) return
        var imgs = this.elementTable.select('IMG[name="sort"]')

        imgs.each(function(node) {
            var p = node.parentNode
            p.removeChild(node)
        })

        for (var i = 0; i < this.parent.columns.length; i++) {
            var node = this.parent.columns[i]
            var th = $(this.elementTable.rows[1].cells[i])
            if (node.sorted > 0) {
                var im = (node.sorted == 1) ? _AT_SORTASC.cloneNode(true) : _AT_SORTDESC.cloneNode(true)
                im.name = "sort"
                //th.insert(im)
                th.down('NOBR').insert({ after: im })
                im.setStyle({ marginLeft: '3px' })
            }
        }
    }

}

/**<description><![CDATA[Gère le pied du tableau.</BR>
Cette zone est construite dans un DIV. A l'intérieur se trouve un tableau avec une ligne de gabari et un element de type footer.]]></description>
*<fullName>AJAXTableauFooter</fullName>
*<type>Class</type>
*/
var AJAXTableauFooter = Class.create()
AJAXTableauFooter.prototype = {
    initialize: function(JSONObject, parent) {
        this.className = null
        this.rowClassName = null
        this.rowStyle = null
        this.style = null
        this.isVisible = null
        for (var property in JSONObject) this[property] = JSONObject[property];
        if (parent) this.parent = parent // AJAXTAbleau
        this.element = null
        this.elementFooter = null
        this.elementBody = null
    },

    /**<description><![CDATA[Effectue le rendu de l'objet.]]></description>
    *<fullName>AJAXTableauFooter.render</fullName>
    *<type>method</type>
    <encapsulation>private</encapsulation>
    */
    render: function() {

        if (!this.element) {

            this.element = new Element('DIV', { style: "width:" + this.parent.width }) // div
            var t = new Element('TABLE', { cellPadding: this.parent.cellPadding, cellSpacing: this.parent.cellSpacing }) // table
            t.setStyle({ width: '100%', tableLayout: 'fixed' })
            this.element.insert(t) // insertion de la table dans le div
            var tg = new Element('TFOOT', { className: (this.className) ? this.className : '' }) // creation footer
            this.elementBody = tg
            t.insert(tg) // insertion footer dans le tableau
            if (this.style) tg.setStyle(this.style)
            this.parent.body.container.insert(this.element)
        }

        this.elementBody.update(); this.elementBody.insert(this.parent.columns.getColGroupeElement()) // vide le footer
        if (this.isVisible) { this.show() } else { this.hide() }
        this.parent.setPosition()
    },

    show: function() { this.isVisible = true; this.element.show() }, /**<description>Affiche le footer</description><fullName>AJAXTableauFooter.show</fullName><type>method</type> */
    hide: function() { this.isVisible = false; this.element.hide() }, /**<description>Masque le footer</description><fullName>AJAXTableauFooter.hide</fullName><type>method</type> */
    setClassName: function(className) { this.className = className; this.element.className = className }, /**<description>Assigne la feuille de style className sur le div qui contient l'élément et affecte la propirété className</description><fullName>AJAXTableauFooter.setClassName</fullName><type>method</type><param name="className">class css à appliquer</param> */
    setStyle: function(style) { this.style = style; if (style) this.element.setStyle(style) }, /**<description>Assigne le style css 'style' sur le div qui contient l'élément et affecte la propirété style</description><fullName>AJAXTableauFooter.setStyle</fullName><type>method</type><param name="style">style css à appliquer (JSON)</param> */
    setRowClassname: function(rowClassName) { this.rowClassName = rowClassName; this.elementBody.rows[0].className = rowClassName }, /**<description>Assigne la class Css sur la ligne du footer et affecte la propriété className de l'AJAXTableauRow</description><fullName>AJAXTableauFooter.setRowClassname</fullName><type>method</type><param name="className">Class css à appliquer</param> */
    setRowStyle: function(rowStyle) { this.rowStyle = rowStyle; if (rowStyle) $(this.elementBody.rows[0]).setStyle(rowStyle) }, /**<description>Assigne le Style Css sur la ligne du footer et affecte la propriété classStyle de l'AJAXTableauRow</description><fullName>AJAXTableauFooter.setRowStyle</fullName><type>method</type><param name="style">style css à appliquer (JSON)</param> */

    /**<description><![CDATA[Charge le contenu de la ligne.]]></description>
    *<fullName>AJAXTableauFooter.databind</fullName>
    *<type>method</type>
    <encapsulation>private</encapsulation>
    */
    databind: function(footerValues) {

        this.rows = new AJAXTableauRows(null, this)
        var r = this.rows.add(footerValues)
        r.isFooter = true
        
        for (var i = 0; i < this.parent.columns.length; i++) {
            var co = this.parent.columns[i]
            var c = r.cells[i]
            if (co.footerStyle) { c.element.setStyle(co.footerStyle); c.style = co.footerStyle}
        }

        if (typeof this.parent.onAfterFooterBinded == 'function') this.parent.onAfterFooterBinded(this.parent, r)
    }
}

 
var AJAXColumns = Class.create()
AJAXColumns.prototype = {
    initialize:function(JSONColumns, parent){
        var a = new Array()
        Object.extend(this,$A(a))
        this['push'] = a['push']
        this['length'] = a['length']
        if(parent) this.parent = parent // Tableau
        //this.add({width:this.parent.rowSelector.width, isSelector:true}) // Ajoute une cellule pour les rowSelector     
        if (JSONColumns) this.addRange(JSONColumns)
    },
        
    addRange:function(JSONColumns){
        $A(JSONColumns).each(function(node){this.add(node, this)}.bind(this))
    },
        
    add:function(JSONColumn){
        var c = new AJAXColumn(JSONColumn, this)
        this.push(c)
        return c
    },
        
    getColGroupeElement:function(){
        var cs = new Element('TR')
        cs.setStyle({height:'0px',backgroundImage:'none', backgroundColor:'transparent'})
        this.each(function(node){
            var c = node.getColElement()
            if(c)cs.insert(c)
        })
        return cs
    },
          
    getColumnByField:function(field){
        var result = null
        this.each(function(c){
            
        })
        return result
    },
         
    indexOf:function(col){
        for (var index=0; index<this.length; index ++){if (this[index] == col) return index}
    }
}
 
var AJAXColumn = Class.create()
AJAXColumn.prototype = {
    initialize: function(JSONColumn, parent) {
        //this.isSelector = false
        this.width = null
        this.isVisible = true
        this.bodyClassName = null
        this.headerClassName = null
        this.bodyStyle = null
        this.headerStyle = null
        this.caption = null
        this.field = null
        this.isDate = null
        this.nbDecimal = null
        this.isReadOnly = null
        this.isSortable = null
        this.bodyWrap = null
        this.parent = null // ajaxColumns
        this.filterType = -1

        for (var property in JSONColumn) this[property] = JSONColumn[property];

        this.format = null
        if (parent) this.parent = parent // --> Column
        if (this.filterType > -1) this.setEnableFilter(this.filterType)
        if (JSONColumn.format) { this.format = JSONColumn.format; this.format.init(this) }
    },

    getColElement: function() {

        var col = new Element('TD', {style:'height:0px'})
        if (this.width) { col.style.width = this.width } else { col.style.width = 'auto' }
        if (!this.isVisible) col.setStyle({ display: 'none', width: '15px' })

        if (this.field && (!this.isVisible || this.field == this.parent.parent.body.groupByField)) {  //masque la colonne si elle est marquée selector ou pas visible
            col.setStyle({ display: 'none', width: '15px' })
        }
        
        return col
    },

    setWidth: function(w) {
        this.width = w

        if (w == '0px' || w == '0%' || w == '0') { this.hide(); return } // si w=0 on masque la colonne

        var t = this.parent.parent
        var cgr = t.header.elementTable.firstDescendant().firstDescendant() //obtient la première ligne du header.
        cgr.childNodes[this.parent.indexOf(this)].setStyle({ width: w })

        if (t.header.isFixed) {
            var cgb = t.body.elementTable.firstDescendant().firstDescendant() //obtient la première ligne du TBODY
            cgb.childNodes[this.parent.indexOf(this)].setStyle({ width: w })
        }
    },

    show: function() {
        var index = this.parent.indexOf(this)
        var tab = this.parent.parent
        var cgr = tab.header.elementTable.firstDescendant()
        $A(cgr.rows).each(function(r) { r.cells[index].style.display = '' })

        this.isVisible = true
        if (tab.header.isFixed) {
            var cgb = tab.body.elementTable.firstDescendant()//obtient le body
            $A(cgb.rows).each(function(r) { r.cells[index].style.display = '' })
        }
    },

    hide: function() {
        var index = this.parent.indexOf(this)
        var tab = this.parent.parent
        var cgr = tab.header.elementTable.firstDescendant()
        $A(cgr.rows).each(function(r) { r.cells[index].style.display = 'none' })

        this.isVisible = false
        if (tab.header.isFixed) {
            var cgb = tab.body.elementTable.firstDescendant() //obtient le body
            $A(cgb.rows).each(function(r) { r.cells[index].style.display = 'none' })
        }
    },

    setCaption: function(text) {
        var index = this.parent.indexOf(this)
        var cgr = this.parent.parent.header.elementTable.firstDescendant()
        var td = cgr.rows[1].cells[index]
        this.caption = text
        td.innerHTML = ''
        var tx = new Element('NOBR')
        tx.innerHTML = this.caption
        td.insert(tx)
    },

    setEnableFilter: function(intVal) {
        this.filterType = parseInt(intVal)
        if (this.filter) { this.filter.remove(); this.filter = null; return }
        this.filter = new AJAXTableauFilter(this)
    },

    getIndex: function() {
        return this.parent.indexOf(this)   
    }
}
     
var AJAXTableauStatus = Class.create()
AJAXTableauStatus.prototype = {
    initialize:function(parent){
        this.style = null
        this.className=null
        this.visible=false
        this.parent = parent
        this.element = null
        this.render()
        this.progressBarValue = 0
    },
    
    render:function(){
        if (this.element) return this.element
        var ul = new Element('UL')
        this.className =(this.className)?this.className:'status'
        ul.className = this.className
        this.element = ul
        var liMarginHeight = (Prototype.Browser.IE)?'0px':'4px'
        //var li = new Element('LI')
        //this.chargement = li
        this.add('chargement')
        this.setChargement('Idle')
        //ul.appendChild(li)
        ul.hide()
    },
    
    show:function(){this.element.show(); this.visible=true; this.parent.setPosition()},
    hide:function(){this.element.hide(); this.visible=false; this.parent.setPosition()},
    
    setChargement:function(text){
        window.setTimeout(function(){
            this.chargement.update(text)
        }.bind(this), 1)
    },
    
    add:function(name, styles){
        var li = new Element('LI')
        if (styles) li.setStyle(styles)
        this[name] = li
        this.element.insert(li)
        return li
             
    },
        
    setStatusText:function(name, text){
        this[name].update(text)
    }

} 
 

 
/** <description>Gère les lignes sélectionnées d'un AJAXTableau</description>
<type>class</type>
<fullName>AJAXTableauSelectedRows</fullName>
*/ 
var AJAXTableauSelectedRows = Class.create()
AJAXTableauSelectedRows.prototype = {
    initialize: function(parent) { /**<description>Constructeur</description><fullName>AJAXTableauSelectedRows.initialize</fullName><param name="parent">Body</param> */
        // parent --> le body
        var a = new Array()
        a = $A(a)
        Object.extend(this, a)
        this['push'] = a['push']
        this['splice'] = a['splice']
        this['indexOf'] = a['indexOf']
        this['sort'] = a['sort']
        this['join'] = a['join']
        this['concat'] = a['concat']
        this['length'] = a['length']

        this.selectAll = false /**<description>Indique si toutes les lignes sont sélectionnées. Dans ce cas, les lignes ne sont pas réellement intégrées dans la collection, seul leur apparence est modifiée.</description><fullName>AJAXTableauSelectedRows.selectAll</fullName><type>property</type>*/

        this.parent = parent // --> Body
        this.parentTalbeau = this.parent.parent // --> Tableau /**<description>Tableau</description><fullName>AJAXTableauSelectedRows.parentTalbeau</fullName><type>property</type>*/


        this.rowClassName = parent.rowClassName /**<description>Class css à appliquer sur les lignes 'normale'</description><fullName>AJAXTableauSelectedRows.rowClassName</fullName><type>property</type>*/
        this.rowStyle = parent.rowStyle/**<description>style css à appliquer sur les lignes 'normale'</description><fullName>AJAXTableauSelectedRows.rowStyle</fullName><type>property</type>*/
        this.rowOverClassName = parent.rowOverClassName/**<description>Class css à appliquer au survol des lignes</description><fullName>AJAXTableauSelectedRows.rowOverClassName</fullName><type>property</type>*/
        this.rowOverStyle = parent.rowOverStyle/**<description>style css à appliquer au survol des lignes</description><fullName>AJAXTableauSelectedRows.rowOverStyle</fullName><type>property</type>*/
        this.rowSelectedClassName = parent.rowSelectedClassName/**<description>class css à appliquer sur les lignes sélectionnées</description><fullName>AJAXTableauSelectedRows.rowSelectedClassName</fullName><type>property</type>*/
        this.rowSelectedStyle = parent.rowSelectedStyle/**<description>style css à appliquer sur les lignes sélectionnées</description><fullName>AJAXTableauSelectedRows.rowSelectedStyle</fullName><type>property</type>*/
        this.rowAlternateClassName = parent.rowAlternateClassName/**<description>class css à appliquer sur les lignes 'alternate'</description><fullName>AJAXTableauSelectedRows.rowAlternateClassName</fullName><type>property</type>*/
        this.rowAlternateStyle = parent.rowAlternateStyle/**<description>style css à appliquer sur les lignes 'alternate'</description><fullName>AJAXTableauSelectedRows.rowAlternateStyle</fullName><type>property</type>*/

    },

    /**<description>supprime la sélection en cours et ajoute la ligne passée en paramètre</description>
    * <fullName>AJAXTableauSelectedRows.setRow</fullName>
    * <type>method</type>
    * <param name="ATRow">AJAXTableauRow à ajouter à la sélection</param>
    */
    setRow: function(ATRow) { // supprime la sélection en cours en sélectionne la ligne passée.
        this.clearSelection()
        this.add(ATRow)
        this.setGroupeRowsLink()
    },

    /**<description>Ajoute la ligne passée en paramètre à la sélection</description>
    * <fullName>AJAXTableauSelectedRows.add</fullName>
    * <type>method</type>
    * <param name="ATRow">AJAXTableauRow à ajouter à la sélection</param>
    */
    add: function(ATRow) { // Ajoute une ligne à la sélection
        this.selectAll = false
        if (this.indexOf(ATRow) > -1) { this.remove(ATRow); return }
        ATRow.isSelected = true
        this.push(ATRow);
        ATRow.element.addClassName(this.rowSelectedClassName)
        if (this.rowSelectedStyle) ATRow.setStyle(this.rowSelectedStyle)
        this.setGroupeRowsLink
        if (this.parentTalbeau.selectorColumnIndex > -1) {
            ATRow.cells[this.parentTalbeau.selectorColumnIndex].displayControl.setCheck(true)
        }
        if (typeof this.parent.parent.onSelectedRow == 'function') this.parent.parent.onSelectedRow(ATRow)
    },

    /**<description>Obtient les lignes situées entre la lignes clickées et la précédente lignes ajoutée et les ajoute dans la sélection.</description>
    * <fullName>AJAXTableauSelectedRows.shiftAdd</fullName>
    * <type>method</type>
    * <param name="ATRow">AJAXTableauRow qui sert de limite à la sélection à ajouter</param>
    */
    shiftAdd: function(ATRow) {
        if (this.length == 0) {
            this.setRow(ATRow)
            return
        }

        var index1 = this.parent.rows.indexOf(this[this.length - 1])
        var index2 = this.parent.rows.indexOf(ATRow)

        var minIndex = (index1 < index2) ? index1 + 1 : index2
        var maxIndex = (index1 < index2) ? index2 : index1 - 1

        for (var i = minIndex; i <= maxIndex; i++) { this.add(this.parent.rows[i]); }

        this.setGroupeRowsLink()

    },

    /**<description>Supprime de la sélection la ligne passée en paramètre</description>
    * <fullName>AJAXTableauSelectedRows.remove</fullName>
    * <type>method</type>
    * <param name="ATRow">AJAXTableauRow à supprimer</param>
    */
    remove: function(ATRow) { // supprime la ligne de la sélection en cours
        var index = this.indexOf(ATRow)
        if (index > -1) this.splice(index, 1)
        ATRow.isSelected = false
        ATRow.element.removeClassName(this.rowSelectedClassName)
        if (ATRow.isAlternate) {
            ATRow.element.removeClassName(this.rowSelectedClassName)
            ATRow.setStyle(this.rowAlternateStyle)
        }
        else {
            ATRow.setStyle(this.rowStyle)
        }

        if (this.parentTalbeau.selectorColumnIndex > -1) ATRow.cells[this.parentTalbeau.selectorColumnIndex].displayControl.setCheck(false)
        this.setGroupeRowsLink()

    },

    /** <description>Affecte la collection encours à la propriété AJAXTableau.groupeLinked.tableRowsLinked si l'objet existe</description>
    <fullName>AJAXTableauSelectedRows.setGroupeRowsLink</fullName>
    <type>method</type>
    <encapsulation>private</encapsulation>
    */
    setGroupeRowsLink: function() {
        if (!this.parentTalbeau.groupeLinked) return
        this.parentTalbeau.groupeLinked.tableRowsLinked = this
        this.parentTalbeau.groupeLinked.tableRowLinked = this[0]

    },

    /** <description>supprime les lignes de la base dont les datakeys sont passées en tableau</description>
    * <fullName>AJAXTableauSelectedRows.delRows</fullName>
    * <type>method</type>
    * <param name="dks">Array qui contient la liste des PK à supprimer</param>
    * <param name="ajaxHandler">handler alternatif</param>
    */
    delRows: function(dks, ajaxHandler) { // supprime les lignes de la base dont les datakeys sont passées en tableau

        var dks = $A(new Array())
        this.each(function(r) { dks.push(r.datakey) })

        if (dks.length == 0) { alert('Aucune ligne à supprimer'); return }

        if (!ajaxHandler) ajaxHandler = 'ajaxtableau.ajax'
        var flag = false
        var params = 'action=2&fr=' + this.parentTalbeau.fileRessource + '&pp=' + this.parentTalbeau.pagePath + '&cid=' + this.parentTalbeau.controlId + '&dks=' + dks.join(',')
        var a = new Ajax.Request(ajaxHandler, {
            method: 'post',
            postBody: params,
            asynchronous: false,
            onComplete: function(transport) {
                var r = transport.responseJSON
                if (!r.result) { alert(r.message); return }
                this.removeSelectionFromDocument()
                setGroupeRowsLink()
                if (typeof this.parentTalbeau.onAfterRowDeleted == 'function') { this.parentTalbeau.onAfterRowDeleted(this.parentTalbeau) }
            } .bind(this)
        })
    },

    /** <description>Supprime les lignes sélectionnées du tableau sans les supprimer de la base</description>
    * <fullName>AJAXTableauSelectedRows.removeSelectionFromDocument</fullName>
    * <type>method</type>
    */
    removeSelectionFromDocument: function() { // Supprime toutes les lignes du tableaux et efface la sélection en cours
        while (this.length > 0) { this[0].remove() }
        this.clear()
    },

    /** <description>Efface la sélection en cours en réajustant les fonds de ligne.</description>
    * <fullName>AJAXTableauSelectedRows.clearSelection</fullName>
    * <type>method</type>
    */
    clearSelection: function() {

        if (this.selectAll == true) {
            this.parent.rows.each(function(node) {
                if (node.typeOf == 'AJAXTableauRow') {
                    node.isSelected = false
                    node.element.removeClassName(this.rowSelectedClassName)
                    if (node.isAlternate) {
                        node.setStyle(this.rowAlternateStyle)
                    }
                    else {
                        node.setStyle(this.rowStyle)
                    }
                    if (this.parentTalbeau.selectorColumnIndex > -1) node.cells[this.parentTalbeau.selectorColumnIndex].displayControl.setCheck(false)
                }
            } .bind(this))
            this.selectAll = false
        }

        this.each(function(node) {
            node.isSelected = false
            node.element.removeClassName(this.rowSelectedClassName)
            if (node.isAlternate) {
                node.setStyle(this.rowAlternateStyle)
            }
            else {
                node.setStyle(this.rowStyle)
            }
            if (this.parentTalbeau.selectorColumnIndex > -1) node.cells[this.parentTalbeau.selectorColumnIndex].displayControl.setCheck(false)
        } .bind(this))


        this.clear()

        this.setGroupeRowsLink()
    },

    /** <description>Renvoie un tableau composé des clés primaires des lignes sélectionnées.</description>
    * <fullName>AJAXTableauSelectedRows.getDataKeys</fullName>
    * <type>function</type>
    * <return>taleau de string</return>
    */
    getDataKeys: function() {
        var a = $A(new Array())
        this.each(function(node) {
            a.push(node.datakey)
        })

        return a
    },

    setSelectAll: function(bSelAll) {

        if (bSelAll == false) { this.clearSelection(); this.selectAll = false; return }

        this.clearSelection
        this.parent.rows.each(function(r) {
            if (r.isGroup == false) {
                r.isSelected = true
                r.element.addClassName(this.rowSelectedClassName)
                if (this.rowSelectedStyle) r.setStyle(this.rowSelectedStyle)
                if (this.parentTalbeau.selectorColumnIndex > -1) r.cells[this.parentTalbeau.selectorColumnIndex].displayControl.setCheck(true)
            }
        } .bind(this))

        this.selectAll = true
    }
}

/** <description>Gère l'affichage des groupes et des ruptures.</description>
<fullName>AJAXTableauGroups</fullName>
<type>class</type>
*/
var AJAXTableauGroups = Class.create()
AJAXTableauGroups.prototype = {
    initialize: function(parent) {
        this.typeOf = 'AJAXTableauGroups'
        var a = new Hash()
        Object.extend(this, a)
        this.parent = parent // body
    },

    /** <description>Ajoute un groupe à la collection</description>
    <fullName>AJAXTableauGroups.add</fullName>
    <type>method</type>
    */
    add: function(groupName, r) {
        if (!this.get(groupName)) { this.set(groupName, $A(new Array())) }
        this.get(groupName).push(r)
    },

    /** <description>Affiche le groupe et les lignes qui en dépendent.</description>
    <fullName>AJAXTableauGroups.show</fullName>
    <type>method</type>
    */
    show: function(groupName) {
        var a = this.get(groupName)
        a.each(function(r) { r.show() })
    },

    /** <description>Inverse l'état de visibilité du groupe</description>
    <fullName>AJAXTableauGroups.toggle</fullName>
    <type>method</type>
    <param name="groupName">Label du groupe</param>
    <param name="img">Image HTML qui a généré l'évènement</param>
    */
    toggle: function(groupName, img) {
        if (img.src == _AT_PLUS.src) {
            this.show(groupName);
            img.src = _AT_MOINS.src
        } else {
            this.hide(groupName);
            img.src = _AT_PLUS.src
        }
    },


    /** <description>Masque le groupe et les lignes qui en dépendent.</description>
    <fullName>AJAXTableauGroups.hide</fullName>
    <type>method</type>
    */
    hide: function(groupName) {
        var a = this.get(groupName)
        a.each(function(r) { if (r.isGroup == false) r.hide() })
    },


    /** <description>Obtient le label du groupe</description>
    <fullName>AJAXTableauGroups.getLabel</fullName>
    <type>function</type>
    <param name="groupName">Nom du groupe</param>
    <return>Renvoie le label du groupe (string)</return>
    */
    getLabel: function(groupName) {
        var rs = this.get(groupName)
        if (rs) return rs[0].cells[0].text
        return null
    },

    /** <description>Définit le label du groupe</description>
    <fullName>AJAXTableauGroups.setLabel</fullName>
    <type>method</type>
    <param name="groupName">Nom du groupe</param>
    <param name="text">Text à affecter.</param>
    */
    setLabel: function(groupName, text) {
        var rs = this.get(groupName)
        rs[0].cells[0].setValue({ value: text, text: text })
    },

    /** <description>Crée un ligne de rupture</description>
    *   <fullName>AJAXTableauGroups.getGroupRow</fullName>
    *   <param name="AJAXRow">Définition de la ligne à ajouter au format JSON</param>
    *   <type>function</type>
    *   <return>Renvoie un HTMLElement de type TR</return>
    */
    getGroupRow: function(AJAXRow) {
        var tr = new Element('TR')
       

        var c = new Element('TD', { style: "verticalAlign: middle", colspan: AJAXRow.colspan })
        var moins = _AT_MOINS.cloneNode(true)
        moins.setStyle({ verticalAlign: 'middle' })
        c.insert(moins)

        moins.observe('click', function(e) { this.toggle(AJAXRow.groupName, e.target) } .bindAsEventListener(this))

        var nbr = new Element('NOBR').update(AJAXRow.groupName)
        c.insert(nbr)

        tr.insert(c)

        AJAXRow.parentBody.elementBody.insert(tr)

        if (this.parent.body.rowGroupClassName) tr.addClassName(this.parent.body.rowGroupClassName)
        if (this.parent.body.rowGroupStyle) tr.setStyle(this.parent.body.rowGroupStyle)

        return tr
    }
}


var AJAXTableauFilter = Class.create()
AJAXTableauFilter.prototype = {
    initialize: function(col) {
        this.column = col
        this.typeOf = 'AJAXTableauFilter'
        this.type = 'combo'
        this.elementText = null
        this.elementCombo = null
        this.comboClassName = 'table comboFilter'
        this.comboElement = null
        this.iconeElement = null
        this.value = ''
        this.parentTable = col.parent.parent
        this.filterType = col.filterType // -1: none / 0 : icone / 1: textbox
        this.timeOut

        var f = $(document.forms[0])
        if (this.comboElement) {
            this.comboElement.update()
        } else {
            this.comboElement = new Element('UL', { className: this.comboClassName })
            f.insert(this.comboElement)
        }

        this.comboElement.setStyle({ zIndex: '999999' })

        this.comboElement.observe('click', function(e) {
            this.value = (Prototype.Browser.IE) ? e.target.innerText : e.target.textContent
            if (this.filterType == 1) this.elementText.down('INPUT').value = this.value
            this.comboElement.hide()
            this.getDatas()
        } .bind(this))

        this.comboElement.observe('mouseover', function(e) {
            if (e.target.tagName == 'LI') e.target.addClassName('over')
            if (this.timeOut) { window.clearTimeout(this.timeOut); }
        } .bind(this))

        this.comboElement.observe('mouseout', function(e) {
            var s = this.comboElement
            if (e.target.tagName == 'LI') e.target.removeClassName('over')
            this.timeOut = window.setTimeout(function() { s.hide() }, 500)
        } .bind(this))

        this.comboElement.hide()

    },

    setColumn: function(col) { this.column = col },
    setType: function(type) { this.type = type },

    render: function() {
        if (this.filterType == 1) { return this.renderText() } else { return this.renderIcone() }
    },

    show: function() {

        this.fillCombo()

        var td
        if (this.filterType == 0) { td = this.iconeElement.parentNode } else { td = this.elementText.parentNode }

        var pos = td.cumulativeOffset()
        var dim = td.getDimensions()

        var mousePosition = { y: pos.top + dim.height, x: pos.left }

        this.comboElement.setStyle({ top: mousePosition.y + 'px', left: mousePosition.x + 'px' })

        this.comboElement.show()
        //new Effect.BlindDown(this.comboElement, {duration:0.5})

    },

    fillCombo: function(ajaxHandler) {
        var params = 'action=3&fr=' + this.parentTable.fileRessource + '&pp=' + this.parentTable.pagePath + '&cid=' + this.parentTable.controlId + '&colIndex=' + (this.column.parent.indexOf(this.column))
        // --> insertion des paramètres de sélection dans la requete
        //if (this.parentTable.params){this.parentTable.params.each(function(node){params += '&' + node.name + '=' + node.value})}

        for (var index = 0; index < this.parentTable.columns.length; index++) {
            var node = this.parentTable.columns[index]
            if (node.filterType > -1 && node.filter.value) {
                params += '&' + node.field + '=' + node.filter.value
            }
        }


        if (!ajaxHandler) ajaxHandler = 'ajaxtableau.ajax'
        this.comboElement.update()
        var a = new Ajax.Request(ajaxHandler, {
            method: 'post',
            postBody: params,
            onComplete: function(transport) {
                var r = transport.responseJSON
                this.comboElement.insert(new Element('LI').insert(new Element('NOBR').update('[Tous]')))
                for (var i = 0; i < r.items.length; i++) {
                    var li = new Element('LI')
                    li.insert(new Element('NOBR').update(r.items[i]))
                    this.comboElement.insert(li)
                    if (r.items[i] == this.value) li.addClassName('selected')
                }
            } .bind(this)
        })
    },

    mouseOnImage: function(e) {
        if (e.target.tagName != 'INPUT') return
        var txt = e.target
        var pos = txt.cumulativeOffset()
        var taille = txt.getDimensions()
        var posMouse = { left: 0, top: 0 }
        posMouse.left = e.pointerX() - pos.left
        if (posMouse.left > taille.width) posMouse.left = -1
        posMouse.top = e.pointerY() - pos.top
        if (posMouse.top > taille.height) posMouse.top = -1
        if (taille.width - posMouse.left < 18 && taille.width - posMouse.left > 0) {
            return true
        }
        return false
    },

    getDatas: function() { // recharge le tableau
        var params = ''
        if (this.value == '[Tous]') this.value = '-xxxxx'
        var ps = this.parentTable.params
        if (this.parentTable.body.loadOnDemand == true) {
            this.parentTable.initLOD()
        }
        this.parentTable.databind(params, null, null, true)
    },

    renderText: function() {
        this.elementText = new Element('DIV')
        this.elementText.setStyle({ width: '100%', textAlign: 'center' })
        var txt = new Element('INPUT', { type: 'text', text: this.value })
        txt.setStyle({ cursor: 'default', backgroundImage: 'url(' + _AT_CLOSE.src + ')', backgroundPosition: 'right', backgroundRepeat: 'no-repeat' })
        this.elementText.insert(txt)

        this.elementText.observe('click', function(e) {
            if (e.target.tagName == 'INPUT') {

                if (this.mouseOnImage(e)) {
                    if (this.filterType == 1) this.elementText.down('INPUT').value = ''
                    this.value = ''
                    this.getDatas()
                    this.comboElement.hide()
                    return
                }
                if (!this.comboElement.visible()) { this.show() } else { this.comboElement.hide() }
                return
            }
        } .bind(this))

        this.elementText.observe('mousemove', function(e) {
            if (this.mouseOnImage(e)) {
                txt.setStyle({ cursor: 'pointer' });
                return
            }
            txt.setStyle({ cursor: 'default' })
        } .bind(this))

        return this.elementText
    },

    renderIcone: function() {
        this.iconeElement = _AT_FILTER.cloneNode(true)
        this.iconeElement.name = 'filter'
        this.iconeElement.setStyle({ verticalAlign: 'middle' })
        this.iconeElement.observe('click', function(e) {
            this.show()
        } .bind(this))
        return this.iconeElement

    }
}


