Pārlūkot izejas kodu

Support nested components

Caleb Porzio 5 gadi atpakaļ
vecāks
revīzija
747673a915
6 mainītis faili ar 42 papildinājumiem un 107 dzēšanām
  1. 1 1
      dist/mix-manifest.json
  2. 6 5
      dist/project-x.js
  3. 3 3
      src/component.js
  4. 0 97
      src/something.js
  5. 3 1
      src/utils.js
  6. 29 0
      test/nesting.spec.js

+ 1 - 1
dist/mix-manifest.json

@@ -1,4 +1,4 @@
 {
-    "/project-x.js": "/project-x.js?id=e45ec620878b956774b7",
+    "/project-x.js": "/project-x.js?id=7551001734d762a47f88",
     "/project-x.min.js": "/project-x.min.js?id=d98d428b50d33783e5d7"
 }

+ 6 - 5
dist/project-x.js

@@ -899,7 +899,7 @@ function () {
     value: function initialize() {
       var _this = this;
 
-      Object(_utils__WEBPACK_IMPORTED_MODULE_0__["walk"])(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,
@@ -966,7 +966,7 @@ function () {
       var self = this;
 
       var walkThenClearDependancyTracker = function walkThenClearDependancyTracker(rootEl, callback) {
-        Object(_utils__WEBPACK_IMPORTED_MODULE_0__["walk"])(rootEl, callback);
+        Object(_utils__WEBPACK_IMPORTED_MODULE_0__["walkSkippingNestedComponents"])(rootEl, callback);
         self.concernedData = [];
       };
 
@@ -1289,14 +1289,14 @@ if (!window.projectX && !Object(_utils__WEBPACK_IMPORTED_MODULE_2__["isTesting"]
 /*!**********************!*\
   !*** ./src/utils.js ***!
   \**********************/
-/*! exports provided: domReady, isTesting, walk, debounce, onlyUnique, saferEval, saferEvalNoReturn, isXAttr, getXAttrs */
+/*! exports provided: domReady, isTesting, walkSkippingNestedComponents, debounce, onlyUnique, saferEval, saferEvalNoReturn, isXAttr, getXAttrs */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "domReady", function() { return domReady; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isTesting", function() { return isTesting; });
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "walk", function() { return walk; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "walkSkippingNestedComponents", function() { return walkSkippingNestedComponents; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "debounce", function() { return debounce; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "onlyUnique", function() { return onlyUnique; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "saferEval", function() { return saferEval; });
@@ -1325,11 +1325,12 @@ function domReady() {
 function isTesting() {
   return navigator.userAgent, navigator.userAgent.includes("Node.js") || navigator.userAgent.includes("jsdom");
 }
-function walk(el, callback) {
+function walkSkippingNestedComponents(el, callback) {
   callback(el);
   var node = el.firstElementChild;
 
   while (node) {
+    if (node.hasAttribute('x-data')) return;
     walk(node, callback);
     node = node.nextElementSibling;
   }

+ 3 - 3
src/component.js

@@ -1,4 +1,4 @@
-import { walk, onlyUnique, saferEval, saferEvalNoReturn, getXAttrs, debounce } from './utils'
+import { walkSkippingNestedComponents, saferEval, saferEvalNoReturn, getXAttrs, debounce } from './utils'
 
 export default class Component {
     constructor(el) {
@@ -31,7 +31,7 @@ export default class Component {
     }
 
     initialize() {
-        walk(this.el, el => {
+        walkSkippingNestedComponents(this.el, el => {
             getXAttrs(el).forEach(({ type, value, modifiers, expression }) => {
                 switch (type) {
                     case 'on':
@@ -82,7 +82,7 @@ export default class Component {
         var self = this
 
         const walkThenClearDependancyTracker = (rootEl, callback) => {
-            walk(rootEl, callback)
+            walkSkippingNestedComponents(rootEl, callback)
 
             self.concernedData = []
         }

+ 0 - 97
src/something.js

@@ -1,97 +0,0 @@
-/* @flow */
-
-const validDivisionCharRE = /[\w).+\-_$\]]/
-
-export function parseFilters (exp: string): string {
-  let inSingle = false
-  let inDouble = false
-  let inTemplateString = false
-  let inRegex = false
-  let curly = 0
-  let square = 0
-  let paren = 0
-  let lastFilterIndex = 0
-  let c, prev, i, expression, filters
-
-  for (i = 0; i < exp.length; i++) {
-    prev = c
-    c = exp.charCodeAt(i)
-    if (inSingle) {
-      if (c === 0x27 && prev !== 0x5C) inSingle = false
-    } else if (inDouble) {
-      if (c === 0x22 && prev !== 0x5C) inDouble = false
-    } else if (inTemplateString) {
-      if (c === 0x60 && prev !== 0x5C) inTemplateString = false
-    } else if (inRegex) {
-      if (c === 0x2f && prev !== 0x5C) inRegex = false
-    } else if (
-      c === 0x7C && // pipe
-      exp.charCodeAt(i + 1) !== 0x7C &&
-      exp.charCodeAt(i - 1) !== 0x7C &&
-      !curly && !square && !paren
-    ) {
-      if (expression === undefined) {
-        // first filter, end of expression
-        lastFilterIndex = i + 1
-        expression = exp.slice(0, i).trim()
-      } else {
-        pushFilter()
-      }
-    } else {
-      switch (c) {
-        case 0x22: inDouble = true; break         // "
-        case 0x27: inSingle = true; break         // '
-        case 0x60: inTemplateString = true; break // `
-        case 0x28: paren++; break                 // (
-        case 0x29: paren--; break                 // )
-        case 0x5B: square++; break                // [
-        case 0x5D: square--; break                // ]
-        case 0x7B: curly++; break                 // {
-        case 0x7D: curly--; break                 // }
-      }
-      if (c === 0x2f) { // /
-        let j = i - 1
-        let p
-        // find first non-whitespace prev char
-        for (; j >= 0; j--) {
-          p = exp.charAt(j)
-          if (p !== ' ') break
-        }
-        if (!p || !validDivisionCharRE.test(p)) {
-          inRegex = true
-        }
-      }
-    }
-  }
-
-  if (expression === undefined) {
-    expression = exp.slice(0, i).trim()
-  } else if (lastFilterIndex !== 0) {
-    pushFilter()
-  }
-
-  function pushFilter () {
-    (filters || (filters = [])).push(exp.slice(lastFilterIndex, i).trim())
-    lastFilterIndex = i + 1
-  }
-
-  if (filters) {
-    for (i = 0; i < filters.length; i++) {
-      expression = wrapFilter(expression, filters[i])
-    }
-  }
-
-  return expression
-}
-
-function wrapFilter (exp: string, filter: string): string {
-  const i = filter.indexOf('(')
-  if (i < 0) {
-    // _f: resolveFilter
-    return `_f("${filter}")(${exp})`
-  } else {
-    const name = filter.slice(0, i)
-    const args = filter.slice(i + 1)
-    return `_f("${name}")(${exp}${args !== ')' ? ',' + args : args}`
-  }
-}

+ 3 - 1
src/utils.js

@@ -16,12 +16,14 @@ export function isTesting() {
         || navigator.userAgent.includes("jsdom")
 }
 
-export function walk(el, callback) {
+export function walkSkippingNestedComponents(el, callback) {
     callback(el)
 
     let node = el.firstElementChild
 
     while (node) {
+        if (node.hasAttribute('x-data')) return
+
         walk(node, callback)
         node = node.nextElementSibling
     }

+ 29 - 0
test/nesting.spec.js

@@ -0,0 +1,29 @@
+import projectX from 'project-x'
+import { wait } from 'dom-testing-library'
+const timeout = ms => new Promise(resolve => setTimeout(resolve, ms))
+
+global.MutationObserver = class {
+    observe() {}
+}
+
+test('can nest components', async () => {
+    document.body.innerHTML = `
+        <div x-data="{ foo: 'bar' }">
+            <span x-text="foo"></span>
+
+            <div x-data="{ foo: 'bob' }">
+                <button x-on:click="foo = 'baz'">Something</button>
+            </div>
+        </div>
+    `
+
+    projectX.start()
+
+    expect(document.querySelector('span').innerText).toEqual('bar')
+
+    document.querySelector('button').click()
+
+    await timeout(20)
+
+    await wait(() => { expect(document.querySelector('span').innerText).toEqual('bar') })
+})