Нет описания

scope.js 2.9KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. export function scope(node) {
  2. return mergeProxies(closestDataStack(node))
  3. }
  4. export function addScopeToNode(node, data, referenceNode) {
  5. node._x_dataStack = [data, ...closestDataStack(referenceNode || node)]
  6. return () => {
  7. node._x_dataStack = node._x_dataStack.filter(i => i !== data)
  8. }
  9. }
  10. export function hasScope(node) {
  11. return !! node._x_dataStack
  12. }
  13. export function closestDataStack(node) {
  14. if (node._x_dataStack) return node._x_dataStack
  15. if (typeof ShadowRoot === 'function' && node instanceof ShadowRoot) {
  16. return closestDataStack(node.host)
  17. }
  18. if (! node.parentNode) {
  19. return []
  20. }
  21. return closestDataStack(node.parentNode)
  22. }
  23. export function closestDataProxy(el) {
  24. return mergeProxies(closestDataStack(el))
  25. }
  26. export function mergeProxies(objects) {
  27. let thisProxy = new Proxy({}, {
  28. ownKeys: () => {
  29. return Array.from(new Set(objects.flatMap(i => Object.keys(i))))
  30. },
  31. has: (target, name) => {
  32. return objects.some(obj => obj.hasOwnProperty(name))
  33. },
  34. get: (target, name) => {
  35. return (objects.find(obj => {
  36. if (obj.hasOwnProperty(name)) {
  37. let descriptor = Object.getOwnPropertyDescriptor(obj, name)
  38. // If we already bound this getter, don't rebind.
  39. if ((descriptor.get && descriptor.get._x_alreadyBound) || (descriptor.set && descriptor.set._x_alreadyBound)) {
  40. return true
  41. }
  42. // Properly bind getters and setters to this wrapper Proxy.
  43. if ((descriptor.get || descriptor.set) && descriptor.enumerable) {
  44. // Only bind user-defined getters, not our magic properties.
  45. let getter = descriptor.get
  46. let setter = descriptor.set
  47. let property = descriptor
  48. getter = getter && getter.bind(thisProxy)
  49. setter = setter && setter.bind(thisProxy)
  50. if (getter) getter._x_alreadyBound = true
  51. if (setter) setter._x_alreadyBound = true
  52. Object.defineProperty(obj, name, {
  53. ...property,
  54. get: getter,
  55. set: setter,
  56. })
  57. }
  58. return true
  59. }
  60. return false
  61. }) || {})[name]
  62. },
  63. set: (target, name, value) => {
  64. let closestObjectWithKey = objects.find(obj => obj.hasOwnProperty(name))
  65. if (closestObjectWithKey) {
  66. closestObjectWithKey[name] = value
  67. } else {
  68. objects[objects.length - 1][name] = value
  69. }
  70. return true
  71. },
  72. })
  73. return thisProxy
  74. }