diff --git a/.github/workflows/deploy-image.yml b/.github/workflows/deploy-image.yml index 94ba56e..a79c48d 100644 --- a/.github/workflows/deploy-image.yml +++ b/.github/workflows/deploy-image.yml @@ -39,6 +39,7 @@ jobs: commit_author: github-actions file_pattern: | ./.gitignore + build/index.js build/index.min.js build/index.min.js.gz skip_dirty_check: true @@ -61,6 +62,7 @@ jobs: uses: softprops/action-gh-release@v1 with: files: | + build/index.js build/index.min.js build/index.min.js.gz tag_name: ${{ steps.package-version.outputs.current-version }} diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..058a7c8 --- /dev/null +++ b/.npmignore @@ -0,0 +1,2 @@ +tests/ +node_modules/ \ No newline at end of file diff --git a/README.md b/README.md index 39b8636..bcdae78 100644 --- a/README.md +++ b/README.md @@ -19,11 +19,6 @@

CSS-in-JS without CSS and JS
- Explore the docs » -
-
- View Demo - · Report Bug · Request Feature @@ -45,12 +40,10 @@

  • Getting Started
  • -
  • Usage
  • -
  • Roadmap
  • Contributing
  • License
  • Contact
  • @@ -84,74 +77,40 @@ CSS-in-JS-in-HTML is a JavaScript library which permits you to apply CSS propert ## Getting Started -### Prerequisites - -> ⚠️ The following prerequisites were tested with the version 0.1.6 of the library and not the current version. However, the compatibility should be the same. - -The followed prerequisites are the minimum requirements to use the library. The library may work with older browsers with the polyfills but it's not guaranteed (and recommended). +### Compatible browsers -__Modern browers__ - - Chrome 9+ - - Edge 12+ - - Firefox 6+ - - Safari 5.1+ - - Opera 12.1+ - -__Browsers for mobile__ - - IOS Safari 5.1+ - - UC Browser for Android 11 - - Firefox for Android 49 - -__Older browsers__ - - IE10+ +* Chrome : 73+ +* Firefox : 67+ +* Safari : 13+ +* Edge (Chromium) : 79+ +* Opera : 60+ +* Samsung Internet : 11.1+ +* iOS Safari : 13+ ### Installation #### From CDN 1. Import `main.js` in your HTML file - ```html - - ``` +```html + +``` 2. Add one line of CSS to hide the page while building (and permits to hide elements with hidden attribute) - ```css - html[aria-busy="true"], [hidden] { display: none!important; } - ``` +```css +[hidden]:not([hidden="false"]) { display: none!important; } +``` #### Manual installation 1. Clone the repo - ```sh - git clone https://github.com/ulyssear/css-in-js-in-html.git - ``` +```sh +git clone https://github.com/ulyssear/css-in-js-in-html.git +``` 2. Import `main.js` in your HTML file - ```html - - ``` - -

    (back to top)

    - - - -## Usage - - - -

    (back to top)

    - - - - -## Roadmap - - -See the [open issues](https://github.com/ulyssear/css-in-js-in-html/issues) for a full list of proposed features (and known issues). +```html + +```

    (back to top)

    diff --git a/build/index.js b/build/index.js new file mode 100644 index 0000000..01357f1 --- /dev/null +++ b/build/index.js @@ -0,0 +1,201 @@ +const EVENTS = Object.keys(window).filter(e=>e.substring(0,2)=='on').map(e=>e.substring(2).toLowerCase()); + +const REGEXES_COMMENTS = [ + /\/\*[\s\S]*?\*\//g, + /\/\/.*/g +]; +const REGEXES = [ + /([a-zA-Z0-9\-,]+)-\[([a-zA-Z0-9 .%#,\-()'"\/:?!]+)\]/g, + /((?:\[[a-zA-Z0-9\-@():>,+ ]+\]:)*)\{\s*?((?:[a-zA-Z\-]+-\[[a-zA-Z0-9,%. \-()/ :?!'"#]+\]\s*?)+)\}/g +]; + +function getIndexChildren(element,index=0) { + if ('HTML' !== element.tagName) { + return getIndexChildren(element.parentElement,index+1); + } + return index; +} + +function joinArrays(...arrays) { + const newArray = []; + const highestLength = Math.max(...arrays.map(arr => arr.length)); + for (let i = 0; i < highestLength; i++) { + const newElement = []; + for (const arr of arrays) { + newElement.push(arr[i] || null); + } + newArray.push(newElement); + } + return newArray; +} + +function isEvents(string) { + const events = string.split(',').map(e => e.trim().toLowerCase()); + return events.every(e => EVENTS.includes(e)); +} + +function getCurrentDOMPath(element) { + let dompath = ''; + let currentElement = element; + while (currentElement && currentElement.tagName !== 'HTML') { + const tagName = currentElement.tagName.toLowerCase(); + const siblingsWithSameTag = Array.from(currentElement.parentNode.children).filter(child => child.tagName === currentElement.tagName); + const index = siblingsWithSameTag.indexOf(currentElement) + 1; + dompath = `>${tagName}${index > 1 ? `:nth-of-type(${index})` : ''}` + dompath; + currentElement = currentElement.parentNode; + if (currentElement.hasAttribute('data-cijih-current-tag')) { + dompath = `${currentElement.getAttribute('data-cijih-current-tag')}` + dompath; + return dompath; + } + } + if (currentElement.tagName === 'HTML') { + return `html`; + } + return xpath.substring(1); +} + +function getQueries(string) { + const queries = []; + let currentQuery = ''; + let indexBracket = 0; + for (let i = 0; i < string.length; i++) { + const char = string[i]; + if (char === '[') { + indexBracket++; + currentQuery += char; + } else if (char === ']') { + indexBracket--; + currentQuery += char; + } else if (char === ',' && indexBracket === 0) { + queries.push(currentQuery.trim()); + currentQuery = ''; + } else { + currentQuery += char; + } + } + if (currentQuery) { + queries.push(currentQuery.trim()); + } + return queries; +} + +function getGroupsBrackets(string,result={ + media: '', + events: '', + query: '' +}) { + const groups = [] + let j = 0; + for (let i = 0; i < string.length; i++) { + const char = string[i]; + if (char === '[') { + j = i + 1; + while (j < string.length && string[j] !== ']') { + j++; + } + groups.push(string.slice(i, j + 1)); + i = j; + } + } + for (let i = 0; i < groups.length; i++) { + const group = groups[i].substring(1, groups[i].length - 1); + if (group.startsWith('@media(')) { + result.media = group + } else if (isEvents(group)) { + result.events = group + } else { + result.query = group + } + } + return result; +} + +function getStylesFromClasses(classes) { + const styles = {}; + const matches = classes.matchAll(REGEXES[0]); + for (const match of matches) { + const [_, property, value] = match; + styles[property] = value; + } + return styles; +} + +window.addEventListener('DOMContentLoaded', function () { + let elements = document.querySelectorAll('[class]'); + const indexes = Array.from(elements).map(e => getIndexChildren(e)); + elements = Array.from(elements).map((e, i) => [e, indexes[i]]); + elements = elements.sort((a, b) => a[1] - b[1]); + for (let i = 0; i < elements.length; i++) { + const element = elements[i][0]; + + for (const regex of REGEXES_COMMENTS) { + element.className = element.className.replace(regex, ''); + } + + const matchesSecondCase = element.className.matchAll(REGEXES[1]); + + for (const match of matchesSecondCase) { + const [_, groupsBrackets, classes] = match; + const groups = getGroupsBrackets(groupsBrackets); + const queries = getQueries(groups.query); + for (let i = 0; i < queries.length; i++) { + if (queries[i].startsWith('>')) { + const currentDOMPath = getCurrentDOMPath(element); + element.dataset.cijihCurrentTag = currentDOMPath; + queries[i] = currentDOMPath+queries[i]; + } + if ('current'===queries[i]) { + const currentDOMPath = getCurrentDOMPath(element); + element.dataset.cijihCurrentTag = currentDOMPath; + queries[i] = currentDOMPath; + } + } + if (groups.events) { + const events = groups.events.split(',').map(e => e.trim().toLowerCase()); + for (const event of events) { + element.addEventListener(event, function () { + if (queries.length > 0) { + for (const query of queries) { + const elements = element.querySelectorAll(query); + const styles = getStylesFromClasses(classes); + for (const [property, value] of Object.entries(styles)) { + elements.forEach(el => el.style.setProperty(property, value)); + } + } + } + else { + const styles = getStylesFromClasses(classes); + for (const [property, value] of Object.entries(styles)) { + element.style.setProperty(property, value); + } + } + }); + } + } + for (const query of queries) { + const elements = document.querySelectorAll(query); + const styles = getStylesFromClasses(classes); + for (const [property, value] of Object.entries(styles)) { + elements.forEach(el => el.style.setProperty(property, value)); + } + } + const length = match[0].length; + const spaces = ' '.repeat(length); + element.className = element.className.replace(match[0], spaces); + } + + const matchesFirstCase = element.className.matchAll(REGEXES[0]); + const styles = getStylesFromClasses(element.className); + for (const [property, value] of Object.entries(styles)) { + element.style.setProperty(property, value); + } + for (const match of matchesFirstCase) { + const length = match[0].length; + const spaces = ' '.repeat(length); + element.className = element.className.replace(match[0], spaces); + } + element.className = element.className.trim(); + } + this.document.documentElement.removeAttribute('hidden'); + const elementsWithClasses = document.querySelector('[class]'); +}); \ No newline at end of file diff --git a/build/index.min.js b/build/index.min.js index 7ca2384..5459e0e 100644 --- a/build/index.min.js +++ b/build/index.min.js @@ -1 +1 @@ -(()=>{function L(){let A=i();function i(){let n=Array.from(Object.keys(window).filter(c=>/^on/.test(c)).map(c=>c.slice(2)));return n.push("hover"),n}function N(n){let c=[];for(;n.tagName!=="HTML";){let a=n.tagName;if(n.id){a+="#"+n.id,c.unshift(a);break}else{let u=n,t=1;for(;u=u.previousElementSibling;)u.tagName===n.tagName&&t++;t!=1&&(a+=`:nth-of-type(${t})`)}c.unshift(a),n=n.parentElement}return c.unshift("HTML"),c.join(">")}function j(){let n=document.querySelectorAll('[class*="["]'),c=[/\/\*[\s\S]*?\*\//g,/\/\/.*/g];for(let t of n){let b=t.className.matchAll(c[0]);for(let d of b)t.className=t.className.replace(d[0],"").trim();let E=t.className.matchAll(c[1]);for(let d of E)t.className=t.className.replace(d[0],"").trim()}let a=[/([a-zA-Z0-9\-,]+)-\[([a-zA-Z0-9 .%#,\-()'"\/]+)\]/g,/((?:\[[a-zA-Z0-9\-@():>, ]+\]:)*)\{\s*?((?:[a-zA-Z\-]+-\[[a-zA-Z0-9,%. \-()/ ]+\]\s*?)+)\}/g];for(let t of n){let b=t.className.matchAll(a[1]),E={events:void 0,media:void 0,query:void 0,classes:void 0};for(let h of b){t.className=t.className.replace(h[0],"").trim();let s=h[0].split("]:"),o={...E};for(let e=0;eA.includes(l))?o.events=e:s[e].startsWith("@media(")?o.media=e:s[e].startsWith("{")&&s[e].endsWith("}")?o.classes=e:o.query=e;let y=Object.entries(o).sort((e,l)=>e[1]-l[1]).filter(e=>e[1]!==void 0).map(e=>e[0]);if(y.join(",")==="events,query,classes"){let e=s[o.events].split(","),l=s[o.query].replaceAll(/current\s*,?/g,N(t)+","),f=Array.from(s[o.classes].slice(1,-1).matchAll(a[0])).map(r=>r.slice(1)),p=document.querySelectorAll(l);for(let r of p)for(let v of e)v==="hover"?(r._style=Object.assign({},r.style),r.addEventListener("mouseover",function(){for(let[m,g]of f)r.style.setProperty(m,g)}),r.addEventListener("mouseout",function(){for(let[m,g]of f)r.style.setProperty(m,r._style[m]??"initial")})):r.addEventListener(v,function(){for(let[m,g]of f)r.style.setProperty(m,g)});continue}if(y.join(",")==="query,classes"){let e=s[o.query].replaceAll(/current\s*,?/g,N(t)+","),l=Array.from(s[o.classes].slice(1,-1).matchAll(a[0])).map(p=>p.slice(1));e.startsWith(">")&&(console.log("before : ",e),e=N(t)+e,console.log("after : ",e)),e.endsWith(",")&&(e=e.slice(0,-1));let f=document.querySelectorAll(e);for(let p of f)for(let[r,v]of l)p.style.setProperty(r,v);continue}if(y.join(",")==="classes"){let e=Array.from(s[o.classes].slice(1,-1).matchAll(a[0])).map(l=>l.slice(1));for(let[l,f]of e)t.style.setProperty(l,f);continue}}let d=t.className.matchAll(a[0]);for(let h of d){let[s,o,y]=h;t.style.setProperty(o,y),t.className=t.className.replace(s,"").trim()}}document.documentElement.setAttribute("aria-busy","false");let u=new Event("css-in-js-in-html-ready");document.dispatchEvent(u)}j()}var q;window.addEventListener("css-in-js-in-html-ready",function(){q||(q=new MutationObserver(A=>{for(let i of A){if(i.type==="attributes"&&i.attributeName==="class"){L();break}if(i.type==="childList"&&(i.addedNodes.length||i.removedNodes.length)){L();break}}}),q.observe(document.body,{attributes:!0,childList:!0,subtree:!0,attributeFilter:["class"]}))});document.addEventListener("DOMContentLoaded",L);})(); +(()=>{var L=Object.keys(window).filter(s=>s.substring(0,2)=="on").map(s=>s.substring(2).toLowerCase()),O=[/\/\*[\s\S]*?\*\//g,/\/\/.*/g],v=[/([a-zA-Z0-9\-,]+)-\[([a-zA-Z0-9 .%#,\-()'"\/:?!]+)\]/g,/((?:\[[a-zA-Z0-9\-@():>,+ ]+\]:)*)\{\s*?((?:[a-zA-Z\-]+-\[[a-zA-Z0-9,%. \-()/ :?!'"#]+\]\s*?)+)\}/g];function b(s,r=0){return s.tagName!=="HTML"?b(s.parentElement,r+1):r}function M(s){return s.split(",").map(t=>t.trim().toLowerCase()).every(t=>L.includes(t))}function E(s){let r="",t=s;for(;t&&t.tagName!=="HTML";){let n=t.tagName.toLowerCase(),o=Array.from(t.parentNode.children).filter(u=>u.tagName===t.tagName).indexOf(t)+1;if(r=`>${n}${o>1?`:nth-of-type(${o})`:""}`+r,t=t.parentNode,t.hasAttribute("data-cijih-current-tag"))return r=`${t.getAttribute("data-cijih-current-tag")}`+r,r}return t.tagName==="HTML"?"html":xpath.substring(1)}function T(s){let r=[],t="",n=0;for(let e=0;eb(n));s=Array.from(s).map((n,e)=>[n,r[e]]),s=s.sort((n,e)=>n[1]-e[1]);for(let n=0;n")){let c=E(e);e.dataset.cijihCurrentTag=c,i[a]=c+i[a]}if(i[a]==="current"){let c=E(e);e.dataset.cijihCurrentTag=c,i[a]=c}}if(N.events){let a=N.events.split(",").map(c=>c.trim().toLowerCase());for(let c of a)e.addEventListener(c,function(){if(i.length>0)for(let m of i){let f=e.querySelectorAll(m),h=g(d);for(let[A,j]of Object.entries(h))f.forEach(q=>q.style.setProperty(A,j))}else{let m=g(d);for(let[f,h]of Object.entries(m))e.style.setProperty(f,h)}})}for(let a of i){let c=document.querySelectorAll(a),m=g(d);for(let[f,h]of Object.entries(m))c.forEach(A=>A.style.setProperty(f,h))}let S=l[0].length,w=" ".repeat(S);e.className=e.className.replace(l[0],w)}let u=e.className.matchAll(v[0]),C=g(e.className);for(let[l,p]of Object.entries(C))e.style.setProperty(l,p);for(let l of u){let p=l[0].length,y=" ".repeat(p);e.className=e.className.replace(l[0],y)}e.className=e.className.trim()}this.document.documentElement.removeAttribute("hidden");let t=document.querySelector("[class]")});})(); diff --git a/build/index.min.js.gz b/build/index.min.js.gz index 7fdf0b8..ae8ae80 100644 Binary files a/build/index.min.js.gz and b/build/index.min.js.gz differ diff --git a/index.js b/index.js deleted file mode 100644 index 3565ccc..0000000 --- a/index.js +++ /dev/null @@ -1,188 +0,0 @@ -function init() { - const EVENTS = getAllEventsNames(); - - function getAllEventsNames() { - const events = Array.from(Object.keys(window).filter(key => /^on/.test(key)).map(e => e.slice(2))); - events.push('hover'); - return events; - } - - function getFullPathToElement(element) { - const path = []; - while (element.tagName !== 'HTML') { - let selector = element.tagName; - if (element.id) { - selector += '#' + element.id; - path.unshift(selector); - break; - } else { - let sib = element, nth = 1; - while (sib = sib.previousElementSibling) { - if (sib.tagName === element.tagName) nth++; - } - if (nth != 1) selector += `:nth-of-type(${nth})`; - } - path.unshift(selector); - element = element.parentElement; - } - path.unshift('HTML'); - return path.join('>'); - } - - function main() { - const elements = document.querySelectorAll('[class*="["]'); - const regularExpressionsComments = [ - /\/\*[\s\S]*?\*\//g, - /\/\/.*/g - ]; - for (const element of elements) { - const matches = element.className.matchAll(regularExpressionsComments[0]); - for (const match of matches) { - element.className = element.className.replace(match[0], '').trim(); - } - const matches2 = element.className.matchAll(regularExpressionsComments[1]); - for (const match of matches2) { - element.className = element.className.replace(match[0], '').trim(); - } - } - const regularExpressions = [ - /([a-zA-Z0-9\-,]+)-\[([a-zA-Z0-9 .%#,\-()'"\/]+)\]/g, - /((?:\[[a-zA-Z0-9\-@():>, ]+\]:)*)\{\s*?((?:[a-zA-Z\-]+-\[[a-zA-Z0-9,%. \-()/ ]+\]\s*?)+)\}/g - ]; - for (const element of elements) { - const matches = element.className.matchAll(regularExpressions[1]); - const generic = { - events: undefined, - media: undefined, - query: undefined, - classes: undefined - } - for (const match of matches) { - element.className = element.className.replace(match[0], '').trim(); - - const split = match[0].split(']:'); - const entry = { ...generic }; - for (let i = 0; i < split.length; i++) { - if (i < split.length - 1) { - split[i] = split[i].trim().slice(1); - } - if (split[i].split(',').every(e => EVENTS.includes(e))) { // is events - entry.events = i - } - else if (split[i].startsWith('@media(')) { // is media - entry.media = i; - } - else if (split[i].startsWith('{') && split[i].endsWith('}')) { // is classes - entry.classes = i; - } - else { // else query - entry.query = i; - } - } - const _entry = Object.entries(entry).sort((a, b) => a[1] - b[1]).filter(e => e[1] !== undefined).map(e => e[0]); - - if (_entry.join(',') === 'events,query,classes') { - const events = split[entry.events].split(','); - const query = split[entry.query].replaceAll(/current\s*,?/g, getFullPathToElement(element) + ','); - const classes = Array.from(split[entry.classes].slice(1, -1).matchAll(regularExpressions[0])).map(e => e.slice(1)); - const elements = document.querySelectorAll(query); - for (const element of elements) { - for (const event of events) { - if (event === 'hover') { - element._style = Object.assign({}, element.style); - element.addEventListener('mouseover', function () { - for (const [property, value] of classes) { - element.style.setProperty(property, value); - } - }); - element.addEventListener('mouseout', function () { - for (const [property, value] of classes) { - element.style.setProperty(property, element._style[property] ?? 'initial'); - } - }); - } - else { - element.addEventListener(event, function () { - for (const [property, value] of classes) { - element.style.setProperty(property, value); - } - }); - } - } - } - - continue; - } - - if (_entry.join(',') === 'query,classes') { - let query = split[entry.query].replaceAll(/current\s*,?/g, getFullPathToElement(element) + ','); - const classes = Array.from(split[entry.classes].slice(1, -1).matchAll(regularExpressions[0])).map(e => e.slice(1)); - if (query.startsWith('>')) { - console.log('before : ', query); - query = getFullPathToElement(element) + query; - console.log('after : ', query); - } - if (query.endsWith(',')) { - query = query.slice(0, -1); - } - const elements = document.querySelectorAll(query); - for (const element of elements) { - for (const [property, value] of classes) { - element.style.setProperty(property, value); - } - } - - continue; - } - - if (_entry.join(',') === 'classes') { - const classes = Array.from(split[entry.classes].slice(1, -1).matchAll(regularExpressions[0])).map(e => e.slice(1)); - for (const [property, value] of classes) { - element.style.setProperty(property, value); - } - - continue; - } - } - - const matches2 = element.className.matchAll(regularExpressions[0]); - for (const match of matches2) { - const [_, property, value] = match; - element.style.setProperty(property, value); - element.className = element.className.replace(_, '').trim(); - } - } - - document.documentElement.setAttribute('aria-busy', 'false'); - - const event = new Event('css-in-js-in-html-ready'); - document.dispatchEvent(event); - } - - main(); -} -let observer; -window.addEventListener('css-in-js-in-html-ready', function () { - if (!observer) { - observer = new MutationObserver((mutationsList) => { - for (const mutation of mutationsList) { - if (mutation.type === 'attributes' && mutation.attributeName === 'class') { - init(); - break; - } - if (mutation.type === 'childList' && (mutation.addedNodes.length || mutation.removedNodes.length)) { - init(); - break; - } - } - }); - - observer.observe(document.body, { - attributes: true, - childList: true, - subtree: true, - attributeFilter: ['class'] - }); - } -}); -document.addEventListener('DOMContentLoaded', init); \ No newline at end of file diff --git a/package.json b/package.json index d98eb0f..45ad052 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "@ulyssear/css-in-js-in-html", - "version": "0.3.8", + "version": "0.4.0", "description": "CSS-in-JS-in-HTML is a library that allows you to use CSS-in-JS with HTML only.", - "main": "build/index.js", + "main": "build/index.min.js", "scripts": { "tests": "echo \"Error: no test specified\" && exit 1", "compress": "node scripts/compress.js", - "build": "npm run compress && esbuild index.js --bundle --outfile=build/index.min.js --minify" + "build": "esbuild src/index.js --bundle --outfile=build/index.min.js --minify && npm run compress && cp src/index.js build/index.js" }, "repository": { "type": "git", diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..6169f5a --- /dev/null +++ b/src/index.js @@ -0,0 +1,211 @@ +const EVENTS = Object.keys(window).filter(e=>e.substring(0,2)=='on').map(e=>e.substring(2).toLowerCase()); + +const REGEXES_COMMENTS = [ + /\/\*[\s\S]*?\*\//g, + /\/\/.*/g +]; +const REGEXES = [ + /([a-zA-Z0-9\-,]+)-\[([a-zA-Z0-9 .%#,\-()'"\/:?!]+)\]/g, + /((?:\[[a-zA-Z0-9\-@():>,+ ]+\]:)*)\{\s*?((?:[a-zA-Z\-]+-\[[a-zA-Z0-9,%. \-()/ :?!'"#]+\]\s*?)+)\}/g +]; + +function getIndexChildren(element,index=0) { + if ('HTML' !== element.tagName) { + return getIndexChildren(element.parentElement,index+1); + } + return index; +} + +function joinArrays(...arrays) { + const newArray = []; + const highestLength = Math.max(...arrays.map(arr => arr.length)); + for (let i = 0; i < highestLength; i++) { + const newElement = []; + for (const arr of arrays) { + newElement.push(arr[i] || null); + } + newArray.push(newElement); + } + return newArray; +} + +function isEvents(string) { + const events = string.split(',').map(e => e.trim().toLowerCase()); + return events.every(e => EVENTS.includes(e)); +} + +function getCurrentDOMPath(element) { + let dompath = ''; + let currentElement = element; + while (currentElement && currentElement.tagName !== 'HTML') { + const tagName = currentElement.tagName.toLowerCase(); + const siblingsWithSameTag = Array.from(currentElement.parentNode.children).filter(child => child.tagName === currentElement.tagName); + const index = siblingsWithSameTag.indexOf(currentElement) + 1; + dompath = `>${tagName}${index > 1 ? `:nth-of-type(${index})` : ''}` + dompath; + currentElement = currentElement.parentNode; + if (currentElement.hasAttribute('data-cijih-current-tag')) { + dompath = `${currentElement.getAttribute('data-cijih-current-tag')}` + dompath; + return dompath; + } + } + if (currentElement.tagName === 'HTML') { + return `html`; + } + return xpath.substring(1); +} + +function getQueries(string) { + const queries = []; + let currentQuery = ''; + let indexBracket = 0; + for (let i = 0; i < string.length; i++) { + const char = string[i]; + if (char === '[') { + indexBracket++; + currentQuery += char; + } else if (char === ']') { + indexBracket--; + currentQuery += char; + } else if (char === ',' && indexBracket === 0) { + queries.push(currentQuery.trim()); + currentQuery = ''; + } else { + currentQuery += char; + } + } + if (currentQuery) { + queries.push(currentQuery.trim()); + } + return queries; +} + +function getGroupsBrackets(string,result={ + media: '', + events: '', + query: '' +}) { + const groups = [] + let j = 0; + for (let i = 0; i < string.length; i++) { + const char = string[i]; + if (char === '[') { + j = i + 1; + while (j < string.length && string[j] !== ']') { + j++; + } + groups.push(string.slice(i, j + 1)); + i = j; + } + } + for (let i = 0; i < groups.length; i++) { + const group = groups[i].substring(1, groups[i].length - 1); + if (group.startsWith('@media(')) { + result.media = group + } else if (isEvents(group)) { + result.events = group + } else { + result.query = group + } + } + return result; +} + +function getStylesFromClasses(classes) { + const styles = {}; + const matches = classes.matchAll(REGEXES[0]); + for (const match of matches) { + const [_, property, value] = match; + styles[property] = value; + } + return styles; +} + +window.addEventListener('DOMContentLoaded', function () { + let elements = document.querySelectorAll('[class]'); + const indexes = Array.from(elements).map(e => getIndexChildren(e)); + elements = Array.from(elements).map((e, i) => [e, indexes[i]]); + elements = elements.sort((a, b) => a[1] - b[1]); + for (let i = 0; i < elements.length; i++) { + const element = elements[i][0]; + + for (const regex of REGEXES_COMMENTS) { + element.className = element.className.replace(regex, ''); + } + + const matchesSecondCase = element.className.matchAll(REGEXES[1]); + + for (const match of matchesSecondCase) { + const [_, groupsBrackets, classes] = match; + const groups = getGroupsBrackets(groupsBrackets); + const queries = getQueries(groups.query); + for (let i = 0; i < queries.length; i++) { + if (queries[i].startsWith('>')) { + const currentDOMPath = getCurrentDOMPath(element); + element.dataset.cijihCurrentTag = currentDOMPath; + queries[i] = currentDOMPath+queries[i]; + } + if ('current'===queries[i]) { + const currentDOMPath = getCurrentDOMPath(element); + element.dataset.cijihCurrentTag = currentDOMPath; + queries[i] = currentDOMPath; + } + } + if (groups.events) { + const events = groups.events.split(',').map(e => e.trim().toLowerCase()); + for (const event of events) { + element.addEventListener(event, function () { + if (queries.length > 0) { + for (const query of queries) { + const elements = element.querySelectorAll(query); + const styles = getStylesFromClasses(classes); + for (const [property, value] of Object.entries(styles)) { + elements.forEach(el => el.style.setProperty(property, value)); + } + } + } + else { + const styles = getStylesFromClasses(classes); + for (const [property, value] of Object.entries(styles)) { + element.style.setProperty(property, value); + } + } + }); + } + } + for (const query of queries) { + const elements = document.querySelectorAll(query); + const styles = getStylesFromClasses(classes); + for (const [property, value] of Object.entries(styles)) { + elements.forEach(el => el.style.setProperty(property, value)); + } + } + const length = match[0].length; + const spaces = ' '.repeat(length); + element.className = element.className.replace(match[0], spaces); + } + + const matchesFirstCase = element.className.matchAll(REGEXES[0]); + const styles = getStylesFromClasses(element.className); + for (const [property, value] of Object.entries(styles)) { + element.style.setProperty(property, value); + } + for (const match of matchesFirstCase) { + const length = match[0].length; + const spaces = ' '.repeat(length); + element.className = element.className.replace(match[0], spaces); + } + element.className = element.className.trim(); + } + this.document.documentElement.removeAttribute('hidden'); + const elementsWithClasses = document.querySelector('[class]'); + for (const element of elementsWithClasses) { + // remove all classes if the element has no classes + if (element.className === '') { + element.removeAttribute('class'); + } + } + const elementsWithData = document.querySelectorAll('[data-cijih-current-tag]'); + for (const element of elementsWithData) { + element.removeAttribute('data-cijih-current-tag'); + } +}); \ No newline at end of file