Unreviewed, rolling out r216677.
[WebKit-https.git] / PerformanceTests / Speedometer / resources / todomvc / dependency-examples / flight / bower_components / flight / lib / registry.js
1 // ==========================================
2 // Copyright 2013 Twitter, Inc
3 // Licensed under The MIT License
4 // http://opensource.org/licenses/MIT
5 // ==========================================
6
7 define(
8
9   [],
10
11   function() {
12     'use strict';
13
14     function parseEventArgs(instance, args) {
15       var element, type, callback;
16       var end = args.length;
17
18       if (typeof args[end - 1] === 'function') {
19         end -= 1;
20         callback = args[end];
21       }
22
23       if (typeof args[end - 1] === 'object') {
24         end -= 1;
25       }
26
27       if (end == 2) {
28         element = args[0];
29         type = args[1];
30       } else {
31         element = instance.node;
32         type = args[0];
33       }
34
35       return {
36         element: element,
37         type: type,
38         callback: callback
39       };
40     }
41
42     function matchEvent(a, b) {
43       return (
44         (a.element == b.element) &&
45         (a.type == b.type) &&
46         (b.callback == null || (a.callback == b.callback))
47       );
48     }
49
50     function Registry() {
51
52       var registry = this;
53
54       (this.reset = function() {
55         this.components = [];
56         this.allInstances = {};
57         this.events = [];
58       }).call(this);
59
60       function ComponentInfo(component) {
61         this.component = component;
62         this.attachedTo = [];
63         this.instances = {};
64
65         this.addInstance = function(instance) {
66           var instanceInfo = new InstanceInfo(instance);
67           this.instances[instance.identity] = instanceInfo;
68           this.attachedTo.push(instance.node);
69
70           return instanceInfo;
71         };
72
73         this.removeInstance = function(instance) {
74           delete this.instances[instance.identity];
75           var indexOfNode = this.attachedTo.indexOf(instance.node);
76           (indexOfNode > -1) && this.attachedTo.splice(indexOfNode, 1);
77
78           if (!Object.keys(this.instances).length) {
79             //if I hold no more instances remove me from registry
80             registry.removeComponentInfo(this);
81           }
82         };
83
84         this.isAttachedTo = function(node) {
85           return this.attachedTo.indexOf(node) > -1;
86         };
87       }
88
89       function InstanceInfo(instance) {
90         this.instance = instance;
91         this.events = [];
92
93         this.addBind = function(event) {
94           this.events.push(event);
95           registry.events.push(event);
96         };
97
98         this.removeBind = function(event) {
99           for (var i = 0, e; e = this.events[i]; i++) {
100             if (matchEvent(e, event)) {
101               this.events.splice(i, 1);
102             }
103           }
104         };
105       }
106
107       this.addInstance = function(instance) {
108         var component = this.findComponentInfo(instance);
109
110         if (!component) {
111           component = new ComponentInfo(instance.constructor);
112           this.components.push(component);
113         }
114
115         var inst = component.addInstance(instance);
116
117         this.allInstances[instance.identity] = inst;
118
119         return component;
120       };
121
122       this.removeInstance = function(instance) {
123         var index, instInfo = this.findInstanceInfo(instance);
124
125         //remove from component info
126         var componentInfo = this.findComponentInfo(instance);
127         componentInfo && componentInfo.removeInstance(instance);
128
129         //remove from registry
130         delete this.allInstances[instance.identity];
131       };
132
133       this.removeComponentInfo = function(componentInfo) {
134         var index = this.components.indexOf(componentInfo);
135         (index > -1) && this.components.splice(index, 1);
136       };
137
138       this.findComponentInfo = function(which) {
139         var component = which.attachTo ? which : which.constructor;
140
141         for (var i = 0, c; c = this.components[i]; i++) {
142           if (c.component === component) {
143             return c;
144           }
145         }
146
147         return null;
148       };
149
150       this.findInstanceInfo = function(instance) {
151         return this.allInstances[instance.identity] || null;
152       };
153
154       this.findInstanceInfoByNode = function(node) {
155         var result = [];
156         Object.keys(this.allInstances).forEach(function(k) {
157           var thisInstanceInfo = this.allInstances[k];
158           if (thisInstanceInfo.instance.node === node) {
159             result.push(thisInstanceInfo);
160           }
161         }, this);
162         return result;
163       };
164
165       this.on = function(componentOn) {
166         var instance = registry.findInstanceInfo(this), boundCallback;
167
168         // unpacking arguments by hand benchmarked faster
169         var l = arguments.length, i = 1;
170         var otherArgs = new Array(l - 1);
171         for (; i < l; i++) otherArgs[i - 1] = arguments[i];
172
173         if (instance) {
174           boundCallback = componentOn.apply(null, otherArgs);
175           if (boundCallback) {
176             otherArgs[otherArgs.length-1] = boundCallback;
177           }
178           var event = parseEventArgs(this, otherArgs);
179           instance.addBind(event);
180         }
181       };
182
183       this.off = function(/*el, type, callback*/) {
184         var event = parseEventArgs(this, arguments),
185             instance = registry.findInstanceInfo(this);
186
187         if (instance) {
188           instance.removeBind(event);
189         }
190
191         //remove from global event registry
192         for (var i = 0, e; e = registry.events[i]; i++) {
193           if (matchEvent(e, event)) {
194             registry.events.splice(i, 1);
195           }
196         }
197       };
198
199       // debug tools may want to add advice to trigger
200       registry.trigger = function() {};
201
202       this.teardown = function() {
203         registry.removeInstance(this);
204       };
205
206       this.withRegistration = function() {
207         this.after('initialize', function() {
208           registry.addInstance(this);
209         });
210
211         this.around('on', registry.on);
212         this.after('off', registry.off);
213         //debug tools may want to add advice to trigger
214         window.DEBUG && DEBUG.enabled && this.after('trigger', registry.trigger);
215         this.after('teardown', {obj: registry, fnName: 'teardown'});
216       };
217
218     }
219
220     return new Registry;
221   }
222 );