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