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 ====================*/
	/*========================================================================*/
};