|
263 | 263 | merge.able = o => isArr(o) || |
264 | 264 | (o != null && typeof o === 'object' && !isFunc(o.then)) |
265 | 265 |
|
| 266 | + const emitter = (host = Object.create(null), listeners = new Map()) => Object.assign(host, { |
| 267 | + emit: infinify((event, ...data) => exports.runAsync(() => { |
| 268 | + if (listeners.has(event)) { |
| 269 | + for (const h of listeners.get(event)) h.apply(null, data) |
| 270 | + } |
| 271 | + })), |
| 272 | + on: infinify((event, handler) => { |
| 273 | + if (!listeners.has(event)) listeners.set(event, new Set()) |
| 274 | + listeners.get(event).add(handler) |
| 275 | + const manager = () => host.off(event, handler) |
| 276 | + manager.off = manager |
| 277 | + manager.on = () => { |
| 278 | + manager() |
| 279 | + return host.on(event, handler) |
| 280 | + } |
| 281 | + manager.once = () => { |
| 282 | + manager() |
| 283 | + return host.once(event, handler) |
| 284 | + } |
| 285 | + return manager |
| 286 | + }), |
| 287 | + once: infinify((event, handler) => host.on(event, function h () { |
| 288 | + handler(...arguments) |
| 289 | + host.off(event, h) |
| 290 | + })), |
| 291 | + off: infinify((event, handler) => { |
| 292 | + if (listeners.has(event)) { |
| 293 | + const ls = listeners.get(event) |
| 294 | + ls.delete(handler) |
| 295 | + if (!ls.size) listeners.delete(event) |
| 296 | + } |
| 297 | + }) |
| 298 | + }) |
| 299 | + |
266 | 300 | /* global Node NodeList */ |
267 | 301 |
|
268 | 302 | const listen = function (once, target, type, fn, options = false) { |
|
520 | 554 | } |
521 | 555 |
|
522 | 556 | if (bind) { |
| 557 | + const isinput = isInput(el) |
523 | 558 | for (const key in bind) { |
524 | 559 | if (key in el) throw new Error('databind overwrites property') |
525 | | - const b = databind(bind[key], el) |
526 | | - Object.defineProperty(bind, key, { get () { return b.ops.val }, set: b }) |
527 | | - Object.defineProperty(bind, '$' + key, { value: b }) |
| 560 | + bind[key].host = proxied || el |
| 561 | + bind[key].isinput = isinput |
| 562 | + const b = databind(bind[key]) |
| 563 | + Object.defineProperty(bind, key, { |
| 564 | + get () { return b.val }, |
| 565 | + set: b.change |
| 566 | + }) |
| 567 | + Object.defineProperty(bind, '$' + key, { |
| 568 | + value: b |
| 569 | + }) |
528 | 570 | } |
529 | 571 | el.bind = bind |
530 | 572 | } |
|
885 | 927 | } |
886 | 928 | domfn.empty = domfn.clear |
887 | 929 |
|
888 | | - const databind = (ops, host) => { |
889 | | - if (!ops) ops = {} |
890 | | - const change = (newval, force, silent) => { |
891 | | - if (newval == null) return ops.val |
892 | | - if (isFunc(newval)) newval = newval(ops.val, ops) |
893 | | - if (force || (newval !== ops.val)) { |
894 | | - ops.old = ops.val |
895 | | - ops.val = newval |
896 | | - if (ops.change) { |
897 | | - const res = ops.change(ops.val, ops) |
898 | | - if (res != null && ops.val !== res) ops.val = res |
899 | | - } |
900 | | - if (!silent) { |
901 | | - change.observers.forEach(o => { |
902 | | - o(o.key != null ? view[o.key](ops.val, ops) : ops.val, ops) |
903 | | - }) |
904 | | - } |
905 | | - if (ops.key && ops.host) { |
906 | | - ops.host[ops.key] = ops.view ? ops.view(ops.val, ops) : ops.val |
| 930 | + const databind = ops => { |
| 931 | + const core = emitter() |
| 932 | + core.ops = ops |
| 933 | + core.host = ops.host |
| 934 | + core.val = ops.val != null ? ops.val : '' |
| 935 | + delete ops.val |
| 936 | + core.change = val => { |
| 937 | + if (val === core.val) return |
| 938 | + if (core.ops.change) { |
| 939 | + const out = core.ops.change(val, core) |
| 940 | + if (out != null && out !== val) val = out |
| 941 | + } |
| 942 | + core.emit.change(core.val = val) |
| 943 | + if (core.ops.views) { |
| 944 | + for (const name in core.ops.views) { |
| 945 | + const out = core.ops.views[name](val, core) |
| 946 | + if (out != null) core.emit[name](out, core) |
907 | 947 | } |
908 | 948 | } |
909 | | - return change |
910 | 949 | } |
911 | | - change.change = change |
912 | | - change.ops = ops |
913 | | - change.observers = new Set() |
914 | | - change.observe = infinify((key, fn) => { |
915 | | - if (isFunc(key)) [fn, key] = [key, null] |
916 | | - if (key) fn.key = key |
917 | | - const off = () => { |
918 | | - change.observers.delete(fn) |
919 | | - return off |
| 950 | + |
| 951 | + core.view = infinify((key, fn) => { |
| 952 | + if (key in core.ops.views) { |
| 953 | + return fn ? fn(core.ops.views[key](core.val, core), core) : core.ops.views[key](core.val, core) |
920 | 954 | } |
921 | | - return ((off.off = off).on = () => { |
922 | | - change.observers.add(fn) |
923 | | - return off |
924 | | - })() |
925 | | - }) |
926 | | - const view = change.view = infinify((key, fn) => { |
927 | | - if (key in view) return fn ? fn(view[key](ops.val, ops), ops) : view[key](ops.val, ops) |
928 | | - if (key === 'view') return fn ? fn(ops.view(ops.val, ops), ops) : ops.view(ops.val, ops) |
929 | | - if (key === '') return fn ? fn(ops.val, ops) : ops.val |
930 | | - view[key] = fn |
| 955 | + if (!isFunc(fn)) throw new TypeError('databind view needs function') |
| 956 | + core.ops.views[key] = fn |
931 | 957 | }) |
932 | | - if (ops.views) for (const key in ops.views) view(key, ops.views[key]) |
933 | | - ops.$change = change |
934 | | - change.stop = ops.$stop = () => { |
935 | | - if (ops.isinput) ops.inputUpdaters.off() |
936 | | - if (ops.stop) ops.stop(ops.host, ops) |
937 | | - change.observers.clear() |
938 | | - } |
939 | | - change.text = (host, fn) => { |
940 | | - const text$$1 = new Text() |
941 | | - if (isStr(host)) { |
942 | | - text$$1.off = change.observe(host, val => { text$$1.textContent = val }) |
943 | | - } else { |
944 | | - text$$1.off = change.observe(val => { |
945 | | - text$$1.textContent = ops.view ? ops.view(ops.val, ops) : ops.val |
946 | | - }) |
| 958 | + |
| 959 | + core.stop = () => { |
| 960 | + for (const bind of core.binds) { |
| 961 | + bind.off() |
| 962 | + if (bind.inputUpdaters) bind.inputUpdaters.off() |
947 | 963 | } |
948 | | - if (isFunc(fn)) fn(text$$1, ops) |
949 | | - return text$$1 |
| 964 | + core.bind = core.change = null |
950 | 965 | } |
951 | 966 |
|
952 | | - if (host) { |
953 | | - ops.host = host |
954 | | - if (isEl(host) || isProxyNode(host)) { |
955 | | - if (isInput(host)) { |
956 | | - ops.isinput = true |
957 | | - ops.host = $(host) |
958 | | - const inputUpdate = e => change(host.value) |
959 | | - ops.inputUpdaters = ops.host.on({ |
960 | | - input: inputUpdate, |
961 | | - keyup: inputUpdate, |
962 | | - blur: inputUpdate, |
963 | | - focus: inputUpdate |
964 | | - }) |
| 967 | + core.binds = new Set() |
| 968 | + core.bind = new Proxy((host, key, view) => { |
| 969 | + if (isStr(key) && key.includes(':')) [view, key] = key.split(':') |
| 970 | + if (isInput(host)) { |
| 971 | + [view, key] = [key, 'value'] |
| 972 | + const inputUpdate = e => { |
| 973 | + core.change(host[key]) |
965 | 974 | } |
| 975 | + var inputUpdaters = ops.host.on({ |
| 976 | + input: inputUpdate, |
| 977 | + keyup: inputUpdate, |
| 978 | + blur: inputUpdate, |
| 979 | + focus: inputUpdate |
| 980 | + }) |
966 | 981 | } |
967 | | - if (ops.init) ops.init(host, ops) |
968 | | - if ('val' in ops) change(ops.val, true) |
969 | | - } |
970 | | - return change |
| 982 | + const handle = core.on[isStr(view) ? view : 'change'](val => { |
| 983 | + if (host[key] !== val) host[key] = val |
| 984 | + }) |
| 985 | + if (inputUpdaters) handle.inputUpdaters = inputUpdaters |
| 986 | + host[key] = isStr(view) ? core.view(view) : core.val |
| 987 | + core.binds.add(handle) |
| 988 | + return handle |
| 989 | + }, { |
| 990 | + get (_, key) { |
| 991 | + if (key in core) return Reflect.get(core, key) |
| 992 | + if (key in core.ops.views) return core.ops.views[key](core.val, core) |
| 993 | + }, |
| 994 | + set (_, key, val) { |
| 995 | + if (key === 'change') core.ops.change = val |
| 996 | + else if (key === 'val') core.val = val |
| 997 | + else Reflect.set(core, key, val) |
| 998 | + return true |
| 999 | + } |
| 1000 | + }) |
| 1001 | + |
| 1002 | + if (core.ops.host) core.bind(core.ops.host, core.ops.key) |
| 1003 | + |
| 1004 | + return core |
971 | 1005 | } |
972 | 1006 |
|
973 | 1007 | /* global Node Element */ |
|
1290 | 1324 |
|
1291 | 1325 | if (!Created(el)) { |
1292 | 1326 | if (bind) { |
| 1327 | + const isinput = isInput(el) |
1293 | 1328 | for (const key in bind) { |
1294 | | - const b = databind(bind[key], proxied) |
1295 | | - Object.defineProperty(el, key, { get () { return b.ops.val }, set: b }) |
| 1329 | + bind[key].host = proxied |
| 1330 | + bind[key].isinput = isinput |
| 1331 | + const b = databind(bind[key]) |
| 1332 | + Object.defineProperty(el, key, { get () { return b.val }, set: b.change }) |
1296 | 1333 | Object.defineProperty(el, '$' + key, { value: b }) |
1297 | 1334 | } |
1298 | 1335 | } |
|
1400 | 1437 | exports.component = component |
1401 | 1438 | exports.componentReady = componentReady |
1402 | 1439 | exports.databind = databind |
| 1440 | + exports.emitter = emitter |
1403 | 1441 | exports.run = run |
1404 | 1442 | exports.render = render |
1405 | 1443 | exports.query = query |
|
0 commit comments