UNPKG

6.36 kBJavaScriptView Raw
1
2
3
4!function(exports, Object) {
5 var undef
6 , P = "prototype"
7 , A = Array[P]
8 , F = Function[P]
9 , S = String[P]
10 , N = Number[P]
11 , slice = F.call.bind(A.slice)
12 , fns = {}
13 , hasOwn = fns.hasOwnProperty
14 , fnRe = /('|")(?:\\?.)*?\1|\/(?:\\?.)+?\/[gim]*|\b(?:false|in|new|null|this|true|typeof|void)\b|\.\w+|\w+:/g
15 , formatRe = /{(?!\\)((?:("|')(?:\\?.)*?\2|[^}])*?)}/g
16 , numbersRe = /-?\d+\.?\d*/g
17 , wordRe = /\b[a-z_$][\w$]*/ig
18 , unescapeRe = /{\\/g
19
20
21 exports.Fn = Fn
22 Fn.hold = hold
23 Fn.wait = wait
24
25
26 // Function extensions
27 // -------------------
28
29 F.extend = function() {
30 var arg
31 , fn = this
32 , i = 0
33
34 function wrapper() {
35 return fn.apply(this, arguments)
36 }
37
38 for (wrapper[P] = Object.create(fn[P]); arg = arguments[i++]; ) {
39 JSON.merge(wrapper[P], arg)
40 }
41 wrapper[P].constructor = wrapper
42 return wrapper
43 }
44
45
46 // Non-standard
47 Object.each = function(obj, fn, scope, key) {
48 if (obj) for (key in obj) {
49 hasOwn.call(obj, key) && fn.call(scope, obj[key], key, obj)
50 }
51 }
52
53 Object.values = function(obj) {
54 return Object.keys(obj || {}).map(function(e) {
55 return obj[e]
56 })
57 }
58
59 // Non-standard
60 // IE<9 bug: [1,2].splice(0).join("") == "" but should be "12"
61 A.remove = arrayRemove
62 function arrayRemove() {
63 var arr = this
64 , len = arr.length
65 , o = slice(arguments)
66 , lastId = -1
67
68 for (; len--; ) if (~o.indexOf(arr[len])) {
69 arr.splice(lastId = len, 1)
70 }
71 return lastId
72 }
73
74 A.each = A.forEach
75 // uniq
76 // first item preserved
77 A.uniq = function() {
78 for (var a = this, i = a.length; i--; ) {
79 if (a.indexOf(a[i]) !== i) a.splice(i, 1)
80 }
81 return a
82 }
83
84 A.pushUniq = function(item) {
85 return this.indexOf(item) < 0 && this.push(item)
86 }
87
88 // THANKS: Oliver Steele - Functional Javascript [http://www.osteele.com/sources/javascript/functional/]
89 function Fn(expr /*, scope, mask1, ..maskN */) {
90 var args = []
91 , arr = expr.match(/[^"']+?->|.+$/g)
92 , scope = slice(arguments, 1)
93 , key = scope.length + ":" + expr
94 , fn = fns[key]
95
96 if (!fn) {
97 fn = expr.replace(fnRe, "").match(wordRe) || []
98 for (; arr.length > 1; ) {
99 expr = arr.pop()
100 args = arr.pop().match(/\w+/g) || []
101 arrayRemove.apply(fn, args)
102 if (arr.length) {
103 arr.push("function(" + args + "){return(" + expr + ")}" + (scope[0] ? ".bind(this)" : ""))
104 }
105 }
106 expr = "return(" + expr + ")"
107
108 if (scope[0]) {
109 arr = Object.keys(scope).map(Fn("a->'__'+a"))
110 arr[0] = "this"
111 expr = (
112 fn[0] ?
113 "var " + fn.uniq().join("='',") + "='';" :
114 ""
115 ) + "with(" + arr.join(")with(") + "){" + expr + "}"
116 args = arr.slice(1).concat(args)
117 }
118
119 fn = fns[key] = Function(args, expr)
120 }
121
122 return scope.length ? fn.bind.apply(fn, scope) : fn
123 }
124
125 Fn.keys = function(str) {
126 var i, tmp
127 , arr = []
128 , match = str.match(formatRe)
129 if (match) {
130 for (i = match.length; i--; ) {
131 if (tmp = match[i].replace(fnRe, "").match(wordRe)) {
132 arr.push.apply(arr, tmp)
133 }
134 }
135 }
136 return arr.uniq()
137 }
138
139 S.format = function() {
140 var args = A.slice.call(arguments)
141 args.unshift(0)
142 return this.replace(formatRe, function(_, arg) {
143 args[0] = arg
144 return Fn.apply(null, args)()
145 }).replace(unescapeRe, "{")
146 }
147
148 N.format = function(data) {
149 return "" + this
150 }
151
152 S.safe = function() {
153 return this
154 .replace(/&/g, "&amp;")
155 .replace(/</g, "&lt;")
156 .replace(/>/g, "&gt;")
157 .replace(/\"/g, "&quot;")
158 }
159
160 S.capitalize = function() {
161 return this.charAt(0).toUpperCase() + this.slice(1)
162 }
163
164 S.camelCase = function() {
165 return this.replace(/[ _-]+([a-z])/g, function(_, a) {
166 return a.toUpperCase()
167 })
168 }
169
170 S.lower = S.toLowerCase
171 S.upper = S.toUpperCase
172
173 N.step = function(a, add) {
174 var x = ("" + a).split(".")
175 , steps = this / a
176 , n = ~~(steps + ((steps < 0 ? -1 : 1) * (add == undef ? .5 : add === 1 && steps == (steps|0) ? 0 : +add))) * a
177 return "" + (1 in x ? n.toFixed(x[1].length) : n)
178 }
179
180 S.step = function(a, add) {
181 return this.replace(numbersRe, function(num) {
182 return (+num).step(a, add)
183 })
184 }
185
186 N.scale = words([1000, 1000, 1000], ["","k","M","G"], {"default": "{n}{u}"})
187
188 S.scale = function() {
189 return this.replace(numbersRe, function(num) {
190 return (+num).scale()
191 })
192 }
193
194 S.pick = N.pick = function() {
195 var val = this + "="
196 for (var s, a = arguments, i = 0, len = a.length; i < len;) {
197 s = a[i++]
198 if (s.indexOf(val) == 0) {
199 s = s.slice(val.length)
200 i = len
201 }
202 }
203 return s.replace("#", this)
204 }
205
206 S.plural = N.plural = function() {
207 // Plural-Forms: nplurals=2; plural=n != 1;
208 // http://www.gnu.org/software/gettext/manual/html_mono/gettext.html#Plural-forms
209 return arguments[ +Fn("n->" + (String.plural || "n!=1"))( parseFloat(this) ) ].replace("#", this)
210 }
211
212 A.pluck = function(name) {
213 for (var arr = this, i = arr.length, out = []; i--; ) {
214 out[i] = arr[i][name]
215 }
216 return out
217 }
218
219 function words(steps, units, strings, overflow) {
220 return function(input) {
221 var n = +(arguments.length ? input : this)
222 , i = 0
223 , s = strings || {"default": "{n} {u}{s}"}
224
225 for (; n>=steps[i]; ) {
226 n /= steps[i++]
227 }
228 if (i == steps.length && overflow) {
229 return overflow(this)
230 }
231 i = units[i]
232 return (s[n < 2 ? i : i + "s"] || s["default"]).format({n: n, u: i, s: n < 2 ? "" : "s"})
233 }
234 }
235 Fn.words = words
236
237 function wait(fn) {
238 var pending = 1
239 function resume() {
240 if (!--pending && fn) fn.call(this)
241 }
242 resume.wait = function() {
243 pending++
244 return resume
245 }
246 return resume
247 }
248
249 function hold(ignore) {
250 var k
251 , obj = this
252 , hooks = []
253 , hooked = []
254 , _resume = wait(resume)
255 ignore = ignore || obj.syncMethods || []
256
257 for (k in obj) if (typeof obj[k] == "function" && ignore.indexOf(k) == -1) !function(k) {
258 hooked.push(k, hasOwn.call(obj, k) && obj[k])
259 obj[k] = function() {
260 hooks.push(k, arguments)
261 return obj
262 }
263 }(k)
264
265 /**
266 * `wait` is already in hooked array,
267 * so override hooked method
268 * that will be cleared on resume.
269 */
270 obj.wait = _resume.wait
271
272 return _resume
273
274 function resume() {
275 for (var v, scope = obj, i = hooked.length; i--; i--) {
276 if (hooked[i]) obj[hooked[i-1]] = hooked[i]
277 else delete obj[hooked[i-1]]
278 }
279 // i == -1 from previous loop
280 for (; v = hooks[++i]; ) {
281 scope = scope[v].apply(scope, hooks[++i]) || scope
282 }
283 hooks = hooked = null
284 }
285 }
286
287}(this, Object)
288
289
290