Skip to content

Commit

Permalink
Merge pull request #56 from viivue/2.3.0
Browse files Browse the repository at this point in the history
2.3.0
  • Loading branch information
phucbm authored Sep 29, 2023
2 parents 8a58382 + ae9c3a9 commit 4f4aee9
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 74 deletions.
43 changes: 24 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import "@viivue/easy-tab-accordion";

```html
<!-- JS (10KB) -->
<script src="https://cdn.jsdelivr.net/gh/viivue/easy-tab-accordion@2.2.0/dist/easy-tab-accordion.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/viivue/easy-tab-accordion@2.3.0/dist/easy-tab-accordion.min.js"></script>
```

## Initialize
Expand Down Expand Up @@ -197,27 +197,29 @@ Add these attributes on the wrapper element.

## Events

| Name | Description |
|----------------------------------|-------------|
| `onBeforeInit: (data) => {}` | |
| `onAfterInit: (data) => {}` | |
| `onBeforeOpen: (data,el) => {}` | |
| `onBeforeClose: (data,el) => {}` | |
| `onAfterOpen: (data,el) => {}` | |
| `onAfterClose: (data,el) => {}` | |
| `onDestroy: (data) => {}` | |
| `onUpdate: (data) => {}` | |
| Name | Description |
|-------------------------------|-------------|
| `onBeforeInit: (data) => {}` | |
| `onAfterInit: (data) => {}` | |
| `onBeforeOpen: (data) => {}` | |
| `onBeforeClose: (data) => {}` | |
| `onAfterOpen: (data) => {}` | |
| `onAfterClose: (data) => {}` | |
| `onDestroy: (data) => {}` | |
| `onUpdate: (data) => {}` | |

## Methods

| Name | Usage | Description |
|-----------------|----------------------------|-----------------------------|
| `toggle` | `eta.toggle(id)` | Toggle a section by ID |
| `toggleByIndex` | `eta.toggleByIndex(index)` | Toggle a section by index |
| `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 |
| Name | Usage | Description |
|-----------------|-------------------------------------------|-----------------------------------------------------------------------|
| `toggle` | `eta.toggle(panelId)` | Toggle a panel |
| `openPanel` | `eta.openPanel(panelId, isStrict=false)` | Open a panel. Turn `isStrict` on to only open is currently closing. |
| `closePanel` | `eta.closePanel(panelId, isStrict=false)` | Close a panel. Turn `isStrict` on to only close is currently opening. |
| `toggleByIndex` | `eta.toggleByIndex(index)` | Toggle a section by index |
| `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 Down Expand Up @@ -246,6 +248,9 @@ npm run prod

# Build dev site (for Netlify only)
npm run build

# Research replace to set new version
npm publish
```

## License
Expand Down
2 changes: 1 addition & 1 deletion dev/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ <h2 class="heading-separator"><span>Tab</span></h2>

<h2 class="heading-separator"><span>Accordion initialize with JSON format</span></h2>

<div data-eta='{ "id":"my-id", "animation":"slide", "hash":"false", "duration":"1000", "isPreventDefault": "true"}'>
<div data-eta='{ "id":"init-with-json", "animation":"slide", "hash":"false", "duration":"1000", "isPreventDefault": "true"}'>
<!-- section 1 -->
<div>
<a href="https://github.com" target="_blank" data-eta-trigger="section-1">Section 1</a>
Expand Down
4 changes: 2 additions & 2 deletions dist/easy-tab-accordion.min.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/easy-tab-accordion.module.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@viivue/easy-tab-accordion",
"filename": "easy-tab-accordion",
"prettyName": "Easy Tabs & Accordion",
"version": "2.2.0",
"version": "2.3.0",
"description": "Javascript library to create tabs or accordion.",
"homepage": "https://github.com/viivue/easy-tab-accordion",
"repository": {
Expand Down
91 changes: 58 additions & 33 deletions src/_index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import {hashScroll, updateURL} from "./hash";
import {
validID,
getToggleState,
getIndexById,
getPanelIndexById,
getElements,
removeActiveClass, addActiveClass, getIdByIndex, log
} from "./helpers";
import {debounce} from "./utils";
import {debounce, uniqueId} from "./utils";
import {initSetup, onLoad, onResize} from "./methods";
import {isLive, validBreakpoints} from "./responsive";
import {scrollIntoView} from "./animation";
Expand All @@ -17,24 +17,27 @@ import {EventsManager, getOptionsFromAttribute} from "@phucbm/os-util";

export class EasyTabAccordion{
constructor(options){
// init events manager
this.events = new EventsManager(this, {
names: ['onBeforeInit', 'onAfterInit', 'onBeforeOpen', 'onBeforeClose', 'onAfterOpen', 'onAfterClose', 'onDestroy', 'onUpdate'],
})

// save options
this.originalOptions = options;
// update options
this.options = {...DEFAULTS, id: uniqueId('eta-'), ...options};
if(!this.options.el){
log(this, 'warn', 'ETA Error, target not found!');
return;
}

// get options init by data attribute (JSON format)
this.options
= getOptionsFromAttribute({
target: this.wrapper,
defaultOptions: {...DEFAULTS, ...options},
this.options = getOptionsFromAttribute({
target: this.options.el,
defaultOptions: this.options,
attributeName: ATTRS.container,
numericValues: ['duration', 'activeSection'],
dev: DEFAULTS.dev
});

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

// init
this.init();

Expand All @@ -53,13 +56,8 @@ export class EasyTabAccordion{
};

init(){
if(!this.options.el){
log(this, 'warn', 'ETA Error, target not found!');
return;
}

this.wrapper = this.options.el;
this.id = '';
this.id = this.options.id;
this.current_id = '';
this.previous_id = '';
this.type = '';
Expand Down Expand Up @@ -100,6 +98,9 @@ export class EasyTabAccordion{
window.addEventListener('load', e => onLoad(this, e));
}

/******************************
* Methods: ETA
******************************/
destroy(){
this.hasInitialized = false;
this.wrapper.classList.remove(CLASSES.enabled);
Expand Down Expand Up @@ -140,15 +141,27 @@ export class EasyTabAccordion{
this.events.fire('onUpdate');
}

openPanel(id = this.current_id){
if(!validID(this, id)) return;

/******************************
* Methods: Panel
******************************/
openPanel(panelId = this.current_id, isStrict = false){
if(!validID(this, panelId)) return;
const panel = this.getPanelByID(panelId);

// only open when is currently closing
if(isStrict && panel.active){
log(this, 'warn', `openPanel(${panelId}) does not run as the panel is already opened!`);
return;
}

const beforeOpen = () => {
// update section status
this.dataset[getIndexById(this, id)].active = true;
//this.dataset[getPanelIndexById(this, id)].active = true;
this.getPanelByID(panelId).active = true;

// update URL
updateURL(this, id);
updateURL(this, panelId);

// events
this.events.fire('onBeforeOpen', {
Expand Down Expand Up @@ -182,11 +195,11 @@ export class EasyTabAccordion{
});

// log
log(this, 'log', 'after open', id);
log(this, 'log', 'after open', panelId);
};

// open
const {current} = getElements(this, id);
const {current} = getElements(this, panelId);
switch(this.options.animation){
case 'slide':
current.forEach(el => slideDown(el, this.options.duration, () => afterOpen(el)));
Expand All @@ -197,11 +210,11 @@ export class EasyTabAccordion{
}

// update classes
addActiveClass(this, id);
addActiveClass(this, panelId);

// close all others
const closeAllOthers = this.options.animation === 'fade' || this.options.animation === 'slide' && !this.options.allowExpandAll;
if(closeAllOthers) this.dataset.filter(x => x.id !== id).forEach(item => {
if(closeAllOthers) this.dataset.filter(x => x.id !== panelId).forEach(item => {
if(item.active || this.isFirst){
this.closePanel(item.id);
}
Expand All @@ -212,8 +225,15 @@ export class EasyTabAccordion{
}
}

closePanel(id = this.current_id){
if(!validID(this, id)) return;
closePanel(panelId = this.current_id, isStrict = false){
if(!validID(this, panelId)) return;
const panel = this.getPanelByID(panelId);

// only open when is currently closing
if(isStrict && !panel.active){
console.warn(`closePanel(${panelId}) does not run as the panel is already closed!`);
return;
}

// event: on Before Close
this.events.fire('onBeforeClose', {
Expand All @@ -223,7 +243,8 @@ export class EasyTabAccordion{
});

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

Expand All @@ -232,11 +253,11 @@ export class EasyTabAccordion{
log(this, 'log', 'Stop animation.');

// log
log(this, 'log', 'after close', id);
log(this, 'log', 'after close', panelId);
};

// close animation
const {current} = getElements(this, id);
const {current} = getElements(this, panelId);
switch(this.options.animation){
case 'slide':
current.forEach(el => slideUp(el, this.options.duration, () => afterClose(el)));
Expand All @@ -247,7 +268,11 @@ export class EasyTabAccordion{
}

// update classes
removeActiveClass(this, id);
removeActiveClass(this, panelId);
}

getPanelByID(panelId){
return this.dataset[getPanelIndexById(this, panelId)];
}

toggle(id, type = 'undefined', force = false){
Expand Down
7 changes: 2 additions & 5 deletions src/configs.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import {uniqueId} from './utils'

/**
* Classes
* */
export const CLASSES = {
enabled: 'easy-tab-accordion-enabled',
active: 'active',
hasAssignedTriggerEvent: 'assigned-trigger-event',
};
/**
Expand All @@ -24,8 +21,8 @@ export const ATTRS = {
* */
export const DEFAULTS = {
// selectors
el: document.querySelector('[data-eta]'), // DOM element
id: uniqueId('eta-'),
el: undefined, // DOM element
id: undefined,
trigger: '[data-eta-trigger]', // string selector
triggerAttr: 'data-eta-trigger', // attribute name
receiver: '[data-eta-receiver]', // string selector
Expand Down
21 changes: 10 additions & 11 deletions src/helpers.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {arrayUnique} from "./utils";
import {CLASSES, ATTRS} from './configs'

/**
* Has valid id
Expand Down Expand Up @@ -36,7 +35,7 @@ export function getToggleState(context, id){
}
}

const open = context.dataset[getIndexById(context, id)].active;
const open = context.dataset[getPanelIndexById(context, id)].active;
const allowCollapseAll = context.options.animation === 'slide' ? context.options.allowCollapseAll : false;

// is open and allow collapse all => close
Expand Down Expand Up @@ -133,19 +132,19 @@ export function getElements(context, id){


/**
* Get index by ID
* Get panel index by panel ID
* @param context
* @param id
* @param panelId
* @returns {number}
* @since 2.0.0
*/
export function getIndexById(context, id){
return context.dataset.findIndex(x => x.id === id);
export function getPanelIndexById(context, panelId){
return context.dataset.findIndex(x => x.id === panelId);
}


/**
* Get ID by index
* Get panel ID by panel index
* @param context
* @param index
* @returns {*}
Expand All @@ -166,8 +165,8 @@ export function removeActiveClass(context, id){
const {current, currentTrigger} = getElements(context, id);

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


Expand All @@ -181,8 +180,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(CLASSES.active));
if(currentTrigger) currentTrigger.forEach(item => item.classList.add(CLASSES.active));
if(current) current.forEach(item => item.classList.add(context.options.activeClass));
if(currentTrigger) currentTrigger.forEach(item => item.classList.add(context.options.activeClass));
}

export function log(context, status, ...message){
Expand Down

0 comments on commit 4f4aee9

Please sign in to comment.