/
class.addbehavior.js
54 lines (48 loc) · 1.76 KB
/
class.addbehavior.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
Class.addBehavior = function(instance) {
var proto = instance.constructor.prototype;
for (var prop in proto) {
// should wrap functions only (isFunction yields true for regexp so check those as well)
if (typeof proto[prop] == 'function'
&& proto[prop].constructor != RegExp
// method should only be "wrapped" once
&& !proto[prop].__extended)
// need to "save" method and prop in a closure here
proto[prop] = (function(method, prop) {
function m() {
// event should know which instance has fired it
document.fire('before:' + prop, { instance: instance });
// method should be called within an instance context
//var _return = method.apply(instance, arguments);
(function(){document.fire('after:' + prop, { instance: instance });}).defer();
return method.apply(instance, arguments);
};
// method's toString should reference original one
m.toString = method.toString.bind(method);
return m;
})(proto[prop], prop);
// set __extended flag
proto[prop].__extended = true;
}
// and make it chain-friendly
return instance;
};
var Person = Class.create({
initialize: function(name) {
this.name = name;
},
say: function(message) {
return this.name + ': ' + message;
},
eat: function(food) {
for (var i=0;i<100;i++) { $$('*') };
return this.name + ': eating ' + food;
}
});
var jdd = new Person('John');
// document.observe('before:eat', function(e){ console.log('before:eat ', e.memo.instance) });
// document.observe('after:eat', function(e){ console.log('after:eat ', e.memo.instance) });
Class.addBehavior(jdd);
jdd.eat('chicken');
// 'before:eat, { john }'
// 'John: eating chicken'
// 'after:eat, { john }'