• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mozilla / blurts-server / #12296

pending completion
#12296

push

circleci

web-flow
Merge pull request #2830 from mozilla/MNTOR-1160/add-new-email

Mntor 1160/add new email

282 of 1332 branches covered (21.17%)

Branch coverage included in aggregate %.

79 of 79 new or added lines in 7 files covered. (100.0%)

959 of 3548 relevant lines covered (27.03%)

2.2 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/client/js/dialog.js
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4

5
const main = document.querySelector('body > main')
×
6
const observer = new MutationObserver(handleMutation)
×
7
const triggerLinks = main.querySelectorAll('a[href*="dialog/"], button[data-dialog]')
×
8
let dialogEl
9

10
function init (links) {
11
  if (!dialogEl) {
×
12
    dialogEl = document.createElement('dialog')
×
13
    document.body.append(dialogEl)
×
14
  }
15

16
  links.forEach(link => link.addEventListener('click', handleEvent))
×
17
}
18

19
function handleMutation (mutationList) {
20
  for (const mutation of mutationList) {
×
21
    if (!mutation.addedNodes.length) continue // ignore removed-node mutations
×
22
    const triggerLink = mutation.target.querySelector('a[href*="dialog/"], button[data-dialog]')
×
23
    if (triggerLink) init([triggerLink])
×
24
  }
25
}
26

27
function handleEvent (e) {
28
  switch (true) {
×
29
    case e.target.matches('a[href*="dialog/"]'):
30
      e.preventDefault()
×
31
      openDialog(e.target.href)
×
32
      break
×
33
    case e.target.matches('button[data-dialog]'):
34
      openDialog(`dialog/${e.target.dataset.dialog}`)
×
35
      break
×
36
    case e.target.matches('dialog button.close'):
37
      dialogEl.close()
×
38
      break
×
39
  }
40
}
41

42
async function openDialog (path) {
43
  const partialName = path.substring(path.lastIndexOf('/') + 1)
×
44

45
  dialogEl.showModal() // provide immediate UI response by showing ::backdrop regardless of content load
×
46
  dialogEl.setAttribute('data-partial', partialName) // allow selector access, e.g. dialog[data-partial='add-email']
×
47
  dialogEl.addEventListener('click', handleEvent)
×
48
  dialogEl.addEventListener('close', resetDialog)
×
49

50
  try {
×
51
    const res = await fetch(path)
×
52

53
    if (!res.ok) throw new Error('Bad fetch response')
×
54

55
    const content = await res.text()
×
56
    dialogEl.insertAdjacentHTML('beforeend', content)
×
57

58
    try {
×
59
      const module = await import(`./partials/${partialName}.js`) // import module associated with dialog content
×
60
      module.default() // TODO: refactor filenames with camelCase to allow the filename as function name instead of default
×
61
    } catch (e) {
62
      console.log(`Dialog module "${partialName}.js" not found.`, e)
×
63
    }
64
  } catch (e) {
65
    dialogEl.close()
×
66
    console.error(`Could not load dialog content for ${partialName}.`, e)
×
67
  }
68
}
69

70
function resetDialog () {
71
  dialogEl.removeEventListener('click', handleEvent)
×
72
  dialogEl.removeEventListener('close', resetDialog)
×
73
  dialogEl.removeAttribute('data-partial')
×
74
  dialogEl.replaceChildren()
×
75
}
76

77
if (triggerLinks.length) init(triggerLinks) // adds event listeners for dialog links already in DOM
×
78
observer.observe(main, { attributes: false, childList: true, subtree: true }) // watches for new dialog links dynamically added to DOM
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc