如何使用 showModal 按照承诺完全屏蔽外部内容?

2022-01-17 00:00:00 modal-dialog javascript

我正在尝试使用 javascript: 书签修改页面行为,因为我无法在当前环境中制作插件(或几乎任何其他东西).

I'm trying to modify a page behaviour with a javascript: bookmark, as I can't make plugins (or almost anything else) in my current environment.

除了某些页面中预期的回车键之外,几乎一切都运行良好,其中包含某种全局捕获.会发生这样的事情:

almost everything is working fine, except the expected enter key in some pages, which contain some kind of global capture for it. something like this is what happens:

(function(){
    window.dialog = dialog
    function dialog (title, callback, value) {
        let alertDialog = document.getElementById('alertDialog')
        if (alertDialog) alertDialog.remove()
        let htmlDiv = document.createElement('div')
        let html = `<div>dummy</div>
        <dialog id="alertDialog">
          <form method="dialog">
            <section>
              <p>
                <label for="value">${title}</label>
                <br />
                <input type="text" name="value" value="${value}">
              </p>
            </section>
            <menu>
              <button id="cancel" type="reset">cancel</button>
              &nbsp;
              <button type="submit">ok</button>
            </menu>
          </form>
        </dialog>
        <style>dialog#alertDialog input { width: 100%; } dialog#alertDialog menu { text-align: center; }</style>`
        htmlDiv.innerHTML = html.replace(/^s*</gm,'<').replace(/[
	fv]/g,'') // "minify" else append child fails, although...
            .replace('> <', '><') // ...after jscompress minifies this and we paste into bookmark, it adds those spaces which would yield to append child error
        alertDialog = htmlDiv.childNodes[1]
        document.querySelector('body').appendChild(alertDialog)
        let cancelButton = alertDialog.querySelector('#cancel')
        if (cancelButton) cancelButton.addEventListener('click', function() { alertDialog.close() })
        let input = alertDialog.querySelector('input')
        if (typeof callback === 'function') {
            alertDialog.onsubmit = function(){ callback(input ? input.value : true) }
            alertDialog.oncancel = function(){ callback(false) }
        }

        if (value !== undefined) {
            alertDialog.showModal() // prompt
        } else {
            alertDialog.querySelector('input').remove()
            if (title.substr(-1) === '?') {
                alertDialog.showModal() // confirm
            } else {
                alertDialog.querySelector('#cancel').remove()
                alertDialog.showModal() // alert
            }
        }
        return null
    }

//    dialog('foo!')
}())

<body onkeypress="handle(event)">
<form action="#">
    <input type="text" name="txt" />
    <a href="javascript:window.dialog('foo!')">modal</a>
</form>

<script>
    function handle(e){
        if(e.keyCode === 13){
            e.preventDefault(); // Ensure it is only this code that rusn
            alert("Enter was pressed was presses");
        }
    }
</script>
</body>

如果我可以更改此 DOM 并将 onkeypressbody 移动到 form,问题就解决了.但我什至不知道要修改的页面中的输入捕获事件在哪里.

if I could change this DOM and move the onkeypress from the body into the form, problem solved. but I don't even know where the enter capture event is in the page I'm trying to modify.

除了使用 alertconfirm 和/或 prompt 之外,有没有通用的方法来解决这个问题?在那里一小时我认为使用promises或yield可能会有所帮助,但它没有.

other than using alert, confirm and/or prompt, is there a generic approach to resolve this? for one hour there I thought using promises or yield might help, but it didn't.

我想继续使用 (或至少具有所有功能的东西,包括简单性和小代码),因为它为我解决了许多其他问题.

I want to keep using (or something with at least all features, including simplicity and small code) as it resolves a lot of other problems for me.

文档承诺这一点:

HTMLDialogElement 接口的 showModal() 方法将对话框显示为模式,位于可能存在的任何其他对话框的顶部.它与 ::backdrop 伪元素一起显示在顶层.对话框外的交互被阻止,对话框外的内容被渲染为惰性.

The showModal() method of the HTMLDialogElement interface displays the dialog as a modal, over the top of any other dialogs that might be present. It displays into the top layer, along with a ::backdrop pseudo-element. Interaction outside the dialog is blocked and the content outside it is rendered inert.

但现在这并不完全正确,是吗?

but that's not entirely true now, is it?

推荐答案

终于!这行得通.

首先我想让我们尝试覆盖 onkeypress",但是当它在这个单一实例中工作时,它不在我的环境中.然后最终我想哦,也许它在按键上".就这样.:)

first I figured "let's just try to override the onkeypress", but while it was working in this singular instance, it wasn't in my environment. then eventually I figured "oh, maybe it's on the keydown". and so it was. :)

因此,最后,该陈述并非完全错误.它只是没有阻止其他事件的传播,可能是每个设计,因为如果你需要的话,有资源可以做到这一点.(即,在这种情况下,stopPropagation).

so, in the end, the statement isn't entirely false. it's just not preventing other events from propagating, probably per design, as there are resources to do it if you need to. (namely, in this case, stopPropagation).

(function(){
    window.overrideEnter = overrideEnter
    function overrideEnter (event) {
        if (event.keyCode == 13) {
            event.stopPropagation()
        }
    }
    window.dialog = dialog
    function dialog (title, callback, value) {
        let alertDialog = document.getElementById('alertDialog')
        if (alertDialog) alertDialog.remove()
        let htmlDiv = document.createElement('div')
        let html = `<div>dummy</div>
        <dialog id="alertDialog">
          <form method="dialog" onkeypress="return window.overrideEnter(event)" onkeydown="return window.overrideEnter(event)" onkeyup="return window.overrideEnter(event)">
            <section>
              <p>
                <label for="value">${title}</label>
                <br />
                <input type="text" name="value" value="${value}">
              </p>
            </section>
            <menu>
              <button type="submit">ok</button>
              &nbsp;
              <button id="cancel" type="reset">cancel</button>
            </menu>
          </form>
        </dialog>
        <style>dialog#alertDialog input { width: 100%; } dialog#alertDialog menu { text-align: center; }</style>`
        htmlDiv.innerHTML = html.replace(/^s*</gm,'<').replace(/[
	fv]/g,'') // "minify" else append child fails, although...
            .replace('> <', '><') // ...after jscompress minifies this and we paste into bookmark, it adds those spaces which would yield to append child error
        alertDialog = htmlDiv.childNodes[1]
        document.querySelector('body').appendChild(alertDialog)
        let cancelButton = alertDialog.querySelector('#cancel')
        cancelButton.addEventListener('click', function(){ alertDialog.close(); callback(false) })
        let input = alertDialog.querySelector('input')
        //console.log(input)
        if (typeof callback === 'function') {
            alertDialog.onsubmit = function(){ callback(input ? input.value : true) }
            alertDialog.oncancel = function(){ callback(false) }
            alertDialog.onclose = function(){}
        }

        document.onkeydown = function(event) {
            event = event || window.event
            if (event.keyCode == 13) {
                event.stopPropagation()
            }
        }
        if (value !== undefined) {
            alertDialog.showModal() // prompt
        } else {
            input.remove()
            input = undefined
            if (title.substr(-1) === '?') {
                alertDialog.showModal() // confirm
            } else {
                cancelButton.remove()
                alertDialog.showModal() // alert
            }
        }
        return null
    }
}())

<body onkeypress="handle(event)">
<form action="#">
    <input type="text" name="txt" />
    <a href="javascript:window.dialog('foo?', result => console.log(result))">modal</a>
</form>

<script>
    function handle(e){
        if(e.keyCode === 13){
            e.preventDefault()
            alert("Enter was pressed was pressed")
        }
        return true
    }
</script>
</body>

相关文章