Compare commits

..

No commits in common. "master" and "add-scroll" have entirely different histories.

19 changed files with 260 additions and 781 deletions

2
.github/FUNDING.yml vendored
View File

@ -1,2 +0,0 @@
github: tanrax
ko_fi: androsfenollosa

307
README.md
View File

@ -1,30 +1,12 @@
# FFNM (Front-End for the next master) # FFNM (Front-End for the next master)
``` html ![example](media/example.png)
<button is-click="class:add('open', 'article')">open</button>
<article></article> Simple utility to **avoid writing Javascript** when working with **classes**. It only takes up **1Kb**!
```
👇 🖱 **Click!** 👇
``` html
<button is-click="class:add('open', 'article')">open</button>
<article class="open"></article>
```
Simple utility to **avoid writing Javascript** when working with **classes**. It only takes up **3.8Kb**!
- Simplifies the **click**.
- Simplifies the **scroll**.
- Simplifies **hover**.
- Simplifies when the elements are **visible** or not.
## DEMOS ## DEMOS
[Click](https://codepen.io/androsfenollosa/pen/dyGdRVE) | [Scroll](https://codepen.io/androsfenollosa/pen/xxZQxNV) | [Visible](https://codepen.io/androsfenollosa/pen/YzwBLGW) [Click](https://codepen.io/androsfenollosa/pen/dyGdRVE)
## Documentation ## Documentation
@ -40,50 +22,29 @@ Simple utility to **avoid writing Javascript** when working with **classes**. It
Add to your `<head>` the following tag. Add to your `<head>` the following tag.
```html ```html
<script src="https://cdn.jsdelivr.net/gh/tanrax/FFNM@1.5.0/dist/ffnm.min.js" integrity="sha384-qlI8XJcMcJMh52x4w9HA9ItB8KmW6pKaJXijVQFl6UvT1nGCH+U6Y7sbbc11HkCH" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/gh/tanrax/FFNM@v1.0.0/dist/ffnm.min.js"></script>
``` ```
### Examples ### Examples
#### Click #### Click
##### Add the class `press` to `button` when the button is pressed.
```html
<button is-click="class:add('press')">open</button>
```
##### Remove the class `press` to `button` when the button is pressed.
```html
<button is-click="class:remove('press')">close</button>
```
##### Switch the classs `show` to `button` when the button is pressed.
```html
<button is-click="class:toggle('show')">view</button>
```
##### Add the class `show` to the `#nav` selector when the button is pressed. ##### Add the class `show` to the `#nav` selector when the button is pressed.
```html ```html
<button is-click="class:add('show', '#nav')">open</button> <button i-click="class:add('show', '#nav')">open</button>
<nav id="nav"></nav>
``` ```
##### Remove the `show` class from the `#nav` selector when the button is pressed. ##### Remove the `show` class from the `#nav` selector when the button is pressed.
```html ```html
<button is-click="class:remove('show', '#nav')">close</button> <button i-click="class:remove('show', '#nav')">close</button>
<nav id="nav" class="show"></nav>
``` ```
##### Switch the `show` class to the `#nav` selector when the button is pressed. ##### Switch the `show` class to the `#nav` selector when the button is pressed.
```html ```html
<button is-click="class:toggle('show', '#nav')">view</button> <button i-click="class:toggle('show', '#nav')">view</button>
<nav id="nav" class="show"></nav>
``` ```
#### Scroll up #### Scroll up
@ -91,13 +52,13 @@ Add to your `<head>` the following tag.
##### Add the class `show` to `nav` when the scroll goes up. ##### Add the class `show` to `nav` when the scroll goes up.
```html ```html
<nav is-scroll-up="class:add('show')"></nav> <nav i-scroll-up="class:add('show')"></nav>
``` ```
##### Remove the `show` class from `nav` when the scroll goes up. ##### Remove the `show` class from `nav` when the scroll goes up.
```html ```html
<nav is-scroll-up="class:remove('show')"></nav> <nav i-scroll-up="class:remove('show')"></nav>
``` ```
#### Scroll down #### Scroll down
@ -105,109 +66,34 @@ Add to your `<head>` the following tag.
##### Add the class `show` to `nav` when the scroll down. ##### Add the class `show` to `nav` when the scroll down.
```html ```html
<nav is-scroll-down="class:add('show')"></nav> <nav i-scroll-down="class:add('show')"></nav>
``` ```
##### Remove the `show` class from `nav` when the scroll down. ##### Remove the `show` class from `nav` when the scroll down.
```html ```html
<nav is-scroll-down="class:remove('show')"></nav> <nav i-scroll-down="class:remove('show')"></nav>
```
#### Scroll top
##### Add the class `show` to `nav` when the scroll is top of the page.
```html
<nav is-scroll-top="class:add('show')"></nav>
```
##### Remove the `show` class from `nav` when the scroll top of the page.
```html
<nav is-scroll-top="class:remove('show')"></nav>
``` ```
#### Hover #### Classes without events
##### Add the class `show` to `div` when hover. ##### Add the class `show` to the `#nav` selector
```html ```javascript
<div is-hover="class:add('show')"></div> class:add('show', '#nav')
``` ```
##### Remove the `show` class from `div` when hover. ##### Remove the `show` class from the `#nav` selector
```html ```javascript
<div is-hover="class:remove('show')"></div> class:remove('show', '#nav')
``` ```
##### Toggle the `show` class from `div` when hover. ##### Switch the class `show` to the `#nav` selector
```html ```javascript
<div is-hover="class:toggle('show')"></div> class:toggle('show', '#nav')
```
##### Add the class `show` to `#button` when `div` hover.
```html
<div is-hover="class:toggle('show', '#button')"></div>
<button id="button">Hi</button>
```
#### Visible
##### Add the class `show` to `div` when is visible.
```html
<div is-visible="class:add('show')"></div>
```
##### Remove the `show` class from `div` when is visible.
```html
<div is-visible="class:remove('show')"></div>
```
##### Toggle the `show` class from `div` when is visible.
```html
<div is-visible="class:toggle('show')"></div>
```
##### Add the class `show` to `#button` when `div` is visible.
```html
<div is-visible="class:toggle('show', '#button')"></div>
<button id="button">Hi</button>
```
#### Not visible
##### Add the class `show` to `div` when is not visible.
```html
<div is-not-visible="class:add('show')"></div>
```
##### Remove the `show` class from `div` when is not visible.
```html
<div is-not-visible="class:remove('show')"></div>
```
##### Toggle the `show` class from `div` when is not visible.
```html
<div is-not-visible="class:toggle('show')"></div>
```
##### Add the class `show` to `#name` when `div` is not visible.
```html
<div is-not-visible="class:toggle('show', '#button')"></div>
<input id="name">
``` ```
--- ---
@ -219,50 +105,29 @@ Add to your `<head>` the following tag.
Añade a tu `<head>` la siguiente etiqueta. Añade a tu `<head>` la siguiente etiqueta.
```html ```html
<script src="https://cdn.jsdelivr.net/gh/tanrax/FFNM@1.5.0/dist/ffnm.min.js" integrity="sha384-qlI8XJcMcJMh52x4w9HA9ItB8KmW6pKaJXijVQFl6UvT1nGCH+U6Y7sbbc11HkCH" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/gh/tanrax/FFNM@v1.0.0/ffnm.min.js"></script>
``` ```
### Ejemplos de uso ### Ejemplos de uso
#### Clic #### Clic
##### Añadir la clase `apretado` a `button` cuando sea pulsado.
```html
<button is-click="class:add('apretado')">Apreta</button>
```
##### Quitar la clase `apretado` a `button` cuando sea pulsado.
```html
<button is-click="class:remove('apretado')">cerrar</button>
```
##### Intercambiar la clase `apretado` a `button` cuando sea pulsado.
```html
<button is-click="class:toggle('apretado')">ver</button>
```
##### Añadir la clase `show` al selector `#menu` cuando sea pulsado el botón. ##### Añadir la clase `show` al selector `#menu` cuando sea pulsado el botón.
```html ```html
<button is-click="class:add('show', '#menu')">abrir</button> <button i-click="class:add('show', '#menu')">abrir</button>
<nav id="menu"></nav>
``` ```
##### Quitar la clase `show` al selector `#menu` cuando sea pulsado el botón. ##### Quitar la clase `show` al selector `#menu` cuando sea pulsado el botón.
```html ```html
<button is-click="class:remove('show', '#menu')">cerrar</button> <button i-click="class:remove('show', '#menu')">cerrar</button>
<nav id="menu" class="show"></nav>
``` ```
##### Intercambiar la clase `show` al selector `#menu` cuando sea pulsado el botón. ##### Intercambiar la clase `show` al selector `#menu` cuando sea pulsado el botón.
```html ```html
<button is-click="class:toggle('show', '#menu')">ver</button> <button i-click="class:toggle('show', '#menu')">ver</button>
<nav id="menu" class="show"></nav>
``` ```
#### Subir scroll #### Subir scroll
@ -270,13 +135,13 @@ Añade a tu `<head>` la siguiente etiqueta.
##### Añadir la clase `show` al selector `nav` cuando el scroll sube. ##### Añadir la clase `show` al selector `nav` cuando el scroll sube.
```html ```html
<nav is-scroll-up="class:add('show')"></nav> <nav i-scroll-up="class:add('show')"></nav>
``` ```
##### Quitar la clase `show` al selector `nav` cuando el scroll sube. ##### Quitar la clase `show` al selector `nav` cuando el scroll sube.
```html ```html
<nav is-scroll-up="class:remove('show')"></nav> <nav i-scroll-up="class:remove('show')"></nav>
``` ```
#### Bajar scroll #### Bajar scroll
@ -284,111 +149,35 @@ Añade a tu `<head>` la siguiente etiqueta.
##### Añadir la clase `show` al selector `nav` cuando el scroll baja. ##### Añadir la clase `show` al selector `nav` cuando el scroll baja.
```html ```html
<nav is-scroll-down="class:add('show')"></nav> <nav i-scroll-down="class:add('show')"></nav>
``` ```
##### Quitar la clase `show` al selector `nav` cuando el scroll baja. ##### Quitar la clase `show` al selector `nav` cuando el scroll baja.
```html ```html
<nav is-scroll-down="class:remove('show')"></nav> <nav i-scroll-down="class:remove('show')"></nav>
```
#### Scroll esta arriba de la pagina (principio)
##### Añadir la clase `show` al selector `nav` cuando el scroll esta al inicio.
```html
<nav is-scroll-top="class:add('show')"></nav>
```
##### Quitar la clase `show` al selector `nav` cuando el scroll esta al inicio.
```html
<nav is-scroll-top="class:remove('show')"></nav>
```
#### Hover
##### Añade la clase `show` al `div` cuando sea hover.
```html
<div is-hover="class:add('show')"></div>
```
##### Quita la clase `show` al `div` cuando sea hover.
```html
<div is-hover="class:remove('show')"></div>
```
##### Intercambia la clase `show` al `div` cuando sea hover.
```html
<div is-hover="class:toggle('show')"></div>
```
##### Añade la clase `show` a `#button` cuando `div` sea hover.
```html
<div is-hover="class:toggle('show', '#button')"></div>
<button id="button">Hi</button>
```
#### Visible
##### Añade la clase `ver` en el `div` cuando es visible.
```html
<div is-visible="class:add('ver')"></div>
```
##### Quita la clase `ver` en el `div` cuando es visible.
```html
<div is-visible="class:remove('ver')"></div>
```
##### Intercambia la clase `ver` cuando el `div` es visible.
```html
<div is-visible="class:toggle('ver')"></div>
```
##### Añade la clase `ver` en `#boton` cuando el `div` es visible.
```html
<div is-visible="class:toggle('ver', '#boton')"></div>
<button id="boton">Hi</button>
```
#### No visible
##### Añade la clase `ver` en el `div` cuando no es visible.
```html
<div is-not-visible="class:add('ver')"></div>
```
##### Quita la clase `ver` en el `div` cuando no es visible.
```html
<div is-not-visible="class:remove('ver')"></div>
```
##### Intercambia la clase `ver` cuando el `div` no es visible.
```html
<div is-not-visible="class:toggle('ver')"></div>
```
##### Añade la clase `ver` en `#boton` cuando el `div` no es visible.
```html
<div is-not-visible="class:toggle('ver', '#boton')"></div>
<button id="boton">Hi</button>
``` ```
#### Clases sin eventos
##### Añadir la clase `show` al selector `#menu`
```javascript
class:add('show', '#menu')
```
##### Quitar la clase `show` al selector `#menu`
```javascript
class:remove('show', '#menu')
```
##### Intercambiar la clase `show` al selector `#menu`
```javascript
class:toggle('show', '#menu')
```
--- ---
## Development ## Development

2
dist/ffnm.min.js vendored
View File

@ -1,2 +1,2 @@
const EVENTS=["is-click","is-scroll-up","is-scroll-down","is-scroll-top","is-hover","is-visible","is-not-visible"],FUNCTION_TREE={class:["add","remove","toggle"]};let elementsValidates=[],lastScrollTop=void 0;function validateSyntax(){return elementsValidates=[],EVENTS.map(e=>[...document.querySelectorAll(`[${e}]`)].map(t=>{let s=Object.keys(FUNCTION_TREE).map(s=>FUNCTION_TREE[s].map(a=>RegExp(`^${s}:${a}\\('.+'(, ?'[.#i\\w][_-\\w0-9]+')?\\)$`).test(t.getAttribute(e))).some(e=>e)).every(e=>e);return s?elementsValidates.push(t):(console.error("FFNM: Bad syntax"),console.error(t)),s}).every(e=>e)).every(e=>e)}function splitParams(e,t){let s=e.getAttribute(t),a=RegExp("^(\\w+):").exec(s)[1],l=RegExp(":(\\w+)\\(").exec(s)[1],i=RegExp("\\('(\\w[_-\\w0-9]+)',?").exec(s)[1],c=RegExp(", ?'([.#i\\w][_-\\w0-9]+)'\\)");return{functionParent:a,functionChild:l,value:i,target:null!==c.exec(s)?c.exec(s)[1]:void 0}}function getElementsValidatesByEvent(e){return[...elementsValidates].filter(t=>t.hasAttribute(e))}function addEventClick(){return getElementsValidatesByEvent("is-click").forEach(e=>{let t=splitParams(e,"is-click");switch(t.functionParent){case"class":[...document.querySelectorAll(t.target)].concat(void 0===t.target?e:void 0).forEach(s=>{void 0!==s&&e.addEventListener("click",()=>{switch(t.functionChild){case"add":s.classList.add(t.value);break;case"remove":s.classList.remove(t.value);break;case"toggle":s.classList.toggle(t.value)}})})}})}function addEventScroll(){let e=getElementsValidatesByEvent("is-scroll-down"),t=getElementsValidatesByEvent("is-scroll-up"),s=getElementsValidatesByEvent("is-scroll-top");window.addEventListener("scroll",()=>{let a=window.pageYOffset||document.documentElement.scrollTop;e.forEach(e=>{if(a>lastScrollTop){let t=splitParams(e,"is-scroll-down");switch(t.functionParent){case"class":switch(t.functionChild){case"add":e.classList.add(t.value);break;case"remove":e.classList.remove(t.value)}}}}),t.forEach(e=>{if(a<=lastScrollTop){let t=splitParams(e,"is-scroll-up");switch(t.functionParent){case"class":switch(t.functionChild){case"add":e.classList.add(t.value);break;case"remove":e.classList.remove(t.value)}}}}),lastScrollTop=a<=0?0:a,s.forEach(e=>{let t=splitParams(e,"is-scroll-top");if(a<=0)switch(t.functionParent){case"class":switch(t.functionChild){case"add":e.classList.add(t.value);break;case"remove":e.classList.remove(t.value)}}else switch(t.functionParent){case"class":switch(t.functionChild){case"add":e.classList.remove(t.value);break;case"remove":e.classList.add(t.value)}}})},!1)}function addEventHover(){return getElementsValidatesByEvent("is-hover").forEach(e=>{let t=splitParams(e,"is-hover");switch(t.functionParent){case"class":[...document.querySelectorAll(t.target)].concat(void 0===t.target?e:void 0).forEach(s=>{if(void 0!==s)switch(t.functionChild){case"add":e.addEventListener("mouseenter",()=>{s.classList.add(t.value)}),e.addEventListener("mouseout",()=>{s.classList.remove(t.value)});break;case"remove":e.addEventListener("mouseenter",()=>{s.classList.remove(t.value)}),e.addEventListener("mouseout",()=>{s.classList.add(t.value)});break;case"toggle":e.addEventListener("mouseenter",()=>{s.classList.toggle(t.value)}),e.addEventListener("mouseout",()=>{s.classList.toggle(t.value)})}})}})}function addEventVisible(){let e=getElementsValidatesByEvent("is-visible"),t=getElementsValidatesByEvent("is-not-visible");const s=new IntersectionObserver(e=>{e.forEach(e=>{let t=e.target;if(e.isIntersecting){let e=splitParams(t,"is-visible");switch(e.functionParent){case"class":switch(e.functionChild){case"add":t.classList.add(e.value);break;case"remove":t.classList.remove(e.value)}}}})});e.forEach(e=>{s.observe(e)});const a=new IntersectionObserver(e=>{e.forEach(e=>{let t=e.target;if(!e.isIntersecting){let e=splitParams(t,"is-not-visible");switch(e.functionParent){case"class":switch(e.functionChild){case"add":t.classList.add(e.value);break;case"remove":t.classList.remove(e.value)}}}})});t.forEach(e=>{a.observe(e)})}document.addEventListener("DOMContentLoaded",()=>{validateSyntax(),addEventClick(),addEventScroll(),addEventHover(),addEventVisible()}); document.addEventListener("DOMContentLoaded",()=>{const e={class:["add","remove","toggle"]};let c=[],t=void 0;function l(e,c){let t=e.getAttribute(c),l=RegExp("^(\\w+):").exec(t)[1],s=RegExp(":(\\w+)\\(").exec(t)[1],a=RegExp("\\('(\\w+)',").exec(t),o=null!==a?a.exec(t)[1]:void 0,r=RegExp(", *'([#,.,a-zA-Z]\\w*)'\\)").exec(t);return{functionParent:l,functionChild:s,value:o,target:null!==r?r.exec(t)[1]:void 0}}c=[],["i-click","i-scroll-up","i-scroll-down"].map(t=>[...document.querySelectorAll(`[${t}]`)].map(l=>{let s=Object.keys(e).map(c=>e[c].map(e=>RegExp(`^${c}:${e}\\('\\w+', *'[#,.,a-zA-Z]\\w*'\\)$`).test(l.getAttribute(t))).some(e=>e)).every(e=>e);return s?c.push(l):(console.error("FFNM: Bad syntax"),console.error(l)),s}).every(e=>e)).every(e=>e),[...document.querySelectorAll("[i-click]")].forEach(e=>{let c=l(e,"i-click");switch(c.functionParent){case"class":[...document.querySelectorAll(c.target)].forEach(t=>{e.addEventListener("click",()=>{switch(c.functionChild){case"add":t.classList.add(c.value);break;case"remove":t.classList.remove(c.value);break;case"toggle":t.classList.toggle(c.value)}})})}}),window.addEventListener("scroll",()=>{let e=window.pageYOffset||document.documentElement.scrollTop;[...document.querySelectorAll("[i-scroll-down]")].forEach(c=>{if(e>t){let e=l(c,"i-scroll-down");switch(e.functionParent){case"class":switch(e.functionChild){case"add":c.classList.add(e.value);break;case"remove":c.classList.remove(e.value)}}}}),[...document.querySelectorAll("[i-scroll-up]")].forEach(c=>{if(e<=t){let e=l(c,"i-scroll-up");switch(e.functionParent){case"class":switch(e.functionChild){case"add":c.classList.add(e.value);break;case"remove":c.classList.remove(e.value)}}}}),t=e<=0?0:e},!1)});
//# sourceMappingURL=ffnm.min.js.map //# sourceMappingURL=ffnm.min.js.map

View File

@ -19,15 +19,7 @@ const DIST_JS = 'ffnm.min.js';
// JS concat + sourcemaps + babel + min // JS concat + sourcemaps + babel + min
function js(cb) { function js(cb) {
return src([ return src([SRC_PATH + 'core.js'])
SRC_PATH + 'globals.js',
SRC_PATH + 'syntax.js',
SRC_PATH + 'events/click.js',
SRC_PATH + 'events/scroll.js',
SRC_PATH + 'events/hover.js',
SRC_PATH + 'events/visible.js',
SRC_PATH + 'core.js'
])
.pipe(sourcemaps.init()) .pipe(sourcemaps.init())
.pipe(concat(DIST_JS)) .pipe(concat(DIST_JS))
.pipe(uglify()) .pipe(uglify())
@ -45,7 +37,7 @@ const build = series(js);
// gulp dev // gulp dev
exports.dev = function () { exports.dev = function () {
build(); build();
watch(SRC_PATH + '**/*.js', js); watch(SRC_PATH + '*.js', js);
} }
// gulp // gulp

BIN
media/example.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

26
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "ffnm", "name": "ffnm",
"version": "1.5.0", "version": "1.0.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -1327,9 +1327,9 @@
} }
}, },
"hosted-git-info": { "hosted-git-info": {
"version": "2.8.9", "version": "2.8.8",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg=="
}, },
"inflight": { "inflight": {
"version": "1.0.6", "version": "1.0.6",
@ -1346,9 +1346,9 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
}, },
"ini": { "ini": {
"version": "1.3.8", "version": "1.3.5",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
}, },
"interpret": { "interpret": {
"version": "1.4.0", "version": "1.4.0",
@ -2006,9 +2006,9 @@
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
}, },
"path-parse": { "path-parse": {
"version": "1.0.7", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
}, },
"path-root": { "path-root": {
"version": "0.1.1", "version": "0.1.1",
@ -2899,9 +2899,9 @@
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
}, },
"y18n": { "y18n": {
"version": "3.2.2", "version": "3.2.1",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
"integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==" "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE="
}, },
"yargs": { "yargs": {
"version": "7.1.1", "version": "7.1.1",

View File

@ -1,6 +1,6 @@
{ {
"name": "ffnm", "name": "ffnm",
"version": "1.5.0", "version": "1.0.0",
"description": "Simple plugin to avoid writing Javascript in trivial tasks.", "description": "Simple plugin to avoid writing Javascript in trivial tasks.",
"main": "gulpfile.js", "main": "gulpfile.js",
"dependencies": { "dependencies": {

View File

@ -1,15 +1,149 @@
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
//===
// VARIABLES
//===
const EVENTS = ['i-click', 'i-scroll-up', 'i-scroll-down'];
const FUNCTION_TREE = {
'class': ['add', 'remove', 'toggle']
};
let elementsValidates = [];
let lastScrollTop = undefined;
//===
// FUNCTIONS
//===
/**
* Method that validates syntax and reports.
* return - Bool
*/
function validateSyntax() {
elementsValidates = [];
// Check all event syntax
return EVENTS.map((event) => {
// Check element FUNCTION_TREE
return [...document.querySelectorAll(`[${event}]`)].map((element) => {
// Check KEY FUNCTION_TREE
let checked = Object.keys(FUNCTION_TREE).map((key) => {
// Check METHODS FUNCTION_TREE
return FUNCTION_TREE[key].map((method) => {
return RegExp(`^${key}:${method}\\('\\w+', *'[#,.,a-zA-Z]\\w*'\\)$`).test(element.getAttribute(event));
}).some(method => method);
}).every(key => key);
if(checked) {
// Save element validate
elementsValidates.push(element);
} else {
// Notify error
console.error('FFNM: Bad syntax');
console.error(element);
}
return checked;
}).every(item => item);
}).every(event => event);
}
/**
* Method return params
* return JSON - {'functionParent': '', 'functionChild': '', 'value': '', 'target': ''}
* example - i-click="class:add('show', '#menu')"
* return {'functionParent': 'class', 'functionChild': 'add', 'value': 'show', 'target': '#menu'}
*/
function splitParams(element, attribute) {
let params = element.getAttribute(attribute);
let functionParent = RegExp(`^(\\w+):`).exec(params)[1];
let functionChild = RegExp(`:(\\w+)\\(`).exec(params)[1];
let resultValue = RegExp(`\\(\'(\\w+)\',`).exec(params);
let value = resultValue !== null ? resultValue.exec(params)[1] : undefined;
let resultTarget = RegExp(`, *\'([#,.,a-zA-Z]\\w*)\'\\)`).exec(params);
let target = resultTarget !== null ? resultTarget.exec(params)[1] : undefined;
return {'functionParent': functionParent, 'functionChild': functionChild, 'value': value, 'target': target};
}
/**
* Method add events i-click
* return void
*/
function addEventClick() {
let eventClick = 'i-click';
return [...document.querySelectorAll(`[${eventClick}]`)].forEach((element) => {
let params = splitParams(element, eventClick);
switch(params.functionParent) {
case 'class':
[...document.querySelectorAll(params.target)].forEach((item) => {
element.addEventListener('click', () => {
switch(params.functionChild) {
case 'add':
item.classList.add(params.value);
break;
case 'remove':
item.classList.remove(params.value);
break;
case 'toggle':
item.classList.toggle(params.value);
break;
}
});
});
break;
}
});
}
/**
* Method add events i-scroll
* return void
*/
function addEventScroll() {
let eventScrollDown = 'i-scroll-down';
let eventScrollUp = 'i-scroll-up';
window.addEventListener("scroll", () => {
let posScroll = window.pageYOffset || document.documentElement.scrollTop;
// Scroll down
[...document.querySelectorAll(`[${eventScrollDown}]`)].forEach((element) => {
if (posScroll > lastScrollTop) {
let params = splitParams(element, eventScrollDown);
switch(params.functionParent) {
case 'class':
switch(params.functionChild) {
case 'add':
element.classList.add(params.value);
break;
case 'remove':
element.classList.remove(params.value);
break;
}
break;
}
}
});
// Scroll up
[...document.querySelectorAll(`[${eventScrollUp}]`)].forEach((element) => {
if (posScroll <= lastScrollTop) {
let params = splitParams(element, eventScrollUp);
switch(params.functionParent) {
case 'class':
switch(params.functionChild) {
case 'add':
element.classList.add(params.value);
break;
case 'remove':
element.classList.remove(params.value);
break;
}
break;
}
}
});
lastScrollTop = posScroll <= 0 ? 0 : posScroll; // For Mobile or negative scrolling
}, false);
}
//=== //===
// INIT // INIT
//=== //===
// Syntax
validateSyntax(); validateSyntax();
// Events
addEventClick(); addEventClick();
addEventScroll(); addEventScroll();
addEventHover();
addEventVisible();
}); });

View File

@ -1,36 +0,0 @@
//===
// FUNCTIONS
//===
/**
* Method add events is-click
* return void
*/
function addEventClick() {
let eventClick = 'is-click';
return getElementsValidatesByEvent(eventClick).forEach((element) => {
let params = splitParams(element, eventClick);
switch(params.functionParent) {
case 'class':
[...document.querySelectorAll(params.target)].concat(params.target === undefined ? element : undefined).forEach((item) => {
if (item !== undefined) {
element.addEventListener('click', () => {
switch(params.functionChild) {
case 'add':
item.classList.add(params.value);
break;
case 'remove':
item.classList.remove(params.value);
break;
case 'toggle':
item.classList.toggle(params.value);
break;
}
});
}
});
break;
}
});
}

View File

@ -1,57 +0,0 @@
//===
// FUNCTIONS
//===
/**
* Method add events is-hover
* return void
*/
function addEventHover() {
let eventHover = 'is-hover';
return getElementsValidatesByEvent(eventHover).forEach((element) => {
let params = splitParams(element, eventHover);
switch(params.functionParent) {
case 'class':
[...document.querySelectorAll(params.target)].concat(params.target === undefined ? element : undefined).forEach((item) => {
if (item !== undefined) {
// Enter
switch(params.functionChild) {
case 'add':
// Enter
element.addEventListener('mouseenter', () => {
item.classList.add(params.value);
});
// Out
element.addEventListener('mouseout', () => {
item.classList.remove(params.value);
});
break;
case 'remove':
// Enter
element.addEventListener('mouseenter', () => {
item.classList.remove(params.value);
});
// Out
element.addEventListener('mouseout', () => {
item.classList.add(params.value);
});
break;
case 'toggle':
// Enter
element.addEventListener('mouseenter', () => {
item.classList.toggle(params.value);
});
// Out
element.addEventListener('mouseout', () => {
item.classList.toggle(params.value);
});
break;
}
}
});
break;
}
});
}

View File

@ -1,93 +0,0 @@
//===
// FUNCTIONS
//===
/**
* Method add events is-scroll
* return void
*/
function addEventScroll() {
const eventScrollDown = 'is-scroll-down';
const eventScrollUp = 'is-scroll-up';
const eventScrollTop = 'is-scroll-top';
let elementsDown = getElementsValidatesByEvent(eventScrollDown);
let elementsUp = getElementsValidatesByEvent(eventScrollUp);
let elementsTop = getElementsValidatesByEvent(eventScrollTop);
window.addEventListener("scroll", () => {
let posScroll = window.pageYOffset || document.documentElement.scrollTop;
// Scroll down - is-scroll-down
elementsDown.forEach((element) => {
if (posScroll > lastScrollTop) {
let params = splitParams(element, eventScrollDown);
switch(params.functionParent) {
case 'class':
switch(params.functionChild) {
case 'add':
element.classList.add(params.value);
break;
case 'remove':
element.classList.remove(params.value);
break;
}
break;
}
}
});
// Scroll up - is-scroll-up
elementsUp.forEach((element) => {
if (posScroll <= lastScrollTop) {
let params = splitParams(element, eventScrollUp);
switch(params.functionParent) {
case 'class':
switch(params.functionChild) {
case 'add':
element.classList.add(params.value);
break;
case 'remove':
element.classList.remove(params.value);
break;
}
break;
}
}
});
lastScrollTop = posScroll <= 0 ? 0 : posScroll; // For Mobile or negative scrolling
// Scroll top - is-scroll-top
elementsTop.forEach((element) => {
let params = splitParams(element, eventScrollTop);
if (posScroll <= 0) {
switch(params.functionParent) {
case 'class':
switch(params.functionChild) {
case 'add':
element.classList.add(params.value);
break;
case 'remove':
element.classList.remove(params.value);
break;
}
break;
}
} else {
switch(params.functionParent) {
case 'class':
switch(params.functionChild) {
case 'add':
element.classList.remove(params.value);
break;
case 'remove':
element.classList.add(params.value);
break;
}
break;
}
}
});
}, false);
}

View File

@ -1,69 +0,0 @@
//===
// FUNCTIONS
//===
/**
* Method that manages the events is-visible and is-not-visible
* return void
*/
function addEventVisible() {
let eventVisible = 'is-visible';
let eventNotVisible = 'is-not-visible';
let elementsVisibles = getElementsValidatesByEvent(eventVisible);
let elementsNotVisibles = getElementsValidatesByEvent(eventNotVisible);
// Visible
const onIntersectionVisible = (entries) => {
entries.forEach((entry) => {
let element = entry.target;
if (entry.isIntersecting) {
let params = splitParams(element, eventVisible);
switch(params.functionParent) {
case 'class':
switch(params.functionChild) {
case 'add':
element.classList.add(params.value);
break;
case 'remove':
element.classList.remove(params.value);
break;
}
break;
}
}
});
};
const observerVisible = new IntersectionObserver(onIntersectionVisible);
elementsVisibles.forEach((element) => {
observerVisible.observe(element);
});
// Not visible
const onIntersectionNotVisible = (entries) => {
entries.forEach((entry) => {
let element = entry.target;
if (!entry.isIntersecting) {
let params = splitParams(element, eventNotVisible);
switch(params.functionParent) {
case 'class':
switch(params.functionChild) {
case 'add':
element.classList.add(params.value);
break;
case 'remove':
element.classList.remove(params.value);
break;
}
break;
}
}
});
};
const observerNotVisible = new IntersectionObserver(onIntersectionNotVisible);
elementsNotVisibles.forEach((element) => {
observerNotVisible.observe(element);
});
}

View File

@ -1,10 +0,0 @@
//===
// VARIABLES
//===
const EVENTS = ['is-click', 'is-scroll-up', 'is-scroll-down', 'is-scroll-top', 'is-hover', 'is-visible', 'is-not-visible'];
const FUNCTION_TREE = {
'class': ['add', 'remove', 'toggle']
};
let elementsValidates = [];
let lastScrollTop = undefined;

View File

@ -1,61 +0,0 @@
//===
// FUNCTIONS
//===
/**
* Method that validates syntax and reports.
* return - Bool
*/
function validateSyntax() {
elementsValidates = [];
// Check all event syntax
return EVENTS.map((event) => {
// Check element FUNCTION_TREE
return [...document.querySelectorAll(`[${event}]`)].map((element) => {
// Check KEY FUNCTION_TREE
let checked = Object.keys(FUNCTION_TREE).map((key) => {
// Check METHODS FUNCTION_TREE
return FUNCTION_TREE[key].map((method) => {
return RegExp(`^${key}:${method}\\('.+'(, ?'[.#i\\w][_-\\w0-9]+')?\\)$`).test(element.getAttribute(event));
}).some(method => method);
}).every(key => key);
if(checked) {
// Save element validate
elementsValidates.push(element);
} else {
// Notify error
console.error('FFNM: Bad syntax');
console.error(element);
}
return checked;
}).every(item => item);
}).every(event => event);
}
/**
* Method return params
* return JSON - {'functionParent': '', 'functionChild': '', 'value': '', 'target': ''}
* example - is-click="class:add('show', '#menu')"
* return {'functionParent': 'class', 'functionChild': 'add', 'value': 'show', 'target': '#menu'}
*/
function splitParams(element, attribute) {
let params = element.getAttribute(attribute);
let functionParent = RegExp("^(\\w+):").exec(params)[1];
let functionChild = RegExp(":(\\w+)\\(").exec(params)[1];
let value = RegExp("\\(\'(\\w[_-\\w0-9]+)\',?").exec(params)[1];
let resultTarget = RegExp(", ?\'([.#i\\w][_-\\w0-9]+)\'\\)");
let target = resultTarget.exec(params) !== null ? resultTarget.exec(params)[1] : undefined;
return {'functionParent': functionParent, 'functionChild': functionChild, 'value': value, 'target': target};
}
/**
* Method that returns all validated elements filtered by an event
* return Array
*/
function getElementsValidatesByEvent(nameEvent) {
return [...elementsValidates].filter(element => {
return element.hasAttribute(nameEvent);
});
}

View File

@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"/> <meta charset="UTF-8"/>
<title>Test is-click</title> <title>Test syntax</title>
<script src="../dist/ffnm.min.js"></script> <script src="../dist/ffnm.min.js"></script>
<style> <style>
.nav { .nav {
@ -21,9 +21,9 @@
</style> </style>
</head> </head>
<body> <body>
<nav class="nav" id="nav" is-click="class:remove('show')">Mi nav</nav> <nav class="nav" id="nav">Mi nav</nav>
<button is-click="class:add('show', '#nav')">add</button> <button i-click="class:add('show', '#nav')">add</button>
<button is-click="class:remove('show', '#nav')">remove</button> <button i-click="class:remove('show', '#nav')">remove</button>
<button is-click="class:toggle('show', '#nav')">toggle</button> <button i-click="class:toggle('show', '#nav')">toggle</button>
</body> </body>
</html> </html>

View File

@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"/> <meta charset="UTF-8"/>
<title>Test is-scroll</title> <title>Test i-scroll</title>
<script src="../dist/ffnm.min.js"></script> <script src="../dist/ffnm.min.js"></script>
<style> <style>
.nav { .nav {
@ -15,31 +15,14 @@
transition: 1s; transition: 1s;
transform: translateY(10rem); transform: translateY(10rem);
} }
.top {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 5rem;
color: white;
background: red;
transition: 1s;
transform: translateY(-10rem);
display: flex;
justify-content: center;
align-items: center;
}
.show { .show {
transform: translateY(0); transform: translateY(0);
} }
</style> </style>
</head> </head>
<body> <body>
<nav is-scroll-down="class:remove('show')" is-scroll-up="class:add('show')" class="nav" id="nav">Mi nav</nav> <nav i-scroll-down="class:remove('show')" i-scroll-up="class:add('show')" class="nav" id="nav">Mi nav</nav>
<div is-scroll-top="class:add('show')" class="top show">You is top page</div> <p i-scroll-down="class:toggle('ala', 'p')">
<p is-scroll-down="class:toggle('ala')">
Ullamcorper morbi tincidunt ornare massa, eget egestas purus viverra accumsan in nisl nisi, scelerisque eu ultrices. Sapien et ligula ullamcorper malesuada proin libero nunc, consequat interdum varius sit amet, mattis. Ullamcorper morbi tincidunt ornare massa, eget egestas purus viverra accumsan in nisl nisi, scelerisque eu ultrices. Sapien et ligula ullamcorper malesuada proin libero nunc, consequat interdum varius sit amet, mattis.
</p> </p>
<p> <p>

View File

@ -1,31 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Test is-hover</title>
<script src="../dist/ffnm.min.js"></script>
<style>
.uppercase {
text-transform: uppercase;
}
</style>
</head>
<body>
<p is-hover="class:add('uppercase', '.text__1--hover')">Place the cursor over this text</p>
<p class="text__1--hover">
Quisque id diam vel quam elementum pulvinar etiam non quam?
</p>
<p class="text__1--hover">
Ac, feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper.
</p>
<p class="text__1--hover" is-hover="class:add('uppercase')">
Nunc aliquet bibendum enim, facilisis gravida neque convallis a cras.
</p>
<p class="text__1--hover">
Orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt tortor.
</p>
<p class="text__1--hover">
Volutpat consequat, mauris nunc congue nisi, vitae suscipit tellus mauris.
</p>
</body>
</html>

View File

@ -1,47 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Test is-visible</title>
<script src="../dist/ffnm.min.js"></script>
<link href="https://unpkg.com/spectre.css/dist/spectre.min.css" rel="stylesheet"/>
<style>
.image-1 {
transition: 1s;
transform: translateY(-2rem);
opacity: 0;
}
.image-2 {
transform: scale(.5);
transition: 1s;
opacity: 0;
}
.show {
transform: scale(1) translateY(0);
opacity: 1;
}
</style>
</head>
<body>
<div class="hero hero-lg">
<div class="hero-body">
<h1 class="text-center">Please scroll down</h1>
</div>
</div>
<p class="text-center">
<img is-visible="class:add('show')" class="image-1" src="https://source.unsplash.com/random/500x300?cat" alt="Image 1">
</p>
<p class="text-center">
<img is-visible="class:add('show')" is-not-visible="class:remove('show')" class="image-2" src="https://source.unsplash.com/random/500x300?dog" alt="Image 2">
</p>
<p class="text-center">
<img is-visible="class:add('show')" is-not-visible="class:remove('show')" class="image-1" src="https://source.unsplash.com/random/500x300?koala" alt="Image 1">
</p>
</body>
</html>

View File

@ -3,114 +3,101 @@
<head> <head>
<meta charset="UTF-8"/> <meta charset="UTF-8"/>
<title>Test syntax</title> <title>Test syntax</title>
<script src="../dist/ffnm.min.js"></script> <script src="../dist/FFNM.min.js"></script>
</head> </head>
<body> <body>
<!-- Class with ID --> <!-- Class with ID -->
<div is-click="class:add('show1', '#menu1')">add</div> <div i-click="class:add('show1', '#menu1')">add</div>
<div is-click="class:remove('show2', '#menu2')">remove</div> <div i-click="class:remove('show2', '#menu2')">remove</div>
<div is-click="class:toggle('show3', '#menu3')">toggle</div> <div i-click="class:toggle('show3', '#menu3')">toggle</div>
<!-- End Class with ID --> <!-- End Class with ID -->
<!-- Class with class --> <!-- Class with class -->
<div is-click="class:add('show1', '.menu1')">add</div> <div i-click="class:add('show1', '.menu1')">add</div>
<div is-click="class:remove('show2', '.menu2')">remove</div> <div i-click="class:remove('show2', '.menu2')">remove</div>
<div is-click="class:toggle('show3', '.menu3')">toggle</div> <div i-click="class:toggle('show3', '.menu3')">toggle</div>
<!-- End Class with class --> <!-- End Class with class -->
<!-- Class with tag --> <!-- Class with tag -->
<div is-click="class:add('show1', 'a')">add</div> <div i-click="class:add('show1', 'a')">add</div>
<div is-click="class:remove('show2', 'li')">remove</div> <div i-click="class:remove('show2', 'li')">remove</div>
<div is-click="class:toggle('show3', 'button')">toggle</div> <div i-click="class:toggle('show3', 'button')">toggle</div>
<!-- End Class with tag --> <!-- End Class with tag -->
<!-- Class with ID --> <!-- Class with ID -->
<div is-scroll-up="class:add('show1', '#menu1')">add</div> <div i-scroll-up="class:add('show1', '#menu1')">add</div>
<div is-scroll-up="class:remove('show2', '#menu2')">remove</div> <div i-scroll-up="class:remove('show2', '#menu2')">remove</div>
<div is-scroll-up="class:toggle('show3', '#menu3')">toggle</div> <div i-scroll-up="class:toggle('show3', '#menu3')">toggle</div>
<!-- End Class with ID --> <!-- End Class with ID -->
<!-- Class with class --> <!-- Class with class -->
<div is-scroll-up="class:add('show1', '.menu1')">add</div> <div i-scroll-up="class:add('show1', '.menu1')">add</div>
<div is-scroll-up="class:remove('show2', '.menu2')">remove</div> <div i-scroll-up="class:remove('show2', '.menu2')">remove</div>
<div is-scroll-up="class:toggle('show3', '.menu3')">toggle</div> <div i-scroll-up="class:toggle('show3', '.menu3')">toggle</div>
<!-- End Class with class --> <!-- End Class with class -->
<!-- Class with tag --> <!-- Class with tag -->
<div is-scroll-up="class:add('show1', 'a')">add</div> <div i-scroll-up="class:add('show1', 'a')">add</div>
<div is-scroll-up="class:remove('show2', 'li')">remove</div> <div i-scroll-up="class:remove('show2', 'li')">remove</div>
<div is-scroll-up="class:toggle('show3', 'button')">toggle</div> <div i-scroll-up="class:toggle('show3', 'button')">toggle</div>
<!-- End Class with tag --> <!-- End Class with tag -->
<!-- Class with ID --> <!-- Class with ID -->
<div is-scroll-down="class:add('show1', '#menu1')">add</div> <div i-scroll-down="class:add('show1', '#menu1')">add</div>
<div is-scroll-down="class:remove('show2', '#menu2')">remove</div> <div i-scroll-down="class:remove('show2', '#menu2')">remove</div>
<div is-scroll-down="class:toggle('show3', '#menu3')">toggle</div> <div i-scroll-down="class:toggle('show3', '#menu3')">toggle</div>
<!-- End Class with ID --> <!-- End Class with ID -->
<!-- Class with class --> <!-- Class with class -->
<div is-scroll-down="class:add('show1', '.menu1')">add</div> <div i-scroll-down="class:add('show1', '.menu1')">add</div>
<div is-scroll-down="class:remove('show2', '.menu2')">remove</div> <div i-scroll-down="class:remove('show2', '.menu2')">remove</div>
<div is-scroll-down="class:toggle('show3', '.menu3')">toggle</div> <div i-scroll-down="class:toggle('show3', '.menu3')">toggle</div>
<!-- End Class with class --> <!-- End Class with class -->
<!-- Class with tag --> <!-- Class with tag -->
<div is-scroll-down="class:add('show1', 'a')">add</div> <div i-scroll-down="class:add('show1', 'a')">add</div>
<div is-scroll-down="class:remove('show2', 'li')">remove</div> <div i-scroll-down="class:remove('show2', 'li')">remove</div>
<div is-scroll-down="class:toggle('show3', 'button')">toggle</div> <div i-scroll-down="class:toggle('show3', 'button')">toggle</div>
<!-- End Class with tag --> <!-- End Class with tag -->
<!-- Class with ID --> <!-- Class with ID -->
<div is-hover="class:add('show1', '#menu1')">add</div> <div i-hover="class:add('show1', '#menu1')">add</div>
<div is-hover="class:remove('show2', '#menu2')">remove</div> <div i-hover="class:remove('show2', '#menu2')">remove</div>
<div is-hover="class:toggle('show3', '#menu3')">toggle</div> <div i-hover="class:toggle('show3', '#menu3')">toggle</div>
<!-- End Class with ID --> <!-- End Class with ID -->
<!-- Class with class --> <!-- Class with class -->
<div is-hover="class:add('show1', '.menu1')">add</div> <div i-hover="class:add('show1', '.menu1')">add</div>
<div is-hover="class:remove('show2', '.menu2')">remove</div> <div i-hover="class:remove('show2', '.menu2')">remove</div>
<div is-hover="class:toggle('show3', '.menu3')">toggle</div> <div i-hover="class:toggle('show3', '.menu3')">toggle</div>
<!-- End Class with class --> <!-- End Class with class -->
<!-- Class with tag --> <!-- Class with tag -->
<div is-hover="class:add('show1', 'a')">add</div> <div i-hover="class:add('show1', 'a')">add</div>
<div is-hover="class:remove('show2', 'li')">remove</div> <div i-hover="class:remove('show2', 'li')">remove</div>
<div is-hover="class:toggle('show3', 'button')">toggle</div> <div i-hover="class:toggle('show3', 'button')">toggle</div>
<!-- End Class with tag --> <!-- End Class with tag -->
<!-- Class with ID --> <!-- Class with ID -->
<div is-visible="class:add('show1', '#menu1')">add</div> <div i-view="class:add('show1', '#menu1')">add</div>
<div is-visible="class:remove('show2', '#menu2')">remove</div> <div i-view="class:remove('show2', '#menu2')">remove</div>
<div i-view="class:toggle('show3', '#menu3')">toggle</div>
<!-- End Class with ID --> <!-- End Class with ID -->
<!-- Class with class --> <!-- Class with class -->
<div is-visible="class:add('show1', '.menu1')">add</div> <div i-view="class:add('show1', '.menu1')">add</div>
<div is-visible="class:remove('show2', '.menu2')">remove</div> <div i-view="class:remove('show2', '.menu2')">remove</div>
<div i-view="class:toggle('show3', '.menu3')">toggle</div>
<!-- End Class with class --> <!-- End Class with class -->
<!-- Class with tag --> <!-- Class with tag -->
<div is-visible="class:add('show1', 'a')">add</div> <div i-view="class:add('show1', 'a')">add</div>
<div is-visible="class:remove('show2', 'li')">remove</div> <div i-view="class:remove('show2', 'li')">remove</div>
<div i-view="class:toggle('show3', 'button')">toggle</div>
<!-- End Class with tag --> <!-- End Class with tag -->
<!-- Class with ID -->
<div is-not-visible="class:add('show1', '#menu1')">add</div>
<div is-not-visible="class:remove('show2', '#menu2')">remove</div>
<!-- End Class with ID -->
<!-- Class with class -->
<div is-not-visible="class:add('show1', '.menu1')">add</div>
<div is-not-visible="class:remove('show2', '.menu2')">remove</div>
<!-- End Class with class -->
<!-- Class with tag -->
<div is-not-visible="class:add('show1', 'a')">add</div>
<div is-not-visible="class:remove('show2', 'li')">remove</div>
<!-- End Class with tag -->
<!-- Errors --> <!-- Errors -->
<div is-click="class:dd('show1', '.menu1')">add</div> <div i-click="class:dd('show1', '.menu1')">add</div>
</body> </body>
</html> </html>