Forráskód Böngészése

Merge pull request #379 from ryangjchandler/feature/event-self-modifier

Added new `.self` modifier for event listeners
Caleb Porzio 5 éve
szülő
commit
9a0f2de6b4
5 módosított fájl, 68 hozzáadás és 21 törlés
  1. 5 0
      README.md
  2. 12 7
      dist/alpine-ie11.js
  3. 12 7
      dist/alpine.js
  4. 12 7
      src/directives/on.js
  5. 27 0
      test/on.spec.js

+ 5 - 0
README.md

@@ -296,6 +296,11 @@ Adding `.prevent` to an event listener will call `preventDefault` on the trigger
 
 Adding `.stop` to an event listener will call `stopPropagation` on the triggered event. In the above example, this means the "click" event won't bubble from the button to the outer `<div>`. Or in other words, when a user clicks the button, `foo` won't be set to `'bar'`.
 
+**`.self` modifier**
+**Example:** `<div x-on:click.self="foo = 'bar'"><button></button></div>`
+
+Adding `.self` to an event listener will only trigger the handler if the `$event.target` is the element itself. In the above example, this means the "click" event that bubbles from the button to the outer `<div>` will **not** run the handler.
+
 **`.window` modifier**
 **Example:** `<div x-on:resize.window="isOpen = window.outerWidth > 768 ? false : open"></div>`
 

+ 12 - 7
dist/alpine-ie11.js

@@ -6243,14 +6243,19 @@
         }
 
         if (modifiers.includes('prevent')) e.preventDefault();
-        if (modifiers.includes('stop')) e.stopPropagation();
-        var returnValue = runListenerHandler(component, expression, e, extraVars);
+        if (modifiers.includes('stop')) e.stopPropagation(); // If the .self modifier isn't present, or if it is present and
+        // the target element matches the element we are registering the
+        // event on, run the handler
 
-        if (returnValue === false) {
-          e.preventDefault();
-        } else {
-          if (modifiers.includes('once')) {
-            listenerTarget.removeEventListener(event, _handler2);
+        if (!modifiers.includes('self') || e.target === el) {
+          var returnValue = runListenerHandler(component, expression, e, extraVars);
+
+          if (returnValue === false) {
+            e.preventDefault();
+          } else {
+            if (modifiers.includes('once')) {
+              listenerTarget.removeEventListener(event, _handler2);
+            }
           }
         }
       }.bind(this);

+ 12 - 7
dist/alpine.js

@@ -741,14 +741,19 @@
         }
 
         if (modifiers.includes('prevent')) e.preventDefault();
-        if (modifiers.includes('stop')) e.stopPropagation();
-        const returnValue = runListenerHandler(component, expression, e, extraVars);
+        if (modifiers.includes('stop')) e.stopPropagation(); // If the .self modifier isn't present, or if it is present and
+        // the target element matches the element we are registering the
+        // event on, run the handler
 
-        if (returnValue === false) {
-          e.preventDefault();
-        } else {
-          if (modifiers.includes('once')) {
-            listenerTarget.removeEventListener(event, handler);
+        if (!modifiers.includes('self') || e.target === el) {
+          const returnValue = runListenerHandler(component, expression, e, extraVars);
+
+          if (returnValue === false) {
+            e.preventDefault();
+          } else {
+            if (modifiers.includes('once')) {
+              listenerTarget.removeEventListener(event, handler);
+            }
           }
         }
       };

+ 12 - 7
src/directives/on.js

@@ -43,13 +43,18 @@ export function registerListener(component, el, event, modifiers, expression, ex
             if (modifiers.includes('prevent')) e.preventDefault()
             if (modifiers.includes('stop')) e.stopPropagation()
 
-            const returnValue = runListenerHandler(component, expression, e, extraVars)
-
-            if (returnValue === false) {
-                e.preventDefault()
-            } else {
-                if (modifiers.includes('once')) {
-                    listenerTarget.removeEventListener(event, handler)
+            // If the .self modifier isn't present, or if it is present and
+            // the target element matches the element we are registering the
+            // event on, run the handler
+            if (! modifiers.includes('self') || e.target === el) {
+                const returnValue = runListenerHandler(component, expression, e, extraVars)
+
+                if (returnValue === false) {
+                    e.preventDefault()
+                } else {
+                    if (modifiers.includes('once')) {
+                        listenerTarget.removeEventListener(event, handler)
+                    }
                 }
             }
         }

+ 27 - 0
test/on.spec.js

@@ -63,6 +63,33 @@ test('.stop modifier', async () => {
     })
 })
 
+test('.self modifier', async () => {
+    document.body.innerHTML = `
+        <div x-data="{ foo: 'bar' }">
+            <div x-on:click.self="foo = 'baz'" id="selfTarget">
+                <button></button>
+            </div>
+            <span x-text="foo"></span>
+        </div>
+    `
+
+    Alpine.start()
+
+    expect(document.querySelector('span').innerText).toEqual('bar')
+
+    document.querySelector('button').click()
+
+    await wait(() => {
+        expect(document.querySelector('span').innerText).toEqual('bar')
+    })
+
+    document.querySelector('#selfTarget').click()
+
+    await wait(() => {
+        expect(document.querySelector('span').innerText).toEqual('baz')
+    })
+})
+
 test('.prevent modifier', async () => {
     document.body.innerHTML = `
         <div x-data="{}">