You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
3.5 KiB
114 lines
3.5 KiB
/* eslint-disable no-plusplus */ |
|
const prefix = 'ProseMirror-prompt'; |
|
|
|
function reportInvalid(dom, message) { |
|
// FIXME this is awful and needs a lot more work |
|
let parent = dom.parentNode; |
|
let msg = parent.appendChild(document.createElement('div')); |
|
msg.style.left = dom.offsetLeft + dom.offsetWidth + 2 + 'px'; |
|
msg.style.top = dom.offsetTop - 5 + 'px'; |
|
msg.className = 'ProseMirror-invalid'; |
|
msg.textContent = message; |
|
setTimeout(() => parent.removeChild(msg), 1500); |
|
} |
|
|
|
function getValues(fields, domFields) { |
|
let result = Object.keys(fields) |
|
.filter((name, index) => { |
|
let field = fields[name]; |
|
let dom = domFields[index]; |
|
let value = field.read(dom); |
|
let bad = field.validate(value); |
|
|
|
if (bad) reportInvalid(dom, bad); |
|
return !bad; |
|
}) |
|
.reduce((acc, name, index) => { |
|
let field = fields[name]; |
|
let dom = domFields[index]; |
|
let value = field.read(dom); |
|
acc[name] = field.clean(value); |
|
return acc; |
|
}, {}); |
|
return result; |
|
} |
|
|
|
export function openPrompt(options) { |
|
let wrapper = document.body.appendChild(document.createElement('div')); |
|
wrapper.className = prefix; |
|
|
|
const close = () => { |
|
// eslint-disable-next-line no-use-before-define |
|
window.removeEventListener('mousedown', mouseOutside); |
|
if (wrapper.parentNode) wrapper.parentNode.removeChild(wrapper); |
|
}; |
|
|
|
let mouseOutside = e => { |
|
if (!wrapper.contains(e.target)) close(); |
|
}; |
|
setTimeout(() => window.addEventListener('mousedown', mouseOutside), 50); |
|
|
|
let domFields = []; |
|
|
|
Object.values(options.fields).map(field => domFields.push(field.render())); |
|
|
|
let submitButton = document.createElement('button'); |
|
submitButton.type = 'submit'; |
|
submitButton.className = |
|
'button tiny button--save-link ' + prefix + '-submit'; |
|
submitButton.textContent = 'Create Link'; |
|
let cancelButton = document.createElement('button'); |
|
cancelButton.type = 'button'; |
|
cancelButton.className = 'button tiny hollow secondary' + prefix + '-cancel'; |
|
cancelButton.textContent = 'Cancel'; |
|
cancelButton.addEventListener('click', close); |
|
|
|
let form = wrapper.appendChild(document.createElement('form')); |
|
if (options.title) { |
|
const titleDom = document.createElement('h5'); |
|
titleDom.className = 'sub-block-title'; |
|
form.appendChild(titleDom).textContent = options.title; |
|
} |
|
domFields.forEach(field => { |
|
form.appendChild(document.createElement('div')).appendChild(field); |
|
}); |
|
let buttons = form.appendChild(document.createElement('div')); |
|
buttons.className = prefix + '-buttons'; |
|
buttons.appendChild(submitButton); |
|
buttons.appendChild(document.createTextNode(' ')); |
|
buttons.appendChild(cancelButton); |
|
|
|
let box = wrapper.getBoundingClientRect(); |
|
wrapper.style.top = (window.innerHeight - box.height) / 2 + 'px'; |
|
wrapper.style.left = (window.innerWidth - box.width) / 2 + 'px'; |
|
|
|
let submit = () => { |
|
let params = getValues(options.fields, domFields); |
|
if (params) { |
|
close(); |
|
options.callback(params); |
|
} |
|
}; |
|
|
|
form.addEventListener('submit', e => { |
|
e.preventDefault(); |
|
submit(); |
|
}); |
|
|
|
form.addEventListener('keydown', e => { |
|
if (e.key === 'Esc') { |
|
e.preventDefault(); |
|
close(); |
|
} else if (e.key === 'Enter' && !(e.ctrlKey || e.metaKey || e.shiftKey)) { |
|
e.preventDefault(); |
|
submit(); |
|
} else if (e.key === 'Tab') { |
|
window.setTimeout(() => { |
|
if (!wrapper.contains(document.activeElement)) close(); |
|
}, 500); |
|
} |
|
}); |
|
|
|
let input = form.elements[0]; |
|
if (input) input.focus(); |
|
}
|
|
|