UNPKG

14.7 kBJavaScriptView Raw
1
2
3
4!function(exports) {
5 "use strict";
6 var arrProto = Array.prototype
7 , getFns = Object.create(null)
8 , setFns = Object.create(null)
9 , filterFns = Object.create(null)
10 , escRe = /['\n\r\u2028\u2029]|\\(?!x2e)/g
11 , intRe = /^-?\d+$/
12 , pathRe = /(^$|.+?)(?:\[([^\]]*?)\])?(\.(?=[^.])|$)/g
13 , reEscRe = /[.+^=:${}()|\/\\]/g
14 , globRe = /[?*]|\[\w+\]/
15 , globReplace = /\?|(?=\*)/g
16 , globGroup = /\[!(?=.*\])/g
17 , primitiveRe = /^(-?(\d*\.)?\d+|true|false|null)$/
18 , valRe = /(["'])(\\?.)*?\1|(\w*)\{((["'])(?:\\?.)*?\5|\w*\{(?:(["'])(?:\\?.)*?\6|[^}])*?\}|.)*?\}|(@?)[^,]+/g
19 , filterRe = /(!?)(\$?)((?:[-+:.\/\w]+|\[[^\]]+?\])+)(\[])?(?:(!(?=\1)==?|(?=\1)[<>=]=?)((?:(["'])(?:\\?.)*?\7|\w*\{(?:(["'])(?:\\?.)*?\8|\w*\{(?:(["'])(?:\\?.)*?\9|[^}])*?\}|.)*?\}|[^|&()])+))?(?=[)|&]|$)|((&|\|)\11*|([()])|.)/g
20 , onlyFilterRe = RegExp("^(" + filterRe.source.slice(0, -10) + "))+$")
21 , cleanRe = /(\(o=d\)&&(?!.*o=o).*)\(o=d\)&&/g
22 , fns = {
23 "==": "e",
24 "===": "s",
25 ">": "g",
26 ">=": "ge",
27 "<": "l",
28 "<=": "le"
29 }
30 , equal = Fn("a->b->a==b")
31 , strictEqual = Fn("a->b->a===b")
32 , greater = Fn("a->b->a<b")
33 , greaterEqual = Fn("a->b->a<=b")
34 , less = Fn("a->b->a>b")
35 , lessEqual = Fn("a->b->a>=b")
36 , reMatch = Fn("a->b->typeof b==='string'&&a.test(b)")
37 , tmpDate = new Date()
38
39 exports.Item = Item
40 exports.List = List
41
42 Item.filterFn = filterFn
43 filterFn.re = filterRe
44 Item.copy = copy
45 Item.extend = List.extend = extend
46 Item.cache = {}
47 List.cache = {}
48
49 Item.get = function(obj, pointer) {
50 return pathFn(pointer)(obj)
51 }
52 Item.get.str = pathStr
53
54 Item.set = function(obj, pointer, value) {
55 return pathFn(pointer, true)(obj, value)
56 }
57
58 function escFn(str) {
59 return escape(str).replace(/%u/g, "\\u").replace(/%/g, "\\x")
60 }
61
62 function extend(a, b, c, d, e) {
63 var fn = this
64 , clone = Function("return " + fn.toString())()
65 , _super = fn.prototype
66 clone.prototype = Object.assign(
67 Array.isArray(_super) ? [] : Object.create(null),
68 _super, a, b, c, d, e, {_super: _super, constructor: clone}
69 )
70 clone.extend = extend
71 clone.cache = clone.prototype.cache || fn.cache
72 return clone
73 }
74
75 /* istanbul ignore next */
76 function Item(attrs, opts) {
77 var item = this
78 if (attrs instanceof Item) {
79 return attrs
80 }
81 if (!(item instanceof Item)) {
82 return Item.cache[attrs.id] || (Item.cache[attrs.id] = new Item(attrs, opts))
83 }
84 item.data = attrs
85 item.lists = []
86 if (item.init) {
87 item.init(attrs, opts)
88 }
89 item.set(attrs)
90 }
91
92 Item.prototype = {
93 constructor: Item,
94 set: function(key, val, opts) {
95 var item = this
96 , changed = []
97 , previous = {}
98 , data = key
99
100 if (typeof key !== "object") {
101 pathFn(key, true)(data = {}, val)
102 } else {
103 opts = val
104 }
105
106 if (item.validate(data, opts)) {
107 JSON.mergePatch(item.data, data, changed, previous)
108 }
109
110 if (changed.length) {
111 item.emit("change", changed, item, opts, previous)
112 changed.each(function(pointer, idx) {
113 item.emit("change:" + pointer, item.get(pointer), item, opts, previous[pointer])
114 })
115 }
116 return changed
117 },
118 get: function(name, fallback) {
119 var val = pathFn(name)(this.data)
120 return val == void 0 ? fallback : val
121 },
122 validate: returnTrue,
123 destroy: function(next) {
124 var item = this
125 , arr = item.lists.slice()
126 , len = arr.length
127
128 for (; len--; ) {
129 arr[len].remove(item)
130 }
131
132 item.emit("destroy")
133 item.off()
134 item.constructor.cache[item.get("id")] = null
135 //delete item.constructor.cache[item.get("id")]
136 },
137 matches: function(expr) {
138 return filterFn(expr)(this.data)
139 },
140 each: function(path, fn, scope) {
141 Object.each(this.get(path), fn, scope || this)
142 return this
143 },
144 then: _then,
145 toJSON: function(attrs) {
146 return Array.isArray(attrs) ? copy({}, this.data, attrs) : this.data
147 }
148 }
149 Event.asEmitter(Item.prototype)
150
151 /* istanbul ignore next */
152 function List(name, opts) {
153 var list = this
154 if (!(list instanceof List)) {
155 return List.cache[name] || (List.cache[name] = new List(name, opts))
156 }
157 list.name = name
158 if (list.init) {
159 list.init(name, opts)
160 }
161 list.on("newListener", function(type, fn, scope, origin) {
162 if (type.split(":")[0] === "change") {
163 list.eachLive(add, remove)
164 list.on("removeListener", off)
165 }
166 function add(item) {
167 item.on(type, fn, scope, origin)
168 }
169 function remove(item) {
170 item.off(type, fn, scope, origin)
171 }
172 function off(_type, _fn, _scope, _origin) {
173 if (_type === type && _fn == fn && _scope == scope && _origin == origin) {
174 list.each(remove).off("add", add).off("remove", remove)
175 list.off("removeListener", off)
176 }
177 }
178 })
179 }
180
181 Object.assign(List.prototype = [], Event.Emitter.prototype, {
182 item: Item,
183 wait: Fn.hold,
184 syncMethods: [
185 "add", "emit", "filterFn", "merge",
186 "item", "paged", "pluck", "remove", "removeAll", "sortFn"
187 ],
188 add: function(item) {
189 var pos
190 , list = this
191
192 if (item) {
193 if (item.constructor === Object) item = list.item(item)
194
195 if (item.lists.indexOf(list) == -1) {
196 pos = indexFor(list, item, list.sortFn)
197 if (list.filterFn(item, pos)) {
198 item.lists.push(list)
199 list.splice(pos , 0, item)
200 list.emit("add", item, pos)
201 }
202 }
203 }
204 return list
205 },
206 filterFn: returnTrue,
207 remove: function(item) {
208 var list = this
209 if (item && item.lists && item.lists.remove(list) > -1) {
210 list.emit("remove", item, arrProto.remove.call(list, item))
211 }
212 return list
213 },
214 removeAll: function(){
215 for (var list = this, len = list.length; len--; ) {
216 list.remove(list[len])
217 }
218 return list
219 },
220 each: function(fn, scope) {
221 arrProto.each.call(this, fn, scope || this)
222 return this
223 },
224 eachLive: function(start, stop, scope) {
225 this
226 .on("add", start, scope)
227 .on("remove", stop, scope)
228 .slice(0)
229 .each(start, scope)
230 return this
231 },
232 get: function(id, next, scope) {
233 var list = this
234 , item = list.item.cache[id]
235
236 if (item && item.lists.indexOf(list) != -1) {
237 return next ?
238 (next.call(scope || list, null, item), list) :
239 item
240 }
241
242 next && next.call(scope || list, Error("Item[#" + id + "] not found in " + list))
243 },
244 at: function(index, next, scope) {
245 var list = this
246 , item = list[index < 0 ? list.length + index : index]
247 , err = item ? null : Error("Item not found at " + index + " in " + list)
248
249 return next ?
250 (next.call(scope || list, err, item), list) :
251 item
252 },
253 then: _then,
254 pluck: function(field, next, scope) {
255 var list = this
256 , arr = arrProto.map.call(list, function(item) {
257 return item.get(field)
258 })
259 return next ?
260 (next.call(scope || list, arr), list) :
261 arr
262 },
263 set: function(key, val) {
264 this.each(function(item) {
265 item.set(key, val)
266 })
267 return this
268 },
269 merge: function(mergeList) {
270 var list = this
271 , lists = list.lists || (list.lists = [])
272
273 if (mergeList && lists.indexOf(mergeList) == -1) {
274 lists.push(mergeList)
275
276 mergeList
277 .eachLive(list.add, _remove, list)
278 .on("change", _change, list)
279 .then(list.wait())
280 }
281
282 return list
283 },
284 unmerge: function(mergedList) {
285 var list = this
286 , lists = list.lists
287 , idx = lists && lists.indexOf(mergedList)
288
289 if (lists && mergedList && idx != -1) {
290 lists.splice(idx, 1)
291
292 mergedList
293 .each(_remove, list)
294 .off("add", list.add, list)
295 .off("remove", _remove, list)
296 .off("change", _change, list)
297 }
298 return list
299 },
300 paged: function(num) {
301 var list = this
302 , view = new List()
303 , start = 0
304 , end = num
305
306 view.filterFn = function(item, pos) {
307 pos = list.indexOf(item)
308 return pos >= start && pos < end
309 }
310
311 view.pages = new List()
312 view.setPage = function(newPage) {
313 var lastPage = 0 | (list.length / num)
314 if (newPage > lastPage) {
315 newPage = lastPage
316 }
317 view.page = newPage
318 start = num * newPage
319 end = start + num
320 view.reFilter()
321 }
322
323 view.merge(list)
324
325 return view
326 },
327 reFilter: function() {
328 var list = this
329 , lists = list.lists || (list.lists = [])
330
331 lists.each(function(parent) {
332 parent.each(function(item) {
333 _change.call(list, null, item)
334 })
335 })
336 },
337 reSort: function(fn) {
338 var item
339 , list = this
340 , len = list.length
341 , removed = []
342
343 if (typeof fn === "string") {
344 fn = [fn]
345 }
346
347 if (Array.isArray(fn)) {
348 fn = Fn("a b->" + fn.map(function(key) {
349 return "(A=a.get('" + key + "'))<(B=b.get('" + key + "'))?-1:A>B?1:0"
350 }).join("||"))
351 }
352
353 fn = list.sortFn = fn || list.sortFn
354
355 for (; len > 1; ) {
356 item = list[--len - 1]
357 if (fn(item, list[len]) > 0) {
358 removed.push(item)
359 list.remove(item)
360 }
361 }
362 removed.each(list.add, list)
363 },
364 toJSON: function() {
365 return this.slice(0)
366 }
367 })
368
369 function _remove(item) {
370 if (item.lists.every(notIn, this.lists)) {
371 this.remove(item)
372 }
373 }
374
375 function _change(changed, item) {
376 var list = this
377 , matches = list.filterFn(item)
378 , inList = item.lists.indexOf(list) > -1
379
380 if (matches && !inList) {
381 list.add(item)
382 }
383 if (!matches && inList) {
384 list.remove(item)
385 }
386 }
387
388
389 function pathStr(str, set) {
390 return (
391 str.charAt(0) === "/" ?
392 str.slice(1).replace(/\./g, "\\x2e").replace(/\//g, ".").replace(/~1/g, "/").replace(/~0/g, "~") :
393 str
394 )
395 .replace(escRe, escFn)
396 .replace(pathRe, set === true ? pathSet : pathGet)
397
398 }
399 function pathGet(str, path, arr, dot) {
400 if (arr && !onlyFilterRe.test(arr)) throw Error("Invalid filter in GET")
401 var v = dot ? "(o=" : "(c="
402 return (
403 arr ? pathGet(0, path, 0, 1) + "i(o)&&" + v + (
404 intRe.test(arr) ? "o[" + (arr < 0 ? "o.length" + arr : arr) + "])" :
405 "F(o,f('" + arr + "')))"
406 ) :
407 v + "o['" + path + (arr === "" ? "'])&&i(c)&&c" : "'])")
408 ) + (dot ? "&&" : "")
409 }
410 function pathSet(str, path, _arr, dot) {
411 var op = "o['" + path + "']"
412 , arr = _arr || ""
413 if (arr) {
414 arr = "(o=i(o['" + path + "'])?o['" + path + "']:(o['" + path + "']=[]))&&"
415 if (intRe.test(_arr)) {
416 op = "o[" + (_arr < 0 ? "o.length" + _arr : _arr) + "]"
417 } else if (_arr === "-") {
418 op = "o[o.length]"
419 } else {
420 if (!onlyFilterRe.test(_arr)) throw Error("Invalid filter in SET")
421 op = "o[t]"
422 arr += "(t=F(o,f('" + _arr + "'),1))!=null&&"
423 }
424 }
425 return (dot ?
426 arr + "(o=typeof " + op + "==='object'&&" + op + "||(" + op + "={}))&&" :
427 arr + "((c=" + op + "),(" + op + "=v),c)"
428 )
429 }
430 function pathFn(str, set) {
431 var map = set === true ? setFns : getFns
432 return (
433 map[str] ||
434 (map[str] = Function("i,f,F", "return function(d,v){var c,o,t;return (o=d)&&" + pathStr(str, set) + "||c}")(
435 Array.isArray, filterFn, findFn
436 ))
437 )
438 }
439
440
441 function copy(a, b, attrs) {
442 var len = b && attrs && attrs.length
443 return len ? (
444 copy[len] ||
445 (copy[len] = Function("a,b,k,g", "var v,u;return " + Object.keys(attrs).map(copyFnI) + ",a"))
446 )(a, b, attrs, pathFn) : a
447 }
448
449 function copyFnI(i) {
450 return "(v=g(k[" + i + "])(b))!==u&&g(k[" + i + "],true)(a,v)"
451 }
452
453 function returnTrue() {
454 return true
455 }
456
457 function _then(next, scope) {
458 if (typeof next === "function") {
459 next.call(scope || this)
460 }
461 return this
462 }
463
464 function notIn(v) {
465 return this.indexOf(v) == -1
466 }
467
468 function indexFor(arr, el, compFn) {
469 var o
470 , i = 0
471 , l = arr.length
472
473 // Fast lookup for last position
474 if (compFn && l && compFn(el, arr[l-1]) < 1) {
475 // Otherwise binary search
476 for (; i < l; ) {
477 compFn(el, arr[o=(i+l)>>1]) < 0 ? l=o : i=o+1
478 }
479 }
480 return l
481 }
482
483 function findFn(a, fn, idx) {
484 for (var i = -1, len = a.length; ++i < len; ) {
485 if (fn(a[i])) return idx == null ? a[i] : i
486 }
487 return idx != null && len
488 }
489
490 function filterFn(str, prefix, opts, getter, tmp) {
491 var optimized
492 , arr = []
493 , key = (prefix || "") + filterStr(str, opts, arr, getter)
494 , fn = filterFns[key]
495 if (!fn) {
496 for (optimized = key; optimized != (optimized = optimized.replace(cleanRe, "$1")); );
497 fn = filterFns[key] = Function("a,i,f,p,e,s,g,ge,l,le,m,F,t", "return function(d){var o;return "+optimized+"}")
498 }
499 return fn(
500 arr, Array.isArray, filterFn, pathFn,
501 equal, strictEqual, greater, greaterEqual, less, lessEqual, reMatch, findFn, tmp
502 )
503 }
504 filterFn.str = filterStr
505 filterFn.valRe = valRe
506
507 // Date{day=1,2}
508 // Geo{distance=200km&lat=40&lon=-70}
509 // ?pos=Geo{distance=200km&lat=@lat&lon=@lon}
510 // [lon, lat] in The GeoJSON Format RFC 7946
511 // IP{net=127.0.0.1/30}
512 // var re = /^((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])(?:\.(?=.)|$)){4}$/
513 // ["1.2.3.4", "127.0.0.1", "192.175.255.254."].map(re.test, re)
514
515 filterFn.date = function filterDate(str) {
516 return filterFn(str, "(t.setTime(+d)>=0)&&", null, dateGetter, tmpDate)
517 }
518 function dateGetter(name) {
519 return "(t.get" + Date.fnMap[name] + ")"
520 }
521
522 function filterStr(qs, opts, arr, getter) {
523 return qs.replace(filterRe, worker).replace(/^[1&]&+|&+1?$/g, "") || "1"
524
525 function worker(all, not, isOption, attr, isArray, op, val, q1, q2, q3, ext, ok2, ok1) {
526 if (ext) {
527 if (!ok2 && !ok1) {
528 throw new Error("Invalid filter: " + qs)
529 }
530 return ok2 ? ok2 + ok2 : ok1
531 }
532 if (isOption) {
533 if (opts) opts[attr] = val
534 return "1"
535 }
536
537 var idd, m, v, isRe
538 , a = []
539 , pre = "(o=d)&&"
540 , not2 = op == "!=" || op == "!=="
541
542 attr = (getter || pathStr)(attr)
543
544 if (m = attr.match(/\(c=(.*?)\)$/)) {
545 if (m.index) pre += attr.slice(0, m.index)
546 attr = m[1]
547 }
548
549 if (not2) {
550 op = op.slice(1)
551 }
552
553 if (!op) {
554 return pre + (not ? "!" : "") + (isArray ? "i(" + attr + ")" : attr)
555 }
556 if (op == "=" || op == "==") op += "="
557 for (; m = valRe.exec(val); ) {
558 isRe = 0
559 idd = arr.indexOf(v =
560 m[1] || m[4] ? m[0].slice(m[3] ? m[3].length + 1 : 1, -1) :
561 m[7] ? m[0].slice(1) :
562 primitiveRe.test(m[0]) ? (
563 m[0] === "true" ? true :
564 m[0] === "false" ? false :
565 m[0] === "null" ? null :
566 +m[0]
567 ) :
568 (isRe = globRe.test(m[0])) ? RegExp(
569 "^" + m[0]
570 .replace(reEscRe, "\\$&")
571 .replace(globReplace, ".")
572 .replace(globGroup, "[^") + "$",
573 op === "==" ? "i" : ""
574 ) :
575 m[0]
576 )
577 v = "a[" + (idd > -1 ? idd : arr.push(v) - 1) + "]"
578 idd = m[3] ? 'f.' + m[3].toLowerCase() : m[4] ? "f" : isRe ? "m" : fns[op]
579 a.push(
580 isArray ? attr + ".some(" + idd + "(" + v + "))" :
581 isRe ? "typeof " + attr + "==='string'&&" + v + ".test(" + attr + ")" :
582 m[3] || m[4] ? idd + '(' + v + ")(" + attr + ")" :
583 m[7] ? attr + "!==void 0&&" + attr + op + "p(" + v + ")(o)" :
584 attr + op + v
585 )
586 }
587
588 return pre + (isArray ? (not2 ? "!i("+attr+")||" : "i("+attr+")&&") : "") + (not2 ? "!(" : "(") + a.join("||") + ")"
589 }
590 }
591}(this)
592
593
594