chromium/extensions/renderer/resources/guest_view/guest_view_deny.js

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This module implements the registration of guestview elements when
// permissions are not available. These elements exist only to provide a useful
// error message when developers attempt to use them.

var $CustomElementRegistry =
    require('safeMethods').SafeMethods.$CustomElementRegistry;
var $EventTarget = require('safeMethods').SafeMethods.$EventTarget;
var GuestViewInternalNatives = requireNative('guest_view_internal');

// Once the document has loaded, expose the error-providing element's
// constructor to user code via |window|.
// GuestView elements used to be defined only once the document had loaded (see
// https://crbug.com/810012). This has been fixed, but as seen in
// https://crbug.com/1014385, user code that does not have permission for a
// GuestView could be using the same name for another purpose. In order to avoid
// potential name collisions with user code, we preserve the previous
// asynchronous behaviour for exposing the constructor of the error-providing
// element via |window|.
function asyncProvideElementConstructor(viewType, elementConstructor) {
  let useCapture = true;
  window.addEventListener('readystatechange', function listener(event) {
    if (document.readyState == 'loading')
      return;

    // If user code did use the name, we won't overwrite with the
    // error-providing element.
    if (!$Object.hasOwnProperty(window, viewType)) {
      $Object.defineProperty(window, viewType, {
        value: elementConstructor,
      });
    }

    $EventTarget.removeEventListener(window, event.type, listener, useCapture);
  }, useCapture);
}

// Registers an error-providing GuestView custom element.
function registerDeniedElement(viewType, permissionName) {
  GuestViewInternalNatives.AllowGuestViewElementDefinition(() => {
    var DeniedElement = class extends HTMLElement {
      constructor() {
        super();
        window.console.error(`You do not have permission to use the ${
            viewType} element. Be sure to declare the "${
            permissionName}" permission in your manifest file.`);
      }
    }
    $CustomElementRegistry.define(
        window.customElements, $String.toLowerCase(viewType), DeniedElement);
    asyncProvideElementConstructor(viewType, DeniedElement);
  });
}

// Exports.
exports.$set('registerDeniedElement', registerDeniedElement);