import {Feature} from './feature'; import Dom from '../dom'; import Arr from '../array'; import Str from '../string'; import Sort from '../sort'; import Event from '../event'; const SORT_ERROR = 'Filter options for column {0} cannot be sorted in ' + '{1} manner.'; export class CheckList extends Feature{ /** * Checklist UI component * @param {Object} tf TableFilter instance */ constructor(tf){ super(tf, 'checkList'); // Configuration object let f = tf.config(); this.checkListDiv = []; //checklist container div //defines css class for div containing checklist filter this.checkListDivCssClass = f.div_checklist_css_class || 'div_checklist'; //defines css class for checklist filters this.checkListCssClass = f.checklist_css_class || 'flt_checklist'; //defines css class for checklist item (li) this.checkListItemCssClass = f.checklist_item_css_class || 'flt_checklist_item'; //defines css class for selected checklist item (li) this.checkListSlcItemCssClass = f.checklist_selected_item_css_class || 'flt_checklist_slc_item'; //Load on demand text this.activateCheckListTxt = f.activate_checklist_text || 'Click to load filter data'; //defines css class for checklist filters this.checkListItemDisabledCssClass = f.checklist_item_disabled_css_class || 'flt_checklist_item_disabled'; this.enableCheckListResetFilter = f.enable_checklist_reset_filter===false ? false : true; //checklist filter container div this.prfxCheckListDiv = 'chkdiv_'; this.isCustom = null; this.opts = null; this.optsTxt = null; this.excludedOpts = null; } onChange(evt){ let elm = evt.target; let tf = this.tf; tf.activeFilterId = elm.getAttribute('id'); tf.activeFlt = Dom.id(tf.activeFilterId); tf.filter(); } optionClick(evt){ this.setCheckListValues(evt.target); this.onChange(evt); } onCheckListClick(evt){ let elm = Event.target(evt); if(this.tf.loadFltOnDemand && elm.getAttribute('filled') === '0'){ let ct = elm.getAttribute('ct'); let div = this.checkListDiv[ct]; this.build(ct); Event.remove(div, 'click', (evt)=> this.onCheckListClick(evt)); } } /** * Initialize checklist filter * @param {Number} colIndex Column index * @param {Boolean} isExternal External filter flag * @param {DOMElement} container Dom element containing the filter */ init(colIndex, isExternal, container){ let tf = this.tf; let externalFltTgtId = isExternal ? tf.externalFltTgtIds[colIndex] : null; let divCont = Dom.create('div', ['id', this.prfxCheckListDiv+colIndex+'_'+tf.id], ['ct', colIndex], ['filled', '0']); divCont.className = this.checkListDivCssClass; //filter is appended in desired element if(externalFltTgtId){ Dom.id(externalFltTgtId).appendChild(divCont); tf.externalFltEls.push(divCont); } else { container.appendChild(divCont); } this.checkListDiv[colIndex] = divCont; tf.fltIds.push(tf.prfxFlt+colIndex+'_'+tf.id); if(!tf.loadFltOnDemand){ this.build(colIndex); } else { Event.add(divCont, 'click', (evt)=> this.onCheckListClick(evt)); divCont.appendChild(Dom.text(this.activateCheckListTxt)); } this.emitter.on( ['build-checklist-filter'], (tf, colIndex, isExternal)=> this.build(colIndex, isExternal) ); this.emitter.on( ['select-checklist-options'], (tf, colIndex, values)=> this.selectOptions(colIndex, values) ); this.initialized = true; } /** * Build checklist UI * @param {Number} colIndex Column index */ build(colIndex){ let tf = this.tf; colIndex = parseInt(colIndex, 10); this.emitter.emit('before-populating-filter', tf, colIndex); this.opts = []; this.optsTxt = []; let flt = this.checkListDiv[colIndex]; let ul = Dom.create( 'ul', ['id', tf.fltIds[colIndex]], ['colIndex', colIndex]); ul.className = this.checkListCssClass; Event.add(ul, 'change', (evt)=> this.onChange(evt)); let rows = tf.tbl.rows; this.isCustom = tf.isCustomOptions(colIndex); let activeFlt; if(tf.linkedFilters && tf.activeFilterId){ activeFlt = tf.activeFilterId.split('_')[0]; activeFlt = activeFlt.split(tf.prfxFlt)[1]; } let filteredDataCol = []; if(tf.linkedFilters && tf.disableExcludedOptions){ this.excludedOpts = []; } flt.innerHTML = ''; for(let k=tf.refRow; k this.optionClick(evt)); } ul.appendChild(li); if(val === ''){ //item is hidden li.style.display = 'none'; } } } /** * Add checklist header option * @param {Number} colIndex Column index * @param {Object} ul Ul element */ addTChecks(colIndex, ul){ let tf = this.tf; let chkCt = 1; let li0 = Dom.createCheckItem( tf.fltIds[colIndex]+'_0', '', tf.displayAllText); li0.className = this.checkListItemCssClass; ul.appendChild(li0); Event.add(li0.check, 'click', (evt)=> this.optionClick(evt)); if(!this.enableCheckListResetFilter){ li0.style.display = 'none'; } if(tf.enableEmptyOption){ let li1 = Dom.createCheckItem( tf.fltIds[colIndex]+'_1', tf.emOperator, tf.emptyText); li1.className = this.checkListItemCssClass; ul.appendChild(li1); Event.add(li1.check, 'click', (evt)=> this.optionClick(evt)); chkCt++; } if(tf.enableNonEmptyOption){ let li2 = Dom.createCheckItem( tf.fltIds[colIndex]+'_2', tf.nmOperator, tf.nonEmptyText ); li2.className = this.checkListItemCssClass; ul.appendChild(li2); Event.add(li2.check, 'click', (evt)=> this.optionClick(evt)); chkCt++; } return chkCt; } /** * Store checked options in DOM element attribute * @param {Object} o checklist option DOM element */ setCheckListValues(o){ if(!o){ return; } let tf = this.tf; let chkValue = o.value; //checked item value let chkIndex = parseInt(o.id.split('_')[2], 10); // TODO: provide helper to extract column index, ugly! let colIdx = o.id.split('_')[0].replace(tf.prfxFlt, ''); let itemTag = 'LI'; let n = tf.getFilterElement(parseInt(colIdx, 10)); let li = n.childNodes[chkIndex]; let colIndex = n.getAttribute('colIndex'); let fltValue = n.getAttribute('value'); //filter value (ul tag) let fltIndexes = n.getAttribute('indexes'); //selected items (ul tag) if(o.checked){ //show all item if(chkValue === ''){ if((fltIndexes && fltIndexes!=='')){ //items indexes let indSplit = fltIndexes.split(tf.separator); //checked items loop for(let u=0; u this.build(colIndex, isExternal) ); this.emitter.off( ['select-checklist-options'], (tf, colIndex, values)=> this.selectOptions(colIndex, values) ); } }