import { classList , addClass , removeClass , isNullOrUndefined , Browser } from '@syncfusion/ej2-base' ; import { Query , DataManager } from '@syncfusion/ej2-data' ; import { Column } from '../models/column' ; import { Button } from '@syncfusion/ej2-buttons' ; import { EventHandler , L10n , closest } from '@syncfusion/ej2-base' ; import { CheckBox } from '@syncfusion/ej2-buttons' ; import { ServiceLocator } from '../services/service-locator' ; import { IGrid , IAction , NotifyArgs , EJ2Intance } from '../base/interface' ; import * as events from '../base/constant' ; import { ShowHide } from './show-hide' ; import { Dialog , calculateRelativeBasedPosition } from '@syncfusion/ej2-popups' ; import { createCboxWithWrap , toogleCheckbox , parentsUntil } from '../base/util' ; import { createCheckBox } from '@syncfusion/ej2-buttons' ; import { SearchBox } from '../services/focus-strategy' ; import { Grid } from '../base/grid' ; /**
 * The `ColumnChooser` module is used to show or hide columns dynamically.
 */ export class ColumnChooser implements IAction { private dataManager : DataManager ; private column : Column ; private parent : IGrid ; private serviceLocator : ServiceLocator ; private l10n : L10n ; private dlgObj : Dialog ; private searchValue : string ; private flag : boolean ; private timer : number ; public getShowHideService : ShowHide ; private showColumn : string [ ] = [ ] ; private hideColumn : string [ ] = [ ] ; private mainDiv : HTMLElement ; private innerDiv : HTMLElement ; private ulElement : HTMLElement ; private isDlgOpen : boolean = false ; private dlghide : boolean = false ; private initialOpenDlg : boolean = true ; private stateChangeColumns : Column [ ] = [ ] ; private dlgDiv : HTMLElement ; private isInitialOpen : boolean = false ; private isCustomizeOpenCC : boolean = false ; private cBoxTrue : Element ; private cBoxFalse : Element ; private searchBoxObj : SearchBox ; private searchOperator : string = 'startswith' ; private targetdlg : Element ; hidden constructor ( parent ? , serviceLocator ? ) { this . parent = parent ; this . serviceLocator = serviceLocator ; this . addEventListener ( ) ; this . cBoxTrue = createCheckBox ( this . parent . createElement , true , { checked : true , label : ' ' } ) ; this . cBoxFalse = createCheckBox ( this . parent . createElement , true , { checked : false , label : ' ' } ) ; this . cBoxTrue . insertBefore ( this . parent . createElement ( 'input' , { className : 'e-chk-hidden e-cc e-cc-chbox' , attrs : { type : 'checkbox' } } ) , this . cBoxTrue . firstChild ) ; this . cBoxFalse . insertBefore ( this . parent . createElement ( 'input' , { className : 'e-chk-hidden e-cc e-cc-chbox' , attrs : { 'type' : 'checkbox' } } ) , this . cBoxFalse . firstChild ) ; this . cBoxFalse . querySelector ( '.e-frame' ) . classList . add ( 'e-uncheck' ) ; if ( this . parent . enableRtl ) { addClass ( [ this . cBoxTrue , this . cBoxFalse ] , [ 'e-rtl' ] ) ; } } private destroy ( ) { let gridElement = this . parent . element ; if ( ! gridElement || ( ! gridElement . querySelector ( '.e-gridheader' ) && ! gridElement . querySelector ( '.e-gridcontent' ) ) ) { return ; } this . removeEventListener ( ) ; this . unWireEvents ( ) ; if ( ! isNullOrUndefined ( this . dlgObj ) && this . dlgObj . element && ! this . dlgObj . isDestroyed ) { this . dlgObj . destroy ( ) ; } } private rtlUpdate ( ) { if ( this . parent . enableRtl ) { addClass ( this . innerDiv . querySelectorAll ( '.e-checkbox-wrapper' ) , [ 'e-rtl' ] ) ; } else { removeClass ( this . innerDiv . querySelectorAll ( '.e-checkbox-wrapper' ) , [ 'e-rtl' ] ) ; } } hidden public addEventListener ( ) { if ( this . parent . isDestroyed ) { return ; } this . parent . on ( events . click , this . clickHandler , this ) ; this . parent . on ( events . uiUpdate , this . enableAfterRenderEle , this ) ; this . parent . on ( events . initialEnd , this . render , this ) ; this . parent . addEventListener ( events . dataBound , this . hideDialog . bind ( this ) ) ; this . parent . on ( events . destroy , this . destroy , this ) ; this . parent . on ( events . rtlUpdated , this . rtlUpdate , this ) ; } hidden public removeEventListener ( ) { if ( this . parent . isDestroyed ) { return ; } this . parent . off ( events . click , this . clickHandler ) ; this . parent . off ( events . initialEnd , this . render ) ; this . parent . off ( events . destroy , this . destroy ) ; this . parent . off ( events . uiUpdate , this . enableAfterRenderEle ) ; this . parent . off ( events . rtlUpdated , this . rtlUpdate ) ; } private render ( ) { this . l10n = this . serviceLocator . getService < L10n > ( 'localization' ) ; this . renderDlgContent ( ) ; this . getShowHideService = this . serviceLocator . getService < ShowHide > ( 'showHideService' ) ; } private clickHandler ( e ) { let targetElement = e . target as Element ; if ( ! this . isCustomizeOpenCC ) { if ( ! isNullOrUndefined ( closest ( targetElement , '.e-cc' ) ) || ! isNullOrUndefined ( closest ( targetElement , '.e-cc-toolbar' ) ) ) { if ( targetElement . classList . contains ( 'e-columnchooser-btn' ) || targetElement . classList . contains ( 'e-cc-toolbar' ) ) { if ( ( this . initialOpenDlg && this . dlgObj . visible ) || ! this . isDlgOpen ) { this . isDlgOpen = true ; return ; } } else if ( targetElement . classList . contains ( 'e-cc-cancel' ) ) { ( < HTMLInputElement > targetElement . parentElement . querySelector ( '.e-ccsearch' ) ) . value = '' ; this . columnChooserSearch ( '' ) ; this . removeCancelIcon ( ) ; this . refreshCheckboxButton ( ) ; } } else { if ( ! isNullOrUndefined ( this . dlgObj ) && this . dlgObj . visible && ! targetElement . classList . contains ( 'e-toolbar-items' ) ) { this . dlgObj . hide ( ) ; this . clearActions ( ) ; this . refreshCheckboxState ( ) ; this . isDlgOpen = false ; } } if ( this . parent . detailTemplate || this . parent . childGrid ) { this . targetdlg = e . target as Element ; } } if ( this . isCustomizeOpenCC && ( e . target as Element ) . classList . contains ( 'e-cc-cancel' ) ) { this . refreshCheckboxState ( ) ; } this . rtlUpdate ( ) ; } private hideDialog ( ) { if ( ! isNullOrUndefined ( this . dlgObj ) && this . dlgObj . visible ) { this . dlgObj . hide ( ) ; this . isDlgOpen = false ; } } return { void } hidden public renderColumnChooser ( x ? , y ? , target ? ) { if ( ! this . dlgObj . visible && ( this . parent . detailTemplate || this . parent . childGrid ) ) { this . hideOpenedDialog ( ) ; } if ( ! this . dlgObj . visible ) { let pos = { X : null , Y : null } ; let args1 = { requestType : 'beforeOpenColumnChooser' , element : this . parent . element , columns : this . getColumns ( ) as Column [ ] , cancel : false , searchOperator : this . searchOperator } ; this . parent . trigger ( events . beforeOpenColumnChooser , args1 ) ; if ( args1 . cancel ) { return ; } this . searchOperator = args1 . searchOperator ; if ( target ) { this . targetdlg = target ; } this . refreshCheckboxState ( ) ; this . dlgObj . dataBind ( ) ; this . dlgObj . element . style . maxHeight = '430px' ; let elementVisible = this . dlgObj . element . style . display ; this . dlgObj . element . style . display = 'block' ; let newpos = calculateRelativeBasedPosition ( ( < HTMLElement > closest ( target , '.e-toolbar-item' ) ) , this . dlgObj . element ) ; this . dlgObj . element . style . display = elementVisible ; this . dlgObj . element . style . top = newpos . top + closest ( target , '.e-cc-toolbar' ) . getBoundingClientRect ( ) . height + 'px' ; let dlgWidth = 250 ; if ( ! isNullOrUndefined ( closest ( target , '.e-bigger' ) ) ) { this . dlgObj . width = 258 ; } if ( Browser . isDevice ) { this . dlgObj . target = document . body ; this . dlgObj . position = { X : 'center' , Y : 'center' } ; this . dlgObj . refreshPosition ( ) ; this . dlgObj . open = this . mOpenDlg . bind ( this ) ; } else { if ( this . parent . enableRtl ) { this . dlgObj . element . style . left = ( < HTMLElement > target ) . offsetLeft + 'px' ; } else { this . dlgObj . element . style . left = ( ( newpos . left - dlgWidth ) + closest ( target , '.e-cc-toolbar' ) . clientWidth ) + 2 + 'px' ; } } this . removeCancelIcon ( ) ; this . dlgObj . show ( ) ; } else { this . hideDialog ( ) ; this . addcancelIcon ( ) ; } this . rtlUpdate ( ) ; } param { number } X param { number } Y return { void } public openColumnChooser ( X ? , Y ? ) { this . isCustomizeOpenCC = true ; if ( this . dlgObj . visible ) { this . hideDialog ( ) ; return ; } if ( ! this . isInitialOpen ) { this . dlgObj . content = this . renderChooserList ( ) ; } else { this . refreshCheckboxState ( ) ; } this . dlgObj . dataBind ( ) ; this . dlgObj . position = { X : 'center' , Y : 'center' } ; if ( isNullOrUndefined ( X ) ) { this . dlgObj . position = { X : 'center' , Y : 'center' } ; this . dlgObj . refreshPosition ( ) ; } else { this . dlgObj . element . style . top = '' ; this . dlgObj . element . style . left = '' ; this . dlgObj . element . style . top = Y + 'px' ; this . dlgObj . element . style . left = X + 'px' ; } this . dlgObj . beforeOpen = this . customDialogOpen . bind ( this ) ; this . dlgObj . show ( ) ; this . isInitialOpen = true ; this . dlgObj . beforeClose = this . customDialogClose . bind ( this ) ; } private enableAfterRenderEle ( e ) { if ( e . module === this . getModuleName ( ) && e . enable ) { this . render ( ) ; } } private customDialogOpen ( ) { let searchElement = ( this . dlgObj . content as Element ) . querySelector ( 'input.e-ccsearch' ) ; EventHandler . add ( searchElement , 'keyup' , this . columnChooserManualSearch , this ) ; } private customDialogClose ( ) { let searchElement = ( this . dlgObj . content as Element ) . querySelector ( 'input.e-ccsearch' ) ; EventHandler . remove ( searchElement , 'keyup' , this . columnChooserManualSearch ) ; } private getColumns ( ) { let columns = this . parent . getColumns ( ) . filter ( ( column ) => ( column . type !== 'checkbox' && column . showInColumnChooser === true ) || ( column . type === 'checkbox' && column . field !== undefined ) ) ; return columns ; } private renderDlgContent ( ) { let y ; this . dlgDiv = this . parent . createElement ( 'div' , { className : 'e-ccdlg e-cc' , id : this . parent . element . id + '_ccdlg' } ) ; this . parent . element . appendChild ( this . dlgDiv ) ; let xpos = this . parent . element . getBoundingClientRect ( ) . width - 250 ; let dialoPos = this . parent . enableRtl ? 'left' : 'right' ; let tarElement = this . parent . element . querySelector ( '.e-ccdiv' ) ; if ( ! isNullOrUndefined ( tarElement ) ) { y = tarElement . getBoundingClientRect ( ) . top ; } let pos = { X : null , Y : null } ; this . dlgObj = new Dialog ( { header : this . l10n . getConstant ( 'ChooseColumns' ) , showCloseIcon : false , closeOnEscape : false , locale : this . parent . locale , visible : false , enableRtl : this . parent . enableRtl , target : document . getElementById ( this . parent . element . id ) , buttons : [ { click : this . confirmDlgBtnClick . bind ( this ) , buttonModel : { content : this . l10n . getConstant ( 'OKButton' ) , isPrimary : true , cssClass : 'e-cc e-cc_okbtn' , } } , { click : this . clearActions . bind ( this ) , buttonModel : { cssClass : 'e-flat e-cc e-cc-cnbtn' , content : this . l10n . getConstant ( 'CancelButton' ) } } ] , content : this . renderChooserList ( ) , width : 250 , cssClass : 'e-cc' , animationSettings : { effect : 'None' } , } ) ; this . dlgObj . appendTo ( this . dlgDiv ) ; this . wireEvents ( ) ; } private renderChooserList ( ) { this . mainDiv = this . parent . createElement ( 'div' , { className : 'e-main-div e-cc' } ) ; let searchDiv = this . parent . createElement ( 'div' , { className : 'e-cc-searchdiv e-cc e-input-group' } ) ; let ccsearchele = this . parent . createElement ( 'input' , { className : 'e-ccsearch e-cc e-input' , attrs : { placeholder : this . l10n . getConstant ( 'Search' ) } } ) ; let ccsearchicon = this . parent . createElement ( 'span' , { className : 'e-ccsearch-icon e-icons e-cc e-input-group-icon' , attrs : { title : this . l10n . getConstant ( 'Search' ) } } ) ; let conDiv = this . parent . createElement ( 'div' , { className : 'e-cc-contentdiv' } ) ; this . innerDiv = this . parent . createElement ( 'div' , { className : 'e-innerdiv e-cc' } ) ; searchDiv . appendChild ( ccsearchele ) ; searchDiv . appendChild ( ccsearchicon ) ; this . searchBoxObj = new SearchBox ( ccsearchele ) ; let innerDivContent = this . refreshCheckboxList ( this . parent . getColumns ( ) as Column [ ] ) ; this . innerDiv . appendChild ( ( innerDivContent as Element ) ) ; conDiv . appendChild ( this . innerDiv ) ; this . mainDiv . appendChild ( searchDiv ) ; this . mainDiv . appendChild ( conDiv ) ; return this . mainDiv ; } private confirmDlgBtnClick ( args ) { this . stateChangeColumns = [ ] ; if ( ! isNullOrUndefined ( args ) ) { if ( this . hideColumn . length ) { this . columnStateChange ( this . hideColumn , false ) ; } if ( this . showColumn . length ) { this . columnStateChange ( this . showColumn , true ) ; } let params = { requestType : 'columnstate' , element : this . parent . element , columns : this . stateChangeColumns as Column [ ] , dialogInstance : this . dlgObj } ; this . parent . trigger ( events . actionComplete , params ) ; this . getShowHideService . setVisible ( this . stateChangeColumns ) ; this . clearActions ( ) ; this . parent . notify ( events . tooltipDestroy , { module : 'edit' } ) ; } } private columnStateChange ( stateColumns , state ) { for ( let index = 0 ; index < stateColumns . length ; index ++ ) { let colUid = stateColumns [ index ] ; let currentCol = this . parent . getColumnByUid ( colUid ) ; currentCol . visible = state ; this . stateChangeColumns . push ( currentCol ) ; } } private clearActions ( ) { this . hideColumn = [ ] ; this . showColumn = [ ] ; this . hideDialog ( ) ; this . addcancelIcon ( ) ; } private checkstatecolumn ( isChecked , coluid ) { if ( isChecked ) { if ( this . hideColumn . indexOf ( coluid ) !== - 1 ) { this . hideColumn . splice ( this . hideColumn . indexOf ( coluid ) , 1 ) ; } if ( this . showColumn . indexOf ( coluid ) === - 1 ) { this . showColumn . push ( coluid ) ; } } else { if ( this . showColumn . indexOf ( coluid ) !== - 1 ) { this . showColumn . splice ( this . showColumn . indexOf ( coluid ) , 1 ) ; } if ( this . hideColumn . indexOf ( coluid ) === - 1 ) { this . hideColumn . push ( coluid ) ; } } } private columnChooserSearch ( searchVal ) { let clearSearch = false ; let fltrCol ; let okButton ; let buttonEle = this . dlgDiv . querySelector ( '.e-footer-content' ) ; if ( buttonEle ) { okButton = ( buttonEle . querySelector ( '.e-btn' ) as EJ2Intance ) . ej2_instances [ 0 ] as Button ; } if ( searchVal === '' ) { this . removeCancelIcon ( ) ; fltrCol = this . getColumns ( ) as Column [ ] ; clearSearch = true ; } else { fltrCol = new DataManager ( ( this . getColumns ( ) as Object [ ] ) as JSON [ ] ) . executeLocal ( new Query ( ) . where ( 'headerText' , this . searchOperator , searchVal , true ) ) as Column [ ] ; } if ( fltrCol . length ) { this . innerDiv . innerHTML = ' ' ; this . innerDiv . classList . remove ( 'e-ccnmdiv' ) ; this . innerDiv . appendChild ( < HTMLElement > this . refreshCheckboxList ( fltrCol , searchVal ) ) ; if ( ! clearSearch ) { this . addcancelIcon ( ) ; this . refreshCheckboxButton ( ) ; } else { if ( okButton ) { okButton . disabled = false ; } } } else { let nMatchele = this . parent . createElement ( 'span' , { className : 'e-cc e-nmatch' } ) ; nMatchele . innerHTML = this . l10n . getConstant ( 'Matchs' ) ; this . innerDiv . innerHTML = ' ' ; this . innerDiv . appendChild ( nMatchele ) ; this . innerDiv . classList . add ( 'e-ccnmdiv' ) ; if ( okButton ) { okButton . disabled = true ; } } this . flag = true ; this . stopTimer ( ) ; } private wireEvents ( ) { EventHandler . add ( this . dlgObj . element , 'click' , this . checkBoxClickHandler , this ) ; EventHandler . add ( this . searchBoxObj . searchBox , 'keyup' , this . columnChooserManualSearch , this ) ; this . searchBoxObj . wireEvent ( ) ; } private unWireEvents ( ) { if ( this . parent . isDestroyed ) { return ; } if ( this . dlgObj . element ) { EventHandler . remove ( this . dlgObj . element , 'click' , this . checkBoxClickHandler ) ; } EventHandler . remove ( this . searchBoxObj . searchBox , 'keyup' , this . columnChooserManualSearch ) ; this . searchBoxObj . unWireEvent ( ) ; } private checkBoxClickHandler ( e ) { let checkstate ; let elem = parentsUntil ( e . target as Element , 'e-checkbox-wrapper' ) ; if ( elem ) { toogleCheckbox ( elem . parentElement ) ; ( elem . querySelector ( '.e-chk-hidden' ) as HTMLElement ) . focus ( ) ; if ( elem . querySelector ( '.e-check' ) ) { checkstate = true ; } else if ( elem . querySelector ( '.e-uncheck' ) ) { checkstate = false ; } else { return ; } let columnUid = parentsUntil ( elem , 'e-ccheck' ) . getAttribute ( 'uid' ) ; this . checkstatecolumn ( checkstate , columnUid ) ; this . refreshCheckboxButton ( ) ; } } private refreshCheckboxButton ( ) { let searchValue = ( < HTMLInputElement > this . dlgObj . element . querySelector ( '.e-cc.e-input' ) ) . value ; let selected = this . innerDiv . querySelectorAll ( '.e-check' ) . length ; let btn = ( this . dlgDiv . querySelector ( '.e-footer-content' ) . querySelector ( '.e-btn' ) as EJ2Intance ) . ej2_instances [ 0 ] as Button ; btn . disabled = false ; let srchShowCols = [ ] ; let searchData = this . parent . element . querySelectorAll ( '.e-cc-chbox' ) ; for ( let i = 0 , itemsLen = searchData . length ; i < itemsLen ; i ++ ) { let element = searchData [ i ] as HTMLInputElement ; let columnUID = parentsUntil ( element , 'e-ccheck' ) . getAttribute ( 'uid' ) ; srchShowCols . push ( columnUID ) ; } let hideCols = this . showColumn . filter ( ( column ) => srchShowCols . indexOf ( column ) !== - 1 ) ; if ( selected === 0 && hideCols . length === 0 ) { btn . disabled = true ; } btn . dataBind ( ) ; } private refreshCheckboxList ( gdCol , searchVal ? ) { this . ulElement = this . parent . createElement ( 'ul' , { className : 'e-ccul-ele e-cc' } ) ; for ( let i = 0 ; i < gdCol . length ; i ++ ) { let columns = ( gdCol [ i ] as Column ) ; this . renderCheckbox ( columns ) ; } return this . ulElement ; } private refreshCheckboxState ( ) { ( < HTMLInputElement > this . dlgObj . element . querySelector ( '.e-cc.e-input' ) ) . value = '' ; this . columnChooserSearch ( '' ) ; let gridObject = this . parent ; let currentCheckBoxColls = this . dlgObj . element . querySelectorAll ( '.e-cc-chbox' ) ; for ( let i = 0 , itemLen = currentCheckBoxColls . length ; i < itemLen ; i ++ ) { let element = currentCheckBoxColls [ i ] as HTMLInputElement ; let columnUID ; if ( this . parent . childGrid || this . parent . detailTemplate ) { columnUID = parentsUntil ( this . dlgObj . element . querySelectorAll ( '.e-cc-chbox' ) [ i ] , 'e-ccheck' ) . getAttribute ( 'uid' ) ; } else { columnUID = parentsUntil ( element , 'e-ccheck' ) . getAttribute ( 'uid' ) ; } let column = gridObject . getColumnByUid ( columnUID ) ; if ( column . visible ) { element . checked = true ; this . checkState ( element . parentElement . querySelector ( '.e-icons' ) , true ) ; } else { element . checked = false ; this . checkState ( element . parentElement . querySelector ( '.e-icons' ) , false ) ; } } } private checkState ( element , state ) { state ? classList ( element , [ 'e-check' ] , [ 'e-uncheck' ] ) : classList ( element , [ 'e-uncheck' ] , [ 'e-check' ] ) ; } private createCheckBox ( label , checked , uid ) { let cbox = checked ? this . cBoxTrue . cloneNode ( true ) as Element : this . cBoxFalse . cloneNode ( true ) as Element ; cbox . querySelector ( '.e-label' ) . innerHTML = label ; return createCboxWithWrap ( uid , cbox , 'e-ccheck' ) ; } private renderCheckbox ( column ) { let cclist ; let hideColState ; let showColState ; let checkBoxObj ; if ( column . showInColumnChooser ) { cclist = this . parent . createElement ( 'li' , { className : 'e-cclist e-cc' , styles : 'list-style:None' , id : 'e-ccli_' + column . uid } ) ; hideColState = this . hideColumn . indexOf ( column . uid ) === - 1 ? false : true ; showColState = this . showColumn . indexOf ( column . uid ) === - 1 ? false : true ; let cccheckboxlist = this . createCheckBox ( column . headerText , ( column . visible && ! hideColState ) || showColState , column . uid ) ; cclist . appendChild ( cccheckboxlist ) ; this . ulElement . appendChild ( cclist ) ; } } private columnChooserManualSearch ( e ) { this . addcancelIcon ( ) ; this . searchValue = ( < HTMLInputElement > e . target ) . value ; let proxy = this ; this . stopTimer ( ) ; this . startTimer ( e ) ; } private startTimer ( e ) { let proxy = this ; let interval = ! proxy . flag && e . keyCode !== 13 ? 500 : 0 ; this . timer = window . setInterval ( ( ) => { proxy . columnChooserSearch ( proxy . searchValue ) ; } , interval ) ; } private stopTimer ( ) { window . clearInterval ( this . timer ) ; } private addcancelIcon ( ) { this . dlgDiv . querySelector ( '.e-cc.e-ccsearch-icon' ) . classList . add ( 'e-cc-cancel' ) ; } private removeCancelIcon ( ) { this . dlgDiv . querySelector ( '.e-cc.e-ccsearch-icon' ) . classList . remove ( 'e-cc-cancel' ) ; } private mOpenDlg ( ) { if ( Browser . isDevice ) { this . dlgObj . element . querySelector ( '.e-cc-searchdiv' ) . classList . remove ( 'e-input-focus' ) ; ( < HTMLElement > this . dlgObj . element . querySelectorAll ( '.e-cc-chbox' ) [ 0 ] ) . focus ( ) ; } } private getModuleName ( ) { return 'columnChooser' ; } private hideOpenedDialog ( ) { let openCC = [ ] . slice . call ( document . getElementsByClassName ( 'e-ccdlg' ) ) . filter ( ( dlgEle ) => dlgEle . classList . contains ( 'e-popup-open' ) ) ; for ( let i = 0 , dlgLen = openCC . length ; i < dlgLen ; i ++ ) { if ( openCC [ i ] . classList . contains ( 'e-dialog' ) || this . parent . element . id + '_ccdlg' !== openCC [ i ] . id ) { ( openCC [ i ] as EJ2Intance ) . ej2_instances [ 0 ] . hide ( ) ; } } } }