Browse Source

Merge branch 'master' into master-ie11

Keyur Shah 5 năm trước cách đây
mục cha
commit
925ebcdf30
10 tập tin đã thay đổi với 93 bổ sung33 xóa
  1. 1 1
      README.md
  2. 0 0
      dist/alpine-ie11.js
  3. 0 0
      dist/alpine-ie11.js.map
  4. 0 0
      dist/alpine.js
  5. 0 0
      dist/alpine.js.map
  6. 1 1
      package.json
  7. 8 26
      src/component.js
  8. 8 4
      src/directives/on.js
  9. 23 0
      src/utils.js
  10. 52 1
      test/on.spec.js

+ 1 - 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.
 ```html
-<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v1.9.8/dist/alpine.js" defer></script>
+<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v1.10.1/dist/alpine.js" defer></script>
 ```
 
 That's it. It will initialize itself.

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/alpine-ie11.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/alpine-ie11.js.map


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/alpine.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/alpine.js.map


+ 1 - 1
package.json

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

+ 8 - 26
src/component.js

@@ -1,4 +1,4 @@
-import { walk, saferEval, saferEvalNoReturn, getXAttrs, debounce } from './utils'
+import { walk, saferEval, saferEvalNoReturn, getXAttrs, debounce, deepProxy } from './utils'
 import { handleForDirective } from './directives/for'
 import { handleAttributeBindingDirective } from './directives/bind'
 import { handleShowDirective } from './directives/show'
@@ -81,11 +81,9 @@ export default class Component {
 
         const proxyHandler = {
             set(obj, property, value) {
-                // If value is an Alpine proxy (i.e. an element returned when sorting a list of objects),
-                // we want to set the original element to avoid a matryoshka effect (nested proxies).
-                const setWasSuccessful = value['$isAlpineProxy']
-                    ? Reflect.set(obj, property, value['$originalTarget'])
-                    : Reflect.set(obj, property, value)
+                // Set the value converting it to a "Deep Proxy" when required
+                // Note that if a project is not a valid object, it won't be converted to a proxy
+                const setWasSuccessful = Reflect.set(obj, property, deepProxy(value, proxyHandler))
 
                 // Don't react to data changes for cases like the `x-created` hook.
                 if (self.pauseReactivity) return setWasSuccessful
@@ -105,28 +103,12 @@ export default class Component {
                 // Provide a way to determine if this object is an Alpine proxy or not.
                 if (key === "$isAlpineProxy") return true
 
-                // Provide a hook to access the underlying "proxied" data directly.
-                if (key === "$originalTarget") return target
-
-                // If the property we are trying to get is a proxy, just return it.
-                // Like in the case of $refs
-                if (target[key] && target[key].$isRefsProxy) return target[key]
-
-                // If property is a DOM node, just return it. (like in the case of this.$el)
-                if (target[key] && target[key] instanceof Node) return target[key]
-
-                // If accessing a nested property, return this proxy recursively.
-                // This enables reactivity on setting nested data.
-                if (typeof target[key] === 'object' && target[key] !== null) {
-                    return new Proxy(target[key], proxyHandler)
-                }
-
-                // If none of the above, just return the flippin' value. Gawsh.
+                // Just return the flippin' value. Gawsh.
                 return target[key]
             }
         }
 
-        return new Proxy(data, proxyHandler)
+        return deepProxy(data, proxyHandler)
     }
 
     walkAndSkipNestedComponents(el, callback, initializeComponentCallback = () => {}) {
@@ -268,7 +250,7 @@ export default class Component {
     }
 
     evaluateCommandExpression(el, expression, extraVars = () => {}) {
-        saferEvalNoReturn(expression, this.$data, {
+        return saferEvalNoReturn(expression, this.$data, {
             ...extraVars(),
             $dispatch: this.getDispatchFunction(el),
         })
@@ -353,7 +335,7 @@ export default class Component {
         // For this reason, I'm using an "on-demand" proxy to fake a "$refs" object.
         return new Proxy(refObj, {
             get(object, property) {
-                if (property === '$isRefsProxy') return true
+                if (property === '$isAlpineProxy') return true
 
                 var ref
 

+ 8 - 4
src/directives/on.js

@@ -34,10 +34,14 @@ export function registerListener(component, el, event, modifiers, expression, ex
             if (modifiers.includes('prevent')) e.preventDefault()
             if (modifiers.includes('stop')) e.stopPropagation()
 
-            runListenerHandler(component, expression, e, extraVars)
+            const returnValue = runListenerHandler(component, expression, e, extraVars)
 
-            if (modifiers.includes('once')) {
-                listenerTarget.removeEventListener(event, handler)
+            if (returnValue === false) {
+                e.preventDefault()
+            } else {
+                if (modifiers.includes('once')) {
+                    listenerTarget.removeEventListener(event, handler)
+                }
             }
         }
 
@@ -46,7 +50,7 @@ export function registerListener(component, el, event, modifiers, expression, ex
 }
 
 function runListenerHandler(component, expression, e, extraVars) {
-    component.evaluateCommandExpression(e.target, expression, () => {
+    return component.evaluateCommandExpression(e.target, expression, () => {
         return {...extraVars(), '$event': e}
     })
 }

+ 23 - 0
src/utils.js

@@ -168,3 +168,26 @@ export function transition(el, classesDuring, classesStart, classesEnd, hook1, h
         })
     });
 }
+
+export function deepProxy(target, proxyHandler) {
+    // If target is null, return it.
+    if (target === null) return target;
+
+    // If target is not an object, return it.
+    if (typeof target !== 'object') return target;
+
+    // If target is a DOM node (like in the case of this.$el), return it.
+    if (target instanceof Node) return target
+
+    // If target is already an Alpine proxy, return it.
+    if (target['$isAlpineProxy']) return target;
+
+    // Otherwise proxy the properties recursively.
+    // This enables reactivity on setting nested data.
+    // Note that if a project is not a valid object, it won't be converted to a proxy
+    for (let property in target) {
+        target[property] = deepProxy(target[property], proxyHandler)
+    }
+
+    return new Proxy(target, proxyHandler)
+}

+ 52 - 1
test/on.spec.js

@@ -120,7 +120,7 @@ test('.once modifier', async () => {
         <div x-data="{ count: 0 }">
             <button x-on:click.once="count = count+1"></button>
 
-            <span x-bind:foo="count"
+            <span x-bind:foo="count"></span>
         </div>
     `
 
@@ -139,6 +139,32 @@ test('.once modifier', async () => {
     expect(document.querySelector('span').getAttribute('foo')).toEqual('1')
 })
 
+test('.once modifier doest remove listener if false is returned', async () => {
+    document.body.innerHTML = `
+        <div x-data="{ count: 0 }">
+            <button x-on:click.once="return ++count === 2"></button>
+
+            <span x-bind:foo="count"></span>
+        </div>
+    `
+
+    Alpine.start()
+
+    expect(document.querySelector('span').getAttribute('foo')).toEqual('0')
+
+    document.querySelector('button').click()
+
+    await wait(() => { expect(document.querySelector('span').getAttribute('foo')).toEqual('1') })
+
+    document.querySelector('button').click()
+
+    await wait(() => { expect(document.querySelector('span').getAttribute('foo')).toEqual('2') })
+
+    await timeout(25)
+
+    expect(document.querySelector('span').getAttribute('foo')).toEqual('2')
+})
+
 test('keydown modifiers', async () => {
     document.body.innerHTML = `
         <div x-data="{ count: 0 }">
@@ -299,3 +325,28 @@ test('event with colon', async () => {
 
     await wait(() => { expect(document.querySelector('span').getAttribute('foo')).toEqual('baz') })
 })
+
+
+test('prevent default action when an event returns false', async () => {
+    window.confirm = jest.fn().mockImplementation(() => false)
+
+    document.body.innerHTML = `
+        <div x-data="{}">
+            <input type="checkbox" x-on:click="return confirm('are you sure?')">
+        </div>
+    `
+
+    Alpine.start()
+
+    expect(document.querySelector('input').checked).toEqual(false)
+
+    document.querySelector('input').click()
+
+    expect(document.querySelector('input').checked).toEqual(false)
+
+    window.confirm = jest.fn().mockImplementation(() => true)
+
+    document.querySelector('input').click()
+
+    expect(document.querySelector('input').checked).toEqual(true)
+})

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác