|
46 | 46 | path = window.location.pathname.replace(/\/[^\/]*$/, ""); // Remove file from path |
47 | 47 | } |
48 | 48 |
|
49 | | - // For localhost/127.0.0.1, trim everything after '/src' |
| 49 | + // For localhost/127.0.0.1, remove everything up to and including the first '/src' |
| 50 | + // so content AFTER '/src' is treated as the root |
50 | 51 | if ( |
51 | 52 | isBrowser && |
52 | 53 | (location.hostname === "localhost" || |
53 | 54 | location.hostname === "127.0.0.1") |
54 | 55 | ) { |
| 56 | + // Find the '/src' directory in the path and keep everything after it (exclude '/src' itself) |
55 | 57 | const srcIndex = path.indexOf("/src"); |
56 | 58 | if (srcIndex !== -1) { |
57 | | - path = path.substring(0, srcIndex + 4); // keep '/src' |
| 59 | + path = path.slice(srcIndex + 4); // remove '/src' and everything before it |
58 | 60 | } |
59 | 61 | } |
60 | 62 |
|
|
314 | 316 |
|
315 | 317 | function getValueFromObject(object = {}, path = "", throwError = false) { |
316 | 318 | try { |
317 | | - if (!Object.keys(object).length || !path) { |
| 319 | + if ((!Array.isArray(object) && !Object.keys(object).length) || !path) { |
318 | 320 | if (throwError) |
319 | 321 | throw new Error("Invalid input to getValueFromObject"); |
320 | 322 | return; |
321 | 323 | } |
322 | 324 |
|
323 | | - path = path.replace(/\[(\d+)\]/g, ".$1"); |
| 325 | + // remove leading dot if path is like `[0].src` |
| 326 | + path = path.replace(/\[(\d+)\]/g, ".$1").replace(/^\./, ''); |
324 | 327 |
|
325 | 328 | let data = object, |
326 | 329 | subpath = path.split("."); |
|
706 | 709 | * @returns {Array} - An array of elements that match the query. |
707 | 710 | */ |
708 | 711 | function queryElements({ element = document, prefix, selector }) { |
709 | | - // Initialize a Set to store unique elements. |
710 | | - let elements = new Set(); |
711 | | - |
712 | | - // If no selector is provided and the element is an element node. |
713 | | - if (!selector && element.nodeType === 1) { |
714 | | - // If no prefix is provided, derive one from the element's attributes. |
715 | | - if (!prefix) { |
716 | | - for (let attr of element.attributes) { |
717 | | - // If an attribute with "-query" suffix is found, extract prefix. |
718 | | - if (attr.name.endsWith("-query")) { |
719 | | - prefix = attr.name.slice(0, -6); |
| 712 | + try { |
| 713 | + // Initialize a Set to store unique elements. |
| 714 | + let elements = new Set(); |
| 715 | + |
| 716 | + // If no selector is provided and the element is an element node. |
| 717 | + if (!selector && element.nodeType === 1) { |
| 718 | + // If no prefix is provided, derive one from the element's attributes. |
| 719 | + if (!prefix) { |
| 720 | + for (let attr of element.attributes) { |
| 721 | + // If an attribute with "-query" suffix is found, extract prefix. |
| 722 | + if (attr.name.endsWith("-query")) { |
| 723 | + prefix = attr.name.slice(0, -6); |
| 724 | + } |
720 | 725 | } |
| 726 | + // If no valid prefix is found, exit the function. |
| 727 | + if (!prefix) return []; |
721 | 728 | } |
722 | | - // If no valid prefix is found, exit the function. |
723 | | - if (!prefix) return false; |
| 729 | + // Get the selector using the derived prefix. |
| 730 | + selector = element.getAttribute(prefix + "-" + "query"); |
| 731 | + if (!selector) return []; // Exit if no selector is found. |
724 | 732 | } |
725 | | - // Get the selector using the derived prefix. |
726 | | - selector = element.getAttribute(prefix + "-" + "query"); |
727 | | - if (!selector) return false; // Exit if no selector is found. |
728 | | - } |
729 | 733 |
|
730 | | - // Split complex selectors into individual ones, handling nested structures. |
731 | | - let selectors = selector.split(/,(?![^()\[\]]*[)\]])/g); |
732 | | - for (let i = 0; i < selectors.length; i++) { |
733 | | - if (!selectors[i]) continue; // Skip empty selectors. |
| 734 | + // Split complex selectors into individual ones, handling nested structures. |
| 735 | + let selectors = selector.split(/,(?![^()\[\]]*[)\]])/g); |
| 736 | + for (let i = 0; i < selectors.length; i++) { |
| 737 | + if (!selectors[i]) continue; // Skip empty selectors. |
734 | 738 |
|
735 | | - let queriedElement = element; // Start query from the current element. |
| 739 | + let queriedElement = element; // Start query from the current element. |
736 | 740 |
|
737 | | - // If media queries are included, verify and filter the selector accordingly. |
738 | | - if (selectors[i].includes("@")) { |
739 | | - selectors[i] = checkMediaQueries(selectors[i]); |
740 | | - if (selectors[i] === false) continue; // Skip if media query is not matched. |
741 | | - } |
| 741 | + // If media queries are included, verify and filter the selector accordingly. |
| 742 | + if (selectors[i].includes("@")) { |
| 743 | + selectors[i] = checkMediaQueries(selectors[i]); |
| 744 | + if (selectors[i] === false) continue; // Skip if media query is not matched. |
| 745 | + } |
| 746 | + |
| 747 | + let remainingSelector = selectors[i].trim(); // Trim any whitespace. |
| 748 | + let match; |
| 749 | + |
| 750 | + // Process each part of the selector that corresponds to specific query types/operators. |
| 751 | + while ( |
| 752 | + (match = queryTypesRegex.exec(remainingSelector)) !== null |
| 753 | + ) { |
| 754 | + const matchIndex = match.index; |
| 755 | + const operator = match[0]; |
| 756 | + |
| 757 | + // Process the part before the operator (if any). |
| 758 | + const part = remainingSelector |
| 759 | + .substring(0, matchIndex) |
| 760 | + .trim() |
| 761 | + .replace(/,$/, ""); |
| 762 | + if (part) { |
| 763 | + queriedElement = querySelector(queriedElement, part); |
| 764 | + if (!queriedElement) break; // Exit loop if no element is found. |
| 765 | + } |
| 766 | + |
| 767 | + // Remove the processed part and operator from the remaining selector. |
| 768 | + remainingSelector = remainingSelector |
| 769 | + .substring(matchIndex + operator.length) |
| 770 | + .trim(); |
| 771 | + |
| 772 | + // Handle the $closest operator specifically. |
| 773 | + if (operator === "$closest") { |
| 774 | + let [closest, remaining = ""] = |
| 775 | + remainingSelector.split(/\s+/, 2); |
| 776 | + queriedElement = queriedElement.closest(closest); |
| 777 | + remainingSelector = remaining.trim(); |
| 778 | + } else { |
| 779 | + // Process other operators using the queryType function. |
| 780 | + queriedElement = queryType(queriedElement, operator); |
| 781 | + } |
742 | 782 |
|
743 | | - let remainingSelector = selectors[i].trim(); // Trim any whitespace. |
744 | | - let match; |
745 | | - |
746 | | - // Process each part of the selector that corresponds to specific query types/operators. |
747 | | - while ((match = queryTypesRegex.exec(remainingSelector)) !== null) { |
748 | | - const matchIndex = match.index; |
749 | | - const operator = match[0]; |
750 | | - |
751 | | - // Process the part before the operator (if any). |
752 | | - const part = remainingSelector |
753 | | - .substring(0, matchIndex) |
754 | | - .trim() |
755 | | - .replace(/,$/, ""); |
756 | | - if (part) { |
757 | | - queriedElement = querySelector(queriedElement, part); |
758 | 783 | if (!queriedElement) break; // Exit loop if no element is found. |
759 | 784 | } |
760 | 785 |
|
761 | | - // Remove the processed part and operator from the remaining selector. |
762 | | - remainingSelector = remainingSelector |
763 | | - .substring(matchIndex + operator.length) |
764 | | - .trim(); |
| 786 | + if (!queriedElement) continue; // Skip if no element is found. |
765 | 787 |
|
766 | | - // Handle the $closest operator specifically. |
767 | | - if (operator === "$closest") { |
768 | | - let [closest, remaining = ""] = remainingSelector.split( |
769 | | - /\s+/, |
770 | | - 2 |
| 788 | + // Process the remaining part after the last operator (if any). |
| 789 | + if (remainingSelector) { |
| 790 | + queriedElement = querySelector( |
| 791 | + queriedElement, |
| 792 | + remainingSelector |
771 | 793 | ); |
772 | | - queriedElement = queriedElement.closest(closest); |
773 | | - remainingSelector = remaining.trim(); |
774 | | - } else { |
775 | | - // Process other operators using the queryType function. |
776 | | - queriedElement = queryType(queriedElement, operator); |
777 | 794 | } |
778 | 795 |
|
779 | | - if (!queriedElement) break; // Exit loop if no element is found. |
780 | | - } |
781 | | - |
782 | | - if (!queriedElement) continue; // Skip if no element is found. |
783 | | - |
784 | | - // Process the remaining part after the last operator (if any). |
785 | | - if (remainingSelector) { |
786 | | - queriedElement = querySelector( |
787 | | - queriedElement, |
788 | | - remainingSelector |
789 | | - ); |
790 | | - } |
791 | | - |
792 | | - // Add elements to the set. |
793 | | - if ( |
794 | | - Array.isArray(queriedElement) || |
795 | | - queriedElement instanceof HTMLCollection || |
796 | | - queriedElement instanceof NodeList |
797 | | - ) { |
798 | | - for (let el of queriedElement) { |
799 | | - if (el instanceof Element) { |
800 | | - elements.add(el); |
| 796 | + // Add elements to the set. |
| 797 | + if ( |
| 798 | + Array.isArray(queriedElement) || |
| 799 | + queriedElement instanceof HTMLCollection || |
| 800 | + queriedElement instanceof NodeList |
| 801 | + ) { |
| 802 | + for (let el of queriedElement) { |
| 803 | + if (el instanceof Element) { |
| 804 | + elements.add(el); |
| 805 | + } |
801 | 806 | } |
| 807 | + } else if (queriedElement instanceof Element) { |
| 808 | + elements.add(queriedElement); |
802 | 809 | } |
803 | | - } else if (queriedElement instanceof Element) { |
804 | | - elements.add(queriedElement); |
805 | 810 | } |
806 | | - } |
807 | 811 |
|
808 | | - return Array.from(elements); // Convert Set to Array and return found elements. |
| 812 | + return Array.from(elements); // Convert Set to Array and return found elements. |
| 813 | + } catch (e) { |
| 814 | + console.error( |
| 815 | + `CoCreate: Error in queryElements with selector: "${selector}".`, |
| 816 | + e |
| 817 | + ); |
| 818 | + return []; |
| 819 | + } |
809 | 820 | } |
810 | 821 |
|
811 | 822 | function queryType(element, type) { |
|
0 commit comments