Coverage

97%
115
112
3

class.js

96%
63
61
2
LineHitsSource
1// Class
2// -----------------
3// Thanks to:
4// - http://mootools.net/docs/core/Class/Class
5// - http://ejohn.org/blog/simple-javascript-inheritance/
6// - https://github.com/ded/klass
7// - http://documentcloud.github.com/backbone/#Model-extend
8// - https://github.com/joyent/node/blob/master/lib/util.js
9// - https://github.com/kissyteam/kissy/blob/master/src/seed/src/kissy.js
10
11
12// The base Class implementation.
131function Class(o) {
14 // Convert existed function to Class.
1511 if (!(this instanceof Class) && isFunction(o)) {
161 return classify(o)
17 }
18}
19
201module.exports = Class
21
22
23// Create a new Class.
24//
25// var SuperPig = Class.create({
26// Extends: Animal,
27// Implements: Flyable,
28// initialize: function() {
29// SuperPig.superclass.initialize.apply(this, arguments)
30// },
31// Statics: {
32// COLOR: 'red'
33// }
34// })
35//
361Class.create = function(parent, properties) {
3729 if (!isFunction(parent)) {
3817 properties = parent
3917 parent = null
40 }
41
4229 properties || (properties = {})
4329 parent || (parent = properties.Extends || Class)
4429 properties.Extends = parent
45
46 // The created class constructor
4729 function SubClass() {
48 // Call the parent constructor.
4926 parent.apply(this, arguments)
50
51 // Only call initialize in self constructor.
5226 if (this.constructor === SubClass && this.initialize) {
538 this.initialize.apply(this, arguments)
54 }
55 }
56
57 // Inherit class (static) properties from parent.
5829 if (parent !== Class) {
5918 mix(SubClass, parent, parent.StaticsWhiteList)
60 }
61
62 // Add instance properties to the subclass.
6329 implement.call(SubClass, properties)
64
65 // Make subclass extendable.
6629 return classify(SubClass)
67}
68
69
701function implement(properties) {
7131 var key, value
72
7331 for (key in properties) {
7452 value = properties[key]
75
7652 if (Class.Mutators.hasOwnProperty(key)) {
7732 Class.Mutators[key].call(this, value)
78 } else {
7920 this.prototype[key] = value
80 }
81 }
82}
83
84
85// Create a sub Class based on `Class`.
861Class.extend = function(properties) {
876 properties || (properties = {})
886 properties.Extends = this
89
906 return Class.create(properties)
91}
92
93
941function classify(cls) {
9530 cls.extend = Class.extend
9630 cls.implement = implement
9730 return cls
98}
99
100
101// Mutators define special properties.
1021Class.Mutators = {
103
104 'Extends': function(parent) {
10529 var existed = this.prototype
10629 var proto = createProto(parent.prototype)
107
108 // Keep existed properties.
10929 mix(proto, existed)
110
111 // Enforce the constructor to be what we expect.
11229 proto.constructor = this
113
114 // Set the prototype chain to inherit from `parent`.
11529 this.prototype = proto
116
117 // Set a convenience property in case the parent's prototype is
118 // needed later.
11929 this.superclass = parent.prototype
120 },
121
122 'Implements': function(items) {
1231 isArray(items) || (items = [items])
1241 var proto = this.prototype, item
125
1261 while (item = items.shift()) {
1272 mix(proto, item.prototype || item)
128 }
129 },
130
131 'Statics': function(staticProperties) {
1322 mix(this, staticProperties)
133 }
134}
135
136
137// Shared empty constructor function to aid in prototype-chain creation.
1381function Ctor() {
139}
140
141// See: http://jsperf.com/object-create-vs-new-ctor
1421var createProto = Object.__proto__ ?
143 function(proto) {
14429 return { __proto__: proto }
145 } :
146 function(proto) {
1470 Ctor.prototype = proto
1480 return new Ctor()
149 }
150
151
152// Helpers
153// ------------
154
1551function mix(r, s, wl) {
156 // Copy "all" properties including inherited ones.
15751 for (var p in s) {
15860 if (s.hasOwnProperty(p)) {
15966 if (wl && indexOf(wl, p) === -1) continue
160
161 // 在 iPhone 1 代等设备的 Safari 中,prototype 也会被枚举出来,需排除
16254 if (p !== 'prototype') {
16354 r[p] = s[p]
164 }
165 }
166 }
167}
168
169
1701var toString = Object.prototype.toString
1711var isArray = Array.isArray
172
1731var isFunction = function(val) {
17430 return toString.call(val) === '[object Function]'
175}
176
1771var indexOf = function(arr, item) {
1787 return arr.indexOf(item)
179}

events.js

98%
52
51
1
LineHitsSource
1// Events
2// -----------------
3// Thanks to:
4// - https://github.com/documentcloud/backbone/blob/master/backbone.js
5// - https://github.com/joyent/node/blob/master/lib/events.js
6
7
8// Regular expression used to split event strings
91var eventSplitter = /\s+/
10
11
12// A module that can be mixed in to *any object* in order to provide it
13// with custom events. You may bind with `on` or remove with `off` callback
14// functions to an event; `trigger`-ing an event fires all callbacks in
15// succession.
16//
17// var object = new Events();
18// object.on('expand', function(){ alert('expanded'); });
19// object.trigger('expand');
20//
211function Events() {
22}
23
241module.exports = Events
25
26
27// Bind one or more space separated events, `events`, to a `callback`
28// function. Passing `"all"` will bind the callback to all events fired.
291Events.prototype.on = function(events, callback, context) {
3037 var cache, event, list
3138 if (!callback) return this
32
3336 cache = this.__events || (this.__events = {})
3436 events = events.split(eventSplitter)
35
3636 while (event = events.shift()) {
3748 list = cache[event] || (cache[event] = [])
3848 list.push(callback, context)
39 }
40
4136 return this
42}
43
44
45// Remove one or many callbacks. If `context` is null, removes all callbacks
46// with that function. If `callback` is null, removes all callbacks for the
47// event. If `events` is null, removes all bound callbacks for all events.
481Events.prototype.off = function(events, callback, context) {
4920 var cache, event, list, i
50
51 // No events, or removing *all* events.
5221 if (!(cache = this.__events)) return this
5319 if (!(events || callback || context)) {
543 delete this.__events
553 return this
56 }
57
5816 events = events ? events.split(eventSplitter) : Object.keys(cache)
59
60 // Loop through the callback list, splicing where appropriate.
6116 while (event = events.shift()) {
6221 list = cache[event]
6321 if (!list) continue
64
6521 if (!(callback || context)) {
666 delete cache[event]
676 continue
68 }
69
7015 for (i = list.length - 2; i >= 0; i -= 2) {
7127 if (!(callback && list[i] !== callback ||
72 context && list[i + 1] !== context)) {
7316 list.splice(i, 2)
74 }
75 }
76 }
77
7816 return this
79}
80
81
82// Trigger one or many events, firing all bound callbacks. Callbacks are
83// passed the same arguments as `trigger` is, apart from the event name
84// (unless you're listening on `"all"`, which will cause your callback to
85// receive the true name of the event as the first argument).
861Events.prototype.trigger = function(events) {
8735 var cache, event, all, list, i, len, rest = [], args
8836 if (!(cache = this.__events)) return this
89
9034 events = events.split(eventSplitter)
91
92 // Fill up `rest` with the callback arguments. Since we're only copying
93 // the tail of `arguments`, a loop is much faster than Array#slice.
9434 for (i = 1, len = arguments.length; i < len; i++) {
950 rest[i - 1] = arguments[i]
96 }
97
98 // For each event, walk through the list of callbacks twice, first to
99 // trigger the event, then to trigger any `"all"` callbacks.
10034 while (event = events.shift()) {
101 // Copy callback lists to prevent modification.
10253 if (all = cache.all) all = all.slice()
10382 if (list = cache[event]) list = list.slice()
104
105 // Execute event callbacks.
10645 if (list) {
10737 for (i = 0, len = list.length; i < len; i += 2) {
10838 list[i].apply(list[i + 1] || this, rest)
109 }
110 }
111
112 // Execute "all" callbacks.
11345 if (all) {
1148 args = [event].concat(rest)
1158 for (i = 0, len = all.length; i < len; i += 2) {
1168 all[i].apply(all[i + 1] || this, args)
117 }
118 }
119 }
120
12134 return this
122}
123
124
125// Mix `Events` to object instance or Class function.
1261Events.mixTo = function(receiver) {
1272 receiver = receiver.prototype || receiver
1282 var proto = Events.prototype
129
1302 for (var p in proto) {
1316 if (proto.hasOwnProperty(p)) {
1326 receiver[p] = proto[p]
133 }
134 }
135}