// Copyright (c) 2006 Tafel, Fabien Tafelmacher // // See http://membres.lycos.fr/tafelmak/arbre.php for more info // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // This is distributed under Free-BSD licence. /* @todo ------------------ check-restore default gestion xml (load + save) multidrop scrolldrop */ /** *------------------------------------------------------------------------------ * TafelTree Class *------------------------------------------------------------------------------ */ var TAFELTREE_WRONG_BRANCH_STRUCTURE = "La structure de la branche n'est pas correcte. Il faut au moins un id et un texte"; var TAFELTREE_NO_BODY_TAG = "Il n'y a pas de balise BODY!"; var TAFELTREE_DEBUG = false; var TafelTree = Class.create(); /** * Fragment de script pour supprimer les lors du loadFromUL() */ //TafelTree.scriptFragment = /(?:)((\n|\r|.)*)*/img; TafelTree.version = '1.9.1'; TafelTree.lastUpdate = '2007-07-21'; TafelTree.scriptFragment = /[\s]*<[/]?[ul|li].*>.*/ig; TafelTree.debugReturn = '
'; TafelTree.debugTab = '    '; /** * Attributs des LI */ TafelTree.prefixAttribute = 'T'; TafelTree.textAttributes = [ TafelTree.prefixAttribute + 'img', TafelTree.prefixAttribute + 'imgopen', TafelTree.prefixAttribute + 'imgclose', TafelTree.prefixAttribute + 'imgselect', TafelTree.prefixAttribute + 'imgselectopen', TafelTree.prefixAttribute + 'imgselectclose', TafelTree.prefixAttribute + 'style', TafelTree.prefixAttribute + 'droplink', TafelTree.prefixAttribute + 'openlink', TafelTree.prefixAttribute + 'editlink', TafelTree.prefixAttribute + 'tooltip', TafelTree.prefixAttribute + 'title' ]; TafelTree.numericAttributes = [ TafelTree.prefixAttribute + 'canhavechildren', TafelTree.prefixAttribute + 'acceptdrop', TafelTree.prefixAttribute + 'draggable', TafelTree.prefixAttribute + 'editable', TafelTree.prefixAttribute + 'open', TafelTree.prefixAttribute + 'check', TafelTree.prefixAttribute + 'checkbox', TafelTree.prefixAttribute + 'select', TafelTree.prefixAttribute + 'last' ]; TafelTree.functionAttributes = [ TafelTree.prefixAttribute + 'onbeforecheck', TafelTree.prefixAttribute + 'oncheck', TafelTree.prefixAttribute + 'onclick', TafelTree.prefixAttribute + 'ondblclick', TafelTree.prefixAttribute + 'onbeforeopen', TafelTree.prefixAttribute + 'onopen', TafelTree.prefixAttribute + 'onedit', TafelTree.prefixAttribute + 'oneditajax', TafelTree.prefixAttribute + 'onmouseover', TafelTree.prefixAttribute + 'onmouseout', TafelTree.prefixAttribute + 'onmousedown', TafelTree.prefixAttribute + 'onmouseup', TafelTree.prefixAttribute + 'ondrop', TafelTree.prefixAttribute + 'ondragstarteffect', TafelTree.prefixAttribute + 'ondragendeffect', TafelTree.prefixAttribute + 'onerrorajax', TafelTree.prefixAttribute + 'ondropajax', TafelTree.prefixAttribute + 'onopenpopulate' ]; /** *------------------------------------------------------------------------------ * TafelTree static methods *------------------------------------------------------------------------------ */ /** * Constructeur d'un nouvel arbre via UL * * @access public * @param string id L'id de l'élément HTML conteneur * @param string imgBase Le path vers les images, ou les options * @param integer width La largeur de l'arbre * @param integer height La hauteur de l'arbre * @param object options Les options de génération * @return TafelTree L'arbre créé sur la base des UL - LI */ TafelTree.loadFromUL = function (id, imgBase, width, height, options, debug) { // 2006-11-25 : "options" est maintenant à la place de "imgBase" if (typeof(imgBase) == 'object') { options = imgBase; debug = width; imgBase = (options.imgBase) ? options.imgBase : 'imgs/'; width = (options.width) ? options.width : '100%'; height = (options.height) ? options.height : 'auto'; } // Suite var obj = $(id); var load = document.createElement('img'); load.setAttribute('title', 'load'); load.setAttribute('alt', 'load'); load.src = ((imgBase) ? imgBase : 'imgs/') + 'load.gif'; obj.parentNode.insertBefore(load, obj); Element.hide(obj); var tab = ''; var tabModel = (debug) ? TafelTree.debugTab : ''; var rt = (debug) ? TafelTree.debugReturn : ''; var virgule = ''; var str = (debug) ? 'var struct = [' : '(['; for (var i = 0; i < obj.childNodes.length; i++) { if (obj.childNodes[i].nodeName.toLowerCase() == 'li') { str += this._loadFromUL(obj.childNodes[i], virgule, rt, tab, tabModel); virgule = ','; } } str += rt + ((debug) ? '];' : '])'); var div = document.createElement('div'); div.id = obj.id; obj.id += '____todelete'; obj.parentNode.insertBefore(div, obj); if (!debug) { var m = TafelTree.prefixAttribute; var struct = eval(str); var _tree = new TafelTree(id, struct, options); } else { div.innerHTML = str.replace(/ 1) { this.cookieChecked = branches[1].split(this.cookieSeparator); } } // Instance de debug this.debugObj = document.createElement('div'); this.debugObj.setAttribute('id', this.classTree + '_debug'); Element.hide(this.debugObj); this.div.appendChild(this.debugObj); // Instance Ajax this.ajaxObj = document.createElement('div'); this.ajaxObj.setAttribute('id', this.classTree + '_ajax'); Element.hide(this.ajaxObj); this.div.appendChild(this.ajaxObj); Event.observe(this.div, 'mousedown', this.evt_setAsCurrent.bindAsEventListener(this), false); Event.observe(this.div, 'focus', this.evt_setAsCurrent.bindAsEventListener(this), false); // don't generate if cookie is on server side if (!this.serverCookie) { if (this.options.generate) { this.generate(); } if (this.options.generateBigTree) { this.generate(true); } } TafelTreeManager.add(this); }, /** *------------------------------------------------------------------------------ * TafelTree global events management *------------------------------------------------------------------------------ */ /** * Set l'arbre comme étant l'arbre courant * * Toutes les actions claviers auront effet seulement sur cet arbre et non sur les autres* * * @access public * @param Event ev L'événement déclencheur * @return void */ evt_setAsCurrent : function (ev) { var obj = Event.element(ev); TafelTreeManager.setCurrentTree(this); }, /** * Retourne une liste de branches ordrée (en fonction de leur position dans l'arbre) * * @access public * @param array list Un tableau de TafelTreeBranch * @return array Un tableau ordré de TafelTreeBranch */ orderListBranches : function (list) { var ordered = []; var level = []; var nivmin = 100; var nivmax = 0; // On ordre par niveau var niv = 0; for (var i = 0; i < list.length; i++) { niv = list[i].getLevel(); if (typeof(level[niv]) == 'undefined') { level[niv] = []; } level[niv].push(list[i]); if (niv > nivmax) nivmax = niv; if (niv < nivmin) nivmin = niv; } // On enlève le cheni de m... à cause de la gestion tableau javascript for (var i = nivmin; i <= nivmax; i++) { if (level[i]) { ordered.push(level[i]); } } // Pour chaque niveau, on ordre par position dans l'arbre // On ne récupère que les 1er niveaux. S'il y a des enfants, on les ignore return ordered; }, /** * Retourne les branches copiées de l'arbre, ou d'un arbre lié * * Si le tableau n'a pas de branches, la méthode va voir dans les arbres liés * pour récupérer les branches qui seraient copiées dans l'autre arbre * * @access public * @return array Les branches copiées */ getCopiedBranches : function () { var branches = this.copiedBranches; if (branches.length == 0) { for (var i = 0; i < this.otherTrees.length; i++) { branches = this.otherTrees[i].copiedBranches; if (branches.length > 0) break; } } return branches; }, /** * Retourne les branches coupées de l'arbre, ou d'un arbre lié * * Si le tableau n'a pas de branches, la méthode va voir dans les arbres liés * pour récupérer les branches qui seraient coupées dans l'autre arbre * * @access public * @return array Les branches coupées */ getCuttedBranches : function () { var branches = this.cuttedBranches; if (branches.length == 0) { for (var i = 0; i < this.otherTrees.length; i++) { branches = this.otherTrees[i].cuttedBranches; if (branches.length > 0) break; } } return branches; }, /** * Fonction qui coupe la sélection et la met dans un cache * * @access public * @return return True si ça coupe, false sinon */ cut : function () { this.unsetCut(); this.unsetCopy(); var level = this.orderListBranches(this.selectedBranches); //this.debug(level); var sel = null; for (var i = 0; i < level.length; i++) { for (var j = 0; j < level[i].length; j++) { sel = level[i][j]; this._cut(sel); this.cuttedBranches.push(sel); } } return true; }, /** * Fonction qui copie la sélection dans un cache * * @access public * @return return True si ça copie, false sinon */ copy : function () { this.unsetCut(); this.unsetCopy(); var level = this.orderListBranches(this.selectedBranches); var sel = null; for (var i = 0; i < this.selectedBranches.length; i++) { sel = this.selectedBranches[i]; this._copy(sel); this.copiedBranches[i] = sel; } return true; }, /** * Fonction qui colle le cache à l'endroit sélectionné. Il ne doit y avoir qu'une sélection * * @access public * @return return True si ça colle, false sinon */ paste : function () { if (this.selectedBranches.length != 1) return false; var branch = this.selectedBranches[0]; var copied = this.getCopiedBranches(); var cutted = this.getCuttedBranches(); var nbCopy = copied.length; var nbCut = cutted.length; if (nbCopy > 0) { var list = copied; var b = null; for (var i = 0; i < list.length; i++) { if (this._okForPaste(branch, list, i)) { b = branch.insertIntoLast(list[i].clone()); } } } if (nbCut > 0) { var list = cutted; for (var i = 0; i < list.length; i++) { if (this._okForPaste(branch, list, i)) { list[i].move(branch); } } } //this.unsetCopy(); this.unsetCut(); return true; }, /** * Détermine si on peut coller la partie courante du cache ou non * * @access private * @param TafelTreeBranch branch La branche dans laquelle on colle * @param array list Le tableau de cache ordré par niveau * @param integer i La position courante dans le cache * @return boolean True si on peut coller, false sinon */ _okForPaste : function (branch, list, i) { var ok = true; if (!branch.isChild(list[i])) { for (var j = 0; j < i; j++) { if (list[i].isChild(list[j])) { ok = false; break; } } } else { ok = false; } return ok; }, unsetCut : function () { // On enlève les branches coupées des autres arbres (suppression du "presse-papier") var _tree = null; var branches = null; for (var i = 0; i < this.otherTrees.length; i++) { _tree = this.otherTrees[i]; branches = _tree.cuttedBranches; for (var t = 0; t < branches.length; t++) { _tree._unsetCut(branches[t]); } _tree.cuttedBranches = []; } var cut = null; for (var i = 0; i < this.cuttedBranches.length; i++) { cut = this.cuttedBranches[i]; this._unsetCut(cut); } this.cuttedBranches = []; }, unsetCopy : function () { // On enlève les branches copiées des autres arbres (suppression du "presse-papier") var _tree = null; var branches = null; for (var i = 0; i < this.otherTrees.length; i++) { _tree = this.otherTrees[i]; branches = _tree.copiedBranches; for (var t = 0; t < branches.length; t++) { _tree._unsetCopy(branches[t]); } _tree.copiedBranches = []; } var copy = null; for (var i = 0; i < this.copiedBranches.length; i++) { copy = this.copiedBranches[i]; this._unsetCopy(copy); } this.copiedBranches = []; }, /** * Annule les [n] dernières actions (todo...) * * @access public * @return boolean True si quelque chose a été annulé */ undo : function () { }, /** *------------------------------------------------------------------------------ * TafelTree private keyboard methods *------------------------------------------------------------------------------ */ /** * Méthode récursive qui fait l'effet "couper" sur toutes les sous-branches * * @access private * @param TafelTreeBranch branch La branche courante * @return void */ _cut : function (branch) { if (!this.classCut) { new Effect.Opacity(branch.txt, { duration: 0.1, transition: Effect.Transitions.linear, from: 1.0, to: 0.4 }); new Effect.Opacity(branch.img, { duration: 0.1, transition: Effect.Transitions.linear, from: 1.0, to: 0.4 }); } else { Element.addClassName(branch.txt, this.classCut); Element.addClassName(branch.img, this.classCut); } if (branch.hasChildren()) { for (var i = 0; i < branch.children.length; i++) { this._cut(branch.children[i]); } } }, /** * Méthode récursive qui enlève l'effet "couper" sur toutes les sous-branches * * @access private * @param TafelTreeBranch branch La branche courante * @return void */ _unsetCut : function (branch) { if (!this.classCut) { new Effect.Opacity(branch.txt, { duration: 0.1, transition: Effect.Transitions.linear, from: 0.4, to: 1.0 }); new Effect.Opacity(branch.img, { duration: 0.1, transition: Effect.Transitions.linear, from: 0.4, to: 1.0 }); } else { Element.removeClassName(branch.txt, this.classCut); Element.removeClassName(branch.img, this.classCut); } if (branch.hasChildren()) { for (var i = 0; i < branch.children.length; i++) { this._unsetCut(branch.children[i]); } } }, /** * Méthode récursive qui fait l'effet "copier" sur toutes les sous-branches * * @access private * @param TafelTreeBranch branch La branche courante * @return void */ _copy : function (branch) { if (this.classCopy) { Element.addClassName(branch.txt, this.classCopy); Element.addClassName(branch.img, this.classCopy); } if (branch.hasChildren()) { for (var i = 0; i < branch.children.length; i++) { this._copy(branch.children[i]); } } }, /** * Méthode récursive qui enlève l'effet "copier" sur toutes les sous-branches * * @access private * @param TafelTreeBranch branch La branche courante * @return void */ _unsetCopy : function (branch) { if (this.classCopy) { Element.removeClassName(branch.txt, this.classCopy); Element.removeClassName(branch.img, this.classCopy); } if (branch.hasChildren()) { for (var i = 0; i < branch.children.length; i++) { this._unsetCopy(branch.children[i]); } } }, /** *------------------------------------------------------------------------------ * TafelTree getters and setters methods *------------------------------------------------------------------------------ */ enableMultiline : function (multiline) { this.multiline = (multiline) ? true : false; }, enableRTL : function (rtl) { this.rtlMode = (rtl) ? true : false; if (this.rtlMode) { // plante sous Safari... //this.div.style.float = 'right'; this.div.style.textAlign = 'right'; this.div.style.direction = 'rtl'; } else { // plante sous Safari //this.div.style.float = 'left'; this.div.style.textAlign = 'left'; this.div.style.direction = 'ltr'; } this.setLineStyle(this.lineStyle); }, isRTL : function () { return this.rtlMode; }, disableDropALT : function (alt) { this.dropALT = (alt) ? true : false; }, disableDropCTRL : function (copy) { this.dropCTRL = (copy) ? true : false; }, enableCheckboxes : function (enable) { this.checkboxes = (enable) ? true : false; }, enableCheckboxesThreeState : function (enable) { this.enableCheckboxes(enable); this.checkboxesThreeState = (enable) ? true : false; }, /** * Permet d'utiliser les cookies ou non. Le séparateur est optionnel, '|' par défaut * * @access public * @param boolean enable True (par défaut) pour gérer les cookies * @param string separator Le séparateur dans le cookie ) */ enableCookies : function (enable, separator) { this.useCookie = (enable) ? true : false; if (typeof(separator) != 'undefined') { this.cookieSeparator = separator; } }, openOneAtOnce : function (yes) { this.onlyOneOpened = (yes) ? true : false; }, openAfterAdd : function (yes) { this.openedAfterAdd = (yes) ? true : false; }, reopenFromServerAfterLoad : function (yes) { this.reopenFromServer = (yes) ? true : false; }, /** * Fonction qui set par défaut l'état des branches (ouvert ou fermé) * * @access public * @param boolean open True pour tout ouvrir, false pour tout fermer * @return void */ openAtLoad : function (open) { this.openAll = (open) ? true : false; }, showSelectedBranch : function (show) { this.selectedBranchShowed = (show) ? true : false; }, /** * Permet de choisir quel comportement par defaut le drop aura * * L'autre comportement s'obtient en gardant la touche ALT appuyée et/ou CTRL * * @access public * @param string def 'sibling', 'siblingcopy', 'child' ou 'childcopy' * @return void */ setBehaviourDrop : function (def) { switch (def) { case 'sibling' : this.behaviourDrop = 1; break; case 'childcopy' : this.behaviourDrop = 2; break; case 'siblingcopy' : this.behaviourDrop = 3; break; case 'child' : default : this.behaviourDrop = 0; } }, /** * Set les icônes par défaut pour toutes les branches * * Si imgopen n'est pas défini, il prend la valeur d'img. Pareil pour imgclose. * * @access public * @param string img L'image quand la branche n'a pas d'enfants * @param string imgopen L'image quand la branche des enfants et est ouverte * @param string imgclose L'image quand la branche a des enfants et est fermée * @return void */ setIcons : function (img, imgopen, imgclose) { this.icons[0] = img; this.icons[1] = (imgopen) ? imgopen : img; this.icons[2] = (imgclose) ? imgclose : img; }, /** * Set les icônes de sélection par défaut pour toutes les branches * * @access public * @param string img L'image quand la branche n'a pas d'enfants * @param string imgopen L'image quand la branche des enfants et est ouverte * @param string imgclose L'image quand la branche a des enfants et est fermée * @return void */ setIconsSelected : function (img, imgopen, imgclose) { this.iconsSelected[0] = img; this.iconsSelected[1] = (imgopen) ? imgopen : null; this.iconsSelected[2] = (imgclose) ? imgclose : null; }, /** * Fonction qui permet de choisir le style des lignes entre les branches * * @access public * @param string style LE style des lignes, 'none' ou 'line' * @return void */ setLineStyle : function (style) { this.lineStyle = style; switch (style) { case 'none' : this.imgLine0 = 'empty.gif'; this.imgLine1 = 'empty.gif'; this.imgLine2 = 'empty.gif'; this.imgLine3 = 'empty.gif'; this.imgLine4 = 'empty.gif'; this.imgLine5 = 'empty.gif'; this.imgWait = 'wait.gif'; this.imgEmpty = 'empty.gif'; this.imgMinus1 = 'minus0.gif'; this.imgMinus2 = 'minus0.gif'; this.imgMinus3 = 'minus0.gif'; this.imgMinus4 = 'minus0.gif'; this.imgMinus5 = 'minus0.gif'; this.imgPlus1 = 'plus0.gif'; this.imgPlus2 = 'plus0.gif'; this.imgPlus3 = 'plus0.gif'; this.imgPlus4 = 'plus0.gif'; this.imgPlus5 = 'plus0.gif'; this.imgCheck1 = 'check1.gif'; this.imgCheck2 = 'check2.gif'; this.imgCheck3 = 'check3.gif'; // Les 2 premiers sont des noms d'images, les 2 autres de classes CSS this.imgMulti1 = 'empty.gif'; this.imgMulti2 = 'empty.gif'; this.imgMulti3 = ''; this.imgMulti4 = ''; break; case 'full' : if (this.isRTL()) { this.imgLine0 = 'rtl_linefull0.gif'; this.imgLine1 = 'rtl_linefull1.gif'; this.imgLine2 = 'rtl_linefull2.gif'; this.imgLine3 = 'rtl_linefull3.gif'; this.imgLine4 = 'rtl_linefull4.gif'; this.imgLine5 = 'rtl_linefull5.gif'; this.imgWait = 'wait.gif'; this.imgEmpty = 'empty.gif'; this.imgMinus1 = 'rtl_minusfull1.gif'; this.imgMinus2 = 'rtl_minusfull2.gif'; this.imgMinus3 = 'rtl_minusfull3.gif'; this.imgMinus4 = 'rtl_minusfull4.gif'; this.imgMinus5 = 'rtl_minusfull5.gif'; this.imgPlus1 = 'rtl_plusfull1.gif'; this.imgPlus2 = 'rtl_plusfull2.gif'; this.imgPlus3 = 'rtl_plusfull3.gif'; this.imgPlus4 = 'rtl_plusfull4.gif'; this.imgPlus5 = 'rtl_plusfull5.gif'; this.imgCheck1 = 'check1.gif'; this.imgCheck2 = 'check2.gif'; this.imgCheck3 = 'check3.gif'; // Les 2 premiers sont des noms d'images, les 2 autres de classes CSS this.imgMulti1 = 'rtl_linebgfull.gif'; this.imgMulti2 = 'rtl_linebgfull2.gif'; this.imgMulti3 = 'multiline'; this.imgMulti4 = 'multiline2'; } else { this.imgLine0 = 'linefull0.gif'; this.imgLine1 = 'linefull1.gif'; this.imgLine2 = 'linefull2.gif'; this.imgLine3 = 'linefull3.gif'; this.imgLine4 = 'linefull4.gif'; this.imgLine5 = 'linefull5.gif'; this.imgWait = 'wait.gif'; this.imgEmpty = 'empty.gif'; this.imgMinus1 = 'minusfull1.gif'; this.imgMinus2 = 'minusfull2.gif'; this.imgMinus3 = 'minusfull3.gif'; this.imgMinus4 = 'minusfull4.gif'; this.imgMinus5 = 'minusfull5.gif'; this.imgPlus1 = 'plusfull1.gif'; this.imgPlus2 = 'plusfull2.gif'; this.imgPlus3 = 'plusfull3.gif'; this.imgPlus4 = 'plusfull4.gif'; this.imgPlus5 = 'plusfull5.gif'; this.imgCheck1 = 'check1.gif'; this.imgCheck2 = 'check2.gif'; this.imgCheck3 = 'check3.gif'; // Les 2 premiers sont des noms d'images, les 2 autres de classes CSS this.imgMulti1 = 'linebgfull.gif'; this.imgMulti2 = 'linebgfull2.gif'; this.imgMulti3 = 'multiline'; this.imgMulti4 = 'multiline2'; } break; case 'line' : default : if (this.isRTL()) { this.imgLine0 = 'rtl_line0.gif'; this.imgLine1 = 'rtl_line1.gif'; this.imgLine2 = 'rtl_line2.gif'; this.imgLine3 = 'rtl_line3.gif'; this.imgLine4 = 'rtl_line4.gif'; this.imgLine5 = 'rtl_line5.gif'; this.imgWait = 'wait.gif'; this.imgEmpty = 'empty.gif'; this.imgMinus1 = 'rtl_minus1.gif'; this.imgMinus2 = 'rtl_minus2.gif'; this.imgMinus3 = 'rtl_minus3.gif'; this.imgMinus4 = 'rtl_minus4.gif'; this.imgMinus5 = 'rtl_minus5.gif'; this.imgPlus1 = 'rtl_plus1.gif'; this.imgPlus2 = 'rtl_plus2.gif'; this.imgPlus3 = 'rtl_plus3.gif'; this.imgPlus4 = 'rtl_plus4.gif'; this.imgPlus5 = 'rtl_plus5.gif'; this.imgCheck1 = 'check1.gif'; this.imgCheck2 = 'check2.gif'; this.imgCheck3 = 'check3.gif'; // Les 2 premiers sont des noms d'images, les 2 autres de classes CSS this.imgMulti1 = 'rtl_linebg.gif'; this.imgMulti2 = 'rtl_linebg2.gif'; this.imgMulti3 = 'multiline'; this.imgMulti4 = 'multiline2'; } else { this.imgLine0 = 'line0.gif'; this.imgLine1 = 'line1.gif'; this.imgLine2 = 'line2.gif'; this.imgLine3 = 'line3.gif'; this.imgLine4 = 'line4.gif'; this.imgLine5 = 'line5.gif'; this.imgWait = 'wait.gif'; this.imgEmpty = 'empty.gif'; this.imgMinus1 = 'minus1.gif'; this.imgMinus2 = 'minus2.gif'; this.imgMinus3 = 'minus3.gif'; this.imgMinus4 = 'minus4.gif'; this.imgMinus5 = 'minus5.gif'; this.imgPlus1 = 'plus1.gif'; this.imgPlus2 = 'plus2.gif'; this.imgPlus3 = 'plus3.gif'; this.imgPlus4 = 'plus4.gif'; this.imgPlus5 = 'plus5.gif'; this.imgCheck1 = 'check1.gif'; this.imgCheck2 = 'check2.gif'; this.imgCheck3 = 'check3.gif'; // Les 2 premiers sont des noms d'images, les 2 autres de classes CSS this.imgMulti1 = 'linebg.gif'; this.imgMulti2 = 'linebg2.gif'; this.imgMulti3 = 'multiline'; this.imgMulti4 = 'multiline2'; } } }, setTooltipDuration : function (show, hide) { this.durationTooltipShow = show; this.durationTooltipHide = hide; }, /** * Méthode qui permet d'interdir les mouvements dans la branche dragguée * * @access public * @param boolean propagateRestiction True pour interdir le mouvement des enfants de la branche droppée * @return void */ propagateRestriction : function (propagate) { this.propagation = (typeof(propagate) == 'undefined') ? true : propagate; }, getSelectedBranches : function () { return this.selectedBranches; }, setContextMenu : function (menu) { var div = document.createElement('div'); div.innerHTML = menu; this.div.appendChild(div); }, /** *------------------------------------------------------------------------------ * TafelTree public methods *------------------------------------------------------------------------------ */ /** * Fonction pour générer l'arbre * * @access public * @param boolean bigTree True pour spécifier que c'est un gros arbre * @return void */ generate : function (bigTree) { if (!bigTree) { var isNotFirst = false; var isNotLast = false; for (var i = 0; i < this.baseStruct.length; i++) { isNotFirst = (i > 0) ? true : false; isNotLast = (i < this.baseStruct.length - 1) ? true : false; this.roots[i] = new TafelTreeRoot(this, this.baseStruct[i], 0, isNotFirst, isNotLast, i); this.div.appendChild(this.roots[i].obj); } this.loadComplete(); } else { this.bigTreeLoading = 0; setTimeout(this._checkLoad.bind(this), 100); setTimeout(this._generateBigTree.bind(this), 10); } }, /** * Lance les fonctions générales de l'arbre * * @access public * @param object options Les fonctions et autres ouvertures automatiques* * @return void */ setOptions : function (options) { // Fonctions événementielles if (options.onLoad) this.setOnLoad(options.onLoad); if (options.onDebug) this.setOnDebug(options.onDebug); if (options.onCheck) this.setOnCheck(options.onCheck); if (options.onBeforeCheck) this.setOnBeforeCheck(options.onBeforeCheck); if (options.onClick) this.setOnClick(options.onClick); if (options.onMouseDown) this.setOnMouseDown(options.onMouseDown); if (options.onMouseUp) this.setOnMouseUp(options.onMouseUp); if (options.onDblClick) this.setOnDblClick(options.onDblClick); if (options.onBeforeOpen) this.setOnBeforeOpen(options.onBeforeOpen); if (options.onOpen) this.setOnOpen(options.onOpen); if (options.onMouseOver) this.setOnMouseOver(options.onMouseOver); if (options.onMouseOut) this.setOnMouseOut(options.onMouseOut); if (options.onDrop) this.setOnDrop(options.onDrop); if (options.onDragStartEffect) this.setOnDragStartEffect(options.onDragStartEffect); if (options.onDragEndEffect) this.setOnDragEndEffect(options.onDragEndEffect); if (options.onErrorAjax) this.setOnDropAfter(options.onErrorAjax); if (options.onEdit) this.setOnEdit(options.onEdit); if (options.onEditAjax) this.setOnEditAjax(options.onEditAjax[0], options.onEditAjax[1]); if (options.onDropAjax) this.setOnDropAjax(options.onDropAjax[0], options.onDropAjax[1]); if (options.onOpenPopulate) this.setOnOpenPopulate(options.onOpenPopulate[0], options.onOpenPopulate[1]); // Fonctions avancées if (typeof(options.rtlMode) != 'undefined') this.enableRTL(options.rtlMode); if (typeof(options.dropALT) != 'undefined') this.disableDropALT(options.dropALT); if (typeof(options.dropCTRL) != 'undefined') this.disableDropCTRL(options.dropCTRL); if (typeof(options.multiline) != 'undefined') this.enableMultiline(options.multiline); if (typeof(options.checkboxes) != 'undefined') this.enableCheckboxes(options.checkboxes); if (typeof(options.checkboxesThreeState) != 'undefined') this.enableCheckboxesThreeState(options.checkboxesThreeState); if (typeof(options.cookies) != 'undefined') this.enableCookies(options.cookies); if (typeof(options.openOneAtOnce) != 'undefined') this.openOneAtOnce(options.openOneAtOnce); if (typeof(options.openAtLoad) != 'undefined') this.openAtLoad(options.openAtLoad); if (typeof(options.openAfterAdd) != 'undefined') this.openAfterAdd(options.openAfterAdd); if (typeof(options.showSelectedBranch) != 'undefined') this.showSelectedBranch(options.showSelectedBranch); if (typeof(options.reopenFromServer) != 'undefined') this.reopenFromServerAfterLoad(options.reopenFromServer); if (typeof(options.propagateRestriction) != 'undefined') this.propagateRestriction(options.propagateRestriction); if (options.lineStyle) this.setLineStyle(options.lineStyle); if (options.behaviourDrop) this.setBehaviourDrop(options.behaviourDrop); if (options.contextMenu) this.setContextMenu(options.contextMenu); // Fonctions diverses if (options.bind) { for (var i = 0; i < options.bind.length; i++) { this.bind(options.bind[i]); } } if (options.bindAsUnidirectional) { for (var i = 0; i < options.bindAsUnidirectional.length; i++) { this.bind(options.bindAsUnidirectional[i]); } } if (options.defaultImg) { var imgopen = (options.defaultImgOpen) ? options.defaultImgOpen : options.defaultImg; var imgclose = (options.defaultImgClose) ? options.defaultImgClose : options.defaultImg; this.setIcons(options.defaultImg, imgopen, imgclose); } if (options.defaultImgSelected || options.defaultImgOpenSelected || options.defaultImgCloseSelected) { var img = (options.defaultImgSelected) ? options.defaultImgSelected : null; var imgopen = (options.defaultImgOpenSelected) ? options.defaultImgOpenSelected : null; var imgclose = (options.defaultImgCloseSelected) ? options.defaultImgCloseSelected :null; this.setIconsSelected(img, imgopen, imgclose); } this.serverCookie = (options.serverCookie) ? options.serverCookie : false; }, loadComplete : function () { this._adjustOpening(); this._adjustCheck(); this.setCookie(this.classTree + this.id); this.loaded = true; if (typeof(this.onLoad) == 'function') { this.onLoad(); } }, loadRunning : function (loaded) { if (typeof(this.onLoading) == 'function') { this.onLoading(loaded); } }, replace : function (modelBranch, replacedBranch, copy) { var branch1 = this.getBranchById(modelBranch); if (!branch1) return false; return branch1.replace(replacedBranch, copy); }, switchBranches : function (branch1, branch2) { var branch1 = this.getBranchById(branch1); if (!branch1) return false; branch1.switchWith(branch2); }, /** * Restaure les valeurs par défaut d'ouverture et check (selon type) * * Le type peut prendre la valeur "open", "check" ou "all" * * @access public * @param string type Le type de default (open, check ou all) * @return void */ restoreDefault : function (type) { var s = this.defaultStruct; this._restaureDefault(s, type); }, _restaureDefault : function (s, type) { var b = null; var open = false; var check = 0; for (var i = 0; i < s.length; i++) { b = this.getBranchById(s[i].id); if (b) { open = (s[i].open) ? true : this.openAll; check = (s[i].check == 1) ? 1 : 0; switch (type) { case 'open' : if (b.hasChildren()) { b.openIt(open); } break; case 'check' : b.check(check); b._adjustParentCheck(); break; case 'all' : default : if (b.hasChildren()) { b.openIt(open); } //alert(b.getText() + ' : ' + check); b.check(check); b._adjustParentCheck(); } // S'il y a des enfants, on va les restaurer aussi if (typeof(s[i].items) != 'undefined') { this._restaureDefault(s[i].items, type); } } } }, /** * Fonction qui lie des arbres TafelTree entre eux, bidirecitonnellement * * On lui passe autant de TafelTree voulu, en les séparant par des virgules * * @access public * @param TafelTree argument Un ou plusieurs TafelTree * @return void */ bind : function () { var trees = this.bind.arguments; for (var i = 0; i < trees.length; i++) { if (!this.isBindedWith(trees[i])) { this.otherTrees.push(trees[i]); if (!trees[i].isBindedWith(this)) { trees[i].bind(this); } } } }, /** * Fonction qui lie des arbres TafelTree entre eux, mais unnidirecitonnel * * On lui passe autant de TafelTree voulu, en les séparant par des virgules * * @access public * @param TafelTree argument Un ou plusieurs TafelTree * @return void */ bindAsUnidirectional : function () { var trees = this.bindAsUnidirectional.arguments; for (var i = 0; i < trees.length; i++) { if (!this.isBindedWith(trees[i])) { this.otherTrees.push(trees[i]); } } }, isBindedWith : function (_tree) { var binded = false; for (var i = 0; i < this.otherTrees.length; i++) { if (this.otherTrees[i].id == _tree.id) { binded = true; break; } } return binded; }, unselect : function () { var branch = null; for (var i = 0; i < this.selectedBranches.length; i++) { branch = this.selectedBranches[i]; Element.removeClassName(branch.txt, this.classSelected); // On set l'icône s'il doit changer if (branch.getIconSelected() || branch.getOpenIconSelected() || branch.getCloseIconSelected()) { if (branch.hasChildren()) { branch.img.src = (branch.isOpened()) ? branch.tree.imgBase + branch.struct.imgopen : branch.tree.imgBase + branch.struct.imgclose; } else { branch.img.src = branch.tree.imgBase + branch.struct.img; } } } this.selectedBranches = []; }, /** * Retourne toutes les branches contenues entre deux d'entre-elles * * @access public * @param TafelTreeBranch branch1 La première borne * @param TafelTreeBranch branch2 La deuxième borne * @return array Un tableau de branche, ou false si rien n'a été trouvé */ getBranchesBetween : function (branch1, branch2) { var branch1 = this.getBranchById(branch1); var branch2 = this.getBranchById(branch2); if (!branch1 || !branch2) return false; // On quitte si ce n'est pas le même arbre if (branch1.tree.id != branch2.tree.id) return false; var found = false; var selected = []; var pos1 = branch1.getWithinOffset(); var pos2 = branch2.getWithinOffset(); var next = (pos1[1] <= pos2[1]) ? true : false; // On va chercher l'autre branche plus bas branch = (next) ? branch1.getNextBranch() : branch1.getPreviousBranch(); while (branch) { selected.push(branch); if (branch.getId() == branch2.getId()) { found = true; break; } branch = (next) ? branch.getNextBranch() : branch.getPreviousBranch(); } return (found) ? selected : false; }, /** * Retourne le nombre de branche comprises dans l'arbre * * @access public * @return integer Le nombre de branches */ countBranches : function () { var nb = this.roots.length; for (var i = 0; i < this.roots.length; i++) { nb += this.roots[i].countBranches(); } return nb; }, /** * Retourne toutes les branches de l'arbre * * @access public * @param function filter Le filtre des branches * @return array Un tableau des branches de l'arbre */ getBranches : function (filter) { var branches = []; for (var i = 0; i < this.roots.length; i++) { if (typeof(filter) == 'function') { if (filter(this.roots[i])) { branches.push(this.roots[i]); } } else { branches.push(this.roots[i]); } branches = this.roots[i].getBranches(filter, branches); } return branches; }, /** * Récupère toutes les branches ouvertes * * @access public * @return void */ getOpenedBranches : function () { var openedBranches = []; for (var i = 0; i < this.roots.length; i++) { if (this.roots[i].isOpened() && this.roots[i].hasChildren()) { openedBranches.push(this.roots[i]); } openedBranches = this.roots[i].getOpenedBranches(openedBranches); } return openedBranches; }, /** * Récupère toutes les branches checkées * * @access public * @return void */ getCheckedBranches : function () { var checkedBranches = []; for (var i = 0; i < this.roots.length; i++) { if (this.roots[i].isChecked() == 1) { checkedBranches.push(this.roots[i]); } checkedBranches = this.roots[i].getCheckedBranches(checkedBranches); } return checkedBranches; }, /** * Récupère toutes les branches non checkées * * @access public * @return void */ getUnCheckedBranches : function () { var uncheckedBranches = []; for (var i = 0; i < this.roots.length; i++) { if (this.roots[i].isChecked() == 0) { uncheckedBranches.push(this.roots[i]); } uncheckedBranches = this.roots[i].getUnCheckedBranches(uncheckedBranches); } return uncheckedBranches; }, /** * Récupère toutes les branches partiellement checkées * * @access public * @return void */ getPartCheckedBranches : function () { var uncheckedBranches = []; for (var i = 0; i < this.roots.length; i++) { if (this.roots[i].isChecked() == -1) { uncheckedBranches.push(this.roots[i]); } uncheckedBranches = this.roots[i].getPartCheckedBranches(uncheckedBranches); } return uncheckedBranches; }, getParentBranches : function () { var parents = []; for (var i = 0; i < this.roots.length; i++) { if (this.roots[i].hasChildren()) { parents.push(this.roots[i]); } parents = this.roots[i].getParentBranches(parents); } return parents; }, getLeafBranches : function () { var leafs = []; for (var i = 0; i < this.roots.length; i++) { if (!this.roots[i].hasChildren()) { leafs.push(this.roots[i]); } leafs = this.roots[i].getLeafBranches(leafs); } return leafs; }, /** * Fonction qui ouvre tout l'arbre d'un coup * * @access public * @return void */ expend : function () { for (var i = 0; i < this.roots.length; i++) { this.roots[i].expend(); } }, /** * Fonction qui ferme tout l'arbre d'un coup * * @access public * @return void */ collapse : function () { for (var i = 0; i < this.roots.length; i++) { this.roots[i].collapse(); } }, /** * Méthode pour récupérer une branche en fonction de son id * * @access public * @param string position L'id de la branche soeur ou parente, ou l'objet * @param object item La nouvelle branche * @param boolean sibling True pour 'sibling', false pour 'child' * @param boolean isFirst True pour l'insérer, soit comme 1er enfant, soit avant la soeur * @return void */ insertBranch : function (position, item, sibling, isFirst) { var position = this.getBranchById(position); if (!position) return false; if (!sibling) { if (!isFirst) { position.insertIntoLast(item); } else { position.insertIntoFirst(item); } } else { if (!isFirst) { position.insertAfter(item); } else { position.insertBefore(item); } } }, moveBranch : function (position, item, sibling, isFirst) { var position = this.getBranchById(position); if (!position) return false; if (!sibling) { if (!isFirst) { position.moveIntoLast(item); } else { position.moveIntoFirst(item); } } else { if (!isFirst) { position.moveAfter(item); } else { position.moveBefore(item); } } }, /** * Fonction qui efface la branche * * @access public * @return void */ removeBranch : function (branch) { try { var branch = this.getBranchById(branch); if (!branch) return false; // On enlève le drag&drop if (branch.objDrag) { branch.removeDragDrop(); } if (!branch.isRoot) { // On supprime le noeud HTML branch.parent.obj.removeChild(branch.obj); // On l'enlève de la structure Javacript branch.parent.children.splice(branch.pos, 1); branch.parent.struct.items.splice(branch.pos, 1); if (branch.parent.children.length == 0) { branch.parent.setOpenableIcon(false); if (branch.tree.multiline) { branch._manageMultiline(branch.parent.tdImg, 2, false); } } // On repositionne la structure branch.parent._manageLine(); } else { // On supprime le noeud HTML this.div.removeChild(branch.obj); // On l'enlève de la structure Javacript this.roots.splice(branch.pos, 1); if (this.roots[branch.pos-1]) { this.roots[branch.pos-1]._manageAfterRootInsert(); } } branch = null; } catch (err) { throw new Error ('remove(base) : ' + err.message); } }, /** * Méthode pour récupérer une branche en fonction de son id généré * * @access public * @param string id L'id généré de la branche * @return TafelBranch La branche sélectionnée */ getBranchByIdObj : function (id) { try { var obj = null; for (var r = 0; r < this.roots.length; r++) { obj = this._getBranchByIdObj(id, this.roots[r]); if (obj) { break; } } return obj; } catch (err) { throw new Error ('getBranchByIdObj(func) : ' + err.message); } }, /** * Méthode pour récupérer une branche en fonction de son id utilisateur * * @access public * @param string id L'id utilisateur de la branche * @return TafelBranch La branche sélectionnée */ getBranchById : function (id) { try { if (typeof(id) == 'object') return id; var obj = null; for (var r = 0; r < this.roots.length; r++) { obj = this._getBranchById(id, this.roots[r]); if (obj) break; } if (!obj) { // On magouille avec les roots pour ne pas passer // dans une boucle infinie (à cause du getBranchById) var ro = null; for (var i = 0; i < this.otherTrees.length; i++) { ro = this.otherTrees[i].roots; for (var r = 0; r < ro.length; r++) { obj = this.otherTrees[i]._getBranchById(id, ro[r]); if (obj) break; } if (obj) break; } } return obj; } catch (err) { throw new Error ('getBranchById(func) : ' + err.message); } }, /** * Méthode de gestion de debug * * @access public * @param string str Une string à afficher (optionnel) * @return void */ debug : function (str) { try { this.debugObj.style.display = 'block'; if (typeof(this.onDebug) == 'function') { this.onDebug(this, this.debugObj, (str) ? str : ''); } else { this.debugObj.innerHTML += str; } } catch (err) { throw new Error ('debug(func) : ' + err.message); } }, /** * Fonction pour afficher l'ojbet de manière cool * * @access public * @return string La string de l'objet */ toString : function () { var obj = { 'id' : this.id, 'width' : this.div.offsetWidth, 'height' : this.div.offsetHeight, 'imgPath' : this.imgBase, 'roots' : this.roots.length }; var str = 'TafelTree {'; for (var i in obj) { str += TafelTree.debugReturn + TafelTree.debugTab + i + ' : ' + obj[i]; } str += TafelTree.debugReturn + '}'; return str; }, /** * Fonction qui sérialise l'arbre pour en faire une string JSON * * @access public * @return string La string de l'objet */ serialize : function (debug) { var rt = (debug) ? TafelTree.debugReturn : ''; var str = (debug) ? 'TafelTree (' + this.id + ') [' : '['; for (var i = 0; i < this.roots.length; i++) { str += this.roots[i].serialize(debug, true); if (i < this.roots.length - 1) { str += ','; } } str += rt + ((debug) ? '];' : ']'); if (debug) { return str; } else { return encodeURIComponent(str); } }, /** * Fonction qui renvoie les paramètres de l'URL * * ils sont renvoyés sous cette forme : params[0] = { 'name' : 'paramName', 'value': 'paramValue' } * * @access public * @param string url L'url à decomposer * @return array Le tableau de paramètres */ getURLParams : function (url) { var params = []; if (url.indexOf('?') > -1) { var a1 = url.split('?'); var a2 = a1[1].split('&'); var a3 = ''; for (var i = 0; i < a2.length; i++) { a3 = a2[i].split('='); if (a3.length == 2) { params.push({ 'name' : a3[0], 'value': a3[1] }) } } } return params; }, /** *------------------------------------------------------------------------------ * TafelTree private methods *------------------------------------------------------------------------------ */ _generateBigTree : function () { var i = this.bigTreeLoading; var isNotFirst = false; var isNotLast = false; if (i < this.baseStruct.length) { isNotFirst = (i > 0) ? true : false; isNotLast = (i < this.baseStruct.length - 1) ? true : false; this.roots[i] = new TafelTreeRoot(this, this.baseStruct[i], 0, isNotFirst, isNotLast, i); this.div.appendChild(this.roots[i].obj); this.loadRunning(this.roots[i]); this.bigTreeLoading++; setTimeout(this._generateBigTree.bind(this), 10); } else { this.loaded = true; } }, _checkLoad : function () { var complete = true; if (this.loaded) { for (var i = 0; i < this.roots.length; i++) { if (!this.roots[i].loaded || !this._checkLoadChildren(this.roots[i])) { complete = false; break; } } } else { complete = false; } if (!complete){ setTimeout(this._checkLoad.bind(this), 100); } else { this.loadComplete(); } }, _checkLoadChildren : function (branch) { var complete = true; if (branch.loaded) { for (var i = 0; i < branch.children.length; i++) { if (!branch.children[i].loaded || !this._checkLoadChildren(branch.children[i])) { complete = false; break; } } } else { complete = false; } return complete; }, _adjustOpening : function () { // Si on utilise les cookies, on s'en sert pour ouvrir ou fermer les branches if (this.useCookie && this.cookieOpened) { var branch = null; for (var i = 0; i < this.cookieOpened.length; i++) { branch = this.getBranchById(this.cookieOpened[i]); if (typeof(branch) == 'object' && branch.hasChildren()) { if (branch.children.length > 0) { // Cette branche est une branche normale branch.openIt(true); } else { // Cette branche est une branche qui a ses enfants sur le serveur // On va donc les récupérer if (typeof(branch.struct.onopenpopulate) == 'function' && branch.eventable) { branch._openPopulate(); branch.openIt(true); } } } } } }, _adjustCheck : function () { // On ajuste les checks d'après les cookies var branch = null; if (this.checkboxes && this.useCookie && this.cookieChecked) { for (var i = 0; i < this.cookieChecked.length; i++) { branch = this.getBranchById(this.cookieChecked[i]); if (typeof(branch) == 'object') { branch.check(1); } } } // Si on a des checkboxes, on corrige les images en fonction des checks if (this.checkboxes && this.checkboxesThreeState) { var checked = this.getCheckedBranches(); for (var i = 0; i < checked.length; i++) { checked[i]._adjustParentCheck(); } } }, /** * Méthode récursive pour récupérer une branche en fonction de son id généré * * @access private * @param string id L'id généré de la branche recherchée * @param TafelTreeBranch obj La branche courante * @return TafelBranch La branche sélectionnée */ _getBranchByIdObj : function (id, obj) { try { var ob = ''; if (obj.idObj == id) { return obj; } if (typeof(obj.children) == 'object') { for (var c = 0; c < obj.children.length; c++) { ob = this._getBranchByIdObj(id, obj.children[c]); if (ob) { return ob; } } } return ob; } catch (err) { throw new Error ('_getBranchByIdObj(func) : ' + err.message); } }, /** * Méthode récursive pour récupérer une branche en fonction de son id utilisateur * * @access private * @param string id L'id utilisateur de la branche recherchée * @param TafelTreeBranch obj La branche courante * @return TafelBranch La branche sélectionnée */ _getBranchById : function (id, obj) { try { var ob = ''; if (obj.getId() == id) { return obj; } if (typeof(obj.children) == 'object') { for (var c = 0; c < obj.children.length; c++) { ob = this._getBranchById(id, obj.children[c]); if (ob) { return ob; } } } return ob; } catch (err) { throw new Error ('_getBranchById(func) : ' + err.message); } }, /** * Fonction qui change la structure de la branche * * @access private * @param TafelTreeBranch branch La nouvelle structure * @return void */ _changeStruct : function (branch) { try { while (typeof(branch.parent) != 'undefined') { branch.parent.struct.items.splice(branch.pos, 1, branch.struct); if (typeof(branch.parent) != 'undefined') { branch = branch.parent; } } } catch (err) { throw new Error ('_changeStruct(func) : ' + err.message); } }, /** * Méthode pour ajouter l'élément principal * * @access private * @return HTMLDivElement L'élément DIV créé */ _addTree : function () { var div = document.createElement('div'); div.className = this.classTree; return div; }, /** *------------------------------------------------------------------------------ * TafelTree Cookies Management *------------------------------------------------------------------------------ */ /** * Méthode qui sauve le contenu dans le cookie. Propre à l'application * * @access public * @param string name Nom du cookie * @return void */ setCookie : function (name) { try { var str = 'cookieactivate' + this.cookieSeparator; // Les branches ouvertes var arr = this.getOpenedBranches(); for (var i = 0; i < arr.length; i++) { str = str + arr[i].getId() + this.cookieSeparator; } // Les branches checkées str += this.cookieCheckSeparator; var arr = this.getCheckedBranches(); for (var i = 0; i < arr.length; i++) { str = str + arr[i].getId() + this.cookieSeparator; } if (!this.serverCookie) { this._saveCookie(name, str, '', '/', '', ''); } else { // send cookie server only if tree is loaded (optimization) if (this.loaded) { new Ajax.Request(this.serverCookie, { 'method' : 'post', 'parameters' : 'type=set&cookieString=' + str, 'onComplete' : this._cookieSend.bind(this), 'onFailure' : this._cookieFailure.bind(this) }); } } } catch (err) { throw new Error ('setCookie(func) : ' + err.message); } }, /** * Méthode qui récupère le contenu d'un cookie en fonction du nom * * @access public * @param string name Nom du cookie * @return string Le contenu du cookie */ getCookie : function (name) { try { if (!this.serverCookie) { if (name != ''){ var start = document.cookie.indexOf(name + '='); var len = start + name.length + 1; if ((!start) && (name != document.cookie.substring(0, name.length))){ return null; } if ( start == -1 ) return null; var end = document.cookie.indexOf(';', len); if (end == -1){ end = document.cookie.length; } return unescape(document.cookie.substring(len, end)); } } else { new Ajax.Request(this.serverCookie, { 'method' : 'post', 'parameters' : 'type=get', 'onComplete' : this._getCookieComplete.bind(this), 'onFailure' : this._cookieFailure.bind(this) }); } return null; } catch (err) { throw new Error ('getCookie(func) : ' + err.message); } }, _cookieSend : function (response) { alert('ok'); }, _getCookieComplete : function (response) { var fromCookie = response.responseText; if (fromCookie) { var branches = fromCookie.split(this.cookieCheckSeparator); // Branches ouvertes this.cookieOpened = []; this.cookieOpened = branches[0].split(this.cookieSeparator); this.cookieOpened.shift(); // Branches checkées (avec anti-bug pour les anciennes versions et anciens cookies) this.cookieChecked = []; if (branches.length > 1) { this.cookieChecked = branches[1].split(this.cookieSeparator); } } if (this.options.generate) { this.generate(); } if (this.options.generateBigTree) { this.generate(true); } }, _cookieFailure : function (response) { // do nothing }, /** * Méthode qui supprime un cookie. Seul le nom est obligatoire * * @access public * @param string name Nom du cookie * @param string path Le chemin * @param string domain Le domaine * @return void */ deleteCookie : function (name, path, domain) { try { if (get_cookie(name)) document.cookie = name + '=' + ( ( path ) ? ';path=' + path : "") + ( ( domain ) ? ';domain=' + domain : '') + ';expires=Thu, 01-Jan-1970 00:00:01 GMT'; } catch (err) { throw new Error ('deleteCookie(func) : ' + err.message); } }, /** * Méthode qui sauve le contenu dans le cookie. Propre à toute application * * @access private * @param string name Nom du cookie * @param string value La valeur à enregistrer * @param integer expires La durée de vie du cookie, en jour * @param string path Le chemin * @param string domain Le domaine * @param string secure ? * @return void */ _saveCookie : function (name, value, expires, path, domain, secure) { try { // set time, it's in milliseconds var today = new Date(); today.setTime(today.getTime()); if (expires){ expires = expires * 1000 * 60 * 60 * 24; } var expires_date = new Date(today.getTime() + (expires)); document.cookie = name + '=' +escape(value) + ( ( expires ) ? ';expires=' + expires_date.toGMTString() : '') + ( ( path ) ? ';path=' + path : '') + ( ( domain ) ? ';domain=' + domain : '') + ( ( secure ) ? ';secure' : ''); } catch (err) { throw new Error ('_saveCookie(func) : ' + err.message); } }, /** *------------------------------------------------------------------------------ * TafelTree Events Management *------------------------------------------------------------------------------ */ /** * Méthode qui appelle la méthode utilisateur après le load de l'arbre * * @access public * @param function func La fonction utilisateur * @return void */ setOnLoad : function (func) { this.onLoad = eval(func); }, /** * Méthode qui appelle la méthode utilisateur pendant le load de l'arbre * * @access public * @param function func La fonction utilisateur * @return void */ setOnLoading : function (func) { this.onLoading = eval(func); }, /** * Méthode qui appelle la méthode utilisateur après l'ouverture ou fermeture d'un noeud * * @access public * @param function func La fonction utilisateur * @return void */ setOnOpen : function (func) { this.onOpen = eval(func); }, /** * Méthode qui appelle la méthode utilisateur avant l'ouverture ou fermeture d'un noeud * * @access public * @param function func La fonction utilisateur * @return void */ setOnBeforeOpen : function (func) { this.onBeforeOpen = eval(func); }, /** * Méthode qui appelle la méthode utilisateur lorsque la souris est sur un noeud * * @access public * @param function func La fonction utilisateur * @return void */ setOnMouseOver : function (func) { this.onMouseOver = eval(func); }, /** * Méthode qui appelle la méthode utilisateur lorsque la souris quitte le noeud * * @access public * @param function func La fonction utilisateur * @return void */ setOnMouseOut : function (func) { this.onMouseOut = eval(func); }, /** * Méthode qui appelle la méthode utilisateur après un clic sur un noeud * * @access public * @param function func La fonction utilisateur * @return void */ setOnClick : function (func) { this.onClick = eval(func); }, /** * Méthode qui appelle la méthode utilisateur après un mouse down * * @access public * @param function func La fonction utilisateur * @return void */ setOnMouseDown : function (func) { this.onMouseDown = eval(func); }, /** * Méthode qui appelle la méthode utilisateur après un mouse up * * @access public * @param function func La fonction utilisateur * @return void */ setOnMouseUp : function (func) { this.onMouseUp = eval(func); }, /** * Méthode qui appelle la méthode utilisateur lors d'un double-clic sur un noeud * * @access public * @param function func La fonction utilisateur * @return void */ setOnDblClick : function (func) { this.onDblClick = eval(func); }, /** * Méthode qui appelle la méthode utilisateur lors de la fin de l'édition d'une branche * * @access public * @param function func La fonction utilisateur * @param string link Le lien de la page ajax * @return void */ setOnEdit : function (func, link) { if (link) { this.onEditAjax = { 'func' : eval(func), 'link' : link }; } else { this.onEdit = eval(func); } this.editableBranches = true; }, /** * Méthode qui appelle la méthode utilisateur lorsqu'on clique sur une checkbox, avant que celle-ci change de status * * @access public * @param function func La fonction utilisateur * @return void */ setOnBeforeCheck : function (func) { this.onBeforeCheck = eval(func); }, /** * Méthode qui appelle la méthode utilisateur lorsqu'on clique sur une checkbox, après qu'elle ait changé de status * * @access public * @param function func La fonction utilisateur * @return void */ setOnCheck : function (func) { this.onCheck = eval(func); }, /** * Méthode qui appelle la méthode utilisateur lors d'un drop sur un noeud * * @access public * @param function func La fonction utilisateur * @return void */ setOnDrop : function (func) { this.onDrop = eval(func); }, /** * Méthode qui appelle la méthode utilisateur après un drop sur un noeud * * @access public * @param function func La fonction utilisateur * @return void */ setOnDropAfter : function (func) { this.onErrorAjax = eval(func); }, /** * Méthode qui appelle la méthode utilisateur lors d'un drop sur un noeud * * @access public * @param function func La fonction utilisateur * @param string link Le lien de la page ajax * @param boolean propagateRestiction True pour interdir le mouvement des enfants de la branche droppée * @return void */ setOnDropAjax : function (func, link) { this.onDropAjax = { 'func' : eval(func), 'link' : link }; }, /** * Fonction appelée au retour de la requête Ajax après un open de la branche * * @access public * @param function|boolean func La fonction utilisateur ou true * @param string link Le lien de la page ajax * @return void */ setOnOpenPopulate : function (func, link) { this.onOpenPopulate = { 'func' : eval(func), 'link' : link }; }, /** * Méthode qui appelle la méthode utilisateur lors de la fin de l'édition d'une branche * * @access public * @param function func La fonction utilisateur * @param string link Le lien de la page ajax * @return void */ setOnEditAjax : function (func, link) { this.onEditAjax = { 'func' : eval(func), 'link' : link }; this.editableBranches = true; }, setOnDragStartEffect : function (func) { this.onDragStartEffect = eval(func); }, setOnDragEndEffect : function (func) { this.onDragEndEffect = eval(func); } }; /** *------------------------------------------------------------------------------ * Abstract TafelTreeBaseBranch Class *------------------------------------------------------------------------------ */ var TafelTreeBaseBranch = Class.create(); TafelTreeBaseBranch.prototype = { initialize : function () {}, /** *------------------------------------------------------------------------------ * TafelTreeBaseBranch getters & setters *------------------------------------------------------------------------------ */ getId : function () { return this.struct.id; }, getText : function () { return this.struct.txt; }, getLevel : function () { return this.level; }, getTree : function () { return this.tree; }, getParent : function () { return (this.isRoot) ? null : this.parent; }, /** * Retourne la racine parente, null s'il n'y en a pas * * @access public * @return TafelTreeRoot La racine parente */ getAncestor : function () { return (this.isRoot) ? null : this.root; }, /** * Retourne tous les parents, racine comprise. * * Le 1er élément du tableau est le parent direct, le dernier étant * la racine * * @access public * @return array Les parents */ getParents : function () { var parents = []; var branch = this; while (branch.parent) { parents.push(branch.parent); branch = branch.parent; } return parents; }, getChildren : function () { return this.children; }, getIcon : function () { return this.struct.img; }, getOpenIcon : function () { return this.struct.imgopen; }, getCloseIcon : function () { return this.struct.imgclose; }, getIconSelected : function () { return this.struct.imgselected; }, getOpenIconSelected : function () { return this.struct.imgopenselected; }, getCloseIconSelected : function () { return this.struct.imgcloseselected; }, getCurrentIcon : function () { var img = this._getImgInfo(this.img); return img.fullName; }, setText : function (text) { this.struct.txt = text; this.txt.innerHTML = text; }, setIcons : function (icon, iconOpen, iconClose) { this.struct.img = icon; this.struct.imgopen = (iconOpen) ? iconOpen : icon; this.struct.imgclose = (iconClose) ? iconClose : icon; if (this.hasChildren()) { this.img.src = (this.isOpened()) ? this.tree.imgBase + this.struct.imgopen : this.tree.imgBase + this.struct.imgclose; } else { this.img.src = this.tree.imgBase + this.struct.img; } }, setIconsSelected : function (icon, iconOpen, iconClose) { this.struct.imgselected = icon; this.struct.imgopenselected = (iconOpen) ? iconOpen : null; this.struct.imgcloseselected = (iconClose) ? iconClose : null; if (this.isSelected()) { if (this.hasChildren()) { this.img.src = (this.isOpened()) ? this.tree.imgBase + this.struct.imgopenselected : this.tree.imgBase + this.struct.imgcloseselected; } else { this.img.src = this.tree.imgBase + this.struct.imgselected; } } }, /** * Méthode qui change l'id de l'élément. A utiliser avec parcimonie * * @access public * @param string newId Le nouvel id * @return boolean True si tout est ok, false si l'id existe déjà dans l'arbre */ changeId : function (newId) { var used = this.tree.getBranchById(newId); if (!used) { this.struct.id = newId; this.tree._changeStruct(this); return true; } else { return false; } }, /** * Méthode qui détermine si l'élément a des enfants ou non* * * @access public * @return boolean True s'il a des enfants, false sinon */ hasChildren : function () { return (this.struct.items.length > 0 || this.struct.canhavechildren) ? true : false; }, isOpened : function () { return (this.struct.open) ? true : false; }, isAlwaysLast : function () { return (this.struct.last) ? true : false; }, isOpenedInCookie : function () { if (this.tree.useCookie && this.tree.cookieOpened) { for (var i = 0; i < this.tree.cookieOpened.length; i++) { if (this.getId() == this.tree.cookieOpened[i]) return true; } } return false; }, /** * Retourne true si la branche est visible * * @access public * @return boolean True si la branche est visible, false sinon */ isVisible : function () { var visible = true; var branch = this; while (branch.parent) { if (branch.parent.isOpened()) { branch = branch.parent; } else { visible = false; break; } } return visible; }, /** * Retourne TRUE si la branche est sélectionnée * * @access public * @return boolean True si la branche est sélectionnée, false sinon */ isSelected : function () { return (Element.hasClassName(this.txt, this.tree.classSelected)) ? true : false; }, /** *------------------------------------------------------------------------------ * TafelTreeBaseBranch public functions *------------------------------------------------------------------------------ */ /** * Rafraichit les enfants de la branche en fonction de ce qu'il y a sur le serveur * * @access public * @return void */ refreshChildren : function () { this.removeChildren(); this._openPopulate(); }, /** * Clone toute la structure de la branche * * @access public* * @param boolean withDefaultFunc True pour copier les fonctions par defaut de l'arbre * @return object La structure JSON de la branche */ clone : function (withDefaultFunc) { var struct = {}; for (var property in this.struct) { if (property != 'items') { // On prend les fonctions seulement si elles sont définies pour la branche if (!withDefaultFunc && typeof(this.struct[property]) == 'function') { if (!eval('this.' + property + 'Default')) { struct[property] = this.struct[property]; } } else { struct[property] = this.struct[property]; } } } if (this.hasChildren()) { struct.items = []; for (var i = 0; i < this.children.length; i++) { struct.items.push(this.children[i].clone(withDefaultFunc)); } } this.copiedTimes++; struct.id = struct.id + this.tree.copyNameBreak + this.tree.idTree; struct.txt = struct.txt + this.tree.copyName.replace('%n', this.copiedTimes); return struct; }, /** * Retourne le premier enfant de la branche, ou null s'il y en a pas * * @access public * @return TafelTreeBranch Le premier enfant de la branche */ getFirstBranch : function () { return (this.children.length > 0) ? this.children[0] : null; }, /** * Retourne le dernier enfant de la branche, ou null s'il y en a pas * * @access public * @return TafelTreeBranch Le dernier enfant de la branche */ getLastBranch : function () { var pos = this.children.length - 1; return (pos >= 0) ? this.children[pos] : null; }, /** * Fonction qui récupère la branche précédente du même niveau * * @access public * @return TafelTreeBranch La branche si elle existe, null sinon */ getPreviousSibling : function () { var pos = this.pos - 1; var branch = null; if (this.isRoot) { if (pos >= 0) branch = this.tree.roots[pos]; } else { if (pos >= 0) branch = this.parent.children[pos]; } return branch; }, /** * Fonction qui récupère la branche suivante du même niveau * * @access public * @return TafelTreeBranch La branche si elle existe, null sinon */ getNextSibling : function () { var pos = this.pos + 1; var branch = null; if (this.isRoot) { if (pos < this.tree.roots.length) branch = this.tree.roots[pos]; } else { if (pos < this.parent.children.length) branch = this.parent.children[pos]; } return branch; }, /** * Retourne la branche précédente dans l'arbre, pas forcément de même niveau * * @access public * @return TafelTreeBranch La branche précédente, null s'il n'y en a pas */ getPreviousBranch : function () { var branch = null; var previous = this.getPreviousSibling(); // Si elle a une soeur précédente if (previous) { // On regarde si elle a des enfants et est ouverte if (previous.hasChildren()) { // Si oui, on prend son dernier enfant while (previous.hasChildren()) { previous = previous.getLastBranch(); } branch = previous; } else { // Si ce n'est pas le cas, on la prend elle branch = previous; } } else { // Si elle n'a pas de soeur précédente, on prend le parent (s'il existe) if (this.parent) { branch = this.parent; } } return branch; }, /** * Retourne la branche suivante dans l'arbre, pas forcément de même niveau * * @access public * @return TafelTreeBranch La branche suivante, null s'il n'y en a pas */ getNextBranch : function () { var branch = null; // Récupère le premier enfant, s'il y en a un branch = this.getFirstBranch(); if (!branch) { // Récupère sa prochaine soeur branch = this.getNextSibling(); if (!branch) { // Récupère la soeur du parent ou tout du moins d'un ancêtre var b = null; branch = this.parent; while (!b && branch) { b = branch.getNextSibling(); branch = branch.parent; } branch = b; } } return branch; }, /** * Retourne la branch ouverte précédente (pas forcément du même niveau) * * @access public * @return TafelTreeBranch La branche précédente ouverte, null s'il n'y en a pas */ getPreviousOpenedBranch : function () { var branch = null; var previous = this.getPreviousSibling(); // Si elle a une soeur précédente if (previous) { // On regarde si elle a des enfants et est ouverte if (previous.hasChildren() && previous.isOpened()) { // Si oui, on prend son dernier enfant while (previous.hasChildren() && previous.isOpened()) { previous = previous.getLastBranch(); } branch = previous; } else { // Si ce n'est pas le cas, on la prend elle branch = previous; } } else { // Si elle n'a pas de soeur précédente, on prend le parent (s'il existe) if (this.parent) { branch = this.parent; } } return branch; }, /** * Retourne la branch ouverte suivante (pas forcément du même niveau) * * @access public * @return TafelTreeBranch La branche suivante ouverte, null s'il n'y en a pas */ getNextOpenedBranch : function () { var branch = null; // Si elle a des enfants et qu'elle est ouverte, on prend le 1er if (this.hasChildren() && this.isOpened()) { branch = this.getFirstBranch(); } else { // Si elle a pas d'enfants, on prend sa prochaine soeur var next = this; while (!branch) { branch = next.getNextSibling(); next = next.parent; if (!next) break; } } return branch; }, /** * Fonction qui supprime tous les enfants * * @access public * @return boolean True si la branche est un enfant de elem */ removeChildren : function () { // On utilise concat() pour ne pas faire de référence sur this.children var children = this.children.concat(); for (var i = 0; i < children.length; i++) { this.tree.removeBranch(children[i]); } }, /** * Fonction qui détermine si la branche est enfant de elem * * @access public * @param TafelTreeBranch elem La branche dont on veut savoir si elle est un ancêtre * @return boolean True si la branche est un enfant de elem */ isChild : function (elem) { var elem = this.tree.getBranchById(elem); if (!elem) return false; return this._isChild(this, elem); }, /** * Fonction qui ouvre ou ferme la branche * * @access public * @param boolean open True pour ouvrir la branche * @return void */ openIt : function (open) { try { if (!open) { this._closeChild(); if (this.tree.multiline) { this._manageMultiline(this.tdImg, 2, false); } } else { if (this.tree.onlyOneOpened) { this.closeSiblings(); } this._openChild(); if (this.tree.multiline) { this._manageMultiline(this.tdImg, 2, true); } } if (this.tree.useCookie) { this.tree.setCookie(this.tree.classTree + this.tree.id); } } catch (err) { throw new Error ('openIt(base) : ' + err.message); } }, /** * Fonction qui insère une branche comme enfant, en fin de liste * * @access public * @param object item La nouvelle branche * @return void */ insert : function (item) { return this.insertIntoLast(item); }, insertIntoLast : function (item) { var pos = this.children.length; var isNotFirst = (this.hasChildren()) ? true : false; this.children[pos] = new TafelTreeBranch((this.isRoot) ? this : this.root, this, item, this.level + 1, isNotFirst, false, pos); this.struct.items[pos] = item; this.obj.appendChild(this.children[pos].obj); this._manageAfterInsert(pos); return this.children[pos]; }, insertIntoFirst : function (item) { var pos = 0; var posBefore = 1; var isNotLast = (this.hasChildren()) ? false : true; this._movePartStruct(pos); this.struct.items[pos] = item; this.children[pos] = new TafelTreeBranch((this.isRoot) ? this : this.root, this, item, this.level + 1, false, isNotLast, pos); try { this.obj.insertBefore(this.children[pos].obj, this.children[posBefore].obj); } catch (err) { this.obj.appendChild(this.children[pos].obj); } this._manageAfterInsert(pos); return this.children[pos]; }, /** * Fonction qui ferme toutes les branches soeurs * * @access public * @return void */ closeSiblings : function () { var obj = null; if (this.parent) { for (var i = 0; i < this.parent.children.length; i++) { obj = this.parent.children[i]; if (obj.idObj != this.idObj && obj.hasChildren()) { obj.openIt(false); } } } else if (this.isRoot) { for (var i = 0; i < this.tree.roots.length; i++) { obj = this.tree.roots[i]; if (obj.idObj != this.idObj && obj.hasChildren()) { obj.openIt(false); } } } }, /** * Ajoute une classe CSS au texte * * @access public * @param string style Le style CSS à ajouter * @return void */ addClass : function (style) { Element.addClassName(this.txt, style); }, /** * Retire une classe CSS du texte * * @access public * @param string style Le style CSS à enlever * @return void */ removeClass : function (style) { Element.removeClassName(this.txt, style); }, /** * Retourne un objet anonyme représentant l'image précédant l'icône (un plus, par ex.) * * L'objet a cette structure : var obj = { 'img' : HTMLimgElement, 'number' : Le numéro de l'image (juste avant l'extension), 'type' : le nom de l'image sans le numéro et sans l'extension 'name' : Le nom de l'image sans l'extension, 'fullName': Le nom de l'image avec l'extension }; * * @access public * @return object L'objet anonyme de l'image */ getImgBeforeIcon : function () { try { var img = this.beforeIcon.getElementsByTagName('img')[0]; return this._getImgInfo(img); } catch (err) { throw new Error ('getImgBeforeIcon(base) : ' + err.message); } }, /** * Fonction change l'icône en fonction des enfants, s'il y en a ou pas * * @access public * @param boolean openable True pour mettre l'icone d'ouverture * @return void */ setOpenableIcon : function (openable) { var im = this.getImgBeforeIcon(); var img = im.img; if (openable) { this.struct.open = true; this.img.src = this.tree.imgBase + this.struct.imgopen; if (!this.isRoot) { img.src = (this.hasSiblingsAfter) ? this.tree.imgBase + this.tree.imgMinus3 : this.tree.imgBase + this.tree.imgMinus2; } else { if (this.hasSiblingsBefore) { img.src = (this.hasSiblingsAfter) ? this.tree.imgBase + this.tree.imgMinus3 : this.tree.imgBase + this.tree.imgMinus2; } else { img.src = (this.hasSiblingsAfter) ? this.tree.imgBase + this.tree.imgMinus4 : this.tree.imgBase + this.tree.imgMinus5; } } Event.observe(img, 'click', this.setOpen.bindAsEventListener(this), false); Event.observe(img, 'mouseover', this.evt_openMouseOver.bindAsEventListener(this), false); Event.observe(img, 'mouseout', this.evt_openMouseOut.bindAsEventListener(this), false); } else { this.struct.open = false; this.struct.canhavechildren = false; this.img.src = this.tree.imgBase + this.struct.img; var td = img.parentNode; var newImg = document.createElement('img'); td.removeChild(img); if (!this.isRoot) { newImg.src = (this.hasSiblingsAfter) ? this.tree.imgBase + this.tree.imgLine3 : this.tree.imgBase + this.tree.imgLine2; } else { if (this.hasSiblingsBefore) { newImg.src = (this.hasSiblingsAfter) ? this.tree.imgBase + this.tree.imgLine3 : this.tree.imgBase + this.tree.imgLine2; } else { newImg.src = (this.hasSiblingsAfter) ? this.tree.imgBase + this.tree.imgLine4 : this.tree.imgBase + this.tree.imgLine5; } } td.appendChild(newImg); } }, /** * Fonction qui affiche la branche de manière cool * * @access public * @return string La string à afficher */ toString : function () { var str = (this.isRoot) ? 'TafelTreeRoot {' : 'TafelTreeBranch {'; // Définition de toutes les propriétés var strSave = ''; for (var attr in this.struct) { if (attr != 'items') { strSave = (typeof(this.struct[attr]) != 'function') ? this.struct[attr] : true; str += TafelTree.debugReturn + TafelTree.debugTab + attr + ' : ' + strSave; } } str += TafelTree.debugReturn + TafelTree.debugTab + 'children : ' + this.children.length; str += TafelTree.debugReturn + '}'; return str; }, isChecked : function (dbg) { if (this.tree.checkboxes && this.checkbox) { var img = this._getImgInfo(this.checkbox); if (img.fullName.replace('_over', '') == this.tree.imgCheck2) { return 1; } if (img.fullName.replace('_over', '') == this.tree.imgCheck3) { return -1; } return 0; } return 0; }, getCheckbox : function () { return (this.checkbox) ? this.checkbox : false; }, check : function (checked) { if (this.checkbox) { if (checked == -1) { this.checkbox.src = this.tree.imgBase + this.tree.imgCheck3; this.struct.check = -1; } else if (checked) { this.checkbox.src = this.tree.imgBase + this.tree.imgCheck2; this.struct.check = 1; if (this.tree.useCookie) { this.tree.setCookie(this.tree.classTree + this.tree.id); } } else { this.checkbox.src = this.tree.imgBase + this.tree.imgCheck1; this.struct.check = 0; if (this.tree.useCookie) { this.tree.setCookie(this.tree.classTree + this.tree.id); } } } }, /** * Fonction qui retourne 1 si tous les enfants sont checkés, 0 si aucun et -1 si quelques uns * * @access public * @return integer 1 si tout check, 0 si aucun, -1 si pas tous */ hasAllChildrenChecked : function () { var allChecked = false; var anyChecked = false; for (var i = 0; i < this.children.length; i++) { if (this.children[i].isChecked() == -1) { allChecked = true; anyChecked = true; break; } if (this.children[i].isChecked() == 1) allChecked = true; else anyChecked = true; } if (allChecked && anyChecked) return -1; if (allChecked) return 1; else return 0; }, /** * Permet d'intervertir les deux branches. Elles conserveront toutes leurs * caractéristiques (heureusement) * * @access public * @param TafelTreeBranch branchId L'id de l'autre branche ou l'autre branche elle-même * @return void */ switchWith : function (branchId) { var branch = this.tree.getBranchById(branchId); if (!branch) return false; var copyThis = this.copiedTimes; var newThis = this.clone(); var txtThis = this.getText(); var idThis = this.getId(); var copyBanch = branch.copiedTimes; var newBranch = branch.clone(); var txtBranch = branch.getText(); var idBranch = branch.getId(); // On change l'id de la branche courante this.changeId('temp_switch_change_' + this.tree.idTree); // Inversion des branches var n1 = branch.insertBefore(newThis); this.tree.removeBranch(branch); n1.setText(txtThis); n1.changeId(idThis); n1.copiedTimes = copyThis; var n2 = this.insertBefore(newBranch); this.tree.removeBranch(this); n2.setText(txtBranch); n2.changeId(idBranch); n2.copiedTimes = copyBranch; }, /** * Remplace la branche passée en paramètre par l'autre. * * @access public * @param TafelTreeBranch branchId L'id de la branche à remplacer ou l'objet lui-même * @param boolean copy True pour faire une copie de la branche qui remplace * @return TafelTreeBranch La branche remplacée */ replace : function (branchId, copy) { var branch = this.tree.getBranchById(branchId); if (!branch) return false; // Préparation du remplacement var copyThis = this.copiedTimes; var newThis = this.clone(); var n1 = branch.insertBefore(newThis); this.tree.removeBranch(branch); if (!copy) { var idThis = this.getId(); n1.setText(this.getText()) this.tree.removeBranch(this); n1.changeId(idThis); n1.copiedTimes = copyThis; } return n1; }, /** * Méthode récursive qui ouvre la branche * * @access public * @return void */ expend : function () { if (this.isOpened() != true && this.hasChildren()) { this.openIt(true); } for (var i = 0; i < this.children.length; i++) { this.children[i].expend(); } }, /** * Méthode récursive qui ferme la branche * * @access public * @return void */ collapse : function () { if (this.isOpened() != false && this.hasChildren()) { this.openIt(false); } for (var i = 0; i < this.children.length; i++) { this.children[i].collapse(); } }, /** * Retourne toutes les branches de l'arbre * * @access public * @param function filter Le filtre des branches * @param array [branches] Optionnel, le tableau des branches incomplet * @return array Un tableau des branches de l'arbre */ getBranches : function (filter, branches) { if (!branches) branches = []; for (var i = 0; i < this.children.length; i++) { if (typeof(filter) == 'function') { if (filter(this.children[i])) { branches.push(this.children[i]); } } else { branches.push(this.children[i]); } branches = this.children[i].getBranches(filter, branches); } return branches; }, /** * Retourne les branches parentes (qui ont des enfants) * * @access public * @param array [parent] Optionnel, le tableau des branches parentes incomplet * @return array Le tableau des branches parentes complet */ getParentBranches : function (parents) { if (!parents) parents = []; for (var i = 0; i < this.children.length; i++) { if (this.children[i].hasChildren()) { parents.push(this.children[i]); } parents = this.children[i].getParentBranches(parents); } return parents; }, /** * Retourne les branches qui n'ont pas d'enfants * * @access public * @param array [leafs] Optionnel, le tableau des branches incomplet * @return array Le tableau des branches complet */ getLeafBranches : function (leafs) { if (!leafs) leafs = []; for (var i = 0; i < this.children.length; i++) { if (!this.children[i].hasChildren()) { leafs.push(this.children[i]); } leafs = this.children[i].getLeafBranches(leafs); } return leafs; }, /** * Retourne le nombre de branche comprises dans la branche courante * * @access public * @return integer Le nombre de branches */ countBranches : function () { var nb = this.children.length; for (var i = 0; i < this.children.length; i++) { nb += this.children[i].countBranches(); } return nb; }, /** * Méthode récursive qui détermine si la branche est ouverte ou non * * @access public * @param array openedBranches Le tableau des branches ouvertes * @return void */ getOpenedBranches : function (openedBranches) { if (!openedBranches) openedBranches = []; for (var i = 0; i < this.children.length; i++) { if (this.children[i].isOpened() && this.children[i].hasChildren()) { openedBranches.push(this.children[i]); } openedBranches = this.children[i].getOpenedBranches(openedBranches); } return openedBranches; }, /** * Méthode récursive qui détermine si la branche est checkée * * @access private * @param array checkedBranches Le tableau des branches checkées * @return void */ getCheckedBranches : function (checkedBranches) { return this._getCheckedBranches(checkedBranches, 1); }, /** * Méthode récursive qui détermine si la branche est checkée * * @access private * @param array checkedBranches Le tableau des branches checkées * @return void */ getUnCheckedBranches : function (checkedBranches) { return this._getCheckedBranches(checkedBranches, 0); }, /** * Méthode récursive qui détermine si la branche est checkée * * @access private * @param array checkedBranches Le tableau des branches checkées * @return void */ getPartCheckedBranches : function (checkedBranches) { return this._getCheckedBranches(checkedBranches, -1); }, /** * Sélectionne la branche * * @access public * @param Event ev L'événement déclencheur * @return void */ select : function (ev) { var ctrl = (ev) ? TafelTreeManager.ctrlOn(ev) : false; var shift = (ev) ? TafelTreeManager.shiftOn(ev) : false; if (ctrl) { this.tree.selectedBranches.push(this); } else if (shift && this.tree.selectedBranches.length > 0) { var last = this.tree.selectedBranches.length - 1; var sel = this.tree.getBranchesBetween(this.tree.selectedBranches[last], this); for (var i = 0; i < sel.length; i++) { this.tree.selectedBranches.push(sel[i]); Element.addClassName(sel[i].txt, this.tree.classSelected); } } else { this.tree.unselect(); this.tree.selectedBranches.push(this); } Element.addClassName(this.txt, this.tree.classSelected); // On set l'icône s'il doit changer if (this.isOpened() && this.hasChildren() && this.getOpenIconSelected()) { this.img.src = this.tree.imgBase + this.getOpenIconSelected(); } else if (!this.isOpened() && this.hasChildren() && this.getCloseIconSelected()) { this.img.src = this.tree.imgBase + this.getCloseIconSelected(); } else if (!this.hasChildren() && this.getIconSelected()) { this.img.src = this.tree.imgBase + this.getIconSelected(); } if (ev) Event.stop(ev); }, /** * Désélectionne la branche * * @access public * @return boolean True si la branche a pu être déselectionnée, false sinon */ unselect : function () { var ln = this.tree.selectedBranches.length; if (ln > 0) { for (var i = 0; i < ln; i++) { if (this.tree.selectedBranches[i].getId() == this.getId()) { this.tree.selectedBranches.splice(i, 1); Element.removeClassName(this.txt, this.tree.classSelected); // On set l'icône s'il doit changer if (this.hasChildren()) { this.img.src = (this.isOpened()) ? this.tree.imgBase + this.struct.imgopen : this.tree.imgBase + this.struct.imgclose; } else { this.img.src = this.tree.imgBase + this.struct.img; } return true; } } } return false; }, /** * Calcule la position de la branche à l'intérieur de l'arbre * * @access public * @return array [0] Left pos, [1] Top pos */ getWithinOffset : function () { var realPos = Position.positionedOffset(this.txt); var posTree = Position.positionedOffset(this.tree.div); var pos = [ realPos[0] - posTree[0], realPos[1] - posTree[1] ]; return pos; }, /** * Calcule la position de la branche dans l'écran * * @access public * @return array [0] Left pos, [1] Top pos */ getAbsoluteOffset : function () { return Position.positionedOffset(this.txt); }, /** * Permet de sérialiser la branche, pour en faire une string au format JSON * * Les fonctions ne sont pas encodées dans la string (comme onopen, onclick, etc.). Par contre, on indique * true si la fonction existe bel et bien pour la branche * * @access public * @param boolean debug True pour afficher le debug de la string * @param boolean noEncoding True pour ne pas encoder la string automatiquement * @return string La string JSON de la branche */ serialize : function (debug, noEncoding) { var tab = ''; var rt = ''; if (debug) { rt = TafelTree.debugReturn; for (var i = 0; i < this.level; i++) { tab += TafelTree.debugTab; } } var strSave = ''; var str = rt + tab + '{' + rt; // Définition de toutes les propriétés str += tab + '"id":"' + this._encode(this.struct.id) + '"'; for (var attr in this.struct) { if (attr != 'items' && attr != 'id') { strSave = (typeof(this.struct[attr]) != 'function') ? this.struct[attr] : true; if (this.isBool(strSave)) { str += "," + rt + tab + '"' + attr + '":' + this._encode(strSave); } else { str += "," + rt + tab + '"' + attr + '":"' + this._encode(strSave) + '"'; } } } // Définition des enfants if (this.hasChildren()) { str += ',' + rt + tab + '"items":['; for (var i = 0; i < this.children.length; i++) { str += this.children[i].serialize(debug, true); if (i < this.children.length - 1) { str += ','; } } str += rt + tab + ']'; } str += rt + tab + '}'; if (!noEncoding) { return encodeURIComponent(str); } else { return str; } }, isBool : function (str) { switch (str) { case 'true': case 'false': case true: case false: case '1': case '0' : case 1: case 0 : return true; default : return false; } }, showTooltip : function () { if (this.displayTooltip) { this.tooltip.style.display = 'block'; } }, hideTooltip : function () { if (!this.displayTooltip) { Element.hide(this.tooltip); } }, /** * Fonction récursive qui supprime les liens avec Droppables et Draggable * * @access public * @param TafelTreeBranch obj La branche courante * @return void */ removeDragDrop : function () { if (this.objDrag) { this.objDrag.destroy(); } Droppables.remove(this.txt); for (var i = 0; i < this.children.length; i++) { this.children[i].removeDragDrop(); } }, /** *------------------------------------------------------------------------------ * TafelTreeBaseBranch private methods *------------------------------------------------------------------------------ */ /** * Fonction qui met à jour l'élément en terme de multiline * * @access private * @param HTMLElement element L'élément HTML incriminé * @param integer type 1 ou 2 (suivant le type de ligne) * @param boolean add True si on ajoute le multiline, false si on l'enlève * @return void */ _manageMultiline : function (element, type, add) { switch (type) { case 2 : if (!add) { Element.removeClassName(element, this.tree.imgMulti4); element.style.background = 'none'; } else { Element.addClassName(element, this.tree.imgMulti4); element.style.background = 'url("' + this.tree.imgBase + this.tree.imgMulti2 + '")'; element.style.backgroundRepeat = 'repeat-y'; } break; case 1 : default : if (!add) { Element.removeClassName(element, this.tree.imgMulti3); element.style.background = 'none'; } else { Element.addClassName(element, this.tree.imgMulti3); element.style.background = 'url("' + this.tree.imgBase + this.tree.imgMulti1 + '")'; element.style.backgroundRepeat = 'repeat-y'; } } }, _createTooltip : function () { var div = document.createElement('div'); div.className = this.tree.classTooltip; div.innerHTML = (this.struct.tooltip) ? this.struct.tooltip : ' '; Event.observe(div, 'mouseover', this.showTooltip.bindAsEventListener(this), false); return div; }, _manageAfterInsert : function (pos) { this.tree._changeStruct(this); this._manageLine(); // Si on a des checkboxes, on corrige les images en fonction des checks par défaut if (this.tree.checkboxes && this.tree.checkboxesThreeState) { this.children[pos]._adjustParentCheck(); } if (this.children.length == 1 && !this.struct.canhavechildren) { this.setOpenableIcon(true); } this.openIt((!this.tree.openedAfterAdd && !this.isOpened()) ? false : true); }, _movePartStruct : function (pos) { var nb = this.struct.items.length - 1; var newPos = 0; for (var i = nb; i >= pos; i--) { newPos = i + 1; this.struct.items[newPos] = this.struct.items[i]; this.children[newPos] = this.children[i]; this.children[newPos].pos = newPos; } }, /** * Méthode récursive qui détermine si la branche est checkée ou non * * @access private * @param array checkedBranches Le tableau des branches checkées * @param boolean checked 1 pour récupérer les branches checkées * @return void */ _getCheckedBranches : function (checkedBranches, checked) { if (!checkedBranches) checkedBranches = []; for (var i = 0; i < this.children.length; i++) { if (this.children[i].isChecked() == checked) { checkedBranches.push(this.children[i]); } checkedBranches = this.children[i]._getCheckedBranches(checkedBranches, checked); } return checkedBranches; }, _generate : function () { var i = this.bigTreeLoading; if (i < this.struct.items.length) { if (this.tree.checkboxesThreeState && this.struct.check && typeof(this.struct.items[i].check) == 'undefined') { this.struct.items[i].check = 1; } isNotFirst = (i > 0) ? true : false; isNotLast = (i < this.struct.items.length - 1) ? true : false; this.children[i] = new TafelTreeBranch((this.isRoot) ? this : this.root, this, this.struct.items[i], this.level + 1, isNotFirst, isNotLast, i); this.obj.appendChild(this.children[i].obj); this.openIt((this.tree.useCookie) ? this.isOpenedInCookie : this.struct.open); this.tree.loadRunning(this.children[i]); this.bigTreeLoading++; setTimeout(this._generate.bind(this), 10); } else { this.loaded = true; } }, _getPos : function () { pos = this.children.length; for (var i = 0; i < this.children.length; i++) { if (this.children[i].isAlwaysLast()) { pos--; } } if (pos < 0 ) pos = 0; return pos; }, /** * Fonction qui ajuste le check des parent de la branche, suite à un changement * * @access private * @param boolean fromBranch True pour commencer l'ajustement depuis la branche même * @return void */ _adjustParentCheck : function (fromBranch) { if (this.parent) { var branch = (!fromBranch) ? this.parent : this; while (branch && branch.checkbox) { branch.check(branch.hasAllChildrenChecked()); branch = branch.parent; } } }, /** * Fonction récursive qui va changer le status des checkboxes enfants * * @access private * @param TafelTreeBranch branch La branche courante * @param boolean checked True ou false * @return void */ _manageCheckThreeState : function (branch, checked) { for (var i = 0; i < branch.children.length; i++) { if (branch.tree.checkboxes && branch.children[i].checkbox) { branch.children[i].check(checked); branch._manageCheckThreeState(branch.children[i], checked); } } }, _getImgInfo : function (img) { var url = img.src.split('/'); var name = url[url.length-1].split('.'); var obj = { 'img': img, 'number': name[0].charAt(name[0].length-1), 'type': name[0].substr(0, name[0].length-1), 'name': name[0], 'fullName': url[url.length-1] }; return obj; }, /** * Permet d'encoder la string avant l'envoi en JSON * * @access private * @param string str La string correspondant à la propriété (this.struct.*) * @return string La valeur de la propriété encodée */ _encode : function (str) { //var obj = eval(str); var obj = (str === null) ? '' : str; return obj.toString().replace(/\"/g, '\\"'); }, _closeChild : function (img) { try { img = this.getImgBeforeIcon().img; this.struct.open = false; if (this.isSelected() && this.getCloseIconSelected()) { this.img.src = this.tree.imgBase + this.getCloseIconSelected(); } else { this.img.src = this.tree.imgBase + this.struct.imgclose; } for (var i = 0; i < this.obj.childNodes.length; i++) { if (this.obj.childNodes[i].nodeName.toLowerCase() == 'div') { Element.hide(this.obj.childNodes[i]); } } if (!this.isRoot) { img.src = (this.hasSiblingsAfter) ? this.tree.imgBase + this.tree.imgPlus3 : this.tree.imgBase + this.tree.imgPlus2; } else { if (this.hasSiblingsBefore) { img.src = (this.hasSiblingsAfter) ? this.tree.imgBase + this.tree.imgPlus3 : this.tree.imgBase + this.tree.imgPlus2; } else { img.src = (this.hasSiblingsAfter) ? this.tree.imgBase + this.tree.imgPlus4 : this.tree.imgBase + this.tree.imgPlus5; } } } catch (err) { throw new Error ('_closeChild(base) : ' + err.message); } }, _openChild : function (img) { try { img = this.getImgBeforeIcon().img; this.struct.open = true; if (this.isSelected() && this.getOpenIconSelected()) { this.img.src = this.tree.imgBase + this.getOpenIconSelected(); } else { this.img.src = this.tree.imgBase + this.struct.imgopen; } for (var i = 0; i < this.obj.childNodes.length; i++) { if (this.obj.childNodes[i].nodeName.toLowerCase() == 'div') { this.obj.childNodes[i].style.display = ''; } } if (!this.isRoot) { img.src = (this.hasSiblingsAfter) ? this.tree.imgBase + this.tree.imgMinus3 : this.tree.imgBase + this.tree.imgMinus2; } else { if (this.hasSiblingsBefore) { img.src = (this.hasSiblingsAfter) ? this.tree.imgBase + this.tree.imgMinus3 : this.tree.imgBase + this.tree.imgMinus2; } else { img.src = (this.hasSiblingsAfter) ? this.tree.imgBase + this.tree.imgMinus4 : this.tree.imgBase + this.tree.imgMinus5; } } } catch (err) { throw new Error ('_openChild(base) : ' + err.message); } }, /** * Fonction qui gère les lignes verticales après un drag and drop * * @access private * @return void */ _manageLine : function () { try { for (var i = 0; i < this.children.length; i++) { this.children[i].pos = i; // Si on est au dernier enfant et que celui-ci n'était pas le dernier avant le remove if (i == this.children.length - 1 && this.children[i].hasSiblingsAfter) { this.children[i].hasSiblingsAfter = false; this._manageMultiline(this.children[i].beforeIcon, 1, false); this._clearLine(this.children[i], this.level); } // Si on n'est pas au dernier enfant et que celui-ci était le dernier avant le remove if (i < this.children.length - 1 && !this.children[i].hasSiblingsAfter) { this.children[i].hasSiblingsAfter = true; this._manageMultiline(this.children[i].beforeIcon, 1, true); this._addLine(this.children[i], this.level); } } this.tree._changeStruct(this); } catch (err) { throw new Error ('_manageLine(base) : ' + err.message); } }, _manageLineForRoot : function (add) { for (var i = 0; i < this.children.length; i++) { this.children[i]._manageLineForRoot(add); } var td = this.table.getElementsByTagName('td')[0]; var img = td.getElementsByTagName('img')[0]; if (add) { img.src = this.tree.imgBase + this.tree.imgLine1; } else { img.src = this.tree.imgBase + this.tree.imgEmpty; } }, /** * Fonction qui supprime des lignes au bon endroit* * * @param TafelTreeBranch obj La branche courante * @param integer level Le niveau où supprimer des lignes * @param boolean ok False pour le 1er niveau de branche * @return void */ _clearLine : function (obj, level, ok) { try { for (var i = 0; i < obj.children.length; i++) { this._clearLine(obj.children[i], level, true); } // On récupère la bonne TD et la bonne image var img = obj.table.getElementsByTagName('img')[level+1]; if (ok) { img.src = this.tree.imgBase + this.tree.imgEmpty; if (this.tree.multiline) { this._manageMultiline(img.parentNode, 1, false); } } else { var old = obj.getImgBeforeIcon(); switch (old.fullName.replace('_over', '')) { case this.tree.imgLine1 : case this.tree.imgLine3 : newImg = this.tree.imgLine2; break; case this.tree.imgPlus1 : case this.tree.imgPlus3 : newImg = this.tree.imgPlus2; break; case this.tree.imgMinus1: case this.tree.imgMinus3: newImg = this.tree.imgMinus2; break; default: newImg = obj.fullName; } img.src = this.tree.imgBase + newImg; } } catch (err) { throw new Error ('_clearLine(base) : ' + err.message); } }, /** * Fonction qui ajoute des lignes au bon endroit* * * @param TafelTreeBranch obj La branche courante * @param integer level Le niveau où ajouter des lignes * @param boolean ok False pour le 1er niveau de branche * @return void */ _addLine : function (obj, level, ok) { try { for (var i = 0; i < obj.children.length; i++) { this._addLine(obj.children[i], level, true); } // On récupère la bonne TD et la bonne image var img = obj.table.getElementsByTagName('img')[level+1]; if (ok) { img.src = this.tree.imgBase + this.tree.imgLine1; if (this.tree.multiline) { this._manageMultiline(img.parentNode, 1, true); } } else { var old = obj.getImgBeforeIcon(); switch (old.fullName.replace('_over', '')) { case this.tree.imgLine1 : case this.tree.imgLine2 : newImg = this.tree.imgLine3; break; case this.tree.imgPlus1 : case this.tree.imgPlus2 : newImg = this.tree.imgPlus3; break; case this.tree.imgMinus1: case this.tree.imgMinus2: newImg = this.tree.imgMinus3; break; default: newImg = obj.fullName; } img.src = this.tree.imgBase + newImg; } } catch (err) { throw new Error ('_addLine(base) : ' + err.message); } }, _isChild : function (child, parent) { try { if (parent.idObj == child.idObj) return true; if (child.parent) { return this._isChild(child.parent, parent); } return false; } catch (err) { throw new Error ('_isChild(base) : ' + err.message); } }, /** * Set les propriétés utilisateur de la branche, ou celles par défaut * * @access private * @return void */ _setProperties : function () { // Images if ((typeof(this.struct.img) == 'undefined')) { this.struct.img = (this.tree.icons[0]) ? this.tree.icons[0] : this.tree.imgLine0; } if ((typeof(this.struct.imgopen) == 'undefined')) { this.struct.imgopen = (this.tree.icons[1]) ? this.tree.icons[1] : this.struct.img; } if ((typeof(this.struct.imgclose) == 'undefined')) { this.struct.imgclose = (this.tree.icons[2]) ? this.tree.icons[2] : this.struct.img; } if ((typeof(this.struct.imgselected) == 'undefined')) { this.struct.imgselected = (this.tree.iconsSelected[0]) ? this.tree.iconsSelected[0] : null; } if ((typeof(this.struct.imgopenselected) == 'undefined')) { this.struct.imgopenselected = (this.tree.iconsSelected[1]) ? this.tree.iconsSelected[1] : null; } if ((typeof(this.struct.imgcloseselected) == 'undefined')) { this.struct.imgcloseselected = (this.tree.iconsSelected[2]) ? this.tree.iconsSelected[2] : null; } // Fonctions if (typeof(this.struct.open) == 'undefined') { this.struct.open = (this.tree.useCookie && this.tree.cookieOpened) ? false : this.tree.openAll; } else if (this.tree.useCookie && this.tree.cookieOpened) { this.struct.open = false; } if (typeof(this.struct.check) == 'undefined' || (this.tree.useCookie && this.tree.cookieChecked)) this.struct.check = 0; if (typeof(this.struct.items) == 'undefined') { this.struct.items = []; } if (typeof(this.struct.canhavechildren) == 'undefined') this.struct.canhavechildren = false; if (typeof(this.struct.id) == 'undefined') this.struct.id = this.idObj; if (typeof(this.struct.acceptdrop) == 'undefined') this.struct.acceptdrop = true; if (typeof(this.struct.last) == 'undefined') this.struct.last = false; if (typeof(this.struct.editable) == 'undefined') this.struct.editable = this.tree.editableBranches; if (typeof(this.struct.checkbox) == 'undefined') this.struct.checkbox = true; }, /** * Set les fonctions utilisateur et les fonctions par défaut, s'il y en a * * @access private * @return void */ _setFunctions : function () { if (typeof(this.struct.ondragstarteffect) == 'undefined') { if (typeof(this.tree.onDragStartEffect) == 'function') { this.struct.ondragstarteffect = this.tree.onDragStartEffect; this.ondragstarteffectDefault = true; } } else {this.struct.ondragstarteffect = eval(this.struct.ondragstarteffect);} if (typeof(this.struct.ondragendeffect) == 'undefined') { if (typeof(this.tree.onDragEndEffect) == 'function') { this.struct.ondragendeffect = this.tree.onDragEndEffect; this.ondragendeffectDefault = true; } } else {this.struct.ondragendeffect = eval(this.struct.ondragendeffect);} if (typeof(this.struct.onerrorajax) == 'undefined') { if (typeof(this.tree.onErrorAjax) == 'function') { this.struct.onerrorajax = this.tree.onErrorAjax; this.onerrorajaxDefault = true; } } else {this.struct.onerrorajax = eval(this.struct.onerrorajax);} if (typeof(this.struct.oneditajax) == 'undefined') { if (this.tree.onEditAjax && typeof(this.tree.onEditAjax.func) == 'function') { this.struct.oneditajax = this.tree.onEditAjax.func; this.struct.editlink = this.tree.onEditAjax.link; this.oneditajaxDefault = true; } } else {this.struct.oneditajax = eval(this.struct.oneditajax);} if (typeof(this.struct.onopenpopulate) == 'undefined') { if (this.tree.onOpenPopulate && typeof(this.tree.onOpenPopulate.func) == 'function') { this.struct.onopenpopulate = this.tree.onOpenPopulate.func; this.struct.openlink = this.tree.onOpenPopulate.link; this.onopenpopulateDefault = true; } } else {this.struct.onopenpopulate = eval(this.struct.onopenpopulate);} if (typeof(this.struct.onedit) == 'undefined') { if (typeof(this.tree.onEdit) == 'function') { this.struct.onedit = this.tree.onEdit; this.oneditDefault = true; } } else {this.struct.onedit = eval(this.struct.onedit);} if (typeof(this.struct.oncheck) == 'undefined') { if (typeof(this.tree.onCheck) == 'function') { this.struct.oncheck = this.tree.onCheck; this.oncheckDefault = true; } } else {this.struct.oncheck = eval(this.struct.oncheck);} if (typeof(this.struct.onbeforecheck) == 'undefined') { if (typeof(this.tree.onBeforeCheck) == 'function') { this.struct.onbeforecheck = this.tree.onBeforeCheck; this.onbeforecheckDefault = true; } } else {this.struct.onbeforecheck = eval(this.struct.onbeforecheck);} if (typeof(this.struct.onopen) == 'undefined') { if (typeof(this.tree.onOpen) == 'function') { this.struct.onopen = this.tree.onOpen; this.onopenDefault = true; } } else {this.struct.onopen = eval(this.struct.onopen);} if (typeof(this.struct.onbeforeopen) == 'undefined') { if (typeof(this.tree.onBeforeOpen) == 'function') { this.struct.onbeforeopen = this.tree.onBeforeOpen; this.onbeforeopenDefault = true; } } else {this.struct.onbeforeopen = eval(this.struct.onbeforeopen);} if (typeof(this.struct.onmouseover) == 'undefined') { if (typeof(this.tree.onMouseOver) == 'function') { this.struct.onmouseover = this.tree.onMouseOver; this.onmouseoverDefault = true; } } else {this.struct.onmouseover = eval(this.struct.onmouseover);} if (typeof(this.struct.onmouseout) == 'undefined') { if (typeof(this.tree.onMouseOut) == 'function') { this.struct.onmouseout = this.tree.onMouseOut; this.onmouseoutDefault = true; } } else {this.struct.onmouseout = eval(this.struct.onmouseout);} if (typeof(this.struct.onmousedown) == 'undefined') { if (typeof(this.tree.onMouseDown) == 'function') { this.struct.onmousedown = this.tree.onMouseDown; this.onmousedownDefault = true; } } else {this.struct.onmousedown = eval(this.struct.onmousedown);} if (typeof(this.struct.onmouseup) == 'undefined') { if (typeof(this.tree.onMouseUp) == 'function') { this.struct.onmouseup = this.tree.onMouseUp; this.onmouseupDefault = true; } } else {this.struct.onmouseup = eval(this.struct.onmouseup);} if (typeof(this.struct.onclick) == 'undefined') { if (typeof(this.tree.onClick) == 'function') { this.struct.onclick = this.tree.onClick; this.onclickDefault = true; } } else {this.struct.onclick = eval(this.struct.onclick);} if (typeof(this.struct.ondblclick) == 'undefined') { if (typeof(this.tree.onDblClick) == 'function') { this.struct.ondblclick = this.tree.onDblClick; this.ondblclickDefault = true; } } else {this.struct.ondblclick = eval(this.struct.ondblclick);} }, /** * Set actions like selecting node * * @access private * @return void */ _setActions : function () { if (this.struct.select) { this.select(); } }, /** * Fonction qui set les divers événements en fonction des données utilisateur * * @access private * @param HTMLTdElement event La cellule qui contient le texte * @param HTMLTdElement tdImg La cellule qui contient l'icône * @return void */ _setEvents : function (event, tdImg) { // Le onclick se fait de toutes façon Event.observe(this.txt, 'mousedown', this.setMouseDown.bindAsEventListener(this), false); Event.observe(this.txt, 'mouseup', this.setMouseUp.bindAsEventListener(this), false); // On set les événements if (typeof(this.struct.onclick) == 'function') { Event.observe(event, 'click', this.setClick.bindAsEventListener(this), false); } if (typeof(this.struct.ondblclick) == 'function' || this.struct.editable) { Event.observe(event, 'dblclick', this.setDblClick.bindAsEventListener(this), false); } if (typeof(this.struct.onmouseover) == 'function') { Event.observe(event, 'mouseover', this.setMouseOver.bindAsEventListener(this), false); } if (typeof(this.struct.onmouseout) == 'function') { Event.observe(event, 'mouseout', this.setMouseOut.bindAsEventListener(this), false); } if (this.struct.editable && (typeof(this.struct.onedit) == 'function' || typeof(this.struct.oneditajax) == 'function')) { this.editableInput = document.createElement('input'); this.editableInput.setAttribute('type', 'text'); this.editableInput.setAttribute('autocomplete', 'off'); this.editableInput.className = this.tree.classEditable; event.appendChild(this.editableInput); Event.observe(this.editableInput, 'blur', this.hideEditable.bindAsEventListener(this), false); } // On set l'option drag and drop if (!this.isRoot) { if (this.struct.draggable && (typeof(this.struct.ondrop) == 'function' || typeof(this.struct.ondropajax) == 'function')) { //this.objDrag = new Draggable(this.txt, {revert: this.tree.dragRevert, scroll: this.tree.div, ghosting: this.tree.dragGhosting}); this.objDrag = new Draggable(this.txt, { revert: this.tree.dragRevert, starteffect:this.ondragstarteffect.bindAsEventListener(this), endeffect:this.ondragendeffect.bindAsEventListener(this) }); Element.addClassName(this.txt, this.tree.classDrag); } } if (this.struct.acceptdrop) { Droppables.add(this.txt, {hoverclass: this.tree.classDragOver, onDrop: this.setDrop.bindAsEventListener(this)}); } if (this.struct.tooltip) { Event.observe(event, 'mouseover', this.evt_showTooltip.bindAsEventListener(this), false); Event.observe(event, 'mouseout', this.evt_hideTooltip.bindAsEventListener(this), false); } // On s'occupe des checkboxes, le cas échéant if (this.tree.checkboxes && this.struct.checkbox) { if (this.struct.check == 1) imgc = this.tree.imgCheck2; else if (this.struct.check == -1) imgc = this.tree.imgCheck3; else imgc = this.tree.imgCheck1; this.checkbox = document.createElement('img'); this.checkbox.src = this.tree.imgBase + imgc; tdImg.appendChild(this.checkbox); Event.observe(this.checkbox, 'click', this.checkOnClick.bindAsEventListener(this), false); Event.observe(this.checkbox, 'mouseover', this.evt_openMouseOver.bindAsEventListener(this), false); Event.observe(this.checkbox, 'mouseout', this.evt_openMouseOut.bindAsEventListener(this), false); } else if (this.tree.checkboxes) { // On met éventuellement une image vide au lieu de la checkbox var vide = document.createElement('img'); vide.src = this.tree.imgBase + this.tree.imgEmpty; tdImg.appendChild(vide); } }, _getImgBeforeIcon : function () { try { var td = document.createElement('td'); var img = document.createElement('img'); Element.addClassName(img, this.tree.classOpenable); // On détermine s'il y a des frères if (this.hasSiblingsAfter) { // On détermine s'il y a des enfants if (!this.hasChildren()) { if (this.isRoot) { img.src = this.tree.imgBase + ((this.hasSiblingsBefore) ? this.tree.imgLine3 : this.tree.imgLine4); } else { img.src = this.tree.imgBase + this.tree.imgLine3; } } else { Event.observe(img, 'click', this.setOpen.bindAsEventListener(this), false); Event.observe(img, 'mouseover', this.evt_openMouseOver.bindAsEventListener(this), false); Event.observe(img, 'mouseout', this.evt_openMouseOut.bindAsEventListener(this), false); if (this.isRoot) { img.src = this.tree.imgBase + ((this.hasSiblingsBefore) ? this.tree.imgMinus3 : this.tree.imgMinus4); } else { img.src = this.tree.imgBase + this.tree.imgMinus3; } } if (this.tree.multiline) { this._manageMultiline(td, (this.isRoot ? 2 : 1), true); } } else { // On détermine s'il y a des enfants if (!this.hasChildren()) { if (this.isRoot) { img.src = this.tree.imgBase + ((this.hasSiblingsBefore) ? this.tree.imgLine2 : this.tree.imgEmpty); } else { img.src = this.tree.imgBase + this.tree.imgLine2; } } else { Event.observe(img, 'click', this.setOpen.bindAsEventListener(this), false); Event.observe(img, 'mouseover', this.evt_openMouseOver.bindAsEventListener(this), false); Event.observe(img, 'mouseout', this.evt_openMouseOut.bindAsEventListener(this), false); if (this.isRoot) { img.src = this.tree.imgBase + ((this.hasSiblingsBefore) ? this.tree.imgMinus2 : this.tree.imgMinus5); } else { img.src = this.tree.imgBase + this.tree.imgMinus2; } } } td.appendChild(img); return td; } catch (err) { throw new Error ('_getImgBeforeIcon(base) : ' + err.message); } }, /** * Insère les enfants de la branche * * @access private * @param TafelTreeRoot root L'élément racine parent * @return void */ _setChildren : function (root) { if (this.hasChildren()) { if (this.tree.bigTreeLoading >= 0) { this.loaded = false; this.bigTreeLoading = 0; setTimeout(this._generate.bind(this), 10); } else { for (var i = 0; i < this.struct.items.length; i++) { if (this.tree.checkboxesThreeState && this.struct.check && typeof(this.struct.items[i].check) == 'undefined') { this.struct.items[i].check = 1; } isNotFirst = (i > 0) ? true : false; isNotLast = (i < this.struct.items.length - 1) ? true : false; this.children[i] = new TafelTreeBranch(root, this, this.struct.items[i], this.level + 1, isNotFirst, isNotLast, i); this.obj.appendChild(this.children[i].obj); } this.openIt(this.struct.open); } } }, /** * Set l'image de la branche à wait ainsi que ses enfants * * @access private * @param TafelTreeBranch branch La branche courante * @param boolean wait True pour afficher l'image d'attente * @param boolean localPropagationStop True pour ne pas avoir de propagation, false par défaut * @return void */ _setWaitImg : function (branch, wait, localPropagationStop) { try { this.inProcess = wait; if (wait) { branch.oldImgSrc = branch.img.src; branch.img.src = branch.tree.imgBase + branch.tree.imgWait; branch.eventable = false; } else { branch.eventable = true; branch.img.src = branch.oldImgSrc; } if (this.tree.propagation && !localPropagationStop) { for (var i = 0; i < branch.children.length; i++) { this._setWaitImg(branch.children[i], wait); } } } catch (err) { throw new Error ('_setWaitImg(base) : ' + err.message); } }, /** * Envoi d'une requête Ajax suite à une ouverture de branche * * @access private * @return void */ _openPopulate : function (ev) { try { this._setWaitImg(this, true); var params = 'branch=' + this.serialize() + '&branch_id=' + this.getId() + '&tree_id=' + this.tree.id; var otherParams = this.tree.getURLParams(this.struct.openlink); for (var i = 0; i < otherParams.length; i++) { params += '&' + otherParams[i].name + '=' + otherParams[i].value; } new Ajax.Updater ( this.tree.ajaxObj, this.struct.openlink, { 'method' : 'post', 'parameters' : params, 'evalScripts': true, 'onComplete' : function(event){this._completeOpenPopulate(event);}.bind(this), 'onFailure' : function(event){this._failureOpenPopulate(event);}.bind(this) } ); } catch (err) { this._setWaitImg(this, false); throw ('_openPopulate(base) : ' + err.message); } }, _failureOpenPopulate : function () { this._setWaitImg(this, false); if (typeof(this.struct.onerrorajax) == 'function') { this.struct.onerrorajax('open', 'failure request', this); } }, /** * Méthode appelée lorsque le retour ajax est effectué * * Pour pailler aux éventualités : str.match(/(?:\(\[)((\n|\r|.)*?)(?:\]\))/)[0] * * @access private * @param XMLhttpResquest response L'objet Ajax * @return void */ _completeOpenPopulate : function (response) { try { this._setWaitImg(this, false); var rep = this.struct.onopenpopulate(this, response.responseText); if (rep) { rep = (rep === true) ? response.responseText : rep; var items = eval(rep); if (items) { var ok = []; for (var i = 0 ; i < items.length; i++) { // unicity test if (this.tree.getBranchById(items[i].id)) continue; if (typeof(items[i].id) == 'undefined' || typeof(items[i].txt) == 'undefined') { throw new Error (TAFELTREE_WRONG_BRANCH_STRUCTURE); } ok.push(this.insertIntoLast(items[i])); } // Permet d'ouvrir les branches qui viennent du serveur au load de la page if (this.tree.useCookie && this.tree.cookieOpened && this.tree.reopenFromServer) { var okay = false; for (var o = 0; o < ok.length; o++) { okay = false; for (var i = 0; i < this.tree.cookieOpened.length; i++) { if (this.tree.cookieOpened[i] == ok[o].getId()) { okay = true; break; } } if (okay) { if (typeof(ok[o].struct.onopenpopulate) == 'function' && ok[o].eventable) { ok[o]._openPopulate(); ok[o].openIt(true); } } } } } } } catch (err) { this._setWaitImg(this, false); if (typeof(this.struct.onerrorajax) == 'function') { this.struct.onerrorajax('open', response.responseText, this); } else { alert ('_completeOpenPopulate(' + response.responseText + ') : ' + err.message); } } }, /** * Envoi d'une requête Ajax suite à un drop * * @access private * @param TafelTreeBranch newParentObj Le nouveau parent * @param boolean asSibling True pour dropper l'élément comme frère * @param boolean copydrag True si on fait un copy-drag * @return void */ _setDropAjax : function (newParentObj, asSibling, copydrag, ev) { try { this._setWaitImg(this, true); var sibling = (asSibling) ? 1 : 0; var cdrag = (copydrag) ? 1 : 0; var params = 'drag=' + this.serialize() + '&drag_id=' + this.getId() + '&drop=' + newParentObj.serialize() + '&drop_id=' + newParentObj.getId(); params += '&treedrag_id=' + this.tree.id + '&treedrop_id=' + newParentObj.tree.id + '&sibling=' + sibling + '©drag=' + cdrag; // On passe le futur id de l'élément copié s'il s'agit d'une copie if (cdrag) { var cdragId = this.id + this.tree.copyNameBreak + this.tree.idTree; params += '©drag_id=' + cdragId; } var otherParams = this.tree.getURLParams(this.struct.droplink); for (var i = 0; i < otherParams.length; i++) { params += '&' + otherParams[i].name + '=' + otherParams[i].value; } this.newParent = newParentObj; this.asSibling = asSibling; this.copyDrag = cdrag; new Ajax.Updater ( this.tree.ajaxObj, this.struct.droplink, { 'method' : 'post', 'parameters' : params, 'evalScripts': true, 'onComplete' : function(event){this._completeDropAjax(event);}.bind(this), 'onFailure' : function(event){this._failureDropAjax(event);}.bind(this) } ); } catch (err) { this._setWaitImg(this, false); throw ('_setDropAjax(base) : ' + err.message); } }, _failureDropAjax : function () { this._setWaitImg(this, false); if (typeof(this.struct.onerrorajax) == 'function') { this.struct.onerrorajax('drop', 'failure request', this, this.newParent); } }, /** * Méthode appelée lorsque le retour ajax est effectué * * @access private * @param XMLhttpResquest response L'objet Ajax * @return void */ _completeDropAjax : function (response) { try { if (this.struct.ondropajax(this, this.newParent, response.responseText, false, null)) { var newBranch = null; if (!this.asSibling) { if (!this.copyDrag) { this.move(this.newParent); } else { newBranch = this.newParent.insertIntoLast(this.clone()); } } else { if (!this.copyDrag) { this.moveBefore(this.newParent); } else { newBranch = this.newParent.insertBefore(this.clone()); } } this.struct.ondropajax(this, this.newParent, response.responseText, true, newBranch); } this._setWaitImg(this, false); } catch (err) { if (typeof(this.struct.onerrorajax) == 'function') { this.struct.onerrorajax('drop', response.responseText, this, this.newParent); } else { alert ('_completeDropAjax(base) : ' + err.message); } } }, /** * Envoi d'une requête Ajax suite à une édition de branche * * @access private * @return void */ _editAjax : function (newValue, oldValue, ev) { try { this._setWaitImg(this, true, true); var params = 'branch=' + this.serialize() + '&branch_id=' + this.getId() + '&tree_id=' + this.tree.id; params += '&new_value=' + newValue + '&old_value=' + oldValue; var otherParams = this.tree.getURLParams(this.struct.editlink); for (var i = 0; i < otherParams.length; i++) { params += '&' + otherParams[i].name + '=' + otherParams[i].value; } new Ajax.Updater ( this.tree.ajaxObj, this.struct.editlink, { 'method' : 'post', 'parameters' : params, 'evalScripts': true, 'onComplete' : function(event){this._completeEditAjax(event);}.bind(this), 'onFailure' : function(event){this._failureEditAjax(event);}.bind(this) } ); } catch (err) { this._setWaitImg(this, false, true); throw ('_editAjax(base) : ' + err.message); } }, _failureEditAjax : function () { this._setWaitImg(this, false); if (typeof(this.struct.onerrorajax) == 'function') { this.struct.onerrorajax('edit', 'failure request', this); } }, /** * Méthode appelée lorsque le retour ajax est effectué * * @access private * @param XMLhttpResquest response L'objet Ajax * @return void */ _completeEditAjax : function (response) { try { this._setWaitImg(this, false, true); var rep = this.struct.oneditajax(this, response.responseText, this.txt.innerHTML); if (rep) { this.setText((rep === true ? response.responseText : rep)); } this.hideEditableElement(); } catch (err) { this._setWaitImg(this, false, true); if (typeof(this.struct.onerrorajax) == 'function') { this.struct.onerrorajax('edit', response.responseText, this); } else { alert ('_completeOpenPopulate(' + response.responseText + ') : ' + err.message); } } }, /** *------------------------------------------------------------------------------ * TafelTreeBaseBranch Events Management *------------------------------------------------------------------------------ */ evt_openMouseOver : function (ev) { if (Event.element) { var obj = Event.element(ev); var img = this._getImgInfo(obj); obj.src = this.tree.imgBase + img.type + '_over' + img.number + '.gif'; } }, evt_openMouseOut : function (ev) { if (Event.element) { var obj = Event.element(ev); var img = this._getImgInfo(obj); obj.src = this.tree.imgBase + img.type.replace(/_over/g, '') + img.number + '.gif'; } }, evt_showTooltip : function (ev) { this.displayTooltip = true; setTimeout(this.showTooltip.bind(this), this.tree.durationTooltipShow); }, evt_hideTooltip : function (ev) { this.displayTooltip = false; setTimeout(this.hideTooltip.bind(this), this.tree.durationTooltipHide); }, /** * Méthode appelée lorsque la souris passe sur le noeud * * @access public * @param Element ev L'élément déclencheur * @return boolean True si le changement s'est fait, false sinon */ setMouseOver : function (ev) { if (typeof(this.struct.onmouseover) == 'function') { return this.struct.onmouseover(this, ev); } }, /** * Méthode appelée lorsqu'on clic sur le noeud * * @access public * @param Element ev L'élément déclencheur * @return boolean True si le changement s'est fait, false sinon */ setMouseOut : function (ev) { if (typeof(this.struct.onmouseout) == 'function') { return this.struct.onmouseout(this, ev); } }, /** * Méthode appelée lorsqu'on clique sur le noeud (mousedown) * * @access public * @param Element ev L'élément déclencheur * @return void */ setMouseDown : function (ev) { // Pour une raison ou une autre, le mousedown du div principal n'est pas appelé... this.tree.evt_setAsCurrent(ev); if (this.tree.selectedBranchShowed) { if (!this.isSelected()) { this.select(ev); this.okayForUnselect = false; } else { this.okayForUnselect = true; } } if (this.tooltip) { this.displayTooltip = false; this.hideTooltip(); } if (typeof(this.struct.onmousedown) == 'function') { this.struct.onmousedown(this, ev); } }, /** * Méthode appelée lorsqu'on "déclique" * * @access public * @param Element ev L'élément déclencheur * @return void */ setMouseUp : function (ev) { if (this.tree.lastEdited) { this.tree.lastEdited.hideEditable(ev); } // Si la branche est déjà sélectionnée, on la déselectionne if (this.isSelected() && this.okayForUnselect) { //this.unselect(); return true; } this.okayForUnselect = true; if (typeof(this.struct.onmouseup) == 'function') { this.struct.onmouseup(this, ev); } }, /** * Méthode appelée lorsqu'on clique sur le noeud * * @access public * @param Element ev L'élément déclencheur * @return void */ setClick : function (ev) { if (this.tree.lastEdited) return false; if (typeof(this.struct.onclick) == 'function') { return this.struct.onclick(this, ev); } }, /** * Fonction appelée lorsqu'on clique sur une checkbox * * @access public * @param HTMLimgElement ev L'élément déclencheur * @return boolean True si le changement s'est fait, false sinon */ checkOnClick : function (ev) { if (this.tree.checkboxes && this.checkbox) { var checked = (this.isChecked() > 0) ? 0 : 1; var ok = true; if (typeof(this.struct.onbeforecheck) == 'function') { ok = this.struct.onbeforecheck(this, checked, ev); } if (ok) { this.check(checked); if (this.tree.checkboxesThreeState) { this._manageCheckThreeState(this, checked); this._adjustParentCheck(); } if (typeof(this.struct.oncheck) == 'function') { this.struct.oncheck(this, checked, ev); } } } }, /** * Méthode appelée lors de l'ouverture ou fermeture d'un noeud * * @access public * @param HTMLimgElement ev L'élément déclencheur * @return boolean True si le changement s'est fait, false sinon */ setOpen : function (ev) { if (!this.hasChildren()) return false; var ok = true; if (typeof(this.struct.onbeforeopen) == 'function') { ok = this.struct.onbeforeopen(this, this.struct.open, ev); } if (!ok) return false; // On ne peut pas fermer la branche si elle subit un événement d'ouverture if (typeof(this.struct.onopenpopulate) == 'function' && !this.eventable) return false; this.openIt((this.isOpened()) ? false : true); if (typeof(this.struct.onopen) == 'function') { return this.struct.onopen(this, this.struct.open, ev); } else if (typeof(this.struct.onopenpopulate) == 'function' && this.isOpened() && this.children.length == 0) { if (!this.eventable) return false; return this._openPopulate(ev); } return true; }, /** * Ajoute une fonction utilisateur au start du drag * * @access public * @author coucoudom * @param HTMLObject drag l'objet draggé * @param HTMLObject dragbis */ ondragstarteffect : function (drag, dragbis) { var dragObj = this.tree.getBranchByIdObj(drag.id); if (!dragObj) { for (var i = 0; i < this.tree.otherTrees.length; i++) { dragObj = this.tree.otherTrees[i].getBranchByIdObj(drag.id); if (dragObj) break; } if (!dragObj) return false; } // appel de la function user if (typeof(dragObj.struct.ondragstarteffect) == 'function') { var ok = dragObj.struct.ondragstarteffect(dragObj); } }, /** * Ajoute une fonction utilisateur au end du drag * * @access public * @author coucoudom * @param HTMLObject drag l'objet draggé * @param HTMLObject dragbis */ ondragendeffect : function (drag, dragbis) { var dragObj = this.tree.getBranchByIdObj(drag.id); if (!dragObj) { for (var i = 0; i < this.tree.otherTrees.length; i++) { dragObj = this.tree.otherTrees[i].getBranchByIdObj(drag.id); if (dragObj) break; } if (!dragObj) return false; } // appel de la function user if (typeof(dragObj.struct.ondragendeffect) == 'function') { var ok = dragObj.struct.ondragendeffect(dragObj); } }, /** * Méthode appelée lorsqu'on drop sur le noeud * * Ici, le this correspond à l'objet qui réceptionne le drag * * @access public * @param HTMLElement drag L'élément draggué * @return boolean True si le changement s'est fait, false sinon */ setDrop : function (drag, html, html2, ev) { var dragObj = this.tree.getBranchByIdObj(drag.id); // Si l'objet n'est pas dans l'arbre courant, on va chercher dans les autres liés if (!dragObj) { for (var i = 0; i < this.tree.otherTrees.length; i++) { dragObj = this.tree.otherTrees[i].getBranchByIdObj(drag.id); if (dragObj) break; } if (!dragObj) return false; } var alt = (dragObj.tree.dropALT) ? TafelTreeManager.altOn(ev) : false; var ctrl = (dragObj.tree.dropCTRL) ? TafelTreeManager.ctrlOn(ev) || TafelTreeManager.metaOn(ev) : false; var ok = true; if ((this.tree.id == dragObj.tree.id && this.isChild(dragObj)) || !dragObj.eventable || !this.eventable) return false; // Fonction utilisateur avant le drop if (typeof(dragObj.struct.ondrop) == 'function') { ok = dragObj.struct.ondrop(dragObj, this, false, null, ev); } if (ok) { var asSibling = ((dragObj.tree.behaviourDrop == 1 || dragObj.tree.behaviourDrop == 3) && !alt || (dragObj.tree.behaviourDrop == 0 || dragObj.tree.behaviourDrop == 2) && alt) ? true : false; var copyDrag = ((dragObj.tree.behaviourDrop == 2 || dragObj.tree.behaviourDrop == 3) && !ctrl || (dragObj.tree.behaviourDrop == 0 || dragObj.tree.behaviourDrop == 1) && ctrl) ? true : false; // On va chercher les noeuds sur le serveur s'il y en a if (!asSibling && typeof(this.struct.onopenpopulate) == 'function' && !this.isOpened() && this.children.length == 0) { this._openPopulate(ev); } if (typeof(dragObj.struct.ondropajax) == 'function') { dragObj._setDropAjax(this, asSibling, copyDrag, ev); } else { // Drop normal var newBranch = null; if (!asSibling) { if (!copyDrag) { dragObj.move(this); } else { newBranch = this.insertIntoLast(dragObj.clone()); } } else { if (!copyDrag) { dragObj.moveBefore(this); } else { newBranch = this.insertBefore(dragObj.clone()); } } // Fonction utilisateur après le drop if (typeof(dragObj.struct.ondrop) == 'function') { ok = dragObj.struct.ondrop(dragObj, this, true, newBranch, ev); } } } }, /** * Méthode appelée lorsqu'on double-clic sur le noeud * * @access public * @param Element ev L'élément déclencheur * @return boolean True si le changement s'est fait, false sinon */ setDblClick : function (ev) { if (this.tree.lastEdited) return false; if (typeof(this.struct.ondblclick) == 'function') { this.struct.ondblclick(this, ev); } if (this.struct.editable && this.editableInput) { if (!this.tree.lastEdited || this.tree.lastEdited.getId() != this.getId()) { this.editableInput.style.width = (this.txt.offsetWidth + 20) + 'px'; } Element.hide(this.txt); this.editableInput.value = this.txt.innerHTML; this.editableInput.style.display = 'block'; this.editableInput.focus(); this.tree.lastEdited = this; } }, /** * Enlève l'édition de la branche * * @access public * @param Event ev L'événement déclencheur * @return boolean True si l'élément a été caché, false sinon */ hideEditable : function (ev) { if (this.editableInput && this.struct.editable) { var obj = this.editableInput; var value = obj.value; if (this.struct.oneditajax) { if (!this.eventable) return false; this._editAjax(obj.value, this.txt.innerHTML, ev); } else { if (typeof(this.struct.onedit) == 'function') { value = this.struct.onedit(this, obj.value, this.txt.innerHTML, ev); } this.setText(value); this.hideEditableElement(); } return true; } return false; }, hideEditableElement : function () { Element.hide(this.editableInput); this.editableInput.value = this.getText(); this.txt.style.display = 'block'; this.tree.lastEdited = null; } }; /** *------------------------------------------------------------------------------ * TafelTreeRoot Class *------------------------------------------------------------------------------ */ var TafelTreeRoot = Class.create(); TafelTreeRoot.prototype = Object.extend(new TafelTreeBaseBranch, { /** * Constructeur d'un élément racine * * @access public * @param TafelTree tree L'objet TafelTree courant * @param object struct Les infos concernant la racine est ses enfants * @param integer level Le niveau du noeud (0 pour la racine) * @param boolean before True s'il y a des noeuds avant * @param boolean after True s'il y a des noeuds après */ initialize : function (tree, struct, level, before, after, pos) { this.isRoot = true; this.tree = tree; this.pos = pos; this.level = level; this.struct = struct; this.tree.idTree++; this.idObj = this.tree.idTreeBranch + this.tree.idTree; this.hasSiblingsBefore = before; this.hasSiblingsAfter = after; this.eventable = true; this.loaded = true; this.children = []; this.copiedTimes = 0; this._setProperties(); this._setFunctions(); this.obj = this._addRoot(); this.content = this._addContent(); this.obj.appendChild(this.table); this._setChildren(this); this._setActions(); }, /** * Méthode qui insère une branche avant celle courante * * @access public * @param object item Un objet au format TafelTreeBranch * @return TafelTreeRoot La nouvelle racine insérée */ insertBefore : function (item) { if (this.parent) return false; var pos = this.pos; var posBefore = pos + 1; var isNotFirst = (pos == 0) ? false : true; this._movePartStructRoot(pos); this.tree.roots[pos] = new TafelTreeRoot(this.tree, item, this.level, isNotFirst, true, pos); this.tree.div.insertBefore(this.tree.roots[pos].obj, this.obj); this._manageAfterRootInsert(pos); return this.tree.roots[pos]; }, /** * Méthode qui insère une branche après celle courante * * @access public * @param object item Un objet au format TafelTreeBranch * @return TafelTreeRoot La nouvelle racine insérée */ insertAfter : function (item) { if (this.parent) return false; var pos = this.pos + 1; var posBefore = pos + 1; var isNotLast = (pos == this.tree.roots.length) ? false : true; this._movePartStructRoot(pos); this.tree.roots[pos] = new TafelTreeRoot(this.tree, item, this.level, true, isNotLast, pos); try { this.tree.div.insertBefore(this.tree.roots[pos].obj, this.tree.roots[posBefore].obj); } catch (err) { this.tree.div.appendChild(this.tree.roots[pos].obj); } this._manageAfterRootInsert(pos); return this.tree.roots[pos]; }, /** *------------------------------------------------------------------------------ * TafelTreeRoot private methods *------------------------------------------------------------------------------ */ _manageAfterRootInsert : function (pos) { for (var i = 0; i < this.tree.roots.length; i++) { if (i < this.tree.roots.length - 1) { this.tree.roots[i].hasSiblingsAfter = true; } if (i > 0) { this.tree.roots[i].hasSiblingsBefore = true; } } for (var i = 0; i < this.children.length; i++) { this.children[i]._manageLineForRoot(this.hasSiblingsAfter); } }, _movePartStructRoot : function (pos) { var nb = this.tree.roots.length - 1; var newPos = 0; for (var i = nb; i >= pos; i--) { newPos = i + 1; this.tree.roots[newPos] = this.tree.roots[i]; this.tree.roots[newPos].pos = newPos; } }, /** * Méthode pour ajouter l'élément principal * * @access private * @return HTMLDivElement L'élément DIV créé */ _addRoot : function () { var div = document.createElement('div'); div.className = this.tree.classTreeRoot; return div; }, /** * Méthode pour ajouter le contenu de l'élément (images + textes) * * Créé une structure comme suit : * * * *
* * @access private * @return HTMLTbodyElement L'élément TBODY créé */ _addContent : function () { var table = document.createElement('table'); var tbody = document.createElement('tbody'); var tr = document.createElement('tr'); var tdImg = document.createElement('td'); var tdTxt = document.createElement('td'); var img = document.createElement('img'); var span = document.createElement('div'); var txt = document.createTextNode(txt); img.src = this.tree.imgBase + this.struct.img; span.innerHTML = this.struct.txt; // Ajout du title (de NoisetteProd) if (this.struct.title) { span.setAttribute('title', this.struct.title); } // Fin ajout du title span.setAttribute('id', this.idObj); Element.addClassName(span, this.tree.classContent); Element.addClassName(tdTxt, this.tree.classCanevas); tdTxt.appendChild(span); tdImg.appendChild(img); // Insertion du tooltip, s'il existe if (this.struct.tooltip) { this.tooltip = this._createTooltip(); tdTxt.appendChild(this.tooltip); } // Insertion de l'image avant l'icône this.tdImg = tdImg; this.beforeIcon = this._getImgBeforeIcon(); tr.appendChild(this.beforeIcon); tr.appendChild(tdImg); tr.appendChild(tdTxt); tbody.appendChild(tr); table.appendChild(tbody); if (this.tree.multiline) { tdTxt.style.whiteSpace = 'normal'; if (this.hasChildren()) this._manageMultiline(this.tdImg, 2, true); } if (this.struct.style) { Element.addClassName(tdTxt, this.struct.style); } this.txt = span; this.img = img; this.table = table; this._setEvents(tdTxt, tdImg); return tbody; } }); /** *------------------------------------------------------------------------------ * TafelTreeBranch Class *------------------------------------------------------------------------------ */ /** Properties description this.tree : l'arbre de la branche this.root : la racine de la branche this.parent : le parent de la branche (peut être this.root) this.level : le niveau de la branche. Le 1er niveau sous la racine est le 1 this.pos : la position de la branche au sein des enfants du parent this.idObj : l'id attribué automatiquement. Ne pas se baser dessus pour les developpements externes this.children : les enfants de la branche this.objDrag : L'objet Draggable this.struct : la structure de la branche avec toutes les infos utilisateur this.eventable : Détermine si la branche peut être drag n' droppée ou non. Utilisé uniquement lors du dragndrop ajax et open ajax. this.obj : HTMLDivElement qui symbolise la branche this.content : HTMLTBodyElement qui symbolise le contenu de la branche this.beforeIcon : HTMLTdElement qui symbolise la TD contenant le picto avant l'icône this.img : HTMLImgElement qui représente l'icône avant le texte this.txt : HTMLTextNodeElement qui représente le texte de la branche this.table : HTMLTableElement qui est le parent du Tbody (this.content) */ var TafelTreeBranch = Class.create(); TafelTreeBranch.prototype = Object.extend(new TafelTreeBaseBranch, { /** * Constructeur d'une branche de l'arbre * * @access public * @param TafelRoot root L'objet racine parent * @param TafelBranch parent L'objet directement parent * @param object struct Les infos concernant la branche est ses enfants * @param integer level Le niveau du noeud * @param boolean before True s'il y a des noeuds avant * @param boolean after True s'il y a des noeuds après * @param integer pos La position dans le tableau children[] du parent */ initialize : function (root, parent, struct, level, before, after, pos) { this.tree = root.tree; this.root = root; this.level = level; this.pos = pos; this.parent = parent; this.tree.idTree++; this.idObj = this.tree.idTreeBranch + this.tree.idTree; this.hasSiblingsBefore = before; this.hasSiblingsAfter = after; this.struct = struct; this.eventable = true; this.loaded = true; this.inProcess = false; this.children = []; this.copiedTimes = 0; if (typeof(this.struct.draggable) == 'undefined') this.struct.draggable = 1; this._setProperties(); // Fonctions utilisateurs if (typeof(this.struct.ondrop) == 'undefined') { if (typeof(this.tree.onDrop) == 'function') { this.struct.ondrop = this.tree.onDrop; this.ondropDefault = true; } } else {this.struct.ondrop = eval(this.struct.ondrop);} if (typeof(this.struct.ondropajax) == 'undefined') { if (this.tree.onDropAjax && typeof(this.tree.onDropAjax.func) == 'function') { this.struct.ondropajax = this.tree.onDropAjax.func; this.struct.droplink = this.tree.onDropAjax.link; this.ondropajaxDefault = true; } } else {this.struct.ondropajax = eval(this.struct.ondropajax);} this._setFunctions(); // Initialisation de la branche this.obj = this._addBranch(); this.content = this._addContent(); this.obj.appendChild(this.table); this._setChildren(root); // set actions like select node this._setActions(); }, insertBefore : function (item) { if (!this.parent) return false; var pos = this.pos; var posBefore = pos + 1; var isNotFirst = (pos == 0) ? false : true; this.parent._movePartStruct(pos); this.parent.struct.items[pos] = item; this.parent.children[pos] = new TafelTreeBranch(this.root, this.parent, item, this.level, isNotFirst, true, pos); this.parent.obj.insertBefore(this.parent.children[pos].obj, this.obj); this.parent._manageAfterInsert(pos); return this.parent.children[pos]; }, insertAfter : function (item) { if (!this.parent) return false; var pos = this.pos + 1; var posBefore = pos + 1; var isNotLast = (pos == this.parent.children.length) ? false : true; this.parent._movePartStruct(pos); this.parent.struct.items[pos] = item; this.parent.children[pos] = new TafelTreeBranch(this.root, this.parent, item, this.level, true, isNotLast, pos); try { this.parent.obj.insertBefore(this.parent.children[pos].obj, this.parent.children[posBefore].obj); } catch (err) { this.parent.obj.appendChild(this.parent.children[pos].obj); } this.parent._manageAfterInsert(pos); return this.parent.children[pos]; }, /** * Méthode pour déplacer une branche dans l'arbre comme fille * * @access public * @param string hereb L'id de la nouvelle branche parente * @return TafelTreeBranch La branche bougée */ move : function (hereb) { return this.moveIntoLast(hereb); }, moveIntoLast : function (hereb) { // On récupère l'objet "here" var here = this.tree.getBranchById(hereb); if (!here) return false var pos = here._getPos(); var id = this.getId(); var txt = this.getText(); if (pos == here.children.length) { obj = here.insertIntoLast(this.struct); } else { obj = here.children[pos].insertBefore(this.struct); } this.tree.removeBranch(this); return obj; }, moveIntoFirst : function (hereb) { // On récupère l'objet "here" var here = this.tree.getBranchById(hereb); if (!here) return false var id = this.getId(); var txt = this.getText(); var obj = here.insertIntoFirst(this.struct); this.tree.removeBranch(this); return obj; }, /** * Méthode pour déplacer une branche dans l'arbre comme soeur * * @access public * @param string hereb L'id de la nouvelle branche soeur * @return void */ moveBefore : function (hereb) { // On récupère l'objet "here" var here = this.tree.getBranchById(hereb); if (!here) return false; var id = this.getId(); var txt = this.getText(); var obj = here.insertBefore(this.struct); this.tree.removeBranch(this); return obj; }, moveAfter : function (hereb) { // On récupère l'objet "here" var here = this.tree.getBranchById(hereb); if (!here) return false; var id = this.getId(); var txt = this.getText(); var obj = here.insertAfter(this.struct); this.tree.removeBranch(this); return obj; }, /** *------------------------------------------------------------------------------ * TafelTreeBranch private methods *------------------------------------------------------------------------------ */ /** * Méthode pour ajouter l'élément principal * * @access private * @return HTMLDivElement L'élément DIV créé */ _addBranch : function () { var div = document.createElement('div'); div.className = this.tree.classTreeBranch; return div; }, /** * Méthode pour ajouter le contenu de l'élément (images + textes) * * Créé une structure comme suit : * * * * * *
etc. (relatif au niveau de l'élément courant)
* * @access private * @return HTMLTbodyElement L'élément TBODY créé */ _addContent : function () { var table = document.createElement('table'); var tbody = document.createElement('tbody'); var tr = document.createElement('tr'); var img = document.createElement('img'); // Toutes les images jusqu'à celle avant l'icône var imgs = this._addImgs(); var nbImgs = imgs.length; for (var i = nbImgs - 1; i >= 0; i--) { tr.appendChild(imgs[i]); } // On récupère l'image avant l'icône this.beforeIcon = this._getImgBeforeIcon(); tr.appendChild(this.beforeIcon); // On créé l'icone et le texte var tdImg = document.createElement('td'); var tdTxt = document.createElement('td'); var img = document.createElement('img'); var span = document.createElement('div'); span.innerHTML = this.struct.txt; // Ajout du title (de NoisetteProd) if (this.struct.title) { span.setAttribute('title', this.struct.title); } // Fin ajout du title span.setAttribute('id', this.idObj); Element.addClassName(span, this.tree.classContent); Element.addClassName(tdTxt, this.tree.classCanevas); img.src = this.tree.imgBase + this.struct.img; this.tdImg = tdImg; if (this.tree.multiline) { tdTxt.style.whiteSpace = 'normal'; if (this.hasChildren()) this._manageMultiline(this.tdImg, 2, true); } if (this.struct.style) { Element.addClassName(tdTxt, this.struct.style); } // On append l'ensemble à la table HTML tdTxt.appendChild(span); // Insertion du tooltip, s'il existe if (this.struct.tooltip) { this.tooltip = this._createTooltip(); tdTxt.appendChild(this.tooltip); } tdImg.appendChild(img); tr.appendChild(tdImg); tr.appendChild(tdTxt); tbody.appendChild(tr); table.appendChild(tbody); this.tdImg = tdImg; this.txt = span; this.img = img; this.table = table; this._setEvents(tdTxt, tdImg); return tbody; }, /** * Fonction qui permet de gérer toutes les lignes verticales qui précèdent l'icone * * @access private * @return array Les images à mettre avant l'icône */ _addImgs : function () { var obj = this.parent; var cpt = 0; var imgs = []; var img = null; // On détermine s'il y a des lignes verticales avant l'icone et le texte var td = null; while (obj.parent) { td = document.createElement('td'); img = document.createElement('img'); if (!obj.hasSiblingsAfter) { img.src = this.tree.imgBase + this.tree.imgEmpty; } else { img.src = this.tree.imgBase + this.tree.imgLine1; if (this.tree.multiline) { this._manageMultiline(td, 1, true); } } td.appendChild(img); imgs[cpt] = td; cpt++; obj = obj.parent; } // On teste si le root à des soeurs. Si oui, on ajoute encore une ligne td = document.createElement('td'); img = document.createElement('img'); if (!this.root.hasSiblingsAfter) { img.src = this.tree.imgBase + this.tree.imgEmpty; } else { img.src = this.tree.imgBase + this.tree.imgLine1; if (this.tree.multiline) { this._manageMultiline(td, 1, true); } } td.appendChild(img); imgs[cpt] = td; return imgs; } }); /** *------------------------------------------------------------------------------ * TafelTrees Management *------------------------------------------------------------------------------ */ var TafelTreeManager = { /** *------------------------------------------------------------------------------ * TafelTreeManager properties *------------------------------------------------------------------------------ */ /** * @var boolean stopEvent Stoppe la propagation de l'événement */ stopEvent : true, /** * @var boolean keyboardEvents True pour activer la gestion clavier */ keyboardEvents : true, /** * @var boolean keyboardStructEvents True pour activer la gestion clavier relative à la structure */ keyboardStructuralEvents : true, /** * @var array trees Les arbres actuellement loadés */ trees : [], /** * @var TafelTree currentTree L'arbre actuellement actif */ currentTree : null, /** * @var array userKeys Les touches utilisateur */ userKeys : [], /** *------------------------------------------------------------------------------ * TafelTreeManager public methods *------------------------------------------------------------------------------ */ /** * Permet de setter des fonctions utilisateur pour les touches voulues * * L'objet keys est formé comme ceci : * - keys[0].key = code de la touche * - keys[0].func = fonction utilisateur * * @access public * @param array keys Les touchces et leur fonction * @return void */ setKeys : function (keys) { this.userKeys = keys; }, /** * Ajoute un arbre dans le manager * * @access public * @param TafelTree tree L'arbre à ajouter * @return void */ add : function (tree) { this.trees.push(tree); }, disableKeyboardEvents : function () { this.keyboardEvents = false; }, disableKeyboardStructuralEvents : function () { this.keyboardStructuralEvents = false; }, /** * Retourne l'arbre actuellement actif * * @access public * @return TafelTree L'arbre actuellement actif */ getCurrentTree : function () { return this.currentTree; }, /** * Set l'arbre actuellement actif * * @access public * @param TafelTree L'arbre actuellement actif * @return void */ setCurrentTree : function (tree) { this.currentTree = tree; }, /** * Retourne true si la touche POMME est appuyée (sur Mac Safari) * * @access public * @return boolean True si POMME est appuyé */ metaOn : function (ev) { var ok = false; if (ev && (ev.metaKey)) { ok = true; } return ok; }, /** * Retourne true si la touche CTRL est appuyée * * @access public * @return boolean True si CTRL est appuyé */ ctrlOn : function (ev) { var ok = false; if (ev && (ev.ctrlKey || ev.modifier == 2)) { ok = true; } return ok; }, /** * Retourne true si la touche ALT est appuyée * * @access public * @return boolean True si ALT est appuyé */ altOn : function (ev) { var ok = false; if (ev && (ev.altKey || ev.modifier == 1)) { ok = true; } return ok; }, /** * Retourne true si la touche SHIFT est appuyée * * @access public * @return boolean True si ALT est appuyé */ shiftOn : function (ev) { var ok = false; if (ev && (ev.shiftKey || ev.modifier == 3)) { ok = true; } return ok; }, /** * Retourne le code clavier * * @access public * @param Event ev L'événement déclencheur * @return void */ getCode : function (ev) { return (ev.which) ? ev.which : ev.keyCode; }, /** * Assigne tous les événements nécessaires * * @access public * @return void */ setControlEvents : function () { Event.observe(document, 'keypress', this.evt_keyPress.bindAsEventListener(this), false); var body = document.getElementsByTagName('body'); if (!body || !body[0]) { throw new Error(TAFELTREE_NO_BODY_TAG); } else { Event.observe(body[0], 'mouseup', this.evt_unselect.bindAsEventListener(this), false); } }, /** *------------------------------------------------------------------------------ * TafelTreeManager events management *------------------------------------------------------------------------------ */ /** * Déselectionne l'arbre courant * * @access public * @param Event ev L'événement déclencheur * @return void */ evt_unselect : function (ev) { var obj = Event.element(ev); var current = this.getCurrentTree(); if (current) { if (!Element.hasClassName(obj, current.classSelected) && !Element.hasClassName(obj, current.classOpenable)) { current.unselect(); this.setCurrentTree(null); } } }, /** * Appel lors de la touche ENTER * * @access public * @param TafelTree tree L'arbre incriminé * @param integer code Le code de la touche * @param Object keys Les infos des "metakeys" ctrl, shift, alt et meta * @param Event ev L'événement déclencheur * @return void */ enter : function (tree, code, keys, ev) { if (tree.lastEdited) { tree.lastEdited.editableInput.blur(); if (this.stopEvent) Event.stop(ev); } }, /** * Appel lors de la touche ESCAPE * * @access public */ escape : function (tree, code, keys, ev) { var selected = tree.getSelectedBranches(); var lastPos = selected.length - 1; var nounselect = false; if (lastPos == 0 && tree.lastEdited) { if (tree.lastEdited.hideEditable(ev)) { nounselect = true; } } if (!nounselect) { tree.unselect(); } tree.unsetCut(); tree.unsetCopy(); if (this.stopEvent) Event.stop(ev); }, /** * Appel lors de la touche HOME * * @access public */ moveStart : function (tree, code, keys, ev) { if (!tree.lastEdited) { tree.unselect(); if (tree.roots.length > 0) { var branch = tree.roots[0]; branch.select(); } if (this.stopEvent) Event.stop(ev); } }, /** * Appel lors de la touche END * * @access public */ moveEnd : function (tree, code, keys, ev) { if (!tree.lastEdited) { tree.unselect(); if (tree.roots.length > 0) { var last = tree.roots.length - 1; var branch = tree.roots[last]; while (branch.hasChildren()) { branch = branch.getLastBranch(); } branch.select(); } if (this.stopEvent) Event.stop(ev); } }, /** * Appel lors de la touche Fleche haut * * @access public */ moveUp : function (tree, code, keys, ev) { var selected = tree.getSelectedBranches(); var lastPos = selected.length - 1; if (!tree.lastEdited) { if (lastPos >= 0) { var branch = selected[lastPos].getPreviousOpenedBranch(); if (branch) branch.select(ev); } else { // On sélectionne automatiquement le 1er élément de l'arbre if (typeof(tree.roots[0]) != 'undefined') tree.roots[0].select(); } if (this.stopEvent) Event.stop(ev); } }, /** * Appel lors de la touche Fleche bas * * @access public */ moveDown : function (tree, code, keys, ev) { var selected = tree.getSelectedBranches(); var lastPos = selected.length - 1; if (!tree.lastEdited) { if (lastPos >= 0) { var branch = selected[lastPos].getNextOpenedBranch(); if (branch) branch.select(ev); } else { // On sélectionne automatiquement le 1er élément de l'arbre if (typeof(tree.roots[0]) != 'undefined') tree.roots[0].select(); } if (this.stopEvent) Event.stop(ev); } }, /** * Appel lors de la touche Fleche droite * * @access public */ moveRight : function (tree, code, keys, ev) { var selected = tree.getSelectedBranches(); var lastPos = selected.length - 1; if (!tree.lastEdited) { if (lastPos >= 0) { var branch = selected[lastPos]; if (branch.hasChildren() && !branch.isOpened()) { branch.setOpen(ev); } else { if (branch.hasChildren()) { var sel = branch.getFirstBranch(); var sel = sel.select(ev); } } } else { // On sélectionne automatiquement le 1er élément de l'arbre if (typeof(tree.roots[0]) != 'undefined') tree.roots[0].select(); } if (this.stopEvent) Event.stop(ev); } }, /** * Appel lors de la touche Fleche gauche * * @access public */ moveLeft : function (tree, code, keys, ev) { var selected = tree.getSelectedBranches(); var lastPos = selected.length - 1; if (!tree.lastEdited) { if (lastPos >= 0) { var branch = selected[lastPos]; if (lastPos == 0 && branch.hasChildren() && branch.isOpened()) { branch.openIt(false); } else { if (!branch.isRoot) branch.parent.select(ev); } } else { // On sélectionne automatiquement le 1er élément de l'arbre if (typeof(tree.roots[0]) != 'undefined') tree.roots[0].select(); } if (this.stopEvent) Event.stop(ev); } }, /** * Appel lors de la touche F2 * * @access public */ edit : function (tree, code, keys, ev) { var selected = tree.getSelectedBranches(); var lastPos = selected.length - 1; if (lastPos == 0) { selected[lastPos].setDblClick(ev); } if (this.stopEvent) Event.stop(ev); }, /** * Appel lors de la touche DELETE * * @access public */ remove : function (tree, code, keys, ev) { if (!tree.lastEdited) { var selected = tree.getSelectedBranches(); for (var i = 0; i < selected.length; i++) { tree.removeBranch(selected[i]); } if (this.stopEvent) Event.stop(ev); } }, /** * Appel lors de la touche x ou X * * @access public */ cut : function (tree, code, keys, ev) { if (keys.ctrlKey || keys.metaKey) { tree.cut(); if (this.stopEvent) Event.stop(ev); } }, /** * Appel lors de la touche c ou C * * @access public */ copy : function (tree, code, keys, ev) { if (keys.ctrlKey || keys.metaKey) { tree.copy(); if (this.stopEvent) Event.stop(ev); } }, /** * Appel lors de la touche v ou V * * @access public */ paste : function (tree, code, keys, ev) { if (keys.ctrlKey || keys.metaKey) { tree.paste(); if (this.stopEvent) Event.stop(ev); } }, /** * Appel lors de la touche z ou Z * * @access public */ undo : function (tree, code, keys, ev) { if (keys.ctrlKey || keys.metaKey) { tree.undo(); if (this.stopEvent) Event.stop(ev); } }, /** * Gestion du clavier * * @access private * @param Event ev L'événement déclencheur * @return void */ evt_keyPress : function (ev) { var current = this.getCurrentTree(); if (current && this.keyboardEvents) { // Check Control Ctrl var keys = { 'ctrlKey' : this.ctrlOn(ev), 'metaKey' : this.metaOn(ev), 'altKey' : this.altOn(ev), 'shiftKey' : this.shiftOn(ev) }; // Check de la touche appuyée var code = this.getCode(ev); // Check si l'utilisateur a fourni une fonction particulière for (var i = 0; i < this.userKeys.length; i++) { if (code == this.userKeys[i].key && typeof(this.userKeys[i].func) == 'function') { if (!this.userKeys[i].func(current, code, keys, ev)) { return false; } break; } } switch (code) { // Retour au début (Home) et fin (End) case Event.KEY_HOME : this.moveStart(current, code, keys, ev); break; case Event.KEY_END : this.moveEnd(current, code, keys, ev); break; // Mouvements haut, bas, gauche et droite case Event.KEY_UP : this.moveUp(current, code, keys, ev); break; case Event.KEY_DOWN : this.moveDown(current, code, keys, ev); break; case Event.KEY_RIGHT : this.moveRight(current, code, keys, ev); break; case Event.KEY_LEFT : this.moveLeft(current, code, keys, ev); break; } if (this.keyboardStructuralEvents) { switch (code) { // Fin de l'édition d'une branche case Event.KEY_RETURN : this.enter(current, code, keys, ev); break; // Déselection case Event.KEY_ESC : this.escape(current, code, keys, ev); break; // Effacer (Del) case Event.KEY_DELETE : this.remove(current, code, keys, ev); break; // Editer (F2) case 113: this.edit(current, code, keys, ev); break; // Couper (x-X) case 120: case 88: this.cut(current, code, keys, ev); break; // Copier (c-C) case 99 : case 67: this.copy(current, code, keys, ev); break; // Coller (v-V) case 118: case 86: this.paste(current, code, keys, ev); break; // Annuler (z-Z) case 122: case 90: this.undo(current, code, keys, ev); break; } } } } }; /** *------------------------------------------------------------------------------ * TafelTree pre-instanciation *------------------------------------------------------------------------------ */ function TafelTreeInitBase (ev) { TafelTreeManager.setControlEvents(); if (typeof(TafelTreeInit) == 'function') { TafelTreeInit(); } }; Event.observe(window, 'load', TafelTreeInitBase, false);