浏览代码

Rename project from "Project-X" to "Alpine"

Caleb Porzio 5 年之前
父节点
当前提交
c7c1209d3b

+ 5 - 5
README.md

@@ -1,17 +1,17 @@
-# Project X
+# Alpine.js
 
 
-Project X offers you the reactive and declarative nature of big frameworks like Vue or React at a much lower cost.
+Alpine.js offers you the reactive and declarative nature of big frameworks like Vue or React at a much lower cost.
 
 
 You get to keep your DOM, and sprinkle in behavior as you see fit.
 You get to keep your DOM, and sprinkle in behavior as you see fit.
 
 
 Think of it like [Tailwind](https://tailwindcss.com/) for JavaScript.
 Think of it like [Tailwind](https://tailwindcss.com/) for JavaScript.
 
 
-> Note: This tool's syntax is almost entirely borrowed from [Vue.js](https://vuejs.org/). I am forever grateful for the gift that it is to the web.
+> Note: This tool's syntax is almost entirely borrowed from [Vue.js](https://vuejs.org/)(and by extension [Angular](https://angularjs.org/)). I am forever grateful for the gift they are to the web.
 
 
 ## Install
 ## Install
 Add the following script to the end of your `<head>` section.
 Add the following script to the end of your `<head>` section.
 ```html
 ```html
-<script src="https://cdn.jsdelivr.net/gh/calebporzio/project-x@v0.4.4/dist/project-x.min.js" defer></script>
+<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v1.0.0/dist/alpine.min.js" defer></script>
 ```
 ```
 
 
 ## Use
 ## Use
@@ -219,7 +219,7 @@ This is a helpful alternative to setting ids and using `document.querySelector`
 ### `x-cloak`
 ### `x-cloak`
 **Example:** `<div x-data="{}" x-cloak></div>`
 **Example:** `<div x-data="{}" x-cloak></div>`
 
 
-`x-cloak` attributes are removed from elements when Project-X initializes. This is useful for hiding pre-initialized DOM. It's typical to add the following global style for this to work:
+`x-cloak` attributes are removed from elements when Alpine initializes. This is useful for hiding pre-initialized DOM. It's typical to add the following global style for this to work:
 
 
 ```html
 ```html
 <style>
 <style>

+ 88 - 53
dist/project-x.js → dist/alpine.js

@@ -876,6 +876,7 @@ function () {
     var rawData = Object(_utils__WEBPACK_IMPORTED_MODULE_0__["saferEval"])(this.el.getAttribute('x-data'), {});
     var rawData = Object(_utils__WEBPACK_IMPORTED_MODULE_0__["saferEval"])(this.el.getAttribute('x-data'), {});
     this.data = this.wrapDataInObservable(rawData);
     this.data = this.wrapDataInObservable(rawData);
     this.initialize();
     this.initialize();
+    this.listenForNewElementsToInitialize();
   }
   }
 
 
   _createClass(Component, [{
   _createClass(Component, [{
@@ -915,73 +916,107 @@ function () {
       var _this = this;
       var _this = this;
 
 
       Object(_utils__WEBPACK_IMPORTED_MODULE_0__["walkSkippingNestedComponents"])(this.el, function (el) {
       Object(_utils__WEBPACK_IMPORTED_MODULE_0__["walkSkippingNestedComponents"])(this.el, function (el) {
-        Object(_utils__WEBPACK_IMPORTED_MODULE_0__["getXAttrs"])(el).forEach(function (_ref) {
-          var type = _ref.type,
-              value = _ref.value,
-              modifiers = _ref.modifiers,
-              expression = _ref.expression;
+        _this.initializeElement(el);
+      });
+    }
+  }, {
+    key: "initializeElement",
+    value: function initializeElement(el) {
+      var _this2 = this;
 
 
-          switch (type) {
-            case 'on':
-              var event = value;
+      Object(_utils__WEBPACK_IMPORTED_MODULE_0__["getXAttrs"])(el).forEach(function (_ref) {
+        var type = _ref.type,
+            value = _ref.value,
+            modifiers = _ref.modifiers,
+            expression = _ref.expression;
 
 
-              _this.registerListener(el, event, modifiers, expression);
+        switch (type) {
+          case 'on':
+            var event = value;
 
 
-              break;
+            _this2.registerListener(el, event, modifiers, expression);
 
 
-            case 'model':
-              // If the element we are binding to is a select, a radio, or checkbox
-              // we'll listen for the change event instead of the "input" event.
-              var event = el.tagName.toLowerCase() === 'select' || ['checkbox', 'radio'].includes(el.type) || modifiers.includes('lazy') ? 'change' : 'input';
+            break;
 
 
-              var listenerExpression = _this.generateExpressionForXModelListener(el, modifiers, expression);
+          case 'model':
+            // If the element we are binding to is a select, a radio, or checkbox
+            // we'll listen for the change event instead of the "input" event.
+            var event = el.tagName.toLowerCase() === 'select' || ['checkbox', 'radio'].includes(el.type) || modifiers.includes('lazy') ? 'change' : 'input';
 
 
-              _this.registerListener(el, event, modifiers, listenerExpression);
+            var listenerExpression = _this2.generateExpressionForXModelListener(el, modifiers, expression);
 
 
-              var attrName = 'value';
+            _this2.registerListener(el, event, modifiers, listenerExpression);
 
 
-              var _this$evaluateReturnE = _this.evaluateReturnExpression(expression),
-                  output = _this$evaluateReturnE.output;
+            var attrName = 'value';
 
 
-              _this.updateAttributeValue(el, attrName, output);
+            var _this2$evaluateReturn = _this2.evaluateReturnExpression(expression),
+                output = _this2$evaluateReturn.output;
 
 
-              break;
+            _this2.updateAttributeValue(el, attrName, output);
 
 
-            case 'bind':
-              var attrName = value;
+            break;
 
 
-              var _this$evaluateReturnE2 = _this.evaluateReturnExpression(expression),
-                  output = _this$evaluateReturnE2.output;
+          case 'bind':
+            var attrName = value;
 
 
-              _this.updateAttributeValue(el, attrName, output);
+            var _this2$evaluateReturn2 = _this2.evaluateReturnExpression(expression),
+                output = _this2$evaluateReturn2.output;
 
 
-              break;
+            _this2.updateAttributeValue(el, attrName, output);
 
 
-            case 'text':
-              var _this$evaluateReturnE3 = _this.evaluateReturnExpression(expression),
-                  output = _this$evaluateReturnE3.output;
+            break;
 
 
-              _this.updateTextValue(el, output);
+          case 'text':
+            var _this2$evaluateReturn3 = _this2.evaluateReturnExpression(expression),
+                output = _this2$evaluateReturn3.output;
 
 
-              break;
+            _this2.updateTextValue(el, output);
 
 
-            case 'show':
-              var _this$evaluateReturnE4 = _this.evaluateReturnExpression(expression),
-                  output = _this$evaluateReturnE4.output;
+            break;
 
 
-              _this.updateVisibility(el, output);
+          case 'show':
+            var _this2$evaluateReturn4 = _this2.evaluateReturnExpression(expression),
+                output = _this2$evaluateReturn4.output;
 
 
-              break;
+            _this2.updateVisibility(el, output);
 
 
-            case 'cloak':
-              el.removeAttribute('x-cloak');
-              break;
+            break;
 
 
-            default:
-              break;
+          case 'cloak':
+            el.removeAttribute('x-cloak');
+            break;
+
+          default:
+            break;
+        }
+      });
+    }
+  }, {
+    key: "listenForNewElementsToInitialize",
+    value: function listenForNewElementsToInitialize() {
+      var _this3 = this;
+
+      var targetNode = this.el;
+      var observerOptions = {
+        childList: true,
+        attributes: false,
+        subtree: true
+      };
+      var observer = new MutationObserver(function (mutations) {
+        for (var i = 0; i < mutations.length; i++) {
+          if (mutations[i].addedNodes.length > 0) {
+            mutations[i].addedNodes.forEach(function (node) {
+              if (node.nodeType !== 1) return;
+              if (node.matches('[x-data]')) return;
+
+              if (Object(_utils__WEBPACK_IMPORTED_MODULE_0__["getXAttrs"])(node).length > 0) {
+                _this3.initializeElement(node);
+              }
+            });
           }
           }
-        });
+        }
       });
       });
+      observer.observe(targetNode, observerOptions);
     }
     }
   }, {
   }, {
     key: "refresh",
     key: "refresh",
@@ -1091,7 +1126,7 @@ function () {
   }, {
   }, {
     key: "registerListener",
     key: "registerListener",
     value: function registerListener(el, event, modifiers, expression) {
     value: function registerListener(el, event, modifiers, expression) {
-      var _this2 = this;
+      var _this4 = this;
 
 
       if (modifiers.includes('away')) {
       if (modifiers.includes('away')) {
         var handler = function handler(e) {
         var handler = function handler(e) {
@@ -1101,7 +1136,7 @@ function () {
           if (el.offsetWidth < 1 && el.offsetHeight < 1) return; // Now that we are sure the element is visible, AND the click
           if (el.offsetWidth < 1 && el.offsetHeight < 1) return; // Now that we are sure the element is visible, AND the click
           // is from outside it, let's run the expression.
           // is from outside it, let's run the expression.
 
 
-          _this2.runListenerHandler(expression, e);
+          _this4.runListenerHandler(expression, e);
 
 
           if (modifiers.includes('once')) {
           if (modifiers.includes('once')) {
             document.removeEventListener(event, handler);
             document.removeEventListener(event, handler);
@@ -1117,7 +1152,7 @@ function () {
           if (modifiers.includes('prevent')) e.preventDefault();
           if (modifiers.includes('prevent')) e.preventDefault();
           if (modifiers.includes('stop')) e.stopPropagation();
           if (modifiers.includes('stop')) e.stopPropagation();
 
 
-          _this2.runListenerHandler(expression, e);
+          _this4.runListenerHandler(expression, e);
 
 
           if (modifiers.includes('once')) {
           if (modifiers.includes('once')) {
             node.removeEventListener(event, _handler);
             node.removeEventListener(event, _handler);
@@ -1255,7 +1290,7 @@ function () {
   }, {
   }, {
     key: "getRefsProxy",
     key: "getRefsProxy",
     value: function getRefsProxy() {
     value: function getRefsProxy() {
-      var self = this; // One of the goals of this project is to not hold elements in memory, but rather re-evaluate
+      var self = this; // One of the goals of this  is to not hold elements in memory, but rather re-evaluate
       // the DOM when the system needs something from it. This way, the framework is flexible and
       // the DOM when the system needs something from it. This way, the framework is flexible and
       // friendly to outside DOM changes from libraries like Vue/Livewire.
       // friendly to outside DOM changes from libraries like Vue/Livewire.
       // For this reason, I'm using an "on-demand" proxy to fake a "$refs" object.
       // For this reason, I'm using an "on-demand" proxy to fake a "$refs" object.
@@ -1301,7 +1336,7 @@ __webpack_require__.r(__webpack_exports__);
 /* @flow */
 /* @flow */
 
 
 
 
-var projectX = {
+var Alpine = {
   start: function start() {
   start: function start() {
     var _this = this;
     var _this = this;
 
 
@@ -1380,12 +1415,12 @@ var projectX = {
   }
   }
 };
 };
 
 
-if (!window.projectX && !Object(_utils__WEBPACK_IMPORTED_MODULE_2__["isTesting"])()) {
-  window.projectX = projectX;
-  window.projectX.start();
+if (!window.Alpine && !Object(_utils__WEBPACK_IMPORTED_MODULE_2__["isTesting"])()) {
+  window.Alpine = Alpine;
+  window.Alpine.start();
 }
 }
 
 
-/* harmony default export */ __webpack_exports__["default"] = (projectX);
+/* harmony default export */ __webpack_exports__["default"] = (Alpine);
 
 
 /***/ }),
 /***/ }),
 
 
@@ -1502,7 +1537,7 @@ function getXAttrs(el, type) {
 /*! no static exports found */
 /*! no static exports found */
 /***/ (function(module, exports, __webpack_require__) {
 /***/ (function(module, exports, __webpack_require__) {
 
 
-module.exports = __webpack_require__(/*! /Users/calebporzio/Documents/Code/sites/project-x/src/index.js */"./src/index.js");
+module.exports = __webpack_require__(/*! /Users/calebporzio/Documents/Code/sites/alpine/src/index.js */"./src/index.js");
 
 
 
 
 /***/ })
 /***/ })

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


+ 2 - 2
dist/mix-manifest.json

@@ -1,4 +1,4 @@
 {
 {
-    "/project-x.js": "/project-x.js?id=ec509918933bb1813fd2",
-    "/project-x.min.js": "/project-x.min.js?id=8bba743308e09dcd7d20"
+    "/alpine.min.js": "/alpine.min.js?id=7adbda4e32b0fe66797a",
+    "/alpine.js": "/alpine.js?id=6aaefe3b77e1795daab9"
 }
 }

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


+ 1 - 1
index.html

@@ -5,7 +5,7 @@
             [x-cloak] { display: none; }
             [x-cloak] { display: none; }
         </style>
         </style>
 
 
-        <script src="https://cdn.jsdelivr.net/gh/calebporzio/project-x@v0.4.4/dist/project-x.min.js" defer></script>
+        <script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v1.0.0/dist/alpine.min.js" defer></script>
     </head>
     </head>
     <body>
     <body>
         <table>
         <table>

+ 1 - 1
package-lock.json

@@ -1,5 +1,5 @@
 {
 {
-  "name": "project-x",
+  "name": "alpinejs",
   "version": "0.4.0",
   "version": "0.4.0",
   "lockfileVersion": 1,
   "lockfileVersion": 1,
   "requires": true,
   "requires": true,

+ 4 - 4
package.json

@@ -1,10 +1,10 @@
 {
 {
-  "main": "dist/project-x.js",
-  "name": "project-x",
-  "version": "0.4.4",
+  "main": "dist/alpine.js",
+  "name": "alpinejs",
+  "version": "1.0.0",
   "repository": {
   "repository": {
     "type": "git",
     "type": "git",
-    "url": "git://github.com/calebporzio/project-x.git"
+    "url": "git://github.com/alpinejs/alpine.git"
   },
   },
   "scripts": {
   "scripts": {
     "test": "npx jest",
     "test": "npx jest",

+ 77 - 43
src/component.js

@@ -9,6 +9,8 @@ export default class Component {
         this.data = this.wrapDataInObservable(rawData)
         this.data = this.wrapDataInObservable(rawData)
 
 
         this.initialize()
         this.initialize()
+
+        this.listenForNewElementsToInitialize()
     }
     }
 
 
     wrapDataInObservable(data) {
     wrapDataInObservable(data) {
@@ -44,55 +46,87 @@ export default class Component {
 
 
     initialize() {
     initialize() {
         walkSkippingNestedComponents(this.el, el => {
         walkSkippingNestedComponents(this.el, el => {
-            getXAttrs(el).forEach(({ type, value, modifiers, expression }) => {
-                switch (type) {
-                    case 'on':
-                        var event = value
-                        this.registerListener(el, event, modifiers, expression)
-                        break;
-
-                    case 'model':
-                        // If the element we are binding to is a select, a radio, or checkbox
-                        // we'll listen for the change event instead of the "input" event.
-                        var event = (el.tagName.toLowerCase() === 'select')
-                            || ['checkbox', 'radio'].includes(el.type)
-                            || modifiers.includes('lazy')
-                            ? 'change' : 'input'
-
-                        const listenerExpression = this.generateExpressionForXModelListener(el, modifiers, expression)
+            this.initializeElement(el)
+        })
+    }
 
 
-                        this.registerListener(el, event, modifiers, listenerExpression)
+    initializeElement(el) {
+        getXAttrs(el).forEach(({ type, value, modifiers, expression }) => {
+            switch (type) {
+                case 'on':
+                    var event = value
+                    this.registerListener(el, event, modifiers, expression)
+                    break;
+
+                case 'model':
+                    // If the element we are binding to is a select, a radio, or checkbox
+                    // we'll listen for the change event instead of the "input" event.
+                    var event = (el.tagName.toLowerCase() === 'select')
+                        || ['checkbox', 'radio'].includes(el.type)
+                        || modifiers.includes('lazy')
+                        ? 'change' : 'input'
+
+                    const listenerExpression = this.generateExpressionForXModelListener(el, modifiers, expression)
+
+                    this.registerListener(el, event, modifiers, listenerExpression)
+
+                    var attrName = 'value'
+                    var { output } = this.evaluateReturnExpression(expression)
+                    this.updateAttributeValue(el, attrName, output)
+                    break;
+
+                case 'bind':
+                    var attrName = value
+                    var { output } = this.evaluateReturnExpression(expression)
+                    this.updateAttributeValue(el, attrName, output)
+                    break;
+
+                case 'text':
+                    var { output } = this.evaluateReturnExpression(expression)
+                    this.updateTextValue(el, output)
+                    break;
+
+                case 'show':
+                    var { output } = this.evaluateReturnExpression(expression)
+                    this.updateVisibility(el, output)
+                    break;
+
+                case 'cloak':
+                    el.removeAttribute('x-cloak')
+                    break;
+
+                default:
+                    break;
+            }
+        })
+    }
 
 
-                        var attrName = 'value'
-                        var { output } = this.evaluateReturnExpression(expression)
-                        this.updateAttributeValue(el, attrName, output)
-                        break;
+    listenForNewElementsToInitialize() {
+        var targetNode = this.el
 
 
-                    case 'bind':
-                        var attrName = value
-                        var { output } = this.evaluateReturnExpression(expression)
-                        this.updateAttributeValue(el, attrName, output)
-                        break;
+        var observerOptions = {
+            childList: true,
+            attributes: false,
+            subtree: true,
+        }
 
 
-                    case 'text':
-                        var { output } = this.evaluateReturnExpression(expression)
-                        this.updateTextValue(el, output)
-                        break;
+        var observer = new MutationObserver((mutations) => {
+            for (var i=0; i < mutations.length; i++){
+                if (mutations[i].addedNodes.length > 0) {
+                    mutations[i].addedNodes.forEach(node => {
+                        if (node.nodeType !== 1) return
 
 
-                    case 'show':
-                        var { output } = this.evaluateReturnExpression(expression)
-                        this.updateVisibility(el, output)
-                        break;
-
-                    case 'cloak':
-                        el.removeAttribute('x-cloak')
-                        break;
+                        if (node.matches('[x-data]')) return
 
 
-                    default:
-                        break;
+                        if (getXAttrs(node).length > 0) {
+                            this.initializeElement(node)
+                        }
+                    })
                 }
                 }
-            })
-        })
+              }
+        });
+
+        observer.observe(targetNode, observerOptions);
     }
     }
 
 
     refresh() {
     refresh() {
@@ -334,7 +368,7 @@ export default class Component {
     getRefsProxy() {
     getRefsProxy() {
         var self = this
         var self = this
 
 
-        // One of the goals of this project is to not hold elements in memory, but rather re-evaluate
+        // One of the goals of this  is to not hold elements in memory, but rather re-evaluate
         // the DOM when the system needs something from it. This way, the framework is flexible and
         // the DOM when the system needs something from it. This way, the framework is flexible and
         // friendly to outside DOM changes from libraries like Vue/Livewire.
         // friendly to outside DOM changes from libraries like Vue/Livewire.
         // For this reason, I'm using an "on-demand" proxy to fake a "$refs" object.
         // For this reason, I'm using an "on-demand" proxy to fake a "$refs" object.

+ 6 - 6
src/index.js

@@ -2,7 +2,7 @@
 import Component from './component'
 import Component from './component'
 import { domReady, isTesting } from './utils'
 import { domReady, isTesting } from './utils'
 
 
-const projectX = {
+const Alpine = {
     start: async function () {
     start: async function () {
         if (! isTesting()) {
         if (! isTesting()) {
             await domReady()
             await domReady()
@@ -66,7 +66,7 @@ const projectX = {
               }
               }
         });
         });
 
 
-        observer.observe(targetNode, observerOptions);
+        observer.observe(targetNode, observerOptions)
     },
     },
 
 
     initializeElement: function (el) {
     initializeElement: function (el) {
@@ -74,9 +74,9 @@ const projectX = {
     }
     }
 }
 }
 
 
-if (! window.projectX && ! isTesting()) {
-    window.projectX = projectX
-    window.projectX.start()
+if (! window.Alpine && ! isTesting()) {
+    window.Alpine = Alpine
+    window.Alpine.start()
 }
 }
 
 
-export default projectX
+export default Alpine

+ 9 - 10
test/bind.spec.js

@@ -1,4 +1,4 @@
-import projectX from 'project-x'
+import Alpine from 'alpinejs'
 
 
 global.MutationObserver = class {
 global.MutationObserver = class {
     observe() {}
     observe() {}
@@ -11,7 +11,7 @@ test('attribute bindings are set on initialize', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('span').getAttribute('foo')).toEqual('bar')
     expect(document.querySelector('span').getAttribute('foo')).toEqual('bar')
 })
 })
@@ -23,7 +23,7 @@ test('class attribute bindings are removed by object syntax', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('span').classList.contains('foo')).toBeFalsy()
     expect(document.querySelector('span').classList.contains('foo')).toBeFalsy()
 })
 })
@@ -35,7 +35,7 @@ test('class attribute bindings are added by object syntax', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('span').classList.contains('foo')).toBeTruthy()
     expect(document.querySelector('span').classList.contains('foo')).toBeTruthy()
 })
 })
@@ -47,7 +47,7 @@ test('class attribute bindings are added by nested object syntax', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('span').classList.contains('foo')).toBeTruthy()
     expect(document.querySelector('span').classList.contains('foo')).toBeTruthy()
 })
 })
@@ -59,7 +59,7 @@ test('class attribute bindings are removed by array syntax', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('span').classList.contains('foo')).toBeFalsy()
     expect(document.querySelector('span').classList.contains('foo')).toBeFalsy()
 })
 })
@@ -71,7 +71,7 @@ test('class attribute bindings are added by array syntax', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('span').classList.contains('foo')).toBeTruthy
     expect(document.querySelector('span').classList.contains('foo')).toBeTruthy
 })
 })
@@ -87,7 +87,7 @@ test('boolean attributes set to false are removed from element', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelectorAll('input')[0].disabled).toBeFalsy()
     expect(document.querySelectorAll('input')[0].disabled).toBeFalsy()
     expect(document.querySelectorAll('input')[1].checked).toBeFalsy()
     expect(document.querySelectorAll('input')[1].checked).toBeFalsy()
@@ -106,11 +106,10 @@ test('boolean attributes set to true are added to element', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelectorAll('input')[0].disabled).toBeTruthy()
     expect(document.querySelectorAll('input')[0].disabled).toBeTruthy()
     expect(document.querySelectorAll('input')[1].checked).toBeTruthy()
     expect(document.querySelectorAll('input')[1].checked).toBeTruthy()
     expect(document.querySelectorAll('input')[2].required).toBeTruthy()
     expect(document.querySelectorAll('input')[2].required).toBeTruthy()
     expect(document.querySelectorAll('input')[3].readOnly).toBeTruthy()
     expect(document.querySelectorAll('input')[3].readOnly).toBeTruthy()
 })
 })
-

+ 2 - 2
test/cloak.spec.js

@@ -1,4 +1,4 @@
-import projectX from 'project-x'
+import Alpine from 'alpinejs'
 import { wait } from '@testing-library/dom'
 import { wait } from '@testing-library/dom'
 
 
 global.MutationObserver = class {
 global.MutationObserver = class {
@@ -14,7 +14,7 @@ test('x-cloak is removed', async () => {
 
 
     expect(document.querySelector('span').getAttribute('x-cloak')).not.toBeNull()
     expect(document.querySelector('span').getAttribute('x-cloak')).not.toBeNull()
 
 
-    projectX.start()
+    Alpine.start()
 
 
     await wait(() => { expect(document.querySelector('span').getAttribute('x-cloak')).toBeNull() })
     await wait(() => { expect(document.querySelector('span').getAttribute('x-cloak')).toBeNull() })
 })
 })

+ 47 - 8
test/constructor.spec.js

@@ -1,15 +1,12 @@
-import projectX from 'project-x'
+import Alpine from 'alpinejs'
 import { fireEvent, wait } from '@testing-library/dom'
 import { fireEvent, wait } from '@testing-library/dom'
 
 
-global.MutationObserver = class {
-    observe() {}
-}
 
 
 test('auto-detect new components and dont lose state of existing ones', async () => {
 test('auto-detect new components and dont lose state of existing ones', async () => {
-    var runObserver
+    var runObservers = []
 
 
     global.MutationObserver = class {
     global.MutationObserver = class {
-        constructor(callback) { runObserver = callback }
+        constructor(callback) { runObservers.push(callback) }
         observe() {}
         observe() {}
     }
     }
 
 
@@ -20,7 +17,7 @@ test('auto-detect new components and dont lose state of existing ones', async ()
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     fireEvent.input(document.querySelector('input'), { target: { value: 'bar' }})
     fireEvent.input(document.querySelector('input'), { target: { value: 'bar' }})
 
 
@@ -35,7 +32,7 @@ test('auto-detect new components and dont lose state of existing ones', async ()
     `
     `
     document.body.appendChild(div)
     document.body.appendChild(div)
 
 
-    runObserver([
+    runObservers[1]([
         { addedNodes: [ div ] }
         { addedNodes: [ div ] }
     ])
     ])
 
 
@@ -44,3 +41,45 @@ test('auto-detect new components and dont lose state of existing ones', async ()
         expect(document.querySelector('#B span').innerText).toEqual('baz')
         expect(document.querySelector('#B span').innerText).toEqual('baz')
     })
     })
 })
 })
+
+test('auto-initialize new elements added to a component', async () => {
+    var runObservers = []
+
+    global.MutationObserver = class {
+        constructor(callback) { runObservers.push(callback) }
+        observe() {}
+    }
+
+    document.body.innerHTML = `
+        <div x-data="{ count: 0 }">
+            <span x-text="count"></span>
+
+            <div id="target">
+            </div>
+        </div>
+    `
+
+    Alpine.start()
+
+    expect(document.querySelector('span').innerText).toEqual(0)
+
+    document.querySelector('#target').innerHTML = `
+        <span x-text="count"></span>
+
+        <button x-on:click="count++"></button>
+    `
+
+    runObservers[0]([
+        { addedNodes: [
+            document.querySelector('#target span'),
+            document.querySelector('#target button'),
+        ] }
+    ])
+
+    await wait(() => { expect(document.querySelector('#target span').innerText).toEqual(0) })
+
+    document.querySelector('button').click()
+
+    await wait(() => { expect(document.querySelector('span').innerText).toEqual(1) })
+    await wait(() => { expect(document.querySelector('#target span').innerText).toEqual(1) })
+})

+ 2 - 2
test/data.spec.js

@@ -1,4 +1,4 @@
-import projectX from 'project-x'
+import Alpine from 'alpinejs'
 import { fireEvent, wait } from '@testing-library/dom'
 import { fireEvent, wait } from '@testing-library/dom'
 
 
 global.MutationObserver = class {
 global.MutationObserver = class {
@@ -12,7 +12,7 @@ test('data manipulated on component object is reactive', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     document.querySelector('div').__x.data.foo = 'baz'
     document.querySelector('div').__x.data.foo = 'baz'
 
 

+ 13 - 13
test/model.spec.js

@@ -1,4 +1,4 @@
-import projectX from 'project-x'
+import Alpine from 'alpinejs'
 import { wait, fireEvent } from '@testing-library/dom'
 import { wait, fireEvent } from '@testing-library/dom'
 
 
 global.MutationObserver = class {
 global.MutationObserver = class {
@@ -12,7 +12,7 @@ test('x-model has value binding when initialized', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('input').value).toEqual('bar')
     expect(document.querySelector('input').value).toEqual('bar')
 })
 })
@@ -24,7 +24,7 @@ test('x-model updates value when updated via input event', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     fireEvent.input(document.querySelector('input'), { target: { value: 'baz' }})
     fireEvent.input(document.querySelector('input'), { target: { value: 'baz' }})
 
 
@@ -40,7 +40,7 @@ test('x-model reflects data changed elsewhere', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     document.querySelector('button').click()
     document.querySelector('button').click()
 
 
@@ -54,7 +54,7 @@ test('x-model casts value to number if number modifier is present', async () =>
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     fireEvent.input(document.querySelector('input'), { target: { value: '123' }})
     fireEvent.input(document.querySelector('input'), { target: { value: '123' }})
 
 
@@ -70,7 +70,7 @@ test('x-model trims value if trim modifier is present', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     fireEvent.input(document.querySelector('input'), { target: { value: 'bar   ' }})
     fireEvent.input(document.querySelector('input'), { target: { value: 'bar   ' }})
 
 
@@ -84,7 +84,7 @@ test('x-model updates value when updated via changed event when lazy modifier is
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     fireEvent.change(document.querySelector('input'), { target: { value: 'baz' }})
     fireEvent.change(document.querySelector('input'), { target: { value: 'baz' }})
 
 
@@ -100,7 +100,7 @@ test('x-model binds checkbox value', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('input').checked).toEqual(true)
     expect(document.querySelector('input').checked).toEqual(true)
     expect(document.querySelector('span').getAttribute('bar')).toEqual("true")
     expect(document.querySelector('span').getAttribute('bar')).toEqual("true")
@@ -120,7 +120,7 @@ test('x-model binds checkbox value to array', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelectorAll('input')[0].checked).toEqual(true)
     expect(document.querySelectorAll('input')[0].checked).toEqual(true)
     expect(document.querySelectorAll('input')[1].checked).toEqual(false)
     expect(document.querySelectorAll('input')[1].checked).toEqual(false)
@@ -145,7 +145,7 @@ test('x-model binds radio value', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelectorAll('input')[0].checked).toEqual(true)
     expect(document.querySelectorAll('input')[0].checked).toEqual(true)
     expect(document.querySelectorAll('input')[1].checked).toEqual(false)
     expect(document.querySelectorAll('input')[1].checked).toEqual(false)
@@ -173,7 +173,7 @@ test('x-model binds select dropdown', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelectorAll('option')[0].selected).toEqual(false)
     expect(document.querySelectorAll('option')[0].selected).toEqual(false)
     expect(document.querySelectorAll('option')[1].selected).toEqual(true)
     expect(document.querySelectorAll('option')[1].selected).toEqual(true)
@@ -203,7 +203,7 @@ test('x-model binds multiple select dropdown', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelectorAll('option')[0].selected).toEqual(false)
     expect(document.querySelectorAll('option')[0].selected).toEqual(false)
     expect(document.querySelectorAll('option')[1].selected).toEqual(true)
     expect(document.querySelectorAll('option')[1].selected).toEqual(true)
@@ -229,7 +229,7 @@ test('x-model binds nested keys', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('input').value).toEqual('foo')
     expect(document.querySelector('input').value).toEqual('foo')
     expect(document.querySelector('span').innerText).toEqual('foo')
     expect(document.querySelector('span').innerText).toEqual('foo')

+ 3 - 3
test/nesting.spec.js

@@ -1,4 +1,4 @@
-import projectX from 'project-x'
+import Alpine from 'alpinejs'
 import { wait } from '@testing-library/dom'
 import { wait } from '@testing-library/dom'
 const timeout = ms => new Promise(resolve => setTimeout(resolve, ms))
 const timeout = ms => new Promise(resolve => setTimeout(resolve, ms))
 
 
@@ -17,7 +17,7 @@ test('can nest components', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('span').innerText).toEqual('bar')
     expect(document.querySelector('span').innerText).toEqual('bar')
 
 
@@ -39,7 +39,7 @@ test('can access parent properties after nested components', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('span').innerText).toEqual('bar')
     expect(document.querySelector('span').innerText).toEqual('bar')
 })
 })

+ 8 - 8
test/on.spec.js

@@ -1,4 +1,4 @@
-import projectX from 'project-x'
+import Alpine from 'alpinejs'
 import { wait } from '@testing-library/dom'
 import { wait } from '@testing-library/dom'
 const timeout = ms => new Promise(resolve => setTimeout(resolve, ms))
 const timeout = ms => new Promise(resolve => setTimeout(resolve, ms))
 
 
@@ -15,7 +15,7 @@ test('data modified in event listener updates effected attribute bindings', asyn
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('span').getAttribute('foo')).toEqual('bar')
     expect(document.querySelector('span').getAttribute('foo')).toEqual('bar')
 
 
@@ -33,7 +33,7 @@ test('nested data modified in event listener updates effected attribute bindings
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('span').getAttribute('foo')).toEqual('bar')
     expect(document.querySelector('span').getAttribute('foo')).toEqual('bar')
 
 
@@ -52,7 +52,7 @@ test('.stop modifier', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('div').__x.data.foo).toEqual('bar')
     expect(document.querySelector('div').__x.data.foo).toEqual('bar')
 
 
@@ -70,7 +70,7 @@ test('.prevent modifier', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('input').checked).toEqual(false)
     expect(document.querySelector('input').checked).toEqual(false)
 
 
@@ -88,7 +88,7 @@ test('.window modifier', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('span').getAttribute('foo')).toEqual('bar')
     expect(document.querySelector('span').getAttribute('foo')).toEqual('bar')
 
 
@@ -106,7 +106,7 @@ test('.once modifier', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('span').getAttribute('foo')).toEqual('0')
     expect(document.querySelector('span').getAttribute('foo')).toEqual('0')
 
 
@@ -145,7 +145,7 @@ test('click away', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('ul').classList.contains('hidden')).toEqual(false)
     expect(document.querySelector('ul').classList.contains('hidden')).toEqual(false)
 
 

+ 2 - 2
test/ref.spec.js

@@ -1,4 +1,4 @@
-import projectX from 'project-x'
+import Alpine from 'alpinejs'
 import { wait } from '@testing-library/dom'
 import { wait } from '@testing-library/dom'
 
 
 global.MutationObserver = class {
 global.MutationObserver = class {
@@ -14,7 +14,7 @@ test('can reference elements from event listeners', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('span').innerText).toEqual(undefined)
     expect(document.querySelector('span').innerText).toEqual(undefined)
 
 

+ 3 - 3
test/show.spec.js

@@ -1,4 +1,4 @@
-import projectX from 'project-x'
+import Alpine from 'alpinejs'
 import { wait } from '@testing-library/dom'
 import { wait } from '@testing-library/dom'
 
 
 global.MutationObserver = class {
 global.MutationObserver = class {
@@ -14,7 +14,7 @@ test('x-show toggles display: none; with no other style attributes', async () =>
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('span').getAttribute('style')).toEqual(null)
     expect(document.querySelector('span').getAttribute('style')).toEqual(null)
 
 
@@ -32,7 +32,7 @@ test('x-show toggles display: none; with no other style attributes', async () =>
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     expect(document.querySelector('span').getAttribute('style')).toEqual('color: blue;')
     expect(document.querySelector('span').getAttribute('style')).toEqual('color: blue;')
 
 

+ 3 - 3
test/text.spec.js

@@ -1,4 +1,4 @@
-import projectX from 'project-x'
+import Alpine from 'alpinejs'
 import { wait } from '@testing-library/dom'
 import { wait } from '@testing-library/dom'
 
 
 global.MutationObserver = class {
 global.MutationObserver = class {
@@ -12,7 +12,7 @@ test('x-text on init', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     await wait(() => { expect(document.querySelector('span').innerText).toEqual('bar') })
     await wait(() => { expect(document.querySelector('span').innerText).toEqual('bar') })
 })
 })
@@ -26,7 +26,7 @@ test('x-text on triggered update', async () => {
         </div>
         </div>
     `
     `
 
 
-    projectX.start()
+    Alpine.start()
 
 
     await wait(() => { expect(document.querySelector('span').innerText).toEqual('') })
     await wait(() => { expect(document.querySelector('span').innerText).toEqual('') })
 
 

+ 1 - 1
turbolinks-manual-test/index.html

@@ -1,7 +1,7 @@
 <html>
 <html>
     <head>
     <head>
         <script src="https://cdnjs.cloudflare.com/ajax/libs/turbolinks/5.2.0/turbolinks.js" integrity="sha256-iM4Yzi/zLj/IshPWMC1IluRxTtRjMqjPGd97TZ9yYpU=" crossorigin="anonymous"></script>
         <script src="https://cdnjs.cloudflare.com/ajax/libs/turbolinks/5.2.0/turbolinks.js" integrity="sha256-iM4Yzi/zLj/IshPWMC1IluRxTtRjMqjPGd97TZ9yYpU=" crossorigin="anonymous"></script>
-        <script src="/dist/project-x.js" defer></script>
+        <script src="/dist/alpine.js" defer></script>
     </head>
     </head>
     <body>
     <body>
         <h1>First Page</h1>
         <h1>First Page</h1>

+ 1 - 1
turbolinks-manual-test/navigated-away/index.html

@@ -1,7 +1,7 @@
 <html>
 <html>
     <head>
     <head>
         <script src="https://cdnjs.cloudflare.com/ajax/libs/turbolinks/5.2.0/turbolinks.js" integrity="sha256-iM4Yzi/zLj/IshPWMC1IluRxTtRjMqjPGd97TZ9yYpU=" crossorigin="anonymous"></script>
         <script src="https://cdnjs.cloudflare.com/ajax/libs/turbolinks/5.2.0/turbolinks.js" integrity="sha256-iM4Yzi/zLj/IshPWMC1IluRxTtRjMqjPGd97TZ9yYpU=" crossorigin="anonymous"></script>
-        <script src="/dist/project-x.js" defer></script>
+        <script src="/dist/alpine.js" defer></script>
     </head>
     </head>
     <body>
     <body>
         <h1>Second Page</h1>
         <h1>Second Page</h1>

+ 3 - 3
webpack.mix.js

@@ -1,12 +1,12 @@
 let mix = require('laravel-mix');
 let mix = require('laravel-mix');
 
 
-// Allow both "project-x.js" && "project-x.min.js"
+// Allow both "alpine.js" && "alpine.min.js"
 // to both exist in the mix.manifest file.
 // to both exist in the mix.manifest file.
 require('laravel-mix-merge-manifest');
 require('laravel-mix-merge-manifest');
 
 
 const outputFileName = process.env.NODE_ENV === 'production'
 const outputFileName = process.env.NODE_ENV === 'production'
-    ? 'project-x.min.js'
-    : 'project-x.js'
+    ? 'alpine.min.js'
+    : 'alpine.js'
 
 
 mix
 mix
     .js('src/index.js', outputFileName)
     .js('src/index.js', outputFileName)

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