Skip to content

Commit

Permalink
use EventsManager & add configs.js (#45)
Browse files Browse the repository at this point in the history
* Use events manger (#44)

* feat: use events manger

* fix: remove redundant code

* fix: add bracket for data-ea in DEFAULTS variable

* fix: format code

* fix: return default back

* fix: add comma

* fix: add comma

* fix: remove configs file and add on method

* fix: add comma

* fix: add comma

* fix: add bracket for target

* docs: update README.md

* Add config file (#43)

* feat: add config file

* fix: format code

* fix: add defaults to configs.js

* fix: add comma

* fix: add comma

* fix: replace fire event and add eventsManager

* fix: add on method

---------

Co-authored-by: Pau15122 <[email protected]>
  • Loading branch information
phucbm and vandangnhathung authored Aug 3, 2023
1 parent b108b3c commit 07feeee
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 92 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ Add these attributes on the wrapper element.
| `destroy` | `eta.destroy()` | Remove all style and events |
| `init` | `eta.init()` | Could be use after destroy |
| `update` | `eta.update()` | Update styling |
| `on` | `eta.on()` | Assign events |

Get the instance with JS init

Expand All @@ -229,6 +230,9 @@ const eta = ETA.get('my-eta');

// use methods
eta.update();
eta.on("open", () => {
// do something
});
```

## Deployment
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,8 @@
"webpack-cli": "^4.9.0",
"webpack-dev-server": "^4.3.1",
"webpack-merge": "^5.8.0"
},
"dependencies": {
"@phucbm/os-util": "^0.0.4"
}
}
111 changes: 30 additions & 81 deletions src/_index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,80 +8,19 @@ import {
getElements,
removeActiveClass, addActiveClass, getIdByIndex, log, getOptions
} from "./helpers";
import {debounce, uniqueId} from "./utils";
import {debounce} from "./utils";
import {initSetup, onLoad, onResize} from "./methods";
import {isLive, validBreakpoints} from "./responsive";
import {scrollIntoView} from "./animation";
import {CLASSES, ATTRS, DEFAULTS} from './configs';
import {EventsManager} from "@phucbm/os-util";

export class EasyTabAccordion{
constructor(options){
this._class = {
enabled: 'easy-tab-accordion-enabled',
active: 'active',
hasAssignedTriggerEvent: 'assigned-trigger-event'
};
this._attr = {
container: 'data-eta',
trigger: 'data-eta-trigger',
receiver: 'data-eta-receiver',
hash: 'data-eta-hash',
hashScroll: 'data-eta-hash-scroll',
animation: 'data-eta-animation',
};
this.defaultOptions = {
// selectors
el: document.querySelector(`[${this._attr.container}]`), // DOM element
id: uniqueId('eta-'),
trigger: `[${this._attr.trigger}]`, // string selector
triggerAttr: this._attr.trigger, // attribute name
receiver: `[${this._attr.receiver}]`, // string selector
receiverAttr: this._attr.receiver, // attribute name
activeClass: this._class.active,

// animation
animation: 'slide', // slide, fade
duration: 450,
scrollIntoView: false, // scroll panel into view when open

// hash
hash: false, // update hash URL
hashScroll: false, // scroll into view when page loaded with a valid hash

// responsive
liveBreakpoint: [], // [1920, 1024] => destroy if window.width if bigger than 1920 or less than 1024

// avoid double click
avoidDoubleClick: true,

// dev mode => enable console.log
dev: false,

// open/close
activeSection: 0, // default opening sections, will be ignored if there's a valid hash, allow array of index [0,1,2] for slide animation only
allowCollapseAll: false, // for slide animation only
allowExpandAll: false, // for slide animation only

// prevent default when click to trigger element
isPreventDefault: true,

// events
onBeforeInit: (data) => {
},
onAfterInit: (data) => {
},
onBeforeOpen: (data, el) => {
},
onBeforeClose: (data, el) => {
},
onAfterOpen: (data, el) => {
},
onAfterClose: (data, el) => {
},
onDestroy: (data) => {
},
onUpdate: (data) => {
},
};
// init events manager
this.events = new EventsManager(this, {
names: ['onBeforeInit', 'onAfterInit', 'onBeforeOpen', 'onBeforeClose', 'onAfterOpen', 'onAfterClose', 'onDestroy', 'onUpdate'],
})

// save options
this.originalOptions = options;
Expand All @@ -92,9 +31,19 @@ export class EasyTabAccordion{
this.isAnimating = false;
}

/******************************
* EVENTS
******************************/
/**
* Assign late-events
*/
on(eventName, callback){
this.events.add(eventName, callback);
};

init(){
// setup
this.options = {...this.defaultOptions, ...this.originalOptions};
this.options = {...DEFAULTS, ...this.originalOptions};

if(!this.options.el){
log(this, 'warn', 'ETA Error, target not found!');
Expand All @@ -111,7 +60,7 @@ export class EasyTabAccordion{
this.count = this.wrapper.querySelectorAll(this.options.trigger).length;

// check if ETA has already initialized
if(this.wrapper.classList.contains(this._class.enabled)){
if(this.wrapper.classList.contains(CLASSES.enabled)){
log(this, 'ETA has initialized');
return;
}
Expand All @@ -120,17 +69,17 @@ export class EasyTabAccordion{
this.isFirst = true;

// update hash from attribute
this.options.hash = this.wrapper.hasAttribute(this._attr.hash) === true ? true : this.options.hash;
this.options.hashScroll = this.wrapper.hasAttribute(this._attr.hashScroll) === true ? true : this.options.hashScroll;
this.options.hash = this.wrapper.hasAttribute(ATTRS.hash) === true ? true : this.options.hash;
this.options.hashScroll = this.wrapper.hasAttribute(ATTRS.hashScroll) === true ? true : this.options.hashScroll;
// update animation from attribute
const animationValue = this.wrapper.getAttribute(this._attr.animation);
const animationValue = this.wrapper.getAttribute(ATTRS.animation);
this.options.animation = animationValue !== null ? animationValue : this.options.animation;

// get options init by data attribute (JSON format)
this.options = getOptions(this);

// assign id to wrapper
this.wrapper.setAttribute(this._attr.container, this.id);
this.wrapper.setAttribute(ATTRS.container, this.id);

if(this.count < 1){
log(this, 'warn', 'Quit init due to child panels not found', this);
Expand All @@ -148,7 +97,7 @@ export class EasyTabAccordion{

destroy(){
this.hasInitialized = false;
this.wrapper.classList.remove(this._class.enabled);
this.wrapper.classList.remove(CLASSES.enabled);

// loop through triggers
this.wrapper.querySelectorAll(this.options.trigger).forEach(trigger => {
Expand All @@ -169,7 +118,7 @@ export class EasyTabAccordion{
}

// event: onDestroy
this.options.onDestroy(this);
this.events.fire('onDestroy');
}

update(){
Expand All @@ -183,7 +132,7 @@ export class EasyTabAccordion{
}

// event: onUpdate
this.options.onUpdate(this);
this.events.fire('onUpdate');
}

openPanel(id = this.current_id){
Expand All @@ -197,7 +146,7 @@ export class EasyTabAccordion{
updateURL(this, id);

// events
this.options.onBeforeOpen(this);
this.events.fire('onBeforeOpen');
};

// event: on Before Open
Expand All @@ -216,7 +165,7 @@ export class EasyTabAccordion{
this.isAnimating = false;
log(this, 'log', 'Stop animation.');

this.options.onAfterOpen(this, target);
this.events.fire('onAfterOpen', {target});

// log
log(this, 'log', 'after open', id);
Expand Down Expand Up @@ -253,12 +202,12 @@ export class EasyTabAccordion{
if(!validID(this, id)) return;

// event: on Before Close
this.options.onBeforeClose(this);
this.events.fire('onBeforeClose');

// event: on After Close
this.dataset[getIndexById(this, id)].active = false;
const afterClose = (target) => {
this.options.onAfterClose(this, target);
this.events.fire('onAfterClose', {target});

// toggle animating status
this.isAnimating = false;
Expand Down
60 changes: 60 additions & 0 deletions src/configs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import {uniqueId} from './utils'

/**
* Classes
* */
export const CLASSES = {
enabled: 'easy-tab-accordion-enabled',
active: 'active',
hasAssignedTriggerEvent: 'assigned-trigger-event',
};
/**
* Attributes
* */
export const ATTRS = {
container: 'data-eta',
trigger: 'data-eta-trigger',
receiver: 'data-eta-receiver',
hash: 'data-eta-hash',
hashScroll: 'data-eta-hash-scroll',
animation: 'data-eta-animation',
};
/**
* Defaults
* */
export const DEFAULTS = {
// selectors
el: document.querySelector('[data-eta]'), // DOM element
id: uniqueId('eta-'),
trigger: '[data-eta-trigger]', // string selector
triggerAttr: 'data-eta-trigger', // attribute name
receiver: '[data-eta-receiver]', // string selector
receiverAttr: 'data-eta-receiver', // attribute name
activeClass: 'active',

// animation
animation: 'slide', // slide, fade
duration: 450,
scrollIntoView: false, // scroll panel into view when open

// hash
hash: false, // update hash URL
hashScroll: false, // scroll into view when page loaded with a valid hash

// responsive
liveBreakpoint: [], // [1920, 1024] => destroy if window.width if bigger than 1920 or less than 1024

// avoid double click
avoidDoubleClick: true,

// dev mode => enable console.log
dev: false,

// open/close
activeSection: 0, // default opening sections, will be ignored if there's a valid hash, allow array of index [0,1,2] for slide animation only
allowCollapseAll: false, // for slide animation only
allowExpandAll: false, // for slide animation only

// prevent default when click to trigger element
isPreventDefault: true,
};
12 changes: 6 additions & 6 deletions src/helpers.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {arrayUnique} from "./utils";

import {CLASSES, ATTRS} from './configs'

/**
* Has valid id
Expand Down Expand Up @@ -166,8 +166,8 @@ export function removeActiveClass(context, id){
const {current, currentTrigger} = getElements(context, id);

// update classes
current.forEach(item => item.classList.remove(context._class.active));
currentTrigger.forEach(item => item.classList.remove(context._class.active));
current.forEach(item => item.classList.remove(CLASSES.active));
currentTrigger.forEach(item => item.classList.remove(CLASSES.active));
}


Expand All @@ -181,8 +181,8 @@ export function addActiveClass(context, id){
const {current, currentTrigger} = getElements(context, id ? id : context.current_id);

// update classes
if(current) current.forEach(item => item.classList.add(context._class.active));
if(currentTrigger) currentTrigger.forEach(item => item.classList.add(context._class.active));
if(current) current.forEach(item => item.classList.add(CLASSES.active));
if(currentTrigger) currentTrigger.forEach(item => item.classList.add(CLASSES.active));
}

export function log(context, status, ...message){
Expand All @@ -207,7 +207,7 @@ export function getOptions(context, defaultOptions){
const wrapper = context.wrapper;

// options from attribute
let dataAttribute = wrapper.getAttribute(context._attr.container);
let dataAttribute = wrapper.getAttribute(ATTRS.container);
let options = {};

// data attribute doesn't exist or not JSON format -> string
Expand Down
11 changes: 6 additions & 5 deletions src/methods.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@ import {responsive} from "./responsive";
import {setCSS, setTransition} from "./animation";
import {getHash, isValidHash} from "./hash";
import {defaultActiveSections} from "./helpers";
import {CLASSES} from './configs';

export function initSetup(context){
// event: onBeforeInit
context.options.onBeforeInit(context);
context.events.fire("onBeforeInit");

context.wrapper.classList.add(context._class.enabled);
context.wrapper.classList.add(CLASSES.enabled);

// loop through triggers
context.wrapper.querySelectorAll(context.options.trigger).forEach(trigger => {
// assign click event
trigger.addEventListener('click', e => manualTriggerFunction(context, e));

// add a class to check if the trigger has assigned an event
trigger.classList.add(context._class.hasAssignedTriggerEvent);
trigger.classList.add(CLASSES.hasAssignedTriggerEvent);
});

// loop through receivers
Expand Down Expand Up @@ -63,7 +64,7 @@ export function initSetup(context){
context.hasInitialized = true;

// event: onAfterInit
context.options.onAfterInit(context);
context.events.fire("onAfterInit");
}

function assignTriggerElements(context){
Expand All @@ -77,7 +78,7 @@ function assignTriggerElements(context){
context.dataset.forEach(item => {
if(item.id === id){
// already assigned trigger event
if(trigger.classList.contains(context._class.hasAssignedTriggerEvent)) return;
if(trigger.classList.contains(CLASSES.hasAssignedTriggerEvent)) return;

// valid trigger
trigger.addEventListener('click', e => {
Expand Down

0 comments on commit 07feeee

Please sign in to comment.