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; }
};