浏览代码

Add system-modifier key-combo listeners

Caleb Porzio 5 年之前
父节点
当前提交
5ae7b85cf4
共有 6 个文件被更改,包括 47 次插入5 次删除
  1. 3 1
      README.md
  2. 0 0
      dist/alpine.js
  3. 0 0
      dist/alpine.js.map
  4. 1 1
      package.json
  5. 21 3
      src/component.js
  6. 22 0
      test/on.spec.js

+ 3 - 1
README.md

@@ -14,7 +14,7 @@ Think of it like [Tailwind](https://tailwindcss.com/) for JavaScript.
 
 
 **From CDN:** Add the following script to the end of your `<head>` section.
 **From CDN:** Add the following script to the end of your `<head>` section.
 ```html
 ```html
-<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v1.8.1/dist/alpine.js" defer></script>
+<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v1.8.2/dist/alpine.js" defer></script>
 ```
 ```
 
 
 That's it. It will initialize itself.
 That's it. It will initialize itself.
@@ -234,6 +234,8 @@ You can specify specific keys to listen for using keydown modifiers appended to
 
 
 Examples: `enter`, `escape`, `arrow-up`, `arrow-down`
 Examples: `enter`, `escape`, `arrow-up`, `arrow-down`
 
 
+> Note: You can also listen for system-modifier key combinations like: `x-on:keydown.cmd.enter="foo"`
+
 **`.away` modifier**
 **`.away` modifier**
 
 
 **Example:** `<div x-on:click.away="showModal = false"></div>`
 **Example:** `<div x-on:click.away="showModal = false"></div>`

文件差异内容过多而无法显示
+ 0 - 0
dist/alpine.js


文件差异内容过多而无法显示
+ 0 - 0
dist/alpine.js.map


+ 1 - 1
package.json

@@ -1,7 +1,7 @@
 {
 {
   "main": "dist/alpine.js",
   "main": "dist/alpine.js",
   "name": "alpinejs",
   "name": "alpinejs",
-  "version": "1.8.1",
+  "version": "1.8.2",
   "repository": {
   "repository": {
     "type": "git",
     "type": "git",
     "url": "git://github.com/alpinejs/alpine.git"
     "url": "git://github.com/alpinejs/alpine.git"

+ 21 - 3
src/component.js

@@ -294,10 +294,28 @@ export default class Component {
                 ? window : (modifiers.includes('document') ? document : el)
                 ? window : (modifiers.includes('document') ? document : el)
 
 
             const handler = e => {
             const handler = e => {
-                const modifiersWithoutWindowOrDocument = modifiers
-                    .filter(i => i !== 'window').filter(i => i !== 'document')
+                const keyModifiers = modifiers.filter(i => i !== 'window').filter(i => i !== 'document')
 
 
-                if (event === 'keydown' && modifiersWithoutWindowOrDocument.length > 0 && ! modifiersWithoutWindowOrDocument.includes(keyToModifier(e.key))) return
+                // The user is scoping the keydown listener to a specific key using modifiers.
+                if (event === 'keydown' && keyModifiers.length > 0) {
+                    // The user is listening for a specific key.
+                    if (keyModifiers.length === 1 && ! keyModifiers.includes(keyToModifier(e.key))) return
+
+                    // The user is listening for key combinations.
+                    const systemKeyModifiers = ['ctrl', 'shift', 'alt', 'meta', 'cmd', 'super']
+                    const selectedSystemKeyModifiers = systemKeyModifiers.filter(modifier => keyModifiers.includes(modifier))
+
+                    if (selectedSystemKeyModifiers.length > 0) {
+                        const activelyPressedKeyModifiers = selectedSystemKeyModifiers.filter(modifier => {
+                            // Alias "cmd" and "super" to "meta"
+                            if (modifier === 'cmd' || modifier === 'super') modifier = 'meta'
+
+                            return e[`${modifier}Key`]
+                        })
+
+                        if (activelyPressedKeyModifiers.length === 0) return
+                    }
+                }
 
 
                 if (modifiers.includes('prevent')) e.preventDefault()
                 if (modifiers.includes('prevent')) e.preventDefault()
                 if (modifiers.includes('stop')) e.stopPropagation()
                 if (modifiers.includes('stop')) e.stopPropagation()

+ 22 - 0
test/on.spec.js

@@ -169,6 +169,28 @@ test('keydown modifiers', async () => {
     await wait(() => { expect(document.querySelector('span').innerText).toEqual(7) })
     await wait(() => { expect(document.querySelector('span').innerText).toEqual(7) })
 })
 })
 
 
+test('keydown combo modifiers', async () => {
+    document.body.innerHTML = `
+        <div x-data="{ count: 0 }">
+            <input type="text" x-on:keydown.cmd.enter="count++">
+
+            <span x-text="count"></span>
+        </div>
+    `
+
+    Alpine.start()
+
+    expect(document.querySelector('span').innerText).toEqual(0)
+
+    fireEvent.keyDown(document.querySelector('input'), { key: 'Enter' })
+
+    await wait(() => { expect(document.querySelector('span').innerText).toEqual(0) })
+
+    fireEvent.keyDown(document.querySelector('input'), { key: 'Enter', metaKey: true })
+
+    await wait(() => { expect(document.querySelector('span').innerText).toEqual(1) })
+})
+
 test('click away', async () => {
 test('click away', async () => {
     // Because jsDom doesn't support .offsetHeight and offsetWidth, we have to
     // Because jsDom doesn't support .offsetHeight and offsetWidth, we have to
     // make our own implementation using a specific class added to the class. Ugh.
     // make our own implementation using a specific class added to the class. Ugh.

部分文件因为文件数量过多而无法显示