three
Version:
JavaScript 3D library
171 lines (98 loc) • 2.98 kB
JavaScript
export class Item {
constructor( ...data ) {
this.children = [];
this.isOpen = true;
this.childrenContainer = null;
this.parent = null;
this.domElement = document.createElement( 'div' );
this.domElement.className = 'list-item-wrapper';
this.itemRow = document.createElement( 'div' );
this.itemRow.className = 'list-item-row';
this.userData = {};
this.data = data;
this.data.forEach( ( cellData ) => {
const cell = document.createElement( 'div' );
cell.className = 'list-item-cell';
if ( cellData instanceof HTMLElement ) {
cell.appendChild( cellData );
} else {
cell.append( String( cellData ) );
}
this.itemRow.appendChild( cell );
} );
this.domElement.appendChild( this.itemRow );
// Bindings
this.onItemClick = this.onItemClick.bind( this );
}
onItemClick( e ) {
if ( e.target.closest( 'button, a, input, label' ) ) return;
this.toggle();
}
add( item, index = this.children.length ) {
if ( item.parent !== null ) {
item.parent.remove( item );
}
item.parent = this;
this.children.splice( index, 0, item );
this.itemRow.classList.add( 'collapsible' );
if ( ! this.childrenContainer ) {
this.childrenContainer = document.createElement( 'div' );
this.childrenContainer.className = 'list-children-container';
this.childrenContainer.classList.toggle( 'closed', ! this.isOpen );
this.domElement.appendChild( this.childrenContainer );
this.itemRow.addEventListener( 'click', this.onItemClick );
}
this.childrenContainer.insertBefore(
item.domElement,
this.childrenContainer.children[ index ] || null
);
this.updateToggler();
return this;
}
remove( item ) {
const index = this.children.indexOf( item );
if ( index !== - 1 ) {
this.children.splice( index, 1 );
this.childrenContainer.removeChild( item.domElement );
item.parent = null;
if ( this.children.length === 0 ) {
this.itemRow.classList.remove( 'collapsible' );
this.itemRow.removeEventListener( 'click', this.onItemClick );
this.childrenContainer.remove();
this.childrenContainer = null;
}
this.updateToggler();
}
return this;
}
updateToggler() {
const firstCell = this.itemRow.querySelector( '.list-item-cell:first-child' );
let toggler = this.itemRow.querySelector( '.item-toggler' );
if ( this.children.length > 0 ) {
if ( ! toggler ) {
toggler = document.createElement( 'span' );
toggler.className = 'item-toggler';
firstCell.prepend( toggler );
}
if ( this.isOpen ) {
this.itemRow.classList.add( 'open' );
}
} else if ( toggler ) {
toggler.remove();
}
}
toggle() {
this.isOpen = ! this.isOpen;
this.itemRow.classList.toggle( 'open', this.isOpen );
if ( this.childrenContainer ) {
this.childrenContainer.classList.toggle( 'closed', ! this.isOpen );
}
return this;
}
close() {
if ( this.isOpen ) {
this.toggle();
}
return this;
}
}