|
1 function Relations() { |
|
2 this.items = {}; |
|
3 } |
|
4 |
|
5 Relations.prototype = { |
|
6 constructor: Relations, |
|
7 |
|
8 /** |
|
9 * Add an element to the dictionnary under the given name. |
|
10 * |
|
11 * @param {String} id: identifier for the item |
|
12 * @param {Object} element: item to register |
|
13 * |
|
14 * @returns {Connector}: inserted element wrapped with a Connector |
|
15 */ |
|
16 add: function(id, element) { |
|
17 return this.items[id] = new Connector(element, id, this); |
|
18 }, |
|
19 |
|
20 remove: function(id) { |
|
21 |
|
22 }, |
|
23 |
|
24 /** |
|
25 * Gets the wanted item |
|
26 * |
|
27 * @param {String} id: item name |
|
28 * |
|
29 * @returns {Connector}: the wanted item, wrapped in a selector |
|
30 */ |
|
31 get: function(id) { |
|
32 return this.items[id]; |
|
33 }, |
|
34 |
|
35 /** |
|
36 * Executes all the registered actions for a given element and a given event. |
|
37 * |
|
38 * First, if the required item is frozen, nothing is executed. |
|
39 * Then, it checks every observer to see if they are locked, otherwise, their |
|
40 * action is performed. |
|
41 * |
|
42 * @param {String} id: id of the element activated |
|
43 * @param {String} event: name of the event activated |
|
44 * @param eventParameters: parameters passed by the event raised |
|
45 * |
|
46 * @returns: null |
|
47 */ |
|
48 execute: function(id, event, eventParameters) { |
|
49 var item = this.get(id); |
|
50 if (!item.isFrozen()) { |
|
51 var functions = item.listenedEvents[event]; |
|
52 for(var i =0; i<functions.length; ++i) { |
|
53 var observer = this.get(functions[i][0]); |
|
54 if (!observer.isLocked()) { |
|
55 functions[i][1](observer.element, eventParameters); |
|
56 } |
|
57 } |
|
58 } |
|
59 }, |
|
60 |
|
61 /** |
|
62 * Executes an action on each selected item |
|
63 * |
|
64 * The selection is made through an selector string or directly a regular |
|
65 * expression. Then, on each selected item, the given action is performed |
|
66 * passed the item as this in the action. |
|
67 * |
|
68 * @param {String/RegExp} selector: selection test to get items |
|
69 * @param {Function} action: action to perform |
|
70 * @param {Boolean} getDetails: retrieve all information captured |
|
71 * by special expressions |
|
72 * |
|
73 * @returns: {Integer} nombre d'éléments trouvés par la recherche |
|
74 */ |
|
75 each: function(selector, action, getDetails) { |
|
76 if (undefined==getDetails) { |
|
77 getDetails = false; |
|
78 } |
|
79 |
|
80 var expr = this.buildExpression(selector, getDetails); |
|
81 var compteur = 0; |
|
82 if (false==getDetails) { |
|
83 for (var itemName in this.items) { |
|
84 if (expr.test(itemName)) { |
|
85 action.call(this.items[itemName], this.items[itemName].element); |
|
86 ++compteur; |
|
87 } |
|
88 } |
|
89 } |
|
90 else { |
|
91 var details = null; |
|
92 for (var itemName in this.items) { |
|
93 details = itemName.match(expr); |
|
94 if (null!=details) { |
|
95 action.call(this.items[itemName], this.items[itemName].element, details); |
|
96 ++compteur; |
|
97 } |
|
98 } |
|
99 } |
|
100 |
|
101 return compteur; |
|
102 }, |
|
103 |
|
104 /** |
|
105 * Build a selector from a string |
|
106 * |
|
107 * If a string is passed, it is turned as a RegExp. |
|
108 * If an RegExp instance is passed, it is returned directly. |
|
109 * |
|
110 * @param string selector: string to turn as selector |
|
111 * @param RegExp selector: regular expression to use |
|
112 * |
|
113 * @returns {RegExp}: selector |
|
114 */ |
|
115 buildExpression: function(selector, getDetails) { |
|
116 if (RegExp==selector) { |
|
117 return selector; |
|
118 } |
|
119 |
|
120 var expression = selector; |
|
121 expression = expression.replace(/(\(|\))/g, "\\$1"); |
|
122 |
|
123 if (false==getDetails) { |
|
124 expression = expression.replace(/\[\[digit\]\]/g, "[0-9]+"); |
|
125 expression = expression.replace(/\[\[letter\]\]/g, "[a-zA-Z]+"); |
|
126 expression = expression.replace(/\./g, "\\."); |
|
127 expression = expression.replace(/\?/g, "."); |
|
128 expression = expression.replace(/\*/g, ".+"); |
|
129 } |
|
130 else { |
|
131 expression = expression.replace(/\[\[digit\]\]/g, "([0-9]+)"); |
|
132 expression = expression.replace(/\[\[letter\]\]/g, "([a-zA-Z]+)"); |
|
133 expression = expression.replace(/\./g, "\\."); |
|
134 expression = expression.replace(/\?/g, "(.)"); |
|
135 expression = expression.replace(/\*/g, "(.+)"); |
|
136 } |
|
137 |
|
138 return RegExp("^" + expression + "$"); |
|
139 } |
|
140 }; |
|
141 |
|
142 function Connector(object, id, manager) { |
|
143 this.manager = manager; |
|
144 this.element = object; |
|
145 this.id = id; |
|
146 this.listenedEvents = {}; |
|
147 this.locked = false; |
|
148 this.frozen = false; |
|
149 } |
|
150 |
|
151 Connector.prototype = { |
|
152 constructor: Connector, |
|
153 |
|
154 object: function() { return this.element; }, |
|
155 |
|
156 bind: function(event, id, action) { |
|
157 if (undefined==action) { |
|
158 this.bind(event, this.id, id); |
|
159 } |
|
160 else { |
|
161 if (undefined!=this.listenedEvents[event]) { |
|
162 this.listenedEvents[event].push([id, action]); |
|
163 } |
|
164 else { |
|
165 var object = this; |
|
166 this.listenedEvents[event] = [[id, action]]; |
|
167 this.element.on(event, function() { |
|
168 object.manager.execute(object.id, event, arguments); |
|
169 }) ; |
|
170 } |
|
171 } |
|
172 |
|
173 return this; |
|
174 }, |
|
175 |
|
176 bindTo: function(event, id, action) { |
|
177 this.manager.get(id).bind(event, this.id, action); |
|
178 |
|
179 return this; |
|
180 }, |
|
181 |
|
182 unbind: function(id, event) { |
|
183 return this; |
|
184 }, |
|
185 |
|
186 click: function(id, action) { |
|
187 return this.bind("click", id, action); |
|
188 }, |
|
189 |
|
190 dblclick: function(id, action) { |
|
191 return this.bind("dblclick", id, action); |
|
192 }, |
|
193 |
|
194 mouseover: function(id, action) { |
|
195 return this.bind("mouseover", id, action); |
|
196 }, |
|
197 |
|
198 mouseout: function(id, action) { |
|
199 return this.bind("mouseout", id, action); |
|
200 }, |
|
201 |
|
202 lock: function() { this.locked = true; }, |
|
203 |
|
204 unlock: function() { this.locked = false; }, |
|
205 |
|
206 isLocked: function() { return true==this.locked; }, |
|
207 |
|
208 freeze: function() { this.frozen = true; }, |
|
209 |
|
210 unfreeze: function() { this.frozen = false; }, |
|
211 |
|
212 isFrozen: function() { return true==this.frozen; } |
|
213 }; |