WindowManager
Gestionnaire de Window ancré par colonne.
Source
/** * Gestionnaire de fenêtre * @author neolao <neo@neolao.com> * @version 0.5 (29/01/2006) * @license http://creativecommons.org/licenses/by-sa/2.5/ */ function WindowManager(){ this.__construct.apply(this, arguments); } WindowManager.prototype = { // ----------------------------- CONSTANTES -------------------------------- // ----------------------------- VARIABLES --------------------------------- /** * La cible du gestionnaire * @var HTMLElement */ _target : 0, /** * Le nombre de colonnes * @var int */ _nbColumns : 3, /** * La liste des colonnes * @var Array */ _columns : 0, /** * Fenêtre temporaire */ _windowTemp : 0, /** * La dernière fenêtre sélectionnée * @var HTMLElement */ _targetWindow : null, /** * Indique si on est en train de déplacer une fenêtre * @var bool */ _isDraging : false, /** * La liste des Window * @var Array */ _windowsList : 0, // ----------------------------- EVENEMENTS -------------------------------- /** * Evénement invoqué lorsque les positions changent * @param Array pList La liste des fenêtres avec leur position */ onChanged : function(pList){ }, /*============================= CONSTRUCTEUR =============================*/ /*========================================================================*/ /** * Initialisation de l'application * @param string pTarget L'id de la cible de l'application * @param int pTotalColumns Le nombre de colonnes au total * @param string pClassName (optional) Le style CSS */ __construct : function(pTarget, pTotalColumns, pClassName){ this._target = document.getElementById(pTarget); this._nbColumns = pTotalColumns; // Initialisation de la liste des fenêtres this._windowsList = new Array(); // Création de l'environnement this._createArea(); this._area.className = (pClassName)?pClassName:"windowmanager"; this._target.appendChild(this._area); // Création des colonnes this._createColumns(); // Création de la fenêtre temporaire this._createWindowTemp(); }, /*======================= FIN = CONSTRUCTEUR = FIN =======================*/ /*========================================================================*/ /*=========================== METHODES PRIVEES ===========================*/ /*========================================================================*/ /** * Délégation de fonction * @param object pTarget La cible de la fonction * @param function pFunction La fonction * @param mixed pParam1 Un paramètre supplémentaire (sans limite) * @return function La fonction qui fait la délégation */ _delegate : function(pTarget, pFunction, pParam1){ var f = function(){ var a = new Array(); for(var j=0; j<arguments.length; j++){ a.push(arguments[j]); } return arguments.callee.func.apply(arguments.callee.target, a.concat(arguments.callee.bonus)); }; var args = new Array(); for(var i=0; i<arguments.length; i++){ args.push(arguments[i]); } f.target = args.shift(); f.func = args.shift(); f.bonus = args; return f; }, /** * Création de l'environnement */ _createArea : function(){ this._area = document.createElement("div"); this._area.style.clear = "both"; }, /** * Création des colonnes */ _createColumns : function(){ var colTemp; var dummy; this._columns = new Array(); for(var i=0; i<this._nbColumns; i++){ colTemp = document.createElement("div"); colTemp.className = "column"; // Largeur de la colonne colTemp.style.width = 100/this._nbColumns + "%"; // Evénement pour débuter le déplacement de fenêtre var onColumnDown = function(pEvent){ if(pEvent.targetType == "WindowHeader"){ // On appuye sur le header d'une fenêtre this._targetWindow = pEvent.targetWindow; this._dragWindow(this._targetWindow, pEvent); } }; colTemp.addEventListener("mousedown", this._delegate(this, onColumnDown), false); var onColumnUp = function(pEvent){ if(pEvent.targetType == "WindowHeader"){ // On relache le header d'une fenêtre this._targetWindow = null; } }; colTemp.addEventListener("mouseup", this._delegate(this, onColumnUp), false); var onColumnMove = function(pEvent){ if(!this._isDraging && this._targetWindow != null){ // Premier déplacement après avoir appuyé sur la fenêtre } }; colTemp.addEventListener("mousemove", this._delegate(this, onColumnMove), false); // On crée un élément vide pour qu'il y ait toujours quelque chose dans la colonne dummy = document.createElement("div"); dummy.style.height = "1px"; colTemp.appendChild(dummy); // On ajoute this._columns.push(colTemp); this._area.appendChild(colTemp); } }, /** * Trouve la position X d'un HTMLElement * * source : http://www.quirksmode.org/js/findpos.html * @param HTMLElement obj L'élément * @return int La position X de l'élément */ _findPosX : function (obj){ var curleft = 0; if(obj.offsetParent){ while (obj.offsetParent){ curleft += obj.offsetLeft obj = obj.offsetParent; } }else if(obj.x) curleft += obj.x; return curleft; }, /** * Trouve la position Y d'un HTMLElement * * source : http://www.quirksmode.org/js/findpos.html * @param HTMLElement obj L'élément * @return int La position Y de l'élément */ _findPosY : function (obj){ var curtop = 0; if(obj.offsetParent){ while (obj.offsetParent){ curtop += obj.offsetTop obj = obj.offsetParent; } }else if (obj.y) curtop += obj.y; return curtop; }, /** * Début du déplacement d'une fenêtre * @param HTMLElement pTarget La cible * @param Event pEvent L'événement */ _dragWindow : function(pTarget, pEvent){ // Position de la souris relative à la fenêtre pTarget.currentOffsetX = pEvent.clientX - this._findPosX(pTarget) + 5; pTarget.currentOffsetY = pEvent.clientY - this._findPosY(pTarget) + 5; // Largeur de la fenêtre pTarget.style.width = this._columns[0].style.width; // Nouvelle position de la fenêtre en absolue pTarget.style.left = this._findPosX(pTarget) - 5 + "px"; pTarget.style.top = this._findPosY(pTarget) - 5 + "px"; pTarget.style.position = "absolute"; // Affichage de la fenêtre temporaire pTarget.parentNode.insertBefore(this._windowTemp, pTarget); this._windowTemp.style.display = "block"; this._windowTemp.style.height = pTarget.offsetHeight + "px"; this._windowTempTarget(pEvent); // On attache la fenêtre qu'on déplace à la racine, ca arrange des trucs que j'ai pas compris this._target.appendChild(pTarget); // Déplacement document.onmousemove = this._delegate(this, this._dragingWindow); document.onmouseup = this._delegate(this, this._stopDragWindow); this._isDraging = true; }, /** * Fin du déplacement de la fenêtre * @param Event pEvent L'événement */ _stopDragWindow : function(pEvent){ // Position de la fenêtre en relatif this._targetWindow.style.position = "static"; this._targetWindow.style.width = "auto"; // Fin du déplacement document.onmousemove = null; document.onmouseup = null; // On remplace la fenêtre temporaire par la fenêtre qu'on déplace this._windowTemp.parentNode.replaceChild(this._targetWindow, this._windowTemp); // On cache la fenêtre temporaire this._windowTemp.style.display = "none"; // Evénement this.onChanged(this.getWindowsList()); this._isDraging = false; this._targetWindow = null; }, /** * Pendant le déplacement de la fenêtre * @param Event pEvent L'événement */ _dragingWindow : function(pEvent){ this._targetWindow.style.left = pEvent.clientX - this._targetWindow.currentOffsetX + "px"; this._targetWindow.style.top = pEvent.clientY - this._targetWindow.currentOffsetY + "px"; this._windowTempTarget(pEvent); }, /** * Création de la fenêtre temporaire */ _createWindowTemp : function(){ this._windowTemp = document.createElement("div"); this._windowTemp.className = "windowTemp"; this._windowTemp.style.height = "20px"; this._windowTemp.style.display = "none"; this._windowTemp.column = 0; }, /** * Déplace la fenêtre temporaire suivant la position de la souris */ _windowTempTarget : function(pEvent){ var column = 0; var row = 0; var node; // Recherche de la colonne for(var i=0; i<this._columns.length; i++){ if(pEvent.clientX > this._findPosX(this._columns[i])){ column = i; } } // Recherche de la fenêtre qu'on survole for(var j=0; j<this._columns[column].childNodes.length; j++){ if(pEvent.clientY > this._findPosY(this._columns[column].childNodes[j])){ row = j; } } // On déplace node = this._columns[column].childNodes[row]; node.parentNode.insertBefore(this._windowTemp, node.nextSibling); }, /** * Invoqué lorsqu'une fenêtre se ferme */ _onWindowClose : function(){ // Evénement this.onChanged(this.getWindowsList()); }, /*===================== FIN = METHODES PRIVEES = FIN =====================*/ /*========================================================================*/ /*============================ GETTER SETTER ============================*/ /*========================================================================*/ /** * Récupère la liste des fenêtres avec leur position * @return Array La liste des fenêtres */ getWindowsList : function(){ var list = new Array(); var node; // Pour chaque colonne ... for(var i=0; i<this._columns.length; i++){ // Pour chaque ligne ... for(var j=0; j<this._columns[i].childNodes.length; j++){ if(this._columns[i].childNodes[j].childNodes.length > 0){ // Ce n'est pas un dummy ni la fenêtre temporaire // donc une fenêtre normale node = this._columns[i].childNodes[j]; //node.childNodes[1].innerHTML = i + " / " + j; list.push({instance: node.windowInstance, column: i, row: j}); } } } return list; }, /*====================== FIN = GETTER SETTER = FIN ======================*/ /*========================================================================*/ /*========================== METHODES PUBLIQUES ==========================*/ /*========================================================================*/ /** * Ajouter un Window * @param Window pWindow L'instance d'une fenêtre * @param int pCol (optional) La colonne * @param int pRow (optional) La ligne */ addWindow : function(pWindow, pColumn, pRow){ var windowNode = pWindow.getNode(); windowNode.windowInstance = pWindow; // position pColumn = (pColumn != null)?pColumn:this._columns.length - 1; pRow = (pRow != null)?pRow:this._columns[pColumn].childNodes.length; // événements pWindow.onClose = this._delegate(this, this._onWindowClose); // insertion if(pRow >= this._columns[pColumn].childNodes.length){ this._columns[pColumn].appendChild(windowNode); }else if(pRow <= 0){ this._columns[pColumn].insertBefore(windowNode, this._columns[pColumn].firstChild); }else{ this._columns[pColumn].insertBefore(windowNode, this._columns[pColumn].childNodes[pRow]); } // référencement this._windowsList.push(pWindow); // Mise à jour pWindow.update(); this.onChanged(this.getWindowsList()); } /*==================== FIN = METHODES PUBLIQUES = FIN ====================*/ /*========================================================================*/ };