proxy.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /* Copyright 2020 Mozilla Foundation
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. class ProxyHandler {
  16. constructor() {
  17. // Don't dispatch an event for those properties.
  18. // - delay: allow to delay field redraw until delay is set to false.
  19. // Likely it's useless to implement that stuff.
  20. this.nosend = new Set(["delay"]);
  21. }
  22. get(obj, prop) {
  23. // script may add some properties to the object
  24. if (prop in obj._expandos) {
  25. const val = obj._expandos[prop];
  26. if (typeof val === "function") {
  27. return val.bind(obj);
  28. }
  29. return val;
  30. }
  31. if (typeof prop === "string" && !prop.startsWith("_") && prop in obj) {
  32. // return only public properties
  33. // i.e. the ones not starting with a '_'
  34. const val = obj[prop];
  35. if (typeof val === "function") {
  36. return val.bind(obj);
  37. }
  38. return val;
  39. }
  40. return undefined;
  41. }
  42. set(obj, prop, value) {
  43. if (obj._kidIds) {
  44. // If the field is a container for other fields then
  45. // dispatch the kids.
  46. obj._kidIds.forEach(id => {
  47. obj._appObjects[id].wrapped[prop] = value;
  48. });
  49. }
  50. if (typeof prop === "string" && !prop.startsWith("_") && prop in obj) {
  51. const old = obj[prop];
  52. obj[prop] = value;
  53. if (
  54. !this.nosend.has(prop) &&
  55. obj._send &&
  56. obj._id !== null &&
  57. typeof old !== "function"
  58. ) {
  59. const data = { id: obj._id };
  60. data[prop] = obj[prop];
  61. // send the updated value to the other side
  62. if (!obj._siblings) {
  63. obj._send(data);
  64. } else {
  65. data.siblings = obj._siblings;
  66. obj._send(data);
  67. }
  68. }
  69. } else {
  70. obj._expandos[prop] = value;
  71. }
  72. return true;
  73. }
  74. has(obj, prop) {
  75. return (
  76. prop in obj._expandos ||
  77. (typeof prop === "string" && !prop.startsWith("_") && prop in obj)
  78. );
  79. }
  80. getPrototypeOf(obj) {
  81. return null;
  82. }
  83. setPrototypeOf(obj, proto) {
  84. return false;
  85. }
  86. isExtensible(obj) {
  87. return true;
  88. }
  89. preventExtensions(obj) {
  90. return false;
  91. }
  92. getOwnPropertyDescriptor(obj, prop) {
  93. if (prop in obj._expandos) {
  94. return {
  95. configurable: true,
  96. enumerable: true,
  97. value: obj._expandos[prop],
  98. };
  99. }
  100. if (typeof prop === "string" && !prop.startsWith("_") && prop in obj) {
  101. return { configurable: true, enumerable: true, value: obj[prop] };
  102. }
  103. return undefined;
  104. }
  105. defineProperty(obj, key, descriptor) {
  106. Object.defineProperty(obj._expandos, key, descriptor);
  107. return true;
  108. }
  109. deleteProperty(obj, prop) {
  110. if (prop in obj._expandos) {
  111. delete obj._expandos[prop];
  112. }
  113. }
  114. ownKeys(obj) {
  115. const fromExpandos = Reflect.ownKeys(obj._expandos);
  116. const fromObj = Reflect.ownKeys(obj).filter(k => !k.startsWith("_"));
  117. return fromExpandos.concat(fromObj);
  118. }
  119. }
  120. export { ProxyHandler };