UNPKG

15.2 kBJavaScriptView Raw
1
2
3
4!function(exports, Object) {
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 , pathRe = /(^$|.+?)(?:\[([^\]]*)\]|\{([^}]*)})?(\.(?=[^.])|$)/g
12 , reEscRe = /[.+^=:${}()|\/\\]/g
13 , globRe = /[?*]|\[\w+\]/
14 , globReplace = /\?|(?=\*)/g
15 , globGroup = /\[!(?=.*\])/g
16 , primitiveRe = /^(-?(\d*\.)?\d+|true|false|null)$/
17 , valRe = /("|')(\\?.)*?\1|(\w*)\{(("|')(?:\\?.)*?\5|\w*\{(?:("|')(?:\\?.)*?\6|[^}])*?\}|.)*?\}|(@?)[^,]+/g
18 , filterRe = /(!?)(\$?)((?:[-+:.\/\w]+|\[[^\]]+\]|\{[^}]+})+)(\[]|\{}|)(?:(!(?=\1)==?|(?=\1)[<>=]=?)((?:("|')(?:\\?.)*?\7|\w*\{(?:("|')(?:\\?.)*?\8|\w*\{(?:("|')(?:\\?.)*?\9|[^}])*?\}|.)*?\}|[^|&()])*))?(?=[)|&]|$)|((&|\|)\11*|([()])|.)/g
19 , onlyFilterRe = RegExp("^(" + filterRe.source.slice(0, -10) + "))+$")
20 , cleanRe = /(\(o=d\)&&(?!.*o=o).*)\(o=d\)&&/g
21 , fns = {
22 "==": "e",
23 "===": "s",
24 ">": "g",
25 ">=": "ge",
26 "<": "l",
27 "<=": "le"
28 }
29 , equal = Fn("a->b->a==b")
30 , strictEqual = Fn("a->b->a===b")
31 , greater = Fn("a->b->a<b")
32 , greaterEqual = Fn("a->b->a<=b")
33 , less = Fn("a->b->a>b")
34 , lessEqual = Fn("a->b->a>=b")
35 , reMatch = Fn("a->b->typeof b==='string'&&a.test(b)")
36 , tmpDate = new Date()
37 , isArray = Array.isArray
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 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 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, true)
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), false)
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 (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 function pathStr(str, set) {
389 return (
390 str.charAt(0) === "/" ?
391 str.slice(1).replace(/\./g, "\\x2e").replace(/\//g, ".").replace(/~1/g, "/").replace(/~0/g, "~") :
392 str
393 )
394 .replace(escRe, escFn)
395 .replace(pathRe, set === true ? pathSet : pathGet)
396 }
397
398 function pathGet(str, path, arr, obj, dot) {
399 var v = dot ? "(o=" : "(c="
400 , sub = arr || obj
401 if (sub && !onlyFilterRe.test(sub)) throw Error("Invalid filter in GET")
402 return (
403 sub ?
404 pathGet(0, path, 0, 0, 1) + (arr ? "i" : "j") + "(o)&&" + v + (
405 +arr == arr ? "o[" + (arr < 0 ? "o.length" + arr : arr) + "])" :
406 (arr ? "I" : "J") + "(o,f('" + sub + "')))"
407 ) :
408 v + "o['" + path + (
409 arr === "" ? "'])&&i(c)&&c" :
410 sub === "" ? "'])&&j(c)&&c" :
411 "'])"
412 )
413 ) + (dot ? "&&" : "")
414 }
415
416 function pathSet(str, path, arr, obj, dot) {
417 var op = "o['" + path + "']"
418 , out = ""
419 , sub = arr || obj
420 if (sub) {
421 out = "(o="+(arr?"i":"j")+"(o['" + path + "'])?o['" + path + "']:(o['" + path + "']="+(arr?"[]":"{}")+"))&&"
422 if (arr === "-") {
423 op = "o[o.length]"
424 } else if (+arr == arr) {
425 op = "o[" + (arr < 0 ? "o.length" + arr : arr) + "]"
426 } else {
427 if (!onlyFilterRe.test(arr)) throw Error("Invalid filter in SET")
428 op = "o[t]"
429 out += "(t="+(arr?"I":"J")+"(o,f('" + sub + "'),1))!=null&&"
430 }
431 }
432 return out + (dot ?
433 "(o=typeof " + op + "==='object'&&" + op + "||(" + op + "={}))&&" :
434 "((c=" + op + "),(" + op + "=v),c)"
435 )
436 }
437
438 function pathFn(str, set) {
439 var map = set === true ? setFns : getFns
440 return (
441 map[str] ||
442 (map[str] = Function("i,j,I,J,f", "return function(d,v){var c,o,t;return (o=d)&&" + pathStr(str, set) + "||c}")(
443 isArray, isObject, inArray, inObject, filterFn
444 ))
445 )
446 }
447
448 function copy(a, b, attrs) {
449 var len = b && attrs && attrs.length
450 return len ? (
451 copy[len] ||
452 (copy[len] = Function("a,b,k,g", "var v,u;return " + Object.keys(attrs).map(copyFnI) + ",a"))
453 )(a, b, attrs, pathFn) : a
454 }
455
456 function copyFnI(i) {
457 return "(v=g(k[" + i + "])(b))!==u&&g(k[" + i + "],true)(a,v)"
458 }
459
460 function returnTrue() {
461 return true
462 }
463
464 function _then(next, scope) {
465 if (typeof next === "function") {
466 next.call(scope || this)
467 }
468 return this
469 }
470
471 function notIn(v) {
472 return this.indexOf(v) == -1
473 }
474
475 function indexFor(arr, el, compFn) {
476 var o
477 , i = 0
478 , l = arr.length
479
480 // Fast lookup for last position
481 if (compFn && l && compFn(el, arr[l-1]) < 1) {
482 // Otherwise binary search
483 for (; i < l; ) {
484 compFn(el, arr[o=(i+l)>>1]) < 0 ? l=o : i=o+1
485 }
486 }
487 return l
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(
498 "a,i,j,I,J,f,p,e,s,g,ge,l,le,m,t",
499 "return function(d){var o;return " + optimized + "}"
500 )
501 }
502 return fn(
503 arr, isArray, isObject, inArray, inObject, filterFn, pathFn,
504 equal, strictEqual, greater, greaterEqual, less, lessEqual, reMatch, tmp
505 )
506 }
507 filterFn.str = filterStr
508 filterFn.valRe = valRe
509
510 // Date{day=1,2}
511 // sliceable[start:stop:step]
512 // Geo{distance=200km&lat=40&lon=-70}
513 // ?pos=Geo{distance=200km&lat=@lat&lon=@lon}
514 // [lon, lat] in The GeoJSON Format RFC 7946
515 // IP{net=127.0.0.1/30}
516 // var re = /^((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])(?:\.(?=.)|$)){4}$/
517 // ["1.2.3.4", "127.0.0.1", "192.175.255.254."].map(re.test, re)
518
519 filterFn.date = function filterDate(str) {
520 return filterFn(str, "(t.setTime(+d)>=0)&&", null, dateGetter, tmpDate)
521 }
522
523 function dateGetter(name) {
524 return "(t.get" + Date.fnMap[name] + ")"
525 }
526
527 function filterStr(qs, opts, arr, getter) {
528 return qs.replace(filterRe, worker).replace(/^[1&]&+|&+1?$/g, "") || "1"
529
530 function worker(all, not, isOption, attr, isArray, op, val, q1, q2, q3, ext, ok2, ok1) {
531 if (ext) {
532 if (!ok2 && !ok1) {
533 throw new Error("Invalid filter: " + qs)
534 }
535 return ok2 ? ok2 + ok2 : ok1
536 }
537 if (isOption) {
538 if (opts) opts[attr] = val
539 return "1"
540 }
541
542 var idd, m, v, isRe
543 , a = []
544 , pre = "(o=d)&&"
545
546 attr = (getter || pathStr)(attr)
547
548 if (m = attr.match(/\(c=(.*?)\)$/)) {
549 if (m.index) pre += attr.slice(0, m.index)
550 attr = m[1]
551 }
552
553 if (op == "!=" || op == "!==") {
554 not = "!"
555 op = op.slice(1)
556 }
557 if (isArray) {
558 pre += not + (isArray === "[]" ? "i(" : "j(") + attr + ")"
559 }
560
561 if (!op) {
562 return isArray === "" ? pre + not + attr : pre
563 }
564
565 if (op == "=" || op == "==") op += "="
566 if (val === "") val="''"
567 for (; m = valRe.exec(val); ) {
568 isRe = 0
569 idd = arr.indexOf(v =
570 m[1] || m[4] ? m[0].slice(m[3] ? m[3].length + 1 : 1, -1) :
571 m[7] ? m[0].slice(1) :
572 primitiveRe.test(m[0]) ? JSON.parse(m[0]) :
573 (isRe = globRe.test(m[0])) ? RegExp(
574 "^" + m[0]
575 .replace(reEscRe, "\\$&")
576 .replace(globReplace, ".")
577 .replace(globGroup, "[^") + "$",
578 op === "==" ? "i" : ""
579 ) :
580 m[0]
581 )
582 v = "a[" + (idd > -1 ? idd : arr.push(v) - 1) + "]"
583 idd = m[3] ? 'f.' + m[3].toLowerCase() : m[4] ? "f" : isRe ? "m" : fns[op]
584 a.push(
585 isArray ? (isArray === "[]" ? "I(" : "J(") + attr + "," + idd + "(" + v + "))" :
586 isRe ? "typeof " + attr + "==='string'&&" + v + ".test(" + attr + ")" :
587 m[3] || m[4] ? idd + '(' + v + ")(" + attr + ")" :
588 m[7] ? attr + "!==void 0&&" + attr + op + "p(" + v + ")(o)" :
589 attr + op + v
590 )
591 }
592
593 return pre + (
594 isArray ? (not ? "||" : "&&") : ""
595 ) + not + "(" + a.join("||") + ")"
596 }
597 }
598
599 function isObject(obj) {
600 return obj != null && obj.constructor === Object
601 }
602
603 function inArray(a, fn, idx) {
604 for (var i = -1, len = a.length; ++i < len; ) {
605 if (fn(a[i])) return idx == null ? a[i] : i
606 }
607 return idx != null && len
608 }
609
610 function inObject(o, fn, idx) {
611 for (var key in o) {
612 if (fn(o[key])) return idx == null ? o[key] : key
613 }
614 return null
615 }
616}(this, Object)
617
618
619