mirror of https://github.com/halo-dev/halo
feat: stop Implicit submission (halo-dev/console#766)
<!-- Thanks for sending a pull request! Here are some tips for you: 1. 如果这是你的第一次,请阅读我们的贡献指南:<https://github.com/halo-dev/halo/blob/master/CONTRIBUTING.md>。 1. If this is your first time, please read our contributor guidelines: <https://github.com/halo-dev/halo/blob/master/CONTRIBUTING.md>. 2. 请根据你解决问题的类型为 Pull Request 添加合适的标签。 2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request. 3. 请确保你已经添加并运行了适当的测试。 3. Ensure you have added or ran the appropriate tests for your PR. --> #### What type of PR is this? /kind feature /area console <!-- 添加其中一个类别: Add one of the following kinds: /kind bug /kind cleanup /kind documentation /kind feature /kind optimization 适当添加其中一个或多个类别(可选): Optionally add one or more of the following kinds if applicable: /kind api-change /kind deprecation /kind failing-test /kind flake /kind regression --> #### What this PR does / why we need it: 阻止表单的[隐式提交](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#implicit-submission) >For the purpose of the previous paragraph, an element is a field that blocks implicit submission of a element if it is an element whose [form owner](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#form-owner) is that element and whose attribute is in one of the following states: [Text](https://html.spec.whatwg.org/multipage/input.html#text-(type=text)-state-and-search-state-(type=search)), [Search](https://html.spec.whatwg.org/multipage/input.html#text-(type=text)-state-and-search-state-(type=search)), [URL](https://html.spec.whatwg.org/multipage/input.html#url-state-(type=url)), [Telephone](https://html.spec.whatwg.org/multipage/input.html#telephone-state-(type=tel)), [Email](https://html.spec.whatwg.org/multipage/input.html#email-state-(type=email)), [Password](https://html.spec.whatwg.org/multipage/input.html#password-state-(type=password)), [Date](https://html.spec.whatwg.org/multipage/input.html#date-state-(type=date)), [Month](https://html.spec.whatwg.org/multipage/input.html#month-state-(type=month)), [Week](https://html.spec.whatwg.org/multipage/input.html#week-state-(type=week)), [Time](https://html.spec.whatwg.org/multipage/input.html#time-state-(type=time)), [Local Date and Time](https://html.spec.whatwg.org/multipage/input.html#local-date-and-time-state-(type=datetime-local)), [Number](https://html.spec.whatwg.org/multipage/input.html#number-state-(type=number)) 当form的子元素只有一个且tyep为 ` "text","search","url","email","password","date","month","week","time","datetime-local","number"`其中任一。 阻止键入`enter` 触发`submit` ,做法是在from表单上监听键盘事件,然后阻止。 #### Which issue(s) this PR fixes: <!-- PR 合并时自动关闭 issue。 Automatically closes linked issue when PR is merged. 用法:`Fixes #<issue 号>`,或者 `Fixes (粘贴 issue 完整链接)` Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`. --> Fixes https://github.com/halo-dev/halo/issues/2893 #### Screenshots: <!-- 如果此 PR 有 UI 的改动,最好截图说明这个 PR 的改动。 If there are UI changes to this PR, it is best to take a screenshot to illustrate the changes to this PR. eg. Before:  After:  --> #### Special notes for your reviewer: + 进入[测试页面](https://formkit.com/playground?fkv=1.0.0-beta.12&fileTab=Playground.vue&files=JTVCJTdCJTIybmFtZSUyMiUzQSUyMlBsYXlncm91bmQudnVlJTIyJTJDJTIyZWRpdG9yJTIyJTNBJTIyJTNDc2NyaXB0JTIwc2V0dXAlM0UlNUNuaW1wb3J0JTIwJTdCcmVmJTdEJTIwZnJvbSUyMCd2dWUnJTNCJTVDbmNvbnN0JTIwdHlwZUxpc3QlMjAlM0QlMjByZWYoJTVCJ2F1dG9jb21wbGV0ZSclMkMlMjAnYnV0dG9uJyUyQyUyMCdjaGVja2JveCclMkMlMjAnY29sb3InJTJDJTIwJ2RhdGUnJTJDJTIwJ2RhdGV0aW1lLWxvY2FsJyUyQyUyMCdkcm9wZG93biclMkMlMjAnZW1haWwnJTJDJTIwJ2ZpbGUnJTJDJTIwJTIwJ2xpc3QnJTJDJTIwJ21vbnRoJyUyQyUyMCdudW1iZXInJTJDJTIwJ3Bhc3N3b3JkJyUyQyUyMCdyYWRpbyclMkMlMjAncmFuZ2UnJTJDJTIwJ3JhdGluZyclMkMlMjAncmVwZWF0ZXInJTJDJTIwJ3NlYXJjaCclMkMlMjAnc2VsZWN0JyUyQyUyMCdzdWJtaXQnJTJDJTIwJ3RhZ2xpc3QnJTJDJTIwJ3RleHQnJTJDJTIwJ3RleHRhcmVhJyUyQyUyMCd0aW1lJyUyQyUyMCd0b2dnbGUnJTJDJTIwJ3VybCclMkMlMjAnd2VlayclNUQpJTNCJTVDbmNvbnN0JTIwaW1wbGljaVN1Ym1pc3Npb25UeXBlJTNEJTIwcmVmKCU1Qid0ZXh0JyUyQyUyMCdzZWFyY2gnJTJDJTIwJ3VybCclMkMlMjAlMjAnZW1haWwnJTJDJTIwJ3Bhc3N3b3JkJyUyQyUyMCdkYXRlJyUyQyUyMCdtb250aCclMkMlMjAnd2VlayclMkMlMjAndGltZSclMkMlMjAnZGF0ZXRpbWUtbG9jYWwnJTIwJTJDJTIwJ251bWJlciclNUQpJTVDbiUzQyUyRnNjcmlwdCUzRSU1Q24lNUNuJTNDdGVtcGxhdGUlM0UlNUNuJTIwJTNDaDIlM0VJbXBsaWNpdCUyMHN1Ym1pc3Npb24lMjB0ZXN0JTNDJTJGaDIlM0UlNUNuJTIwJTIwJTIwJTNDZGl2JTIwdi1mb3IlM0QlNUMlMjJ0eXBlJTIwaW4lMjBpbXBsaWNpU3VibWlzc2lvblR5cGUlNUMlMjIlMjAlM0FrZXklM0QlNUMlMjJ0eXBlJTVDJTIyJTIwc3R5bGUlM0QlNUMlMjJwYWRkaW5nJTNBJTIwMjBweCUyMDBweCU1QyUyMiUzRSU1Q24lMjAlMjAlMjAlMjAlM0NGb3JtS2l0JTVDbiUyMCUyMCUyMCUyMHR5cGUlM0QlNUMlMjJmb3JtJTVDJTIyJTVDbiUyMCUyMCUyMCUyMCUzQWxhYmVsJTNEJTVDJTIyJ0Zvcm1LaXQnJTIwJTJCJTIwdHlwZSU1QyUyMiU1Q24lMjAlMjAlMjAlMjBoZWxwJTNEJTVDJTIyZWRpdCUyMG1lJTIwdG8lMjBnZXQlMjBzdGFydGVkJTVDJTIyJTVDbiUyMCUyMCUyMCUyMCU0MGtleWRvd24lM0QlNUMlMjJmbiU1QyUyMiU1Q24lMjAlMjAlMjAlMjAlM0FpZCUzRCU1QyUyMnR5cGUlNUMlMjIlNUNuJTIwJTIwJTNFJTVDbiUyMCUyMCUzQ3AlMjBzdHlsZSUzRCU1QyUyMmJvcmRlci10b3AlM0ElMjA1cHglMjBzb2xpZCUzQiU1QyUyMiUzRXRlc3QlMjBmb3JtJTYwcyUyMGFjdGlvbiUyMHdoZW4lMjB0b3VjaCUyMCdlbnRlciclMjBrZXkuJTIwY2hpbGQlNjBzdHlwZSUyMCUzQSUyMCU3QiU3QnR5cGUlN0QlN0QlMjAlM0MlMkZwJTNFJTVDbiUyMCUyMCUzQ0Zvcm1LaXQlNUNuJTIwJTIwJTIwJTIwJTNBdHlwZSUzRCU1QyUyMnR5cGUlNUMlMjIlNUNuJTIwJTIwJTIwJTIwJTNBbGFiZWwlM0QlNUMlMjInbXklMjB0eXBlJTIwaXMlMjAnJTJCJTIwdHlwZSU1QyUyMiU1Q24lMjAlMjAlMjAlMjBoZWxwJTNEJTVDJTIydG91Y2glMjBlbnRlciUyMGtleSU1QyUyMiU1Q24lMjAlMjAlMjAlMjAlM0F2YWx1ZSUzRCU1QyUyMnR5cGUlNUMlMjIlNUNuJTIwJTIwJTJGJTNFJTVDbiUyMCUyMCUzQyUyRkZvcm1LaXQlM0UlNUNuJTIwJTIwJTNDJTJGZGl2JTNFJTVDbiUyMCUzQ2gyJTNFLi4uJTIwZnJvbSUyMHRlc3QlMjAlM0MlMkZoMiUzRSU1Q24lMjAlMjAlM0NkaXYlMjB2LWZvciUzRCU1QyUyMnR5cGUlMjBpbiUyMHR5cGVMaXN0JTVDJTIyJTIwJTNBa2V5JTNEJTVDJTIydHlwZSU1QyUyMiUyMHN0eWxlJTNEJTVDJTIycGFkZGluZyUzQSUyMDIwcHglMjAwcHglNUMlMjIlMjAlM0UlNUNuJTIwJTIwJTIwJTIwJTNDRm9ybUtpdCU1Q24lMjAlMjAlMjAlMjB2LWlmJTNEJTVDJTIyIWltcGxpY2lTdWJtaXNzaW9uVHlwZS5pbmNsdWRlcyh0eXBlKSU1QyUyMiU1Q24lMjAlMjAlMjAlMjB0eXBlJTNEJTVDJTIyZm9ybSU1QyUyMiU1Q24lMjAlMjAlMjAlMjAlM0FsYWJlbCUzRCU1QyUyMidGb3JtS2l0JyUyMCUyQiUyMHR5cGUlNUMlMjIlNUNuJTIwJTIwJTIwJTIwaGVscCUzRCU1QyUyMmVkaXQlMjBtZSUyMHRvJTIwZ2V0JTIwc3RhcnRlZCU1QyUyMiU1Q24lMjAlMjAlMjAlMjAlNDBrZXlkb3duJTNEJTVDJTIyZm4lNUMlMjIlNUNuJTIwJTIwJTIwJTIwJTNBaWQlM0QlNUMlMjJ0eXBlJTVDJTIyJTVDbiUyMCUyMCUzRSU1Q24lMjAlMjAlM0NwJTIwc3R5bGUlM0QlNUMlMjJib3JkZXItdG9wJTNBJTIwNXB4JTIwc29saWQlM0IlNUMlMjIlM0V0ZXN0JTIwZm9ybSU2MHMlMjBhY3Rpb24lMjB3aGVuJTIwdG91Y2glMjAnZW50ZXInJTIwa2V5LiUyMGNoaWxkJTYwc3R5cGUlMjAlM0ElMjAlN0IlN0J0eXBlJTdEJTdEJTIwJTNDJTJGcCUzRSU1Q24lMjAlMjAlM0NGb3JtS2l0JTVDbiUyMCUyMCUyMCUyMCUzQXR5cGUlM0QlNUMlMjJ0eXBlJTVDJTIyJTVDbiUyMCUyMCUyMCUyMCUzQWxhYmVsJTNEJTVDJTIyJ215JTIwdHlwZSUyMGlzJTIwJyUyQiUyMHR5cGUlNUMlMjIlNUNuJTIwJTIwJTIwJTIwaGVscCUzRCU1QyUyMnRvdWNoJTIwZW50ZXIlMjBrZXklNUMlMjIlNUNuJTIwJTIwJTIwJTIwJTNBdmFsdWUlM0QlNUMlMjJ0eXBlJTVDJTIyJTVDbiUyMCUyMCUyRiUzRSU1Q24lMjAlMjAlM0MlMkZGb3JtS2l0JTNFJTVDbiUyMCUyMCUzQyUyRmRpdiUzRSU1Q24lNUNuJTNDJTJGdGVtcGxhdGUlM0UlNUNuJTVDbiUzQ3N0eWxlJTIwc2NvcGVkJTNFJTVDbiUyRiolNUNudmFuaWxsYSUyMENTUyUyMGNhbiUyMGdvJTIwaGVyZS4lNUNuS2VlcCUyMHN0eWxlcyUyMHNjb3BlZCUyMHRvJTIwYXZvaWQlMjBtdWx0aXBsZSUyMGZpbGVzJTVDbm92ZXJ3cml0aW5nJTIwZWFjaCUyMG90aGVyJTIwaW4lMjB0aGUlMjByZW5kZXIlMjBvdXRwdXQuJTVDbiolMkYlNUNuJTNDJTJGc3R5bGUlM0UlNUNuJTIyJTJDJTIyYWRkZWQlMjIlM0F0cnVlJTdEJTJDJTdCJTIybmFtZSUyMiUzQSUyMmZvcm1raXQuY29uZmlnLmpzJTIyJTJDJTIyZWRpdG9yJTIyJTNBJTIyJTJGKiUyMEluJTIwdGhpcyUyMGZpbGUlMkMlMjBleHBvcnQlMjB5b3VyJTIwZmluYWwlMjBjb25maWcuJTVDbkl0JTIwd2lsbCUyMGF1dG9tYXRpY2FsbHklMjBiZSUyMGluamVjdGVkJTIwaW50byUyMHRoZSUyMHBsYXlncm91bmQlMjBmb3IlMjB5b3UuJTVDbkltcG9ydHMlMjBmcm9tJTIwb3RoZXIlMjBwbGF5Z3JvdW5kJTIwZmlsZXMlMjBhcmUlMjBzdXBwb3J0ZWQuJTIwKiUyRiU1Q25pbXBvcnQlMjAlN0IlMjBvbk1vdW50ZWQlMjAlN0QlMjBmcm9tJTIwJTVDJTIydnVlJTVDJTIyJTNCJTVDbmNvbnN0JTIwaW1wbGljaVN1Ym1pc3Npb25UeXBlJTIwJTNEJTIwJTVCJTVDbiUyMCUyMCU1QyUyMnRleHQlNUMlMjIlMkMlNUNuJTIwJTIwJTVDJTIyc2VhcmNoJTVDJTIyJTJDJTVDbiUyMCUyMCU1QyUyMnVybCU1QyUyMiUyQyU1Q24lMjAlMjAlNUMlMjJlbWFpbCU1QyUyMiUyQyU1Q24lMjAlMjAlNUMlMjJwYXNzd29yZCU1QyUyMiUyQyU1Q24lMjAlMjAlNUMlMjJudW1iZXIlNUMlMjIlMkMlNUNuJTVEJTNCJTVDbmZ1bmN0aW9uJTIwaGFuZGxlS2V5ZG93bihlKSUyMCU3QiU1Q24lMjAlMjBpZiUyMCglNUNuJTIwJTIwJTIwJTIwZS5rZXklMjAlM0QlM0QlMjAlNUMlMjJFbnRlciU1QyUyMiUyMCUyNiUyNiU1Q24lMjAlMjAlMjAlMjBlLmFsdEtleSUyMCUzRCUzRCUyMGZhbHNlJTIwJTI2JTI2JTVDbiUyMCUyMCUyMCUyMGUuY3RybEtleSUyMCUzRCUzRCUyMGZhbHNlJTIwJTI2JTI2JTVDbiUyMCUyMCUyMCUyMGUubWV0YUtleSUyMCUzRCUzRCUyMGZhbHNlJTVDbiUyMCUyMCklMjAlN0IlNUNuJTJGJTJGJTIwb3BlbiUyMHdpbGwlMjBzdG9wJTIwc3VibWl0JTVDbiUyRiUyRiUyMCUyMGUuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCklM0IlNUNuJTJGJTJGJTIwJTIwZS5wcmV2ZW50RGVmYXVsdCgpJTNCJTVDbiUyRiUyRiUyMCUyMGUuc3RvcFByb3BhZ2F0aW9uKCklM0IlNUNuJTIwJTIwJTdEJTVDbiU3RCU1Q24lNUNuY29uc3QlMjBpbnB1dFByZXZlbnRGbiUyMCUzRCUyMChub2RlKSUyMCUzRCUzRSUyMCU3QiU1Q24lMjAlMjBpZiUyMChub2RlLnR5cGUlMjAlM0QlM0QlMjAlNUMlMjJncm91cCU1QyUyMiklMjAlN0IlNUNuJTIwJTIwJTIwJTIwb25Nb3VudGVkKCgpJTIwJTNEJTNFJTIwJTdCJTVDbiUyMCUyMCUyMCUyMCUyMCUyMGlmJTIwKG5vZGUuY2hpbGRyZW4ubGVuZ3RoJTIwJTNEJTNEJTIwMSUyMCUyNiUyNiUyMG5vZGUucHJvcHMudHlwZSUyMCUzRCUzRCUyMCU1QyUyMmZvcm0lNUMlMjIlMjAlMjYlMjYlMjBpbXBsaWNpU3VibWlzc2lvblR5cGUuaW5jbHVkZXMobm9kZS5jaGlsZHJlbiU1QjAlNUQucHJvcHMudHlwZSkpJTIwJTdCJTVDbiUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMGNvbnN0JTIwaWQlMjAlM0QlMjBub2RlLnByb3BzLmlkJTIwJTNGJTNGJTIwJTVDJTIyJTVDJTIyJTNCJTVDbiUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMGNvbnN0JTIwcm9vdEZvcm0lMjAlM0QlMjBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChpZCklM0IlNUNuJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwcm9vdEZvcm0lM0YuYWRkRXZlbnRMaXN0ZW5lciglNUMlMjJrZXlkb3duJTVDJTIyJTJDJTIwaGFuZGxlS2V5ZG93biklM0IlNUNuJTIwJTIwJTIwJTIwJTIwJTIwJTdEJTVDbiUyMCUyMCUyMCUyMCU3RCklM0IlNUNuJTIwJTIwJTdEJTVDbiU3RCUzQiU1Q24lNUNuJTVDbmV4cG9ydCUyMGRlZmF1bHQlMjAlN0IlNUNuJTIwJTIwcGx1Z2lucyUzQSUyMCU1QmlucHV0UHJldmVudEZuJTIwJTVEJTVDbiU3RCU1Q24lMjIlMkMlMjJyZW1vdmFibGUlMjIlM0F0cnVlJTJDJTIyYWRkZWQlMjIlM0F0cnVlJTdEJTVE&imports=JTdCJTIybmFtZSUyMiUzQSUyMkltcG9ydE1hcCUyMiUyQyUyMmVkaXRvciUyMiUzQSUyMiU3QiU1Q24lMjAlMjAlNUMlMjJ2dWUlNUMlMjIlM0ElMjAlNUMlMjJodHRwcyUzQSUyRiUyRmNkbi5qc2RlbGl2ci5uZXQlMkZucG0lMkZ2dWUlNDAzJTJGZGlzdCUyRnZ1ZS5lc20tYnJvd3Nlci5taW4uanMlNUMlMjIlNUNuJTdEJTVDbiUyMiU3RA) + 点击表单元素,表单元素聚焦之后,之后键入`enter`观察是否触发`submit` + 打开`formkit.config.js`tab, 放开注释,阻止事件行为。重复第二点。观察`submit`事件。 #### Does this PR introduce a user-facing change? <!-- 如果当前 Pull Request 的修改不会造成用户侧的任何变更,在 `release-note` 代码块儿中填写 `NONE`。 否则请填写用户侧能够理解的 Release Note。如果当前 Pull Request 包含破坏性更新(Break Change), Release Note 需要以 `action required` 开头。 If no, just write "NONE" in the release-note block below. If yes, a release note is required: Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required". --> ```release-note 禁止使用 Enter 提交,需要使用组合键(Ctrl + Enter) ```pull/3445/head
parent
97d2066d42
commit
be251c08cc
|
@ -17,12 +17,13 @@ import { categoryCheckbox } from "./inputs/category-checkbox";
|
|||
import { tagCheckbox } from "./inputs/tag-checkbox";
|
||||
|
||||
import radioAlt from "./plugins/radio-alt";
|
||||
import stopImplicitSubmission from "./plugins/stop-implicit-submission";
|
||||
|
||||
const config: DefaultConfigOptions = {
|
||||
config: {
|
||||
classes: generateClasses(theme),
|
||||
},
|
||||
plugins: [radioAlt],
|
||||
plugins: [radioAlt, stopImplicitSubmission],
|
||||
inputs: {
|
||||
form,
|
||||
attachment,
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
import router from "@/router";
|
||||
import type { FormKitNode } from "@formkit/core";
|
||||
import { onMounted } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
function handleKeydown(e: KeyboardEvent) {
|
||||
if (
|
||||
e.key == "Enter" &&
|
||||
e.altKey == false &&
|
||||
e.ctrlKey == false &&
|
||||
e.metaKey == false
|
||||
) {
|
||||
e.stopImmediatePropagation();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
// 以下表单键入enter引起表单提交,
|
||||
//https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#implicit-submission
|
||||
const implicitSubmissionType = [
|
||||
"text",
|
||||
"search",
|
||||
"url",
|
||||
"email",
|
||||
"password",
|
||||
"date",
|
||||
"month",
|
||||
"week",
|
||||
"time",
|
||||
"datetime-local",
|
||||
"number",
|
||||
];
|
||||
|
||||
const FormKeydownEventControllerMap = new Map<string, AbortController>();
|
||||
|
||||
const clearFormKeydownEventByPath = (fullPath: string) => {
|
||||
if (FormKeydownEventControllerMap.size) {
|
||||
FormKeydownEventControllerMap.forEach((controller, path) => {
|
||||
if (!fullPath.includes(path)) {
|
||||
controller.abort();
|
||||
FormKeydownEventControllerMap.delete(path);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
//https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/addEventListener#%E5%8F%82%E6%95%B0
|
||||
//使用AbortSignal来取消事件监听
|
||||
const inputPreventFn = (node: FormKitNode) => {
|
||||
const id = node.props.id ?? "";
|
||||
if (node.type == "group") {
|
||||
onMounted(() => {
|
||||
const { path } = useRoute();
|
||||
let controller = FormKeydownEventControllerMap.get(path);
|
||||
if (
|
||||
node.children.length == 1 &&
|
||||
node.props.type == "form" &&
|
||||
implicitSubmissionType.includes(node.children[0].props.type)
|
||||
) {
|
||||
if (!controller) {
|
||||
controller = new AbortController();
|
||||
FormKeydownEventControllerMap.set(path, controller);
|
||||
}
|
||||
const rootForm = document.getElementById(id);
|
||||
rootForm?.addEventListener("keydown", handleKeydown, {
|
||||
signal: controller.signal,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 进入下一个页面,清除上一个页面的事件。
|
||||
// 可以做个测试后面。https://segmentfault.com/q/1010000042671015
|
||||
// map里面的key是path,这里传fullPath,当有多级路由的时候避免清掉上一级的事件。
|
||||
router.beforeEach(({ fullPath }) => {
|
||||
clearFormKeydownEventByPath(fullPath);
|
||||
});
|
||||
|
||||
export default inputPreventFn;
|
Loading…
Reference in New Issue