/**
 * content.js
 */
"use strict";
{
  /* api */
  const {i18n, runtime} = browser;

  /* constants */
  const CLIP_TEXT = "clipboardText";
  const NS_HTML = "http://www.w3.org/1999/xhtml";
  const TYPE_FROM = 8;
  const TYPE_TO = -1;
  const USER_INPUT = "userInput";
  const USER_INPUT_GET = "userInputGet";
  const USER_INPUT_RES = "userInputRes";

  /**
   * log error
   * @param {!Object} e - Error
   * @returns {boolean} - false
   */
  const logError = e => {
    console.error(e);
    return false;
  };

  /**
   * log warn
   * @param {*} msg - message
   * @returns {boolean} - false
   */
  const logWarn = msg => {
    msg && console.warn(msg);
    return false;
  };

  /**
   * get type
   * @param {*} o - object to check
   * @returns {string} - type of object
   */
  const getType = o =>
    Object.prototype.toString.call(o).slice(TYPE_FROM, TYPE_TO);

  /**
   * is string
   * @param {*} o - object to check
   * @returns {boolean} - result
   */
  const isString = o => typeof o === "string" || o instanceof String;

  /**
   * send message
   * @param {*} msg - message
   * @returns {Object} - Promise.<?AsyncFunction>
   */
  const sendMsg = async msg => {
    const func = msg && runtime.sendMessage(msg);
    return func || null;
  };

  /**
   * send status
   * @param {!Object} evt - Event
   * @returns {Object} - Promise.<?AsincFunction>
   */
  const sendStatus = async evt => {
    const enabled = /^(?:(?:(?:application\/(?:[\w\-.]+\+)?|image\/[\w\-.]+\+)x|text\/(?:ht|x))ml)$/.test(document.contentType);
    const msg = {
      [evt.type]: enabled,
    };
    return enabled && sendMsg(msg) || null;
  };

  /**
   * send user input
   * @param {Object} data - input data
   * @returns {Object} - Promise.<AsyncFunction>
   */
  const sendInput = async (data = {}) => {
    const msg = {
      [USER_INPUT_RES]: data,
    };
    return sendMsg(msg);
  };

  /**
   * get user input
   * @param {Object} data - input data
   * @returns {Object} - input data
   */
  const getInput = async (data = {}) => {
    let {content: text} = data;
    const msg = await i18n.getMessage(USER_INPUT);
    text = await window.prompt(msg, text);
    isString(text) && (data.content = text);
    return data;
  };

  /**
   * copy to clipboard
   * @param {string} text - text to copy
   * @returns {void} - Promise.<void>
   */
  const copyToClipboard = async text => {
    if (isString(text)) {
      const root = document.querySelector("body") || document.documentElement;
      if (root) {
        const {namespaceURI} = root;
        const ns = !/^http:\/\/www\.w3\.org\/1999\/xhtml$/.test(namespaceURI) &&
                   NS_HTML || "";
        const elm = document.createElementNS(ns, "div");
        const range = document.createRange();
        const sel = window.getSelection();
        const arr = [];
        if (!sel.isCollapsed) {
          const l = sel.rangeCount;
          let i = 0;
          while (i < l) {
            arr.push(sel.getRangeAt(i));
            i++;
          }
        }
        elm.textContent = text;
        elm.setAttributeNS(
          ns, "style", "all:unset;position:absolute;width:0;height:0;"
        );
        root.append(elm);
        range.selectNodeContents(elm);
        sel.removeAllRanges();
        sel.addRange(range);
        document.execCommand("copy");
        sel.removeAllRanges();
        if (arr.length) {
          for (const i of arr) {
            sel.addRange(i);
          }
        }
        root.removeChild(elm);
      } else {
        logWarn(`url2clipboard: ${document.contentType} not supported yet.`);
      }
    } else {
      logWarn(`url2clipboard: Expected String but got ${getType(text)}.`);
    }
  };

  /**
   * handle message
   * @param {*} msg - message
   * @returns {Object} - Promise.<Array>
   */
  const handleMsg = async (msg = {}) => {
    const items = msg && Object.keys(msg);
    const func = [];
    if (items && items.length) {
      for (const item of items) {
        const obj = msg[item];
        switch (item) {
          case CLIP_TEXT:
            func.push(copyToClipboard(obj));
            break;
          case USER_INPUT_GET:
            func.push(getInput(obj).then(sendInput));
            break;
          default:
        }
      }
    }
    return Promise.all(func);
  };

  /* listeners */
  runtime.onMessage.addListener(msg => handleMsg(msg).catch(logError));
  document.addEventListener("DOMContentLoaded", () => {
    window.addEventListener(
      "load", evt => sendStatus(evt).catch(logError), false
    );
    window.addEventListener(
      "contextmenu", evt => sendStatus(evt).catch(logError), false
    );
  }, false);
}

@@ -259,24 +259,68 @@
 userInput%22;%0A
+  const USER_INPUT_DEFAULT = %22Input Title%22;%0A
   const USER
@@ -1827,35 +1827,28 @@
 put = async 
-(
 data
- = %7B%7D)
  =%3E %7B%0A    co
@@ -2080,40 +2080,8 @@
 %3E %7B%0A
-    let %7Bcontent: text%7D = data;%0A
     
@@ -2125,16 +2125,70 @@
 R_INPUT)
+ %7C%7C USER_INPUT_DEFAULT;%0A    let %7Bcontent: text%7D = data
 ;%0A    te
@@ -2217,24 +2217,30 @@
 pt(msg, text
+ %7C%7C %22%22
 );%0A    isStr

Add / remove default value