toolkit/javascript/nco/relations.js
changeset 47 c0b4a8b5a012
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toolkit/javascript/nco/relations.js	Thu Apr 10 14:20:23 2014 +0200
@@ -0,0 +1,213 @@
+function Relations() {
+	this.items = {};
+}
+
+Relations.prototype = {
+	constructor: Relations,
+	
+	/**
+	 * Add an element to the dictionnary under the given name.
+	 * 
+	 * @param {String} id: identifier for the item
+	 * @param {Object} element: item to register
+	 * 
+	 * @returns {Connector}: inserted element wrapped with a Connector
+	 */
+	add: function(id, element) {
+		return this.items[id] = new Connector(element, id, this);
+	},
+	
+	remove: function(id) {
+		
+	},
+	
+	/**
+	 * Gets the wanted item
+	 * 
+	 * @param {String} id: item name
+	 * 
+	 * @returns {Connector}: the wanted item, wrapped in a selector
+	 */
+	get: function(id) {
+		return this.items[id];
+	},
+	
+	/**
+	 * Executes all the registered actions for a given element and a given event.
+	 * 
+	 * First, if the required item is frozen, nothing is executed.
+	 * Then, it checks every observer to see if they are locked, otherwise, their 
+	 * action is performed.
+	 *  
+	 * @param {String} id: id of the element activated
+	 * @param {String} event: name of the event activated
+	 * @param eventParameters: parameters passed by the event raised
+	 * 
+	 * @returns: null
+	 */
+	execute: function(id, event, eventParameters) {
+		var item = this.get(id);
+		if (!item.isFrozen()) {
+			var functions = item.listenedEvents[event];
+			for(var i =0; i<functions.length; ++i) {
+				var observer = this.get(functions[i][0]);
+				if (!observer.isLocked()) {
+					functions[i][1](observer.element, eventParameters);
+				}
+			}
+		}
+	},
+	
+	/**
+	 * Executes an action on each selected item
+	 * 
+	 * The selection is made through an selector string or directly a regular
+	 * expression. Then, on each selected item, the given action is performed
+	 * passed the item as this in the action.
+	 * 
+	 * @param {String/RegExp} selector: selection test to get items
+	 * @param {Function} action: action to perform
+	 * @param {Boolean} getDetails: retrieve all information captured 
+	 * 	by special expressions
+	 * 
+	 * @returns: {Integer} nombre d'éléments trouvés par la recherche
+	 */
+	each: function(selector, action, getDetails) {
+		if (undefined==getDetails) {
+			getDetails = false;
+		}
+		
+		var expr = this.buildExpression(selector, getDetails);
+		var compteur = 0;
+		if (false==getDetails) {
+			for (var itemName in this.items) {
+				if (expr.test(itemName)) {
+					action.call(this.items[itemName], this.items[itemName].element);
+					++compteur;
+				}
+			}
+		}
+		else {
+			var details = null;
+			for (var itemName in this.items) {
+				details = itemName.match(expr);
+				if (null!=details) {
+					action.call(this.items[itemName], this.items[itemName].element, details);
+					++compteur;
+				}
+			}
+		}
+		
+		return compteur;
+	},
+	
+	/**
+	 * Build a selector from a string
+	 * 
+	 * If a string is passed, it is turned as a RegExp.
+	 * If an RegExp instance is passed, it is returned directly.
+	 * 
+	 * @param string selector: string to turn as selector
+	 * @param RegExp selector: regular expression to use
+	 * 
+	 * @returns {RegExp}: selector
+	 */
+	buildExpression: function(selector, getDetails) {
+		if (RegExp==selector) {
+			return selector;
+		}
+		
+		var expression = selector;
+		expression = expression.replace(/(\(|\))/g, "\\$1");
+		
+		if (false==getDetails) {
+			expression = expression.replace(/\[\[digit\]\]/g, "[0-9]+");
+			expression = expression.replace(/\[\[letter\]\]/g, "[a-zA-Z]+");
+			expression = expression.replace(/\./g, "\\.");
+			expression = expression.replace(/\?/g, ".");
+			expression = expression.replace(/\*/g, ".+");
+		}
+		else {
+			expression = expression.replace(/\[\[digit\]\]/g, "([0-9]+)");
+			expression = expression.replace(/\[\[letter\]\]/g, "([a-zA-Z]+)");
+			expression = expression.replace(/\./g, "\\.");
+			expression = expression.replace(/\?/g, "(.)");
+			expression = expression.replace(/\*/g, "(.+)");
+		}
+		
+		return RegExp("^" + expression + "$");
+	}
+};
+
+function Connector(object, id, manager) {
+	this.manager = manager;
+	this.element = object;
+	this.id = id;
+	this.listenedEvents = {};
+	this.locked = false;
+	this.frozen = false;
+}
+
+Connector.prototype = {
+	constructor: Connector,
+	
+	object: function() { return this.element; },
+	
+	bind: function(event, id, action) {
+		if (undefined==action) {
+			this.bind(event, this.id, id);
+		}
+		else {
+			if (undefined!=this.listenedEvents[event]) {
+				this.listenedEvents[event].push([id, action]);
+			}
+			else {
+				var object = this;
+				this.listenedEvents[event] = [[id, action]];
+				this.element.on(event, function() {
+					object.manager.execute(object.id, event, arguments);
+				}) ;
+			}
+		}
+		
+		return this;
+	},
+	
+	bindTo: function(event, id, action) {
+		this.manager.get(id).bind(event, this.id, action);
+		
+		return this;
+	},
+	
+	unbind: function(id, event) {
+		return this;
+	},
+	
+	click: function(id, action) {
+		return this.bind("click", id, action);
+	},
+	
+	dblclick: function(id, action) {
+		return this.bind("dblclick", id, action);
+	},
+	
+	mouseover: function(id, action) {
+		return this.bind("mouseover", id, action);
+	},
+	
+	mouseout: function(id, action) {
+		return this.bind("mouseout", id, action);
+	},
+	
+	lock: function() {	this.locked = true;	},
+	
+	unlock: function() {	this.locked = false;	},
+	
+	isLocked: function() {	return true==this.locked; },
+	
+	freeze: function() {	this.frozen = true;	},
+	
+	unfreeze: function() {	this.frozen = false;	},
+	
+	isFrozen: function() {	return true==this.frozen; }
+};