Zapatec Utils Overview

Overview | File | Class | Tree | Index | Help

Zapatec Utils

PREV NEXT | FRAMES NO FRAMES

## movable.js

#### Summary

No overview generated for 'movable.js'

    //$Id: movable.js 6943 2007-04-16 13:53:11Z slip $
    /**
     * This is a set of functionality used for moving object
     * and is implemented in interface (mixin) manner.
     */
    Zapatec.Movable = {};

    /**
     * Moves the object ot specified position.
     * Object can consist of group of elements,
     * that will be moved together. This method can
     * recognize not only "px" values, but "left", "top",
     * "bottom", "right", etc. This depends on your
     * _parseCoordinate implementation, if you don't
     * want to use standart one.
     * @param x {number or string} X coordinate.
     * @param y {number or string} Y coordinate.
     * @return {boolean} true if success, otherwise false.
     */
    Zapatec.Movable.setPosition = function(x, y) {
    	//preparations which can depend on the Widget.
    	if (!this.isMovableSafely()) {
    		Zapatec.Log({description : "The object with ID '" + this.id + "' was not prepared for moving! Use obj.makeMovable() to do so!", type : "warning"});
    		return false;
    	}
    	var msgValue = null, moveConfig = this.getMoveConfig();
    	//_parseCoordinate takes the coordinate value and first of all
    	//tryes to return the numeric representation in pixels.
    	//Also if it returns null value (false and "" are also
    	//treated so) method stops execution without making something.
    	//This can be useful for implementing restrictions.
    	if (x || x === 0) {
    		msgValue = x;
    		x = this._parseCoordinate(x, "x", moveConfig.moveLayer);
    		if (!x && x !== 0) {
    			Zapatec.Log({description : "The X coordinate " + msgValue + " can not be set for object with ID '" + this.id + "'!", type : "warning"});
    			return false;
    		}
    	}
    	if (y || y === 0) {
    		msgValue = y;
    		y = this._parseCoordinate(y, "y", moveConfig.moveLayer);
    		if (!y && y !== 0) {
    			Zapatec.Log({description : "The Y coordinate " + msgValue + " can not be set for object with ID '" + this.id + "'!", type : "warning"});
    			return false;
    		}
    	}
    	//getMovableElements returns the array of elements
    	//that actually are moved. Param passed is the dimension
    	//in which we move.
    	var elements = Zapatec.Array(this.getMovableElements());
    	if (this.fireEvent("beforePositionChange", x, y) === false) {
    		return false;
    	}
    	if (Zapatec.GlobalEvents.fireEvent("beforePositionChange", x, y, this) === false) {
    		return false;
    	}
    	//proceeding coordinates
    	this._proceedElementsCoords(x, y, elements);
    	//firing events
    	if (this.isMoving()) {
    		this.fireEvent("onMove", x || this.getPosition().x, y || this.getPosition().y);
    		Zapatec.GlobalEvents.fireEvent("onMove", x || this.getPosition().x, y || this.getPosition().y, this);
    	}
    	this.fireEvent("onPositionChange", x || this.getPosition().x, y || this.getPosition().y);
    	Zapatec.GlobalEvents.fireEvent("onPositionChange", x || this.getPosition().x, y || this.getPosition().y, this);
    	//reporting success
    	return true;
    };

    /**
     * This method is used for the objects that use
     * such concept as orientation. Method reacts on
     * two types of orientation: "vertical" and "horizontal".
     * @param x {number} oriented X to set.
     * @param y {number} oriented Y to set.
     * @return {boolean} true if success, otherwise false.
     */
    Zapatec.Movable.setOrientedPosition = function(x, y) {
    	switch (this.getMoveConfig().orientation) {
    		case "vertical" : {
    			//vertical orientation means height
    			return this.setPosition(y, x);
    		}
    		case "horizontal" : {
    			//horizontal orientation means width
    			return this.setPosition(x, y);
    		}
    	}
    	return false;
    };

    /**
     * Sets the position of the object relatively
     * to the document page(BODY).
     * @param x {number or string} X coordinate on the page.
     * @param y {number or string} Y coordinate on the page.
     * @return {boolean} true if success, otherwise false.
     */
    Zapatec.Movable.setPagePosition = function(x, y) {
    	var moveConfig = this.getMoveConfig();
    	if (moveConfig.moveLayer == document.body) {
    		return this.setPosition(x, y);
    	}
    	var msgValue = null;
    	//_parseCoordinate takes the coordinate value and first of all
    	//tryes to return the numeric representation in pixels.
    	//Also if it returns null value (false, "", 0 are also
    	//treated so) method stops execution without making something.
    	//This can be useful for implementing restrictions.
    	if (x || x === 0) {
    		msgValue = x;
    		x = this._parseCoordinate(x, "x", document.body);
    		if (!x && x !== 0) {
    			Zapatec.Log({description : "The X page coordinate " + msgValue + " can not be set for object with ID '" + this.id + "'!", type : "warning"});
    			return false;
    		}
    	}
    	if (y || y === 0) {
    		msgValue = y;
    		y = this._parseCoordinate(y, "y", document.body);
    		if (!y && y !== 0) {
    			Zapatec.Log({description : "The Y page coordinate " + msgValue + " can not be set for object with ID '" + this.id + "'!", type : "warning"});
    			return false;
    		}
    	}
    	var pos = Zapatec.Utils.getElementOffset(moveConfig.moveLayer);
    	return this.setPosition((x || x === 0) ? (x - pos.x) : x, (y || y === 0) ? (y - pos.y) : y);
    };

    /**
     * Sets the position of the object relatively
     * to the client area of the browser.
     * @param x {number or string} X coordinate on the screen.
     * @param y {number or string} Y coordinate on the screen.
     * @return {boolean} true if success, otherwise false.
     */
    Zapatec.Movable.setScreenPosition = function(x, y) {
    	var moveConfig = this.getMoveConfig();
    	var msgValue = null;
    	//_parseCoordinate takes the coordinate value and first of all
    	//tryes to return the numeric representation in pixels.
    	//Also if it returns null value (false, "", 0 are also
    	//treated so) method stops execution without making something.
    	//This can be useful for implementing restrictions.
    	if (x || x === 0) {
    		msgValue = x;
    		x = this._parseCoordinate(x, "x", window);
    		if (!x && x !== 0) {
    			Zapatec.Log({description : "The X screen coordinate " + msgValue + " can not be set for object with ID '" + this.id + "'!", type : "warning"});
    			return false;
    		}
    	}
    	if (y || y === 0) {
    		msgValue = y;
    		y = this._parseCoordinate(y, "y", window);
    		if (!y && y !== 0) {
    			Zapatec.Log({description : "The Y screen coordinate " + msgValue + " can not be set for object with ID '" + this.id + "'!", type : "warning"});
    			return false;
    		}
    	}
    	if (moveConfig.moveLayer != document.body) {
    		var pos = Zapatec.Utils.getElementOffset(moveConfig.moveLayer);
    	} else {
    		var pos = {x : 0, y : 0};
    	}
    	return this.setPosition((x || x === 0) ? (x - pos.x) : x, (y || y === 0) ? (y - pos.y) : y);
    };

    /**
     * Moves the object for the given offset from
     * the place it is currently in.
     * @param offsetLeft {number} the offset value for X coordinate.
     * @param offsetTop {number} the offset value for Y coordinate.
     * @return {boolean} true if success, otherwise false.
     */
    Zapatec.Movable.moveFor = function(offsetLeft, offsetTop) {
    	var pos = this.getPosition();
    	return this.setPosition(
    		offsetLeft == null ? null : pos.x + offsetLeft,
    		offsetTop == null ? null : pos.y + offsetTop
    	);
    };

    /**
     * Returns the position of the main element.
     * If there is no such, we take the one that is
     * the most left and top :).
     * This value is offset from movable parent.
     * @return {object} object with x and y properties.
     */
    Zapatec.Movable.getPosition = function() {
    	//getMovableMeasurement returns the element
    	//that is the measurement of moving for all others.
    	var el = this.getMovableMeasurement();
    	//if we succeed with this lets return coords
    	if (Zapatec.isHtmlElement(el) ||
    	    (el && typeof el == "object" && typeof el.x == "number" && typeof el.y == "number")) {
    			return Zapatec.Utils.getPos(el) || el;
    	}
    	//otherwise reporting failure
    	Zapatec.Log({description : "Can't calculate position for object with ID '" + this.id + "'!", type : "warning"});
    	return false;
    };

    /**
     * Gets the position of the element on the page.
     * @return {object} object with x and y properties.
     */
    Zapatec.Movable.getPagePosition = function() {
    	//getMovableMeasurement returns the element
    	//that is the measurement of moving for all others.
    	var el = this.getMovableMeasurement();
    	//if we succeed with this lets return coords
    	if (Zapatec.isHtmlElement(el) ||
    	    (el && typeof el == "object" && typeof el.x == "number" && typeof el.y == "number")) {
    			return Zapatec.Utils.getElementOffset(el) || el;
    	}
    	//otherwise reporting failure
    	Zapatec.Log({description : "Can't calculate screen position for object with ID '" + this.id + "'!", type : "warning"});
    	return false;
    };

    /**
     * Gets the position of the element on the screen.
     * @return {object} object with x and y properties.
     */
    Zapatec.Movable.getScreenPosition = function() {
    	//getting page position
    	var pos = this.getPagePosition();
    	//excluding scrolling
    	pos.x -= Zapatec.Utils.getPageScrollX();
    	pos.y -= Zapatec.Utils.getPageScrollY();
    	//returning position
    	return pos;
    };

    /**
     * Strats the event of moving. This is used
     * to send message to interested objects that
     * moving was started. This involves the calling
     * of "onMove" event from setPosition.
     * endMove method stops the action.
     * @return {boolean} true if success, otherwise false
     */
    Zapatec.Movable.startMove = function() {
    	//preparations which can depend on the Widget.
    	if (!this.isMovableSafely()) {
    		Zapatec.Log({description : "The object with ID '" + this.id + "' was not prepared for moving! Use obj.makeMovable() to do so!", type : "warning"});
    		return false;
    	}
    	this.fireEvent("moveStart");
    	Zapatec.GlobalEvents.fireEvent("moveStart", this);
    	this._setMovingState(true);
    	return true;
    };

    /**
     * Ends the event of moving. This is used
     * to send message to interested objects that
     * moving was ended. This stops the calling
     * of "onMove" event from setPosition.
     * @return {boolean} true if success, otherwise false
     */
    Zapatec.Movable.endMove = function() {
    	if (!this.isMoving()) {
    		Zapatec.Log({description : "The moving for object with ID '" + this.id + "' was not started!", type : "warning"});
    		return false;
    	}
    	this.fireEvent("moveEnd");
    	Zapatec.GlobalEvents.fireEvent("moveEnd", this);
    	this._setMovingState(false);
    	return true;
    };

    /**
     * Gets the state of moving. It returns
     * true if moving was started, otherwise
     * it returns false.
     * @return {boolean} true if moving started, otherwise false
     */
    Zapatec.Movable.isMoving = function() {
    	return this.movingState;
    };

    /**
     * Sets the state of moving to true or false.
     * This is used internally and can be overwritten
     * in child classes to use another propety for the flag.
     */
    Zapatec.Movable._setMovingState = function(on) {
    	this.movingState = on;
    };

    /**
     * Is object prepared for moving.
     * Mostly you will need to redefine this method,
     * to use some other property as a flag.
     * @return {boolean} true if prepared, otherwise false.
     */
    Zapatec.Movable.isMovableSafely = function() {
    	return this.safelyMovable;
    };

    /**
     * Fills some flag with the true or false value.
     * Same flag should be used in isMovableSafely method.
     * @param on {boolean} turn on or turn of.
     */
    Zapatec.Movable._setMovableSafely = function(on) {
    	this.safelyMovable = on;
    };

    /**
     * Makes all movable elements safely movable.
     * @return {boolean} true if success, otherwise false.
     */
    Zapatec.Movable.makeMovable = function() {
    	if (!this.requireInterface("Zapatec.CommandEvent")) {
    		return false;
    	}
    	if (this.isMovableSafely()) {
    		return true;
    	}
    	var elements = Zapatec.Array(this.getMovableElements()), self = this,
    	moveConfig = this.getMoveConfig();
    	//trying to prepare each element
    	success = elements.each(function(index, movable) {
    		if (Zapatec.isHtmlElement(movable)) {
    			//prepareing HTML elements
    			if (moveConfig.preserveSizes &&
    			    !Zapatec.Utils.makeSafelySizable(movable)) {
    					return "break";
    			}
    			if (!Zapatec.Utils.makeSafelyMovable(movable, moveConfig.moveLayer)) {
    				return "break";
    			}
    			self.createProperty(movable, "moveObj", self);
    		} else if (Zapatec.isMovableObj(movable)) {
    			//prepareing movable objects
    			if (!movable.makeMovable()) {
    				return "break";
    			}
    		}
    	});
    	//if there was failure we need roll back all the preparations
    	if (!success) {
    		//restoreing elements or objects
    		this.restoreOfMove();
    		//reporting error
    		Zapatec.Log({description : "Can not make the object with ID '" + this.id + "' movable!"});
    		return false;
    	}
    	//reporting success
    	this._setMovableSafely(true);
    	return true;
    };

    /**
     * Restoreing object of movable state.
     * @return {boolean} always returns true.
     */
    Zapatec.Movable.restoreOfMove = function() {
    	if (!this.isMovableSafely()) {
    		return true;
    	}
    	//getting all movable elements
    	var elements = Zapatec.Array(this.getMovableElements());
    	var self = this;
    	//restoreing each item
    	elements.each(function(index, movable) {
    		if (Zapatec.isHtmlElement(movable)) {
    			Zapatec.Utils.restoreOfMove(movable);
    			if (self.getMoveConfig().preserveSizes) {
    				Zapatec.Utils.restoreOfSizing(movable);
    			}
    			movable.moveObj = null;
    		} else if (Zapatec.isMovableObj(movable)) {
    			movable.restoreOfMove();
    		}
    	}, true);
    	//returning success
    	this._setMovableSafely(false);
    	return true;
    };

    /**
     * Returns the measurement element for this movable
     * object. This a generous method, and mostly will
     * be overwritten in implementing class.
     * @return {null or number or HTML element} method should return
     * null if there is no measure, or number or HTML element to
     * calculate measurement.
     */
    Zapatec.Movable.getMovableMeasurement = function() {
    	return this.getContainer();
    };

    /**
     * Returns the configuration object for movement.
     * @return {object} configuration object.
     */
    Zapatec.Movable.getMoveConfig = function() {
    	return this.getConfiguration();
    };

    /**
     * Sets the moving configuration.
     * @param config {object} a set of new configuration.
     */
    Zapatec.Movable.setMoveConfig = function(config) {
    	this.reconfigure(config);
    };

    /**
     * Returns the array of elements to be moved in this
     * object. This a generous method, and mostly will
     * be overwritten in implementing class.
     * @return {mixed} method should return null if there is no movable
     * elements, or array of HTML elements or Zapatec.Movable objects
     * to size them or get their size or prepare them.
     */
    Zapatec.Movable.getMovableElements = function() {
    	return this.getContainer();
    };

    /**
     * Returns container for this object.
     */
    Zapatec.Movable.getContainer = function() {
    	return this.getMoveConfig().container;
    };

    /**
     * Parses the value of the coord argument
     * to calculate the number in pixels.
     * If this method returns null or false
     * or "" or 0 nothing is done at all.
     * @param coord {string} string representation of the coord.
     * @param dimension {string} dimension in which we should parse.
     * @return {number or null} null if nothing should be done
     * by setPosition method, otherwise returns the coordinate in pixels.
     */
    Zapatec.Movable._parseCoordinate = function(coord, dimension, within) {
    	switch (true) {
    		case (typeof coord == "number") : {
    			if (within == window) {
    				coord += Zapatec.Utils["getPageScroll" + dimension.toUpperCase()]();
    			}
    			break;
    		}
    		case ((/^\d+px$/).test(String(coord))) : {
    			coord = parseInt(coord, 10);
    			if (within == window) {
    				coord += Zapatec.Utils["getPageScroll" + dimension.toUpperCase()]();
    			}
    			break;
    		}
    		case ((/^(left|top|bottom|right|center)$/i).test(String(coord))) : {
    			coord = this._parseWordCoordinate(coord, dimension, within);
    			break;
    		}
    	}
    	return this._canSetCoordinate(coord, dimension, within);
    };

    /**
     * Parses coordinate that is represented with one of the
     * following words : "left", "top", "right", "bottom", "center".
     * All of the words (except center) have special meaning for
     * upper case. If lower case means top to top (left to left, etc.),
     * then upper case means bottom to top.
     * @param coord {string} string representing coordinate.
     * @param dimension {string} dimension in which we parse.
     * @param within {HTML element} this is the basis on which we parse.
     * @return {number or false} numeric representation of the coordinate
     * or false if can not parse.
     */
    Zapatec.Movable._parseWordCoordinate = function(coord, dimension, within) {
    	//preventing errors
    	if ((/(left|right)/i).test(String(coord)) && dimension.toUpperCase() != "X") {
    		return false;
    	}
    	if ((/(top|bottom)/i).test(String(coord)) && dimension.toUpperCase() != "Y") {
    		return false;
    	}
    	//additional helpfull strings to make code shorter
    	var dim = (dimension.toUpperCase() == "X") ? "Left" : "Top";
    	var sizeDim = (dimension.toUpperCase() == "X") ? "Width" : "Height";
    	//at first leave it as zero
    	var parsedCoord = 0;
    	//getting needed within size for calculating coordinate
    	var wSize = null;
    	if (Zapatec.isHtmlElement(within)) {
    		//include scrolling
    		parsedCoord = within["scroll" + dim];
    		//getting size
    		wSize = Zapatec.Utils["get" + sizeDim](within);
    	} else if (within == window) {
    		//include scrolling
    		parsedCoord = Zapatec.Utils["getPageScroll" + dimension.toUpperCase()]();
    		//getting size
    		wSize = Zapatec.Utils.getWindowSize()[sizeDim.toLowerCase()];
    	} else if (within && typeof within == "object") {
    		//changing coordinate
    		parsedCoord += within["scroll" + dim] || 0;
    		//getting size
    		wSize = within[sizeDim.toLowerCase()];
    	} else {
    		return false;
    	}
    	//getting measurement
    	var measurement = this.getMovableMeasurement();
    	//getting needed measurement size for calculating coordinate
    	var mSize = null;
    	if (Zapatec.isHtmlElement(measurement)) {
    		mSize = Zapatec.Utils["get" + sizeDim](measurement);
    	} else if (measurement && typeof measurement == "object") {
    		mSize = measurement[sizeDim.toLowerCase()];
    	}
    	//calculating actual coordinate
    	switch (coord) {
    		case "left" : case "top" : {
    			break;
    		}
    		case "LEFT" : case "TOP" : {
    			parsedCoord -= mSize;
    			break;
    		}
    		case "right" : case "bottom" : {
    			parsedCoord += wSize - mSize;
    			break;
    		}
    		case "RIGHT" : case "BOTTOM" : {
    			parsedCoord += wSize;
    			break;
    		}
    		case "center" : {
    			parsedCoord += Math.round((wSize - mSize) / 2);
    			break;
    		}
    		case "CENTER" : {
    			parsedCoord += Math.round(wSize / 2);
    			break;
    		}
    		default : {
    			parsedCoord = null;
    			break;
    		}
    	}
    	//returning result
    	if (!parsedCoord && parsedCoord !== 0) {
    		return false;
    	} else {
    		return parsedCoord;
    	}
    };

    /**
     * This method restricts coordinate setting.
     * @param coord {string} coordinate.
     * @param dimension {string} dimension in which we check.
     * @param within {HTML element} this is the basis on which we check.
     * @return {number or false} the coordinate or false if can not set.
     */
    Zapatec.Movable._canSetCoordinate = function(coord, dimension, within) {
    	if (typeof coord != "number") {
    		return false;
    	}
    	//getting move configuration
    	var moveConfig = this.getMoveConfig();
    	//we don't check for other withins than moveLayer
    	if (within != moveConfig.moveLayer) {
    		return coord;
    	}
    	//getting limit object
    	var limitObj = moveConfig.limit;
    	//coordinate dimension ("X" or "Y") to be used for getting values
    	var dim = dimension.toUpperCase();
    	//direction of possible movement
    	var direction = moveConfig.direction.toLowerCase();
    	//getting corrections to restriction due to moving shape
    	var correction = this._getMovableShape();
    	//if dimension is opposite to possible direction of movement
    	//returning overflow handling
    	if (dim == "X" && direction == "vertical") {
    		return this._handleCoordOverflow(this.getPosition().x);
    	} else if (dim == "Y" && direction == "horizontal") {
    		return this._handleCoordOverflow(this.getPosition().y);
    	}
    	//checking the lower bound
    	if ((limitObj["min" + dim] || limitObj["min" + dim] === 0) && coord < limitObj["min" + dim] + correction["min" + dim]) {
    		return this._handleCoordOverflow(limitObj["min" + dim] + correction["min" + dim]);
    	}
    	//checking the upper bound
    	if ((limitObj["max" + dim] || limitObj["max" + dim] === 0) && coord > limitObj["max" + dim] + correction["max" + dim]) {
    		return this._handleCoordOverflow(limitObj["max" + dim] + correction["max" + dim]);
    	}
    	//just returning value
    	return coord;
    };

    /**
     * A method to handle coordinate overflow of the limit.
     * @param limit {number} limit that was overflowed.
     * @param dimension {string} dimension of coordinate.
     * @return {boolean or number} false if can not set,
     * otherwise new coordinate.
     */
    Zapatec.Movable._handleCoordOverflow = function(limit, dimension) {
    	return false;
    };

    /**
     * Returns the object with 4 properties. Each
     * of them means the correction to upper or lower
     * measure of the limit.
     * @return {object} object with minX, maxX, minY and maxY properties.
     */
    Zapatec.Movable._getMovableShape = function() {
    	//getting measurement element
    	var measurement = this.getMovableMeasurement();
    	//default corrections are equal 0
    	var obj = {minX : 0, maxX : 0, minY : 0, maxY : 0};
    	//currently we only support true value
    	switch (this.getMoveConfig().followShape) {
    		case (true) : {
    			//not an HTML element no corrections
    			if (!Zapatec.isHtmlElement(measurement)) {
    				return obj;
    			}
    			//correcting upper bounds
    			obj.maxX = -Zapatec.Utils.getWidth(measurement);
    			obj.maxY = -Zapatec.Utils.getHeight(measurement);
    			return obj
    		}
    		default : {
    			return obj;
    		}
    	}
    };

    /**
     * Returns the coordinate of the moving point.
     * Its the point which is thought to be the
     * center of movement.
     * @return {object} object with x and y properties.
     */
    Zapatec.Movable.getMovingPoint = function() {
    	return this.getScreenPosition();
    };

    /**
     * Iterates through all the elements in the
     * array and tryes to set their coordinates.
     * @param x {number} x coordinate.
     * @param y {number} y coordinate.
     * @param elements {array} array of elements to proceed.
     */
    Zapatec.Movable._proceedElementsCoords = function(x, y, elements) {
    	//making sure this is Zapatec.Array
    	elements = Zapatec.Array(elements);
    	//calculateing measurement position
    	var measurement = this.getMovableMeasurement();
    	var pos = null;
    	if (Zapatec.isHtmlElement(measurement)) {
    		pos = Zapatec.Utils.getPos(measurement);
    	} else if (measurement && typeof measurement == "object") {
    		pos = {
    			x : (typeof measurement.x == "number") ? measurement.x : null,
    			y : (typeof measurement.y == "number") ? measurement.y : null
    		};
    		if (!measurement.x || !measurement.y) {
    			pos = null;
    		}
    	}
    	//iterating through all items
    	elements.each(function(index, movable) {
    		var mX = x, mY = y;
    		//if there is measurement calculating position
    		if (pos) {
    			var mPos = null;
    			if (Zapatec.isHtmlElement(movable)) {
    				mPos = Zapatec.Utils.getPos(movable);
    			} else if (Zapatec.isMovableObj(movable)) {
    				mPos = movable.getPosition();
    			} else {
    				return;
    			}
    			if (x || x === 0) {
    				mX = mPos.x + (x - pos.x);
    			}
    			if (y || y === 0) {
    				mY = mPos.y + (y - pos.y);
    			}
    		}
    		//setting position
    		if (Zapatec.isHtmlElement(movable)) {
    			Zapatec.Utils.moveTo(movable, mX, mY);
    		} else if (Zapatec.isMovableObj(movable)) {
    			movable.setPosition(mX, mY);
    		}
    	});
    };

    /**
     * Sorts elements in array by their path in the DOM
     * tree. This is usefull when you have synchronized
     * elements that influence each other in the DOM tree
     * when you try to make them movable. The sort order
     * is descending.
     * @param elements {array} array of elements to be sorted.
     * @return {boolean} true if successful, otherwise false.
     */
    Zapatec.Movable.sortElementsByPath = function(elements) {
    	//making array of elements Zapatec.Array
    	elements = Zapatec.Array(elements);
    	//iterating through each item to get path and compare with others
    	elements.each(function(index, element) {
    		//no path - no action for this element
    		var path = Zapatec.Utils.getElementPath(element, document.body);
    		if (!path) {
    			return;
    		}
    		//splitting path into array
    		path = Zapatec.Array(path.split("-"));
    		//compareing path with path of all other elements
    		for(var i = index; i < elements.length; ++i) {
    			//no path - no action for this element
    			var compPath = Zapatec.Utils.getElementPath(elements[i], document.body);
    			if (!compPath) {
    				continue;
    			}
    			//splitting path into array
    			compPath = Zapatec.Array(compPath.split("-"));
    			//compareing parts of both pahs
    			path.each(function(k, pathPiece, whole) {
    				//if our part is bigger than breaking the cycle
    				if (parseInt(pathPiece, 10) > (parseInt(compPath[k], 10) || 0)) {
    					return "break";
    				} else if (parseInt(pathPiece, 10) < parseInt(compPath[k], 10)) {
    					//if our part is smaller then exchanging elements with
    					//their places in array and breaking the cycle
    					var el = elements[index]
    					elements[index] = elements[i];
    					elements[i] = el;
    					path = compPath;
    					return "break";
    				}
    				//continuing compareing if parts are equal
    			});
    		}
    	});
    	return true;
    };

    /**
     * This is Zapatec.Utils.Movable object definition.
     * This is done in the "interface" manner.
     * It represents most of the routines and
     * events connected to moving of the object.
     * @param config {object} - all parameters are passed as the properties of this object.
     *
     * Constructor recognizes the following properties of the config object
     * \code
     *    prop. name     | description
     *  -------------------------------------------------------------------------------------------------
     *  container        | {HTML element} The main element to be movable (default null).
     *  synchronize      | {array} Elements to be synchronize in moving (default []).
     *  direction        | {string} Enabled direction of moving. Can be "vertical", "horizontal" or "both"
     *                   | (default "both").
     *  limit            | {object} Object with properties "minX", "maxX", "minY" and "maxY",
     *                   | that are used as restrictions for setting position.
     *  moveLayer        | {HTML element} Element to be used as movement parent (default document.body).
     *
     * \endcode
     */
    Zapatec.Utils.Movable = function(config) {
    	Zapatec.Utils.Movable.SUPERconstructor.call(this, config);
    };

    Zapatec.Utils.Movable.id = "Zapatec.Utils.Movable";
    Zapatec.inherit(Zapatec.Utils.Movable, Zapatec.Widget);
    //implementing Zapatec.CommandEvent interface
    Zapatec.implement(Zapatec.Utils.Movable, "Zapatec.CommandEvent");
    //implementing Zapatec.Movable interface
    Zapatec.implement(Zapatec.Utils.Movable, "Zapatec.Movable");

    /**
     * Inits the object with set of config options.
     * @param config {object} configuration parameters.
     */
    Zapatec.Utils.Movable.prototype.init = function(config) {
    	//calling parent init
    	Zapatec.Utils.Movable.SUPERclass.init.call(this, config);
    	var self = this;
    	var elements = null;
    	//makes object movable (means all elements that are movable)
    	if (this.getConfiguration().makeMovable) {
    		this.makeMovable();
    	} else {
    		elements = Zapatec.Array(this.getMovableElements());
    		elements.each(function(index, movable) {
    			if (Zapatec.isHtmlElement(movable)) {
    				self.createProperty(movable, "moveObj", self);
    			}
    		});
    	}
    };

    /**
     * Sets the default configuration of the object and
     * inits it with user defined values.
     * @param config {object} configuration parameters.
     */
    Zapatec.Utils.Movable.prototype.configure = function(config) {
    	//set of elements to be moved with container
    	this.defineConfigOption("synchronize", []);
    	//container, which is actually moved too and also
    	//is used as a measurement
    	this.defineConfigOption("container", null);
    	//limitations of the moving
    	this.defineConfigOption("limit", {
    		minX : null,
    		maxX : null,
    		minY : null,
    		maxY : null
    	});
    	//direction of move (you can enable move only in one direction)
    	this.defineConfigOption("direction", "both");
    	//moving layer, the element to be used as offset parent
    	this.defineConfigOption("moveLayer", document.body);
    	//restriction shape for the element
    	this.defineConfigOption("followShape", "LT");
    	//should we preserve element's sizes
    	this.defineConfigOption("preserveSizes", true);
    	//if false, init doesn't make element movable
    	this.defineConfigOption("makeMovable", true);
    	//no theme
    	this.defineConfigOption("theme", null);
    	// Call parent method
    	Zapatec.Utils.Movable.SUPERclass.configure.call(this, config);
    	config = this.getConfiguration();
    	//checking if limit object wasn't overwritten
    	if (!config.limit || typeof config.limit != "object") {
    		config.limit = {
    			minX : null,
    			maxX : null,
    			minY : null,
    			maxY : null
    		};
    	}
    	var self = this;
    	//making sure that config.syncronize will be Array.
    	config.synchronize = Zapatec.Array(config.synchronize);
    	config.synchronize.each(function(index, element) {
    		if (element === null) {
    			return;
    		}
    		element = Zapatec.Widget.getElementById(element);
    		element = Zapatec.Utils.img2div(element);
    		if (!element) {
    			Zapatec.Log({description : "Wrong element in synchronize array for the movable object with ID '" + self.id + "'!"});
    		} else {
    			config.synchronize[index] = element;
    		}
    	});
    	//setting default container element
    	config.container = Zapatec.Widget.getElementById(config.container);
    	config.container = Zapatec.Utils.img2div(config.container);
    	if (!Zapatec.isHtmlElement(config.container)) {
    		Zapatec.Log({description : "Wrong element passed as container for the movable object with ID '" + self.id + "'!"});
    	}
    	this.movableElements = Zapatec.Array(config.synchronize.concat(config.container));
    	if (this.movableElements.length > 1) {
    		this.sortElementsByPath(this.movableElements);
    	}
    	//setting default move layer
    	if (!Zapatec.isHtmlElement(config.moveLayer = Zapatec.Widget.getElementById(config.moveLayer))) {
    		config.moveLayer = document.body;
    	}
    };

    /**
     * Reconfigures the object with new parameters.
     * @param config {object} new configuration parameters.
     */
    Zapatec.Utils.Movable.prototype.reconfigure = function(config) {
    	// Call parent method
    	Zapatec.Utils.Movable.SUPERclass.reconfigure.call(this, config);
    };

    /**
     * Returns the array of synchronized moving elements.
     * @return {array} array of elements that are synchronized
     */
    Zapatec.Utils.Movable.prototype.getMovableElements = function() {
    	return this.movableElements;
    };

Overview | File | Class | Tree | Index | Help

Zapatec Utils

PREV NEXT | FRAMES NO FRAMES

Documentation generated by JSDoc on Thu Aug 16 12:18:39 2007