Re: [w3c/manifest] Add installation prompt control flow (#417)

Ok, this is what is going in to the spec (as prose and IDL, obvs.). I've got a battery of about 100 test to go with it. 

All, please review the final design.   

```JS
"use strict";
const internalSlots = new WeakMap();
const installProcesses = [];
const AppBannerPromptOutcome = new Set([
  "accepted",
  "dismissed",
]);

class BeforeInstallPromptEvent extends Event {
  constructor(typeArg, eventInit) {
    // WebIDL Guard. Wont be in spec in spec as it's all handled by WebIDL.
    if (arguments.length === 0) {
      throw new TypeError("Not enough arguments. Expected at least 1.");
    }
    const initType = typeof eventInit;
    if (arguments.length === 2 && initType !== "undefined" && initType !== "object") {
      throw new TypeError("Value can't be converted to a dictionary.");
    }
    super(typeArg, Object.assign({ cancelable: true }, eventInit));

    if (eventInit && typeof eventInit.userChoice !== "undefined" && !AppBannerPromptOutcome.has(String(eventInit.userChoice))) {
      const msg = `The provided value '${eventInit.userChoice}' is not a valid` +
        "enum value of type AppBannerPromptOutcome.";
      throw new TypeError(msg);
    }
    // End WebIDL guard.

    const internal = {
      didPrompt: false,
    };

    internal.userChoicePromise = new Promise((resolve) => {
      internal.userChoiceHandlers = {
        resolve,
      };
      if (eventInit && "userChoice" in eventInit) {
        resolve(eventInit.userChoice);
      }
    });
    internalSlots.set(this, internal);
  }
  prompt() {
    if (internalSlots.get(this).didPrompt) {
      const msg = ".prompt() can only be called once.";
      throw new DOMException(msg, "InvalidStateError");
    } else {
      internalSlots.get(this).didPrompt = true;
    }

    if (this.isTrusted === false) {
      const msg = "Untrusted events can't call prompt().";
      throw new DOMException(msg, "NotAllowedError");
    }

    if (this.defaultPrevented === false) {
      const msg = ".prompt() needs to be called after .preventDefault()";
      throw new DOMException(msg, "InvalidStateError");
    }

    (async function task() {
      const userChoice = await showInstallPrompt();
      internalSlots.get(this).userChoiceHandlers.resolve(userChoice);
    }.bind(this)())
  }

  get userChoice() {
    return internalSlots.get(this).userChoicePromise;
  }
}

// Browser behavior for 
async function notifyBeforeInstallPrompt(element) {
  await trackReadyState(); // don't fire until document fully loaded!
  if (installProcesses.length) { // If the user is already installing, stop
    return;
  }
  const event = new BeforeInstallPromptEvent("beforeinstallprompt");
  window.dispatchEvent(event);
  if (!event.defaultPrevented) {
    await showInstallPrompt(element);
  }
}
```

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/manifest/issues/417#issuecomment-254744543

Received on Wednesday, 19 October 2016 08:13:58 UTC