import { child , children } from './utils' ; import { Elements , Event , Options , Sortboard } from './types' ; import { emitus , Emitus , EmitusListener as Listener } from 'emitus' ; export const defaults = { container : '.sortboard' , selector : '.sortboard-block' , gutter : 0 , resetFilterValue : 'all' , hiddenClass : '.sortboard-hidden' , matchedClass : '.sortboard-matched' } ; const emitter = emitus ( ) ; export default function sortboard ( options ? ) { const opts = { ... defaults , ... options } as Options ; if ( ! opts . container ) { return null ; } let container ; if ( typeof opts . container === 'string' ) { const childContainer = child ( document . body , opts . container ) ; if ( ! childContainer ) { return null ; } container = childContainer ; } else { container = opts . container ; } let api = null ; const blocks = children ( opts . selector , container ) ; if ( ! blocks . length ) { return null ; } const els = { container , blocks } ; api = createSortboard ( els , opts ) ; return api ; } export { sortboard , Sortboard , Elements , Options , Listener , Event , Emitus } ; function createSortboard ( { container , blocks } , opts ) { let currentFilter = '' ; const api = { sort , reset , filter , on : emitter . on , off : emitter . off } ; init ( ) ; return api ; function init ( ) { events ( ) ; sort ( ) ; } function filter ( pattern = '' ) { if ( ! pattern || pattern === currentFilter ) return ; currentFilter = pattern ; const notMatchedElements = [ ] ; const matchedElements = blocks . filter ( ( item ) => { const cords = item . getAttribute ( 'data-cords' ) . trim ( ) ; if ( pattern === opts . resetFilterValue ) { translate ( item , cords , false ) ; return true ; } const data = ( item . getAttribute ( 'data-filter' ) || '' ) . toString ( ) . trim ( ) ; const regx = pattern instanceof RegExp ? pattern : RegExp ( pattern ) ; const matchPattern = ! ! data && regx . test ( data ) ; if ( ! matchPattern ) { notMatchedElements . push ( item ) ; } translate ( item , cords , ! matchPattern ) ; return matchPattern ; } ) ; emitter . emit ( 'filter' , [ matchedElements , notMatchedElements , currentFilter ] ) ; if ( matchedElements . length ) { sort ( ) ; } } function reset ( ) { filter ( opts . resetFilterValue ) ; } function sort ( ) { let n = 0 ; let x = 0 ; let y = 0 ; let totalW = 0 ; let totalH = 0 ; let breakW = 0 ; const gutter = opts . gutter ! ; const parentWidth = container . parentElement ! . offsetWidth ; blocks . forEach ( ( child ) => { if ( child . classList . contains ( opts . hiddenClass ! ) ) return ; if ( totalW >= parentWidth - child . offsetHeight - gutter ) { totalW = 0 ; y += child . offsetHeight + gutter ; if ( ! breakW ) { breakW = n * child . offsetWidth + ( n * gutter - gutter ) ; } } else { totalW += n ? gutter : 0 ; } n ++ ; totalW += child . offsetWidth ; x = totalW - child . offsetWidth ; totalH = y + child . offsetHeight ; translate ( child , `${ x },${ y }` , false ) ; } ) ; const pNWidth = n * parentWidth + ( n < 2 ? n : n - 1 ) * gutter ; const pWidth = breakW || pNWidth ; container . style . width = `${ pWidth }px` ; container . style . height = `${ totalH }px` ; emitter . emit ( 'sort' ) ; } function events ( ) { window . addEventListener ( 'resize' , sort , false ) ; } function translate ( item , cords , hide ) { const matrix = `matrix(1,0,0,1,${ cords }) scale(${ hide ? '0.001' : '1' })` ; if ( hide ) { item . classList . add ( opts . hiddenClass ! ) ; item . classList . remove ( opts . matchedClass ! ) ; } else { item . classList . add ( opts . matchedClass ! ) ; item . classList . remove ( opts . hiddenClass ! ) ; } item . setAttribute ( 'data-cords' , cords ) ; item . style . setProperty ( 'opacity' , hide ? '0' : '1' ) ; item . style . setProperty ( '-webkit-transform' , matrix ) ; item . style . setProperty ( '-moz-transform' , matrix ) ; item . style . setProperty ( 'transform' , matrix ) ; } }