{"version":3,"file":"mail-editor-4286cb81.js","sources":["../../libs/squire-raw.mjs","../../../src/gui/editor/HtmlEditor.ts","../../../src/gui/editor/Editor.ts","../../../src/mail/signature/Signature.ts","../../../src/mail/editor/MailEditorViewModel.ts","../../../src/templates/model/TemplatePopupModel.ts","../../../src/templates/view/TemplateConstants.ts","../../../src/templates/view/TemplatePopupResultRow.ts","../../../src/templates/view/TemplateExpander.ts","../../../src/templates/view/TemplateSearchBar.ts","../../../src/templates/TemplateGroupUtils.ts","../../../src/templates/view/TemplatePopup.ts","../../../src/templates/view/TemplateShortcutListener.ts","../../../src/knowledgebase/view/KnowledgeBaseListEntry.ts","../../../src/knowledgebase/view/KnowledgeBaseEntryView.ts","../../../src/knowledgebase/view/KnowledgeBaseDialogContent.ts","../../../src/knowledgebase/view/KnowledgeBaseDialog.ts","../../../src/knowledgebase/model/KnowledgeBaseSearchFilter.ts","../../../src/knowledgebase/model/KnowledgeBaseModel.ts","../../../src/mail/editor/MailEditor.ts","../../../src/mail/editor/SendMailModel.ts","../../../src/mail/press/PressReleaseEditor.ts"],"sourcesContent":["// source/node/TreeIterator.ts\nvar SHOW_ELEMENT = 1;\nvar SHOW_TEXT = 4;\nvar SHOW_ELEMENT_OR_TEXT = 5;\nvar always = () => true;\nvar TreeIterator = class {\n  root;\n  currentNode;\n  nodeType;\n  filter;\n  constructor(root, nodeType, filter) {\n    this.root = root;\n    this.currentNode = root;\n    this.nodeType = nodeType;\n    this.filter = filter || always;\n  }\n  isAcceptableNode(node) {\n    const nodeType = node.nodeType;\n    const nodeFilterType = nodeType === Node.ELEMENT_NODE ? SHOW_ELEMENT : nodeType === Node.TEXT_NODE ? SHOW_TEXT : 0;\n    return !!(nodeFilterType & this.nodeType) && this.filter(node);\n  }\n  nextNode() {\n    const root = this.root;\n    let current = this.currentNode;\n    let node;\n    while (true) {\n      node = current.firstChild;\n      while (!node && current) {\n        if (current === root) {\n          break;\n        }\n        node = current.nextSibling;\n        if (!node) {\n          current = current.parentNode;\n        }\n      }\n      if (!node) {\n        return null;\n      }\n      if (this.isAcceptableNode(node)) {\n        this.currentNode = node;\n        return node;\n      }\n      current = node;\n    }\n  }\n  previousNode() {\n    const root = this.root;\n    let current = this.currentNode;\n    let node;\n    while (true) {\n      if (current === root) {\n        return null;\n      }\n      node = current.previousSibling;\n      if (node) {\n        while (current = node.lastChild) {\n          node = current;\n        }\n      } else {\n        node = current.parentNode;\n      }\n      if (!node) {\n        return null;\n      }\n      if (this.isAcceptableNode(node)) {\n        this.currentNode = node;\n        return node;\n      }\n      current = node;\n    }\n  }\n  // Previous node in post-order.\n  previousPONode() {\n    const root = this.root;\n    let current = this.currentNode;\n    let node;\n    while (true) {\n      node = current.lastChild;\n      while (!node && current) {\n        if (current === root) {\n          break;\n        }\n        node = current.previousSibling;\n        if (!node) {\n          current = current.parentNode;\n        }\n      }\n      if (!node) {\n        return null;\n      }\n      if (this.isAcceptableNode(node)) {\n        this.currentNode = node;\n        return node;\n      }\n      current = node;\n    }\n  }\n};\n\n// source/Constants.ts\nvar ELEMENT_NODE = 1;\nvar TEXT_NODE = 3;\nvar DOCUMENT_FRAGMENT_NODE = 11;\nvar ZWS = \"\\u200B\";\nvar ua = navigator.userAgent;\nvar isMac = /Mac OS X/.test(ua);\nvar isWin = /Windows NT/.test(ua);\nvar isIOS = /iP(?:ad|hone|od)/.test(ua) || isMac && !!navigator.maxTouchPoints;\nvar isAndroid = /Android/.test(ua);\nvar isGecko = /Gecko\\//.test(ua);\nvar isLegacyEdge = /Edge\\//.test(ua);\nvar isWebKit = !isLegacyEdge && /WebKit\\//.test(ua);\nvar ctrlKey = isMac || isIOS ? \"Meta-\" : \"Ctrl-\";\nvar cantFocusEmptyTextNodes = isWebKit;\nvar supportsInputEvents = \"onbeforeinput\" in document && \"inputType\" in new InputEvent(\"input\");\nvar notWS = /[^ \\t\\r\\n]/;\n\n// source/node/Category.ts\nvar inlineNodeNames = /^(?:#text|A(?:BBR|CRONYM)?|B(?:R|D[IO])?|C(?:ITE|ODE)|D(?:ATA|EL|FN)|EM|FONT|HR|I(?:FRAME|MG|NPUT|NS)?|KBD|Q|R(?:P|T|UBY)|S(?:AMP|MALL|PAN|TR(?:IKE|ONG)|U[BP])?|TIME|U|VAR|WBR)$/;\nvar leafNodeNames = /* @__PURE__ */ new Set([\"BR\", \"HR\", \"IFRAME\", \"IMG\", \"INPUT\"]);\nvar UNKNOWN = 0;\nvar INLINE = 1;\nvar BLOCK = 2;\nvar CONTAINER = 3;\nvar cache = /* @__PURE__ */ new WeakMap();\nvar resetNodeCategoryCache = () => {\n  cache = /* @__PURE__ */ new WeakMap();\n};\nvar isLeaf = (node) => {\n  return leafNodeNames.has(node.nodeName);\n};\nvar getNodeCategory = (node) => {\n  switch (node.nodeType) {\n    case TEXT_NODE:\n      return INLINE;\n    case ELEMENT_NODE:\n    case DOCUMENT_FRAGMENT_NODE:\n      if (cache.has(node)) {\n        return cache.get(node);\n      }\n      break;\n    default:\n      return UNKNOWN;\n  }\n  let nodeCategory;\n  if (!Array.from(node.childNodes).every(isInline)) {\n    nodeCategory = CONTAINER;\n  } else if (inlineNodeNames.test(node.nodeName)) {\n    nodeCategory = INLINE;\n  } else {\n    nodeCategory = BLOCK;\n  }\n  cache.set(node, nodeCategory);\n  return nodeCategory;\n};\nvar isInline = (node) => {\n  return getNodeCategory(node) === INLINE;\n};\nvar isBlock = (node) => {\n  return getNodeCategory(node) === BLOCK;\n};\nvar isContainer = (node) => {\n  return getNodeCategory(node) === CONTAINER;\n};\n\n// source/node/Node.ts\nvar createElement = (tag, props, children) => {\n  const el = document.createElement(tag);\n  if (props instanceof Array) {\n    children = props;\n    props = null;\n  }\n  if (props) {\n    for (const attr in props) {\n      const value = props[attr];\n      if (value !== void 0) {\n        el.setAttribute(attr, value);\n      }\n    }\n  }\n  if (children) {\n    children.forEach((node) => el.appendChild(node));\n  }\n  return el;\n};\nvar areAlike = (node, node2) => {\n  if (isLeaf(node)) {\n    return false;\n  }\n  if (node.nodeType !== node2.nodeType || node.nodeName !== node2.nodeName) {\n    return false;\n  }\n  if (node instanceof HTMLElement && node2 instanceof HTMLElement) {\n    return node.nodeName !== \"A\" && node.className === node2.className && node.style.cssText === node2.style.cssText;\n  }\n  return true;\n};\nvar hasTagAttributes = (node, tag, attributes) => {\n  if (node.nodeName !== tag) {\n    return false;\n  }\n  for (const attr in attributes) {\n    if (!(\"getAttribute\" in node) || node.getAttribute(attr) !== attributes[attr]) {\n      return false;\n    }\n  }\n  return true;\n};\nvar getNearest = (node, root, tag, attributes) => {\n  while (node && node !== root) {\n    if (hasTagAttributes(node, tag, attributes)) {\n      return node;\n    }\n    node = node.parentNode;\n  }\n  return null;\n};\nvar getNodeBeforeOffset = (node, offset) => {\n  let children = node.childNodes;\n  while (offset && node instanceof Element) {\n    node = children[offset - 1];\n    children = node.childNodes;\n    offset = children.length;\n  }\n  return node;\n};\nvar getNodeAfterOffset = (node, offset) => {\n  let returnNode = node;\n  if (returnNode instanceof Element) {\n    const children = returnNode.childNodes;\n    if (offset < children.length) {\n      returnNode = children[offset];\n    } else {\n      while (returnNode && !returnNode.nextSibling) {\n        returnNode = returnNode.parentNode;\n      }\n      if (returnNode) {\n        returnNode = returnNode.nextSibling;\n      }\n    }\n  }\n  return returnNode;\n};\nvar getLength = (node) => {\n  return node instanceof Element || node instanceof DocumentFragment ? node.childNodes.length : node instanceof CharacterData ? node.length : 0;\n};\nvar empty = (node) => {\n  const frag = document.createDocumentFragment();\n  let child = node.firstChild;\n  while (child) {\n    frag.appendChild(child);\n    child = node.firstChild;\n  }\n  return frag;\n};\nvar detach = (node) => {\n  const parent = node.parentNode;\n  if (parent) {\n    parent.removeChild(node);\n  }\n  return node;\n};\nvar replaceWith = (node, node2) => {\n  const parent = node.parentNode;\n  if (parent) {\n    parent.replaceChild(node2, node);\n  }\n};\n\n// source/node/Whitespace.ts\nvar notWSTextNode = (node) => {\n  return node instanceof Element ? node.nodeName === \"BR\" : (\n    // okay if data is 'undefined' here.\n    notWS.test(node.data)\n  );\n};\nvar isLineBreak = (br, isLBIfEmptyBlock) => {\n  let block = br.parentNode;\n  while (isInline(block)) {\n    block = block.parentNode;\n  }\n  const walker = new TreeIterator(\n    block,\n    SHOW_ELEMENT_OR_TEXT,\n    notWSTextNode\n  );\n  walker.currentNode = br;\n  return !!walker.nextNode() || isLBIfEmptyBlock && !walker.previousNode();\n};\nvar removeZWS = (root, keepNode) => {\n  const walker = new TreeIterator(root, SHOW_TEXT);\n  let textNode;\n  let index;\n  while (textNode = walker.nextNode()) {\n    while ((index = textNode.data.indexOf(ZWS)) > -1 && // eslint-disable-next-line no-unmodified-loop-condition\n    (!keepNode || textNode.parentNode !== keepNode)) {\n      if (textNode.length === 1) {\n        let node = textNode;\n        let parent = node.parentNode;\n        while (parent) {\n          parent.removeChild(node);\n          walker.currentNode = parent;\n          if (!isInline(parent) || getLength(parent)) {\n            break;\n          }\n          node = parent;\n          parent = node.parentNode;\n        }\n        break;\n      } else {\n        textNode.deleteData(index, 1);\n      }\n    }\n  }\n};\n\n// source/range/Boundaries.ts\nvar START_TO_START = 0;\nvar START_TO_END = 1;\nvar END_TO_END = 2;\nvar END_TO_START = 3;\nvar isNodeContainedInRange = (range, node, partial) => {\n  const nodeRange = document.createRange();\n  nodeRange.selectNode(node);\n  if (partial) {\n    const nodeEndBeforeStart = range.compareBoundaryPoints(END_TO_START, nodeRange) > -1;\n    const nodeStartAfterEnd = range.compareBoundaryPoints(START_TO_END, nodeRange) < 1;\n    return !nodeEndBeforeStart && !nodeStartAfterEnd;\n  } else {\n    const nodeStartAfterStart = range.compareBoundaryPoints(START_TO_START, nodeRange) < 1;\n    const nodeEndBeforeEnd = range.compareBoundaryPoints(END_TO_END, nodeRange) > -1;\n    return nodeStartAfterStart && nodeEndBeforeEnd;\n  }\n};\nvar moveRangeBoundariesDownTree = (range) => {\n  let { startContainer, startOffset, endContainer, endOffset } = range;\n  while (!(startContainer instanceof Text)) {\n    let child = startContainer.childNodes[startOffset];\n    if (!child || isLeaf(child)) {\n      if (startOffset) {\n        child = startContainer.childNodes[startOffset - 1];\n        if (child instanceof Text) {\n          let textChild = child;\n          let prev;\n          while (!textChild.length && (prev = textChild.previousSibling) && prev instanceof Text) {\n            textChild.remove();\n            textChild = prev;\n          }\n          startContainer = textChild;\n          startOffset = textChild.data.length;\n        }\n      }\n      break;\n    }\n    startContainer = child;\n    startOffset = 0;\n  }\n  if (endOffset) {\n    while (!(endContainer instanceof Text)) {\n      const child = endContainer.childNodes[endOffset - 1];\n      if (!child || isLeaf(child)) {\n        if (child && child.nodeName === \"BR\" && !isLineBreak(child, false)) {\n          endOffset -= 1;\n          continue;\n        }\n        break;\n      }\n      endContainer = child;\n      endOffset = getLength(endContainer);\n    }\n  } else {\n    while (!(endContainer instanceof Text)) {\n      const child = endContainer.firstChild;\n      if (!child || isLeaf(child)) {\n        break;\n      }\n      endContainer = child;\n    }\n  }\n  range.setStart(startContainer, startOffset);\n  range.setEnd(endContainer, endOffset);\n};\nvar moveRangeBoundariesUpTree = (range, startMax, endMax, root) => {\n  let startContainer = range.startContainer;\n  let startOffset = range.startOffset;\n  let endContainer = range.endContainer;\n  let endOffset = range.endOffset;\n  let parent;\n  if (!startMax) {\n    startMax = range.commonAncestorContainer;\n  }\n  if (!endMax) {\n    endMax = startMax;\n  }\n  while (!startOffset && startContainer !== startMax && startContainer !== root) {\n    parent = startContainer.parentNode;\n    startOffset = Array.from(parent.childNodes).indexOf(\n      startContainer\n    );\n    startContainer = parent;\n  }\n  while (true) {\n    if (endContainer === endMax || endContainer === root) {\n      break;\n    }\n    if (endContainer.nodeType !== TEXT_NODE && endContainer.childNodes[endOffset] && endContainer.childNodes[endOffset].nodeName === \"BR\" && !isLineBreak(endContainer.childNodes[endOffset], false)) {\n      endOffset += 1;\n    }\n    if (endOffset !== getLength(endContainer)) {\n      break;\n    }\n    parent = endContainer.parentNode;\n    endOffset = Array.from(parent.childNodes).indexOf(endContainer) + 1;\n    endContainer = parent;\n  }\n  range.setStart(startContainer, startOffset);\n  range.setEnd(endContainer, endOffset);\n};\nvar moveRangeBoundaryOutOf = (range, tag, root) => {\n  let parent = getNearest(range.endContainer, root, tag);\n  if (parent && (parent = parent.parentNode)) {\n    const clone = range.cloneRange();\n    moveRangeBoundariesUpTree(clone, parent, parent, root);\n    if (clone.endContainer === parent) {\n      range.setStart(clone.endContainer, clone.endOffset);\n      range.setEnd(clone.endContainer, clone.endOffset);\n    }\n  }\n  return range;\n};\n\n// source/node/MergeSplit.ts\nvar fixCursor = (node) => {\n  let fixer = null;\n  if (node instanceof Text) {\n    return node;\n  }\n  if (isInline(node)) {\n    let child = node.firstChild;\n    if (cantFocusEmptyTextNodes) {\n      while (child && child instanceof Text && !child.data) {\n        node.removeChild(child);\n        child = node.firstChild;\n      }\n    }\n    if (!child) {\n      if (cantFocusEmptyTextNodes) {\n        fixer = document.createTextNode(ZWS);\n      } else {\n        fixer = document.createTextNode(\"\");\n      }\n    }\n  } else if (node instanceof Element && !node.querySelector(\"BR\")) {\n    fixer = createElement(\"BR\");\n    let parent = node;\n    let child;\n    while ((child = parent.lastElementChild) && !isInline(child)) {\n      parent = child;\n    }\n  }\n  if (fixer) {\n    try {\n      node.appendChild(fixer);\n    } catch (error) {\n    }\n  }\n  return node;\n};\nvar fixContainer = (container, root) => {\n  let wrapper = null;\n  Array.from(container.childNodes).forEach((child) => {\n    const isBR = child.nodeName === \"BR\";\n    if (!isBR && isInline(child)) {\n      if (!wrapper) {\n        wrapper = createElement(\"DIV\");\n      }\n      wrapper.appendChild(child);\n    } else if (isBR || wrapper) {\n      if (!wrapper) {\n        wrapper = createElement(\"DIV\");\n      }\n      fixCursor(wrapper);\n      if (isBR) {\n        container.replaceChild(wrapper, child);\n      } else {\n        container.insertBefore(wrapper, child);\n      }\n      wrapper = null;\n    }\n    if (isContainer(child)) {\n      fixContainer(child, root);\n    }\n  });\n  if (wrapper) {\n    container.appendChild(fixCursor(wrapper));\n  }\n  return container;\n};\nvar split = (node, offset, stopNode, root) => {\n  if (node instanceof Text && node !== stopNode) {\n    if (typeof offset !== \"number\") {\n      throw new Error(\"Offset must be a number to split text node!\");\n    }\n    if (!node.parentNode) {\n      throw new Error(\"Cannot split text node with no parent!\");\n    }\n    return split(node.parentNode, node.splitText(offset), stopNode, root);\n  }\n  let nodeAfterSplit = typeof offset === \"number\" ? offset < node.childNodes.length ? node.childNodes[offset] : null : offset;\n  const parent = node.parentNode;\n  if (!parent || node === stopNode || !(node instanceof Element)) {\n    return nodeAfterSplit;\n  }\n  const clone = node.cloneNode(false);\n  while (nodeAfterSplit) {\n    const next = nodeAfterSplit.nextSibling;\n    clone.appendChild(nodeAfterSplit);\n    nodeAfterSplit = next;\n  }\n  if (node instanceof HTMLOListElement && getNearest(node, root, \"BLOCKQUOTE\")) {\n    clone.start = (+node.start || 1) + node.childNodes.length - 1;\n  }\n  fixCursor(node);\n  fixCursor(clone);\n  parent.insertBefore(clone, node.nextSibling);\n  return split(parent, clone, stopNode, root);\n};\nvar _mergeInlines = (node, fakeRange) => {\n  const children = node.childNodes;\n  let l = children.length;\n  const frags = [];\n  while (l--) {\n    const child = children[l];\n    const prev = l ? children[l - 1] : null;\n    if (prev && isInline(child) && areAlike(child, prev)) {\n      if (fakeRange.startContainer === child) {\n        fakeRange.startContainer = prev;\n        fakeRange.startOffset += getLength(prev);\n      }\n      if (fakeRange.endContainer === child) {\n        fakeRange.endContainer = prev;\n        fakeRange.endOffset += getLength(prev);\n      }\n      if (fakeRange.startContainer === node) {\n        if (fakeRange.startOffset > l) {\n          fakeRange.startOffset -= 1;\n        } else if (fakeRange.startOffset === l) {\n          fakeRange.startContainer = prev;\n          fakeRange.startOffset = getLength(prev);\n        }\n      }\n      if (fakeRange.endContainer === node) {\n        if (fakeRange.endOffset > l) {\n          fakeRange.endOffset -= 1;\n        } else if (fakeRange.endOffset === l) {\n          fakeRange.endContainer = prev;\n          fakeRange.endOffset = getLength(prev);\n        }\n      }\n      detach(child);\n      if (child instanceof Text) {\n        prev.appendData(child.data);\n      } else {\n        frags.push(empty(child));\n      }\n    } else if (child instanceof Element) {\n      let frag;\n      while (frag = frags.pop()) {\n        child.appendChild(frag);\n      }\n      _mergeInlines(child, fakeRange);\n    }\n  }\n};\nvar mergeInlines = (node, range) => {\n  const element = node instanceof Text ? node.parentNode : node;\n  if (element instanceof Element) {\n    const fakeRange = {\n      startContainer: range.startContainer,\n      startOffset: range.startOffset,\n      endContainer: range.endContainer,\n      endOffset: range.endOffset\n    };\n    _mergeInlines(element, fakeRange);\n    range.setStart(fakeRange.startContainer, fakeRange.startOffset);\n    range.setEnd(fakeRange.endContainer, fakeRange.endOffset);\n  }\n};\nvar mergeWithBlock = (block, next, range, root) => {\n  let container = next;\n  let parent;\n  let offset;\n  while ((parent = container.parentNode) && parent !== root && parent instanceof Element && parent.childNodes.length === 1) {\n    container = parent;\n  }\n  detach(container);\n  offset = block.childNodes.length;\n  const last = block.lastChild;\n  if (last && last.nodeName === \"BR\") {\n    block.removeChild(last);\n    offset -= 1;\n  }\n  block.appendChild(empty(next));\n  range.setStart(block, offset);\n  range.collapse(true);\n  mergeInlines(block, range);\n};\nvar mergeContainers = (node, root) => {\n  const prev = node.previousSibling;\n  const first = node.firstChild;\n  const isListItem = node.nodeName === \"LI\";\n  if (isListItem && (!first || !/^[OU]L$/.test(first.nodeName))) {\n    return;\n  }\n  if (prev && areAlike(prev, node)) {\n    if (!isContainer(prev)) {\n      if (isListItem) {\n        const block = createElement(\"DIV\");\n        block.appendChild(empty(prev));\n        prev.appendChild(block);\n      } else {\n        return;\n      }\n    }\n    detach(node);\n    const needsFix = !isContainer(node);\n    prev.appendChild(empty(node));\n    if (needsFix) {\n      fixContainer(prev, root);\n    }\n    if (first) {\n      mergeContainers(first, root);\n    }\n  } else if (isListItem) {\n    const block = createElement(\"DIV\");\n    node.insertBefore(block, first);\n    fixCursor(block);\n  }\n};\n\n// source/Clean.ts\nvar styleToSemantic = {\n  \"font-weight\": {\n    regexp: /^bold|^700/i,\n    replace() {\n      return createElement(\"B\");\n    }\n  },\n  \"font-style\": {\n    regexp: /^italic/i,\n    replace() {\n      return createElement(\"I\");\n    }\n  },\n  \"font-family\": {\n    regexp: notWS,\n    replace(classNames, family) {\n      return createElement(\"SPAN\", {\n        class: classNames.fontFamily,\n        style: \"font-family:\" + family\n      });\n    }\n  },\n  \"font-size\": {\n    regexp: notWS,\n    replace(classNames, size) {\n      return createElement(\"SPAN\", {\n        class: classNames.fontSize,\n        style: \"font-size:\" + size\n      });\n    }\n  },\n  \"text-decoration\": {\n    regexp: /^underline/i,\n    replace() {\n      return createElement(\"U\");\n    }\n  }\n};\nvar replaceStyles = (node, _, config) => {\n  const style = node.style;\n  let newTreeBottom;\n  let newTreeTop;\n  for (const attr in styleToSemantic) {\n    const converter = styleToSemantic[attr];\n    const css = style.getPropertyValue(attr);\n    if (css && converter.regexp.test(css)) {\n      const el = converter.replace(config.classNames, css);\n      if (el.nodeName === node.nodeName && el.className === node.className) {\n        continue;\n      }\n      if (!newTreeTop) {\n        newTreeTop = el;\n      }\n      if (newTreeBottom) {\n        newTreeBottom.appendChild(el);\n      }\n      newTreeBottom = el;\n      node.style.removeProperty(attr);\n    }\n  }\n  if (newTreeTop && newTreeBottom) {\n    newTreeBottom.appendChild(empty(node));\n    if (node.style.cssText) {\n      node.appendChild(newTreeTop);\n    } else {\n      replaceWith(node, newTreeTop);\n    }\n  }\n  return newTreeBottom || node;\n};\nvar replaceWithTag = (tag) => {\n  return (node, parent) => {\n    const el = createElement(tag);\n    const attributes = node.attributes;\n    for (let i = 0, l = attributes.length; i < l; i += 1) {\n      const attribute = attributes[i];\n      el.setAttribute(attribute.name, attribute.value);\n    }\n    parent.replaceChild(el, node);\n    el.appendChild(empty(node));\n    return el;\n  };\n};\nvar fontSizes = {\n  \"1\": \"10\",\n  \"2\": \"13\",\n  \"3\": \"16\",\n  \"4\": \"18\",\n  \"5\": \"24\",\n  \"6\": \"32\",\n  \"7\": \"48\"\n};\nvar stylesRewriters = {\n  STRONG: replaceWithTag(\"B\"),\n  EM: replaceWithTag(\"I\"),\n  INS: replaceWithTag(\"U\"),\n  STRIKE: replaceWithTag(\"S\"),\n  SPAN: replaceStyles,\n  FONT: (node, parent, config) => {\n    const font = node;\n    const face = font.face;\n    const size = font.size;\n    let color = font.color;\n    const classNames = config.classNames;\n    let fontSpan;\n    let sizeSpan;\n    let colorSpan;\n    let newTreeBottom;\n    let newTreeTop;\n    if (face) {\n      fontSpan = createElement(\"SPAN\", {\n        class: classNames.fontFamily,\n        style: \"font-family:\" + face\n      });\n      newTreeTop = fontSpan;\n      newTreeBottom = fontSpan;\n    }\n    if (size) {\n      sizeSpan = createElement(\"SPAN\", {\n        class: classNames.fontSize,\n        style: \"font-size:\" + fontSizes[size] + \"px\"\n      });\n      if (!newTreeTop) {\n        newTreeTop = sizeSpan;\n      }\n      if (newTreeBottom) {\n        newTreeBottom.appendChild(sizeSpan);\n      }\n      newTreeBottom = sizeSpan;\n    }\n    if (color && /^#?([\\dA-F]{3}){1,2}$/i.test(color)) {\n      if (color.charAt(0) !== \"#\") {\n        color = \"#\" + color;\n      }\n      colorSpan = createElement(\"SPAN\", {\n        class: classNames.color,\n        style: \"color:\" + color\n      });\n      if (!newTreeTop) {\n        newTreeTop = colorSpan;\n      }\n      if (newTreeBottom) {\n        newTreeBottom.appendChild(colorSpan);\n      }\n      newTreeBottom = colorSpan;\n    }\n    if (!newTreeTop || !newTreeBottom) {\n      newTreeTop = newTreeBottom = createElement(\"SPAN\");\n    }\n    parent.replaceChild(newTreeTop, font);\n    newTreeBottom.appendChild(empty(font));\n    return newTreeBottom;\n  },\n  TT: (node, parent, config) => {\n    const el = createElement(\"SPAN\", {\n      class: config.classNames.fontFamily,\n      style: 'font-family:menlo,consolas,\"courier new\",monospace'\n    });\n    parent.replaceChild(el, node);\n    el.appendChild(empty(node));\n    return el;\n  }\n};\nvar allowedBlock = /^(?:A(?:DDRESS|RTICLE|SIDE|UDIO)|BLOCKQUOTE|CAPTION|D(?:[DLT]|IV)|F(?:IGURE|IGCAPTION|OOTER)|H[1-6]|HEADER|L(?:ABEL|EGEND|I)|O(?:L|UTPUT)|P(?:RE)?|SECTION|T(?:ABLE|BODY|D|FOOT|H|HEAD|R)|COL(?:GROUP)?|UL)$/;\nvar blacklist = /^(?:HEAD|META|STYLE)/;\nvar cleanTree = (node, config, preserveWS) => {\n  const children = node.childNodes;\n  let nonInlineParent = node;\n  while (isInline(nonInlineParent)) {\n    nonInlineParent = nonInlineParent.parentNode;\n  }\n  const walker = new TreeIterator(\n    nonInlineParent,\n    SHOW_ELEMENT_OR_TEXT\n  );\n  for (let i = 0, l = children.length; i < l; i += 1) {\n    let child = children[i];\n    const nodeName = child.nodeName;\n    const rewriter = stylesRewriters[nodeName];\n    if (child instanceof HTMLElement) {\n      const childLength = child.childNodes.length;\n      if (rewriter) {\n        child = rewriter(child, node, config);\n      } else if (blacklist.test(nodeName)) {\n        node.removeChild(child);\n        i -= 1;\n        l -= 1;\n        continue;\n      } else if (!allowedBlock.test(nodeName) && !isInline(child)) {\n        i -= 1;\n        l += childLength - 1;\n        node.replaceChild(empty(child), child);\n        continue;\n      }\n      if (childLength) {\n        cleanTree(child, config, preserveWS || nodeName === \"PRE\");\n      }\n    } else {\n      if (child instanceof Text) {\n        let data = child.data;\n        const startsWithWS = !notWS.test(data.charAt(0));\n        const endsWithWS = !notWS.test(data.charAt(data.length - 1));\n        if (preserveWS || !startsWithWS && !endsWithWS) {\n          continue;\n        }\n        if (startsWithWS) {\n          walker.currentNode = child;\n          let sibling;\n          while (sibling = walker.previousPONode()) {\n            if (sibling.nodeName === \"IMG\" || sibling instanceof Text && notWS.test(sibling.data)) {\n              break;\n            }\n            if (!isInline(sibling)) {\n              sibling = null;\n              break;\n            }\n          }\n          data = data.replace(/^[ \\t\\r\\n]+/g, sibling ? \" \" : \"\");\n        }\n        if (endsWithWS) {\n          walker.currentNode = child;\n          let sibling;\n          while (sibling = walker.nextNode()) {\n            if (sibling.nodeName === \"IMG\" || sibling instanceof Text && notWS.test(sibling.data)) {\n              break;\n            }\n            if (!isInline(sibling)) {\n              sibling = null;\n              break;\n            }\n          }\n          data = data.replace(/[ \\t\\r\\n]+$/g, sibling ? \" \" : \"\");\n        }\n        if (data) {\n          child.data = data;\n          continue;\n        }\n      }\n      node.removeChild(child);\n      i -= 1;\n      l -= 1;\n    }\n  }\n  return node;\n};\nvar removeEmptyInlines = (node) => {\n  const children = node.childNodes;\n  let l = children.length;\n  while (l--) {\n    const child = children[l];\n    if (child instanceof Element && !isLeaf(child)) {\n      removeEmptyInlines(child);\n      if (isInline(child) && !child.firstChild) {\n        node.removeChild(child);\n      }\n    } else if (child instanceof Text && !child.data) {\n      node.removeChild(child);\n    }\n  }\n};\nvar cleanupBRs = (node, root, keepForBlankLine) => {\n  const brs = node.querySelectorAll(\"BR\");\n  const brBreaksLine = [];\n  let l = brs.length;\n  for (let i = 0; i < l; i += 1) {\n    brBreaksLine[i] = isLineBreak(brs[i], keepForBlankLine);\n  }\n  while (l--) {\n    const br = brs[l];\n    const parent = br.parentNode;\n    if (!parent) {\n      continue;\n    }\n    if (!brBreaksLine[l]) {\n      detach(br);\n    } else if (!isInline(parent)) {\n      fixContainer(parent, root);\n    }\n  }\n};\nvar escapeHTML = (text) => {\n  return text.split(\"&\").join(\"&amp;\").split(\"<\").join(\"&lt;\").split(\">\").join(\"&gt;\").split('\"').join(\"&quot;\");\n};\n\n// source/node/Block.ts\nvar getBlockWalker = (node, root) => {\n  const walker = new TreeIterator(root, SHOW_ELEMENT, isBlock);\n  walker.currentNode = node;\n  return walker;\n};\nvar getPreviousBlock = (node, root) => {\n  const block = getBlockWalker(node, root).previousNode();\n  return block !== root ? block : null;\n};\nvar getNextBlock = (node, root) => {\n  const block = getBlockWalker(node, root).nextNode();\n  return block !== root ? block : null;\n};\nvar isEmptyBlock = (block) => {\n  return !block.textContent && !block.querySelector(\"IMG\");\n};\n\n// source/range/Block.ts\nvar getStartBlockOfRange = (range, root) => {\n  const container = range.startContainer;\n  let block;\n  if (isInline(container)) {\n    block = getPreviousBlock(container, root);\n  } else if (container !== root && container instanceof HTMLElement && isBlock(container)) {\n    block = container;\n  } else {\n    const node = getNodeBeforeOffset(container, range.startOffset);\n    block = getNextBlock(node, root);\n  }\n  return block && isNodeContainedInRange(range, block, true) ? block : null;\n};\nvar getEndBlockOfRange = (range, root) => {\n  const container = range.endContainer;\n  let block;\n  if (isInline(container)) {\n    block = getPreviousBlock(container, root);\n  } else if (container !== root && container instanceof HTMLElement && isBlock(container)) {\n    block = container;\n  } else {\n    let node = getNodeAfterOffset(container, range.endOffset);\n    if (!node || !root.contains(node)) {\n      node = root;\n      let child;\n      while (child = node.lastChild) {\n        node = child;\n      }\n    }\n    block = getPreviousBlock(node, root);\n  }\n  return block && isNodeContainedInRange(range, block, true) ? block : null;\n};\nvar isContent = (node) => {\n  return node instanceof Text ? notWS.test(node.data) : node.nodeName === \"IMG\";\n};\nvar rangeDoesStartAtBlockBoundary = (range, root) => {\n  const startContainer = range.startContainer;\n  const startOffset = range.startOffset;\n  let nodeAfterCursor;\n  if (startContainer instanceof Text) {\n    if (startOffset) {\n      return false;\n    }\n    nodeAfterCursor = startContainer;\n  } else {\n    nodeAfterCursor = getNodeAfterOffset(startContainer, startOffset);\n    if (nodeAfterCursor && !root.contains(nodeAfterCursor)) {\n      nodeAfterCursor = null;\n    }\n    if (!nodeAfterCursor) {\n      nodeAfterCursor = getNodeBeforeOffset(startContainer, startOffset);\n      if (nodeAfterCursor instanceof Text && nodeAfterCursor.length) {\n        return false;\n      }\n    }\n  }\n  const block = getStartBlockOfRange(range, root);\n  if (!block) {\n    return false;\n  }\n  const contentWalker = new TreeIterator(\n    block,\n    SHOW_ELEMENT_OR_TEXT,\n    isContent\n  );\n  contentWalker.currentNode = nodeAfterCursor;\n  return !contentWalker.previousNode();\n};\nvar rangeDoesEndAtBlockBoundary = (range, root) => {\n  const endContainer = range.endContainer;\n  const endOffset = range.endOffset;\n  let currentNode;\n  if (endContainer instanceof Text) {\n    const length = endContainer.data.length;\n    if (length && endOffset < length) {\n      return false;\n    }\n    currentNode = endContainer;\n  } else {\n    currentNode = getNodeBeforeOffset(endContainer, endOffset);\n  }\n  const block = getEndBlockOfRange(range, root);\n  if (!block) {\n    return false;\n  }\n  const contentWalker = new TreeIterator(\n    block,\n    SHOW_ELEMENT_OR_TEXT,\n    isContent\n  );\n  contentWalker.currentNode = currentNode;\n  return !contentWalker.nextNode();\n};\nvar expandRangeToBlockBoundaries = (range, root) => {\n  const start = getStartBlockOfRange(range, root);\n  const end = getEndBlockOfRange(range, root);\n  let parent;\n  if (start && end) {\n    parent = start.parentNode;\n    range.setStart(parent, Array.from(parent.childNodes).indexOf(start));\n    parent = end.parentNode;\n    range.setEnd(parent, Array.from(parent.childNodes).indexOf(end) + 1);\n  }\n};\n\n// source/range/InsertDelete.ts\nfunction createRange(startContainer, startOffset, endContainer, endOffset) {\n  const range = document.createRange();\n  range.setStart(startContainer, startOffset);\n  if (endContainer && typeof endOffset === \"number\") {\n    range.setEnd(endContainer, endOffset);\n  } else {\n    range.setEnd(startContainer, startOffset);\n  }\n  return range;\n}\nvar insertNodeInRange = (range, node) => {\n  let { startContainer, startOffset, endContainer, endOffset } = range;\n  let children;\n  if (startContainer instanceof Text) {\n    const parent = startContainer.parentNode;\n    children = parent.childNodes;\n    if (startOffset === startContainer.length) {\n      startOffset = Array.from(children).indexOf(startContainer) + 1;\n      if (range.collapsed) {\n        endContainer = parent;\n        endOffset = startOffset;\n      }\n    } else {\n      if (startOffset) {\n        const afterSplit = startContainer.splitText(startOffset);\n        if (endContainer === startContainer) {\n          endOffset -= startOffset;\n          endContainer = afterSplit;\n        } else if (endContainer === parent) {\n          endOffset += 1;\n        }\n        startContainer = afterSplit;\n      }\n      startOffset = Array.from(children).indexOf(\n        startContainer\n      );\n    }\n    startContainer = parent;\n  } else {\n    children = startContainer.childNodes;\n  }\n  const childCount = children.length;\n  if (startOffset === childCount) {\n    startContainer.appendChild(node);\n  } else {\n    startContainer.insertBefore(node, children[startOffset]);\n  }\n  if (startContainer === endContainer) {\n    endOffset += children.length - childCount;\n  }\n  range.setStart(startContainer, startOffset);\n  range.setEnd(endContainer, endOffset);\n};\nvar extractContentsOfRange = (range, common, root) => {\n  const frag = document.createDocumentFragment();\n  if (range.collapsed) {\n    return frag;\n  }\n  if (!common) {\n    common = range.commonAncestorContainer;\n  }\n  if (common instanceof Text) {\n    common = common.parentNode;\n  }\n  const startContainer = range.startContainer;\n  const startOffset = range.startOffset;\n  let endContainer = split(range.endContainer, range.endOffset, common, root);\n  let endOffset = 0;\n  let node = split(startContainer, startOffset, common, root);\n  while (node && node !== endContainer) {\n    const next = node.nextSibling;\n    frag.appendChild(node);\n    node = next;\n  }\n  if (startContainer instanceof Text && endContainer instanceof Text) {\n    startContainer.appendData(endContainer.data);\n    detach(endContainer);\n    endContainer = startContainer;\n    endOffset = startOffset;\n  }\n  range.setStart(startContainer, startOffset);\n  if (endContainer) {\n    range.setEnd(endContainer, endOffset);\n  } else {\n    range.setEnd(common, common.childNodes.length);\n  }\n  fixCursor(common);\n  return frag;\n};\nvar getAdjacentInlineNode = (iterator, method, node) => {\n  iterator.currentNode = node;\n  let nextNode;\n  while (nextNode = iterator[method]()) {\n    if (nextNode instanceof Text || isLeaf(nextNode)) {\n      return nextNode;\n    }\n    if (!isInline(nextNode)) {\n      return null;\n    }\n  }\n  return null;\n};\nvar deleteContentsOfRange = (range, root) => {\n  const startBlock = getStartBlockOfRange(range, root);\n  let endBlock = getEndBlockOfRange(range, root);\n  const needsMerge = startBlock !== endBlock;\n  if (startBlock && endBlock) {\n    moveRangeBoundariesDownTree(range);\n    moveRangeBoundariesUpTree(range, startBlock, endBlock, root);\n  }\n  const frag = extractContentsOfRange(range, null, root);\n  moveRangeBoundariesDownTree(range);\n  if (needsMerge) {\n    endBlock = getEndBlockOfRange(range, root);\n    if (startBlock && endBlock && startBlock !== endBlock) {\n      mergeWithBlock(startBlock, endBlock, range, root);\n    }\n  }\n  if (startBlock) {\n    fixCursor(startBlock);\n  }\n  const child = root.firstChild;\n  if (!child || child.nodeName === \"BR\") {\n    fixCursor(root);\n    if (root.firstChild) {\n      range.selectNodeContents(root.firstChild);\n    }\n  }\n  range.collapse(true);\n  const startContainer = range.startContainer;\n  const startOffset = range.startOffset;\n  const iterator = new TreeIterator(root, SHOW_ELEMENT_OR_TEXT);\n  let afterNode = startContainer;\n  let afterOffset = startOffset;\n  if (!(afterNode instanceof Text) || afterOffset === afterNode.data.length) {\n    afterNode = getAdjacentInlineNode(iterator, \"nextNode\", afterNode);\n    afterOffset = 0;\n  }\n  let beforeNode = startContainer;\n  let beforeOffset = startOffset - 1;\n  if (!(beforeNode instanceof Text) || beforeOffset === -1) {\n    beforeNode = getAdjacentInlineNode(\n      iterator,\n      \"previousPONode\",\n      afterNode || (startContainer instanceof Text ? startContainer : startContainer.childNodes[startOffset] || startContainer)\n    );\n    if (beforeNode instanceof Text) {\n      beforeOffset = beforeNode.data.length;\n    }\n  }\n  let node = null;\n  let offset = 0;\n  if (afterNode instanceof Text && afterNode.data.charAt(afterOffset) === \" \" && rangeDoesStartAtBlockBoundary(range, root)) {\n    node = afterNode;\n    offset = afterOffset;\n  } else if (beforeNode instanceof Text && beforeNode.data.charAt(beforeOffset) === \" \") {\n    if (afterNode instanceof Text && afterNode.data.charAt(afterOffset) === \" \" || rangeDoesEndAtBlockBoundary(range, root)) {\n      node = beforeNode;\n      offset = beforeOffset;\n    }\n  }\n  if (node) {\n    node.replaceData(offset, 1, \"\\xA0\");\n  }\n  range.setStart(startContainer, startOffset);\n  range.collapse(true);\n  return frag;\n};\nvar insertTreeFragmentIntoRange = (range, frag, root) => {\n  const firstInFragIsInline = frag.firstChild && isInline(frag.firstChild);\n  let node;\n  fixContainer(frag, root);\n  node = frag;\n  while (node = getNextBlock(node, root)) {\n    fixCursor(node);\n  }\n  if (!range.collapsed) {\n    deleteContentsOfRange(range, root);\n  }\n  moveRangeBoundariesDownTree(range);\n  range.collapse(false);\n  const stopPoint = getNearest(range.endContainer, root, \"BLOCKQUOTE\") || root;\n  let block = getStartBlockOfRange(range, root);\n  let blockContentsAfterSplit = null;\n  const firstBlockInFrag = getNextBlock(frag, frag);\n  const replaceBlock = !firstInFragIsInline && !!block && isEmptyBlock(block);\n  if (block && firstBlockInFrag && !replaceBlock && // Don't merge table cells or PRE elements into block\n  !getNearest(firstBlockInFrag, frag, \"PRE\") && !getNearest(firstBlockInFrag, frag, \"TABLE\")) {\n    moveRangeBoundariesUpTree(range, block, block, root);\n    range.collapse(true);\n    let container = range.endContainer;\n    let offset = range.endOffset;\n    cleanupBRs(block, root, false);\n    if (isInline(container)) {\n      const nodeAfterSplit = split(\n        container,\n        offset,\n        getPreviousBlock(container, root) || root,\n        root\n      );\n      container = nodeAfterSplit.parentNode;\n      offset = Array.from(container.childNodes).indexOf(\n        nodeAfterSplit\n      );\n    }\n    if (\n      /*isBlock( container ) && */\n      offset !== getLength(container)\n    ) {\n      blockContentsAfterSplit = document.createDocumentFragment();\n      while (node = container.childNodes[offset]) {\n        blockContentsAfterSplit.appendChild(node);\n      }\n    }\n    mergeWithBlock(container, firstBlockInFrag, range, root);\n    offset = Array.from(container.parentNode.childNodes).indexOf(\n      container\n    ) + 1;\n    container = container.parentNode;\n    range.setEnd(container, offset);\n  }\n  if (getLength(frag)) {\n    if (replaceBlock && block) {\n      range.setEndBefore(block);\n      range.collapse(false);\n      detach(block);\n    }\n    moveRangeBoundariesUpTree(range, stopPoint, stopPoint, root);\n    let nodeAfterSplit = split(\n      range.endContainer,\n      range.endOffset,\n      stopPoint,\n      root\n    );\n    const nodeBeforeSplit = nodeAfterSplit ? nodeAfterSplit.previousSibling : stopPoint.lastChild;\n    stopPoint.insertBefore(frag, nodeAfterSplit);\n    if (nodeAfterSplit) {\n      range.setEndBefore(nodeAfterSplit);\n    } else {\n      range.setEnd(stopPoint, getLength(stopPoint));\n    }\n    block = getEndBlockOfRange(range, root);\n    moveRangeBoundariesDownTree(range);\n    const container = range.endContainer;\n    const offset = range.endOffset;\n    if (nodeAfterSplit && isContainer(nodeAfterSplit)) {\n      mergeContainers(nodeAfterSplit, root);\n    }\n    nodeAfterSplit = nodeBeforeSplit && nodeBeforeSplit.nextSibling;\n    if (nodeAfterSplit && isContainer(nodeAfterSplit)) {\n      mergeContainers(nodeAfterSplit, root);\n    }\n    range.setEnd(container, offset);\n  }\n  if (blockContentsAfterSplit && block) {\n    const tempRange = range.cloneRange();\n    mergeWithBlock(block, blockContentsAfterSplit, tempRange, root);\n    range.setEnd(tempRange.endContainer, tempRange.endOffset);\n  }\n  moveRangeBoundariesDownTree(range);\n};\n\n// source/Clipboard.ts\nvar indexOf = Array.prototype.indexOf;\nvar setClipboardData = (event, contents, root, toCleanHTML, toPlainText, plainTextOnly) => {\n  const clipboardData = event.clipboardData;\n  const body = document.body;\n  const node = createElement(\"DIV\");\n  let html;\n  let text;\n  if (contents.childNodes.length === 1 && contents.childNodes[0] instanceof Text) {\n    text = contents.childNodes[0].data.replace(/ /g, \" \");\n    plainTextOnly = true;\n  } else {\n    node.appendChild(contents);\n    html = node.innerHTML;\n    if (toCleanHTML) {\n      html = toCleanHTML(html);\n    }\n  }\n  if (text !== void 0) {\n  } else if (toPlainText && html !== void 0) {\n    text = toPlainText(html);\n  } else {\n    cleanupBRs(node, root, true);\n    node.setAttribute(\n      \"style\",\n      \"position:fixed;overflow:hidden;bottom:100%;right:100%;\"\n    );\n    body.appendChild(node);\n    text = node.innerText || node.textContent;\n    text = text.replace(/ /g, \" \");\n    body.removeChild(node);\n  }\n  if (isWin) {\n    text = text.replace(/\\r?\\n/g, \"\\r\\n\");\n  }\n  if (!plainTextOnly && html && text !== html) {\n    clipboardData.setData(\"text/html\", html);\n  }\n  clipboardData.setData(\"text/plain\", text);\n  event.preventDefault();\n};\nvar extractRangeToClipboard = (event, range, root, removeRangeFromDocument, toCleanHTML, toPlainText, plainTextOnly) => {\n  if (!isLegacyEdge && event.clipboardData) {\n    const startBlock = getStartBlockOfRange(range, root);\n    const endBlock = getEndBlockOfRange(range, root);\n    let copyRoot = root;\n    if (startBlock === endBlock && startBlock?.contains(range.commonAncestorContainer)) {\n      copyRoot = startBlock;\n    }\n    let contents;\n    if (removeRangeFromDocument) {\n      contents = deleteContentsOfRange(range, root);\n    } else {\n      range = range.cloneRange();\n      moveRangeBoundariesDownTree(range);\n      moveRangeBoundariesUpTree(range, copyRoot, copyRoot, root);\n      contents = range.cloneContents();\n    }\n    let parent = range.commonAncestorContainer;\n    if (parent instanceof Text) {\n      parent = parent.parentNode;\n    }\n    while (parent && parent !== copyRoot) {\n      const newContents = parent.cloneNode(false);\n      newContents.appendChild(contents);\n      contents = newContents;\n      parent = parent.parentNode;\n    }\n    setClipboardData(\n      event,\n      contents,\n      root,\n      toCleanHTML,\n      toPlainText,\n      plainTextOnly\n    );\n    return true;\n  }\n  return false;\n};\nvar _onCut = function(event) {\n  const range = this.getSelection();\n  const root = this._root;\n  if (range.collapsed) {\n    event.preventDefault();\n    return;\n  }\n  this.saveUndoState(range);\n  const handled = extractRangeToClipboard(\n    event,\n    range,\n    root,\n    true,\n    this._config.willCutCopy,\n    null,\n    false\n  );\n  if (!handled) {\n    setTimeout(() => {\n      try {\n        this._ensureBottomLine();\n      } catch (error) {\n        this._config.didError(error);\n      }\n    }, 0);\n  }\n  this.setSelection(range);\n};\nvar _onCopy = function(event) {\n  extractRangeToClipboard(\n    event,\n    this.getSelection(),\n    this._root,\n    false,\n    this._config.willCutCopy,\n    null,\n    false\n  );\n};\nvar _monitorShiftKey = function(event) {\n  this._isShiftDown = event.shiftKey;\n};\nvar _onPaste = function(event) {\n  const clipboardData = event.clipboardData;\n  const items = clipboardData?.items;\n  const choosePlain = this._isShiftDown;\n  let hasRTF = false;\n  let hasImage = false;\n  let plainItem = null;\n  let htmlItem = null;\n  if (items) {\n    let l = items.length;\n    while (l--) {\n      const item = items[l];\n      const type = item.type;\n      if (type === \"text/html\") {\n        htmlItem = item;\n      } else if (type === \"text/plain\" || type === \"text/uri-list\") {\n        plainItem = item;\n      } else if (type === \"text/rtf\") {\n        hasRTF = true;\n      } else if (/^image\\/.*/.test(type)) {\n        hasImage = true;\n      }\n    }\n    if (hasImage && !(hasRTF && htmlItem)) {\n      event.preventDefault();\n      this.fireEvent(\"pasteImage\", {\n        clipboardData\n      });\n      return;\n    }\n    if (!isLegacyEdge) {\n      event.preventDefault();\n      if (htmlItem && (!choosePlain || !plainItem)) {\n        htmlItem.getAsString((html) => {\n          this.insertHTML(html, true);\n        });\n      } else if (plainItem) {\n        plainItem.getAsString((text) => {\n          let isLink = false;\n          const range2 = this.getSelection();\n          if (!range2.collapsed && notWS.test(range2.toString())) {\n            const match = this.linkRegExp.exec(text);\n            isLink = !!match && match[0].length === text.length;\n          }\n          if (isLink) {\n            this.makeLink(text);\n          } else {\n            this.insertPlainText(text, true);\n          }\n        });\n      }\n      return;\n    }\n  }\n  const types = clipboardData?.types;\n  if (!isLegacyEdge && types && (indexOf.call(types, \"text/html\") > -1 || !isGecko && indexOf.call(types, \"text/plain\") > -1 && indexOf.call(types, \"text/rtf\") < 0)) {\n    event.preventDefault();\n    let data;\n    if (!choosePlain && (data = clipboardData.getData(\"text/html\"))) {\n      this.insertHTML(data, true);\n    } else if ((data = clipboardData.getData(\"text/plain\")) || (data = clipboardData.getData(\"text/uri-list\"))) {\n      this.insertPlainText(data, true);\n    }\n    return;\n  }\n  const body = document.body;\n  const range = this.getSelection();\n  const startContainer = range.startContainer;\n  const startOffset = range.startOffset;\n  const endContainer = range.endContainer;\n  const endOffset = range.endOffset;\n  let pasteArea = createElement(\"DIV\", {\n    contenteditable: \"true\",\n    style: \"position:fixed; overflow:hidden; top:0; right:100%; width:1px; height:1px;\"\n  });\n  body.appendChild(pasteArea);\n  range.selectNodeContents(pasteArea);\n  this.setSelection(range);\n  setTimeout(() => {\n    try {\n      let html = \"\";\n      let next = pasteArea;\n      let first;\n      while (pasteArea = next) {\n        next = pasteArea.nextSibling;\n        detach(pasteArea);\n        first = pasteArea.firstChild;\n        if (first && first === pasteArea.lastChild && first instanceof HTMLDivElement) {\n          pasteArea = first;\n        }\n        html += pasteArea.innerHTML;\n      }\n      this.setSelection(\n        createRange(\n          startContainer,\n          startOffset,\n          endContainer,\n          endOffset\n        )\n      );\n      if (html) {\n        this.insertHTML(html, true);\n      }\n    } catch (error) {\n      this._config.didError(error);\n    }\n  }, 0);\n};\nvar _onDrop = function(event) {\n  if (!event.dataTransfer) {\n    return;\n  }\n  const types = event.dataTransfer.types;\n  let l = types.length;\n  let hasPlain = false;\n  let hasHTML = false;\n  while (l--) {\n    switch (types[l]) {\n      case \"text/plain\":\n        hasPlain = true;\n        break;\n      case \"text/html\":\n        hasHTML = true;\n        break;\n      default:\n        return;\n    }\n  }\n  if (hasHTML || hasPlain && this.saveUndoState) {\n    this.saveUndoState();\n  }\n};\n\n// source/keyboard/Enter.ts\nvar Enter = (self, event, range) => {\n  event.preventDefault();\n  self.splitBlock(event.shiftKey, range);\n};\n\n// source/keyboard/KeyHelpers.ts\nvar afterDelete = (self, range) => {\n  try {\n    if (!range) {\n      range = self.getSelection();\n    }\n    let node = range.startContainer;\n    if (node instanceof Text) {\n      node = node.parentNode;\n    }\n    let parent = node;\n    while (isInline(parent) && (!parent.textContent || parent.textContent === ZWS)) {\n      node = parent;\n      parent = node.parentNode;\n    }\n    if (node !== parent) {\n      range.setStart(\n        parent,\n        Array.from(parent.childNodes).indexOf(node)\n      );\n      range.collapse(true);\n      parent.removeChild(node);\n      if (!isBlock(parent)) {\n        parent = getPreviousBlock(parent, self._root) || self._root;\n      }\n      fixCursor(parent);\n      moveRangeBoundariesDownTree(range);\n    }\n    if (node === self._root && (node = node.firstChild) && node.nodeName === \"BR\") {\n      detach(node);\n    }\n    self._ensureBottomLine();\n    self.setSelection(range);\n    self._updatePath(range, true);\n  } catch (error) {\n    self._config.didError(error);\n  }\n};\nvar detachUneditableNode = (node, root) => {\n  let parent;\n  while (parent = node.parentNode) {\n    if (parent === root || parent.isContentEditable) {\n      break;\n    }\n    node = parent;\n  }\n  detach(node);\n};\nvar linkifyText = (self, textNode, offset) => {\n  if (getNearest(textNode, self._root, \"A\")) {\n    return;\n  }\n  const data = textNode.data || \"\";\n  const searchFrom = Math.max(\n    data.lastIndexOf(\" \", offset - 1),\n    data.lastIndexOf(\"\\xA0\", offset - 1)\n  ) + 1;\n  const searchText = data.slice(searchFrom, offset);\n  const match = self.linkRegExp.exec(searchText);\n  if (match) {\n    const selection = self.getSelection();\n    self._docWasChanged();\n    self._recordUndoState(selection);\n    self._getRangeAndRemoveBookmark(selection);\n    const index = searchFrom + match.index;\n    const endIndex = index + match[0].length;\n    const needsSelectionUpdate = selection.startContainer === textNode;\n    const newSelectionOffset = selection.startOffset - endIndex;\n    if (index) {\n      textNode = textNode.splitText(index);\n    }\n    const defaultAttributes = self._config.tagAttributes.a;\n    const link = createElement(\n      \"A\",\n      Object.assign(\n        {\n          href: match[1] ? /^(?:ht|f)tps?:/i.test(match[1]) ? match[1] : \"http://\" + match[1] : \"mailto:\" + match[0]\n        },\n        defaultAttributes\n      )\n    );\n    link.textContent = data.slice(index, endIndex);\n    textNode.parentNode.insertBefore(link, textNode);\n    textNode.data = data.slice(endIndex);\n    if (needsSelectionUpdate) {\n      selection.setStart(textNode, newSelectionOffset);\n      selection.setEnd(textNode, newSelectionOffset);\n    }\n    self.setSelection(selection);\n  }\n};\n\n// source/keyboard/Backspace.ts\nvar Backspace = (self, event, range) => {\n  const root = self._root;\n  self._removeZWS();\n  self.saveUndoState(range);\n  if (!range.collapsed) {\n    event.preventDefault();\n    deleteContentsOfRange(range, root);\n    afterDelete(self, range);\n  } else if (rangeDoesStartAtBlockBoundary(range, root)) {\n    event.preventDefault();\n    const startBlock = getStartBlockOfRange(range, root);\n    if (!startBlock) {\n      return;\n    }\n    let current = startBlock;\n    fixContainer(current.parentNode, root);\n    const previous = getPreviousBlock(current, root);\n    if (previous) {\n      if (!previous.isContentEditable) {\n        detachUneditableNode(previous, root);\n        return;\n      }\n      mergeWithBlock(previous, current, range, root);\n      current = previous.parentNode;\n      while (current !== root && !current.nextSibling) {\n        current = current.parentNode;\n      }\n      if (current !== root && (current = current.nextSibling)) {\n        mergeContainers(current, root);\n      }\n      self.setSelection(range);\n    } else if (current) {\n      if (getNearest(current, root, \"UL\") || getNearest(current, root, \"OL\")) {\n        self.decreaseListLevel(range);\n        return;\n      } else if (getNearest(current, root, \"BLOCKQUOTE\")) {\n        self.removeQuote(range);\n        return;\n      }\n      self.setSelection(range);\n      self._updatePath(range, true);\n    }\n  } else {\n    moveRangeBoundariesDownTree(range);\n    const text = range.startContainer;\n    const offset = range.startOffset;\n    const a = text.parentNode;\n    if (text instanceof Text && a instanceof HTMLAnchorElement && offset && a.href.includes(text.data)) {\n      text.deleteData(offset - 1, 1);\n      self.setSelection(range);\n      self.removeLink();\n      event.preventDefault();\n    } else {\n      self.setSelection(range);\n      setTimeout(() => {\n        afterDelete(self);\n      }, 0);\n    }\n  }\n};\n\n// source/keyboard/Delete.ts\nvar Delete = (self, event, range) => {\n  const root = self._root;\n  let current;\n  let next;\n  let originalRange;\n  let cursorContainer;\n  let cursorOffset;\n  let nodeAfterCursor;\n  self._removeZWS();\n  self.saveUndoState(range);\n  if (!range.collapsed) {\n    event.preventDefault();\n    deleteContentsOfRange(range, root);\n    afterDelete(self, range);\n  } else if (rangeDoesEndAtBlockBoundary(range, root)) {\n    event.preventDefault();\n    current = getStartBlockOfRange(range, root);\n    if (!current) {\n      return;\n    }\n    fixContainer(current.parentNode, root);\n    next = getNextBlock(current, root);\n    if (next) {\n      if (!next.isContentEditable) {\n        detachUneditableNode(next, root);\n        return;\n      }\n      mergeWithBlock(current, next, range, root);\n      next = current.parentNode;\n      while (next !== root && !next.nextSibling) {\n        next = next.parentNode;\n      }\n      if (next !== root && (next = next.nextSibling)) {\n        mergeContainers(next, root);\n      }\n      self.setSelection(range);\n      self._updatePath(range, true);\n    }\n  } else {\n    originalRange = range.cloneRange();\n    moveRangeBoundariesUpTree(range, root, root, root);\n    cursorContainer = range.endContainer;\n    cursorOffset = range.endOffset;\n    if (cursorContainer instanceof Element) {\n      nodeAfterCursor = cursorContainer.childNodes[cursorOffset];\n      if (nodeAfterCursor && nodeAfterCursor.nodeName === \"IMG\") {\n        event.preventDefault();\n        detach(nodeAfterCursor);\n        moveRangeBoundariesDownTree(range);\n        afterDelete(self, range);\n        return;\n      }\n    }\n    self.setSelection(originalRange);\n    setTimeout(() => {\n      afterDelete(self);\n    }, 0);\n  }\n};\n\n// source/keyboard/Tab.ts\nvar Tab = (self, event, range) => {\n  const root = self._root;\n  self._removeZWS();\n  if (range.collapsed && rangeDoesStartAtBlockBoundary(range, root)) {\n    let node = getStartBlockOfRange(range, root);\n    let parent;\n    while (parent = node.parentNode) {\n      if (parent.nodeName === \"UL\" || parent.nodeName === \"OL\") {\n        event.preventDefault();\n        self.increaseListLevel(range);\n        break;\n      }\n      node = parent;\n    }\n  }\n};\nvar ShiftTab = (self, event, range) => {\n  const root = self._root;\n  self._removeZWS();\n  if (range.collapsed && rangeDoesStartAtBlockBoundary(range, root)) {\n    const node = range.startContainer;\n    if (getNearest(node, root, \"UL\") || getNearest(node, root, \"OL\")) {\n      event.preventDefault();\n      self.decreaseListLevel(range);\n    }\n  }\n};\n\n// source/keyboard/Space.ts\nvar Space = (self, _, range) => {\n  let node;\n  const root = self._root;\n  self._recordUndoState(range);\n  self._getRangeAndRemoveBookmark(range);\n  if (!range.collapsed) {\n    deleteContentsOfRange(range, root);\n    self._ensureBottomLine();\n    self.setSelection(range);\n    self._updatePath(range, true);\n  }\n  node = range.endContainer;\n  if (range.endOffset === getLength(node)) {\n    do {\n      if (node.nodeName === \"A\") {\n        range.setStartAfter(node);\n        break;\n      }\n    } while (!node.nextSibling && (node = node.parentNode) && node !== root);\n  }\n  if (self._config.addLinks) {\n    const linkRange = range.cloneRange();\n    moveRangeBoundariesDownTree(linkRange);\n    const textNode = linkRange.startContainer;\n    const offset = linkRange.startOffset;\n    setTimeout(() => {\n      linkifyText(self, textNode, offset);\n    }, 0);\n  }\n  self.setSelection(range);\n};\n\n// source/keyboard/KeyHandlers.ts\nvar keys = {\n  8: \"Backspace\",\n  9: \"Tab\",\n  13: \"Enter\",\n  27: \"Escape\",\n  32: \"Space\",\n  33: \"PageUp\",\n  34: \"PageDown\",\n  37: \"ArrowLeft\",\n  38: \"ArrowUp\",\n  39: \"ArrowRight\",\n  40: \"ArrowDown\",\n  46: \"Delete\",\n  191: \"/\",\n  219: \"[\",\n  220: \"\\\\\",\n  221: \"]\"\n};\nvar _onKey = function(event) {\n  const code = event.keyCode;\n  let key = keys[code];\n  let modifiers = \"\";\n  const range = this.getSelection();\n  if (event.defaultPrevented) {\n    return;\n  }\n  if (!key) {\n    key = String.fromCharCode(code).toLowerCase();\n    if (!/^[A-Za-z0-9]$/.test(key)) {\n      key = \"\";\n    }\n  }\n  if (111 < code && code < 124) {\n    key = \"F\" + (code - 111);\n  }\n  if (key !== \"Backspace\" && key !== \"Delete\") {\n    if (event.altKey) {\n      modifiers += \"Alt-\";\n    }\n    if (event.ctrlKey) {\n      modifiers += \"Ctrl-\";\n    }\n    if (event.metaKey) {\n      modifiers += \"Meta-\";\n    }\n    if (event.shiftKey) {\n      modifiers += \"Shift-\";\n    }\n  }\n  if (isWin && event.shiftKey && key === \"Delete\") {\n    modifiers += \"Shift-\";\n  }\n  key = modifiers + key;\n  if (this._keyHandlers[key]) {\n    this._keyHandlers[key](this, event, range);\n  } else if (!range.collapsed && // !event.isComposing stops us from blatting Kana-Kanji conversion in\n  // Safari\n  !event.isComposing && !event.ctrlKey && !event.metaKey && (event.key || key).length === 1) {\n    this.saveUndoState(range);\n    deleteContentsOfRange(range, this._root);\n    this._ensureBottomLine();\n    this.setSelection(range);\n    this._updatePath(range, true);\n  }\n};\nvar keyHandlers = {\n  \"Backspace\": Backspace,\n  \"Delete\": Delete,\n  \"Tab\": Tab,\n  \"Shift-Tab\": ShiftTab,\n  \"Space\": Space,\n  \"ArrowLeft\"(self) {\n    self._removeZWS();\n  },\n  \"ArrowRight\"(self, event, range) {\n    self._removeZWS();\n    const root = self.getRoot();\n    if (rangeDoesEndAtBlockBoundary(range, root)) {\n      moveRangeBoundariesDownTree(range);\n      let node = range.endContainer;\n      do {\n        if (node.nodeName === \"CODE\") {\n          let next = node.nextSibling;\n          if (!(next instanceof Text)) {\n            const textNode = document.createTextNode(\"\\xA0\");\n            node.parentNode.insertBefore(textNode, next);\n            next = textNode;\n          }\n          range.setStart(next, 1);\n          self.setSelection(range);\n          event.preventDefault();\n          break;\n        }\n      } while (!node.nextSibling && (node = node.parentNode) && node !== root);\n    }\n  }\n};\nif (!supportsInputEvents) {\n  keyHandlers.Enter = Enter;\n  keyHandlers[\"Shift-Enter\"] = Enter;\n}\nif (!isMac && !isIOS) {\n  keyHandlers.PageUp = (self) => {\n    self.moveCursorToStart();\n  };\n  keyHandlers.PageDown = (self) => {\n    self.moveCursorToEnd();\n  };\n}\nvar mapKeyToFormat = (tag, remove) => {\n  remove = remove || null;\n  return (self, event) => {\n    event.preventDefault();\n    const range = self.getSelection();\n    if (self.hasFormat(tag, null, range)) {\n      self.changeFormat(null, { tag }, range);\n    } else {\n      self.changeFormat({ tag }, remove, range);\n    }\n  };\n};\nkeyHandlers[ctrlKey + \"b\"] = mapKeyToFormat(\"B\");\nkeyHandlers[ctrlKey + \"i\"] = mapKeyToFormat(\"I\");\nkeyHandlers[ctrlKey + \"u\"] = mapKeyToFormat(\"U\");\nkeyHandlers[ctrlKey + \"Shift-7\"] = mapKeyToFormat(\"S\");\nkeyHandlers[ctrlKey + \"Shift-5\"] = mapKeyToFormat(\"SUB\", { tag: \"SUP\" });\nkeyHandlers[ctrlKey + \"Shift-6\"] = mapKeyToFormat(\"SUP\", { tag: \"SUB\" });\nkeyHandlers[ctrlKey + \"Shift-8\"] = (self, event) => {\n  event.preventDefault();\n  const path = self.getPath();\n  if (!/(?:^|>)UL/.test(path)) {\n    self.makeUnorderedList();\n  } else {\n    self.removeList();\n  }\n};\nkeyHandlers[ctrlKey + \"Shift-9\"] = (self, event) => {\n  event.preventDefault();\n  const path = self.getPath();\n  if (!/(?:^|>)OL/.test(path)) {\n    self.makeOrderedList();\n  } else {\n    self.removeList();\n  }\n};\nkeyHandlers[ctrlKey + \"[\"] = (self, event) => {\n  event.preventDefault();\n  const path = self.getPath();\n  if (/(?:^|>)BLOCKQUOTE/.test(path) || !/(?:^|>)[OU]L/.test(path)) {\n    self.decreaseQuoteLevel();\n  } else {\n    self.decreaseListLevel();\n  }\n};\nkeyHandlers[ctrlKey + \"]\"] = (self, event) => {\n  event.preventDefault();\n  const path = self.getPath();\n  if (/(?:^|>)BLOCKQUOTE/.test(path) || !/(?:^|>)[OU]L/.test(path)) {\n    self.increaseQuoteLevel();\n  } else {\n    self.increaseListLevel();\n  }\n};\nkeyHandlers[ctrlKey + \"d\"] = (self, event) => {\n  event.preventDefault();\n  self.toggleCode();\n};\nkeyHandlers[ctrlKey + \"z\"] = (self, event) => {\n  event.preventDefault();\n  self.undo();\n};\nkeyHandlers[ctrlKey + \"y\"] = keyHandlers[ctrlKey + \"Shift-z\"] = (self, event) => {\n  event.preventDefault();\n  self.redo();\n};\n\n// source/Editor.ts\nvar Squire = class {\n  _root;\n  _config;\n  _isFocused;\n  _lastSelection;\n  _willRestoreSelection;\n  _mayHaveZWS;\n  _lastAnchorNode;\n  _lastFocusNode;\n  _path;\n  _events;\n  _undoIndex;\n  _undoStack;\n  _undoStackLength;\n  _isInUndoState;\n  _ignoreChange;\n  _ignoreAllChanges;\n  _isShiftDown;\n  _keyHandlers;\n  _mutation;\n  constructor(root, config) {\n    this._root = root;\n    this._config = this._makeConfig(config);\n    this._isFocused = false;\n    this._lastSelection = createRange(root, 0);\n    this._willRestoreSelection = false;\n    this._mayHaveZWS = false;\n    this._lastAnchorNode = null;\n    this._lastFocusNode = null;\n    this._path = \"\";\n    this._events = /* @__PURE__ */ new Map();\n    this._undoIndex = -1;\n    this._undoStack = [];\n    this._undoStackLength = 0;\n    this._isInUndoState = false;\n    this._ignoreChange = false;\n    this._ignoreAllChanges = false;\n    this.addEventListener(\"selectionchange\", this._updatePathOnEvent);\n    this.addEventListener(\"blur\", this._enableRestoreSelection);\n    this.addEventListener(\"mousedown\", this._disableRestoreSelection);\n    this.addEventListener(\"touchstart\", this._disableRestoreSelection);\n    this.addEventListener(\"focus\", this._restoreSelection);\n    this._isShiftDown = false;\n    this.addEventListener(\"cut\", _onCut);\n    this.addEventListener(\"copy\", _onCopy);\n    this.addEventListener(\"paste\", _onPaste);\n    this.addEventListener(\"drop\", _onDrop);\n    this.addEventListener(\n      \"keydown\",\n      _monitorShiftKey\n    );\n    this.addEventListener(\"keyup\", _monitorShiftKey);\n    this.addEventListener(\"keydown\", _onKey);\n    this._keyHandlers = Object.create(keyHandlers);\n    const mutation = new MutationObserver(() => this._docWasChanged());\n    mutation.observe(root, {\n      childList: true,\n      attributes: true,\n      characterData: true,\n      subtree: true\n    });\n    this._mutation = mutation;\n    root.setAttribute(\"contenteditable\", \"true\");\n    try {\n      document.execCommand(\"enableObjectResizing\", false, \"false\");\n      document.execCommand(\"enableInlineTableEditing\", false, \"false\");\n    } catch (_) {\n    }\n    this.addEventListener(\n      \"beforeinput\",\n      this._beforeInput\n    );\n    this.setHTML(\"\");\n  }\n  destroy() {\n    this._events.forEach((_, type) => {\n      this.removeEventListener(type);\n    });\n    this._mutation.disconnect();\n    this._undoIndex = -1;\n    this._undoStack = [];\n    this._undoStackLength = 0;\n  }\n  _makeConfig(userConfig) {\n    const config = {\n      blockTag: \"DIV\",\n      blockAttributes: null,\n      tagAttributes: {},\n      classNames: {\n        color: \"color\",\n        fontFamily: \"font\",\n        fontSize: \"size\",\n        highlight: \"highlight\"\n      },\n      undo: {\n        documentSizeThreshold: -1,\n        // -1 means no threshold\n        undoLimit: -1\n        // -1 means no limit\n      },\n      addLinks: true,\n      willCutCopy: null,\n      sanitizeToDOMFragment: (html) => {\n        const frag = DOMPurify.sanitize(html, {\n          ALLOW_UNKNOWN_PROTOCOLS: true,\n          WHOLE_DOCUMENT: false,\n          RETURN_DOM: true,\n          RETURN_DOM_FRAGMENT: true,\n          FORCE_BODY: false\n        });\n        return frag ? document.importNode(frag, true) : document.createDocumentFragment();\n      },\n      didError: (error) => console.log(error)\n    };\n    if (userConfig) {\n      Object.assign(config, userConfig);\n      config.blockTag = config.blockTag.toUpperCase();\n    }\n    return config;\n  }\n  setKeyHandler(key, fn) {\n    this._keyHandlers[key] = fn;\n    return this;\n  }\n  _beforeInput(event) {\n    switch (event.inputType) {\n      case \"insertText\":\n        if (isAndroid && event.data && event.data.includes(\"\\n\")) {\n          event.preventDefault();\n        }\n        break;\n      case \"insertLineBreak\":\n        event.preventDefault();\n        this.splitBlock(true);\n        break;\n      case \"insertParagraph\":\n        event.preventDefault();\n        this.splitBlock(false);\n        break;\n      case \"insertOrderedList\":\n        event.preventDefault();\n        this.makeOrderedList();\n        break;\n      case \"insertUnoderedList\":\n        event.preventDefault();\n        this.makeUnorderedList();\n        break;\n      case \"historyUndo\":\n        event.preventDefault();\n        this.undo();\n        break;\n      case \"historyRedo\":\n        event.preventDefault();\n        this.redo();\n        break;\n      case \"formatBold\":\n        event.preventDefault();\n        this.bold();\n        break;\n      case \"formaItalic\":\n        event.preventDefault();\n        this.italic();\n        break;\n      case \"formatUnderline\":\n        event.preventDefault();\n        this.underline();\n        break;\n      case \"formatStrikeThrough\":\n        event.preventDefault();\n        this.strikethrough();\n        break;\n      case \"formatSuperscript\":\n        event.preventDefault();\n        this.superscript();\n        break;\n      case \"formatSubscript\":\n        event.preventDefault();\n        this.subscript();\n        break;\n      case \"formatJustifyFull\":\n      case \"formatJustifyCenter\":\n      case \"formatJustifyRight\":\n      case \"formatJustifyLeft\": {\n        event.preventDefault();\n        let alignment = event.inputType.slice(13).toLowerCase();\n        if (alignment === \"full\") {\n          alignment = \"justify\";\n        }\n        this.setTextAlignment(alignment);\n        break;\n      }\n      case \"formatRemove\":\n        event.preventDefault();\n        this.removeAllFormatting();\n        break;\n      case \"formatSetBlockTextDirection\": {\n        event.preventDefault();\n        let dir = event.data;\n        if (dir === \"null\") {\n          dir = null;\n        }\n        this.setTextDirection(dir);\n        break;\n      }\n      case \"formatBackColor\":\n        event.preventDefault();\n        this.setHighlightColor(event.data);\n        break;\n      case \"formatFontColor\":\n        event.preventDefault();\n        this.setTextColor(event.data);\n        break;\n      case \"formatFontName\":\n        event.preventDefault();\n        this.setFontFace(event.data);\n        break;\n    }\n  }\n  // --- Events\n  handleEvent(event) {\n    this.fireEvent(event.type, event);\n  }\n  fireEvent(type, detail) {\n    let handlers = this._events.get(type);\n    if (/^(?:focus|blur)/.test(type)) {\n      const isFocused = this._root === document.activeElement;\n      if (type === \"focus\") {\n        if (!isFocused || this._isFocused) {\n          return this;\n        }\n        this._isFocused = true;\n      } else {\n        if (isFocused || !this._isFocused) {\n          return this;\n        }\n        this._isFocused = false;\n      }\n    }\n    if (handlers) {\n      const event = detail instanceof Event ? detail : new CustomEvent(type, {\n        detail\n      });\n      handlers = handlers.slice();\n      for (const handler of handlers) {\n        try {\n          if (\"handleEvent\" in handler) {\n            handler.handleEvent(event);\n          } else {\n            handler.call(this, event);\n          }\n        } catch (error) {\n          this._config.didError(error);\n        }\n      }\n    }\n    return this;\n  }\n  /**\n   * Subscribing to these events won't automatically add a listener to the\n   * document node, since these events are fired in a custom manner by the\n   * editor code.\n   */\n  customEvents = /* @__PURE__ */ new Set([\n    \"pathChange\",\n    \"select\",\n    \"input\",\n    \"pasteImage\",\n    \"undoStateChange\"\n  ]);\n  addEventListener(type, fn) {\n    let handlers = this._events.get(type);\n    let target = this._root;\n    if (!handlers) {\n      handlers = [];\n      this._events.set(type, handlers);\n      if (!this.customEvents.has(type)) {\n        if (type === \"selectionchange\") {\n          target = document;\n        }\n        target.addEventListener(type, this, true);\n      }\n    }\n    handlers.push(fn);\n    return this;\n  }\n  removeEventListener(type, fn) {\n    const handlers = this._events.get(type);\n    let target = this._root;\n    if (handlers) {\n      if (fn) {\n        let l = handlers.length;\n        while (l--) {\n          if (handlers[l] === fn) {\n            handlers.splice(l, 1);\n          }\n        }\n      } else {\n        handlers.length = 0;\n      }\n      if (!handlers.length) {\n        this._events.delete(type);\n        if (!this.customEvents.has(type)) {\n          if (type === \"selectionchange\") {\n            target = document;\n          }\n          target.removeEventListener(type, this, true);\n        }\n      }\n    }\n    return this;\n  }\n  // --- Focus\n  focus() {\n    this._root.focus({ preventScroll: true });\n    return this;\n  }\n  blur() {\n    this._root.blur();\n    return this;\n  }\n  // --- Selection and bookmarking\n  _enableRestoreSelection() {\n    this._willRestoreSelection = true;\n  }\n  _disableRestoreSelection() {\n    this._willRestoreSelection = false;\n  }\n  _restoreSelection() {\n    if (this._willRestoreSelection) {\n      this.setSelection(this._lastSelection);\n    }\n  }\n  // ---\n  _removeZWS() {\n    if (!this._mayHaveZWS) {\n      return;\n    }\n    removeZWS(this._root);\n    this._mayHaveZWS = false;\n  }\n  // ---\n  startSelectionId = \"squire-selection-start\";\n  endSelectionId = \"squire-selection-end\";\n  _saveRangeToBookmark(range) {\n    let startNode = createElement(\"INPUT\", {\n      id: this.startSelectionId,\n      type: \"hidden\"\n    });\n    let endNode = createElement(\"INPUT\", {\n      id: this.endSelectionId,\n      type: \"hidden\"\n    });\n    let temp;\n    insertNodeInRange(range, startNode);\n    range.collapse(false);\n    insertNodeInRange(range, endNode);\n    if (startNode.compareDocumentPosition(endNode) & Node.DOCUMENT_POSITION_PRECEDING) {\n      startNode.id = this.endSelectionId;\n      endNode.id = this.startSelectionId;\n      temp = startNode;\n      startNode = endNode;\n      endNode = temp;\n    }\n    range.setStartAfter(startNode);\n    range.setEndBefore(endNode);\n  }\n  _getRangeAndRemoveBookmark(range) {\n    const root = this._root;\n    const start = root.querySelector(\"#\" + this.startSelectionId);\n    const end = root.querySelector(\"#\" + this.endSelectionId);\n    if (start && end) {\n      let startContainer = start.parentNode;\n      let endContainer = end.parentNode;\n      const startOffset = Array.from(startContainer.childNodes).indexOf(\n        start\n      );\n      let endOffset = Array.from(endContainer.childNodes).indexOf(end);\n      if (startContainer === endContainer) {\n        endOffset -= 1;\n      }\n      start.remove();\n      end.remove();\n      if (!range) {\n        range = document.createRange();\n      }\n      range.setStart(startContainer, startOffset);\n      range.setEnd(endContainer, endOffset);\n      mergeInlines(startContainer, range);\n      if (startContainer !== endContainer) {\n        mergeInlines(endContainer, range);\n      }\n      if (range.collapsed) {\n        startContainer = range.startContainer;\n        if (startContainer instanceof Text) {\n          endContainer = startContainer.childNodes[range.startOffset];\n          if (!endContainer || !(endContainer instanceof Text)) {\n            endContainer = startContainer.childNodes[range.startOffset - 1];\n          }\n          if (endContainer && endContainer instanceof Text) {\n            range.setStart(endContainer, 0);\n            range.collapse(true);\n          }\n        }\n      }\n    }\n    return range || null;\n  }\n  getSelection() {\n    const selection = window.getSelection();\n    const root = this._root;\n    let range = null;\n    if (this._isFocused && selection && selection.rangeCount) {\n      range = selection.getRangeAt(0).cloneRange();\n      const startContainer = range.startContainer;\n      const endContainer = range.endContainer;\n      if (startContainer && isLeaf(startContainer)) {\n        range.setStartBefore(startContainer);\n      }\n      if (endContainer && isLeaf(endContainer)) {\n        range.setEndBefore(endContainer);\n      }\n    }\n    if (range && root.contains(range.commonAncestorContainer)) {\n      this._lastSelection = range;\n    } else {\n      range = this._lastSelection;\n      if (!document.contains(range.commonAncestorContainer)) {\n        range = null;\n      }\n    }\n    if (!range) {\n      range = createRange(root.firstElementChild || root, 0);\n    }\n    return range;\n  }\n  setSelection(range) {\n    this._lastSelection = range;\n    if (!this._isFocused) {\n      this._enableRestoreSelection();\n    } else {\n      const selection = window.getSelection();\n      if (selection) {\n        if (\"setBaseAndExtent\" in Selection.prototype) {\n          selection.setBaseAndExtent(\n            range.startContainer,\n            range.startOffset,\n            range.endContainer,\n            range.endOffset\n          );\n        } else {\n          selection.removeAllRanges();\n          selection.addRange(range);\n        }\n      }\n    }\n    return this;\n  }\n  // ---\n  _moveCursorTo(toStart) {\n    const root = this._root;\n    const range = createRange(root, toStart ? 0 : root.childNodes.length);\n    moveRangeBoundariesDownTree(range);\n    this.setSelection(range);\n    return this;\n  }\n  moveCursorToStart() {\n    return this._moveCursorTo(true);\n  }\n  moveCursorToEnd() {\n    return this._moveCursorTo(false);\n  }\n  // ---\n  getCursorPosition() {\n    const range = this.getSelection();\n    let rect = range.getBoundingClientRect();\n    if (rect && !rect.top) {\n      this._ignoreChange = true;\n      const node = createElement(\"SPAN\");\n      node.textContent = ZWS;\n      insertNodeInRange(range, node);\n      rect = node.getBoundingClientRect();\n      const parent = node.parentNode;\n      parent.removeChild(node);\n      mergeInlines(parent, range);\n    }\n    return rect;\n  }\n  // --- Path\n  getPath() {\n    return this._path;\n  }\n  _updatePathOnEvent() {\n    if (this._isFocused) {\n      this._updatePath(this.getSelection());\n    }\n  }\n  _updatePath(range, force) {\n    const anchor = range.startContainer;\n    const focus = range.endContainer;\n    let newPath;\n    if (force || anchor !== this._lastAnchorNode || focus !== this._lastFocusNode) {\n      this._lastAnchorNode = anchor;\n      this._lastFocusNode = focus;\n      newPath = anchor && focus ? anchor === focus ? this._getPath(focus) : \"(selection)\" : \"\";\n      if (this._path !== newPath) {\n        this._path = newPath;\n        this.fireEvent(\"pathChange\", {\n          path: newPath\n        });\n      }\n    }\n    this.fireEvent(range.collapsed ? \"cursor\" : \"select\", {\n      range\n    });\n  }\n  _getPath(node) {\n    const root = this._root;\n    const config = this._config;\n    let path = \"\";\n    if (node && node !== root) {\n      const parent = node.parentNode;\n      path = parent ? this._getPath(parent) : \"\";\n      if (node instanceof HTMLElement) {\n        const id = node.id;\n        const classList = node.classList;\n        const classNames = Array.from(classList).sort();\n        const dir = node.dir;\n        const styleNames = config.classNames;\n        path += (path ? \">\" : \"\") + node.nodeName;\n        if (id) {\n          path += \"#\" + id;\n        }\n        if (classNames.length) {\n          path += \".\";\n          path += classNames.join(\".\");\n        }\n        if (dir) {\n          path += \"[dir=\" + dir + \"]\";\n        }\n        if (classList.contains(styleNames.highlight)) {\n          path += \"[backgroundColor=\" + node.style.backgroundColor.replace(/ /g, \"\") + \"]\";\n        }\n        if (classList.contains(styleNames.color)) {\n          path += \"[color=\" + node.style.color.replace(/ /g, \"\") + \"]\";\n        }\n        if (classList.contains(styleNames.fontFamily)) {\n          path += \"[fontFamily=\" + node.style.fontFamily.replace(/ /g, \"\") + \"]\";\n        }\n        if (classList.contains(styleNames.fontSize)) {\n          path += \"[fontSize=\" + node.style.fontSize + \"]\";\n        }\n      }\n    }\n    return path;\n  }\n  // --- History\n  modifyDocument(modificationFn) {\n    const mutation = this._mutation;\n    if (mutation) {\n      if (mutation.takeRecords().length) {\n        this._docWasChanged();\n      }\n      mutation.disconnect();\n    }\n    this._ignoreAllChanges = true;\n    modificationFn();\n    this._ignoreAllChanges = false;\n    if (mutation) {\n      mutation.observe(this._root, {\n        childList: true,\n        attributes: true,\n        characterData: true,\n        subtree: true\n      });\n      this._ignoreChange = false;\n    }\n    return this;\n  }\n  _docWasChanged() {\n    resetNodeCategoryCache();\n    this._mayHaveZWS = true;\n    if (this._ignoreAllChanges) {\n      return;\n    }\n    if (this._ignoreChange) {\n      this._ignoreChange = false;\n      return;\n    }\n    if (this._isInUndoState) {\n      this._isInUndoState = false;\n      this.fireEvent(\"undoStateChange\", {\n        canUndo: true,\n        canRedo: false\n      });\n    }\n    this.fireEvent(\"input\");\n  }\n  /**\n   * Leaves bookmark.\n   */\n  _recordUndoState(range, replace) {\n    if (!this._isInUndoState || replace) {\n      let undoIndex = this._undoIndex;\n      const undoStack = this._undoStack;\n      const undoConfig = this._config.undo;\n      const undoThreshold = undoConfig.documentSizeThreshold;\n      const undoLimit = undoConfig.undoLimit;\n      if (!replace) {\n        undoIndex += 1;\n      }\n      if (undoIndex < this._undoStackLength) {\n        undoStack.length = this._undoStackLength = undoIndex;\n      }\n      if (range) {\n        this._saveRangeToBookmark(range);\n      }\n      const html = this._getRawHTML();\n      if (undoThreshold > -1 && html.length * 2 > undoThreshold) {\n        if (undoLimit > -1 && undoIndex > undoLimit) {\n          undoStack.splice(0, undoIndex - undoLimit);\n          undoIndex = undoLimit;\n          this._undoStackLength = undoLimit;\n        }\n      }\n      undoStack[undoIndex] = html;\n      this._undoIndex = undoIndex;\n      this._undoStackLength += 1;\n      this._isInUndoState = true;\n    }\n    return this;\n  }\n  saveUndoState(range) {\n    if (!range) {\n      range = this.getSelection();\n    }\n    this._recordUndoState(range, this._isInUndoState);\n    this._getRangeAndRemoveBookmark(range);\n    return this;\n  }\n  undo() {\n    if (this._undoIndex !== 0 || !this._isInUndoState) {\n      this._recordUndoState(this.getSelection(), false);\n      this._undoIndex -= 1;\n      this._setRawHTML(this._undoStack[this._undoIndex]);\n      const range = this._getRangeAndRemoveBookmark();\n      if (range) {\n        this.setSelection(range);\n      }\n      this._isInUndoState = true;\n      this.fireEvent(\"undoStateChange\", {\n        canUndo: this._undoIndex !== 0,\n        canRedo: true\n      });\n      this.fireEvent(\"input\");\n    }\n    return this;\n  }\n  redo() {\n    const undoIndex = this._undoIndex;\n    const undoStackLength = this._undoStackLength;\n    if (undoIndex + 1 < undoStackLength && this._isInUndoState) {\n      this._undoIndex += 1;\n      this._setRawHTML(this._undoStack[this._undoIndex]);\n      const range = this._getRangeAndRemoveBookmark();\n      if (range) {\n        this.setSelection(range);\n      }\n      this.fireEvent(\"undoStateChange\", {\n        canUndo: true,\n        canRedo: undoIndex + 2 < undoStackLength\n      });\n      this.fireEvent(\"input\");\n    }\n    return this;\n  }\n  // --- Get and set data\n  getRoot() {\n    return this._root;\n  }\n  _getRawHTML() {\n    return this._root.innerHTML;\n  }\n  _setRawHTML(html) {\n    const root = this._root;\n    root.innerHTML = html;\n    let node = root;\n    const child = node.firstChild;\n    if (!child || child.nodeName === \"BR\") {\n      const block = this.createDefaultBlock();\n      if (child) {\n        node.replaceChild(block, child);\n      } else {\n        node.appendChild(block);\n      }\n    } else {\n      while (node = getNextBlock(node, root)) {\n        fixCursor(node);\n      }\n    }\n    this._ignoreChange = true;\n    return this;\n  }\n  getHTML(withBookmark) {\n    let range;\n    if (withBookmark) {\n      range = this.getSelection();\n      this._saveRangeToBookmark(range);\n    }\n    const html = this._getRawHTML().replace(/\\u200B/g, \"\");\n    if (withBookmark) {\n      this._getRangeAndRemoveBookmark(range);\n    }\n    return html;\n  }\n  setHTML(html) {\n    const frag = this._config.sanitizeToDOMFragment(html, this);\n    const root = this._root;\n    cleanTree(frag, this._config);\n    cleanupBRs(frag, root, false);\n    fixContainer(frag, root);\n    let node = frag;\n    let child = node.firstChild;\n    if (!child || child.nodeName === \"BR\") {\n      const block = this.createDefaultBlock();\n      if (child) {\n        node.replaceChild(block, child);\n      } else {\n        node.appendChild(block);\n      }\n    } else {\n      while (node = getNextBlock(node, root)) {\n        fixCursor(node);\n      }\n    }\n    this._ignoreChange = true;\n    while (child = root.lastChild) {\n      root.removeChild(child);\n    }\n    root.appendChild(frag);\n    this._undoIndex = -1;\n    this._undoStack.length = 0;\n    this._undoStackLength = 0;\n    this._isInUndoState = false;\n    const range = this._getRangeAndRemoveBookmark() || createRange(root.firstElementChild || root, 0);\n    this.saveUndoState(range);\n    this.setSelection(range);\n    this._updatePath(range, true);\n    return this;\n  }\n  /**\n   * Insert HTML at the cursor location. If the selection is not collapsed\n   * insertTreeFragmentIntoRange will delete the selection so that it is\n   * replaced by the html being inserted.\n   */\n  insertHTML(html, isPaste) {\n    const config = this._config;\n    let frag = config.sanitizeToDOMFragment(html, this);\n    const range = this.getSelection();\n    this.saveUndoState(range);\n    try {\n      const root = this._root;\n      if (config.addLinks) {\n        this.addDetectedLinks(frag, frag);\n      }\n      cleanTree(frag, this._config);\n      cleanupBRs(frag, root, false);\n      removeEmptyInlines(frag);\n      frag.normalize();\n      let node = frag;\n      while (node = getNextBlock(node, frag)) {\n        fixCursor(node);\n      }\n      let doInsert = true;\n      if (isPaste) {\n        const event = new CustomEvent(\"willPaste\", {\n          detail: {\n            fragment: frag\n          }\n        });\n        this.fireEvent(\"willPaste\", event);\n        frag = event.detail.fragment;\n        doInsert = !event.defaultPrevented;\n      }\n      if (doInsert) {\n        insertTreeFragmentIntoRange(range, frag, root);\n        range.collapse(false);\n        moveRangeBoundaryOutOf(range, \"A\", root);\n        this._ensureBottomLine();\n      }\n      this.setSelection(range);\n      this._updatePath(range, true);\n      if (isPaste) {\n        this.focus();\n      }\n    } catch (error) {\n      this._config.didError(error);\n    }\n    return this;\n  }\n  insertElement(el, range) {\n    if (!range) {\n      range = this.getSelection();\n    }\n    range.collapse(true);\n    if (isInline(el)) {\n      insertNodeInRange(range, el);\n      range.setStartAfter(el);\n    } else {\n      const root = this._root;\n      const startNode = getStartBlockOfRange(\n        range,\n        root\n      );\n      let splitNode = startNode || root;\n      let nodeAfterSplit = null;\n      while (splitNode !== root && !splitNode.nextSibling) {\n        splitNode = splitNode.parentNode;\n      }\n      if (splitNode !== root) {\n        const parent = splitNode.parentNode;\n        nodeAfterSplit = split(\n          parent,\n          splitNode.nextSibling,\n          root,\n          root\n        );\n      }\n      if (startNode && isEmptyBlock(startNode)) {\n        detach(startNode);\n      }\n      root.insertBefore(el, nodeAfterSplit);\n      const blankLine = this.createDefaultBlock();\n      root.insertBefore(blankLine, nodeAfterSplit);\n      range.setStart(blankLine, 0);\n      range.setEnd(blankLine, 0);\n      moveRangeBoundariesDownTree(range);\n    }\n    this.focus();\n    this.setSelection(range);\n    this._updatePath(range);\n    return this;\n  }\n  insertImage(src, attributes) {\n    const img = createElement(\n      \"IMG\",\n      Object.assign(\n        {\n          src\n        },\n        attributes\n      )\n    );\n    this.insertElement(img);\n    return img;\n  }\n  insertPlainText(plainText, isPaste) {\n    const range = this.getSelection();\n    if (range.collapsed && getNearest(range.startContainer, this._root, \"PRE\")) {\n      const startContainer = range.startContainer;\n      let offset = range.startOffset;\n      let textNode;\n      if (!startContainer || !(startContainer instanceof Text)) {\n        const text = document.createTextNode(\"\");\n        startContainer.insertBefore(\n          text,\n          startContainer.childNodes[offset]\n        );\n        textNode = text;\n        offset = 0;\n      } else {\n        textNode = startContainer;\n      }\n      let doInsert = true;\n      if (isPaste) {\n        const event = new CustomEvent(\"willPaste\", {\n          detail: {\n            text: plainText\n          }\n        });\n        this.fireEvent(\"willPaste\", event);\n        plainText = event.detail.text;\n        doInsert = !event.defaultPrevented;\n      }\n      if (doInsert) {\n        textNode.insertData(offset, plainText);\n        range.setStart(textNode, offset + plainText.length);\n        range.collapse(true);\n      }\n      this.setSelection(range);\n      return this;\n    }\n    const lines = plainText.split(\"\\n\");\n    const config = this._config;\n    const tag = config.blockTag;\n    const attributes = config.blockAttributes;\n    const closeBlock = \"</\" + tag + \">\";\n    let openBlock = \"<\" + tag;\n    for (const attr in attributes) {\n      openBlock += \" \" + attr + '=\"' + escapeHTML(attributes[attr]) + '\"';\n    }\n    openBlock += \">\";\n    for (let i = 0, l = lines.length; i < l; i += 1) {\n      let line = lines[i];\n      line = escapeHTML(line).replace(/ (?=(?: |$))/g, \"&nbsp;\");\n      if (i) {\n        line = openBlock + (line || \"<BR>\") + closeBlock;\n      }\n      lines[i] = line;\n    }\n    return this.insertHTML(lines.join(\"\"), isPaste);\n  }\n  getSelectedText() {\n    const range = this.getSelection();\n    if (range.collapsed) {\n      return \"\";\n    }\n    const startContainer = range.startContainer;\n    const endContainer = range.endContainer;\n    const walker = new TreeIterator(\n      range.commonAncestorContainer,\n      SHOW_ELEMENT_OR_TEXT,\n      (node2) => {\n        return isNodeContainedInRange(range, node2, true);\n      }\n    );\n    walker.currentNode = startContainer;\n    let node = startContainer;\n    let textContent = \"\";\n    let addedTextInBlock = false;\n    let value;\n    if (!(node instanceof Element) && !(node instanceof Text) || !walker.filter(node)) {\n      node = walker.nextNode();\n    }\n    while (node) {\n      if (node instanceof Text) {\n        value = node.data;\n        if (value && /\\S/.test(value)) {\n          if (node === endContainer) {\n            value = value.slice(0, range.endOffset);\n          }\n          if (node === startContainer) {\n            value = value.slice(range.startOffset);\n          }\n          textContent += value;\n          addedTextInBlock = true;\n        }\n      } else if (node.nodeName === \"BR\" || addedTextInBlock && !isInline(node)) {\n        textContent += \"\\n\";\n        addedTextInBlock = false;\n      }\n      node = walker.nextNode();\n    }\n    return textContent;\n  }\n  // --- Inline formatting\n  /**\n   * Extracts the font-family and font-size (if any) of the element\n   * holding the cursor. If there's a selection, returns an empty object.\n   */\n  getFontInfo(range) {\n    const fontInfo = {\n      color: void 0,\n      backgroundColor: void 0,\n      fontFamily: void 0,\n      fontSize: void 0\n    };\n    if (!range) {\n      range = this.getSelection();\n    }\n    let seenAttributes = 0;\n    let element = range.commonAncestorContainer;\n    if (range.collapsed || element instanceof Text) {\n      if (element instanceof Text) {\n        element = element.parentNode;\n      }\n      while (seenAttributes < 4 && element) {\n        const style = element.style;\n        if (style) {\n          const color = style.color;\n          if (!fontInfo.color && color) {\n            fontInfo.color = color;\n            seenAttributes += 1;\n          }\n          const backgroundColor = style.backgroundColor;\n          if (!fontInfo.backgroundColor && backgroundColor) {\n            fontInfo.backgroundColor = backgroundColor;\n            seenAttributes += 1;\n          }\n          const fontFamily = style.fontFamily;\n          if (!fontInfo.fontFamily && fontFamily) {\n            fontInfo.fontFamily = fontFamily;\n            seenAttributes += 1;\n          }\n          const fontSize = style.fontSize;\n          if (!fontInfo.fontSize && fontSize) {\n            fontInfo.fontSize = fontSize;\n            seenAttributes += 1;\n          }\n        }\n        element = element.parentNode;\n      }\n    }\n    return fontInfo;\n  }\n  /**\n   * Looks for matching tag and attributes, so won't work if <strong>\n   * instead of <b> etc.\n   */\n  hasFormat(tag, attributes, range) {\n    tag = tag.toUpperCase();\n    if (!attributes) {\n      attributes = {};\n    }\n    if (!range) {\n      range = this.getSelection();\n    }\n    if (!range.collapsed && range.startContainer instanceof Text && range.startOffset === range.startContainer.length && range.startContainer.nextSibling) {\n      range.setStartBefore(range.startContainer.nextSibling);\n    }\n    if (!range.collapsed && range.endContainer instanceof Text && range.endOffset === 0 && range.endContainer.previousSibling) {\n      range.setEndAfter(range.endContainer.previousSibling);\n    }\n    const root = this._root;\n    const common = range.commonAncestorContainer;\n    if (getNearest(common, root, tag, attributes)) {\n      return true;\n    }\n    if (common instanceof Text) {\n      return false;\n    }\n    const walker = new TreeIterator(common, SHOW_TEXT, (node2) => {\n      return isNodeContainedInRange(range, node2, true);\n    });\n    let seenNode = false;\n    let node;\n    while (node = walker.nextNode()) {\n      if (!getNearest(node, root, tag, attributes)) {\n        return false;\n      }\n      seenNode = true;\n    }\n    return seenNode;\n  }\n  changeFormat(add, remove, range, partial) {\n    if (!range) {\n      range = this.getSelection();\n    }\n    this.saveUndoState(range);\n    if (remove) {\n      range = this._removeFormat(\n        remove.tag.toUpperCase(),\n        remove.attributes || {},\n        range,\n        partial\n      );\n    }\n    if (add) {\n      range = this._addFormat(\n        add.tag.toUpperCase(),\n        add.attributes || {},\n        range\n      );\n    }\n    this.setSelection(range);\n    this._updatePath(range, true);\n    return this.focus();\n  }\n  _addFormat(tag, attributes, range) {\n    const root = this._root;\n    if (range.collapsed) {\n      const el = fixCursor(createElement(tag, attributes));\n      insertNodeInRange(range, el);\n      const focusNode = el.firstChild || el;\n      const focusOffset = focusNode instanceof Text ? focusNode.length : 0;\n      range.setStart(focusNode, focusOffset);\n      range.collapse(true);\n      let block = el;\n      while (isInline(block)) {\n        block = block.parentNode;\n      }\n      removeZWS(block, el);\n    } else {\n      const walker = new TreeIterator(\n        range.commonAncestorContainer,\n        SHOW_ELEMENT_OR_TEXT,\n        (node) => {\n          return (node instanceof Text || node.nodeName === \"BR\" || node.nodeName === \"IMG\") && isNodeContainedInRange(range, node, true);\n        }\n      );\n      let { startContainer, startOffset, endContainer, endOffset } = range;\n      walker.currentNode = startContainer;\n      if (!(startContainer instanceof Element) && !(startContainer instanceof Text) || !walker.filter(startContainer)) {\n        const next = walker.nextNode();\n        if (!next) {\n          return range;\n        }\n        startContainer = next;\n        startOffset = 0;\n      }\n      do {\n        let node = walker.currentNode;\n        const needsFormat = !getNearest(node, root, tag, attributes);\n        if (needsFormat) {\n          if (node === endContainer && node.length > endOffset) {\n            node.splitText(endOffset);\n          }\n          if (node === startContainer && startOffset) {\n            node = node.splitText(startOffset);\n            if (endContainer === startContainer) {\n              endContainer = node;\n              endOffset -= startOffset;\n            } else if (endContainer === startContainer.parentNode) {\n              endOffset += 1;\n            }\n            startContainer = node;\n            startOffset = 0;\n          }\n          const el = createElement(tag, attributes);\n          replaceWith(node, el);\n          el.appendChild(node);\n        }\n      } while (walker.nextNode());\n      range = createRange(\n        startContainer,\n        startOffset,\n        endContainer,\n        endOffset\n      );\n    }\n    return range;\n  }\n  _removeFormat(tag, attributes, range, partial) {\n    this._saveRangeToBookmark(range);\n    let fixer;\n    if (range.collapsed) {\n      if (cantFocusEmptyTextNodes) {\n        fixer = document.createTextNode(ZWS);\n      } else {\n        fixer = document.createTextNode(\"\");\n      }\n      insertNodeInRange(range, fixer);\n    }\n    let root = range.commonAncestorContainer;\n    while (isInline(root)) {\n      root = root.parentNode;\n    }\n    const startContainer = range.startContainer;\n    const startOffset = range.startOffset;\n    const endContainer = range.endContainer;\n    const endOffset = range.endOffset;\n    const toWrap = [];\n    const examineNode = (node, exemplar) => {\n      if (isNodeContainedInRange(range, node, false)) {\n        return;\n      }\n      let child;\n      let next;\n      if (!isNodeContainedInRange(range, node, true)) {\n        if (!(node instanceof HTMLInputElement) && (!(node instanceof Text) || node.data)) {\n          toWrap.push([exemplar, node]);\n        }\n        return;\n      }\n      if (node instanceof Text) {\n        if (node === endContainer && endOffset !== node.length) {\n          toWrap.push([exemplar, node.splitText(endOffset)]);\n        }\n        if (node === startContainer && startOffset) {\n          node.splitText(startOffset);\n          toWrap.push([exemplar, node]);\n        }\n      } else {\n        for (child = node.firstChild; child; child = next) {\n          next = child.nextSibling;\n          examineNode(child, exemplar);\n        }\n      }\n    };\n    const formatTags = Array.from(\n      root.getElementsByTagName(tag)\n    ).filter((el) => {\n      return isNodeContainedInRange(range, el, true) && hasTagAttributes(el, tag, attributes);\n    });\n    if (!partial) {\n      formatTags.forEach((node) => {\n        examineNode(node, node);\n      });\n    }\n    toWrap.forEach(([el, node]) => {\n      el = el.cloneNode(false);\n      replaceWith(node, el);\n      el.appendChild(node);\n    });\n    formatTags.forEach((el) => {\n      replaceWith(el, empty(el));\n    });\n    this._getRangeAndRemoveBookmark(range);\n    if (fixer) {\n      range.collapse(false);\n    }\n    mergeInlines(root, range);\n    return range;\n  }\n  // ---\n  bold() {\n    return this.changeFormat({ tag: \"B\" });\n  }\n  removeBold() {\n    return this.changeFormat(null, { tag: \"B\" });\n  }\n  italic() {\n    return this.changeFormat({ tag: \"I\" });\n  }\n  removeItalic() {\n    return this.changeFormat(null, { tag: \"I\" });\n  }\n  underline() {\n    return this.changeFormat({ tag: \"U\" });\n  }\n  removeUnderline() {\n    return this.changeFormat(null, { tag: \"U\" });\n  }\n  strikethrough() {\n    return this.changeFormat({ tag: \"S\" });\n  }\n  removeStrikethrough() {\n    return this.changeFormat(null, { tag: \"S\" });\n  }\n  subscript() {\n    return this.changeFormat({ tag: \"SUB\" }, { tag: \"SUP\" });\n  }\n  removeSubscript() {\n    return this.changeFormat(null, { tag: \"SUB\" });\n  }\n  superscript() {\n    return this.changeFormat({ tag: \"SUP\" }, { tag: \"SUB\" });\n  }\n  removeSuperscript() {\n    return this.changeFormat(null, { tag: \"SUP\" });\n  }\n  // ---\n  makeLink(url, attributes) {\n    const range = this.getSelection();\n    if (range.collapsed) {\n      let protocolEnd = url.indexOf(\":\") + 1;\n      if (protocolEnd) {\n        while (url[protocolEnd] === \"/\") {\n          protocolEnd += 1;\n        }\n      }\n      insertNodeInRange(\n        range,\n        document.createTextNode(url.slice(protocolEnd))\n      );\n    }\n    attributes = Object.assign(\n      {\n        href: url\n      },\n      this._config.tagAttributes.a,\n      attributes\n    );\n    return this.changeFormat(\n      {\n        tag: \"A\",\n        attributes\n      },\n      {\n        tag: \"A\"\n      },\n      range\n    );\n  }\n  removeLink() {\n    return this.changeFormat(\n      null,\n      {\n        tag: \"A\"\n      },\n      this.getSelection(),\n      true\n    );\n  }\n  /*\n  linkRegExp = new RegExp(\n      // Only look on boundaries\n      '\\\\b(?:' +\n      // Capture group 1: URLs\n      '(' +\n          // Add links to URLS\n          // Starts with:\n          '(?:' +\n              // http(s):// or ftp://\n              '(?:ht|f)tps?:\\\\/\\\\/' +\n              // or\n              '|' +\n              // www.\n              'www\\\\d{0,3}[.]' +\n              // or\n              '|' +\n              // foo90.com/\n              '[a-z0-9][a-z0-9.\\\\-]*[.][a-z]{2,}\\\\/' +\n          ')' +\n          // Then we get one or more:\n          '(?:' +\n              // Run of non-spaces, non ()<>\n              '[^\\\\s()<>]+' +\n              // or\n              '|' +\n              // balanced parentheses (one level deep only)\n              '\\\\([^\\\\s()<>]+\\\\)' +\n          ')+' +\n          // And we finish with\n          '(?:' +\n              // Not a space or punctuation character\n              '[^\\\\s?&`!()\\\\[\\\\]{};:\\'\".,<>«»“”‘’]' +\n              // or\n              '|' +\n              // Balanced parentheses.\n              '\\\\([^\\\\s()<>]+\\\\)' +\n          ')' +\n      // Capture group 2: Emails\n      ')|(' +\n          // Add links to emails\n          '[\\\\w\\\\-.%+]+@(?:[\\\\w\\\\-]+\\\\.)+[a-z]{2,}\\\\b' +\n          // Allow query parameters in the mailto: style\n          '(?:' +\n              '[?][^&?\\\\s]+=[^\\\\s?&`!()\\\\[\\\\]{};:\\'\".,<>«»“”‘’]+' +\n              '(?:&[^&?\\\\s]+=[^\\\\s?&`!()\\\\[\\\\]{};:\\'\".,<>«»“”‘’]+)*' +\n          ')?' +\n      '))',\n      'i'\n  );\n  */\n  linkRegExp = /\\b(?:((?:(?:ht|f)tps?:\\/\\/|www\\d{0,3}[.]|[a-z0-9][a-z0-9.\\-]*[.][a-z]{2,}\\/)(?:[^\\s()<>]+|\\([^\\s()<>]+\\))+(?:[^\\s?&`!()\\[\\]{};:'\".,<>«»“”‘’]|\\([^\\s()<>]+\\)))|([\\w\\-.%+]+@(?:[\\w\\-]+\\.)+[a-z]{2,}\\b(?:[?][^&?\\s]+=[^\\s?&`!()\\[\\]{};:'\".,<>«»“”‘’]+(?:&[^&?\\s]+=[^\\s?&`!()\\[\\]{};:'\".,<>«»“”‘’]+)*)?))/i;\n  addDetectedLinks(searchInNode, root) {\n    const walker = new TreeIterator(\n      searchInNode,\n      SHOW_TEXT,\n      (node2) => !getNearest(node2, root || this._root, \"A\")\n    );\n    const linkRegExp = this.linkRegExp;\n    const defaultAttributes = this._config.tagAttributes.a;\n    let node;\n    while (node = walker.nextNode()) {\n      const parent = node.parentNode;\n      let data = node.data;\n      let match;\n      while (match = linkRegExp.exec(data)) {\n        const index = match.index;\n        const endIndex = index + match[0].length;\n        if (index) {\n          parent.insertBefore(\n            document.createTextNode(data.slice(0, index)),\n            node\n          );\n        }\n        const child = createElement(\n          \"A\",\n          Object.assign(\n            {\n              href: match[1] ? /^(?:ht|f)tps?:/i.test(match[1]) ? match[1] : \"http://\" + match[1] : \"mailto:\" + match[0]\n            },\n            defaultAttributes\n          )\n        );\n        child.textContent = data.slice(index, endIndex);\n        parent.insertBefore(child, node);\n        node.data = data = data.slice(endIndex);\n      }\n    }\n    return this;\n  }\n  // ---\n  setFontFace(name) {\n    const className = this._config.classNames.fontFamily;\n    return this.changeFormat(\n      name ? {\n        tag: \"SPAN\",\n        attributes: {\n          class: className,\n          style: \"font-family: \" + name + \", sans-serif;\"\n        }\n      } : null,\n      {\n        tag: \"SPAN\",\n        attributes: { class: className }\n      }\n    );\n  }\n  setFontSize(size) {\n    const className = this._config.classNames.fontSize;\n    return this.changeFormat(\n      size ? {\n        tag: \"SPAN\",\n        attributes: {\n          class: className,\n          style: \"font-size: \" + (typeof size === \"number\" ? size + \"px\" : size)\n        }\n      } : null,\n      {\n        tag: \"SPAN\",\n        attributes: { class: className }\n      }\n    );\n  }\n  setTextColor(color) {\n    const className = this._config.classNames.color;\n    return this.changeFormat(\n      color ? {\n        tag: \"SPAN\",\n        attributes: {\n          class: className,\n          style: \"color:\" + color\n        }\n      } : null,\n      {\n        tag: \"SPAN\",\n        attributes: { class: className }\n      }\n    );\n  }\n  setHighlightColor(color) {\n    const className = this._config.classNames.highlight;\n    return this.changeFormat(\n      color ? {\n        tag: \"SPAN\",\n        attributes: {\n          class: className,\n          style: \"background-color:\" + color\n        }\n      } : null,\n      {\n        tag: \"SPAN\",\n        attributes: { class: className }\n      }\n    );\n  }\n  // --- Block formatting\n  _ensureBottomLine() {\n    const root = this._root;\n    const last = root.lastElementChild;\n    if (!last || last.nodeName !== this._config.blockTag || !isBlock(last)) {\n      root.appendChild(this.createDefaultBlock());\n    }\n  }\n  createDefaultBlock(children) {\n    const config = this._config;\n    return fixCursor(\n      createElement(config.blockTag, config.blockAttributes, children)\n    );\n  }\n  tagAfterSplit = {\n    DT: \"DD\",\n    DD: \"DT\",\n    LI: \"LI\",\n    PRE: \"PRE\"\n  };\n  splitBlock(lineBreakOnly, range) {\n    if (!range) {\n      range = this.getSelection();\n    }\n    const root = this._root;\n    let block;\n    let parent;\n    let node;\n    let nodeAfterSplit;\n    this._recordUndoState(range);\n    this._removeZWS();\n    this._getRangeAndRemoveBookmark(range);\n    if (!range.collapsed) {\n      deleteContentsOfRange(range, root);\n    }\n    if (this._config.addLinks) {\n      moveRangeBoundariesDownTree(range);\n      const textNode = range.startContainer;\n      const offset2 = range.startOffset;\n      setTimeout(() => {\n        linkifyText(this, textNode, offset2);\n      }, 0);\n    }\n    block = getStartBlockOfRange(range, root);\n    if (block && (parent = getNearest(block, root, \"PRE\"))) {\n      moveRangeBoundariesDownTree(range);\n      node = range.startContainer;\n      const offset2 = range.startOffset;\n      if (!(node instanceof Text)) {\n        node = document.createTextNode(\"\");\n        parent.insertBefore(node, parent.firstChild);\n      }\n      if (!lineBreakOnly && node instanceof Text && (node.data.charAt(offset2 - 1) === \"\\n\" || rangeDoesStartAtBlockBoundary(range, root)) && (node.data.charAt(offset2) === \"\\n\" || rangeDoesEndAtBlockBoundary(range, root))) {\n        node.deleteData(offset2 && offset2 - 1, offset2 ? 2 : 1);\n        nodeAfterSplit = split(\n          node,\n          offset2 && offset2 - 1,\n          root,\n          root\n        );\n        node = nodeAfterSplit.previousSibling;\n        if (!node.textContent) {\n          detach(node);\n        }\n        node = this.createDefaultBlock();\n        nodeAfterSplit.parentNode.insertBefore(node, nodeAfterSplit);\n        if (!nodeAfterSplit.textContent) {\n          detach(nodeAfterSplit);\n        }\n        range.setStart(node, 0);\n      } else {\n        node.insertData(offset2, \"\\n\");\n        fixCursor(parent);\n        if (node.length === offset2 + 1) {\n          range.setStartAfter(node);\n        } else {\n          range.setStart(node, offset2 + 1);\n        }\n      }\n      range.collapse(true);\n      this.setSelection(range);\n      this._updatePath(range, true);\n      this._docWasChanged();\n      return this;\n    }\n    if (!block || lineBreakOnly || /^T[HD]$/.test(block.nodeName)) {\n      moveRangeBoundaryOutOf(range, \"A\", root);\n      insertNodeInRange(range, createElement(\"BR\"));\n      range.collapse(false);\n      this.setSelection(range);\n      this._updatePath(range, true);\n      return this;\n    }\n    if (parent = getNearest(block, root, \"LI\")) {\n      block = parent;\n    }\n    if (isEmptyBlock(block)) {\n      if (getNearest(block, root, \"UL\") || getNearest(block, root, \"OL\")) {\n        this.decreaseListLevel(range);\n        return this;\n      } else if (getNearest(block, root, \"BLOCKQUOTE\")) {\n        this.removeQuote(range);\n        return this;\n      }\n    }\n    node = range.startContainer;\n    const offset = range.startOffset;\n    let splitTag = this.tagAfterSplit[block.nodeName];\n    nodeAfterSplit = split(\n      node,\n      offset,\n      block.parentNode,\n      this._root\n    );\n    const config = this._config;\n    let splitProperties = null;\n    if (!splitTag) {\n      splitTag = config.blockTag;\n      splitProperties = config.blockAttributes;\n    }\n    if (!hasTagAttributes(nodeAfterSplit, splitTag, splitProperties)) {\n      block = createElement(splitTag, splitProperties);\n      if (nodeAfterSplit.dir) {\n        block.dir = nodeAfterSplit.dir;\n      }\n      replaceWith(nodeAfterSplit, block);\n      block.appendChild(empty(nodeAfterSplit));\n      nodeAfterSplit = block;\n    }\n    removeZWS(block);\n    removeEmptyInlines(block);\n    fixCursor(block);\n    while (nodeAfterSplit instanceof Element) {\n      let child = nodeAfterSplit.firstChild;\n      let next;\n      if (nodeAfterSplit.nodeName === \"A\" && (!nodeAfterSplit.textContent || nodeAfterSplit.textContent === ZWS)) {\n        child = document.createTextNode(\"\");\n        replaceWith(nodeAfterSplit, child);\n        nodeAfterSplit = child;\n        break;\n      }\n      while (child && child instanceof Text && !child.data) {\n        next = child.nextSibling;\n        if (!next || next.nodeName === \"BR\") {\n          break;\n        }\n        detach(child);\n        child = next;\n      }\n      if (!child || child.nodeName === \"BR\" || child instanceof Text) {\n        break;\n      }\n      nodeAfterSplit = child;\n    }\n    range = createRange(nodeAfterSplit, 0);\n    this.setSelection(range);\n    this._updatePath(range, true);\n    return this;\n  }\n  forEachBlock(fn, mutates, range) {\n    if (!range) {\n      range = this.getSelection();\n    }\n    if (mutates) {\n      this.saveUndoState(range);\n    }\n    const root = this._root;\n    let start = getStartBlockOfRange(range, root);\n    const end = getEndBlockOfRange(range, root);\n    if (start && end) {\n      do {\n        if (fn(start) || start === end) {\n          break;\n        }\n      } while (start = getNextBlock(start, root));\n    }\n    if (mutates) {\n      this.setSelection(range);\n      this._updatePath(range, true);\n    }\n    return this;\n  }\n  modifyBlocks(modify, range) {\n    if (!range) {\n      range = this.getSelection();\n    }\n    this._recordUndoState(range, this._isInUndoState);\n    const root = this._root;\n    expandRangeToBlockBoundaries(range, root);\n    moveRangeBoundariesUpTree(range, root, root, root);\n    const frag = extractContentsOfRange(range, root, root);\n    if (!range.collapsed) {\n      let node = range.endContainer;\n      if (node === root) {\n        range.collapse(false);\n      } else {\n        while (node.parentNode !== root) {\n          node = node.parentNode;\n        }\n        range.setStartBefore(node);\n        range.collapse(true);\n      }\n    }\n    insertNodeInRange(range, modify.call(this, frag));\n    if (range.endOffset < range.endContainer.childNodes.length) {\n      mergeContainers(\n        range.endContainer.childNodes[range.endOffset],\n        root\n      );\n    }\n    mergeContainers(\n      range.startContainer.childNodes[range.startOffset],\n      root\n    );\n    this._getRangeAndRemoveBookmark(range);\n    this.setSelection(range);\n    this._updatePath(range, true);\n    return this;\n  }\n  // ---\n  setTextAlignment(alignment) {\n    this.forEachBlock((block) => {\n      const className = block.className.split(/\\s+/).filter((klass) => {\n        return !!klass && !/^align/.test(klass);\n      }).join(\" \");\n      if (alignment) {\n        block.className = className + \" align-\" + alignment;\n        block.style.textAlign = alignment;\n      } else {\n        block.className = className;\n        block.style.textAlign = \"\";\n      }\n    }, true);\n    return this.focus();\n  }\n  setTextDirection(direction) {\n    this.forEachBlock((block) => {\n      if (direction) {\n        block.dir = direction;\n      } else {\n        block.removeAttribute(\"dir\");\n      }\n    }, true);\n    return this.focus();\n  }\n  // ---\n  _getListSelection(range, root) {\n    let list = range.commonAncestorContainer;\n    let startLi = range.startContainer;\n    let endLi = range.endContainer;\n    while (list && list !== root && !/^[OU]L$/.test(list.nodeName)) {\n      list = list.parentNode;\n    }\n    if (!list || list === root) {\n      return null;\n    }\n    if (startLi === list) {\n      startLi = startLi.childNodes[range.startOffset];\n    }\n    if (endLi === list) {\n      endLi = endLi.childNodes[range.endOffset];\n    }\n    while (startLi && startLi.parentNode !== list) {\n      startLi = startLi.parentNode;\n    }\n    while (endLi && endLi.parentNode !== list) {\n      endLi = endLi.parentNode;\n    }\n    return [list, startLi, endLi];\n  }\n  increaseListLevel(range) {\n    if (!range) {\n      range = this.getSelection();\n    }\n    const root = this._root;\n    const listSelection = this._getListSelection(range, root);\n    if (!listSelection) {\n      return this.focus();\n    }\n    let [list, startLi, endLi] = listSelection;\n    if (!startLi || startLi === list.firstChild) {\n      return this.focus();\n    }\n    this._recordUndoState(range, this._isInUndoState);\n    const type = list.nodeName;\n    let newParent = startLi.previousSibling;\n    let listAttrs;\n    let next;\n    if (newParent.nodeName !== type) {\n      listAttrs = this._config.tagAttributes[type.toLowerCase()];\n      newParent = createElement(type, listAttrs);\n      list.insertBefore(newParent, startLi);\n    }\n    do {\n      next = startLi === endLi ? null : startLi.nextSibling;\n      newParent.appendChild(startLi);\n    } while (startLi = next);\n    next = newParent.nextSibling;\n    if (next) {\n      mergeContainers(next, root);\n    }\n    this._getRangeAndRemoveBookmark(range);\n    this.setSelection(range);\n    this._updatePath(range, true);\n    return this.focus();\n  }\n  decreaseListLevel(range) {\n    if (!range) {\n      range = this.getSelection();\n    }\n    const root = this._root;\n    const listSelection = this._getListSelection(range, root);\n    if (!listSelection) {\n      return this.focus();\n    }\n    let [list, startLi, endLi] = listSelection;\n    if (!startLi) {\n      startLi = list.firstChild;\n    }\n    if (!endLi) {\n      endLi = list.lastChild;\n    }\n    this._recordUndoState(range, this._isInUndoState);\n    let next;\n    let insertBefore = null;\n    if (startLi) {\n      let newParent = list.parentNode;\n      insertBefore = !endLi.nextSibling ? list.nextSibling : split(list, endLi.nextSibling, newParent, root);\n      if (newParent !== root && newParent.nodeName === \"LI\") {\n        newParent = newParent.parentNode;\n        while (insertBefore) {\n          next = insertBefore.nextSibling;\n          endLi.appendChild(insertBefore);\n          insertBefore = next;\n        }\n        insertBefore = list.parentNode.nextSibling;\n      }\n      const makeNotList = !/^[OU]L$/.test(newParent.nodeName);\n      do {\n        next = startLi === endLi ? null : startLi.nextSibling;\n        list.removeChild(startLi);\n        if (makeNotList && startLi.nodeName === \"LI\") {\n          startLi = this.createDefaultBlock([empty(startLi)]);\n        }\n        newParent.insertBefore(startLi, insertBefore);\n      } while (startLi = next);\n    }\n    if (!list.firstChild) {\n      detach(list);\n    }\n    if (insertBefore) {\n      mergeContainers(insertBefore, root);\n    }\n    this._getRangeAndRemoveBookmark(range);\n    this.setSelection(range);\n    this._updatePath(range, true);\n    return this.focus();\n  }\n  _makeList(frag, type) {\n    const walker = getBlockWalker(frag, this._root);\n    const tagAttributes = this._config.tagAttributes;\n    const listAttrs = tagAttributes[type.toLowerCase()];\n    const listItemAttrs = tagAttributes.li;\n    let node;\n    while (node = walker.nextNode()) {\n      if (node.parentNode instanceof HTMLLIElement) {\n        node = node.parentNode;\n        walker.currentNode = node.lastChild;\n      }\n      if (!(node instanceof HTMLLIElement)) {\n        const newLi = createElement(\"LI\", listItemAttrs);\n        if (node.dir) {\n          newLi.dir = node.dir;\n        }\n        const prev = node.previousSibling;\n        if (prev && prev.nodeName === type) {\n          prev.appendChild(newLi);\n          detach(node);\n        } else {\n          replaceWith(node, createElement(type, listAttrs, [newLi]));\n        }\n        newLi.appendChild(empty(node));\n        walker.currentNode = newLi;\n      } else {\n        node = node.parentNode;\n        const tag = node.nodeName;\n        if (tag !== type && /^[OU]L$/.test(tag)) {\n          replaceWith(\n            node,\n            createElement(type, listAttrs, [empty(node)])\n          );\n        }\n      }\n    }\n    return frag;\n  }\n  makeUnorderedList() {\n    this.modifyBlocks((frag) => this._makeList(frag, \"UL\"));\n    return this.focus();\n  }\n  makeOrderedList() {\n    this.modifyBlocks((frag) => this._makeList(frag, \"OL\"));\n    return this.focus();\n  }\n  removeList() {\n    this.modifyBlocks((frag) => {\n      const lists = frag.querySelectorAll(\"UL, OL\");\n      const items = frag.querySelectorAll(\"LI\");\n      const root = this._root;\n      for (let i = 0, l = lists.length; i < l; i += 1) {\n        const list = lists[i];\n        const listFrag = empty(list);\n        fixContainer(listFrag, root);\n        replaceWith(list, listFrag);\n      }\n      for (let i = 0, l = items.length; i < l; i += 1) {\n        const item = items[i];\n        if (isBlock(item)) {\n          replaceWith(item, this.createDefaultBlock([empty(item)]));\n        } else {\n          fixContainer(item, root);\n          replaceWith(item, empty(item));\n        }\n      }\n      return frag;\n    });\n    return this.focus();\n  }\n  // ---\n  increaseQuoteLevel(range) {\n    this.modifyBlocks(\n      (frag) => createElement(\n        \"BLOCKQUOTE\",\n        this._config.tagAttributes.blockquote,\n        [frag]\n      ),\n      range\n    );\n    return this.focus();\n  }\n  decreaseQuoteLevel(range) {\n    this.modifyBlocks((frag) => {\n      Array.from(frag.querySelectorAll(\"blockquote\")).filter((el) => {\n        return !getNearest(el.parentNode, frag, \"BLOCKQUOTE\");\n      }).forEach((el) => {\n        replaceWith(el, empty(el));\n      });\n      return frag;\n    }, range);\n    return this.focus();\n  }\n  removeQuote(range) {\n    this.modifyBlocks(\n      () => this.createDefaultBlock([\n        createElement(\"INPUT\", {\n          id: this.startSelectionId,\n          type: \"hidden\"\n        }),\n        createElement(\"INPUT\", {\n          id: this.endSelectionId,\n          type: \"hidden\"\n        })\n      ]),\n      range\n    );\n    return this.focus();\n  }\n  // ---\n  code() {\n    const range = this.getSelection();\n    if (range.collapsed || isContainer(range.commonAncestorContainer)) {\n      this.modifyBlocks((frag) => {\n        const root = this._root;\n        const output = document.createDocumentFragment();\n        const blockWalker = getBlockWalker(frag, root);\n        let node;\n        while (node = blockWalker.nextNode()) {\n          let nodes = node.querySelectorAll(\"BR\");\n          const brBreaksLine = [];\n          let l = nodes.length;\n          for (let i = 0; i < l; i += 1) {\n            brBreaksLine[i] = isLineBreak(nodes[i], false);\n          }\n          while (l--) {\n            const br = nodes[l];\n            if (!brBreaksLine[l]) {\n              detach(br);\n            } else {\n              replaceWith(br, document.createTextNode(\"\\n\"));\n            }\n          }\n          nodes = node.querySelectorAll(\"CODE\");\n          l = nodes.length;\n          while (l--) {\n            replaceWith(nodes[l], empty(nodes[l]));\n          }\n          if (output.childNodes.length) {\n            output.appendChild(document.createTextNode(\"\\n\"));\n          }\n          output.appendChild(empty(node));\n        }\n        const textWalker = new TreeIterator(output, SHOW_TEXT);\n        while (node = textWalker.nextNode()) {\n          node.data = node.data.replace(/ /g, \" \");\n        }\n        output.normalize();\n        return fixCursor(\n          createElement(\"PRE\", this._config.tagAttributes.pre, [\n            output\n          ])\n        );\n      }, range);\n      this.focus();\n    } else {\n      this.changeFormat(\n        {\n          tag: \"CODE\",\n          attributes: this._config.tagAttributes.code\n        },\n        null,\n        range\n      );\n    }\n    return this;\n  }\n  removeCode() {\n    const range = this.getSelection();\n    const ancestor = range.commonAncestorContainer;\n    const inPre = getNearest(ancestor, this._root, \"PRE\");\n    if (inPre) {\n      this.modifyBlocks((frag) => {\n        const root = this._root;\n        const pres = frag.querySelectorAll(\"PRE\");\n        let l = pres.length;\n        while (l--) {\n          const pre = pres[l];\n          const walker = new TreeIterator(pre, SHOW_TEXT);\n          let node;\n          while (node = walker.nextNode()) {\n            let value = node.data;\n            value = value.replace(/ (?= )/g, \"\\xA0\");\n            const contents = document.createDocumentFragment();\n            let index;\n            while ((index = value.indexOf(\"\\n\")) > -1) {\n              contents.appendChild(\n                document.createTextNode(value.slice(0, index))\n              );\n              contents.appendChild(createElement(\"BR\"));\n              value = value.slice(index + 1);\n            }\n            node.parentNode.insertBefore(contents, node);\n            node.data = value;\n          }\n          fixContainer(pre, root);\n          replaceWith(pre, empty(pre));\n        }\n        return frag;\n      }, range);\n      this.focus();\n    } else {\n      this.changeFormat(null, { tag: \"CODE\" }, range);\n    }\n    return this;\n  }\n  toggleCode() {\n    if (this.hasFormat(\"PRE\") || this.hasFormat(\"CODE\")) {\n      this.removeCode();\n    } else {\n      this.code();\n    }\n    return this;\n  }\n  // ---\n  _removeFormatting(root, clean) {\n    for (let node = root.firstChild, next; node; node = next) {\n      next = node.nextSibling;\n      if (isInline(node)) {\n        if (node instanceof Text || node.nodeName === \"BR\" || node.nodeName === \"IMG\") {\n          clean.appendChild(node);\n          continue;\n        }\n      } else if (isBlock(node)) {\n        clean.appendChild(\n          this.createDefaultBlock([\n            this._removeFormatting(\n              node,\n              document.createDocumentFragment()\n            )\n          ])\n        );\n        continue;\n      }\n      this._removeFormatting(node, clean);\n    }\n    return clean;\n  }\n  removeAllFormatting(range) {\n    if (!range) {\n      range = this.getSelection();\n    }\n    if (range.collapsed) {\n      return this.focus();\n    }\n    const root = this._root;\n    let stopNode = range.commonAncestorContainer;\n    while (stopNode && !isBlock(stopNode)) {\n      stopNode = stopNode.parentNode;\n    }\n    if (!stopNode) {\n      expandRangeToBlockBoundaries(range, root);\n      stopNode = root;\n    }\n    if (stopNode instanceof Text) {\n      return this.focus();\n    }\n    this.saveUndoState(range);\n    moveRangeBoundariesUpTree(range, stopNode, stopNode, root);\n    const startContainer = range.startContainer;\n    let startOffset = range.startOffset;\n    const endContainer = range.endContainer;\n    let endOffset = range.endOffset;\n    const formattedNodes = document.createDocumentFragment();\n    const cleanNodes = document.createDocumentFragment();\n    const nodeAfterSplit = split(endContainer, endOffset, stopNode, root);\n    let nodeInSplit = split(startContainer, startOffset, stopNode, root);\n    let nextNode;\n    while (nodeInSplit !== nodeAfterSplit) {\n      nextNode = nodeInSplit.nextSibling;\n      formattedNodes.appendChild(nodeInSplit);\n      nodeInSplit = nextNode;\n    }\n    this._removeFormatting(formattedNodes, cleanNodes);\n    cleanNodes.normalize();\n    nodeInSplit = cleanNodes.firstChild;\n    nextNode = cleanNodes.lastChild;\n    if (nodeInSplit) {\n      stopNode.insertBefore(cleanNodes, nodeAfterSplit);\n      const childNodes = Array.from(stopNode.childNodes);\n      startOffset = childNodes.indexOf(nodeInSplit);\n      endOffset = nextNode ? childNodes.indexOf(nextNode) + 1 : 0;\n    } else if (nodeAfterSplit) {\n      const childNodes = Array.from(stopNode.childNodes);\n      startOffset = childNodes.indexOf(nodeAfterSplit);\n      endOffset = startOffset;\n    }\n    range.setStart(stopNode, startOffset);\n    range.setEnd(stopNode, endOffset);\n    mergeInlines(stopNode, range);\n    moveRangeBoundariesDownTree(range);\n    this.setSelection(range);\n    this._updatePath(range, true);\n    return this.focus();\n  }\n};\n\n// source/Squire.ts\nvar Squire_default = Squire;\nexport {\n  Squire_default as default\n};\n","import m, { Children, Component } from \"mithril\"\nimport stream from \"mithril/stream\"\nimport { Editor } from \"./Editor.js\"\nimport type { TranslationKey, TranslationText } from \"../../misc/LanguageViewModel\"\nimport { lang } from \"../../misc/LanguageViewModel\"\nimport { px } from \"../size\"\nimport { htmlSanitizer } from \"../../misc/HtmlSanitizer\"\nimport { assertNotNull } from \"@tutao/tutanota-utils\"\nimport { DropDownSelector } from \"../base/DropDownSelector.js\"\nimport { RichTextToolbar, RichTextToolbarAttrs } from \"../base/RichTextToolbar.js\"\n\nexport enum HtmlEditorMode {\n\tHTML = \"html\",\n\tWYSIWYG = \"what you see is what you get\",\n}\n\nexport class HtmlEditor implements Component {\n\teditor: Editor\n\tprivate mode = HtmlEditorMode.WYSIWYG\n\tprivate active = false\n\tprivate domTextArea: HTMLTextAreaElement | null = null\n\tprivate _showBorders = false\n\tprivate minHeight: number | null = null\n\tprivate placeholderId: TranslationKey | null = null\n\tprivate placeholderDomElement: HTMLElement | null = null\n\tprivate value = stream(\"\")\n\tprivate htmlMonospace = true\n\tprivate modeSwitcherLabel: TranslationText | null = null\n\tprivate toolbarEnabled = false\n\tprivate toolbarAttrs: Omit<RichTextToolbarAttrs, \"editor\"> = {}\n\n\tconstructor(private label?: TranslationText, private readonly injections?: () => Children) {\n\t\tthis.editor = new Editor(null, (html) => htmlSanitizer.sanitizeFragment(html, { blockExternalContent: false }).fragment)\n\t\tthis.view = this.view.bind(this)\n\t\tthis.initializeEditorListeners()\n\t}\n\n\tview(): Children {\n\t\tconst modeSwitcherLabel = this.modeSwitcherLabel\n\t\tlet borderClasses = this._showBorders\n\t\t\t? this.active && this.editor.isEnabled()\n\t\t\t\t? \".editor-border-active\"\n\t\t\t\t: \".editor-border\" + (modeSwitcherLabel != null ? \".editor-no-top-border\" : \"\")\n\t\t\t: \"\"\n\n\t\tconst renderedInjections = this.injections?.() ?? null\n\n\t\tconst getPlaceholder = () =>\n\t\t\t!this.active && this.isEmpty()\n\t\t\t\t? m(\n\t\t\t\t\t\t\".abs.text-ellipsis.noselect.z1.i.pr-s\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toncreate: (vnode) => (this.placeholderDomElement = vnode.dom as HTMLElement),\n\t\t\t\t\t\t\tonclick: () =>\n\t\t\t\t\t\t\t\tthis.mode === HtmlEditorMode.WYSIWYG ? assertNotNull(this.editor.domElement).focus() : assertNotNull(this.domTextArea).focus(),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tthis.placeholderId ? lang.get(this.placeholderId) : \"\",\n\t\t\t\t  )\n\t\t\t\t: null\n\n\t\treturn m(\".html-editor\" + (this.mode === HtmlEditorMode.WYSIWYG ? \".text-break\" : \"\"), [\n\t\t\tmodeSwitcherLabel != null\n\t\t\t\t? m(DropDownSelector, {\n\t\t\t\t\t\tlabel: () => lang.getMaybeLazy(modeSwitcherLabel),\n\t\t\t\t\t\titems: [\n\t\t\t\t\t\t\t{ name: lang.get(\"richText_label\"), value: HtmlEditorMode.WYSIWYG },\n\t\t\t\t\t\t\t{ name: lang.get(\"htmlSourceCode_label\"), value: HtmlEditorMode.HTML },\n\t\t\t\t\t\t],\n\t\t\t\t\t\tselectedValue: this.mode,\n\t\t\t\t\t\tselectionChangedHandler: (mode: HtmlEditorMode) => {\n\t\t\t\t\t\t\tthis.mode = mode\n\t\t\t\t\t\t\tthis.setValue(this.value())\n\t\t\t\t\t\t\tthis.initializeEditorListeners()\n\t\t\t\t\t\t},\n\t\t\t\t  })\n\t\t\t\t: null,\n\t\t\tthis.label ? m(\".small.mt-form\", lang.getMaybeLazy(this.label)) : null,\n\t\t\tm(borderClasses, [\n\t\t\t\tgetPlaceholder(),\n\t\t\t\tthis.mode === HtmlEditorMode.WYSIWYG\n\t\t\t\t\t? m(\".wysiwyg.rel.overflow-hidden.selectable\", [\n\t\t\t\t\t\t\tthis.editor.isEnabled() && (this.toolbarEnabled || renderedInjections)\n\t\t\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t\t\tm(\".flex-end.sticky.pb-2\", [\n\t\t\t\t\t\t\t\t\t\t\tthis.toolbarEnabled ? m(RichTextToolbar, Object.assign({ editor: this.editor }, this.toolbarAttrs)) : null,\n\t\t\t\t\t\t\t\t\t\t\trenderedInjections,\n\t\t\t\t\t\t\t\t\t\t]),\n\t\t\t\t\t\t\t\t\t\tm(\"hr.hr.mb-s\"),\n\t\t\t\t\t\t\t\t  ]\n\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\tm(this.editor, {\n\t\t\t\t\t\t\t\toncreate: () => {\n\t\t\t\t\t\t\t\t\tthis.editor.initialized.promise.then(() => this.editor.setHTML(this.value()))\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tonremove: () => {\n\t\t\t\t\t\t\t\t\tthis.value(this.getValue())\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t  ])\n\t\t\t\t\t: m(\n\t\t\t\t\t\t\t\".html\",\n\t\t\t\t\t\t\tm(\"textarea.input-area.selectable\", {\n\t\t\t\t\t\t\t\toncreate: (vnode) => {\n\t\t\t\t\t\t\t\t\tthis.domTextArea = vnode.dom as HTMLTextAreaElement\n\t\t\t\t\t\t\t\t\tif (!this.isEmpty()) {\n\t\t\t\t\t\t\t\t\t\tthis.domTextArea.value = this.value()\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tonfocus: () => this.focus(),\n\t\t\t\t\t\t\t\tonblur: () => this.blur(),\n\t\t\t\t\t\t\t\toninput: () => {\n\t\t\t\t\t\t\t\t\tif (this.domTextArea) {\n\t\t\t\t\t\t\t\t\t\tthis.domTextArea.style.height = \"0px\"\n\t\t\t\t\t\t\t\t\t\tthis.domTextArea.style.height = this.domTextArea.scrollHeight + \"px\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\t\t\t\"font-family\": this.htmlMonospace ? \"monospace\" : \"inherit\",\n\t\t\t\t\t\t\t\t\t\"min-height\": this.minHeight ? px(this.minHeight) : \"initial\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tdisabled: !this.editor.enabled,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t  ),\n\t\t\t]),\n\t\t])\n\t}\n\n\tprivate initializeEditorListeners() {\n\t\tthis.editor.initialized.promise.then(() => {\n\t\t\tconst dom = assertNotNull(this.editor?.domElement)\n\t\t\tdom.onfocus = () => this.focus()\n\t\t\tdom.onblur = () => this.blur()\n\t\t})\n\t}\n\n\tprivate focus() {\n\t\tthis.active = true\n\t\tm.redraw()\n\t}\n\n\tprivate blur() {\n\t\tthis.active = false\n\t\tif (this.mode === HtmlEditorMode.WYSIWYG) {\n\t\t\tthis.value(this.editor.getValue())\n\t\t} else {\n\t\t\tthis.value(assertNotNull(this.domTextArea).value)\n\t\t}\n\t}\n\n\tsetModeSwitcher(label: TranslationText): this {\n\t\tthis.modeSwitcherLabel = label\n\t\treturn this\n\t}\n\n\tshowBorders(): HtmlEditor {\n\t\tthis._showBorders = true\n\t\treturn this\n\t}\n\n\tsetMinHeight(height: number): HtmlEditor {\n\t\tthis.minHeight = height\n\t\tthis.editor.setMinHeight(height)\n\t\treturn this\n\t}\n\n\tsetPlaceholderId(placeholderId: TranslationKey): HtmlEditor {\n\t\tthis.placeholderId = placeholderId\n\t\treturn this\n\t}\n\n\tgetValue(): string {\n\t\tif (this.mode === HtmlEditorMode.WYSIWYG) {\n\t\t\tif (this.editor.isAttached()) {\n\t\t\t\treturn this.editor.getHTML()\n\t\t\t} else {\n\t\t\t\treturn this.value()\n\t\t\t}\n\t\t} else {\n\t\t\tif (this.domTextArea) {\n\t\t\t\treturn htmlSanitizer.sanitizeHTML(this.domTextArea.value, { blockExternalContent: false }).html\n\t\t\t} else {\n\t\t\t\treturn this.value()\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * squire HTML editor usually has some HTML when appearing empty, sometimes we don't want that content.\n\t */\n\tgetTrimmedValue(): string {\n\t\treturn this.isEmpty() ? \"\" : this.getValue()\n\t}\n\n\tsetValue(html: string): HtmlEditor {\n\t\tif (this.mode === HtmlEditorMode.WYSIWYG) {\n\t\t\tthis.editor.initialized.promise.then(() => this.editor.setHTML(html))\n\t\t} else if (this.domTextArea) {\n\t\t\tthis.domTextArea.value = html\n\t\t}\n\t\tthis.value(html)\n\t\treturn this\n\t}\n\n\tisActive(): boolean {\n\t\treturn this.active\n\t}\n\n\tisEmpty(): boolean {\n\t\t// either nothing or default squire content\n\t\treturn this.value() === \"\" || this.value() === \"<div><br></div>\"\n\t}\n\n\t/** set whether the dialog should be editable.*/\n\tsetEnabled(enabled: boolean): HtmlEditor {\n\t\tthis.editor.setEnabled(enabled)\n\t\tif (this.domTextArea) {\n\t\t\tthis.domTextArea.disabled = !enabled\n\t\t}\n\t\treturn this\n\t}\n\n\tsetMode(mode: HtmlEditorMode): HtmlEditor {\n\t\tthis.mode = mode\n\t\treturn this\n\t}\n\n\tsetHtmlMonospace(monospace: boolean): HtmlEditor {\n\t\tthis.htmlMonospace = monospace\n\t\treturn this\n\t}\n\n\t/** show the rich text toolbar */\n\tenableToolbar(): this {\n\t\tthis.toolbarEnabled = true\n\t\treturn this\n\t}\n\n\tisToolbarEnabled(): boolean {\n\t\treturn this.toolbarEnabled\n\t}\n\n\t/** toggle the visibility of the rich text toolbar */\n\ttoggleToolbar(): this {\n\t\tthis.toolbarEnabled = !this.toolbarEnabled\n\t\treturn this\n\t}\n\n\tsetToolbarOptions(attrs: Omit<RichTextToolbarAttrs, \"editor\">): this {\n\t\tthis.toolbarAttrs = attrs\n\t\treturn this\n\t}\n}\n","import m, { Children, Component } from \"mithril\"\nimport SquireEditor from \"squire-rte\"\nimport { defer } from \"@tutao/tutanota-utils\"\nimport { px } from \"../size\"\nimport { Dialog } from \"../base/Dialog\"\nimport { isMailAddress } from \"../../misc/FormatValidator\"\nimport type { ImageHandler } from \"../../mail/model/MailUtils\"\nimport { Keys, TabIndex } from \"../../api/common/TutanotaConstants\"\nimport { isKeyPressed } from \"../../misc/KeyManager\"\n\ntype SanitizerFn = (html: string, isPaste: boolean) => DocumentFragment\nexport type ImagePasteEvent = CustomEvent<{ clipboardData: DataTransfer }>\nexport type TextPasteEvent = CustomEvent<{ fragment: DocumentFragment }>\nexport type Style = \"b\" | \"i\" | \"u\" | \"c\" | \"a\"\nexport type Alignment = \"left\" | \"center\" | \"right\" | \"justify\"\nexport type Listing = \"ol\" | \"ul\"\ntype Styles = {\n\t[key in Style]: boolean\n} & {\n\talignment: Alignment\n\tlisting: Listing | null\n}\n\nexport class Editor implements ImageHandler, Component {\n\tsquire: SquireEditor | null\n\tinitialized = defer<void>()\n\tdomElement: HTMLElement | null = null\n\tenabled = true\n\tprivate createsLists = true\n\tprivate userHasPasted = false\n\tprivate styleActions = Object.freeze({\n\t\tb: [() => this.squire.bold(), () => this.squire.removeBold(), () => this.styles.b],\n\t\ti: [() => this.squire.italic(), () => this.squire.removeItalic(), () => this.styles.i],\n\t\tu: [() => this.squire.underline(), () => this.squire.removeUnderline(), () => this.styles.u],\n\t\tc: [() => this.squire.setFontFace(\"monospace\"), () => this.squire.setFontFace(null), () => this.styles.c],\n\t\ta: [() => this.makeLink(), () => this.squire.removeLink(), () => this.styles.a],\n\t} as const)\n\n\tstyles: Styles = {\n\t\tb: false,\n\t\ti: false,\n\t\tu: false,\n\t\tc: false,\n\t\ta: false,\n\t\talignment: \"left\",\n\t\tlisting: null,\n\t}\n\n\t/**\n\t * squire 2.0 removed the isPaste argument from the sanitizeToDomFragment function.\n\t * since sanitizeToDomFragment is called before squire's willPaste event is fired, we\n\t * can't have our sanitization strategy depend on the willPaste event.\n\t *\n\t * we therefore add our own paste handler to the dom element squire uses and set a\n\t * flag once we detect a paste and reset it when squire next fires the \"input\" event.\n\t *\n\t * * user pastes\n\t * * \"paste\" event on dom sets flag\n\t * * sanitizeToDomFragment is called by squire\n\t * * \"input\" event on squire resets flag.\n\t */\n\tprivate pasteListener: (e: ClipboardEvent) => void = (_: ClipboardEvent) => (this.userHasPasted = true)\n\n\tconstructor(private minHeight: number | null, private sanitizer: SanitizerFn) {\n\t\tthis.onremove = this.onremove.bind(this)\n\t\tthis.onbeforeupdate = this.onbeforeupdate.bind(this)\n\t\tthis.view = this.view.bind(this)\n\t}\n\n\tonbeforeupdate(): boolean {\n\t\t// do not update the dom part managed by squire\n\t\treturn this.squire == null\n\t}\n\n\tonremove() {\n\t\tthis.domElement?.removeEventListener(\"paste\", this.pasteListener)\n\t\tif (this.squire) {\n\t\t\tthis.squire.destroy()\n\n\t\t\tthis.squire = null\n\t\t\tthis.initialized = defer()\n\t\t}\n\t}\n\n\tview(): Children {\n\t\treturn m(\".hide-outline.selectable\", {\n\t\t\trole: \"textbox\",\n\t\t\t\"aria-multiline\": \"true\",\n\t\t\ttabindex: TabIndex.Default,\n\t\t\toncreate: (vnode) => this.initSquire(vnode.dom as HTMLElement),\n\t\t\tclass: \"flex-grow\",\n\t\t\tstyle: this.minHeight\n\t\t\t\t? {\n\t\t\t\t\t\t\"min-height\": px(this.minHeight),\n\t\t\t\t  }\n\t\t\t\t: {},\n\t\t})\n\t}\n\n\tisEmpty(): boolean {\n\t\treturn !this.squire || this.squire.getHTML() === \"<div><br></div>\"\n\t}\n\n\tgetValue(): string {\n\t\treturn this.isEmpty() ? \"\" : this.squire.getHTML()\n\t}\n\n\taddChangeListener(callback: (...args: Array<any>) => any) {\n\t\tthis.squire.addEventListener(\"input\", callback)\n\t}\n\n\tsetMinHeight(minHeight: number): Editor {\n\t\tthis.minHeight = minHeight\n\t\treturn this\n\t}\n\n\tsetCreatesLists(createsLists: boolean): Editor {\n\t\tthis.createsLists = createsLists\n\t\treturn this\n\t}\n\n\tinitSquire(domElement: HTMLElement) {\n\t\tlet squire = new SquireEditor(domElement, {\n\t\t\tsanitizeToDOMFragment: (html: string) => this.sanitizer(html, this.userHasPasted),\n\t\t\tblockAttributes: {\n\t\t\t\tdir: \"auto\",\n\t\t\t},\n\t\t}).addEventListener(\"keyup\", (e: KeyboardEvent) => {\n\t\t\tif (this.createsLists && isKeyPressed(e.keyCode, Keys.SPACE)) {\n\t\t\t\tlet blocks: HTMLElement[] = []\n\t\t\t\tsquire.forEachBlock((block: HTMLElement) => {\n\t\t\t\t\tblocks.push(block)\n\t\t\t\t})\n\t\t\t\tcreateList(blocks, /^1\\.\\s$/, true) // create an ordered list if a line is started with '1. '\n\n\t\t\t\tcreateList(blocks, /^\\*\\s$/, false) // create an unordered list if a line is started with '* '\n\t\t\t}\n\t\t})\n\n\t\tthis.squire = squire\n\n\t\t// Suppress paste events if pasting while disabled\n\t\tthis.squire.addEventListener(\"willPaste\", (e: TextPasteEvent) => {\n\t\t\tif (!this.isEnabled()) {\n\t\t\t\te.preventDefault()\n\t\t\t}\n\t\t})\n\n\t\tthis.squire.addEventListener(\"input\", (_: CustomEvent<void>) => (this.userHasPasted = false))\n\t\tdomElement.addEventListener(\"paste\", this.pasteListener)\n\n\t\tthis.squire.addEventListener(\"pathChange\", () => {\n\t\t\tthis.getStylesAtPath()\n\t\t\tm.redraw() // allow richtexttoolbar to redraw elements\n\t\t})\n\n\t\tthis.domElement = domElement\n\t\t// the _editor might have been disabled before the dom element was there\n\t\tthis.setEnabled(this.enabled)\n\t\tthis.initialized.resolve()\n\n\t\tfunction createList(blocks: HTMLElement[], regex: RegExp, ordered: boolean) {\n\t\t\tif (blocks.length === 1 && blocks[0].textContent?.match(regex)) {\n\t\t\t\tsquire.modifyBlocks(function (fragment: DocumentFragment) {\n\t\t\t\t\tif (fragment.firstChild && fragment.firstChild.firstChild) {\n\t\t\t\t\t\tlet textNode = fragment.firstChild.firstChild\n\n\t\t\t\t\t\twhile (textNode.nodeType !== Node.TEXT_NODE && textNode.firstChild !== null && textNode.nodeName.toLowerCase() !== \"li\") {\n\t\t\t\t\t\t\ttextNode = textNode.firstChild\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (textNode.nodeType === Node.TEXT_NODE) {\n\t\t\t\t\t\t\ttextNode.textContent = textNode.textContent?.replace(regex, \"\") ?? null\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn fragment\n\t\t\t\t})\n\n\t\t\t\tif (ordered) {\n\t\t\t\t\tsquire.makeOrderedList()\n\t\t\t\t} else {\n\t\t\t\t\tsquire.makeUnorderedList()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsetEnabled(enabled: boolean) {\n\t\tthis.enabled = enabled\n\t\tif (this.domElement) {\n\t\t\tthis.domElement.setAttribute(\"contenteditable\", String(enabled))\n\t\t}\n\t}\n\n\tisEnabled(): boolean {\n\t\treturn this.enabled\n\t}\n\n\tsetHTML(html: string | null) {\n\t\tthis.squire.setHTML(html)\n\t}\n\n\tgetHTML(): string {\n\t\treturn this.squire.getHTML()\n\t}\n\n\tsetStyle(state: boolean, style: Style) {\n\t\t;(state ? this.styleActions[style][0] : this.styleActions[style][1])()\n\t}\n\n\thasStyle: (arg0: Style) => boolean = (style) => (this.squire ? this.styleActions[style][2]() : false)\n\tgetStylesAtPath: () => void = () => {\n\t\tif (!this.squire) {\n\t\t\treturn\n\t\t}\n\n\t\tlet pathSegments: string[] = this.squire.getPath().split(\">\")\n\n\t\t// lists\n\t\tconst ulIndex = pathSegments.lastIndexOf(\"UL\")\n\t\tconst olIndex = pathSegments.lastIndexOf(\"OL\")\n\n\t\tif (ulIndex === -1) {\n\t\t\tif (olIndex > -1) {\n\t\t\t\tthis.styles.listing = \"ol\"\n\t\t\t} else {\n\t\t\t\tthis.styles.listing = null\n\t\t\t}\n\t\t} else if (olIndex === -1) {\n\t\t\tif (ulIndex > -1) {\n\t\t\t\tthis.styles.listing = \"ul\"\n\t\t\t} else {\n\t\t\t\tthis.styles.listing = null\n\t\t\t}\n\t\t} else if (olIndex > ulIndex) {\n\t\t\tthis.styles.listing = \"ol\"\n\t\t} else {\n\t\t\tthis.styles.listing = \"ul\"\n\t\t}\n\n\t\t//links\n\t\tthis.styles.a = pathSegments.includes(\"A\")\n\t\t// alignment\n\t\tlet alignment = pathSegments.find((f) => f.includes(\"align\"))\n\n\t\tif (alignment !== undefined) {\n\t\t\tswitch (alignment.split(\".\")[1].substring(6)) {\n\t\t\t\tcase \"left\":\n\t\t\t\t\tthis.styles.alignment = \"left\"\n\t\t\t\t\tbreak\n\n\t\t\t\tcase \"right\":\n\t\t\t\t\tthis.styles.alignment = \"right\"\n\t\t\t\t\tbreak\n\n\t\t\t\tcase \"center\":\n\t\t\t\t\tthis.styles.alignment = \"center\"\n\t\t\t\t\tbreak\n\n\t\t\t\tdefault:\n\t\t\t\t\tthis.styles.alignment = \"justify\"\n\t\t\t}\n\t\t} else {\n\t\t\tthis.styles.alignment = \"left\"\n\t\t}\n\n\t\t// font\n\t\tthis.styles.c = pathSegments.find((f) => f.includes(\"monospace\")) !== undefined\n\t\t// decorations\n\t\tthis.styles.b = this.squire.hasFormat(\"b\")\n\t\tthis.styles.u = this.squire.hasFormat(\"u\")\n\t\tthis.styles.i = this.squire.hasFormat(\"i\")\n\t}\n\n\tmakeLink() {\n\t\tDialog.showTextInputDialog(\"makeLink_action\", \"url_label\", null, \"\").then((url) => {\n\t\t\tif (isMailAddress(url, false)) {\n\t\t\t\turl = \"mailto:\" + url\n\t\t\t} else if (!url.startsWith(\"http://\") && !url.startsWith(\"https://\") && !url.startsWith(\"mailto:\") && !url.startsWith(\"{\")) {\n\t\t\t\turl = \"https://\" + url\n\t\t\t}\n\n\t\t\tthis.squire.makeLink(url)\n\t\t})\n\t}\n\n\tinsertImage(srcAttr: string, attrs?: Record<string, string>): HTMLElement {\n\t\treturn this.squire.insertImage(srcAttr, attrs)\n\t}\n\n\t/**\n\t * Inserts the given html content at the current cursor position.\n\t */\n\tinsertHTML(html: string) {\n\t\tthis.squire.insertHTML(html)\n\t}\n\n\tgetDOM(): HTMLElement {\n\t\treturn this.squire.getRoot()\n\t}\n\n\tgetCursorPosition(): ClientRect {\n\t\treturn this.squire.getCursorPosition()\n\t}\n\n\tfocus(): void {\n\t\tthis.squire.focus()\n\n\t\tthis.getStylesAtPath()\n\t}\n\n\tisAttached(): boolean {\n\t\treturn this.squire != null\n\t}\n\n\tremoveAllFormatting(): void {\n\t\t// Create a range which contains the whole editor\n\t\tconst range = document.createRange()\n\t\trange.selectNode(this.squire.getRoot())\n\n\t\tthis.squire.removeAllFormatting(range)\n\t}\n\n\tgetSelectedText(): string {\n\t\treturn this.squire.getSelectedText()\n\t}\n\n\taddEventListener(type: string, handler: (arg0: Event) => void) {\n\t\tthis.squire.addEventListener(type, handler)\n\t}\n\n\tsetSelection(range: Range) {\n\t\tthis.squire.setSelection(range)\n\t}\n}\n","import { InfoLink, lang } from \"../../misc/LanguageViewModel\"\nimport type { TutanotaProperties } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport { EmailSignatureType as TutanotaConstants } from \"../../api/common/TutanotaConstants\"\nimport { LINE_BREAK } from \"../model/MailUtils\"\nimport { htmlSanitizer } from \"../../misc/HtmlSanitizer\"\nimport type { LoginController } from \"../../api/main/LoginController\"\nimport { assertMainOrNode } from \"../../api/common/Env\"\n\nassertMainOrNode()\n\nexport function getDefaultSignature(): string {\n\t// add one line break to the default signature to add one empty line between signature and body\n\treturn (\n\t\tLINE_BREAK +\n\t\thtmlSanitizer.sanitizeHTML(\n\t\t\tlang.get(\"defaultEmailSignature_msg\", {\n\t\t\t\t\"{1}\": InfoLink.HomePage,\n\t\t\t}),\n\t\t).html\n\t)\n}\n\nexport function getEmailSignature(tutanotaProperties: TutanotaProperties): string {\n\t// provide the user signature, even for shared mail groups\n\tconst type = tutanotaProperties.emailSignatureType\n\n\tif (type === TutanotaConstants.EMAIL_SIGNATURE_TYPE_DEFAULT) {\n\t\treturn getDefaultSignature()\n\t} else if (TutanotaConstants.EMAIL_SIGNATURE_TYPE_CUSTOM === type) {\n\t\treturn tutanotaProperties.customEmailSignature\n\t} else {\n\t\treturn \"\"\n\t}\n}\n\nexport function appendEmailSignature(body: string, properties: TutanotaProperties): string {\n\tconst signature = getEmailSignature(properties)\n\n\tif (signature) {\n\t\t// ensure that signature is on the next line\n\t\treturn body + LINE_BREAK + signature\n\t} else {\n\t\treturn body\n\t}\n}\n\nexport function prependEmailSignature(body: string, logins: LoginController): string {\n\t// add space between signature and existing body\n\tlet bodyWithSignature = \"\"\n\tlet signature = getEmailSignature(logins.getUserController().props)\n\n\tif (body) {\n\t\tbodyWithSignature = LINE_BREAK + LINE_BREAK + LINE_BREAK + body\n\t}\n\n\tif (logins.getUserController().isInternalUser() && signature) {\n\t\t// ensure that signature is on the next line\n\t\tbodyWithSignature = LINE_BREAK + signature + bodyWithSignature\n\t}\n\n\treturn bodyWithSignature\n}\n","import m from \"mithril\"\nimport type { Attachment } from \"./SendMailModel\"\nimport { SendMailModel } from \"./SendMailModel\"\nimport { debounce, findAllAndRemove, isNotNull, ofClass, remove } from \"@tutao/tutanota-utils\"\nimport { Mode } from \"../../api/common/Env\"\nimport { PermissionError } from \"../../api/common/error/PermissionError\"\nimport { Dialog } from \"../../gui/base/Dialog\"\nimport { FileNotFoundError } from \"../../api/common/error/FileNotFoundError\"\nimport { lang } from \"../../misc/LanguageViewModel\"\nimport { FileOpenError } from \"../../api/common/error/FileOpenError\"\nimport { UserError } from \"../../api/main/UserError\"\nimport { showUserError } from \"../../misc/ErrorHandlerImpl\"\nimport { locator } from \"../../api/main/MainLocator\"\nimport { FileReference, isDataFile, isFileReference, isTutanotaFile } from \"../../api/common/utils/FileUtils\"\nimport { DataFile } from \"../../api/common/DataFile\"\nimport { showFileChooser } from \"../../file/FileController.js\"\nimport { ProgrammingError } from \"../../api/common/error/ProgrammingError.js\"\nimport { AttachmentBubbleAttrs } from \"../../gui/AttachmentBubble.js\"\n\nexport async function chooseAndAttachFile(\n\tmodel: SendMailModel,\n\tboundingRect: ClientRect,\n\tfileTypes?: Array<string>,\n): Promise<ReadonlyArray<DataFile | FileReference> | void> {\n\tboundingRect.height = Math.round(boundingRect.height)\n\tboundingRect.width = Math.round(boundingRect.width)\n\tboundingRect.x = Math.round(boundingRect.x)\n\tboundingRect.y = Math.round(boundingRect.y)\n\ttry {\n\t\tconst files = await showFileChooserForAttachments(boundingRect, fileTypes)\n\t\tif (!files || files.length === 0) return\n\t\tswitch (env.mode) {\n\t\t\tcase Mode.App:\n\t\t\t\t// we have file refs and want to keep them\n\t\t\t\tmodel.attachFiles(files)\n\t\t\t\treturn files\n\t\t\tcase Mode.Desktop:\n\t\t\t\t// we have file refs and want to read them.\n\t\t\t\t// this is important for the desktop client so it can attach them as inline images.\n\t\t\t\tconst dataFiles: Array<DataFile> = (\n\t\t\t\t\tawait Promise.all((files as Array<FileReference>).map(async (f) => locator.fileApp.readDataFile(f.location)))\n\t\t\t\t).filter(isNotNull)\n\t\t\t\tmodel.attachFiles(dataFiles)\n\t\t\t\treturn dataFiles\n\t\t\tdefault:\n\t\t\t\t// we have data files and want to keep them\n\t\t\t\tmodel.attachFiles(files)\n\t\t\t\treturn files\n\t\t}\n\t} catch (e) {\n\t\tif (e instanceof UserError) {\n\t\t\tawait showUserError(e)\n\t\t} else {\n\t\t\tconst msg = e.message || \"unknown error\"\n\t\t\tconsole.error(\"could not attach files:\", msg)\n\t\t}\n\t}\n}\n\nexport function showFileChooserForAttachments(boundingRect: ClientRect, fileTypes?: Array<string>): Promise<ReadonlyArray<FileReference | DataFile> | void> {\n\tconst fileSelector = [Mode.App, Mode.Desktop].includes(env.mode)\n\t\t? locator.fileApp.openFileChooser(boundingRect, fileTypes)\n\t\t: showFileChooser(true, fileTypes)\n\treturn fileSelector\n\t\t.catch(\n\t\t\tofClass(PermissionError, () => {\n\t\t\t\tDialog.message(\"fileAccessDeniedMobile_msg\")\n\t\t\t}),\n\t\t)\n\t\t.catch(\n\t\t\tofClass(FileNotFoundError, () => {\n\t\t\t\tDialog.message(\"couldNotAttachFile_msg\")\n\t\t\t}),\n\t\t)\n}\n\nexport function createAttachmentBubbleAttrs(model: SendMailModel, inlineImageElements: Array<HTMLElement>): Array<AttachmentBubbleAttrs> {\n\treturn model.getAttachments().map((attachment) => ({\n\t\tattachment,\n\t\topen: null,\n\t\tdownload: () => _downloadAttachment(attachment),\n\t\tremove: () => {\n\t\t\tmodel.removeAttachment(attachment)\n\n\t\t\t// If an attachment has a cid it means it could be in the editor's inline images too\n\t\t\tif (attachment.cid) {\n\t\t\t\tconst imageElement = inlineImageElements.find((e) => e.getAttribute(\"cid\") === attachment.cid)\n\n\t\t\t\tif (imageElement) {\n\t\t\t\t\timageElement.remove()\n\t\t\t\t\tremove(inlineImageElements, imageElement)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tm.redraw()\n\t\t},\n\t}))\n}\n\nasync function _downloadAttachment(attachment: Attachment) {\n\ttry {\n\t\tif (isFileReference(attachment)) {\n\t\t\tawait locator.fileApp.open(attachment)\n\t\t} else if (isDataFile(attachment)) {\n\t\t\tawait locator.fileController.saveDataFile(attachment)\n\t\t} else if (isTutanotaFile(attachment)) {\n\t\t\tawait locator.fileController.download(attachment)\n\t\t} else {\n\t\t\tthrow new ProgrammingError(\"attachment is neither reference, datafile nor tutanotafile!\")\n\t\t}\n\t} catch (e) {\n\t\tif (e instanceof FileOpenError) {\n\t\t\treturn Dialog.message(\"canNotOpenFileOnDevice_msg\")\n\t\t} else {\n\t\t\tconst msg = e.message || \"unknown error\"\n\t\t\tconsole.error(\"could not open file:\", msg)\n\t\t\treturn Dialog.message(\"errorDuringFileOpen_msg\")\n\t\t}\n\t}\n}\n\nexport const cleanupInlineAttachments: (arg0: HTMLElement, arg1: Array<HTMLElement>, arg2: Array<Attachment>) => void = debounce(\n\t50,\n\t(domElement: HTMLElement, inlineImageElements: Array<HTMLElement>, attachments: Array<Attachment>) => {\n\t\t// Previously we replied on subtree option of MutationObserver to receive info when nested child is removed.\n\t\t// It works but it doesn't work if the parent of the nested child is removed, we would have to go over each mutation\n\t\t// and check each descendant and if it's an image with CID or not.\n\t\t// It's easier and faster to just go over each inline image that we know about. It's more bookkeeping but it's easier\n\t\t// code which touches less dome.\n\t\t//\n\t\t// Alternative would be observe the parent of each inline image but that's more complexity and we need to take care of\n\t\t// new (just inserted) inline images and also assign listener there.\n\t\t// Doing this check instead of relying on mutations also helps with the case when node is removed but inserted again\n\t\t// briefly, e.g. if some text is inserted before/after the element, Squire would put it into another diff and this\n\t\t// means removal + insertion.\n\t\tconst elementsToRemove: HTMLElement[] = []\n\t\tinlineImageElements.forEach((inlineImage) => {\n\t\t\tif (domElement && !domElement.contains(inlineImage)) {\n\t\t\t\tconst cid = inlineImage.getAttribute(\"cid\")\n\t\t\t\tconst attachmentIndex = attachments.findIndex((a) => a.cid === cid)\n\n\t\t\t\tif (attachmentIndex !== -1) {\n\t\t\t\t\tattachments.splice(attachmentIndex, 1)\n\t\t\t\t\telementsToRemove.push(inlineImage)\n\t\t\t\t\tm.redraw()\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t\tfindAllAndRemove(inlineImageElements, (imageElement) => elementsToRemove.includes(imageElement))\n\t},\n)\n\nexport function getConfidentialStateMessage(isConfidential: boolean): string {\n\treturn isConfidential ? lang.get(\"confidentialStatus_msg\") : lang.get(\"nonConfidentialStatus_msg\")\n}\n","import type { LanguageCode } from \"../../misc/LanguageViewModel\"\nimport { lang } from \"../../misc/LanguageViewModel\"\nimport type { EmailTemplateContent } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport { EmailTemplate, EmailTemplateTypeRef, TemplateGroupRootTypeRef } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport type { EntityEventsListener, EntityUpdateData } from \"../../api/main/EventController\"\nimport { EventController, isUpdateForTypeRef } from \"../../api/main/EventController\"\nimport { OperationType } from \"../../api/common/TutanotaConstants\"\nimport stream from \"mithril/stream\"\nimport Stream from \"mithril/stream\"\nimport type { EntityClient } from \"../../api/common/EntityClient\"\nimport type { LoginController } from \"../../api/main/LoginController\"\nimport { getElementId, getEtId, isSameId } from \"../../api/common/utils/EntityUtils\"\nimport type { GroupMembership } from \"../../api/entities/sys/TypeRefs.js\"\nimport { GroupInfoTypeRef, GroupTypeRef, UserTypeRef } from \"../../api/entities/sys/TypeRefs.js\"\nimport { flat, LazyLoaded, promiseMap, SortedArray } from \"@tutao/tutanota-utils\"\nimport type { TemplateGroupInstance } from \"./TemplateGroupModel\"\nimport { search } from \"../../api/common/utils/PlainTextSearch.js\"\n\n/**\n *   Model that holds main logic for the Template Feature.\n *   Handles things like returning the selected Template, selecting Templates, indexes, scrolling.\n */\nexport const TEMPLATE_SHORTCUT_PREFIX = \"#\"\nexport type NavAction = \"previous\" | \"next\"\nexport const SELECT_NEXT_TEMPLATE = \"next\"\nexport const SELECT_PREV_TEMPLATE = \"previous\"\n\n// sort first by name then by tag\nfunction compareTemplatesForSort(template1: EmailTemplate, template2: EmailTemplate) {\n\tconst titleComparison = template1.title.localeCompare(template2.title)\n\treturn titleComparison === 0 ? template1.tag.localeCompare(template2.tag) : titleComparison\n}\n\nexport class TemplatePopupModel {\n\t_allTemplates: SortedArray<EmailTemplate>\n\treadonly searchResults: Stream<ReadonlyArray<EmailTemplate>>\n\treadonly selectedTemplate: Stream<EmailTemplate | null>\n\tinitialized: LazyLoaded<TemplatePopupModel>\n\treadonly _eventController: EventController\n\treadonly _entityEventReceived: EntityEventsListener\n\treadonly _logins: LoginController\n\treadonly _entityClient: EntityClient\n\t_groupInstances: Array<TemplateGroupInstance>\n\t_selectedContentLanguage: LanguageCode\n\t_searchFilter: TemplateSearchFilter\n\n\tconstructor(eventController: EventController, logins: LoginController, entityClient: EntityClient) {\n\t\tthis._eventController = eventController\n\t\tthis._logins = logins\n\t\tthis._entityClient = entityClient\n\t\tthis._allTemplates = SortedArray.empty(compareTemplatesForSort)\n\t\tthis.searchResults = stream<ReadonlyArray<EmailTemplate>>([])\n\t\tthis.selectedTemplate = stream<EmailTemplate | null>(null)\n\t\tthis._selectedContentLanguage = lang.code\n\t\tthis._searchFilter = new TemplateSearchFilter()\n\t\tthis._groupInstances = []\n\n\t\tthis._entityEventReceived = (updates) => {\n\t\t\treturn this._entityUpdate(updates)\n\t\t}\n\n\t\tthis.initialized = new LazyLoaded(() => {\n\t\t\tconst templateMemberships = this._logins.getUserController().getTemplateMemberships()\n\n\t\t\treturn loadTemplateGroupInstances(templateMemberships, this._entityClient)\n\t\t\t\t.then((templateGroupInstances) =>\n\t\t\t\t\tloadTemplates(templateGroupInstances, this._entityClient).then((templates) => {\n\t\t\t\t\t\tthis._allTemplates.insertAll(templates)\n\n\t\t\t\t\t\tthis._groupInstances = templateGroupInstances\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\t.then(() => {\n\t\t\t\t\tthis.searchResults(this._searchFilter.filter(\"\", this._allTemplates.array))\n\t\t\t\t\tthis.setSelectedTemplate(this.searchResults()[0])\n\t\t\t\t\treturn this\n\t\t\t\t})\n\t\t})\n\n\t\tthis._eventController.addEntityListener(this._entityEventReceived)\n\t}\n\n\tinit(): Promise<TemplatePopupModel> {\n\t\treturn this.initialized.getAsync()\n\t}\n\n\tisLoaded(): boolean {\n\t\treturn this.initialized.isLoaded()\n\t}\n\n\tdispose() {\n\t\tthis._eventController.removeEntityListener(this._entityEventReceived)\n\t}\n\n\tisSelectedTemplate(template: EmailTemplate): boolean {\n\t\treturn this.selectedTemplate() === template\n\t}\n\n\tgetAllTemplates(): ReadonlyArray<EmailTemplate> {\n\t\treturn this._allTemplates.array\n\t}\n\n\tgetSelectedTemplate(): EmailTemplate | null {\n\t\treturn this.selectedTemplate()\n\t}\n\n\tgetSelectedContent(): EmailTemplateContent | null {\n\t\tconst selectedTemplate = this.selectedTemplate()\n\t\treturn (\n\t\t\tselectedTemplate &&\n\t\t\t(selectedTemplate.contents.find((contents) => contents.languageCode === this._selectedContentLanguage) ||\n\t\t\t\tselectedTemplate.contents.find((contents) => contents.languageCode === lang.code) ||\n\t\t\t\tselectedTemplate.contents[0])\n\t\t)\n\t}\n\n\tgetSelectedTemplateIndex(): number {\n\t\tconst selectedTemplate = this.selectedTemplate()\n\t\tif (selectedTemplate == null) {\n\t\t\treturn -1\n\t\t}\n\t\treturn this.searchResults().indexOf(selectedTemplate)\n\t}\n\n\tsetSelectedTemplate(template: EmailTemplate | null) {\n\t\tthis.selectedTemplate(template)\n\t}\n\n\tsetSelectedContentLanguage(langCode: LanguageCode) {\n\t\tthis._selectedContentLanguage = langCode\n\t}\n\n\tsearch(query: string): void {\n\t\tthis.searchResults(this._searchFilter.filter(query, this._allTemplates.array))\n\t\tthis.setSelectedTemplate(this.searchResults()[0])\n\t}\n\n\t_rerunSearch(): void {\n\t\tthis.searchResults(this._searchFilter.rerunQuery(this._allTemplates.array))\n\t\tthis.setSelectedTemplate(this.searchResults()[0])\n\t}\n\n\t/**\n\t * Increments or decrements the selection, unless it would go past the beginning or end of the search results\n\t * @param action\n\t * @returns true if the selection changed\n\t */\n\tselectNextTemplate(action: NavAction): boolean {\n\t\tconst selectedIndex = this.getSelectedTemplateIndex()\n\t\tconst nextIndex = selectedIndex + (action === SELECT_NEXT_TEMPLATE ? 1 : -1)\n\n\t\tif (nextIndex >= 0 && nextIndex < this.searchResults().length) {\n\t\t\tconst nextSelectedTemplate = this.searchResults()[nextIndex]\n\t\t\tthis.setSelectedTemplate(nextSelectedTemplate)\n\t\t\treturn true\n\t\t}\n\n\t\treturn false\n\t}\n\n\tfindTemplateWithTag(selectedText: string): EmailTemplate | null {\n\t\tconst tag = selectedText.substring(TEMPLATE_SHORTCUT_PREFIX.length) // remove TEMPLATE_SHORTCUT_PREFIX from selected text\n\n\t\treturn this._allTemplates.array.find((template) => template.tag === tag) ?? null\n\t}\n\n\t_entityUpdate(updates: ReadonlyArray<EntityUpdateData>): Promise<any> {\n\t\treturn promiseMap(updates, (update) => {\n\t\t\tif (isUpdateForTypeRef(EmailTemplateTypeRef, update)) {\n\t\t\t\tif (update.operation === OperationType.CREATE) {\n\t\t\t\t\treturn this._entityClient.load(EmailTemplateTypeRef, [update.instanceListId, update.instanceId]).then((template) => {\n\t\t\t\t\t\tthis._allTemplates.insert(template)\n\n\t\t\t\t\t\tthis._rerunSearch()\n\n\t\t\t\t\t\tthis.setSelectedTemplate(template)\n\t\t\t\t\t})\n\t\t\t\t} else if (update.operation === OperationType.UPDATE) {\n\t\t\t\t\treturn this._entityClient.load(EmailTemplateTypeRef, [update.instanceListId, update.instanceId]).then((template) => {\n\t\t\t\t\t\tthis._allTemplates.removeFirst((t) => isSameId(getElementId(t), update.instanceId))\n\n\t\t\t\t\t\tthis._allTemplates.insert(template)\n\n\t\t\t\t\t\tthis._rerunSearch()\n\n\t\t\t\t\t\tthis.setSelectedTemplate(template)\n\t\t\t\t\t})\n\t\t\t\t} else if (update.operation === OperationType.DELETE) {\n\t\t\t\t\t// Try select the next or the previous template\n\t\t\t\t\t// if neither option is possible, it means we are deleting the last template, so clear the selection\n\t\t\t\t\tif (!this.selectNextTemplate(\"next\") && !this.selectNextTemplate(\"previous\")) {\n\t\t\t\t\t\tthis.setSelectedTemplate(null)\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._allTemplates.removeFirst((t) => isSameId(getElementId(t), update.instanceId))\n\n\t\t\t\t\tthis._rerunSearch()\n\t\t\t\t}\n\t\t\t} else if (isUpdateForTypeRef(UserTypeRef, update) && isSameId(update.instanceId, this._logins.getUserController().user._id)) {\n\t\t\t\t// template group memberships may have changed\n\t\t\t\tif (this._groupInstances.length !== this._logins.getUserController().getTemplateMemberships().length) {\n\t\t\t\t\tthis.initialized.reset()\n\t\t\t\t\treturn this.initialized.getAsync().then(() => this._rerunSearch())\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n\n\tgetTemplateGroupInstances(): Array<TemplateGroupInstance> {\n\t\treturn this._groupInstances\n\t}\n\n\tgetSelectedTemplateGroupInstance(): TemplateGroupInstance | null {\n\t\tconst selected = this.getSelectedTemplate()\n\t\tif (selected == null) {\n\t\t\treturn null\n\t\t} else {\n\t\t\treturn this._groupInstances.find((instance) => isSameId(getEtId(instance.group), selected._ownerGroup)) ?? null\n\t\t}\n\t}\n}\n\nexport function loadTemplateGroupInstances(memberships: Array<GroupMembership>, entityClient: EntityClient): Promise<Array<TemplateGroupInstance>> {\n\treturn promiseMap(memberships, (membership) => loadTemplateGroupInstance(membership, entityClient))\n}\n\nexport function loadTemplateGroupInstance(groupMembership: GroupMembership, entityClient: EntityClient): Promise<TemplateGroupInstance> {\n\treturn entityClient.load(GroupInfoTypeRef, groupMembership.groupInfo).then((groupInfo) =>\n\t\tentityClient.load(TemplateGroupRootTypeRef, groupInfo.group).then((groupRoot) =>\n\t\t\tentityClient.load(GroupTypeRef, groupInfo.group).then((group) => {\n\t\t\t\treturn {\n\t\t\t\t\tgroupInfo,\n\t\t\t\t\tgroup,\n\t\t\t\t\tgroupRoot,\n\t\t\t\t\tgroupMembership,\n\t\t\t\t}\n\t\t\t}),\n\t\t),\n\t)\n}\n\nfunction loadTemplates(templateGroups: Array<TemplateGroupInstance>, entityClient: EntityClient): Promise<Array<EmailTemplate>> {\n\treturn promiseMap(templateGroups, (group) => entityClient.loadAll(EmailTemplateTypeRef, group.groupRoot.templates)).then((groupedTemplates) =>\n\t\tflat(groupedTemplates),\n\t)\n}\n\nexport function searchInTemplates(input: string, allTemplates: ReadonlyArray<EmailTemplate>): ReadonlyArray<EmailTemplate> {\n\tif (input.startsWith(TEMPLATE_SHORTCUT_PREFIX)) {\n\t\t// search in tag only\n\t\tconst newQueryString = input.substring(TEMPLATE_SHORTCUT_PREFIX.length)\n\t\treturn search(newQueryString, allTemplates, [\"tag\"], false)\n\t} else {\n\t\treturn search(input, allTemplates, [\"tag\", \"title\", \"contents.text\"], false)\n\t}\n}\n\nclass TemplateSearchFilter {\n\tlastInput: ReadonlyArray<EmailTemplate>\n\tlastQuery: string\n\tlastResults: ReadonlyArray<EmailTemplate>\n\n\tconstructor() {\n\t\tthis.lastInput = []\n\t\tthis.lastQuery = \"\"\n\t\tthis.lastResults = []\n\t}\n\n\tfilter(query: string, input: ReadonlyArray<EmailTemplate>): ReadonlyArray<EmailTemplate> {\n\t\treturn this._doFilter(query, input)\n\t}\n\n\trerunQuery(input: ReadonlyArray<EmailTemplate>): ReadonlyArray<EmailTemplate> {\n\t\treturn this._doFilter(this.lastQuery, input)\n\t}\n\n\t_doFilter(query: string, input: ReadonlyArray<EmailTemplate>): ReadonlyArray<EmailTemplate> {\n\t\tthis.lastInput = input.slice()\n\t\tthis.lastQuery = query\n\t\tthis.lastResults = query === \"\" ? this.lastInput : searchInTemplates(query, input)\n\t\treturn this.lastResults\n\t}\n}\n","export const TEMPLATE_POPUP_HEIGHT = 340\nexport const TEMPLATE_POPUP_TWO_COLUMN_MIN_WIDTH = 600\nexport const TEMPLATE_LIST_ENTRY_HEIGHT = 47\nexport const TEMPLATE_LIST_ENTRY_WIDTH = 354\n","import m, { Children, Component, Vnode } from \"mithril\"\nimport { px } from \"../../gui/size\"\nimport type { EmailTemplate } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport { TEMPLATE_SHORTCUT_PREFIX } from \"../model/TemplatePopupModel\"\nimport { TEMPLATE_LIST_ENTRY_HEIGHT } from \"./TemplateConstants.js\"\n\nexport type TemplateResultRowAttrs = {\n\ttemplate: EmailTemplate\n}\n\n/**\n *   renders one entry of the list in the template popup\n */\nexport class TemplatePopupResultRow implements Component<TemplateResultRowAttrs> {\n\tview(vnode: Vnode<TemplateResultRowAttrs>): Children {\n\t\tconst { title, tag } = vnode.attrs.template\n\t\treturn m(\n\t\t\t\".flex.flex-column.overflow-hidden.full-width.ml-s\",\n\t\t\t{\n\t\t\t\tstyle: {\n\t\t\t\t\theight: px(TEMPLATE_LIST_ENTRY_HEIGHT),\n\t\t\t\t},\n\t\t\t},\n\t\t\t[\n\t\t\t\t// marginLeft 4px because border-radius of tag has margin of 4px\n\t\t\t\tm(\n\t\t\t\t\t\".text-ellipsis\",\n\t\t\t\t\t{\n\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\tmarginLeft: \"4px\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\ttitle,\n\t\t\t\t),\n\t\t\t\tm(\".flex.badge-line-height.text-ellipsis\", [\n\t\t\t\t\ttag\n\t\t\t\t\t\t? m(\".small.keyword-bubble-no-padding.pl-s.pr-s.border-radius.no-wrap.small.min-content\", TEMPLATE_SHORTCUT_PREFIX + tag.toLowerCase())\n\t\t\t\t\t\t: null,\n\t\t\t\t]),\n\t\t\t],\n\t\t)\n\t}\n}\n","import m, { Children, Component, Vnode } from \"mithril\"\nimport { px, size } from \"../../gui/size\"\nimport { Keys } from \"../../api/common/TutanotaConstants\"\nimport { TemplatePopupModel } from \"../model/TemplatePopupModel\"\nimport { isKeyPressed } from \"../../misc/KeyManager\"\nimport type { EmailTemplate } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport { TEMPLATE_POPUP_HEIGHT } from \"./TemplateConstants.js\"\nimport { memoized } from \"@tutao/tutanota-utils\"\nimport { htmlSanitizer } from \"../../misc/HtmlSanitizer.js\"\n\n/**\n * TemplateExpander is the right side that is rendered within the Popup. Consists of Dropdown, Content and Button.\n * The Popup handles whether the Expander should be rendered or not, depending on available width-space.\n */\nexport type TemplateExpanderAttrs = {\n\ttemplate: EmailTemplate\n\tmodel: TemplatePopupModel\n}\n\nexport class TemplateExpander implements Component<TemplateExpanderAttrs> {\n\tprivate readonly sanitizedText = memoized(\n\t\t(text: string) =>\n\t\t\thtmlSanitizer.sanitizeHTML(text, {\n\t\t\t\tblockExternalContent: false,\n\t\t\t\tallowRelativeLinks: true,\n\t\t\t}).html,\n\t)\n\n\tview({ attrs }: Vnode<TemplateExpanderAttrs>): Children {\n\t\tconst { model } = attrs\n\t\tconst selectedContent = model.getSelectedContent()\n\t\treturn m(\n\t\t\t\".flex.flex-column.flex-grow.scroll.ml-s\",\n\t\t\t{\n\t\t\t\tstyle: {\n\t\t\t\t\t// maxHeight has to be set, because otherwise the content would overflow outside the flexbox (-44 because of header height)\n\t\t\t\t\tmaxHeight: px(TEMPLATE_POPUP_HEIGHT - size.button_height),\n\t\t\t\t},\n\t\t\t\tonkeydown: (e: KeyboardEvent) => {\n\t\t\t\t\tif (isKeyPressed(e.keyCode, Keys.TAB)) {\n\t\t\t\t\t\te.preventDefault()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t\t[m(\".text-break.flex-grow.pr.overflow-y-visible\", selectedContent ? m.trust(this.sanitizedText(selectedContent.text)) : null)],\n\t\t)\n\t}\n}\n","import m, { Children, ClassComponent, Component, Vnode } from \"mithril\"\nimport type { TranslationKey } from \"../../misc/LanguageViewModel\"\nimport { lang } from \"../../misc/LanguageViewModel\"\nimport { inputLineHeight, px } from \"../../gui/size\"\nimport type { keyHandler } from \"../../misc/KeyManager\"\nimport { theme } from \"../../gui/theme\"\nimport type { lazy } from \"@tutao/tutanota-utils\"\nimport Stream from \"mithril/stream\"\nimport { assertNotNull } from \"@tutao/tutanota-utils\"\n\nexport type TemplateSearchBarAttrs = {\n\tvalue: Stream<string>\n\tplaceholder?: TranslationKey | lazy<string>\n\toninput?: (value: string, input: HTMLInputElement) => unknown\n\tkeyHandler?: keyHandler\n}\n\nexport class TemplateSearchBar implements ClassComponent<TemplateSearchBarAttrs> {\n\tdomInput: HTMLInputElement | null = null\n\n\tview(vnode: Vnode<TemplateSearchBarAttrs>): Children {\n\t\tconst a = vnode.attrs\n\t\treturn m(\n\t\t\t\".inputWrapper.pt-xs.pb-xs\",\n\t\t\t{\n\t\t\t\tstyle: {\n\t\t\t\t\t\"border-bottom\": `1px solid ${theme.content_border}`,\n\t\t\t\t},\n\t\t\t},\n\t\t\tthis._getInputField(a),\n\t\t)\n\t}\n\n\t_getInputField(a: TemplateSearchBarAttrs): Children {\n\t\treturn m(\"input.input\", {\n\t\t\tplaceholder: a.placeholder && lang.getMaybeLazy(a.placeholder),\n\t\t\toncreate: (vnode) => {\n\t\t\t\tthis.domInput = vnode.dom as HTMLInputElement\n\t\t\t\tthis.domInput.value = a.value()\n\t\t\t\tthis.domInput.focus()\n\t\t\t},\n\t\t\tonkeydown: (e: KeyboardEvent) => {\n\t\t\t\tlet key = {\n\t\t\t\t\tkeyCode: e.which,\n\t\t\t\t\tkey: e.key,\n\t\t\t\t\tctrl: e.ctrlKey,\n\t\t\t\t\tshift: e.shiftKey,\n\t\t\t\t}\n\t\t\t\treturn a.keyHandler != null ? a.keyHandler(key) : true\n\t\t\t},\n\t\t\toninput: () => {\n\t\t\t\tconst domInput = assertNotNull(this.domInput)\n\t\t\t\ta.value(domInput.value)\n\t\t\t\ta.oninput && a.oninput(domInput.value, domInput)\n\t\t\t},\n\t\t\tstyle: {\n\t\t\t\tlineHeight: px(inputLineHeight),\n\t\t\t},\n\t\t})\n\t}\n}\n","import type { TemplateGroupRoot } from \"../api/entities/tutanota/TypeRefs.js\"\nimport { TemplateGroupRootTypeRef } from \"../api/entities/tutanota/TypeRefs.js\"\nimport { showPlanUpgradeRequiredDialog } from \"../misc/SubscriptionDialogs\"\nimport { locator } from \"../api/main/MainLocator\"\nimport { FeatureType } from \"../api/common/TutanotaConstants\"\nimport { isCustomizationEnabledForCustomer } from \"../api/common/utils/Utils\"\n\n/**\n * @return True if the group has been created.\n */\nexport async function createInitialTemplateListIfAllowed(): Promise<TemplateGroupRoot | null> {\n\tconst userController = locator.logins.getUserController()\n\tconst customer = await userController.loadCustomer()\n\tconst { getAvailablePlansWithTemplates } = await import(\"../subscription/SubscriptionUtils.js\")\n\tconst plans = await getAvailablePlansWithTemplates()\n\tconst allowed =\n\t\t(await userController.getPlanConfig()).templates ||\n\t\tisCustomizationEnabledForCustomer(customer, FeatureType.BusinessFeatureEnabled) ||\n\t\t(await showPlanUpgradeRequiredDialog(plans))\n\tif (allowed) {\n\t\tconst groupId = await locator.groupManagementFacade.createTemplateGroup(\"\")\n\t\treturn locator.entityClient.load<TemplateGroupRoot>(TemplateGroupRootTypeRef, groupId)\n\t} else {\n\t\treturn null\n\t}\n}\n","import m, { Children } from \"mithril\"\nimport type { ModalComponent } from \"../../gui/base/Modal\"\nimport { modal } from \"../../gui/base/Modal\"\nimport { px } from \"../../gui/size\"\nimport type { Shortcut } from \"../../misc/KeyManager\"\nimport { isKeyPressed } from \"../../misc/KeyManager\"\nimport stream from \"mithril/stream\"\nimport Stream from \"mithril/stream\"\nimport { Keys, ShareCapability } from \"../../api/common/TutanotaConstants\"\nimport { TemplatePopupResultRow } from \"./TemplatePopupResultRow\"\nimport { Icons } from \"../../gui/base/icons/Icons\"\nimport { TemplateExpander } from \"./TemplateExpander\"\nimport type { LanguageCode } from \"../../misc/LanguageViewModel\"\nimport { lang, languageByCode } from \"../../misc/LanguageViewModel\"\nimport type { windowSizeListener } from \"../../misc/WindowFacade\"\nimport { windowFacade } from \"../../misc/WindowFacade\"\nimport type { EmailTemplate, TemplateGroupRoot } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport { TemplateGroupRootTypeRef } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport type { ButtonAttrs } from \"../../gui/base/Button.js\"\nimport { Button, ButtonColor, ButtonType } from \"../../gui/base/Button.js\"\nimport { SELECT_NEXT_TEMPLATE, SELECT_PREV_TEMPLATE, TEMPLATE_SHORTCUT_PREFIX, TemplatePopupModel } from \"../model/TemplatePopupModel\"\nimport { attachDropdown, DomRectReadOnlyPolyfilled, PosRect } from \"../../gui/base/Dropdown.js\"\nimport { debounce, downcast, neverNull } from \"@tutao/tutanota-utils\"\nimport { locator } from \"../../api/main/MainLocator\"\nimport { TemplateSearchBar } from \"./TemplateSearchBar\"\nimport { Editor } from \"../../gui/editor/Editor\"\nimport { getSharedGroupName, hasCapabilityOnGroup } from \"../../sharing/GroupUtils\"\nimport { createInitialTemplateListIfAllowed } from \"../TemplateGroupUtils\"\nimport { getConfirmation } from \"../../gui/base/GuiUtils\"\nimport { ScrollSelectList } from \"../../gui/ScrollSelectList\"\nimport { IconButton, IconButtonAttrs } from \"../../gui/base/IconButton.js\"\nimport { TEMPLATE_LIST_ENTRY_WIDTH, TEMPLATE_POPUP_HEIGHT, TEMPLATE_POPUP_TWO_COLUMN_MIN_WIDTH } from \"./TemplateConstants.js\"\n\n/**\n *\tCreates a Modal/Popup that allows user to paste templates directly into the MailEditor.\n *\tAlso allows user to change desired language when pasting.\n */\nexport function showTemplatePopupInEditor(templateModel: TemplatePopupModel, editor: Editor, template: EmailTemplate | null, highlightedText: string) {\n\tconst initialSearchString = template ? TEMPLATE_SHORTCUT_PREFIX + template.tag : highlightedText\n\tconst cursorRect = editor.getCursorPosition()\n\tconst editorRect = editor.getDOM().getBoundingClientRect()\n\n\tconst onSelect = (text: string) => {\n\t\teditor.insertHTML(text)\n\t\teditor.focus()\n\t}\n\n\tlet rect\n\tconst availableHeightBelowCursor = window.innerHeight - cursorRect.bottom\n\tconst popUpHeight = TEMPLATE_POPUP_HEIGHT + 10 // height + 10px offset for space from the bottom of the screen\n\n\t// By default the popup is shown below the cursor. If there is not enough space move the popup above the cursor\n\tconst popUpWidth = editorRect.right - editorRect.left\n\n\tif (availableHeightBelowCursor < popUpHeight) {\n\t\tconst diff = popUpHeight - availableHeightBelowCursor\n\t\trect = new DomRectReadOnlyPolyfilled(editorRect.left, cursorRect.bottom - diff, popUpWidth, cursorRect.height)\n\t} else {\n\t\trect = new DomRectReadOnlyPolyfilled(editorRect.left, cursorRect.bottom, popUpWidth, cursorRect.height)\n\t}\n\n\tconst popup = new TemplatePopup(templateModel, rect, onSelect, initialSearchString)\n\ttemplateModel.search(initialSearchString)\n\tpopup.show()\n}\n\nexport class TemplatePopup implements ModalComponent {\n\tprivate _rect: PosRect\n\tprivate _shortcuts: Shortcut[]\n\tprivate _onSelect: (_: string) => void\n\tprivate _initialWindowWidth: number\n\tprivate _resizeListener: windowSizeListener\n\tprivate _redrawStream: Stream<any>\n\tprivate readonly _templateModel: TemplatePopupModel\n\tprivate readonly _searchBarValue: Stream<string>\n\tprivate _selectTemplateButtonAttrs: ButtonAttrs\n\tprivate _inputDom: HTMLElement | null = null\n\tprivate _debounceFilter: (_: string) => void\n\n\tconstructor(templateModel: TemplatePopupModel, rect: PosRect, onSelect: (arg0: string) => void, initialSearchString: string) {\n\t\tthis._rect = rect\n\t\tthis._onSelect = onSelect\n\t\tthis._initialWindowWidth = window.innerWidth\n\n\t\tthis._resizeListener = () => {\n\t\t\tthis._close()\n\t\t}\n\n\t\tthis._searchBarValue = stream(initialSearchString)\n\t\tthis._templateModel = templateModel\n\t\tthis._shortcuts = [\n\t\t\t{\n\t\t\t\tkey: Keys.ESC,\n\t\t\t\tenabled: () => true,\n\t\t\t\texec: () => {\n\t\t\t\t\tthis._onSelect(\"\")\n\n\t\t\t\t\tthis._close()\n\n\t\t\t\t\tm.redraw()\n\t\t\t\t},\n\t\t\t\thelp: \"closeTemplate_action\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: Keys.RETURN,\n\t\t\t\tenabled: () => true,\n\t\t\t\texec: () => {\n\t\t\t\t\tconst selectedContent = this._templateModel.getSelectedContent()\n\n\t\t\t\t\tif (selectedContent) {\n\t\t\t\t\t\tthis._onSelect(selectedContent.text)\n\n\t\t\t\t\t\tthis._close()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\thelp: \"insertTemplate_action\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: Keys.UP,\n\t\t\t\tenabled: () => true,\n\t\t\t\texec: () => {\n\t\t\t\t\tthis._templateModel.selectNextTemplate(SELECT_PREV_TEMPLATE)\n\t\t\t\t},\n\t\t\t\thelp: \"selectPreviousTemplate_action\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: Keys.DOWN,\n\t\t\t\tenabled: () => true,\n\t\t\t\texec: () => {\n\t\t\t\t\tthis._templateModel.selectNextTemplate(SELECT_NEXT_TEMPLATE)\n\t\t\t\t},\n\t\t\t\thelp: \"selectNextTemplate_action\",\n\t\t\t},\n\t\t]\n\t\tthis._redrawStream = templateModel.searchResults.map((results) => {\n\t\t\tm.redraw()\n\t\t})\n\t\tthis._selectTemplateButtonAttrs = {\n\t\t\tlabel: \"selectTemplate_action\",\n\t\t\tclick: () => {\n\t\t\t\tconst selected = this._templateModel.getSelectedContent()\n\n\t\t\t\tif (selected) {\n\t\t\t\t\tthis._onSelect(selected.text)\n\n\t\t\t\t\tthis._close()\n\t\t\t\t}\n\t\t\t},\n\t\t\ttype: ButtonType.Primary,\n\t\t}\n\t\tthis._debounceFilter = debounce(200, (value: string) => {\n\t\t\ttemplateModel.search(value)\n\t\t})\n\n\t\tthis._debounceFilter(initialSearchString)\n\t}\n\n\tview: () => Children = () => {\n\t\tconst showTwoColumns = this._isScreenWideEnough()\n\n\t\treturn m(\n\t\t\t\".flex.flex-column.abs.elevated-bg.border-radius.dropdown-shadow\",\n\t\t\t{\n\t\t\t\t// Main Wrapper\n\t\t\t\tstyle: {\n\t\t\t\t\twidth: px(this._rect.width),\n\t\t\t\t\theight: px(TEMPLATE_POPUP_HEIGHT),\n\t\t\t\t\ttop: px(this._rect.top),\n\t\t\t\t\tleft: px(this._rect.left),\n\t\t\t\t},\n\t\t\t\tonclick: (e: MouseEvent) => {\n\t\t\t\t\tthis._inputDom?.focus()\n\n\t\t\t\t\te.stopPropagation()\n\t\t\t\t},\n\t\t\t\toncreate: () => {\n\t\t\t\t\twindowFacade.addResizeListener(this._resizeListener)\n\t\t\t\t},\n\t\t\t\tonremove: () => {\n\t\t\t\t\twindowFacade.removeResizeListener(this._resizeListener)\n\t\t\t\t},\n\t\t\t},\n\t\t\t[\n\t\t\t\tthis._renderHeader(),\n\t\t\t\tm(\".flex.flex-grow.scroll.mb-s\", [\n\t\t\t\t\tm(\n\t\t\t\t\t\t\".flex.flex-column.scroll\" + (showTwoColumns ? \".pr\" : \"\"),\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\t\tflex: \"1 1 40%\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tthis._renderList(),\n\t\t\t\t\t),\n\t\t\t\t\tshowTwoColumns\n\t\t\t\t\t\t? m(\n\t\t\t\t\t\t\t\t\".flex.flex-column.flex-grow-shrink-half\",\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\t\t\t\tflex: \"1 1 60%\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tthis._renderRightColumn(),\n\t\t\t\t\t\t  )\n\t\t\t\t\t\t: null,\n\t\t\t\t]),\n\t\t\t],\n\t\t)\n\t}\n\n\t_renderHeader(): Children {\n\t\tconst selectedTemplate = this._templateModel.getSelectedTemplate()\n\n\t\treturn m(\".flex-space-between.center-vertically.pl.pr-s\", [\n\t\t\tm(\".flex-start\", [m(\".flex.center-vertically\", this._renderSearchBar()), this._renderAddButton()]),\n\t\t\tm(\".flex-end\", [\n\t\t\t\tselectedTemplate\n\t\t\t\t\t? this._renderEditButtons(selectedTemplate) // Right header wrapper\n\t\t\t\t\t: null,\n\t\t\t]),\n\t\t])\n\t}\n\n\t_renderSearchBar: () => Children = () => {\n\t\treturn m(TemplateSearchBar, {\n\t\t\tvalue: this._searchBarValue,\n\t\t\tplaceholder: \"filter_label\",\n\t\t\tkeyHandler: (keyPress) => {\n\t\t\t\tif (isKeyPressed(keyPress.keyCode, Keys.DOWN, Keys.UP)) {\n\t\t\t\t\t// This duplicates the listener set in this._shortcuts\n\t\t\t\t\t// because the input consumes the event\n\t\t\t\t\tthis._templateModel.selectNextTemplate(isKeyPressed(keyPress.keyCode, Keys.UP) ? SELECT_PREV_TEMPLATE : SELECT_NEXT_TEMPLATE)\n\n\t\t\t\t\treturn false\n\t\t\t\t} else {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t},\n\t\t\toninput: (value) => {\n\t\t\t\tthis._debounceFilter(value)\n\t\t\t},\n\t\t\toncreate: (vnode) => {\n\t\t\t\tthis._inputDom = vnode.dom.firstElementChild as HTMLElement // firstElementChild is the input field of the input wrapper\n\t\t\t},\n\t\t})\n\t}\n\n\t_renderAddButton(): Children {\n\t\tconst attrs = this._createAddButtonAttributes()\n\n\t\treturn m(\n\t\t\t\"\",\n\t\t\t{\n\t\t\t\tonkeydown: (e: KeyboardEvent) => {\n\t\t\t\t\t// prevents tabbing into the background of the modal\n\t\t\t\t\tif (isKeyPressed(e.keyCode, Keys.TAB) && !this._templateModel.getSelectedTemplate()) {\n\t\t\t\t\t\tthis._inputDom?.focus()\n\n\t\t\t\t\t\te.preventDefault()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t\tattrs ? m(IconButton, attrs as IconButtonAttrs) : null,\n\t\t)\n\t}\n\n\t_createAddButtonAttributes(): IconButtonAttrs | null {\n\t\tconst templateGroupInstances = this._templateModel.getTemplateGroupInstances()\n\n\t\tconst writeableGroups = templateGroupInstances.filter((instance) =>\n\t\t\thasCapabilityOnGroup(locator.logins.getUserController().user, instance.group, ShareCapability.Write),\n\t\t)\n\n\t\tif (templateGroupInstances.length === 0) {\n\t\t\treturn {\n\t\t\t\ttitle: \"createTemplate_action\",\n\t\t\t\tclick: () => {\n\t\t\t\t\tcreateInitialTemplateListIfAllowed().then((groupRoot) => {\n\t\t\t\t\t\tif (groupRoot) {\n\t\t\t\t\t\t\tthis.showTemplateEditor(null, groupRoot)\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t\ticon: Icons.Add,\n\t\t\t\tcolors: ButtonColor.DrawerNav,\n\t\t\t}\n\t\t} else if (writeableGroups.length === 1) {\n\t\t\treturn {\n\t\t\t\ttitle: \"createTemplate_action\",\n\t\t\t\tclick: () => this.showTemplateEditor(null, writeableGroups[0].groupRoot),\n\t\t\t\ticon: Icons.Add,\n\t\t\t\tcolors: ButtonColor.DrawerNav,\n\t\t\t}\n\t\t} else if (writeableGroups.length > 1) {\n\t\t\treturn attachDropdown({\n\t\t\t\tmainButtonAttrs: {\n\t\t\t\t\ttitle: \"createTemplate_action\",\n\t\t\t\t\ticon: Icons.Add,\n\t\t\t\t\tcolors: ButtonColor.DrawerNav,\n\t\t\t\t},\n\t\t\t\tchildAttrs: () =>\n\t\t\t\t\twriteableGroups.map((groupInstances) => {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tlabel: () => getSharedGroupName(groupInstances.groupInfo, locator.logins.getUserController(), true),\n\t\t\t\t\t\t\tclick: () => this.showTemplateEditor(null, groupInstances.groupRoot),\n\t\t\t\t\t\t}\n\t\t\t\t\t}),\n\t\t\t})\n\t\t} else {\n\t\t\treturn null\n\t\t}\n\t}\n\n\t_renderEditButtons(selectedTemplate: EmailTemplate): Children {\n\t\tconst selectedContent = this._templateModel.getSelectedContent()\n\n\t\tconst selectedGroup = this._templateModel.getSelectedTemplateGroupInstance()\n\n\t\tconst canEdit = !!selectedGroup && hasCapabilityOnGroup(locator.logins.getUserController().user, selectedGroup.group, ShareCapability.Write)\n\t\treturn [\n\t\t\tm(\".flex.flex-column.justify-center.mr-m\", selectedContent ? m(\"\", lang.get(languageByCode[selectedContent.languageCode].textId)) : \"\"),\n\t\t\tm(\n\t\t\t\tIconButton,\n\t\t\t\tattachDropdown({\n\t\t\t\t\tmainButtonAttrs: {\n\t\t\t\t\t\ttitle: \"chooseLanguage_action\",\n\t\t\t\t\t\ticon: Icons.Language,\n\t\t\t\t\t},\n\t\t\t\t\tchildAttrs: () =>\n\t\t\t\t\t\tselectedTemplate.contents.map((content) => {\n\t\t\t\t\t\t\tconst langCode: LanguageCode = downcast(content.languageCode)\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tlabel: () => lang.get(languageByCode[langCode].textId),\n\t\t\t\t\t\t\t\tclick: (e: MouseEvent) => {\n\t\t\t\t\t\t\t\t\te.stopPropagation()\n\t\t\t\t\t\t\t\t\tthis._templateModel.setSelectedContentLanguage(langCode)\n\t\t\t\t\t\t\t\t\tthis._inputDom?.focus()\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}),\n\t\t\t\t}),\n\t\t\t),\n\t\t\tcanEdit\n\t\t\t\t? [\n\t\t\t\t\t\tm(IconButton, {\n\t\t\t\t\t\t\ttitle: \"editTemplate_action\",\n\t\t\t\t\t\t\tclick: () =>\n\t\t\t\t\t\t\t\tlocator.entityClient\n\t\t\t\t\t\t\t\t\t.load(TemplateGroupRootTypeRef, neverNull(selectedTemplate._ownerGroup))\n\t\t\t\t\t\t\t\t\t.then((groupRoot) => this.showTemplateEditor(selectedTemplate, groupRoot)),\n\t\t\t\t\t\t\ticon: Icons.Edit,\n\t\t\t\t\t\t\tcolors: ButtonColor.DrawerNav,\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tm(IconButton, {\n\t\t\t\t\t\t\ttitle: \"remove_action\",\n\t\t\t\t\t\t\tclick: () => {\n\t\t\t\t\t\t\t\tgetConfirmation(\"deleteTemplate_msg\").confirmed(() => locator.entityClient.erase(selectedTemplate))\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\ticon: Icons.Trash,\n\t\t\t\t\t\t\tcolors: ButtonColor.DrawerNav,\n\t\t\t\t\t\t}),\n\t\t\t\t  ]\n\t\t\t\t: null,\n\t\t\tm(\".pr-s\", m(\".nav-bar-spacer\")),\n\t\t\tm(\n\t\t\t\t\"\",\n\t\t\t\t{\n\t\t\t\t\tonkeydown: (e: KeyboardEvent) => {\n\t\t\t\t\t\t// prevents tabbing into the background of the modal\n\t\t\t\t\t\tif (isKeyPressed(e.keyCode, Keys.TAB)) {\n\t\t\t\t\t\t\tthis._inputDom?.focus()\n\n\t\t\t\t\t\t\te.preventDefault()\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tm(Button, this._selectTemplateButtonAttrs),\n\t\t\t),\n\t\t]\n\t}\n\n\t_renderList(): Children {\n\t\treturn m(ScrollSelectList, {\n\t\t\titems: this._templateModel.searchResults(),\n\t\t\tselectedItem: this._templateModel.selectedTemplate(),\n\t\t\tonItemSelected: this._templateModel.selectedTemplate,\n\t\t\temptyListMessage: () => (this._templateModel.isLoaded() ? \"nothingFound_label\" : \"loadingTemplates_label\"),\n\t\t\twidth: TEMPLATE_LIST_ENTRY_WIDTH,\n\t\t\trenderItem: (template: EmailTemplate) =>\n\t\t\t\tm(TemplatePopupResultRow, {\n\t\t\t\t\ttemplate: template,\n\t\t\t\t}),\n\t\t\tonItemDoubleClicked: (_: EmailTemplate) => {\n\t\t\t\tconst selected = this._templateModel.getSelectedContent()\n\n\t\t\t\tif (selected) {\n\t\t\t\t\tthis._onSelect(selected.text)\n\n\t\t\t\t\tthis._close()\n\t\t\t\t}\n\t\t\t},\n\t\t})\n\t}\n\n\t_renderRightColumn(): Children {\n\t\tconst template = this._templateModel.getSelectedTemplate()\n\n\t\tif (template) {\n\t\t\treturn [\n\t\t\t\tm(TemplateExpander, {\n\t\t\t\t\ttemplate: template,\n\t\t\t\t\tmodel: this._templateModel,\n\t\t\t\t}),\n\t\t\t]\n\t\t} else {\n\t\t\treturn null\n\t\t}\n\t}\n\n\t_isScreenWideEnough(): boolean {\n\t\treturn window.innerWidth > TEMPLATE_POPUP_TWO_COLUMN_MIN_WIDTH\n\t}\n\n\t_getWindowWidthChange(): number {\n\t\treturn window.innerWidth - this._initialWindowWidth\n\t}\n\n\tshow() {\n\t\tmodal.display(this, false)\n\t}\n\n\t_close(): void {\n\t\tmodal.remove(this)\n\t}\n\n\tbackgroundClick(e: MouseEvent): void {\n\t\tthis._onSelect(\"\")\n\n\t\tthis._close()\n\t}\n\n\thideAnimation(): Promise<void> {\n\t\treturn Promise.resolve()\n\t}\n\n\tonClose(): void {\n\t\tthis._redrawStream.end(true)\n\t}\n\n\tshortcuts(): Shortcut[] {\n\t\treturn this._shortcuts\n\t}\n\n\tpopState(e: Event): boolean {\n\t\treturn true\n\t}\n\n\tshowTemplateEditor(templateToEdit: EmailTemplate | null, groupRoot: TemplateGroupRoot) {\n\t\timport(\"../../settings/TemplateEditor\").then((editor) => {\n\t\t\teditor.showTemplateEditor(templateToEdit, groupRoot)\n\t\t})\n\t}\n}\n","import { Editor } from \"../../gui/editor/Editor\"\nimport { isKeyPressed } from \"../../misc/KeyManager\"\nimport { downcast, getFirstOrThrow } from \"@tutao/tutanota-utils\"\nimport { Keys } from \"../../api/common/TutanotaConstants\"\nimport { TEMPLATE_SHORTCUT_PREFIX, TemplatePopupModel } from \"../model/TemplatePopupModel\"\nimport { lang, languageByCode, LanguageViewModel } from \"../../misc/LanguageViewModel\"\nimport { Dropdown } from \"../../gui/base/Dropdown.js\"\nimport { modal } from \"../../gui/base/Modal\"\nimport { showTemplatePopupInEditor } from \"./TemplatePopup\"\n\nexport function registerTemplateShortcutListener(editor: Editor, templateModel: TemplatePopupModel): TemplateShortcutListener {\n\tconst listener = new TemplateShortcutListener(editor, templateModel, lang)\n\teditor.addEventListener(\"keydown\", (event: KeyboardEvent) => listener.handleKeyDown(event))\n\teditor.addEventListener(\"cursor\", (event: CustomEvent<{ range: Range | null }>) => listener.handleCursorChange(event))\n\treturn listener\n}\n\nclass TemplateShortcutListener {\n\t_currentCursorPosition: Range | null\n\t_editor: Editor\n\t_templateModel: TemplatePopupModel\n\t_lang: LanguageViewModel\n\n\tconstructor(editor: Editor, templateModel: TemplatePopupModel, lang: LanguageViewModel) {\n\t\tthis._editor = editor\n\t\tthis._currentCursorPosition = null\n\t\tthis._templateModel = templateModel\n\t\tthis._lang = lang\n\t}\n\n\t// add this event listener to handle quick selection of templates inside the editor\n\thandleKeyDown(event: KeyboardEvent) {\n\t\tif (isKeyPressed(event.keyCode, Keys.TAB) && this._currentCursorPosition) {\n\t\t\tconst cursorEndPos = this._currentCursorPosition\n\t\t\tconst text = cursorEndPos.startContainer.nodeType === Node.TEXT_NODE ? cursorEndPos.startContainer.textContent ?? \"\" : \"\"\n\t\t\tconst templateShortcutStartIndex = text.lastIndexOf(TEMPLATE_SHORTCUT_PREFIX)\n\t\t\tconst lastWhiteSpaceIndex = text.search(/\\s\\S*$/)\n\n\t\t\tif (\n\t\t\t\ttemplateShortcutStartIndex !== -1 &&\n\t\t\t\ttemplateShortcutStartIndex < cursorEndPos.startOffset &&\n\t\t\t\ttemplateShortcutStartIndex > lastWhiteSpaceIndex\n\t\t\t) {\n\t\t\t\t// stopPropagation & preventDefault to prevent tabbing to \"close\" button or tabbing into background\n\t\t\t\tevent.stopPropagation()\n\t\t\t\tevent.preventDefault()\n\t\t\t\tconst range = document.createRange()\n\t\t\t\trange.setStart(cursorEndPos.startContainer, templateShortcutStartIndex)\n\t\t\t\trange.setEnd(cursorEndPos.startContainer, cursorEndPos.startOffset)\n\n\t\t\t\tthis._editor.setSelection(range)\n\n\t\t\t\t// find and insert template\n\t\t\t\tconst selectedText = this._editor.getSelectedText()\n\n\t\t\t\tconst template = this._templateModel.findTemplateWithTag(selectedText)\n\n\t\t\t\tif (template) {\n\t\t\t\t\tif (template.contents.length > 1) {\n\t\t\t\t\t\t// multiple languages\n\t\t\t\t\t\t// show dropdown to select language\n\t\t\t\t\t\tlet buttons = template.contents.map((content) => {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tlabel: () => this._lang.get(languageByCode[downcast(content.languageCode)].textId),\n\t\t\t\t\t\t\t\tclick: () => {\n\t\t\t\t\t\t\t\t\tthis._editor.insertHTML(content.text)\n\n\t\t\t\t\t\t\t\t\tthis._editor.focus()\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t\tconst dropdown = new Dropdown(() => buttons, 200)\n\t\t\t\t\t\tdropdown.setOrigin(this._editor.getCursorPosition())\n\t\t\t\t\t\tmodal.displayUnique(dropdown, false)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._editor.insertHTML(getFirstOrThrow(template.contents).text)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tshowTemplatePopupInEditor(this._templateModel, this._editor, null, selectedText)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\thandleCursorChange(event: CustomEvent<{ range: Range | null }>) {\n\t\tthis._currentCursorPosition = event.detail.range\n\t}\n}\n","import m, { Children, Component, Vnode } from \"mithril\"\nimport type { KnowledgeBaseEntry } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport { px } from \"../../gui/size\"\n\nexport type KnowledgebaseListEntryAttrs = {\n\tentry: KnowledgeBaseEntry\n}\nexport const KNOWLEDGEBASE_LIST_ENTRY_HEIGHT = 50\n\n/**\n *  Renders one list entry of the knowledgeBase\n */\nexport class KnowledgeBaseListEntry implements Component<KnowledgebaseListEntryAttrs> {\n\tview(vnode: Vnode<KnowledgebaseListEntryAttrs>): Children {\n\t\tconst { title, keywords } = vnode.attrs.entry\n\t\treturn m(\n\t\t\t\".flex.flex-column.overflow-hidden.full-width\",\n\t\t\t{\n\t\t\t\tstyle: {\n\t\t\t\t\theight: px(KNOWLEDGEBASE_LIST_ENTRY_HEIGHT),\n\t\t\t\t},\n\t\t\t},\n\t\t\t[\n\t\t\t\tm(\".text-ellipsis.mb-xs.b\", title),\n\t\t\t\tm(\".flex.badge-line-height.text-ellipsis\", [\n\t\t\t\t\tkeywords.map((keyword) => {\n\t\t\t\t\t\treturn m(\".b.small.teamLabel.pl-s.pr-s.border-radius.no-wrap.small.mr-s.min-content\", keyword.keyword)\n\t\t\t\t\t}),\n\t\t\t\t]),\n\t\t\t],\n\t\t)\n\t}\n}\n","import m, { Children, Component, Vnode } from \"mithril\"\nimport type { KnowledgeBaseEntry } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport { TemplateGroupRootTypeRef } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport { memoized, neverNull, noOp, ofClass, startsWith } from \"@tutao/tutanota-utils\"\nimport { htmlSanitizer } from \"../../misc/HtmlSanitizer\"\nimport type { ButtonAttrs } from \"../../gui/base/Button.js\"\nimport { Button, ButtonType } from \"../../gui/base/Button.js\"\nimport { Icons } from \"../../gui/base/icons/Icons\"\nimport { locator } from \"../../api/main/MainLocator\"\nimport { getConfirmation } from \"../../gui/base/GuiUtils\"\nimport { NotFoundError } from \"../../api/common/error/RestError\"\nimport { IconButton } from \"../../gui/base/IconButton.js\"\n\ntype KnowledgeBaseEntryViewAttrs = {\n\tentry: KnowledgeBaseEntry\n\tonTemplateSelected: (arg0: IdTuple) => unknown\n\treadonly: boolean\n}\n\n/**\n *  Renders one knowledgeBase entry\n */\nexport class KnowledgeBaseEntryView implements Component<KnowledgeBaseEntryViewAttrs> {\n\t_sanitizedEntry: (arg0: KnowledgeBaseEntry) => {\n\t\tcontent: string\n\t}\n\n\tconstructor() {\n\t\tthis._sanitizedEntry = memoized((entry) => {\n\t\t\treturn {\n\t\t\t\tcontent: htmlSanitizer.sanitizeHTML(entry.description, {\n\t\t\t\t\tblockExternalContent: true,\n\t\t\t\t}).html,\n\t\t\t}\n\t\t})\n\t}\n\n\tview({ attrs }: Vnode<KnowledgeBaseEntryViewAttrs>): Children {\n\t\treturn m(\".flex.flex-column\", [this._renderContent(attrs)])\n\t}\n\n\t_renderContent(attrs: KnowledgeBaseEntryViewAttrs): Children {\n\t\tconst { entry, readonly } = attrs\n\t\treturn m(\n\t\t\t\"\",\n\t\t\t{\n\t\t\t\tonclick: (event: MouseEvent) => {\n\t\t\t\t\tthis._handleAnchorClick(event, attrs)\n\t\t\t\t},\n\t\t\t},\n\t\t\t[\n\t\t\t\tm(\n\t\t\t\t\t\".flex.mt-l.center-vertically.selectable\",\n\t\t\t\t\tm(\".h4.text-ellipsis\", entry.title),\n\t\t\t\t\t!readonly ? [m(\".flex.flex-grow.justify-end\", [this.renderEditButton(entry), this.renderRemoveButton(entry)])] : null,\n\t\t\t\t),\n\t\t\t\tm(\"\", [\n\t\t\t\t\tm(\".mt-s.flex.mt-s.wrap\", [\n\t\t\t\t\t\tentry.keywords.map((entryKeyword) => {\n\t\t\t\t\t\t\treturn m(\".keyword-bubble.selectable\", entryKeyword.keyword)\n\t\t\t\t\t\t}),\n\t\t\t\t\t]),\n\t\t\t\t\tm(\".flex.flex-column.mt-s\", [m(\".editor-border.text-break.selectable\", m.trust(this._sanitizedEntry(entry).content))]),\n\t\t\t\t]),\n\t\t\t],\n\t\t)\n\t}\n\n\tprivate renderRemoveButton(entry: KnowledgeBaseEntry) {\n\t\treturn m(IconButton, {\n\t\t\ttitle: \"remove_action\",\n\t\t\ticon: Icons.Trash,\n\t\t\tclick: () => {\n\t\t\t\tgetConfirmation(\"deleteEntryConfirm_msg\").confirmed(() => locator.entityClient.erase(entry).catch(ofClass(NotFoundError, noOp)))\n\t\t\t},\n\t\t})\n\t}\n\n\tprivate renderEditButton(entry: KnowledgeBaseEntry) {\n\t\treturn m(IconButton, {\n\t\t\ttitle: \"edit_action\",\n\t\t\ticon: Icons.Edit,\n\t\t\tclick: () => {\n\t\t\t\timport(\"../../settings/KnowledgeBaseEditor\").then(({ showKnowledgeBaseEditor }) => {\n\t\t\t\t\tlocator.entityClient.load(TemplateGroupRootTypeRef, neverNull(entry._ownerGroup)).then((groupRoot) => {\n\t\t\t\t\t\tshowKnowledgeBaseEditor(entry, groupRoot)\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t},\n\t\t})\n\t}\n\n\t_handleAnchorClick(event: Event, attrs: KnowledgeBaseEntryViewAttrs): void {\n\t\tlet target = event.target as any\n\n\t\tif (target && target.closest) {\n\t\t\tlet anchorElement = target.closest(\"a\")\n\n\t\t\tif (anchorElement && startsWith(anchorElement.href, \"tutatemplate:\")) {\n\t\t\t\tevent.preventDefault()\n\t\t\t\tconst [listId, elementId] = new URL(anchorElement.href).pathname.split(\"/\")\n\t\t\t\tattrs.onTemplateSelected([listId, elementId])\n\t\t\t}\n\t\t}\n\t}\n}\n","import m, { Children, Component, Vnode } from \"mithril\"\nimport { KnowledgeBaseModel } from \"../model/KnowledgeBaseModel\"\nimport type { EmailTemplate, KnowledgeBaseEntry } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport { KNOWLEDGEBASE_LIST_ENTRY_HEIGHT, KnowledgeBaseListEntry } from \"./KnowledgeBaseListEntry\"\nimport { lang } from \"../../misc/LanguageViewModel\"\nimport stream from \"mithril/stream\"\nimport Stream from \"mithril/stream\"\nimport { KnowledgeBaseEntryView } from \"./KnowledgeBaseEntryView\"\nimport { NotFoundError } from \"../../api/common/error/RestError\"\nimport { Dialog } from \"../../gui/base/Dialog\"\nimport { TextField } from \"../../gui/base/TextField.js\"\nimport { makeListSelectionChangedScrollHandler } from \"../../gui/base/GuiUtils\"\nimport { ofClass } from \"@tutao/tutanota-utils\"\n\nexport type KnowledgebaseDialogContentAttrs = {\n\treadonly onTemplateSelect: (arg0: EmailTemplate) => void\n\treadonly model: KnowledgeBaseModel\n}\n\n/**\n *  Renders the SearchBar and the pages (list, entry, template) of the knowledgeBase besides the MailEditor\n */\nexport class KnowledgeBaseDialogContent implements Component<KnowledgebaseDialogContentAttrs> {\n\tprivate _streams: Array<Stream<any>>\n\tprivate filterValue: string = \"\"\n\tprivate _selectionChangedListener!: Stream<void>\n\n\tconstructor() {\n\t\tthis._streams = []\n\t}\n\n\toncreate({ attrs }: Vnode<KnowledgebaseDialogContentAttrs>) {\n\t\tconst { model } = attrs\n\n\t\tthis._streams.push(\n\t\t\tstream.combine(() => {\n\t\t\t\tm.redraw()\n\t\t\t}, [model.selectedEntry, model.filteredEntries]),\n\t\t)\n\t}\n\n\tonremove() {\n\t\tfor (let stream of this._streams) {\n\t\t\tstream.end(true)\n\t\t}\n\t}\n\n\tview({ attrs }: Vnode<KnowledgebaseDialogContentAttrs>): Children {\n\t\tconst model = attrs.model\n\t\tconst selectedEntry = model.selectedEntry()\n\t\treturn selectedEntry\n\t\t\t? m(KnowledgeBaseEntryView, {\n\t\t\t\t\tentry: selectedEntry,\n\t\t\t\t\tonTemplateSelected: (templateId) => {\n\t\t\t\t\t\tmodel\n\t\t\t\t\t\t\t.loadTemplate(templateId)\n\t\t\t\t\t\t\t.then((fetchedTemplate) => {\n\t\t\t\t\t\t\t\tattrs.onTemplateSelect(fetchedTemplate)\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.catch(ofClass(NotFoundError, () => Dialog.message(\"templateNotExists_msg\")))\n\t\t\t\t\t},\n\t\t\t\t\treadonly: model.isReadOnly(selectedEntry),\n\t\t\t  })\n\t\t\t: [\n\t\t\t\t\tm(TextField, {\n\t\t\t\t\t\tlabel: () => lang.get(\"filter_label\"),\n\t\t\t\t\t\tvalue: this.filterValue,\n\t\t\t\t\t\toninput: (value) => {\n\t\t\t\t\t\t\tthis.filterValue = value\n\t\t\t\t\t\t\tmodel.filter(value)\n\t\t\t\t\t\t\tm.redraw()\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\tthis._renderKeywords(model),\n\t\t\t\t\tthis._renderList(model, attrs),\n\t\t\t  ]\n\t}\n\n\t_renderKeywords(model: KnowledgeBaseModel): Children {\n\t\tconst matchedKeywords = model.getMatchedKeywordsInContent()\n\t\treturn m(\".flex.mt-s.wrap\", [\n\t\t\tmatchedKeywords.length > 0 ? m(\".small.full-width\", lang.get(\"matchingKeywords_label\")) : null,\n\t\t\tmatchedKeywords.map((keyword) => {\n\t\t\t\treturn m(\".keyword-bubble-no-padding.plr-button.pl-s.pr-s.border-radius.no-wrap.mr-s.min-content\", keyword)\n\t\t\t}),\n\t\t])\n\t}\n\n\t_renderList(model: KnowledgeBaseModel, attrs: KnowledgebaseDialogContentAttrs): Children {\n\t\treturn m(\n\t\t\t\".mt-s.scroll\",\n\t\t\t{\n\t\t\t\toncreate: (vnode) => {\n\t\t\t\t\tthis._selectionChangedListener = model.selectedEntry.map(\n\t\t\t\t\t\tmakeListSelectionChangedScrollHandler(\n\t\t\t\t\t\t\tvnode.dom as HTMLElement,\n\t\t\t\t\t\t\tKNOWLEDGEBASE_LIST_ENTRY_HEIGHT,\n\t\t\t\t\t\t\tmodel.getSelectedEntryIndex.bind(model),\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t},\n\t\t\t\tonbeforeremove: () => {\n\t\t\t\t\tthis._selectionChangedListener.end()\n\t\t\t\t},\n\t\t\t},\n\t\t\t[\n\t\t\t\tmodel.containsResult()\n\t\t\t\t\t? model.filteredEntries().map((entry) => this._renderListEntry(model, entry))\n\t\t\t\t\t: m(\".center\", lang.get(\"noEntryFound_label\")),\n\t\t\t],\n\t\t)\n\t}\n\n\t_renderListEntry(model: KnowledgeBaseModel, entry: KnowledgeBaseEntry): Children {\n\t\treturn m(\".flex.flex-column.click.hoverable-list-item\", [\n\t\t\tm(\n\t\t\t\t\".flex\",\n\t\t\t\t{\n\t\t\t\t\tonclick: () => {\n\t\t\t\t\t\tmodel.selectedEntry(entry)\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t[\n\t\t\t\t\tm(KnowledgeBaseListEntry, {\n\t\t\t\t\t\tentry: entry,\n\t\t\t\t\t}),\n\t\t\t\t\tm(\"\", {\n\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\twidth: \"17.1px\",\n\t\t\t\t\t\t\theight: \"16px\",\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t],\n\t\t\t),\n\t\t])\n\t}\n}\n","import { KnowledgeBaseModel } from \"../model/KnowledgeBaseModel\"\nimport { Editor } from \"../../gui/editor/Editor\"\nimport type { KnowledgebaseDialogContentAttrs } from \"./KnowledgeBaseDialogContent\"\nimport { KnowledgeBaseDialogContent } from \"./KnowledgeBaseDialogContent\"\nimport { showTemplatePopupInEditor } from \"../../templates/view/TemplatePopup\"\nimport type { ButtonAttrs } from \"../../gui/base/Button.js\"\nimport { ButtonType } from \"../../gui/base/Button.js\"\nimport type { DialogHeaderBarAttrs } from \"../../gui/base/DialogHeaderBar\"\nimport { lang } from \"../../misc/LanguageViewModel\"\nimport type { KnowledgeBaseEntry, TemplateGroupRoot } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport type { lazy } from \"@tutao/tutanota-utils\"\nimport { createDropdown } from \"../../gui/base/Dropdown.js\"\nimport stream from \"mithril/stream\"\nimport Stream from \"mithril/stream\"\nimport type { DialogInjectionRightAttrs } from \"../../gui/base/DialogInjectionRight\"\nimport { TemplatePopupModel } from \"../../templates/model/TemplatePopupModel\"\nimport { getSharedGroupName } from \"../../sharing/GroupUtils\"\n\nexport function createKnowledgeBaseDialogInjection(\n\tknowledgeBase: KnowledgeBaseModel,\n\ttemplateModel: TemplatePopupModel,\n\teditor: Editor,\n): DialogInjectionRightAttrs<KnowledgebaseDialogContentAttrs> {\n\tconst knowledgebaseAttrs: KnowledgebaseDialogContentAttrs = {\n\t\tonTemplateSelect: (template) => {\n\t\t\tshowTemplatePopupInEditor(templateModel, editor, template, \"\")\n\t\t},\n\t\tmodel: knowledgeBase,\n\t}\n\tconst isDialogVisible = stream(false)\n\treturn {\n\t\tvisible: isDialogVisible,\n\t\theaderAttrs: _createHeaderAttrs(knowledgebaseAttrs, isDialogVisible),\n\t\tcomponentAttrs: knowledgebaseAttrs,\n\t\tcomponent: KnowledgeBaseDialogContent,\n\t}\n}\n\nfunction _createHeaderAttrs(attrs: KnowledgebaseDialogContentAttrs, isDialogVisible: Stream<boolean>): lazy<DialogHeaderBarAttrs> {\n\treturn () => {\n\t\tconst selectedEntry = attrs.model.selectedEntry()\n\t\treturn selectedEntry ? createEntryViewHeader(selectedEntry, attrs.model) : createListViewHeader(attrs.model, isDialogVisible)\n\t}\n}\n\nfunction createEntryViewHeader(entry: KnowledgeBaseEntry, model: KnowledgeBaseModel): DialogHeaderBarAttrs {\n\treturn {\n\t\tleft: [\n\t\t\t{\n\t\t\t\tlabel: \"back_action\",\n\t\t\t\tclick: () => model.selectedEntry(null),\n\t\t\t\ttype: ButtonType.Secondary,\n\t\t\t},\n\t\t],\n\t\tmiddle: () => lang.get(\"knowledgebase_label\"),\n\t}\n}\n\nfunction createListViewHeader(model: KnowledgeBaseModel, isDialogVisible: Stream<boolean>): DialogHeaderBarAttrs {\n\treturn {\n\t\tleft: () => [\n\t\t\t{\n\t\t\t\tlabel: \"close_alt\",\n\t\t\t\tclick: () => isDialogVisible(false),\n\t\t\t\ttype: ButtonType.Primary,\n\t\t\t},\n\t\t],\n\t\tmiddle: () => lang.get(\"knowledgebase_label\"),\n\t\tright: [createAddButtonAttrs(model)],\n\t}\n}\n\nfunction createAddButtonAttrs(model: KnowledgeBaseModel): ButtonAttrs {\n\tconst templateGroupInstances = model.getTemplateGroupInstances()\n\n\tif (templateGroupInstances.length === 1) {\n\t\treturn {\n\t\t\tlabel: \"add_action\",\n\t\t\tclick: () => {\n\t\t\t\tshowKnowledgeBaseEditor(null, templateGroupInstances[0].groupRoot)\n\t\t\t},\n\t\t\ttype: ButtonType.Primary,\n\t\t}\n\t} else {\n\t\treturn {\n\t\t\tlabel: \"add_action\",\n\t\t\ttype: ButtonType.Primary,\n\t\t\tclick: createDropdown({\n\t\t\t\tlazyButtons: () =>\n\t\t\t\t\ttemplateGroupInstances.map((groupInstances) => {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tlabel: () => getSharedGroupName(groupInstances.groupInfo, model.userController, true),\n\t\t\t\t\t\t\tclick: () => {\n\t\t\t\t\t\t\t\tshowKnowledgeBaseEditor(null, groupInstances.groupRoot)\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\t\t\t\t\t}),\n\t\t\t}),\n\t\t}\n\t}\n}\n\nfunction showKnowledgeBaseEditor(entryToEdit: KnowledgeBaseEntry | null, groupRoot: TemplateGroupRoot) {\n\timport(\"../../settings/KnowledgeBaseEditor\").then((editor) => {\n\t\teditor.showKnowledgeBaseEditor(entryToEdit, groupRoot)\n\t})\n}\n","import type { KnowledgeBaseEntry } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport { search } from \"../../api/common/utils/PlainTextSearch\"\n\nexport function knowledgeBaseSearch(input: string, allEntries: ReadonlyArray<KnowledgeBaseEntry>): ReadonlyArray<KnowledgeBaseEntry> {\n\treturn search(input, allEntries, [\"title\", \"description\", \"keywords.keyword\"], false)\n}\n","import type { KnowledgeBaseEntry } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport { KnowledgeBaseEntryTypeRef } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport type { EmailTemplate } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport { EmailTemplateTypeRef } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport type { EntityEventsListener, EntityUpdateData } from \"../../api/main/EventController\"\nimport { EventController, isUpdateForTypeRef } from \"../../api/main/EventController\"\nimport { EntityClient } from \"../../api/common/EntityClient\"\nimport { knowledgeBaseSearch } from \"./KnowledgeBaseSearchFilter\"\nimport type { LanguageCode } from \"../../misc/LanguageViewModel\"\nimport { lang } from \"../../misc/LanguageViewModel\"\nimport stream from \"mithril/stream\"\nimport { OperationType, ShareCapability } from \"../../api/common/TutanotaConstants\"\nimport { downcast, flat, LazyLoaded, noOp, promiseMap, SortedArray } from \"@tutao/tutanota-utils\"\nimport { getElementId, getEtId, getLetId, isSameId } from \"../../api/common/utils/EntityUtils\"\nimport type { TemplateGroupInstance } from \"../../templates/model/TemplateGroupModel\"\nimport { loadTemplateGroupInstance } from \"../../templates/model/TemplatePopupModel\"\nimport type { UserController } from \"../../api/main/UserController\"\nimport { hasCapabilityOnGroup } from \"../../sharing/GroupUtils\"\nimport Stream from \"mithril/stream\"\n\nexport const SELECT_NEXT_ENTRY = \"next\"\n\nfunction compareKnowledgeBaseEntriesForSort(entry1: KnowledgeBaseEntry, entry2: KnowledgeBaseEntry): number {\n\treturn entry1.title.localeCompare(entry2.title)\n}\n\n/**\n *   Model that holds main logic for the Knowledgebase.\n */\nexport class KnowledgeBaseModel {\n\t_allEntries: SortedArray<KnowledgeBaseEntry>\n\tfilteredEntries: Stream<ReadonlyArray<KnowledgeBaseEntry>>\n\tselectedEntry: Stream<KnowledgeBaseEntry | null>\n\t_allKeywords: Array<string>\n\t_matchedKeywordsInContent: Array<string | null>\n\t_filterValue: string\n\treadonly _eventController: EventController\n\treadonly _entityClient: EntityClient\n\treadonly _entityEventReceived: EntityEventsListener\n\t_groupInstances: Array<TemplateGroupInstance>\n\t_initialized: LazyLoaded<KnowledgeBaseModel>\n\treadonly userController: UserController\n\n\tconstructor(eventController: EventController, entityClient: EntityClient, userController: UserController) {\n\t\tthis._eventController = eventController\n\t\tthis._entityClient = entityClient\n\t\tthis.userController = userController\n\t\tthis._allEntries = SortedArray.empty(compareKnowledgeBaseEntriesForSort)\n\t\tthis._allKeywords = []\n\t\tthis._matchedKeywordsInContent = []\n\t\tthis.filteredEntries = stream(this._allEntries.array)\n\t\tthis.selectedEntry = stream<KnowledgeBaseEntry | null>(null)\n\t\tthis._filterValue = \"\"\n\n\t\tthis._entityEventReceived = (updates) => {\n\t\t\treturn this._entityUpdate(updates)\n\t\t}\n\n\t\tthis._eventController.addEntityListener(this._entityEventReceived)\n\n\t\tthis._groupInstances = []\n\t\tthis._allKeywords = []\n\t\tthis.filteredEntries(this._allEntries.array)\n\t\tthis.selectedEntry(this.containsResult() ? this.filteredEntries()[0] : null)\n\t\tthis._initialized = new LazyLoaded(() => {\n\t\t\tconst templateMemberships = this.userController.getTemplateMemberships()\n\n\t\t\tlet newGroupInstances: TemplateGroupInstance[] = []\n\t\t\treturn promiseMap(templateMemberships, (membership) => loadTemplateGroupInstance(membership, entityClient))\n\t\t\t\t.then((groupInstances) => {\n\t\t\t\t\tnewGroupInstances = groupInstances\n\t\t\t\t\treturn loadKnowledgebaseEntries(groupInstances, entityClient)\n\t\t\t\t})\n\t\t\t\t.then((knowledgebaseEntries) => {\n\t\t\t\t\tthis._allEntries.insertAll(knowledgebaseEntries)\n\n\t\t\t\t\tthis._groupInstances = newGroupInstances\n\t\t\t\t\tthis.initAllKeywords()\n\t\t\t\t\treturn this\n\t\t\t\t})\n\t\t})\n\t}\n\n\tinit(): Promise<KnowledgeBaseModel> {\n\t\treturn this._initialized.getAsync()\n\t}\n\n\tisInitialized(): boolean {\n\t\treturn this._initialized.isLoaded()\n\t}\n\n\tgetTemplateGroupInstances(): Array<TemplateGroupInstance> {\n\t\treturn this._groupInstances\n\t}\n\n\tinitAllKeywords() {\n\t\tthis._allKeywords = []\n\t\tthis._matchedKeywordsInContent = []\n\n\t\tthis._allEntries.array.forEach((entry) => {\n\t\t\tentry.keywords.forEach((keyword) => {\n\t\t\t\tthis._allKeywords.push(keyword.keyword)\n\t\t\t})\n\t\t})\n\t}\n\n\tisSelectedEntry(entry: KnowledgeBaseEntry): boolean {\n\t\treturn this.selectedEntry() === entry\n\t}\n\n\tcontainsResult(): boolean {\n\t\treturn this.filteredEntries().length > 0\n\t}\n\n\tgetAllKeywords(): Array<string> {\n\t\treturn this._allKeywords.sort()\n\t}\n\n\tgetMatchedKeywordsInContent(): Array<string | null> {\n\t\treturn this._matchedKeywordsInContent\n\t}\n\n\tgetLanguageFromTemplate(template: EmailTemplate): LanguageCode {\n\t\tconst clientLanguage = lang.code\n\t\tconst hasClientLanguage = template.contents.some((content) => content.languageCode === clientLanguage)\n\n\t\tif (hasClientLanguage) {\n\t\t\treturn clientLanguage\n\t\t}\n\n\t\treturn downcast(template.contents[0].languageCode)\n\t}\n\n\tsortEntriesByMatchingKeywords(emailContent: string) {\n\t\tthis._matchedKeywordsInContent = []\n\t\tconst emailContentNoTags = emailContent.replace(/(<([^>]+)>)/gi, \"\") // remove all html tags\n\n\t\tthis._allKeywords.forEach((keyword) => {\n\t\t\tif (emailContentNoTags.includes(keyword)) {\n\t\t\t\tthis._matchedKeywordsInContent.push(keyword)\n\t\t\t}\n\t\t})\n\n\t\tthis._allEntries = SortedArray.from(this._allEntries.array, (a, b) => this._compareEntriesByMatchedKeywords(a, b))\n\t\tthis._filterValue = \"\"\n\t\tthis.filteredEntries(this._allEntries.array)\n\t}\n\n\t_compareEntriesByMatchedKeywords(entry1: KnowledgeBaseEntry, entry2: KnowledgeBaseEntry): number {\n\t\tconst difference = this._getMatchedKeywordsNumber(entry2) - this._getMatchedKeywordsNumber(entry1)\n\n\t\treturn difference === 0 ? compareKnowledgeBaseEntriesForSort(entry1, entry2) : difference\n\t}\n\n\t_getMatchedKeywordsNumber(entry: KnowledgeBaseEntry): number {\n\t\tlet matches = 0\n\t\tentry.keywords.forEach((k) => {\n\t\t\tif (this._matchedKeywordsInContent.includes(k.keyword)) {\n\t\t\t\tmatches++\n\t\t\t}\n\t\t})\n\t\treturn matches\n\t}\n\n\tfilter(input: string): void {\n\t\tthis._filterValue = input\n\t\tconst inputTrimmed = input.trim()\n\n\t\tif (inputTrimmed) {\n\t\t\tthis.filteredEntries(knowledgeBaseSearch(inputTrimmed, this._allEntries.array))\n\t\t} else {\n\t\t\tthis.filteredEntries(this._allEntries.array)\n\t\t}\n\t}\n\n\tselectNextEntry(action: string): boolean {\n\t\t// returns true if selection is changed\n\t\tconst selectedIndex = this.getSelectedEntryIndex()\n\t\tconst nextIndex = selectedIndex + (action === SELECT_NEXT_ENTRY ? 1 : -1)\n\n\t\tif (nextIndex >= 0 && nextIndex < this.filteredEntries().length) {\n\t\t\tconst nextSelectedEntry = this.filteredEntries()[nextIndex]\n\t\t\tthis.selectedEntry(nextSelectedEntry)\n\t\t\treturn true\n\t\t}\n\n\t\treturn false\n\t}\n\n\tgetSelectedEntryIndex(): number {\n\t\tconst selectedEntry = this.selectedEntry()\n\t\tif (selectedEntry == null) {\n\t\t\treturn -1\n\t\t}\n\t\treturn this.filteredEntries().indexOf(selectedEntry)\n\t}\n\n\t_removeFromAllKeywords(keyword: string) {\n\t\tconst index = this._allKeywords.indexOf(keyword)\n\n\t\tif (index > -1) {\n\t\t\tthis._allKeywords.splice(index, 1)\n\t\t}\n\t}\n\n\tdispose() {\n\t\tthis._eventController.removeEntityListener(this._entityEventReceived)\n\t}\n\n\tloadTemplate(templateId: IdTuple): Promise<EmailTemplate> {\n\t\treturn this._entityClient.load(EmailTemplateTypeRef, templateId)\n\t}\n\n\tisReadOnly(entry: KnowledgeBaseEntry): boolean {\n\t\tconst instance = this._groupInstances.find((instance) => isSameId(entry._ownerGroup, getEtId(instance.group)))\n\n\t\treturn !instance || !hasCapabilityOnGroup(this.userController.user, instance.group, ShareCapability.Write)\n\t}\n\n\t_entityUpdate(updates: ReadonlyArray<EntityUpdateData>): Promise<void> {\n\t\treturn promiseMap(updates, (update) => {\n\t\t\tif (isUpdateForTypeRef(KnowledgeBaseEntryTypeRef, update)) {\n\t\t\t\tif (update.operation === OperationType.CREATE) {\n\t\t\t\t\treturn this._entityClient.load(KnowledgeBaseEntryTypeRef, [update.instanceListId, update.instanceId]).then((entry) => {\n\t\t\t\t\t\tthis._allEntries.insert(entry)\n\n\t\t\t\t\t\tthis.filter(this._filterValue)\n\t\t\t\t\t})\n\t\t\t\t} else if (update.operation === OperationType.UPDATE) {\n\t\t\t\t\treturn this._entityClient.load(KnowledgeBaseEntryTypeRef, [update.instanceListId, update.instanceId]).then((updatedEntry) => {\n\t\t\t\t\t\tthis._allEntries.removeFirst((e) => isSameId(getElementId(e), update.instanceId))\n\n\t\t\t\t\t\tthis._allEntries.insert(updatedEntry)\n\n\t\t\t\t\t\tthis.filter(this._filterValue)\n\t\t\t\t\t\tconst oldSelectedEntry = this.selectedEntry()\n\n\t\t\t\t\t\tif (oldSelectedEntry && isSameId(oldSelectedEntry._id, updatedEntry._id)) {\n\t\t\t\t\t\t\tthis.selectedEntry(updatedEntry)\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t} else if (update.operation === OperationType.DELETE) {\n\t\t\t\t\tconst selected = this.selectedEntry()\n\n\t\t\t\t\tif (selected && isSameId(getLetId(selected), [update.instanceListId, update.instanceId])) {\n\t\t\t\t\t\tthis.selectedEntry(null)\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._allEntries.removeFirst((e) => isSameId(getElementId(e), update.instanceId))\n\n\t\t\t\t\tthis.filter(this._filterValue)\n\t\t\t\t}\n\t\t\t}\n\t\t}).then(noOp)\n\t}\n}\n\nfunction loadKnowledgebaseEntries(templateGroups: Array<TemplateGroupInstance>, entityClient: EntityClient): Promise<Array<KnowledgeBaseEntry>> {\n\treturn promiseMap(templateGroups, (group) => entityClient.loadAll(KnowledgeBaseEntryTypeRef, group.groupRoot.knowledgeBase)).then((groupedTemplates) =>\n\t\tflat(groupedTemplates),\n\t)\n}\n","import m, { Children, Component, Vnode } from \"mithril\"\nimport stream from \"mithril/stream\"\nimport Stream from \"mithril/stream\"\nimport { Editor, ImagePasteEvent } from \"../../gui/editor/Editor\"\nimport type { Attachment, InitAsResponseArgs, SendMailModel } from \"./SendMailModel\"\nimport { Dialog } from \"../../gui/base/Dialog\"\nimport { lang } from \"../../misc/LanguageViewModel\"\nimport type { MailboxDetail } from \"../model/MailModel\"\nimport { checkApprovalStatus } from \"../../misc/LoginUtils\"\nimport {\n\tcheckAttachmentSize,\n\tconversationTypeString,\n\tcreateNewContact,\n\tgetEnabledMailAddressesWithUser,\n\tgetMailAddressDisplayText,\n\tLINE_BREAK,\n\tRecipientField,\n} from \"../model/MailUtils\"\nimport { locator } from \"../../api/main/MainLocator\"\nimport { ALLOWED_IMAGE_FORMATS, ConversationType, FeatureType, Keys, MailMethod } from \"../../api/common/TutanotaConstants\"\nimport { TooManyRequestsError } from \"../../api/common/error/RestError\"\nimport type { DialogHeaderBarAttrs } from \"../../gui/base/DialogHeaderBar\"\nimport { ButtonType } from \"../../gui/base/Button.js\"\nimport { attachDropdown, createDropdown, DropdownChildAttrs } from \"../../gui/base/Dropdown.js\"\nimport { isApp, isBrowser, isDesktop } from \"../../api/common/Env\"\nimport { Icons } from \"../../gui/base/icons/Icons\"\nimport { AnimationPromise, animations, height, opacity } from \"../../gui/animation/Animations\"\nimport type { TextFieldAttrs } from \"../../gui/base/TextField.js\"\nimport { Autocomplete, TextField, TextFieldType } from \"../../gui/base/TextField.js\"\nimport { chooseAndAttachFile, cleanupInlineAttachments, createAttachmentBubbleAttrs, getConfidentialStateMessage } from \"./MailEditorViewModel\"\nimport { ExpanderPanel } from \"../../gui/base/Expander\"\nimport { windowFacade } from \"../../misc/WindowFacade\"\nimport { UserError } from \"../../api/main/UserError\"\nimport { showProgressDialog } from \"../../gui/dialogs/ProgressDialog\"\nimport { htmlSanitizer } from \"../../misc/HtmlSanitizer\"\nimport { DropDownSelector } from \"../../gui/base/DropDownSelector.js\"\nimport type { File as TutanotaFile, MailboxProperties } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport { ContactTypeRef } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport type { InlineImages } from \"../view/MailViewer\"\nimport { FileOpenError } from \"../../api/common/error/FileOpenError\"\nimport type { lazy } from \"@tutao/tutanota-utils\"\nimport { cleanMatch, downcast, isNotNull, noOp, ofClass, typedValues } from \"@tutao/tutanota-utils\"\nimport { isCustomizationEnabledForCustomer } from \"../../api/common/utils/Utils\"\nimport { createInlineImage, replaceCidsWithInlineImages, replaceInlineImagesWithCids } from \"../view/MailGuiUtils\"\nimport { client } from \"../../misc/ClientDetector\"\nimport { appendEmailSignature } from \"../signature/Signature\"\nimport { showTemplatePopupInEditor } from \"../../templates/view/TemplatePopup\"\nimport { registerTemplateShortcutListener } from \"../../templates/view/TemplateShortcutListener\"\nimport { TemplatePopupModel } from \"../../templates/model/TemplatePopupModel\"\nimport { createKnowledgeBaseDialogInjection } from \"../../knowledgebase/view/KnowledgeBaseDialog\"\nimport { KnowledgeBaseModel } from \"../../knowledgebase/model/KnowledgeBaseModel\"\nimport { styles } from \"../../gui/styles\"\nimport { showMinimizedMailEditor } from \"../view/MinimizedMailEditorOverlay\"\nimport { SaveErrorReason, SaveStatus, SaveStatusEnum } from \"../model/MinimizedMailEditorViewModel\"\nimport { FileReference, isTutanotaFile } from \"../../api/common/utils/FileUtils\"\nimport { parseMailtoUrl } from \"../../misc/parsing/MailAddressParser\"\nimport { CancelledError } from \"../../api/common/error/CancelledError\"\nimport { Shortcut } from \"../../misc/KeyManager\"\nimport { Recipients, RecipientType } from \"../../api/common/recipients/Recipient\"\nimport { CompletenessIndicator } from \"../../gui/CompletenessIndicator.js\"\nimport { showUserError } from \"../../misc/ErrorHandlerImpl\"\nimport { MailRecipientsTextField } from \"../../gui/MailRecipientsTextField.js\"\nimport { getContactDisplayName } from \"../../contacts/model/ContactUtils\"\nimport { ResolvableRecipient } from \"../../api/main/RecipientsModel\"\nimport { isOfflineError } from \"../../api/common/utils/ErrorCheckUtils.js\"\nimport { animateToolbar, RichTextToolbar } from \"../../gui/base/RichTextToolbar.js\"\nimport { readLocalFiles } from \"../../file/FileController\"\nimport { IconButton, IconButtonAttrs } from \"../../gui/base/IconButton.js\"\nimport { ToggleButton, ToggleButtonAttrs } from \"../../gui/base/buttons/ToggleButton.js\"\nimport { BootIcons } from \"../../gui/base/icons/BootIcons.js\"\nimport { ButtonSize } from \"../../gui/base/ButtonSize.js\"\nimport { DialogInjectionRightAttrs } from \"../../gui/base/DialogInjectionRight.js\"\nimport { KnowledgebaseDialogContentAttrs } from \"../../knowledgebase/view/KnowledgeBaseDialogContent.js\"\nimport { MailWrapper } from \"../../api/common/MailWrapper.js\"\nimport { RecipientsSearchModel } from \"../../misc/RecipientsSearchModel.js\"\nimport { createDataFile, DataFile } from \"../../api/common/DataFile.js\"\nimport { AttachmentBubble } from \"../../gui/AttachmentBubble.js\"\n\nexport type MailEditorAttrs = {\n\tmodel: SendMailModel\n\tdoBlockExternalContent: Stream<boolean>\n\tdoShowToolbar: Stream<boolean>\n\tonload?: (editor: Editor) => void\n\tonclose?: (...args: Array<any>) => any\n\tselectedNotificationLanguage: Stream<string>\n\tdialog: lazy<Dialog>\n\ttemplateModel: TemplatePopupModel | null\n\tknowledgeBaseInjection: (editor: Editor) => Promise<DialogInjectionRightAttrs<KnowledgebaseDialogContentAttrs> | null>\n\tsearch: RecipientsSearchModel\n}\n\nexport function createMailEditorAttrs(\n\tmodel: SendMailModel,\n\tdoBlockExternalContent: boolean,\n\tdoFocusEditorOnLoad: boolean,\n\tdialog: lazy<Dialog>,\n\ttemplateModel: TemplatePopupModel | null,\n\tknowledgeBaseInjection: (editor: Editor) => Promise<DialogInjectionRightAttrs<KnowledgebaseDialogContentAttrs> | null>,\n\tsearch: RecipientsSearchModel,\n): MailEditorAttrs {\n\treturn {\n\t\tmodel,\n\t\tdoBlockExternalContent: stream(doBlockExternalContent),\n\t\tdoShowToolbar: stream<boolean>(false),\n\t\tselectedNotificationLanguage: stream(\"\"),\n\t\tdialog,\n\t\ttemplateModel,\n\t\tknowledgeBaseInjection: knowledgeBaseInjection,\n\t\tsearch,\n\t}\n}\n\nexport class MailEditor implements Component<MailEditorAttrs> {\n\tprivate attrs: MailEditorAttrs\n\n\teditor: Editor\n\n\tprivate readonly recipientFieldTexts = {\n\t\tto: stream(\"\"),\n\t\tcc: stream(\"\"),\n\t\tbcc: stream(\"\"),\n\t}\n\n\tmentionedInlineImages: Array<string>\n\tinlineImageElements: Array<HTMLElement>\n\ttemplateModel: TemplatePopupModel | null\n\tknowledgeBaseInjection: DialogInjectionRightAttrs<KnowledgebaseDialogContentAttrs> | null = null\n\tsendMailModel: SendMailModel\n\tprivate areDetailsExpanded: boolean\n\tprivate recipientShowConfidential: Map<string, boolean> = new Map()\n\n\tconstructor(vnode: Vnode<MailEditorAttrs>) {\n\t\tconst a = vnode.attrs\n\t\tthis.attrs = a\n\t\tthis.inlineImageElements = []\n\t\tthis.mentionedInlineImages = []\n\t\tconst model = a.model\n\t\tthis.sendMailModel = model\n\t\tthis.templateModel = a.templateModel\n\n\t\t// if we have any CC/BCC recipients, we should show these so, should the user send the mail, they know where it will be going to\n\t\tthis.areDetailsExpanded = model.bccRecipients().length + model.ccRecipients().length > 0\n\n\t\tthis.editor = new Editor(200, (html, isPaste) => {\n\t\t\tconst sanitized = htmlSanitizer.sanitizeFragment(html, {\n\t\t\t\tblockExternalContent: !isPaste && a.doBlockExternalContent(),\n\t\t\t})\n\t\t\tthis.mentionedInlineImages = sanitized.inlineImageCids\n\t\t\treturn sanitized.fragment\n\t\t})\n\n\t\tconst onEditorChanged = () => {\n\t\t\tcleanupInlineAttachments(this.editor.getDOM(), this.inlineImageElements, model.getAttachments())\n\t\t\tmodel.markAsChangedIfNecessary(true)\n\t\t\tm.redraw()\n\t\t}\n\n\t\t// call this async because the editor is not initialized before this mail editor dialog is shown\n\t\tthis.editor.initialized.promise.then(() => {\n\t\t\tthis.editor.setHTML(model.getBody())\n\t\t\t// Add mutation observer to remove attachments when corresponding DOM element is removed\n\t\t\tnew MutationObserver(onEditorChanged).observe(this.editor.getDOM(), {\n\t\t\t\tattributes: false,\n\t\t\t\tchildList: true,\n\t\t\t\tsubtree: true,\n\t\t\t})\n\t\t\t// since the editor is the source for the body text, the model won't know if the body has changed unless we tell it\n\t\t\tthis.editor.addChangeListener(() => model.setBody(replaceInlineImagesWithCids(this.editor.getDOM()).innerHTML))\n\t\t\tthis.editor.addEventListener(\"pasteImage\", ({ detail }: ImagePasteEvent) => {\n\t\t\t\tconst items = Array.from(detail.clipboardData.items)\n\t\t\t\tconst imageItems = items.filter((item) => /image/.test(item.type))\n\t\t\t\tif (!imageItems.length) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\tconst file = imageItems[0]?.getAsFile()\n\t\t\t\tif (file == null) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\tconst reader = new FileReader()\n\t\t\t\treader.onload = () => {\n\t\t\t\t\tif (reader.result == null || \"string\" === typeof reader.result) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tconst newInlineImages = [createDataFile(file.name, file.type, new Uint8Array(reader.result))]\n\t\t\t\t\tmodel.attachFiles(newInlineImages)\n\t\t\t\t\tthis.insertInlineImages(model, newInlineImages)\n\t\t\t\t}\n\t\t\t\treader.readAsArrayBuffer(file)\n\t\t\t})\n\n\t\t\tif (a.templateModel) {\n\t\t\t\ta.templateModel.init().then((templateModel) => {\n\t\t\t\t\t// add this event listener to handle quick selection of templates inside the editor\n\t\t\t\t\tregisterTemplateShortcutListener(this.editor, templateModel)\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\n\t\tthis.editor.initialized.promise.then(() => {\n\t\t\tconst dom = this.editor.getDOM()\n\t\t\tthis.inlineImageElements = replaceCidsWithInlineImages(dom, model.loadedInlineImages, (cid, event, dom) => {\n\t\t\t\tconst downloadClickHandler = createDropdown({\n\t\t\t\t\tlazyButtons: () => [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlabel: \"download_action\",\n\t\t\t\t\t\t\tclick: () => this.downloadInlineImage(model, cid),\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t})\n\t\t\t\tdownloadClickHandler(downcast(event), dom)\n\t\t\t})\n\t\t})\n\t\tmodel.onMailChanged.map(() => m.redraw())\n\t\t// Leftover text in recipient field is an error\n\t\tmodel.setOnBeforeSendFunction(() => {\n\t\t\tlet invalidText = \"\"\n\t\t\tfor (const leftoverText of typedValues(this.recipientFieldTexts)) {\n\t\t\t\tif (leftoverText().trim() !== \"\") {\n\t\t\t\t\tinvalidText += \"\\n\" + leftoverText().trim()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (invalidText !== \"\") {\n\t\t\t\tthrow new UserError(() => lang.get(\"invalidRecipients_msg\") + invalidText)\n\t\t\t}\n\t\t})\n\t\tconst dialog = a.dialog()\n\n\t\tif (model.getConversationType() === ConversationType.REPLY || model.toRecipients().length) {\n\t\t\tdialog.setFocusOnLoadFunction(() => {\n\t\t\t\tthis.editor.initialized.promise.then(() => this.editor.focus())\n\t\t\t})\n\t\t}\n\n\t\tconst shortcuts: Shortcut[] = [\n\t\t\t{\n\t\t\t\tkey: Keys.SPACE,\n\t\t\t\tctrl: true,\n\t\t\t\texec: () => this.openTemplates(),\n\t\t\t\thelp: \"openTemplatePopup_msg\",\n\t\t\t}, // these are handled by squire\n\t\t\t{\n\t\t\t\tkey: Keys.B,\n\t\t\t\tctrl: true,\n\t\t\t\texec: noOp,\n\t\t\t\thelp: \"formatTextBold_msg\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: Keys.I,\n\t\t\t\tctrl: true,\n\t\t\t\texec: noOp,\n\t\t\t\thelp: \"formatTextItalic_msg\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tkey: Keys.U,\n\t\t\t\tctrl: true,\n\t\t\t\texec: noOp,\n\t\t\t\thelp: \"formatTextUnderline_msg\",\n\t\t\t},\n\t\t]\n\t\tshortcuts.forEach(dialog.addShortcut.bind(dialog))\n\t\tthis.editor.initialized.promise.then(() => {\n\t\t\ta.knowledgeBaseInjection(this.editor).then((injection) => {\n\t\t\t\tthis.knowledgeBaseInjection = injection\n\t\t\t\tm.redraw()\n\t\t\t})\n\t\t})\n\t}\n\n\tprivate downloadInlineImage(model: SendMailModel, cid: string) {\n\t\tconst inlineAttachment = model.getAttachments().find((attachment) => attachment.cid === cid)\n\n\t\tif (inlineAttachment && isTutanotaFile(inlineAttachment)) {\n\t\t\tlocator.fileController.open(inlineAttachment).catch(ofClass(FileOpenError, () => Dialog.message(\"canNotOpenFileOnDevice_msg\")))\n\t\t}\n\t}\n\n\tview(vnode: Vnode<MailEditorAttrs>): Children {\n\t\tconst a = vnode.attrs\n\t\tthis.attrs = a\n\t\tconst { model } = a\n\t\tthis.sendMailModel = model\n\n\t\tconst showConfidentialButton = model.containsExternalRecipients()\n\t\tconst isConfidential = model.isConfidential() && showConfidentialButton\n\t\tconst confidentialButtonAttrs: ToggleButtonAttrs = {\n\t\t\ttitle: model.isConfidential() ? \"confidential_action\" : \"nonConfidential_action\",\n\t\t\tonToggled: (_, e) => {\n\t\t\t\te.stopPropagation()\n\t\t\t\tmodel.setConfidential(!model.isConfidential())\n\t\t\t},\n\t\t\ticon: model.isConfidential() ? Icons.Lock : Icons.Unlock,\n\t\t\ttoggled: model.isConfidential(),\n\t\t\tsize: ButtonSize.Compact,\n\t\t}\n\t\tconst attachFilesButtonAttrs: IconButtonAttrs = {\n\t\t\ttitle: \"attachFiles_action\",\n\t\t\tclick: (ev, dom) => chooseAndAttachFile(model, dom.getBoundingClientRect()).then(() => m.redraw()),\n\t\t\ticon: Icons.Attachment,\n\t\t\tsize: ButtonSize.Compact,\n\t\t}\n\t\tconst plaintextFormatting = locator.logins.getUserController().props.sendPlaintextOnly\n\t\tthis.editor.setCreatesLists(!plaintextFormatting)\n\n\t\tconst toolbarButton = () =>\n\t\t\t!plaintextFormatting\n\t\t\t\t? m(ToggleButton, {\n\t\t\t\t\t\ttitle: \"showRichTextToolbar_action\",\n\t\t\t\t\t\ticon: Icons.FontSize,\n\t\t\t\t\t\tsize: ButtonSize.Compact,\n\t\t\t\t\t\ttoggled: a.doShowToolbar(),\n\t\t\t\t\t\tonToggled: (_, e) => {\n\t\t\t\t\t\t\ta.doShowToolbar(!a.doShowToolbar())\n\t\t\t\t\t\t\t// Stop the subject bar from being focused\n\t\t\t\t\t\t\te.stopPropagation()\n\t\t\t\t\t\t\tthis.editor.focus()\n\t\t\t\t\t\t},\n\t\t\t\t  })\n\t\t\t\t: null\n\n\t\tconst subjectFieldAttrs: TextFieldAttrs = {\n\t\t\tlabel: \"subject_label\",\n\t\t\thelpLabel: () => getConfidentialStateMessage(model.isConfidential()),\n\t\t\tvalue: model.getSubject(),\n\t\t\toninput: (val) => model.setSubject(val),\n\t\t\tinjectionsRight: () =>\n\t\t\t\tm(\".flex.end.ml-between-s.items-center\", [\n\t\t\t\t\tshowConfidentialButton ? m(ToggleButton, confidentialButtonAttrs) : null,\n\t\t\t\t\tthis.knowledgeBaseInjection ? this.renderToggleKnowledgeBase(this.knowledgeBaseInjection) : null,\n\t\t\t\t\tm(IconButton, attachFilesButtonAttrs),\n\t\t\t\t\ttoolbarButton(),\n\t\t\t\t]),\n\t\t}\n\n\t\tconst attachmentBubbleAttrs = createAttachmentBubbleAttrs(model, this.inlineImageElements)\n\n\t\tlet editCustomNotificationMailAttrs: IconButtonAttrs | null = null\n\n\t\tif (locator.logins.getUserController().isGlobalAdmin()) {\n\t\t\teditCustomNotificationMailAttrs = attachDropdown({\n\t\t\t\tmainButtonAttrs: {\n\t\t\t\t\ttitle: \"more_label\",\n\t\t\t\t\ticon: Icons.More,\n\t\t\t\t\tsize: ButtonSize.Compact,\n\t\t\t\t},\n\t\t\t\tchildAttrs: () => [\n\t\t\t\t\t{\n\t\t\t\t\t\tlabel: \"add_action\",\n\t\t\t\t\t\tclick: () => {\n\t\t\t\t\t\t\timport(\"../../settings/EditNotificationEmailDialog\").then(({ showAddOrEditNotificationEmailDialog }) =>\n\t\t\t\t\t\t\t\tshowAddOrEditNotificationEmailDialog(locator.logins.getUserController()),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tlabel: \"edit_action\",\n\t\t\t\t\t\tclick: () => {\n\t\t\t\t\t\t\timport(\"../../settings/EditNotificationEmailDialog\").then(({ showAddOrEditNotificationEmailDialog }) =>\n\t\t\t\t\t\t\t\tshowAddOrEditNotificationEmailDialog(locator.logins.getUserController(), model.getSelectedNotificationLanguageCode()),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t})\n\t\t}\n\n\t\treturn m(\n\t\t\t\"#mail-editor.full-height.text.touch-callout.flex.flex-column\",\n\t\t\t{\n\t\t\t\tonclick: (e: MouseEvent) => {\n\t\t\t\t\tif (e.target === this.editor.getDOM()) {\n\t\t\t\t\t\tthis.editor.focus()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tondragover: (ev: DragEvent) => {\n\t\t\t\t\t// do not check the data transfer here because it is not always filled, e.g. in Safari\n\t\t\t\t\tev.stopPropagation()\n\t\t\t\t\tev.preventDefault()\n\t\t\t\t},\n\t\t\t\tondrop: (ev: DragEvent) => {\n\t\t\t\t\tif (ev.dataTransfer?.files && ev.dataTransfer.files.length > 0) {\n\t\t\t\t\t\treadLocalFiles(ev.dataTransfer.files)\n\t\t\t\t\t\t\t.then((dataFiles) => {\n\t\t\t\t\t\t\t\tmodel.attachFiles(dataFiles as any)\n\t\t\t\t\t\t\t\tm.redraw()\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.catch((e) => {\n\t\t\t\t\t\t\t\tconsole.log(e)\n\t\t\t\t\t\t\t\treturn Dialog.message(\"couldNotAttachFile_msg\")\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\tev.stopPropagation()\n\t\t\t\t\t\tev.preventDefault()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t\t[\n\t\t\t\tm(\".rel\", this.renderRecipientField(RecipientField.TO, this.recipientFieldTexts.to, a.search)),\n\t\t\t\tm(\n\t\t\t\t\t\".rel\",\n\t\t\t\t\tm(\n\t\t\t\t\t\tExpanderPanel,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\texpanded: this.areDetailsExpanded,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tm(\".details\", [\n\t\t\t\t\t\t\tthis.renderRecipientField(RecipientField.CC, this.recipientFieldTexts.cc, a.search),\n\t\t\t\t\t\t\tthis.renderRecipientField(RecipientField.BCC, this.recipientFieldTexts.bcc, a.search),\n\t\t\t\t\t\t]),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tm(\".wrapping-row\", [\n\t\t\t\t\tm(\n\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\t\t\"min-width\": \"250px\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tm(DropDownSelector, {\n\t\t\t\t\t\t\tlabel: \"sender_label\",\n\t\t\t\t\t\t\titems: getEnabledMailAddressesWithUser(model.mailboxDetails, model.user().userGroupInfo)\n\t\t\t\t\t\t\t\t.sort()\n\t\t\t\t\t\t\t\t.map((mailAddress) => ({\n\t\t\t\t\t\t\t\t\tname: mailAddress,\n\t\t\t\t\t\t\t\t\tvalue: mailAddress,\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\tselectedValue: a.model.getSender(),\n\t\t\t\t\t\t\tselectedValueDisplay: getMailAddressDisplayText(a.model.getSenderName(), a.model.getSender(), false),\n\t\t\t\t\t\t\tselectionChangedHandler: (selection: string) => model.setSender(selection),\n\t\t\t\t\t\t\tdropdownWidth: 250,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\tisConfidential\n\t\t\t\t\t\t? m(\n\t\t\t\t\t\t\t\t\".flex\",\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\t\t\t\t\"min-width\": \"250px\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\toncreate: (vnode) => {\n\t\t\t\t\t\t\t\t\t\tconst htmlDom = vnode.dom as HTMLElement\n\t\t\t\t\t\t\t\t\t\thtmlDom.style.opacity = \"0\"\n\t\t\t\t\t\t\t\t\t\treturn animations.add(htmlDom, opacity(0, 1, true))\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tonbeforeremove: (vnode) => {\n\t\t\t\t\t\t\t\t\t\tconst htmlDom = vnode.dom as HTMLElement\n\t\t\t\t\t\t\t\t\t\thtmlDom.style.opacity = \"1\"\n\t\t\t\t\t\t\t\t\t\treturn animations.add(htmlDom, opacity(1, 0, true))\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\tm(\n\t\t\t\t\t\t\t\t\t\t\".flex-grow\",\n\t\t\t\t\t\t\t\t\t\tm(DropDownSelector, {\n\t\t\t\t\t\t\t\t\t\t\tlabel: \"notificationMailLanguage_label\",\n\t\t\t\t\t\t\t\t\t\t\titems: model.getAvailableNotificationTemplateLanguages().map((language) => {\n\t\t\t\t\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t\t\t\t\tname: lang.get(language.textId),\n\t\t\t\t\t\t\t\t\t\t\t\t\tvalue: language.code,\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t\t\tselectedValue: model.getSelectedNotificationLanguageCode(),\n\t\t\t\t\t\t\t\t\t\t\tselectionChangedHandler: (v: string) => model.setSelectedNotificationLanguageCode(v),\n\t\t\t\t\t\t\t\t\t\t\tdropdownWidth: 250,\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\teditCustomNotificationMailAttrs\n\t\t\t\t\t\t\t\t\t\t? m(\".pt.flex-no-grow.flex-end.border-bottom.flex.items-center\", m(IconButton, editCustomNotificationMailAttrs))\n\t\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t  )\n\t\t\t\t\t\t: null,\n\t\t\t\t]),\n\t\t\t\tisConfidential ? this.renderPasswordFields() : null,\n\t\t\t\tm(\".row\", m(TextField, subjectFieldAttrs)),\n\t\t\t\tm(\n\t\t\t\t\t\".flex-start.flex-wrap.column-gap\",\n\t\t\t\t\tattachmentBubbleAttrs.map((a) => m(AttachmentBubble, a)),\n\t\t\t\t),\n\t\t\t\tmodel.getAttachments().length > 0 ? m(\"hr.hr\") : null,\n\t\t\t\ta.doShowToolbar() ? this.renderToolbar(model) : null,\n\t\t\t\tm(\n\t\t\t\t\t\".pt-s.text.scroll-x.break-word-links.flex.flex-column.flex-grow\",\n\t\t\t\t\t{\n\t\t\t\t\t\tonclick: () => this.editor.focus(),\n\t\t\t\t\t},\n\t\t\t\t\tm(this.editor),\n\t\t\t\t),\n\t\t\t\tm(\".pb\"),\n\t\t\t],\n\t\t)\n\t}\n\n\tprivate renderToggleKnowledgeBase(knowledgeBaseInjection: DialogInjectionRightAttrs<KnowledgebaseDialogContentAttrs>) {\n\t\treturn m(ToggleButton, {\n\t\t\ttitle: \"openKnowledgebase_action\",\n\t\t\ttoggled: knowledgeBaseInjection.visible(),\n\t\t\tonToggled: () => {\n\t\t\t\tif (knowledgeBaseInjection.visible()) {\n\t\t\t\t\tknowledgeBaseInjection.visible(false)\n\t\t\t\t} else {\n\t\t\t\t\tknowledgeBaseInjection.componentAttrs.model.sortEntriesByMatchingKeywords(this.editor.getValue())\n\t\t\t\t\tknowledgeBaseInjection.visible(true)\n\t\t\t\t\tknowledgeBaseInjection.componentAttrs.model.init()\n\t\t\t\t}\n\t\t\t},\n\t\t\ticon: Icons.Book,\n\t\t\tsize: ButtonSize.Compact,\n\t\t})\n\t}\n\n\tprivate renderToolbar(model: SendMailModel): Children {\n\t\t// Toolbar is not removed from DOM directly, only it's parent (array) is so we have to animate it manually.\n\t\t// m.fragment() gives us a vnode without actual DOM element so that we can run callback on removal\n\t\treturn m.fragment(\n\t\t\t{\n\t\t\t\tonbeforeremove: ({ dom }) => animateToolbar(dom.children[0] as HTMLElement, false),\n\t\t\t},\n\t\t\t[\n\t\t\t\tm(RichTextToolbar, {\n\t\t\t\t\teditor: this.editor,\n\t\t\t\t\timageButtonClickHandler: isApp()\n\t\t\t\t\t\t? null\n\t\t\t\t\t\t: (event: Event) => this.imageButtonClickHandler(model, (event.target as HTMLElement).getBoundingClientRect()),\n\t\t\t\t\tcustomButtonAttrs: this.templateModel\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttitle: \"openTemplatePopup_msg\",\n\t\t\t\t\t\t\t\t\tclick: () => {\n\t\t\t\t\t\t\t\t\t\tthis.openTemplates()\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\ticon: Icons.ListAlt,\n\t\t\t\t\t\t\t\t\tsize: ButtonSize.Compact,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t  ]\n\t\t\t\t\t\t: [],\n\t\t\t\t}),\n\t\t\t\tm(\"hr.hr\"),\n\t\t\t],\n\t\t)\n\t}\n\n\tprivate async imageButtonClickHandler(model: SendMailModel, rect: DOMRect): Promise<void> {\n\t\tconst files = await chooseAndAttachFile(model, rect, ALLOWED_IMAGE_FORMATS)\n\t\tif (!files || files.length === 0) return\n\t\treturn await this.insertInlineImages(model, files)\n\t}\n\n\tprivate async insertInlineImages(model: SendMailModel, files: ReadonlyArray<DataFile | FileReference>): Promise<void> {\n\t\tfor (const file of files) {\n\t\t\tconst img = createInlineImage(file as DataFile)\n\t\t\tmodel.loadedInlineImages.set(img.cid, img)\n\t\t\tthis.inlineImageElements.push(\n\t\t\t\tthis.editor.insertImage(img.objectUrl, {\n\t\t\t\t\tcid: img.cid,\n\t\t\t\t\tstyle: \"max-width: 100%\",\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t\tm.redraw()\n\t}\n\n\tprivate renderPasswordFields(): Children {\n\t\treturn m(\n\t\t\t\".external-recipients.overflow-hidden\",\n\t\t\t{\n\t\t\t\toncreate: (vnode) => this.animateHeight(vnode.dom as HTMLElement, true),\n\t\t\t\tonbeforeremove: (vnode) => this.animateHeight(vnode.dom as HTMLElement, false),\n\t\t\t},\n\t\t\tthis.sendMailModel\n\t\t\t\t.allRecipients()\n\t\t\t\t.filter((r) => r.type === RecipientType.EXTERNAL)\n\t\t\t\t.map((recipient) => {\n\t\t\t\t\tif (!this.recipientShowConfidential.has(recipient.address)) this.recipientShowConfidential.set(recipient.address, false)\n\n\t\t\t\t\treturn m(TextField, {\n\t\t\t\t\t\toncreate: (vnode) => this.animateHeight(vnode.dom as HTMLElement, true),\n\t\t\t\t\t\tonbeforeremove: (vnode) => this.animateHeight(vnode.dom as HTMLElement, false),\n\t\t\t\t\t\tlabel: () => lang.get(\"passwordFor_label\", { \"{1}\": recipient.address }),\n\t\t\t\t\t\thelpLabel: () =>\n\t\t\t\t\t\t\tm(\".mt-xs.flex.items-center\", [\n\t\t\t\t\t\t\t\tm(CompletenessIndicator, { percentageCompleted: this.sendMailModel.getPasswordStrength(recipient) }),\n\t\t\t\t\t\t\t\t// hack! We want to reserve enough space from the text field to be like \"real\" password field but we don't have any text and\n\t\t\t\t\t\t\t\t// CSS unit \"lh\" is not supported. We could query it programmatically but instead we insert one text node (this is nbsp character)\n\t\t\t\t\t\t\t\t// which will take line-height and size the line properly.\n\t\t\t\t\t\t\t\tm(\"\", String.fromCharCode(160)),\n\t\t\t\t\t\t\t]),\n\t\t\t\t\t\tvalue: this.sendMailModel.getPassword(recipient.address),\n\t\t\t\t\t\tautocompleteAs: Autocomplete.off,\n\t\t\t\t\t\ttype: this.isConfidentialPasswordRevealed(recipient.address) ? TextFieldType.Text : TextFieldType.Password,\n\t\t\t\t\t\toninput: (val) => this.sendMailModel.setPassword(recipient.address, val),\n\t\t\t\t\t\tinjectionsRight: () => this.renderRevealIcon(recipient.address),\n\t\t\t\t\t})\n\t\t\t\t}),\n\t\t)\n\t}\n\n\tprivate renderRecipientField(field: RecipientField, fieldText: Stream<string>, search: RecipientsSearchModel): Children {\n\t\tconst label = (\n\t\t\t{\n\t\t\t\tto: \"to_label\",\n\t\t\t\tcc: \"cc_label\",\n\t\t\t\tbcc: \"bcc_label\",\n\t\t\t} as const\n\t\t)[field]\n\n\t\treturn m(MailRecipientsTextField, {\n\t\t\tlabel,\n\t\t\ttext: fieldText(),\n\t\t\tonTextChanged: (text) => fieldText(text),\n\t\t\trecipients: this.sendMailModel.getRecipientList(field),\n\t\t\tonRecipientAdded: async (address, name) => {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.sendMailModel.addRecipient(field, { address, name })\n\t\t\t\t} catch (e) {\n\t\t\t\t\tif (isOfflineError(e)) {\n\t\t\t\t\t\t// we are offline but we want to show the error dialog only when we click on send.\n\t\t\t\t\t} else if (e instanceof TooManyRequestsError) {\n\t\t\t\t\t\tawait Dialog.message(\"tooManyAttempts_msg\")\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow e\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tonRecipientRemoved: (address) => this.sendMailModel.removeRecipientByAddress(address, field),\n\t\t\tgetRecipientClickedDropdownAttrs: (address) => {\n\t\t\t\tconst recipient = this.sendMailModel.getRecipient(field, address)!\n\t\t\t\treturn this.getRecipientClickedContextButtons(recipient, field)\n\t\t\t},\n\t\t\tdisabled: !this.sendMailModel.logins.isInternalUserLoggedIn(),\n\t\t\tinjectionsRight:\n\t\t\t\tfield === RecipientField.TO && this.sendMailModel.logins.isInternalUserLoggedIn()\n\t\t\t\t\t? m(\n\t\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t\tm(ToggleButton, {\n\t\t\t\t\t\t\t\ttitle: \"show_action\",\n\t\t\t\t\t\t\t\ticon: BootIcons.Expand,\n\t\t\t\t\t\t\t\tsize: ButtonSize.Compact,\n\t\t\t\t\t\t\t\ttoggled: this.areDetailsExpanded,\n\t\t\t\t\t\t\t\tonToggled: (_, e) => {\n\t\t\t\t\t\t\t\t\te.stopPropagation()\n\t\t\t\t\t\t\t\t\tthis.areDetailsExpanded = !this.areDetailsExpanded\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t  )\n\t\t\t\t\t: null,\n\t\t\tsearch,\n\t\t})\n\t}\n\n\tprivate renderRevealIcon(address: string): Children {\n\t\treturn m(ToggleButton, {\n\t\t\ttitle: this.isConfidentialPasswordRevealed(address) ? \"concealPassword_action\" : \"revealPassword_action\",\n\t\t\ttoggled: this.isConfidentialPasswordRevealed(address),\n\t\t\tonToggled: (_, e) => {\n\t\t\t\tthis.toggleRevealConfidentialPassword(address)\n\t\t\t\te.stopPropagation()\n\t\t\t},\n\t\t\ticon: this.isConfidentialPasswordRevealed(address) ? Icons.NoEye : Icons.Eye,\n\t\t\tsize: ButtonSize.Compact,\n\t\t})\n\t}\n\n\tprivate async getRecipientClickedContextButtons(recipient: ResolvableRecipient, field: RecipientField): Promise<DropdownChildAttrs[]> {\n\t\tconst { logins, entity, contactModel } = this.sendMailModel\n\n\t\tconst canEditBubbleRecipient = locator.logins.getUserController().isInternalUser() && !locator.logins.isEnabled(FeatureType.DisableContacts)\n\n\t\tconst previousMail = this.sendMailModel.getPreviousMail()\n\n\t\tconst canRemoveBubble =\n\t\t\tlocator.logins.getUserController().isInternalUser() &&\n\t\t\t(!previousMail || !previousMail.restrictions || previousMail.restrictions.participantGroupInfos.length === 0)\n\n\t\tconst createdContactReceiver = (contactElementId: Id) => {\n\t\t\tconst mailAddress = recipient.address\n\n\t\t\tcontactModel.contactListId().then((contactListId) => {\n\t\t\t\tif (!contactListId) return\n\t\t\t\tconst id: IdTuple = [contactListId, contactElementId]\n\t\t\t\tentity.load(ContactTypeRef, id).then((contact) => {\n\t\t\t\t\tif (contact.mailAddresses.find((ma) => cleanMatch(ma.address, mailAddress))) {\n\t\t\t\t\t\trecipient.setName(getContactDisplayName(contact))\n\t\t\t\t\t\trecipient.setContact(contact)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.sendMailModel.removeRecipient(recipient, field, false)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\t\t}\n\n\t\tconst contextButtons: Array<DropdownChildAttrs> = []\n\n\t\tif (canEditBubbleRecipient) {\n\t\t\tif (recipient.contact && recipient.contact._id) {\n\t\t\t\tcontextButtons.push({\n\t\t\t\t\tlabel: () => lang.get(\"editContact_label\"),\n\t\t\t\t\tclick: () => {\n\t\t\t\t\t\timport(\"../../contacts/ContactEditor\").then(({ ContactEditor }) => new ContactEditor(entity, recipient.contact).show())\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tcontextButtons.push({\n\t\t\t\t\tlabel: () => lang.get(\"createContact_action\"),\n\t\t\t\t\tclick: () => {\n\t\t\t\t\t\t// contact list\n\t\t\t\t\t\tcontactModel.contactListId().then((contactListId) => {\n\t\t\t\t\t\t\tconst newContact = createNewContact(locator.logins.getUserController().user, recipient.address, recipient.name)\n\t\t\t\t\t\t\timport(\"../../contacts/ContactEditor\").then(({ ContactEditor }) => {\n\t\t\t\t\t\t\t\tnew ContactEditor(entity, newContact, contactListId ?? undefined, createdContactReceiver).show()\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t})\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tif (canRemoveBubble) {\n\t\t\tcontextButtons.push({\n\t\t\t\tlabel: \"remove_action\",\n\t\t\t\tclick: () => this.sendMailModel.removeRecipient(recipient, field, false),\n\t\t\t})\n\t\t}\n\n\t\treturn contextButtons\n\t}\n\n\tprivate openTemplates() {\n\t\tif (this.templateModel) {\n\t\t\tthis.templateModel.init().then((templateModel) => {\n\t\t\t\tshowTemplatePopupInEditor(templateModel, this.editor, null, this.editor.getSelectedText())\n\t\t\t})\n\t\t}\n\t}\n\n\tprivate animateHeight(domElement: HTMLElement, fadein: boolean): AnimationPromise {\n\t\tlet childHeight = domElement.offsetHeight\n\t\treturn animations.add(domElement, fadein ? height(0, childHeight) : height(childHeight, 0)).then(() => {\n\t\t\tdomElement.style.height = \"\"\n\t\t})\n\t}\n\n\tprivate isConfidentialPasswordRevealed(address: string): boolean {\n\t\treturn this.recipientShowConfidential.get(address) ?? false\n\t}\n\n\tprivate toggleRevealConfidentialPassword(address: string): void {\n\t\tthis.recipientShowConfidential.set(address, !this.recipientShowConfidential.get(address))\n\t}\n}\n\n/**\n * Creates a new Dialog with a MailEditor inside.\n * @param model\n * @param blockExternalContent\n * @returns {Dialog}\n * @private\n */\nasync function createMailEditorDialog(model: SendMailModel, blockExternalContent: boolean = false): Promise<Dialog> {\n\tlet dialog: Dialog\n\tlet mailEditorAttrs: MailEditorAttrs\n\n\tconst save = (showProgress: boolean = true) => {\n\t\tconst savePromise = model.saveDraft(true, MailMethod.NONE)\n\n\t\tif (showProgress) {\n\t\t\treturn showProgressDialog(\"save_msg\", savePromise)\n\t\t} else {\n\t\t\treturn savePromise\n\t\t}\n\t}\n\n\tconst send = async () => {\n\t\ttry {\n\t\t\tconst success = await model.send(MailMethod.NONE, Dialog.confirm, showProgressDialog)\n\t\t\tif (success) {\n\t\t\t\tdispose()\n\t\t\t\tdialog.close()\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tif (e instanceof UserError) {\n\t\t\t\tshowUserError(e)\n\t\t\t} else {\n\t\t\t\tthrow e\n\t\t\t}\n\t\t}\n\t}\n\n\t// keep track of things we need to dispose of when the editor is completely closed\n\tconst disposables: { dispose: () => unknown }[] = []\n\n\tconst dispose = () => {\n\t\tmodel.dispose()\n\t\tif (templatePopupModel) templatePopupModel.dispose()\n\t\tfor (const disposable of disposables) {\n\t\t\tdisposable.dispose()\n\t\t}\n\t}\n\n\tconst minimize = () => {\n\t\tlet saveStatus = stream<SaveStatus>({ status: SaveStatusEnum.Saving })\n\t\tif (model.hasMailChanged()) {\n\t\t\tsave(false)\n\t\t\t\t.then(() => saveStatus({ status: SaveStatusEnum.Saved }))\n\t\t\t\t.catch((e) => {\n\t\t\t\t\tconst reason = isOfflineError(e) ? SaveErrorReason.ConnectionLost : SaveErrorReason.Unknown\n\n\t\t\t\t\tsaveStatus({ status: SaveStatusEnum.NotSaved, reason })\n\n\t\t\t\t\t// If we don't show the error in the minimized error dialog,\n\t\t\t\t\t// Then we need to communicate it in a dialog or as an unhandled error\n\t\t\t\t\tif (reason === SaveErrorReason.Unknown) {\n\t\t\t\t\t\tif (e instanceof UserError) {\n\t\t\t\t\t\t\tshowUserError(e)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthrow e\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.finally(() => m.redraw())\n\t\t} else if (!model.draft) {\n\t\t\t// If the mail is unchanged and there was no preexisting draft, close instead of saving and return to not show minimized mail editor\n\t\t\tdispose()\n\t\t\tdialog.close()\n\t\t\treturn\n\t\t}\n\t\t// If the mail is unchanged and there /is/ a preexisting draft, there was no change and the mail is already saved\n\t\telse saveStatus = stream<SaveStatus>({ status: SaveStatusEnum.Saved })\n\t\tshowMinimizedMailEditor(dialog, model, locator.minimizedMailModel, locator.eventController, dispose, saveStatus)\n\t}\n\n\tlet windowCloseUnsubscribe = () => {}\n\n\tconst headerBarAttrs: DialogHeaderBarAttrs = {\n\t\tleft: [\n\t\t\t{\n\t\t\t\tlabel: \"close_alt\",\n\t\t\t\tclick: () => minimize(),\n\t\t\t\ttype: ButtonType.Secondary,\n\t\t\t},\n\t\t],\n\t\tright: [\n\t\t\t{\n\t\t\t\tlabel: \"send_action\",\n\t\t\t\tclick: () => {\n\t\t\t\t\tsend()\n\t\t\t\t},\n\t\t\t\ttype: ButtonType.Primary,\n\t\t\t},\n\t\t],\n\t\tmiddle: () => conversationTypeString(model.getConversationType()),\n\t\tcreate: () => {\n\t\t\tif (isBrowser()) {\n\t\t\t\t// Have a simple listener on browser, so their browser will make the user ask if they are sure they want to close when closing the tab/window\n\t\t\t\twindowCloseUnsubscribe = windowFacade.addWindowCloseListener(() => {})\n\t\t\t} else if (isDesktop()) {\n\t\t\t\t// Simulate clicking the Close button when on the desktop so they can see they can save a draft rather than completely closing it\n\t\t\t\twindowCloseUnsubscribe = windowFacade.addWindowCloseListener(() => {\n\t\t\t\t\tminimize()\n\t\t\t\t})\n\t\t\t}\n\t\t},\n\t\tremove: () => {\n\t\t\twindowCloseUnsubscribe()\n\t\t},\n\t}\n\tconst templatePopupModel =\n\t\tlocator.logins.isInternalUserLoggedIn() && client.isDesktopDevice()\n\t\t\t? new TemplatePopupModel(locator.eventController, locator.logins, locator.entityClient)\n\t\t\t: null\n\n\tconst createKnowledgebaseButtonAttrs = async (editor: Editor) => {\n\t\tif (locator.logins.isInternalUserLoggedIn()) {\n\t\t\tconst customer = await locator.logins.getUserController().loadCustomer()\n\t\t\t// only create knowledgebase button for internal users with valid template group and enabled KnowledgebaseFeature\n\t\t\tif (\n\t\t\t\tstyles.isDesktopLayout() &&\n\t\t\t\ttemplatePopupModel &&\n\t\t\t\tlocator.logins.getUserController().getTemplateMemberships().length > 0 &&\n\t\t\t\tisCustomizationEnabledForCustomer(customer, FeatureType.KnowledgeBase)\n\t\t\t) {\n\t\t\t\tconst knowledgebaseModel = new KnowledgeBaseModel(locator.eventController, locator.entityClient, locator.logins.getUserController())\n\t\t\t\tawait knowledgebaseModel.init()\n\n\t\t\t\t// make sure we dispose knowledbaseModel once the editor is closed\n\t\t\t\tdisposables.push(knowledgebaseModel)\n\n\t\t\t\tconst knowledgebaseInjection = createKnowledgeBaseDialogInjection(knowledgebaseModel, templatePopupModel, editor)\n\t\t\t\tdialog.setInjectionRight(knowledgebaseInjection)\n\t\t\t\treturn knowledgebaseInjection\n\t\t\t} else {\n\t\t\t\treturn null\n\t\t\t}\n\t\t} else {\n\t\t\treturn null\n\t\t}\n\t}\n\n\tmailEditorAttrs = createMailEditorAttrs(\n\t\tmodel,\n\t\tblockExternalContent,\n\t\tmodel.toRecipients().length !== 0,\n\t\t() => dialog,\n\t\ttemplatePopupModel,\n\t\tcreateKnowledgebaseButtonAttrs,\n\t\tawait locator.recipientsSearchModel(),\n\t)\n\tconst shortcuts: Shortcut[] = [\n\t\t{\n\t\t\tkey: Keys.ESC,\n\t\t\texec: () => {\n\t\t\t\tminimize()\n\t\t\t},\n\t\t\thelp: \"close_alt\",\n\t\t},\n\t\t{\n\t\t\tkey: Keys.S,\n\t\t\tctrl: true,\n\t\t\texec: () => {\n\t\t\t\tsave().catch(ofClass(UserError, showUserError))\n\t\t\t},\n\t\t\thelp: \"save_action\",\n\t\t},\n\t\t{\n\t\t\tkey: Keys.S,\n\t\t\tctrl: true,\n\t\t\tshift: true,\n\t\t\texec: () => {\n\t\t\t\tsend()\n\t\t\t},\n\t\t\thelp: \"send_action\",\n\t\t},\n\t\t{\n\t\t\tkey: Keys.RETURN,\n\t\t\tctrl: true,\n\t\t\texec: () => {\n\t\t\t\tsend()\n\t\t\t},\n\t\t\thelp: \"send_action\",\n\t\t},\n\t]\n\tdialog = Dialog.editDialog(headerBarAttrs, MailEditor, mailEditorAttrs)\n\tdialog.setCloseHandler(() => minimize())\n\n\tfor (let shortcut of shortcuts) {\n\t\tdialog.addShortcut(shortcut)\n\t}\n\n\treturn dialog\n}\n\n/**\n * open a MailEditor\n * @param mailboxDetails details to use when sending an email\n * @returns {*}\n * @private\n * @throws PermissionError\n */\nexport async function newMailEditor(mailboxDetails: MailboxDetail): Promise<Dialog> {\n\t// We check approval status so as to get a dialog informing the user that they cannot send mails\n\t// but we still want to open the mail editor because they should still be able to contact sales@tutao.de\n\tawait checkApprovalStatus(locator.logins, false)\n\tconst { appendEmailSignature } = await import(\"../signature/Signature\")\n\tconst signature = appendEmailSignature(\"\", locator.logins.getUserController().props)\n\tconst detailsProperties = await getMailboxDetailsAndProperties(mailboxDetails)\n\treturn newMailEditorFromTemplate(detailsProperties.mailboxDetails, {}, \"\", signature)\n}\n\nexport async function newMailEditorAsResponse(\n\targs: InitAsResponseArgs,\n\tblockExternalContent: boolean,\n\tinlineImages: InlineImages,\n\tmailboxDetails?: MailboxDetail,\n): Promise<Dialog> {\n\tconst detailsProperties = await getMailboxDetailsAndProperties(mailboxDetails)\n\tconst model = await locator.sendMailModel(detailsProperties.mailboxDetails, detailsProperties.mailboxProperties)\n\tawait model.initAsResponse(args, inlineImages)\n\treturn createMailEditorDialog(model, blockExternalContent)\n}\n\nexport async function newMailEditorFromDraft(\n\tattachments: TutanotaFile[],\n\tmailWrapper: MailWrapper,\n\tblockExternalContent: boolean,\n\tinlineImages: InlineImages,\n\tmailboxDetails?: MailboxDetail,\n): Promise<Dialog> {\n\tconst detailsProperties = await getMailboxDetailsAndProperties(mailboxDetails)\n\tconst model = await locator.sendMailModel(detailsProperties.mailboxDetails, detailsProperties.mailboxProperties)\n\tawait model.initWithDraft(attachments, mailWrapper, inlineImages)\n\treturn createMailEditorDialog(model, blockExternalContent)\n}\n\nexport async function newMailtoUrlMailEditor(mailtoUrl: string, confidential: boolean, mailboxDetails?: MailboxDetail): Promise<Dialog> {\n\tconst detailsProperties = await getMailboxDetailsAndProperties(mailboxDetails)\n\tconst mailTo = parseMailtoUrl(mailtoUrl)\n\tlet dataFiles: Attachment[] = []\n\n\tif (mailTo.attach) {\n\t\tconst attach = mailTo.attach\n\n\t\tif (isDesktop()) {\n\t\t\tconst files = await Promise.all(attach.map((uri) => locator.fileApp.readDataFile(uri)))\n\t\t\tdataFiles = files.filter(isNotNull)\n\t\t}\n\t\t// make sure the user is aware that (and which) files have been attached\n\t\tconst keepAttachments =\n\t\t\tdataFiles.length === 0 ||\n\t\t\t(await Dialog.confirm(\"attachmentWarning_msg\", \"attachFiles_action\", () =>\n\t\t\t\tdataFiles.map((df, i) =>\n\t\t\t\t\tm(\n\t\t\t\t\t\t\".text-break.selectable.mt-xs\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttitle: attach[i],\n\t\t\t\t\t\t},\n\t\t\t\t\t\tdf.name,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t))\n\n\t\tif (keepAttachments) {\n\t\t\tconst sizeCheckResult = checkAttachmentSize(dataFiles)\n\t\t\tdataFiles = sizeCheckResult.attachableFiles\n\n\t\t\tif (sizeCheckResult.tooBigFiles.length > 0) {\n\t\t\t\tawait Dialog.message(\n\t\t\t\t\t() => lang.get(\"tooBigAttachment_msg\"),\n\t\t\t\t\t() => sizeCheckResult.tooBigFiles.map((file) => m(\".text-break.selectable\", file)),\n\t\t\t\t)\n\t\t\t}\n\t\t} else {\n\t\t\tthrow new CancelledError(\"user cancelled opening mail editor with attachments\")\n\t\t}\n\t}\n\n\treturn newMailEditorFromTemplate(\n\t\tdetailsProperties.mailboxDetails,\n\t\tmailTo.recipients,\n\t\tmailTo.subject || \"\",\n\t\tappendEmailSignature(mailTo.body || \"\", locator.logins.getUserController().props),\n\t\tdataFiles,\n\t\tconfidential,\n\t\tundefined,\n\t\ttrue, // emails created with mailto should always save as draft\n\t)\n}\n\nexport async function newMailEditorFromTemplate(\n\tmailboxDetails: MailboxDetail,\n\trecipients: Recipients,\n\tsubject: string,\n\tbodyText: string,\n\tattachments?: ReadonlyArray<Attachment>,\n\tconfidential?: boolean,\n\tsenderMailAddress?: string,\n\tinitialChangedState?: boolean,\n): Promise<Dialog> {\n\tconst mailboxProperties = await locator.mailModel.getMailboxProperties(mailboxDetails.mailboxGroupRoot)\n\treturn locator\n\t\t.sendMailModel(mailboxDetails, mailboxProperties)\n\t\t.then((model) => model.initWithTemplate(recipients, subject, bodyText, attachments, confidential, senderMailAddress, initialChangedState))\n\t\t.then((model) => createMailEditorDialog(model))\n}\n\nexport function getSupportMailSignature(): Promise<string> {\n\treturn import(\"../../calendar/date/CalendarUtils\").then(({ getTimeZone }) => {\n\t\treturn (\n\t\t\tLINE_BREAK +\n\t\t\tLINE_BREAK +\n\t\t\t\"--\" +\n\t\t\t`<br>Client: ${client.getIdentifier()}` +\n\t\t\t`<br>Tutanota version: ${env.versionNumber}` +\n\t\t\t`<br>Time zone: ${getTimeZone()}` +\n\t\t\t`<br>User agent:<br> ${navigator.userAgent}`\n\t\t)\n\t})\n}\n\n/**\n * Create and show a new mail editor with a support query, addressed to premium support,\n * or show an option to upgrade\n * @param subject\n * @param mailboxDetails\n * @returns true if sending support email is allowed, false if upgrade to premium is required (may have been ordered)\n */\nexport async function writeSupportMail(subject: string = \"\", mailboxDetails?: MailboxDetail): Promise<boolean> {\n\tif (locator.logins.getUserController().isPremiumAccount()) {\n\t\tconst detailsProperties = await getMailboxDetailsAndProperties(mailboxDetails)\n\t\tconst recipients = {\n\t\t\tto: [\n\t\t\t\t{\n\t\t\t\t\tname: null,\n\t\t\t\t\taddress: \"premium@tutao.de\",\n\t\t\t\t},\n\t\t\t],\n\t\t}\n\t\tconst signature = await getSupportMailSignature()\n\t\tconst dialog = await newMailEditorFromTemplate(detailsProperties.mailboxDetails, recipients, subject, signature)\n\t\tdialog.show()\n\t\treturn true\n\t} else {\n\t\treturn import(\"../../subscription/PriceUtils\")\n\t\t\t.then(({ formatPrice }) => {\n\t\t\t\tconst message = lang.get(\"premiumOffer_msg\", {\n\t\t\t\t\t\"{1}\": formatPrice(1, true),\n\t\t\t\t})\n\t\t\t\tconst title = lang.get(\"upgradeReminderTitle_msg\")\n\t\t\t\treturn Dialog.reminder(title, message)\n\t\t\t})\n\t\t\t.then((confirm) => {\n\t\t\t\tif (confirm) {\n\t\t\t\t\timport(\"../../subscription/UpgradeSubscriptionWizard\").then((utils) => utils.showUpgradeWizard(locator.logins))\n\t\t\t\t}\n\t\t\t})\n\t\t\t.then(() => false)\n\t}\n}\n\n/**\n * Create and show a new mail editor with an invite message\n * @param referralLink\n * @returns {*}\n */\nexport async function writeInviteMail(referralLink: string) {\n\tconst detailsProperties = await getMailboxDetailsAndProperties(null)\n\tconst username = locator.logins.getUserController().userGroupInfo.name\n\tconst body = lang.get(\"invitationMailBody_msg\", {\n\t\t\"{registrationLink}\": referralLink,\n\t\t\"{username}\": username,\n\t})\n\tconst dialog = await newMailEditorFromTemplate(detailsProperties.mailboxDetails, {}, lang.get(\"invitationMailSubject_msg\"), body, [], false)\n\tdialog.show()\n}\n\n/**\n * Create and show a new mail editor with an invite message\n * @param link: the link to the giftcard\n * @param svg: an SVGElement that is the DOM node of the rendered gift card\n * @param mailboxDetails\n * @returns {*}\n */\nexport async function writeGiftCardMail(link: string, svg: SVGElement, mailboxDetails?: MailboxDetail) {\n\tconst detailsProperties = await getMailboxDetailsAndProperties(mailboxDetails)\n\tconst bodyText = lang\n\t\t.get(\"defaultShareGiftCardBody_msg\", {\n\t\t\t\"{link}\": '<a href=\"' + link + '\">' + link + \"</a>\",\n\t\t\t\"{username}\": locator.logins.getUserController().userGroupInfo.name,\n\t\t})\n\t\t.split(\"\\n\")\n\t\t.join(\"<br />\")\n\tconst subject = lang.get(\"defaultShareGiftCardSubject_msg\")\n\tlocator\n\t\t.sendMailModel(detailsProperties.mailboxDetails, detailsProperties.mailboxProperties)\n\t\t.then((model) => model.initWithTemplate({}, subject, appendEmailSignature(bodyText, locator.logins.getUserController().props), [], false))\n\t\t.then((model) => createMailEditorDialog(model, false))\n\t\t.then((dialog) => dialog.show())\n}\n\nasync function getMailboxDetailsAndProperties(\n\tmailboxDetails: MailboxDetail | null | undefined,\n): Promise<{ mailboxDetails: MailboxDetail; mailboxProperties: MailboxProperties }> {\n\tmailboxDetails = mailboxDetails ?? (await locator.mailModel.getUserMailboxDetails())\n\tconst mailboxProperties = await locator.mailModel.getMailboxProperties(mailboxDetails.mailboxGroupRoot)\n\treturn { mailboxDetails, mailboxProperties }\n}\n","import { ApprovalStatus, ConversationType, MailFolderType, MailMethod, MAX_ATTACHMENT_SIZE, OperationType, ReplyType } from \"../../api/common/TutanotaConstants\"\nimport {\n\tAccessBlockedError,\n\tLockedError,\n\tNotAuthorizedError,\n\tNotFoundError,\n\tPayloadTooLargeError,\n\tPreconditionFailedError,\n\tTooManyRequestsError,\n} from \"../../api/common/error/RestError\"\nimport { UserError } from \"../../api/main/UserError\"\nimport { getPasswordStrengthForUser, isSecurePassword, PASSWORD_MIN_SECURE_VALUE } from \"../../misc/passwords/PasswordUtils\"\nimport {\n\tcleanMatch,\n\tdeduplicate,\n\tdowncast,\n\tfindAndRemove,\n\tgetFromMap,\n\tLazyLoaded,\n\tneverNull,\n\tnoOp,\n\tofClass,\n\tpromiseMap,\n\tremove,\n\ttypedValues,\n} from \"@tutao/tutanota-utils\"\nimport { checkAttachmentSize, getDefaultSender, getTemplateLanguages, RecipientField } from \"../model/MailUtils\"\nimport type { EncryptedMailAddress, File as TutanotaFile, Mail, MailboxProperties } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport { ContactTypeRef, ConversationEntryTypeRef, File, FileTypeRef, MailboxPropertiesTypeRef, MailTypeRef } from \"../../api/entities/tutanota/TypeRefs.js\"\nimport { FileNotFoundError } from \"../../api/common/error/FileNotFoundError\"\nimport type { LoginController } from \"../../api/main/LoginController\"\nimport type { MailboxDetail, MailModel } from \"../model/MailModel\"\nimport { RecipientNotResolvedError } from \"../../api/common/error/RecipientNotResolvedError\"\nimport stream from \"mithril/stream\"\nimport Stream from \"mithril/stream\"\nimport type { EntityUpdateData } from \"../../api/main/EventController\"\nimport { EventController, isUpdateForTypeRef } from \"../../api/main/EventController\"\nimport { isMailAddress } from \"../../misc/FormatValidator\"\nimport type { ContactModel } from \"../../contacts/model/ContactModel\"\nimport type { Language, TranslationKey, TranslationText } from \"../../misc/LanguageViewModel\"\nimport { getAvailableLanguageCode, getSubstitutedLanguageCode, lang, languages } from \"../../misc/LanguageViewModel\"\nimport type { UserController } from \"../../api/main/UserController\"\nimport { RecipientsNotFoundError } from \"../../api/common/error/RecipientsNotFoundError\"\nimport { checkApprovalStatus } from \"../../misc/LoginUtils\"\nimport { EntityClient } from \"../../api/common/EntityClient\"\nimport { getContactDisplayName } from \"../../contacts/model/ContactUtils\"\nimport { getListId, isSameId, stringToCustomId } from \"../../api/common/utils/EntityUtils\"\nimport { CustomerPropertiesTypeRef } from \"../../api/entities/sys/TypeRefs.js\"\nimport type { InlineImages } from \"../view/MailViewer\"\nimport { cloneInlineImages, revokeInlineImages } from \"../view/MailGuiUtils\"\nimport { MailBodyTooLargeError } from \"../../api/common/error/MailBodyTooLargeError\"\nimport type { MailFacade } from \"../../api/worker/facades/lazy/MailFacade.js\"\nimport { assertMainOrNode } from \"../../api/common/Env\"\nimport { DataFile } from \"../../api/common/DataFile\"\nimport { FileReference } from \"../../api/common/utils/FileUtils\"\nimport { PartialRecipient, Recipient, RecipientList, Recipients, RecipientType } from \"../../api/common/recipients/Recipient\"\nimport { RecipientsModel, ResolvableRecipient, ResolveMode } from \"../../api/main/RecipientsModel\"\nimport { createApprovalMail } from \"../../api/entities/monitor/TypeRefs\"\nimport { DateProvider } from \"../../api/common/DateProvider.js\"\nimport { getSenderName } from \"../../misc/MailboxPropertiesUtils.js\"\nimport { isLegacyMail, MailWrapper } from \"../../api/common/MailWrapper.js\"\nimport { cleanMailAddress, findRecipientWithAddress } from \"../../api/common/utils/CommonCalendarUtils.js\"\n\nassertMainOrNode()\n\nexport const TOO_MANY_VISIBLE_RECIPIENTS = 10\n\nexport type Attachment = TutanotaFile | DataFile | FileReference\n\nexport type InitAsResponseArgs = {\n\tpreviousMail: Mail\n\tconversationType: ConversationType\n\tsenderMailAddress: string\n\trecipients: Recipients\n\tattachments: TutanotaFile[]\n\tsubject: string\n\tbodyText: string\n\treplyTos: RecipientList\n}\n\ntype InitArgs = {\n\tconversationType: ConversationType\n\tsubject: string\n\tbodyText: string\n\trecipients: Recipients\n\tconfidential: boolean | null\n\tdraft?: Mail | null\n\tsenderMailAddress?: string\n\tattachments?: ReadonlyArray<Attachment>\n\treplyTos?: RecipientList\n\tpreviousMail?: Mail | null\n\tpreviousMessageId?: string | null\n\tinitialChangedState: boolean | null\n}\n\n/**\n * Model which allows sending mails interactively - including resolving of recipients and handling of drafts.\n */\nexport class SendMailModel {\n\tonMailChanged: Stream<null> = stream(null)\n\tonRecipientDeleted: Stream<{ field: RecipientField; recipient: Recipient } | null> = stream(null)\n\tonBeforeSend: () => void = noOp\n\tloadedInlineImages: InlineImages = new Map()\n\n\t// Isn't private because used by MinimizedEditorOverlay, refactor?\n\tdraft: Mail | null = null\n\tprivate conversationType: ConversationType = ConversationType.NEW\n\tprivate subject: string = \"\"\n\tprivate body: string = \"\"\n\tprivate recipients: Map<RecipientField, Array<ResolvableRecipient>> = new Map()\n\tprivate senderAddress: string\n\tprivate confidential: boolean\n\n\t// contains either Files from Tutanota or DataFiles of locally loaded files. these map 1:1 to the _attachmentButtons\n\tprivate attachments: Array<Attachment> = []\n\n\tprivate replyTos: Array<ResolvableRecipient> = []\n\n\t// only needs to be the correct value if this is a new email. if we are editing a draft, conversationType is not used\n\tprivate previousMessageId: Id | null = null\n\n\tprivate previousMail: Mail | null = null\n\tprivate selectedNotificationLanguage: string\n\tprivate availableNotificationTemplateLanguages: Array<Language> = []\n\tprivate mailChangedAt: number = 0\n\tprivate mailSavedAt: number = 1\n\tprivate passwords: Map<string, string> = new Map()\n\n\t// The promise for the draft currently being saved\n\tprivate currentSavePromise: Promise<void> | null = null\n\n\t// If saveDraft is called while the previous call is still running, then flag to call again afterwards\n\tprivate doSaveAgain: boolean = false\n\tprivate recipientsResolved = new LazyLoaded<void>(async () => {})\n\n\t/**\n\t * creates a new empty draft message. calling an init method will fill in all the blank data\n\t */\n\tconstructor(\n\t\tpublic readonly mailFacade: MailFacade,\n\t\tpublic readonly entity: EntityClient,\n\t\tpublic readonly logins: LoginController,\n\t\tpublic readonly mailModel: MailModel,\n\t\tpublic readonly contactModel: ContactModel,\n\t\tprivate readonly eventController: EventController,\n\t\tpublic readonly mailboxDetails: MailboxDetail,\n\t\tprivate readonly recipientsModel: RecipientsModel,\n\t\tprivate readonly dateProvider: DateProvider,\n\t\tprivate mailboxProperties: MailboxProperties,\n\t) {\n\t\tconst userProps = logins.getUserController().props\n\t\tthis.senderAddress = this.getDefaultSender()\n\t\tthis.confidential = !userProps.defaultUnconfidential\n\n\t\tthis.selectedNotificationLanguage = getAvailableLanguageCode(userProps.notificationMailLanguage || lang.code)\n\t\tthis.updateAvailableNotificationTemplateLanguages()\n\n\t\tthis.eventController.addEntityListener(this.entityEventReceived)\n\t}\n\n\tprivate readonly entityEventReceived = async (updates: ReadonlyArray<EntityUpdateData>) => {\n\t\tfor (const update of updates) {\n\t\t\tawait this.handleEntityEvent(update)\n\t\t}\n\t}\n\n\t/**\n\t * Sort list of all languages alphabetically\n\t * then we see if the user has custom notification templates\n\t * in which case we replace the list with just the templates that the user has specified\n\t */\n\tprivate async updateAvailableNotificationTemplateLanguages(): Promise<void> {\n\t\tthis.availableNotificationTemplateLanguages = languages.slice().sort((a, b) => lang.get(a.textId).localeCompare(lang.get(b.textId)))\n\t\tconst filteredLanguages = await getTemplateLanguages(this.availableNotificationTemplateLanguages, this.entity, this.logins)\n\t\tif (filteredLanguages.length > 0) {\n\t\t\tconst languageCodes = filteredLanguages.map((l) => l.code)\n\t\t\tthis.selectedNotificationLanguage =\n\t\t\t\tgetSubstitutedLanguageCode(this.logins.getUserController().props.notificationMailLanguage || lang.code, languageCodes) || languageCodes[0]\n\t\t\tthis.availableNotificationTemplateLanguages = filteredLanguages\n\t\t}\n\t}\n\n\tuser(): UserController {\n\t\treturn this.logins.getUserController()\n\t}\n\n\tgetPreviousMail(): Mail | null {\n\t\treturn this.previousMail\n\t}\n\n\tgetConversationType(): ConversationType {\n\t\treturn this.conversationType\n\t}\n\n\tsetPassword(mailAddress: string, password: string) {\n\t\tthis.onMailChanged(null)\n\t\tthis.passwords.set(mailAddress, password)\n\t}\n\n\tgetPassword(mailAddress: string): string {\n\t\treturn this.passwords.get(mailAddress) || \"\"\n\t}\n\n\tgetSubject(): string {\n\t\treturn this.subject\n\t}\n\n\tsetSubject(subject: string) {\n\t\tthis.markAsChangedIfNecessary(subject !== this.subject)\n\t\tthis.subject = subject\n\t}\n\n\tgetBody(): string {\n\t\treturn this.body\n\t}\n\n\tsetBody(body: string) {\n\t\tthis.markAsChangedIfNecessary(this.body !== body)\n\t\tthis.body = body\n\t}\n\n\t/**\n\t * set the mail address used to send the mail.\n\t * @param senderAddress the mail address that will show up lowercased in the sender field of the sent mail.\n\t */\n\tsetSender(senderAddress: string) {\n\t\t// we can (and should) do this because we lowercase all addresses on signup and when creating aliases.\n\t\tsenderAddress = cleanMailAddress(senderAddress)\n\t\tthis.markAsChangedIfNecessary(this.senderAddress !== senderAddress)\n\t\tthis.senderAddress = senderAddress\n\t}\n\n\tgetSender(): string {\n\t\treturn this.senderAddress\n\t}\n\n\t/**\n\t * Returns the strength indicator for the recipients password\n\t * @returns value between 0 and 100\n\t */\n\tgetPasswordStrength(recipient: PartialRecipient): number {\n\t\treturn getPasswordStrengthForUser(this.getPassword(recipient.address), recipient, this.mailboxDetails, this.logins)\n\t}\n\n\thasMailChanged(): boolean {\n\t\treturn this.mailChangedAt > this.mailSavedAt\n\t}\n\n\t/**\n\t * update the changed state of the mail.\n\t * will only be reset when saving.\n\t */\n\tmarkAsChangedIfNecessary(hasChanged: boolean) {\n\t\tif (!hasChanged) return\n\t\tthis.mailChangedAt = this.dateProvider.now()\n\t\t// if this method is called wherever state gets changed, onMailChanged should function properly\n\t\tthis.onMailChanged(null)\n\t}\n\n\t/**\n\t *\n\t * @param recipients\n\t * @param subject\n\t * @param bodyText\n\t * @param attachments\n\t * @param confidential\n\t * @param senderMailAddress\n\t * @param initialChangedState\n\t * @returns {Promise<SendMailModel>}\n\t */\n\tinitWithTemplate(\n\t\trecipients: Recipients,\n\t\tsubject: string,\n\t\tbodyText: string,\n\t\tattachments?: ReadonlyArray<Attachment>,\n\t\tconfidential?: boolean,\n\t\tsenderMailAddress?: string,\n\t\tinitialChangedState?: boolean,\n\t): Promise<SendMailModel> {\n\t\treturn this.init({\n\t\t\tconversationType: ConversationType.NEW,\n\t\t\tsubject,\n\t\t\tbodyText,\n\t\t\trecipients,\n\t\t\tattachments,\n\t\t\tconfidential: confidential ?? null,\n\t\t\tsenderMailAddress,\n\t\t\tinitialChangedState: initialChangedState ?? null,\n\t\t})\n\t}\n\n\tasync initAsResponse(args: InitAsResponseArgs, inlineImages: InlineImages): Promise<SendMailModel> {\n\t\tconst { previousMail, conversationType, senderMailAddress, recipients, attachments, subject, bodyText, replyTos } = args\n\t\tlet previousMessageId: string | null = null\n\t\tawait this.entity\n\t\t\t.load(ConversationEntryTypeRef, previousMail.conversationEntry)\n\t\t\t.then((ce) => {\n\t\t\t\tpreviousMessageId = ce.messageId\n\t\t\t})\n\t\t\t.catch(\n\t\t\t\tofClass(NotFoundError, (e) => {\n\t\t\t\t\tconsole.log(\"could not load conversation entry\", e)\n\t\t\t\t}),\n\t\t\t)\n\t\t// if we reuse the same image references, changing the displayed mail in mail view will cause the minimized draft to lose\n\t\t// that reference, because it will be revoked\n\t\tthis.loadedInlineImages = cloneInlineImages(inlineImages)\n\t\treturn this.init({\n\t\t\tconversationType,\n\t\t\tsubject,\n\t\t\tbodyText,\n\t\t\trecipients,\n\t\t\tsenderMailAddress,\n\t\t\tconfidential: previousMail.confidential,\n\t\t\tattachments,\n\t\t\treplyTos,\n\t\t\tpreviousMail,\n\t\t\tpreviousMessageId,\n\t\t\tinitialChangedState: false,\n\t\t})\n\t}\n\n\tasync initWithDraft(attachments: File[], mailWrapper: MailWrapper, inlineImages: InlineImages): Promise<SendMailModel> {\n\t\tlet previousMessageId: string | null = null\n\t\tlet previousMail: Mail | null = null\n\n\t\tconst draft = mailWrapper.getMail()\n\t\tconst conversationEntry = await this.entity.load(ConversationEntryTypeRef, draft.conversationEntry)\n\t\tconst conversationType = downcast<ConversationType>(conversationEntry.conversationType)\n\n\t\tif (conversationEntry.previous) {\n\t\t\ttry {\n\t\t\t\tconst previousEntry = await this.entity.load(ConversationEntryTypeRef, conversationEntry.previous)\n\t\t\t\tpreviousMessageId = previousEntry.messageId\n\t\t\t\tif (previousEntry.mail) {\n\t\t\t\t\tpreviousMail = await this.entity.load(MailTypeRef, previousEntry.mail)\n\t\t\t\t}\n\t\t\t} catch (e) {\n\t\t\t\tif (e instanceof NotFoundError) {\n\t\t\t\t\t// ignore\n\t\t\t\t} else {\n\t\t\t\t\tthrow e\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// if we reuse the same image references, changing the displayed mail in mail view will cause the minimized draft to lose\n\t\t// that reference, because it will be revoked\n\t\tthis.loadedInlineImages = cloneInlineImages(inlineImages)\n\t\tconst { confidential, sender, subject } = draft\n\t\tlet recipients: Recipients\n\t\tlet replyTos: EncryptedMailAddress[]\n\t\tif (!isLegacyMail(draft) && mailWrapper) {\n\t\t\tconst { toRecipients, ccRecipients, bccRecipients } = mailWrapper.getDetails().recipients\n\t\t\trecipients = {\n\t\t\t\tto: toRecipients,\n\t\t\t\tcc: ccRecipients,\n\t\t\t\tbcc: bccRecipients,\n\t\t\t}\n\t\t\treplyTos = mailWrapper.getReplyTos()\n\t\t} else {\n\t\t\tconst { toRecipients, ccRecipients, bccRecipients } = draft\n\t\t\trecipients = {\n\t\t\t\tto: toRecipients,\n\t\t\t\tcc: ccRecipients,\n\t\t\t\tbcc: bccRecipients,\n\t\t\t}\n\t\t\treplyTos = draft.replyTos\n\t\t}\n\t\tconst bodyText = mailWrapper.getMailBodyText()\n\t\treturn this.init({\n\t\t\tconversationType: conversationType,\n\t\t\tsubject,\n\t\t\tbodyText,\n\t\t\trecipients,\n\t\t\tdraft,\n\t\t\tsenderMailAddress: sender.address,\n\t\t\tconfidential,\n\t\t\tattachments,\n\t\t\treplyTos,\n\t\t\tpreviousMail,\n\t\t\tpreviousMessageId,\n\t\t\tinitialChangedState: false,\n\t\t})\n\t}\n\n\tprivate async init({\n\t\tconversationType,\n\t\tsubject,\n\t\tbodyText,\n\t\tdraft,\n\t\trecipients,\n\t\tsenderMailAddress,\n\t\tconfidential,\n\t\tattachments,\n\t\treplyTos,\n\t\tpreviousMail,\n\t\tpreviousMessageId,\n\t\tinitialChangedState,\n\t}: InitArgs): Promise<SendMailModel> {\n\t\tthis.conversationType = conversationType\n\t\tthis.subject = subject\n\t\tthis.body = bodyText\n\t\tthis.draft = draft || null\n\n\t\tlet to: RecipientList\n\t\tlet cc: RecipientList\n\t\tlet bcc: RecipientList\n\n\t\tif (recipients instanceof Array) {\n\t\t\tto = recipients\n\t\t\tcc = []\n\t\t\tbcc = []\n\t\t} else {\n\t\t\tto = recipients.to ?? []\n\t\t\tcc = recipients.cc ?? []\n\t\t\tbcc = recipients.bcc ?? []\n\t\t}\n\n\t\t// We deliberately use .map() and not promiseMap() here because we want to insert all\n\t\t// the recipients right away, we count on it in some checks in send() and we also want all of them\n\t\t// to show up immediately.\n\t\t// If we want to limit recipient resolution at some point we need to build a queue in some other place.\n\t\t// Making it LazyLoaded() will allow us to retry it in case it fails.\n\t\t// It is very important that we insert the recipients here synchronously. Even though it is inside the async function it will call insertRecipient()\n\t\t// right away when we call getAsync() below\n\t\tthis.recipientsResolved = new LazyLoaded(async () => {\n\t\t\tawait Promise.all([\n\t\t\t\trecipientsFilter(to).map((r) => this.insertRecipient(RecipientField.TO, r)),\n\t\t\t\trecipientsFilter(cc).map((r) => this.insertRecipient(RecipientField.CC, r)),\n\t\t\t\trecipientsFilter(bcc).map((r) => this.insertRecipient(RecipientField.BCC, r)),\n\t\t\t])\n\t\t})\n\t\t// noinspection ES6MissingAwait\n\t\tthis.recipientsResolved.getAsync()\n\n\t\t// .toLowerCase because all our aliases and accounts are lowercased on creation\n\t\tthis.senderAddress = senderMailAddress?.toLowerCase() || this.getDefaultSender()\n\t\tthis.confidential = confidential ?? !this.user().props.defaultUnconfidential\n\t\tthis.attachments = []\n\n\t\tif (attachments) {\n\t\t\tthis.attachFiles(attachments)\n\t\t}\n\n\t\tthis.replyTos = recipientsFilter(replyTos ?? []).map((recipient) => this.recipientsModel.resolve(recipient, ResolveMode.Eager))\n\t\tthis.previousMail = previousMail || null\n\t\tthis.previousMessageId = previousMessageId || null\n\t\tthis.mailChangedAt = this.dateProvider.now()\n\n\t\t// Determine if we should have this mail already be detected as modified so it saves.\n\t\tif (initialChangedState) {\n\t\t\tthis.onMailChanged(null)\n\t\t\tthis.mailSavedAt = this.mailChangedAt - 1\n\t\t} else {\n\t\t\tthis.mailSavedAt = this.mailChangedAt + 1\n\t\t}\n\n\t\treturn this\n\t}\n\n\tprivate getDefaultSender(): string {\n\t\treturn getDefaultSender(this.logins, this.mailboxDetails)\n\t}\n\n\tgetRecipientList(type: RecipientField): Array<ResolvableRecipient> {\n\t\treturn getFromMap(this.recipients, type, () => [])\n\t}\n\n\ttoRecipients(): Array<ResolvableRecipient> {\n\t\treturn this.getRecipientList(RecipientField.TO)\n\t}\n\n\ttoRecipientsResolved(): Promise<Array<Recipient>> {\n\t\treturn Promise.all(this.toRecipients().map((recipient) => recipient.resolved()))\n\t}\n\n\tccRecipients(): Array<ResolvableRecipient> {\n\t\treturn this.getRecipientList(RecipientField.CC)\n\t}\n\n\tccRecipientsResolved(): Promise<Array<Recipient>> {\n\t\treturn Promise.all(this.ccRecipients().map((recipient) => recipient.resolved()))\n\t}\n\n\tbccRecipients(): Array<ResolvableRecipient> {\n\t\treturn this.getRecipientList(RecipientField.BCC)\n\t}\n\n\tbccRecipientsResolved(): Promise<Array<Recipient>> {\n\t\treturn Promise.all(this.bccRecipients().map((recipient) => recipient.resolved()))\n\t}\n\n\treplyTosResolved(): Promise<Array<Recipient>> {\n\t\treturn Promise.all(this.replyTos.map((r) => r.resolved()))\n\t}\n\n\t/**\n\t * add a recipient to the recipient list without updating the saved state of the draft.\n\t * if the recipient is already inserted, it will wait for it to resolve before returning.\n\t *\n\t * @returns whether the list was actually changed.\n\t */\n\tprivate async insertRecipient(\n\t\tfieldType: RecipientField,\n\t\t{ address, name, type, contact }: PartialRecipient,\n\t\tresolveMode: ResolveMode = ResolveMode.Eager,\n\t): Promise<boolean> {\n\t\tlet recipient = findRecipientWithAddress(this.getRecipientList(fieldType), address)\n\t\t// Only add a recipient if it doesn't exist\n\t\tif (!recipient) {\n\t\t\trecipient = this.recipientsModel.resolve(\n\t\t\t\t{\n\t\t\t\t\taddress,\n\t\t\t\t\tname,\n\t\t\t\t\ttype,\n\t\t\t\t\tcontact,\n\t\t\t\t},\n\t\t\t\tresolveMode,\n\t\t\t)\n\n\t\t\tthis.getRecipientList(fieldType).push(recipient)\n\n\t\t\trecipient.resolved().then(({ address, contact }) => {\n\t\t\t\tif (!this.passwords.has(address) && contact != null) {\n\t\t\t\t\tthis.setPassword(address, contact.presharedPassword ?? \"\")\n\t\t\t\t} else {\n\t\t\t\t\t// always notify listeners after we finished resolving the recipient, even if email itself didn't change\n\t\t\t\t\tthis.onMailChanged(null)\n\t\t\t\t}\n\t\t\t})\n\t\t\tawait recipient.resolved()\n\t\t\treturn true\n\t\t}\n\t\tawait recipient.resolved()\n\t\treturn false\n\t}\n\n\t/**\n\t * Add a new recipient, this method resolves when the recipient resolves.\n\t * will notify of a changed draft state after the recipient was inserted\n\t */\n\tasync addRecipient(fieldType: RecipientField, partialRecipient: PartialRecipient, resolveMode: ResolveMode = ResolveMode.Eager): Promise<void> {\n\t\tconst wasAdded = await this.insertRecipient(fieldType, partialRecipient, resolveMode)\n\t\tthis.markAsChangedIfNecessary(wasAdded)\n\t}\n\n\tgetRecipient(type: RecipientField, address: string): ResolvableRecipient | null {\n\t\treturn findRecipientWithAddress(this.getRecipientList(type), address)\n\t}\n\n\tremoveRecipientByAddress(address: string, type: RecipientField, notify: boolean = true) {\n\t\tconst recipient = findRecipientWithAddress(this.getRecipientList(type), address)\n\t\tif (recipient) {\n\t\t\tthis.removeRecipient(recipient, type, notify)\n\t\t}\n\t}\n\n\t/**\n\t * remove recipient from the recipient list\n\t * @return true if the recipient was removed\n\t */\n\tremoveRecipient(recipient: Recipient, type: RecipientField, notify: boolean = true): boolean {\n\t\tconst recipients = this.recipients.get(type) ?? []\n\t\tconst cleanRecipientAddress = cleanMailAddress(recipient.address)\n\t\tconst didRemove = findAndRemove(recipients, (r) => cleanMailAddress(r.address) === cleanRecipientAddress)\n\t\tthis.markAsChangedIfNecessary(didRemove)\n\n\t\tif (didRemove && notify) {\n\t\t\tthis.onRecipientDeleted({\n\t\t\t\tfield: type,\n\t\t\t\trecipient,\n\t\t\t})\n\t\t}\n\n\t\treturn didRemove\n\t}\n\n\tdispose() {\n\t\tthis.eventController.removeEntityListener(this.entityEventReceived)\n\n\t\trevokeInlineImages(this.loadedInlineImages)\n\t}\n\n\t/**\n\t * @throws UserError in the case that any files were too big to attach. Small enough files will still have been attached\n\t */\n\tgetAttachments(): Array<Attachment> {\n\t\treturn this.attachments\n\t}\n\n\t/** @throws UserError in case files are too big to add */\n\tattachFiles(files: ReadonlyArray<Attachment>): void {\n\t\tlet sizeLeft = MAX_ATTACHMENT_SIZE - this.attachments.reduce((total, file) => total + Number(file.size), 0)\n\n\t\tconst sizeCheckResult = checkAttachmentSize(files, sizeLeft)\n\n\t\tthis.attachments.push(...sizeCheckResult.attachableFiles)\n\t\tthis.markAsChangedIfNecessary(sizeCheckResult.attachableFiles.length > 0)\n\n\t\tif (sizeCheckResult.tooBigFiles.length > 0) {\n\t\t\tthrow new UserError(() => lang.get(\"tooBigAttachment_msg\") + \"\\n\" + sizeCheckResult.tooBigFiles.join(\"\\n\"))\n\t\t}\n\t}\n\n\tremoveAttachment(file: Attachment): void {\n\t\tthis.markAsChangedIfNecessary(remove(this.attachments, file))\n\t}\n\n\tgetSenderName(): string {\n\t\treturn getSenderName(this.mailboxProperties, this.senderAddress) ?? \"\"\n\t}\n\n\tgetDraft(): Readonly<Mail> | null {\n\t\treturn this.draft\n\t}\n\n\tprivate async updateDraft(body: string, attachments: ReadonlyArray<Attachment> | null, draft: Mail): Promise<Mail> {\n\t\treturn this.mailFacade\n\t\t\t.updateDraft({\n\t\t\t\tsubject: this.getSubject(),\n\t\t\t\tbody: body,\n\t\t\t\tsenderMailAddress: this.senderAddress,\n\t\t\t\tsenderName: this.getSenderName(),\n\t\t\t\ttoRecipients: await this.toRecipientsResolved(),\n\t\t\t\tccRecipients: await this.ccRecipientsResolved(),\n\t\t\t\tbccRecipients: await this.bccRecipientsResolved(),\n\t\t\t\tattachments: attachments,\n\t\t\t\tconfidential: this.isConfidential(),\n\t\t\t\tdraft: draft,\n\t\t\t})\n\t\t\t.catch(\n\t\t\t\tofClass(LockedError, (e) => {\n\t\t\t\t\tconsole.log(\"updateDraft: operation is still active\", e)\n\t\t\t\t\tthrow new UserError(\"operationStillActive_msg\")\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.catch(\n\t\t\t\tofClass(NotFoundError, (e) => {\n\t\t\t\t\tconsole.log(\"draft has been deleted, creating new one\")\n\t\t\t\t\treturn this.createDraft(body, attachments, downcast(draft.method))\n\t\t\t\t}),\n\t\t\t)\n\t}\n\n\tprivate async createDraft(body: string, attachments: ReadonlyArray<Attachment> | null, mailMethod: MailMethod): Promise<Mail> {\n\t\treturn this.mailFacade.createDraft({\n\t\t\tsubject: this.getSubject(),\n\t\t\tbodyText: body,\n\t\t\tsenderMailAddress: this.senderAddress,\n\t\t\tsenderName: this.getSenderName(),\n\t\t\ttoRecipients: await this.toRecipientsResolved(),\n\t\t\tccRecipients: await this.ccRecipientsResolved(),\n\t\t\tbccRecipients: await this.bccRecipientsResolved(),\n\t\t\tconversationType: this.conversationType,\n\t\t\tpreviousMessageId: this.previousMessageId,\n\t\t\tattachments: attachments,\n\t\t\tconfidential: this.isConfidential(),\n\t\t\treplyTos: await this.replyTosResolved(),\n\t\t\tmethod: mailMethod,\n\t\t})\n\t}\n\n\tisConfidential(): boolean {\n\t\treturn this.confidential || !this.containsExternalRecipients()\n\t}\n\n\tisConfidentialExternal(): boolean {\n\t\treturn this.confidential && this.containsExternalRecipients()\n\t}\n\n\tsetConfidential(confidential: boolean): void {\n\t\tthis.markAsChangedIfNecessary(this.confidential !== confidential)\n\t\tthis.confidential = confidential\n\t}\n\n\tcontainsExternalRecipients(): boolean {\n\t\treturn this.allRecipients().some((r) => r.type === RecipientType.EXTERNAL)\n\t}\n\n\tgetExternalRecipients(): Array<Recipient> {\n\t\treturn this.allRecipients().filter((r) => r.type === RecipientType.EXTERNAL)\n\t}\n\n\t/**\n\t * @reject {RecipientsNotFoundError}\n\t * @reject {TooManyRequestsError}\n\t * @reject {AccessBlockedError}\n\t * @reject {FileNotFoundError}\n\t * @reject {PreconditionFailedError}\n\t * @reject {LockedError}\n\t * @reject {UserError}\n\t * @param mailMethod\n\t * @param getConfirmation: A callback to get user confirmation\n\t * @param waitHandler: A callback to allow UI blocking while the mail is being sent. it seems like wrapping the send call in showProgressDialog causes the confirmation dialogs not to be shown. We should fix this, but this works for now\n\t * @param tooManyRequestsError\n\t * @return true if the send was completed, false if it was aborted (by getConfirmation returning false\n\t */\n\tasync send(\n\t\tmailMethod: MailMethod,\n\t\tgetConfirmation: (arg0: TranslationText) => Promise<boolean> = (_) => Promise.resolve(true),\n\t\twaitHandler: (arg0: TranslationText, arg1: Promise<any>) => Promise<any> = (_, p) => p,\n\t\ttooManyRequestsError: TranslationKey = \"tooManyMails_msg\",\n\t): Promise<boolean> {\n\t\t// To avoid parallel invocations do not do anything async here that would later execute the sending.\n\t\t// It is fine to wait for getConfirmation() because it is modal and will prevent the user from triggering multiple sends.\n\t\t// If you need to do something async here put it into `asyncSend`\n\t\t//\n\t\t// You can't rely on resolved recipients here, only after waitForResolvedRecipients() inside asyncSend()!\n\t\tthis.onBeforeSend()\n\n\t\tif (this.allRecipients().length === 1 && this.allRecipients()[0].address.toLowerCase().trim() === \"approval@tutao.de\") {\n\t\t\tawait this.sendApprovalMail(this.getBody())\n\t\t\treturn true\n\t\t}\n\n\t\tif (this.toRecipients().length === 0 && this.ccRecipients().length === 0 && this.bccRecipients().length === 0) {\n\t\t\tthrow new UserError(\"noRecipients_msg\")\n\t\t}\n\n\t\tconst numVisibleRecipients = this.toRecipients().length + this.ccRecipients().length\n\n\t\t// Many recipients is a warning\n\t\tif (numVisibleRecipients >= TOO_MANY_VISIBLE_RECIPIENTS && !(await getConfirmation(\"manyRecipients_msg\"))) {\n\t\t\treturn false\n\t\t}\n\n\t\t// Empty subject is a warning\n\t\tif (this.getSubject().length === 0 && !(await getConfirmation(\"noSubject_msg\"))) {\n\t\t\treturn false\n\t\t}\n\n\t\tconst asyncSend = async () => {\n\t\t\t// The next check depends on contacts being available\n\t\t\t// So we need to wait for our recipients here\n\t\t\tconst recipients = await this.waitForResolvedRecipients()\n\n\t\t\t// No password in external confidential mail is an error\n\t\t\tif (this.isConfidentialExternal() && this.getExternalRecipients().some((r) => !this.getPassword(r.address))) {\n\t\t\t\tthrow new UserError(\"noPreSharedPassword_msg\")\n\t\t\t}\n\n\t\t\t// Weak password is a warning\n\t\t\tif (this.isConfidentialExternal() && this.hasInsecurePasswords() && !(await getConfirmation(\"presharedPasswordNotStrongEnough_msg\"))) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tawait this.saveDraft(true, mailMethod)\n\t\t\tawait this.updateContacts(recipients)\n\t\t\tawait this.mailFacade.sendDraft(neverNull(this.draft), recipients, this.selectedNotificationLanguage)\n\t\t\tawait this.updatePreviousMail()\n\t\t\tawait this.updateExternalLanguage()\n\t\t\treturn true\n\t\t}\n\n\t\treturn waitHandler(this.isConfidential() ? \"sending_msg\" : \"sendingUnencrypted_msg\", asyncSend())\n\t\t\t.catch(\n\t\t\t\tofClass(LockedError, () => {\n\t\t\t\t\tthrow new UserError(\"operationStillActive_msg\")\n\t\t\t\t}),\n\t\t\t) // catch all of the badness\n\t\t\t.catch(\n\t\t\t\tofClass(RecipientNotResolvedError, () => {\n\t\t\t\t\tthrow new UserError(\"tooManyAttempts_msg\")\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.catch(\n\t\t\t\tofClass(RecipientsNotFoundError, (e) => {\n\t\t\t\t\tif (mailMethod === MailMethod.ICAL_CANCEL) {\n\t\t\t\t\t\t// in case of calendar event termination we will remove invalid recipients and then delete the event without sending updates\n\t\t\t\t\t\tthrow e\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlet invalidRecipients = e.message\n\t\t\t\t\t\tthrow new UserError(\n\t\t\t\t\t\t\t() => lang.get(\"tutanotaAddressDoesNotExist_msg\") + \" \" + lang.get(\"invalidRecipients_msg\") + \"\\n\" + invalidRecipients,\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.catch(\n\t\t\t\tofClass(TooManyRequestsError, () => {\n\t\t\t\t\tthrow new UserError(tooManyRequestsError)\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.catch(\n\t\t\t\tofClass(AccessBlockedError, (e) => {\n\t\t\t\t\t// special case: the approval status is set to SpamSender, but the update has not been received yet, so use SpamSender as default\n\t\t\t\t\treturn checkApprovalStatus(this.logins, true, ApprovalStatus.SPAM_SENDER).then(() => {\n\t\t\t\t\t\tconsole.log(\"could not send mail (blocked access)\", e)\n\t\t\t\t\t\treturn false\n\t\t\t\t\t})\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.catch(\n\t\t\t\tofClass(FileNotFoundError, () => {\n\t\t\t\t\tthrow new UserError(\"couldNotAttachFile_msg\")\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.catch(\n\t\t\t\tofClass(PreconditionFailedError, () => {\n\t\t\t\t\tthrow new UserError(\"operationStillActive_msg\")\n\t\t\t\t}),\n\t\t\t)\n\t}\n\n\t/**\n\t * Whether any of the external recipients have an insecure password.\n\t * We don't consider empty passwords, because an empty password will disallow and encrypted email from sending, whereas an insecure password\n\t * can still be used\n\t * @returns {boolean}\n\t */\n\thasInsecurePasswords(): boolean {\n\t\tconst minimalPasswordStrength = this.allRecipients()\n\t\t\t.filter((r) => this.getPassword(r.address) !== \"\")\n\t\t\t.reduce((min, recipient) => Math.min(min, this.getPasswordStrength(recipient)), PASSWORD_MIN_SECURE_VALUE)\n\t\treturn !isSecurePassword(minimalPasswordStrength)\n\t}\n\n\tsaveDraft(saveAttachments: boolean, mailMethod: MailMethod): Promise<void> {\n\t\tif (this.currentSavePromise == null) {\n\t\t\tthis.currentSavePromise = Promise.resolve().then(async () => {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.doSaveDraft(saveAttachments, mailMethod)\n\t\t\t\t} finally {\n\t\t\t\t\t// If there is an error, we still need to reset currentSavePromise\n\t\t\t\t\tthis.currentSavePromise = null\n\t\t\t\t}\n\t\t\t\tif (this.hasMailChanged() && this.doSaveAgain) {\n\t\t\t\t\tthis.doSaveAgain = false\n\t\t\t\t\tawait this.saveDraft(saveAttachments, mailMethod)\n\t\t\t\t}\n\t\t\t})\n\t\t} else {\n\t\t\tthis.doSaveAgain = true\n\t\t}\n\n\t\treturn this.currentSavePromise\n\t}\n\n\t/**\n\t * Saves the draft.\n\t * @param saveAttachments True if also the attachments shall be saved, false otherwise.\n\t * @param mailMethod\n\t * @returns {Promise} When finished.\n\t * @throws FileNotFoundError when one of the attachments could not be opened\n\t * @throws PreconditionFailedError when the draft is locked\n\t */\n\tprivate async doSaveDraft(saveAttachments: boolean, mailMethod: MailMethod): Promise<void> {\n\t\ttry {\n\t\t\tconst attachments = saveAttachments ? this.attachments : null\n\n\t\t\t// We also want to create new drafts for drafts edited from trash or spam folder\n\t\t\tthis.draft =\n\t\t\t\tthis.draft == null || (await this.isMailInTrashOrSpam(this.draft))\n\t\t\t\t\t? await this.createDraft(this.getBody(), attachments, mailMethod)\n\t\t\t\t\t: await this.updateDraft(this.getBody(), attachments, this.draft)\n\n\t\t\tconst attachmentIds = await this.mailFacade.getAttachmentIds(this.draft)\n\t\t\tconst newAttachments = await promiseMap(attachmentIds, (fileId) => this.entity.load<TutanotaFile>(FileTypeRef, fileId), {\n\t\t\t\tconcurrency: 5,\n\t\t\t})\n\n\t\t\tthis.attachments = [] // attachFiles will push to existing files but we want to overwrite them\n\t\t\tthis.attachFiles(newAttachments)\n\n\t\t\t// Allow any changes that might occur while the mail is being saved to be accounted for\n\t\t\t// if saved is called before this has completed\n\t\t\tthis.mailSavedAt = this.dateProvider.now()\n\t\t} catch (e) {\n\t\t\tif (e instanceof PayloadTooLargeError) {\n\t\t\t\tthrow new UserError(\"requestTooLarge_msg\")\n\t\t\t} else if (e instanceof MailBodyTooLargeError) {\n\t\t\t\tthrow new UserError(\"mailBodyTooLarge_msg\")\n\t\t\t} else if (e instanceof FileNotFoundError) {\n\t\t\t\tthrow new UserError(\"couldNotAttachFile_msg\")\n\t\t\t} else if (e instanceof PreconditionFailedError) {\n\t\t\t\tthrow new UserError(\"operationStillActive_msg\")\n\t\t\t} else {\n\t\t\t\tthrow e\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async isMailInTrashOrSpam(draft: Mail): Promise<boolean> {\n\t\tconst folders = await this.mailModel.getMailboxFolders(draft)\n\t\tconst mailFolder = folders?.getFolderByMailListId(getListId(draft))\n\t\treturn !!mailFolder && (mailFolder.folderType === MailFolderType.TRASH || mailFolder.folderType === MailFolderType.SPAM)\n\t}\n\n\tprivate sendApprovalMail(body: string): Promise<unknown> {\n\t\tconst listId = \"---------c--\"\n\t\tconst m = createApprovalMail({\n\t\t\t_id: [listId, stringToCustomId(this.senderAddress)],\n\t\t\t_ownerGroup: this.user().user.userGroup.group,\n\t\t\ttext: `Subject: ${this.getSubject()}<br>${body}`,\n\t\t})\n\t\treturn this.entity.setup(listId, m).catch(ofClass(NotAuthorizedError, (e) => console.log(\"not authorized for approval message\")))\n\t}\n\n\tgetAvailableNotificationTemplateLanguages(): Array<Language> {\n\t\treturn this.availableNotificationTemplateLanguages\n\t}\n\n\tgetSelectedNotificationLanguageCode(): string {\n\t\treturn this.selectedNotificationLanguage\n\t}\n\n\tsetSelectedNotificationLanguageCode(code: string) {\n\t\tthis.markAsChangedIfNecessary(this.selectedNotificationLanguage !== code)\n\t\tthis.selectedNotificationLanguage = code\n\t\tthis.markAsChangedIfNecessary(true)\n\t}\n\n\tprivate updateExternalLanguage() {\n\t\tlet props = this.user().props\n\n\t\tif (props.notificationMailLanguage !== this.selectedNotificationLanguage) {\n\t\t\tprops.notificationMailLanguage = this.selectedNotificationLanguage\n\n\t\t\tthis.entity.update(props)\n\t\t}\n\t}\n\n\tprivate updatePreviousMail(): Promise<void> {\n\t\tif (this.previousMail) {\n\t\t\tif (this.previousMail.replyType === ReplyType.NONE && this.conversationType === ConversationType.REPLY) {\n\t\t\t\tthis.previousMail.replyType = ReplyType.REPLY\n\t\t\t} else if (this.previousMail.replyType === ReplyType.NONE && this.conversationType === ConversationType.FORWARD) {\n\t\t\t\tthis.previousMail.replyType = ReplyType.FORWARD\n\t\t\t} else if (this.previousMail.replyType === ReplyType.FORWARD && this.conversationType === ConversationType.REPLY) {\n\t\t\t\tthis.previousMail.replyType = ReplyType.REPLY_FORWARD\n\t\t\t} else if (this.previousMail.replyType === ReplyType.REPLY && this.conversationType === ConversationType.FORWARD) {\n\t\t\t\tthis.previousMail.replyType = ReplyType.REPLY_FORWARD\n\t\t\t} else {\n\t\t\t\treturn Promise.resolve()\n\t\t\t}\n\n\t\t\treturn this.entity.update(this.previousMail).catch(ofClass(NotFoundError, noOp))\n\t\t} else {\n\t\t\treturn Promise.resolve()\n\t\t}\n\t}\n\n\t/**\n\t * If contacts have had their passwords changed, we update them before sending\n\t */\n\tprivate async updateContacts(resolvedRecipients: Recipient[]): Promise<any> {\n\t\tfor (const { address, contact, type } of resolvedRecipients) {\n\t\t\tif (contact == null) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tconst isExternalAndConfidential = type === RecipientType.EXTERNAL && this.isConfidential()\n\n\t\t\tif (!contact._id && (!this.user().props.noAutomaticContacts || isExternalAndConfidential)) {\n\t\t\t\tif (isExternalAndConfidential) {\n\t\t\t\t\tcontact.presharedPassword = this.getPassword(address).trim()\n\t\t\t\t}\n\n\t\t\t\tconst listId = await this.contactModel.contactListId()\n\t\t\t\tawait this.entity.setup(listId, contact)\n\t\t\t} else if (contact._id && isExternalAndConfidential && contact.presharedPassword !== this.getPassword(address).trim()) {\n\t\t\t\tcontact.presharedPassword = this.getPassword(address).trim()\n\t\t\t\tawait this.entity.update(contact)\n\t\t\t}\n\t\t}\n\t}\n\n\tallRecipients(): ReadonlyArray<ResolvableRecipient> {\n\t\treturn this.toRecipients().concat(this.ccRecipients()).concat(this.bccRecipients())\n\t}\n\n\t/**\n\t * Makes sure the recipient type and contact are resolved.\n\t */\n\tasync waitForResolvedRecipients(): Promise<Recipient[]> {\n\t\tawait this.recipientsResolved.getAsync()\n\t\treturn Promise.all(this.allRecipients().map((recipient) => recipient.resolved())).catch(\n\t\t\tofClass(TooManyRequestsError, () => {\n\t\t\t\tthrow new RecipientNotResolvedError(\"\")\n\t\t\t}),\n\t\t)\n\t}\n\n\tasync handleEntityEvent(update: EntityUpdateData): Promise<void> {\n\t\tconst { operation, instanceId, instanceListId } = update\n\t\tlet contactId: IdTuple = [neverNull(instanceListId), instanceId]\n\t\tlet changed = false\n\n\t\tif (isUpdateForTypeRef(ContactTypeRef, update)) {\n\t\t\tawait this.recipientsResolved.getAsync()\n\n\t\t\tif (operation === OperationType.UPDATE) {\n\t\t\t\tthis.entity.load(ContactTypeRef, contactId).then((contact) => {\n\t\t\t\t\tfor (const fieldType of typedValues(RecipientField)) {\n\t\t\t\t\t\tconst matching = this.getRecipientList(fieldType).filter(\n\t\t\t\t\t\t\t(recipient) => recipient.contact && isSameId(recipient.contact._id, contact._id),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tmatching.forEach((recipient) => {\n\t\t\t\t\t\t\t// if the mail address no longer exists on the contact then delete the recipient\n\t\t\t\t\t\t\tif (!contact.mailAddresses.find((ma) => cleanMatch(ma.address, recipient.address))) {\n\t\t\t\t\t\t\t\tchanged = changed || this.removeRecipient(recipient, fieldType, true)\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// else just modify the recipient\n\t\t\t\t\t\t\t\trecipient.setName(getContactDisplayName(contact))\n\t\t\t\t\t\t\t\trecipient.setContact(contact)\n\t\t\t\t\t\t\t\tchanged = true\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t} else if (operation === OperationType.DELETE) {\n\t\t\t\tfor (const fieldType of typedValues(RecipientField)) {\n\t\t\t\t\tconst recipients = this.getRecipientList(fieldType)\n\n\t\t\t\t\tconst toDelete = recipients.filter((recipient) => (recipient.contact && isSameId(recipient.contact._id, contactId)) || false)\n\n\t\t\t\t\tfor (const r of toDelete) {\n\t\t\t\t\t\tchanged = changed || this.removeRecipient(r, fieldType, true)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.markAsChangedIfNecessary(true)\n\t\t} else if (isUpdateForTypeRef(CustomerPropertiesTypeRef, update)) {\n\t\t\tthis.updateAvailableNotificationTemplateLanguages()\n\t\t} else if (isUpdateForTypeRef(MailboxPropertiesTypeRef, update) && operation === OperationType.UPDATE) {\n\t\t\tthis.mailboxProperties = await this.entity.load(MailboxPropertiesTypeRef, update.instanceId)\n\t\t}\n\t\tthis.markAsChangedIfNecessary(changed)\n\t\treturn Promise.resolve()\n\t}\n\n\tsetOnBeforeSendFunction(fun: () => unknown) {\n\t\tthis.onBeforeSend = fun\n\t}\n}\n\n/**\n * deduplicate a list of recipients for insertion in any of the recipient fields\n * recipients are considered equal when their cleanMailAddress() is the same\n * returns the recipients with their original mail address\n *\n * unhandled edge case: it's possible to lose recipients that should be kept when\n * * the mail contains several recipients that have the same clean address (Bob@e.de and bob@e.de)\n * * the e.de mail server considers these distinct\n * * we hit \"reply all\"\n *\n */\nfunction recipientsFilter(recipientList: ReadonlyArray<PartialRecipient>): Array<PartialRecipient> {\n\t// we pack each recipient along with its cleaned address, deduplicate the array by comparing cleaned and then unpack the original recipient\n\t// this prevents us from changing the values contained in the array and still keeps the cleanAddress calls out of the n^2 loop\n\tconst cleanedList = recipientList.filter((r) => isMailAddress(r.address, false)).map((a) => ({ recipient: a, cleaned: cleanMailAddress(a.address) }))\n\treturn deduplicate(cleanedList, (a, b) => a.cleaned === b.cleaned).map((a) => a.recipient)\n}\n","import m, { Children, Component, Vnode } from \"mithril\"\nimport stream from \"mithril/stream\"\nimport Stream from \"mithril/stream\"\nimport { Dialog, DialogType } from \"../../gui/base/Dialog\"\nimport { ButtonType } from \"../../gui/base/Button.js\"\nimport { isMailAddress } from \"../../misc/FormatValidator\"\nimport { UserError } from \"../../api/main/UserError\"\nimport { showUserError } from \"../../misc/ErrorHandlerImpl\"\nimport type { MailboxDetail } from \"../model/MailModel\"\nimport { Keys, MailMethod, TabIndex } from \"../../api/common/TutanotaConstants\"\nimport { getDefaultSender } from \"../model/MailUtils\"\nimport { progressIcon } from \"../../gui/base/Icon\"\nimport { Editor } from \"../../gui/editor/Editor\"\nimport { htmlSanitizer } from \"../../misc/HtmlSanitizer\"\nimport { replaceInlineImagesWithCids } from \"../view/MailGuiUtils\"\nimport { TextField } from \"../../gui/base/TextField.js\"\nimport { DialogHeaderBarAttrs } from \"../../gui/base/DialogHeaderBar\"\nimport { RichTextToolbar } from \"../../gui/base/RichTextToolbar.js\"\nimport { locator } from \"../../api/main/MainLocator.js\"\n\ntype PressContact = {\n\temail: string\n\tgreeting: string\n}\n\nexport function openPressReleaseEditor(mailboxDetails: MailboxDetail): void {\n\tfunction close() {\n\t\tdialog.close()\n\t}\n\n\tasync function send() {\n\t\tconst mailboxProperties = await locator.mailModel.getMailboxProperties(mailboxDetails.mailboxGroupRoot)\n\t\tconst body = pressRelease.bodyHtml()\n\t\tconst subject = pressRelease.subject()\n\t\tlet recipients\n\n\t\ttry {\n\t\t\trecipients = getValidRecipients(pressRelease.recipientsJson())\n\t\t} catch (e) {\n\t\t\tif (e instanceof UserError) {\n\t\t\t\treturn showUserError(e)\n\t\t\t} else {\n\t\t\t\tthrow e\n\t\t\t}\n\t\t}\n\n\t\t// We aren't using translation keys here because it's not a user facing feature\n\t\tconst choice = await Dialog.choice(\n\t\t\t() => `Really send the press release out to ${recipients.length} recipients?`,\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\ttext: () => \"Cancel\",\n\t\t\t\t\tvalue: \"cancel\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttext: () => \"Just test\",\n\t\t\t\t\tvalue: \"test\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttext: () => \"Yes please\",\n\t\t\t\t\tvalue: \"send\",\n\t\t\t\t},\n\t\t\t],\n\t\t)\n\n\t\tif (choice === \"cancel\") {\n\t\t\treturn\n\t\t}\n\n\t\tif (choice === \"test\") {\n\t\t\trecipients.splice(0, recipients.length, {\n\t\t\t\temail: getDefaultSender(locator.logins, mailboxDetails),\n\t\t\t\tgreeting: \"Hi Test Recipient\",\n\t\t\t})\n\t\t}\n\n\t\tlet progressMessage = \"\"\n\t\tlet stop = false\n\t\t// Taken from showProgressDialog which has a hardcoded delay when you show it which we don't want\n\t\t// so we just reuse the same dialog and update the message\n\t\tconst progressDialog = new Dialog(DialogType.Progress, {\n\t\t\tview: () =>\n\t\t\t\tm(\n\t\t\t\t\t\".hide-outline\",\n\t\t\t\t\t{\n\t\t\t\t\t\t// We make this element focusable so that the screen reader announces the dialog\n\t\t\t\t\t\ttabindex: TabIndex.Default,\n\n\t\t\t\t\t\toncreate(vnode) {\n\t\t\t\t\t\t\t// We need to delay so that the eelement is attached to the parent\n\t\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\t\t;(vnode.dom as HTMLElement).focus()\n\t\t\t\t\t\t\t}, 10)\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t[m(\".flex-center\", progressIcon()), m(\"p#dialog-title\", progressMessage)],\n\t\t\t\t),\n\t\t}).addShortcut({\n\t\t\tkey: Keys.ESC,\n\t\t\texec: () => (stop = true),\n\t\t\thelp: \"cancel_action\",\n\t\t})\n\t\tprogressDialog.show()\n\t\tlet didFinish = true\n\n\t\tfor (let recipient of recipients) {\n\t\t\tif (stop) {\n\t\t\t\tdidFinish = false\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tconst bodyWithGreeting = `<p>${recipient.greeting},</p>${body}`\n\n\t\t\ttry {\n\t\t\t\tconst mailboxProperties = await locator.mailModel.getMailboxProperties(mailboxDetails.mailboxGroupRoot)\n\t\t\t\tconst sendMailModel = await locator.sendMailModel(mailboxDetails, mailboxProperties)\n\t\t\t\tconst model = await sendMailModel.initWithTemplate(\n\t\t\t\t\t{\n\t\t\t\t\t\tto: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\taddress: recipient.email,\n\t\t\t\t\t\t\t\tname: null,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t\tsubject,\n\t\t\t\t\tbodyWithGreeting,\n\t\t\t\t\t[],\n\t\t\t\t\tfalse,\n\t\t\t\t)\n\t\t\t\tawait model.send(\n\t\t\t\t\tMailMethod.NONE,\n\t\t\t\t\t() => Promise.resolve(true),\n\t\t\t\t\t(_, p) => {\n\t\t\t\t\t\tprogressMessage = `Sending to ${recipient.email}`\n\t\t\t\t\t\tm.redraw()\n\t\t\t\t\t\treturn p\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t} catch (e) {\n\t\t\t\t// Stop sending after first failure in case something bad happened\n\t\t\t\tDialog.message(() => `Error sending to ${recipient.email}: ${e.message}.\\nStopping.`)\n\t\t\t\tdidFinish = false\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tprogressDialog.close()\n\n\t\tif (didFinish) {\n\t\t\tclose()\n\t\t}\n\t}\n\n\tconst pressRelease = {\n\t\tbodyHtml: stream(\"\"),\n\t\tsubject: stream(\"\"),\n\t\trecipientsJson: stream(\"[\\n    \\n]\"),\n\t}\n\tconst header: DialogHeaderBarAttrs = {\n\t\tleft: [\n\t\t\t{\n\t\t\t\tlabel: \"close_alt\",\n\t\t\t\tclick: close,\n\t\t\t\ttype: ButtonType.Secondary,\n\t\t\t},\n\t\t],\n\t\tmiddle: () => \"Press Release\",\n\t\tright: [\n\t\t\t{\n\t\t\t\tlabel: \"send_action\",\n\t\t\t\tclick: send,\n\t\t\t\ttype: ButtonType.Primary,\n\t\t\t},\n\t\t],\n\t}\n\tconst dialog = Dialog.editDialog(header, PressReleaseForm, pressRelease)\n\tdialog.show()\n}\n\nfunction getValidRecipients(recipientsJSON: string): Array<PressContact> {\n\tlet parsed\n\n\ttry {\n\t\tparsed = JSON.parse(recipientsJSON)\n\t} catch (e) {\n\t\tthrow new UserError(() => \"Unable to parse recipients JSON:\\n\" + e.toString())\n\t}\n\n\tif (!(parsed instanceof Array)) {\n\t\tthrow new UserError(() => \"Recipients must be an array\")\n\t}\n\n\treturn parsed.map(({ email, greeting }) => {\n\t\tif (typeof email !== \"string\" || !isMailAddress(email, false)) {\n\t\t\tthrow new UserError(() => `Not all provided recipients have an \"email\" field`)\n\t\t}\n\n\t\tif (typeof greeting !== \"string\") {\n\t\t\tthrow new UserError(() => `Not all provided recipients have a \"greeting\" field`)\n\t\t}\n\n\t\t// Discard any unneeded fields\n\t\treturn {\n\t\t\temail,\n\t\t\tgreeting,\n\t\t}\n\t})\n}\n\nexport type PressReleaseFormAttrs = {\n\tsubject: Stream<string>\n\tbodyHtml: Stream<string>\n\trecipientsJson: Stream<string>\n}\n\nexport class PressReleaseForm implements Component<PressReleaseFormAttrs> {\n\teditor: Editor\n\n\tconstructor(vnode: Vnode<PressReleaseFormAttrs>) {\n\t\tconst { bodyHtml } = vnode.attrs\n\t\tthis.editor = new Editor(\n\t\t\t200,\n\t\t\t(html, _) =>\n\t\t\t\thtmlSanitizer.sanitizeFragment(html, {\n\t\t\t\t\tblockExternalContent: false,\n\t\t\t\t}).fragment,\n\t\t)\n\t\tthis.editor.initialized.promise.then(() => {\n\t\t\tthis.editor.setHTML(bodyHtml())\n\t\t\tthis.editor.addChangeListener(() => bodyHtml(replaceInlineImagesWithCids(this.editor.getDOM()).innerHTML))\n\t\t})\n\t}\n\n\tview(vnode: Vnode<PressReleaseFormAttrs>): Children {\n\t\tconst { subject, recipientsJson } = vnode.attrs\n\t\treturn m(\"\", [\n\t\t\tm(\"label.i.monospace\", \"Recipients JSON\"),\n\t\t\tm(\"textarea.full-width\", {\n\t\t\t\tstyle: {\n\t\t\t\t\theight: \"200px\",\n\t\t\t\t\tresize: \"none\",\n\t\t\t\t},\n\t\t\t\toninput: (e: InputEvent) => recipientsJson((e.target as HTMLTextAreaElement).value),\n\t\t\t\tvalue: recipientsJson(),\n\t\t\t}),\n\t\t\tm(TextField, {\n\t\t\t\tlabel: \"subject_label\",\n\t\t\t\tvalue: subject(),\n\t\t\t\toninput: subject,\n\t\t\t}),\n\t\t\tm(RichTextToolbar, { editor: this.editor }),\n\t\t\tm(\".border-top\", m(this.editor)),\n\t\t])\n\t}\n}\n"],"names":["always","TreeIterator","root","currentNode","nodeType","filter","constructor","this","isAcceptableNode","node","Node","ELEMENT_NODE","TEXT_NODE","nextNode","current","firstChild","nextSibling","parentNode","previousNode","previousSibling","lastChild","previousPONode","ZWS","ua","navigator","userAgent","isMac","test","isWin","isIOS","maxTouchPoints","isAndroid","isGecko","isLegacyEdge","ctrlKey","cantFocusEmptyTextNodes","supportsInputEvents","document","InputEvent","notWS","inlineNodeNames","leafNodeNames","Set","cache","WeakMap","isLeaf","has","nodeName","getNodeCategory","get","nodeCategory","Array","from","childNodes","every","isInline","set","isBlock","isContainer","createElement","tag","props","children","el","attr","value","setAttribute","forEach","appendChild","areAlike","node2","HTMLElement","className","style","cssText","hasTagAttributes","attributes","getAttribute","getNearest","getNodeBeforeOffset","offset","Element","length","getNodeAfterOffset","returnNode","getLength","DocumentFragment","CharacterData","empty","frag","createDocumentFragment","child","detach","parent","removeChild","replaceWith","replaceChild","notWSTextNode","data","isLineBreak","br","isLBIfEmptyBlock","block","walker","removeZWS","keepNode","textNode","index","indexOf","deleteData","isNodeContainedInRange","range","partial","nodeRange","createRange","selectNode","nodeEndBeforeStart","compareBoundaryPoints","nodeStartAfterEnd","nodeStartAfterStart","nodeEndBeforeEnd","moveRangeBoundariesDownTree","startContainer","startOffset","endContainer","endOffset","Text","prev","textChild","remove","setStart","setEnd","moveRangeBoundariesUpTree","startMax","endMax","commonAncestorContainer","moveRangeBoundaryOutOf","clone","cloneRange","fixCursor","fixer","createTextNode","querySelector","lastElementChild","error","fixContainer","container","wrapper","isBR","insertBefore","split","stopNode","Error","splitText","nodeAfterSplit","cloneNode","next","HTMLOListElement","start","_mergeInlines","fakeRange","l","frags","appendData","push","pop","mergeInlines","element","mergeWithBlock","last","collapse","mergeContainers","first","isListItem","needsFix","styleToSemantic","regexp","replace","classNames","family","class","fontFamily","size","fontSize","replaceWithTag","i","attribute","name","fontSizes","stylesRewriters","STRONG","EM","INS","STRIKE","SPAN","_","config","newTreeBottom","newTreeTop","converter","css","getPropertyValue","removeProperty","FONT","font","face","color","fontSpan","sizeSpan","colorSpan","charAt","TT","allowedBlock","blacklist","cleanTree","preserveWS","nonInlineParent","rewriter","childLength","startsWithWS","endsWithWS","sibling","removeEmptyInlines","cleanupBRs","keepForBlankLine","brs","querySelectorAll","brBreaksLine","escapeHTML","text","join","getBlockWalker","getPreviousBlock","getNextBlock","isEmptyBlock","textContent","getStartBlockOfRange","getEndBlockOfRange","contains","isContent","rangeDoesStartAtBlockBoundary","nodeAfterCursor","contentWalker","rangeDoesEndAtBlockBoundary","expandRangeToBlockBoundaries","end","insertNodeInRange","collapsed","afterSplit","childCount","extractContentsOfRange","common","getAdjacentInlineNode","iterator","method","deleteContentsOfRange","startBlock","endBlock","needsMerge","selectNodeContents","afterNode","afterOffset","beforeNode","beforeOffset","replaceData","prototype","extractRangeToClipboard","event","removeRangeFromDocument","toCleanHTML","toPlainText","plainTextOnly","clipboardData","contents","copyRoot","cloneContents","newContents","body","html","innerHTML","innerText","setData","preventDefault","setClipboardData","_onCut","getSelection","_root","saveUndoState","_config","willCutCopy","setTimeout","_ensureBottomLine","didError","setSelection","_onCopy","_monitorShiftKey","_isShiftDown","shiftKey","_onPaste","items","choosePlain","hasRTF","hasImage","plainItem","htmlItem","item","type","fireEvent","getAsString","isLink","range2","toString","match","linkRegExp","exec","makeLink","insertPlainText","insertHTML","types","call","getData","pasteArea","contenteditable","HTMLDivElement","_onDrop","dataTransfer","hasPlain","hasHTML","Enter","self","splitBlock","afterDelete","_updatePath","detachUneditableNode","isContentEditable","linkifyText","searchFrom","Math","max","lastIndexOf","searchText","slice","selection","_docWasChanged","_recordUndoState","_getRangeAndRemoveBookmark","endIndex","needsSelectionUpdate","newSelectionOffset","defaultAttributes","tagAttributes","a","link","Object","assign","href","keys","_onKey","code","keyCode","key","modifiers","defaultPrevented","String","fromCharCode","toLowerCase","altKey","metaKey","_keyHandlers","isComposing","keyHandlers","Backspace","_removeZWS","previous","decreaseListLevel","removeQuote","HTMLAnchorElement","includes","removeLink","Delete","originalRange","cursorContainer","cursorOffset","Tab","increaseListLevel","Space","setStartAfter","addLinks","linkRange","ArrowLeft","ArrowRight","getRoot","PageUp","moveCursorToStart","PageDown","moveCursorToEnd","mapKeyToFormat","hasFormat","changeFormat","path","getPath","removeList","makeUnorderedList","makeOrderedList","decreaseQuoteLevel","increaseQuoteLevel","toggleCode","undo","redo","HtmlEditorMode","Squire_default","_isFocused","_lastSelection","_willRestoreSelection","_mayHaveZWS","_lastAnchorNode","_lastFocusNode","_path","_events","_undoIndex","_undoStack","_undoStackLength","_isInUndoState","_ignoreChange","_ignoreAllChanges","_mutation","_makeConfig","Map","addEventListener","_updatePathOnEvent","_enableRestoreSelection","_disableRestoreSelection","_restoreSelection","create","mutation","MutationObserver","observe","childList","characterData","subtree","execCommand","_beforeInput","setHTML","destroy","removeEventListener","disconnect","userConfig","blockTag","blockAttributes","highlight","documentSizeThreshold","undoLimit","sanitizeToDOMFragment","DOMPurify","sanitize","ALLOW_UNKNOWN_PROTOCOLS","WHOLE_DOCUMENT","RETURN_DOM","RETURN_DOM_FRAGMENT","FORCE_BODY","importNode","console","log","toUpperCase","setKeyHandler","fn","inputType","bold","italic","underline","strikethrough","superscript","subscript","alignment","setTextAlignment","removeAllFormatting","dir","setTextDirection","setHighlightColor","setTextColor","setFontFace","handleEvent","detail","handlers","isFocused","activeElement","Event","CustomEvent","handler","customEvents","target","splice","delete","focus","preventScroll","blur","startSelectionId","endSelectionId","_saveRangeToBookmark","temp","startNode","id","endNode","compareDocumentPosition","DOCUMENT_POSITION_PRECEDING","setEndBefore","window","rangeCount","getRangeAt","setStartBefore","firstElementChild","Selection","setBaseAndExtent","removeAllRanges","addRange","_moveCursorTo","toStart","getCursorPosition","rect","getBoundingClientRect","top","force","anchor","newPath","_getPath","classList","sort","styleNames","backgroundColor","modifyDocument","modificationFn","takeRecords","canUndo","canRedo","undoIndex","undoStack","undoConfig","undoThreshold","_getRawHTML","_setRawHTML","undoStackLength","createDefaultBlock","getHTML","withBookmark","isPaste","addDetectedLinks","normalize","doInsert","fragment","firstInFragIsInline","stopPoint","blockContentsAfterSplit","firstBlockInFrag","replaceBlock","nodeBeforeSplit","tempRange","insertTreeFragmentIntoRange","insertElement","splitNode","blankLine","insertImage","src","img","plainText","insertData","lines","closeBlock","openBlock","line","getSelectedText","addedTextInBlock","getFontInfo","fontInfo","seenAttributes","setEndAfter","seenNode","add","_removeFormat","_addFormat","focusNode","focusOffset","toWrap","examineNode","exemplar","HTMLInputElement","formatTags","getElementsByTagName","removeBold","removeItalic","removeUnderline","removeStrikethrough","removeSubscript","removeSuperscript","url","protocolEnd","searchInNode","setFontSize","tagAfterSplit","DT","DD","LI","PRE","lineBreakOnly","offset2","splitTag","splitProperties","forEachBlock","mutates","modifyBlocks","modify","klass","textAlign","direction","removeAttribute","_getListSelection","list","startLi","endLi","listSelection","listAttrs","newParent","makeNotList","_makeList","listItemAttrs","li","HTMLLIElement","newLi","lists","listFrag","blockquote","output","blockWalker","nodes","textWalker","pre","removeCode","ancestor","pres","_removeFormatting","clean","formattedNodes","cleanNodes","nodeInSplit","Editor","minHeight","sanitizer","initialized","defer","domElement","enabled","createsLists","userHasPasted","styleActions","freeze","b","squire","styles","u","c","listing","pasteListener","hasStyle","getStylesAtPath","pathSegments","ulIndex","olIndex","find","f","undefined","substring","onremove","bind","onbeforeupdate","view","_a","m","role","tabindex","oncreate","vnode","initSquire","dom","px","isEmpty","getValue","addChangeListener","callback","setMinHeight","setCreatesLists","SquireEditor","e","isKeyPressed","Keys","SPACE","blocks","createList","regex","ordered","_b","isEnabled","redraw","setEnabled","resolve","setStyle","state","Dialog","showTextInputDialog","then","isMailAddress","startsWith","srcAttr","attrs","getDOM","isAttached","exports","HtmlEditor","label","injections","mode","WYSIWYG","active","domTextArea","_showBorders","placeholderId","placeholderDomElement","stream","htmlMonospace","modeSwitcherLabel","toolbarEnabled","toolbarAttrs","editor","htmlSanitizer","sanitizeFragment","blockExternalContent","initializeEditorListeners","borderClasses","renderedInjections","DropDownSelector","lang","getMaybeLazy","HTML","selectedValue","selectionChangedHandler","setValue","onclick","assertNotNull","getPlaceholder","RichTextToolbar","promise","onfocus","onblur","oninput","height","scrollHeight","disabled","setModeSwitcher","showBorders","setPlaceholderId","sanitizeHTML","getTrimmedValue","isActive","setMode","setHtmlMonospace","monospace","enableToolbar","isToolbarEnabled","toggleToolbar","setToolbarOptions","getDefaultSignature","LINE_BREAK","getEmailSignature","tutanotaProperties","emailSignatureType","customEmailSignature","appendEmailSignature","properties","signature","assertMainOrNode","logins","bodyWithSignature","getUserController","isInternalUser","async","chooseAndAttachFile","model","boundingRect","fileTypes","round","width","x","y","files","fileSelector","Mode","App","Desktop","env","locator","fileApp","openFileChooser","showFileChooser","catch","ofClass","PermissionError","message","FileNotFoundError","showFileChooserForAttachments","attachFiles","dataFiles","Promise","all","map","readDataFile","location","isNotNull","UserError","showUserError","msg","createAttachmentBubbleAttrs","inlineImageElements","getAttachments","attachment","open","download","isFileReference","isDataFile","fileController","saveDataFile","isTutanotaFile","ProgrammingError","FileOpenError","_downloadAttachment","removeAttachment","cid","imageElement","cleanupInlineAttachments","debounce","attachments","elementsToRemove","inlineImage","attachmentIndex","findIndex","findAllAndRemove","TEMPLATE_SHORTCUT_PREFIX","SELECT_NEXT_TEMPLATE","SELECT_PREV_TEMPLATE","compareTemplatesForSort","template1","template2","titleComparison","title","localeCompare","TemplatePopupModel","eventController","entityClient","_eventController","_logins","_entityClient","_allTemplates","SortedArray","searchResults","selectedTemplate","_selectedContentLanguage","_searchFilter","TemplateSearchFilter","_groupInstances","_entityEventReceived","updates","_entityUpdate","LazyLoaded","loadTemplateGroupInstances","getTemplateMemberships","templateGroupInstances","templateGroups","promiseMap","group","loadAll","EmailTemplateTypeRef","groupRoot","templates","groupedTemplates","flat","loadTemplates","insertAll","array","setSelectedTemplate","addEntityListener","init","getAsync","isLoaded","dispose","removeEntityListener","isSelectedTemplate","template","getAllTemplates","getSelectedTemplate","getSelectedContent","languageCode","getSelectedTemplateIndex","setSelectedContentLanguage","langCode","search","query","_rerunSearch","rerunQuery","selectNextTemplate","action","nextIndex","nextSelectedTemplate","findTemplateWithTag","selectedText","update","isUpdateForTypeRef","operation","load","instanceListId","instanceId","insert","removeFirst","t","isSameId","getElementId","UserTypeRef","user","_id","reset","getTemplateGroupInstances","getSelectedTemplateGroupInstance","selected","instance","getEtId","_ownerGroup","memberships","membership","loadTemplateGroupInstance","groupMembership","GroupInfoTypeRef","groupInfo","TemplateGroupRootTypeRef","GroupTypeRef","searchInTemplates","input","allTemplates","newQueryString","lastInput","lastQuery","lastResults","_doFilter","TEMPLATE_POPUP_HEIGHT","TemplatePopupResultRow","marginLeft","TemplateExpander","sanitizedText","memoized","allowRelativeLinks","selectedContent","maxHeight","button_height","onkeydown","TAB","trust","TemplateSearchBar","domInput","theme","content_border","_getInputField","placeholder","which","ctrl","shift","keyHandler","lineHeight","inputLineHeight","createInitialTemplateListIfAllowed","userController","customer","loadCustomer","getAvailablePlansWithTemplates","module","import","n","S","plans","getPlanConfig","isCustomizationEnabledForCustomer","FeatureType","BusinessFeatureEnabled","showPlanUpgradeRequiredDialog","groupId","groupManagementFacade","createTemplateGroup","showTemplatePopupInEditor","templateModel","highlightedText","initialSearchString","cursorRect","editorRect","availableHeightBelowCursor","innerHeight","bottom","popUpHeight","popUpWidth","right","left","diff","DomRectReadOnlyPolyfilled","popup","TemplatePopup","show","onSelect","_inputDom","showTwoColumns","_isScreenWideEnough","_rect","stopPropagation","windowFacade","addResizeListener","_resizeListener","removeResizeListener","_renderHeader","flex","_renderList","_renderRightColumn","_renderSearchBar","_searchBarValue","keyPress","DOWN","UP","_templateModel","_debounceFilter","_onSelect","_initialWindowWidth","innerWidth","_close","_shortcuts","ESC","help","RETURN","_redrawStream","results","_selectTemplateButtonAttrs","click","_renderAddButton","_renderEditButtons","_createAddButtonAttributes","IconButton","writeableGroups","hasCapabilityOnGroup","showTemplateEditor","icon","colors","attachDropdown","mainButtonAttrs","childAttrs","groupInstances","getSharedGroupName","selectedGroup","canEdit","languageByCode","textId","content","downcast","neverNull","getConfirmation","confirmed","erase","Button","ScrollSelectList","selectedItem","onItemSelected","emptyListMessage","renderItem","onItemDoubleClicked","_getWindowWidthChange","modal","display","backgroundClick","hideAnimation","onClose","shortcuts","popState","templateToEdit","h","TemplateShortcutListener","_editor","_currentCursorPosition","_lang","handleKeyDown","cursorEndPos","templateShortcutStartIndex","lastWhiteSpaceIndex","buttons","dropdown","Dropdown","setOrigin","displayUnique","getFirstOrThrow","handleCursorChange","KnowledgeBaseListEntry","keywords","entry","keyword","KnowledgeBaseEntryView","_sanitizedEntry","description","_renderContent","readonly","_handleAnchorClick","renderEditButton","renderRemoveButton","entryKeyword","NotFoundError","noOp","K","showKnowledgeBaseEditor","closest","anchorElement","listId","elementId","URL","pathname","onTemplateSelected","KnowledgeBaseDialogContent","filterValue","_streams","combine","selectedEntry","filteredEntries","templateId","loadTemplate","fetchedTemplate","onTemplateSelect","isReadOnly","TextField","_renderKeywords","matchedKeywords","getMatchedKeywordsInContent","_selectionChangedListener","makeListSelectionChangedScrollHandler","getSelectedEntryIndex","onbeforeremove","containsResult","_renderListEntry","_createHeaderAttrs","isDialogVisible","middle","createAddButtonAttrs","createListViewHeader","createDropdown","lazyButtons","entryToEdit","knowledgeBaseSearch","allEntries","compareKnowledgeBaseEntriesForSort","entry1","entry2","KnowledgeBaseModel","_allEntries","_allKeywords","_matchedKeywordsInContent","_filterValue","_initialized","templateMemberships","newGroupInstances","KnowledgeBaseEntryTypeRef","knowledgeBase","loadKnowledgebaseEntries","knowledgebaseEntries","initAllKeywords","isInitialized","isSelectedEntry","getAllKeywords","getLanguageFromTemplate","clientLanguage","some","sortEntriesByMatchingKeywords","emailContent","emailContentNoTags","_compareEntriesByMatchedKeywords","difference","_getMatchedKeywordsNumber","matches","k","inputTrimmed","trim","selectNextEntry","nextSelectedEntry","_removeFromAllKeywords","updatedEntry","oldSelectedEntry","getLetId","createMailEditorAttrs","doBlockExternalContent","doFocusEditorOnLoad","dialog","knowledgeBaseInjection","doShowToolbar","selectedNotificationLanguage","MailEditor","recipientFieldTexts","to","cc","bcc","recipientShowConfidential","mentionedInlineImages","sendMailModel","areDetailsExpanded","bccRecipients","ccRecipients","sanitized","inlineImageCids","onEditorChanged","markAsChangedIfNecessary","getBody","setBody","replaceInlineImagesWithCids","imageItems","file","getAsFile","reader","FileReader","onload","result","newInlineImages","createDataFile","Uint8Array","insertInlineImages","readAsArrayBuffer","listener","registerTemplateShortcutListener","replaceCidsWithInlineImages","loadedInlineImages","downloadInlineImage","downloadClickHandler","onMailChanged","setOnBeforeSendFunction","invalidText","leftoverText","typedValues","getConversationType","toRecipients","setFocusOnLoadFunction","openTemplates","B","I","U","addShortcut","injection","inlineAttachment","showConfidentialButton","containsExternalRecipients","isConfidential","confidentialButtonAttrs","onToggled","setConfidential","toggled","attachFilesButtonAttrs","ev","plaintextFormatting","sendPlaintextOnly","toolbarButton","ToggleButton","subjectFieldAttrs","helpLabel","getConfidentialStateMessage","getSubject","val","setSubject","injectionsRight","renderToggleKnowledgeBase","attachmentBubbleAttrs","editCustomNotificationMailAttrs","isGlobalAdmin","E","showAddOrEditNotificationEmailDialog","getSelectedNotificationLanguageCode","ondragover","ondrop","readLocalFiles","renderRecipientField","RecipientField","TO","ExpanderPanel","expanded","CC","BCC","getEnabledMailAddressesWithUser","mailboxDetails","userGroupInfo","mailAddress","getSender","selectedValueDisplay","getMailAddressDisplayText","getSenderName","setSender","dropdownWidth","htmlDom","opacity","animations","getAvailableNotificationTemplateLanguages","language","v","setSelectedNotificationLanguageCode","renderPasswordFields","AttachmentBubble","renderToolbar","visible","componentAttrs","animateToolbar","imageButtonClickHandler","isApp","customButtonAttrs","ALLOWED_IMAGE_FORMATS","createInlineImage","objectUrl","animateHeight","allRecipients","r","recipient","address","CompletenessIndicator","percentageCompleted","getPasswordStrength","getPassword","autocompleteAs","isConfidentialPasswordRevealed","setPassword","renderRevealIcon","field","fieldText","MailRecipientsTextField","onTextChanged","recipients","getRecipientList","onRecipientAdded","addRecipient","isOfflineError","TooManyRequestsError","onRecipientRemoved","removeRecipientByAddress","getRecipientClickedDropdownAttrs","getRecipient","getRecipientClickedContextButtons","isInternalUserLoggedIn","toggleRevealConfidentialPassword","entity","contactModel","canEditBubbleRecipient","DisableContacts","previousMail","getPreviousMail","canRemoveBubble","restrictions","participantGroupInfos","createdContactReceiver","contactElementId","contactListId","ContactTypeRef","contact","mailAddresses","ma","cleanMatch","setName","getContactDisplayName","setContact","removeRecipient","contextButtons","ContactEditor","newContact","createNewContact","fadein","childHeight","offsetHeight","createMailEditorDialog","mailEditorAttrs","save","showProgress","savePromise","saveDraft","showProgressDialog","send","confirm","close","disposables","templatePopupModel","disposable","minimize","saveStatus","status","hasMailChanged","reason","finally","draft","showMinimizedMailEditor","minimizedMailModel","windowCloseUnsubscribe","headerBarAttrs","conversationTypeString","isBrowser","addWindowCloseListener","isDesktop","client","isDesktopDevice","isDesktopLayout","KnowledgeBase","knowledgebaseModel","knowledgebaseInjection","knowledgebaseAttrs","headerAttrs","component","createKnowledgeBaseDialogInjection","setInjectionRight","recipientsSearchModel","editDialog","setCloseHandler","shortcut","newMailEditorFromTemplate","subject","bodyText","confidential","senderMailAddress","initialChangedState","mailboxProperties","mailModel","getMailboxProperties","mailboxGroupRoot","initWithTemplate","getSupportMailSignature","a4","getTimeZone","getIdentifier","versionNumber","writeSupportMail","isPremiumAccount","detailsProperties","getMailboxDetailsAndProperties","d","formatPrice","reminder","utils","showUpgradeWizard","getUserMailboxDetails","checkApprovalStatus","args","inlineImages","initAsResponse","mailWrapper","initWithDraft","mailtoUrl","mailTo","parseMailtoUrl","attach","uri","df","CancelledError","sizeCheckResult","checkAttachmentSize","attachableFiles","tooBigFiles","svg","referralLink","username","recipientsFilter","recipientList","cleanedList","cleaned","cleanMailAddress","deduplicate","mailFacade","recipientsModel","dateProvider","onRecipientDeleted","onBeforeSend","conversationType","replyTos","previousMessageId","availableNotificationTemplateLanguages","mailChangedAt","mailSavedAt","passwords","currentSavePromise","doSaveAgain","recipientsResolved","entityEventReceived","handleEntityEvent","userProps","senderAddress","getDefaultSender","defaultUnconfidential","getAvailableLanguageCode","notificationMailLanguage","updateAvailableNotificationTemplateLanguages","languages","filteredLanguages","getTemplateLanguages","languageCodes","getSubstitutedLanguageCode","password","getPasswordStrengthForUser","hasChanged","now","ConversationEntryTypeRef","conversationEntry","ce","messageId","cloneInlineImages","getMail","previousEntry","mail","MailTypeRef","sender","isLegacyMail","getDetails","getReplyTos","getMailBodyText","_c","insertRecipient","ResolveMode","Eager","getFromMap","toRecipientsResolved","resolved","ccRecipientsResolved","bccRecipientsResolved","replyTosResolved","fieldType","resolveMode","findRecipientWithAddress","presharedPassword","partialRecipient","wasAdded","notify","cleanRecipientAddress","didRemove","findAndRemove","revokeInlineImages","sizeLeft","MAX_ATTACHMENT_SIZE","reduce","total","Number","getDraft","updateDraft","senderName","LockedError","createDraft","mailMethod","isConfidentialExternal","getExternalRecipients","waitHandler","p","tooManyRequestsError","sendApprovalMail","waitForResolvedRecipients","hasInsecurePasswords","updateContacts","sendDraft","updatePreviousMail","updateExternalLanguage","asyncSend","RecipientNotResolvedError","RecipientsNotFoundError","invalidRecipients","AccessBlockedError","ApprovalStatus","SPAM_SENDER","PreconditionFailedError","minimalPasswordStrength","min","PASSWORD_MIN_SECURE_VALUE","isSecurePassword","saveAttachments","doSaveDraft","isMailInTrashOrSpam","attachmentIds","getAttachmentIds","newAttachments","fileId","FileTypeRef","concurrency","PayloadTooLargeError","MailBodyTooLargeError","folders","getMailboxFolders","mailFolder","getFolderByMailListId","getListId","folderType","MailFolderType","TRASH","SPAM","createApprovalMail","stringToCustomId","userGroup","setup","NotAuthorizedError","replyType","resolvedRecipients","isExternalAndConfidential","noAutomaticContacts","concat","contactId","changed","toDelete","CustomerPropertiesTypeRef","MailboxPropertiesTypeRef","fun","PressReleaseForm","bodyHtml","recipientsJson","resize","pressRelease","header","recipientsJSON","parsed","JSON","parse","email","greeting","getValidRecipients","choice","progressMessage","stop","progressDialog","progressIcon","didFinish","bodyWithGreeting"],"mappings":"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"}