summaryrefslogtreecommitdiff
path: root/runtime/js/01_web_util.js
blob: 9b51021f9f78561832f0eaab5fe8bf1ec1ec7c98 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
"use strict";

((window) => {
  const {
    FunctionPrototypeCall,
    Map,
    MapPrototypeGet,
    MapPrototypeSet,
    ObjectDefineProperty,
    TypeError,
    Symbol,
  } = window.__bootstrap.primordials;
  const illegalConstructorKey = Symbol("illegalConstructorKey");

  function requiredArguments(
    name,
    length,
    required,
  ) {
    if (length < required) {
      const errMsg = `${name} requires at least ${required} argument${
        required === 1 ? "" : "s"
      }, but only ${length} present`;
      throw new TypeError(errMsg);
    }
  }

  const handlerSymbol = Symbol("eventHandlers");
  function makeWrappedHandler(handler, isSpecialErrorEventHandler) {
    function wrappedHandler(...args) {
      if (typeof wrappedHandler.handler !== "function") {
        return;
      }
      if (isSpecialErrorEventHandler) {
        const evt = args[0];
        if (evt instanceof ErrorEvent && evt.type === "error") {
          const ret = FunctionPrototypeCall(
            wrappedHandler.handler,
            this,
            evt.message,
            evt.filename,
            evt.lineno,
            evt.colno,
            evt.error,
          );
          if (ret === true) {
            evt.preventDefault();
          }
          return;
        }
      }

      return FunctionPrototypeCall(wrappedHandler.handler, this, ...args);
    }
    wrappedHandler.handler = handler;
    return wrappedHandler;
  }
  function defineEventHandler(
    emitter,
    name,
    defaultValue = undefined,
    isSpecialErrorEventHandler = false,
  ) {
    // HTML specification section 8.1.5.1
    ObjectDefineProperty(emitter, `on${name}`, {
      get() {
        if (!this[handlerSymbol]) {
          return defaultValue;
        }

        return MapPrototypeGet(this[handlerSymbol], name)?.handler ??
          defaultValue;
      },
      set(value) {
        if (!this[handlerSymbol]) {
          this[handlerSymbol] = new Map();
        }
        let handlerWrapper = MapPrototypeGet(this[handlerSymbol], name);
        if (handlerWrapper) {
          handlerWrapper.handler = value;
        } else {
          handlerWrapper = makeWrappedHandler(
            value,
            isSpecialErrorEventHandler,
          );
          this.addEventListener(name, handlerWrapper);
        }
        MapPrototypeSet(this[handlerSymbol], name, handlerWrapper);
      },
      configurable: true,
      enumerable: true,
    });
  }
  window.__bootstrap.webUtil = {
    illegalConstructorKey,
    requiredArguments,
    defineEventHandler,
  };
})(this);