import { } from "../libs/fuzzysort" ; declare global { interface Application { _recalculateDimensions ( ) : void ; } } ( < any > Application . prototype ) . _recalculateDimensions = function ( ) { this . element [ 0 ] . style . height = '' ; this . setPosition ( { } ) ; } ; abstract class SettingsProcessor { static readonly DELIM = ' `````` ' ; abstract processSettings ( html ) ; abstract injectSearch ( html ) ; abstract performSearch ( pattern ) ; protected _updateLabels ( text , div , percentage ? ) { const [ label , hint ] = text . split ( SettingsProcessor . DELIM ) ; if ( percentage !== undefined ) { if ( isNaN ( percentage ) ) percentage = 0 ; const [ redPerc , greenPerc ] = percentage <= 0.5 ? [ percentage / 0.5 , 1 ] : [ 1 , 1 - ( ( percentage - 0.5 ) / 0.5 ) ] ; const red = Math . round ( redPerc * 255 ) . toString ( 16 ) . padStart ( 2 , '0' ) ; const green = Math . round ( greenPerc * 255 ) . toString ( 16 ) . padStart ( 2 , '0' ) ; div . css ( 'border-left' , `thick solid #${ red }${ green }00` ) ; div . css ( 'padding-left' , '6px' ) ; } else { div . css ( 'border-left' , '' ) ; div . css ( 'padding-left' , '' ) ; } div . find ( '>label' ) . html ( label ) ; if ( div [ 0 ] . classList . contains ( 'submenu' ) ) div . find ( 'button>label' ) . html ( hint ) ; else div . find ( '.notes' ) . html ( hint ) ; } protected _getOptions ( query ) { const threshold = Math . min ( 100000 , 10000 + ( ( query . length - 2 ) * 10000 ) ) ; return { keys : [ 'text' ] , limit : Infinity , threshold : - threshold , allowTypo : false , } ; } } interface DefaultModuleItem { el : JQuery < HTMLElement > ; text : string ; } class DefaultSettingsProcessor extends SettingsProcessor { private _settings : DefaultModuleItem [ ] = [ ] ; private _getMenuData ( div ) { return { el : div , text : $ ( div ) . find ( '>label' ) . text ( ) + SettingsProcessor . DELIM + $ ( div ) . find ( 'button' ) . find ( 'label' ) . text ( ) , } ; } private _getRegularData ( div ) { return { el : div , text : $ ( div ) . find ( '>label' ) . text ( ) + SettingsProcessor . DELIM + $ ( div ) . find ( '.notes' ) . text ( ) , } ; } processSettings ( html ) { const children = $ ( html . find ( '.settings-list' ) [ 2 ] ) . children ( ) ; children . each ( ( idx , element ) => { if ( element instanceof HTMLHeadingElement ) return ; else { if ( element . classList . contains ( 'submenu' ) ) this . _settings . push ( this . _getMenuData ( $ ( element ) ) ) ; else this . _settings . push ( this . _getRegularData ( $ ( element ) ) ) ; } } ) ; } injectSearch ( html ) { const search = < JQuery < HTMLInputElement > > $ ( `
<div id="dfsc_search" class="searchBox">
	<input type="text" placeholder="${ game . i18n . localize ( 'DF_SETTINGS_CLARITY.SearchPlaceholder' ) }">
	<button class="dfsc_clear-search" style="display:none"><i class="fas fa-times"></i></button>
</div>` ) ; $ ( html . find ( '.settings-list' ) [ 2 ] ) . prepend ( search ) ; html . find ( 'button[name="reset"]' ) . css ( 'height' , 'fit-content' ) ; html . find ( 'button[name="reset"]' ) . css ( 'margin-top' , 'auto' ) ; html . find ( 'button[name="submit"]' ) . css ( 'height' , 'fit-content' ) ; html . find ( 'button[name="submit"]' ) . css ( 'margin-top' , 'auto' ) ; return search ; } performSearch ( pattern ) { if ( pattern . length < 2 ) { for ( const item of this . _settings ) { item . el . show ( ) ; this . _updateLabels ( item . text , item . el ) ; } return ; } const results = fuzzysort . go ( pattern , this . _settings , this . _getOptions ( pattern ) ) ; for ( let c = 0 ; c < this . _settings . length ; c ++ ) { const resultIdx = results . findIndex ( x => x . obj === this . _settings [ c ] ) ; let text ; let percentage = undefined ; if ( resultIdx >= 0 ) { this . _settings [ c ] . el . show ( ) ; text = fuzzysort . highlight ( results [ resultIdx ] [ 0 ] ) ; percentage = resultIdx / ( results . length - 1 ) ; } else { this . _settings [ c ] . el . hide ( ) ; text = this . _settings [ c ] . text ; } this . _updateLabels ( text , this . _settings [ c ] . el , percentage ) ; } } } interface TidyUiModuleItem { article : HTMLElement ; el : JQuery < HTMLElement > ; text : string ; } class TidyUiSettingsProcessor extends SettingsProcessor { private _settings : TidyUiModuleItem [ ] = [ ] ; private _articles : Map < HTMLElement , boolean > = new Map ( ) ; private _toggleArticle ( article , open ) { if ( open ) { article . find ( 'h2' ) . addClass ( 'open' ) ; article . find ( 'section' ) . show ( ) ; } else { article . find ( 'h2' ) . removeClass ( 'open' ) ; article . find ( 'section' ) . hide ( ) ; } } private _getMenuData ( article , div ) { return { article , el : div , text : $ ( div ) . find ( '>label' ) . text ( ) + SettingsProcessor . DELIM + $ ( div ) . find ( 'button>label' ) . text ( ) } ; } private _getRegularData ( article , div ) { return { article , el : div , text : $ ( div ) . find ( '>label' ) . text ( ) + SettingsProcessor . DELIM + $ ( div ) . find ( '.notes' ) . text ( ) } ; } processSettings ( html ) { const articles = html . find ( '.settings-list > article' ) ; articles . each ( ( _ , element ) => { this . _articles . set ( element , false ) ; $ ( element ) . find ( 'section' ) . children ( ) . each ( ( _ , childElement ) => { const child = $ ( childElement ) ; if ( childElement . classList . contains ( 'submenu' ) ) this . _settings . push ( this . _getMenuData ( element , child ) ) ; else this . _settings . push ( this . _getRegularData ( element , child ) ) ; } ) ; } ) ; } injectSearch ( html ) { const search = < JQuery < HTMLInputElement > > $ ( `
<div id="dfsc_search" class="searchBox tidy-ui">
	<input type="text" placeholder="${ game . i18n . localize ( 'DF_SETTINGS_CLARITY.SearchPlaceholder' ) }">
	<button class="dfsc_clear-search" style="display:none"><i class="fas fa-times"></i></button>
</div>` ) ; html . find ( '#searchField' ) . after ( search ) ; html . find ( '#config-tabs .settings-list' ) [ 2 ] . style . maxHeight = 'calc(100vh - 227px)' ; return search ; } performSearch ( pattern ) { if ( pattern . length < 2 ) { for ( const item of this . _settings ) { item . el . show ( ) ; super . _updateLabels ( item . text , item . el ) ; } for ( const article of this . _articles . entries ( ) ) { this . _articles . set ( article [ 0 ] , false ) ; this . _toggleArticle ( $ ( article [ 0 ] ) , false ) ; } return ; } const results = fuzzysort . go ( pattern , this . _settings , this . _getOptions ( pattern ) ) ; for ( const article of this . _articles . keys ( ) ) { this . _articles . set ( article , false ) ; } for ( let c = 0 ; c < this . _settings . length ; c ++ ) { const resultIdx = results . findIndex ( x => x . obj === this . _settings [ c ] ) ; let text ; let percentage = undefined ; if ( resultIdx >= 0 ) { this . _articles . set ( this . _settings [ c ] . article , true ) ; this . _settings [ c ] . el . show ( ) ; text = fuzzysort . highlight ( results [ resultIdx ] [ 0 ] ) ; percentage = resultIdx / ( results . length - 1 ) ; } else { this . _settings [ c ] . el . hide ( ) ; text = this . _settings [ c ] . text ; } this . _updateLabels ( text , this . _settings [ c ] . el , percentage ) ; } for ( const article of this . _articles . entries ( ) ) { this . _toggleArticle ( $ ( article [ 0 ] ) , article [ 1 ] ) ; } } } export default class FuzzySearch { private static _settingsProcessor : SettingsProcessor = null ; static init ( ) { Hooks . on ( 'renderSettingsConfig' , ( _settingsConfig , html , _data ) => { if ( game . modules . get ( 'tidy-ui_game-settings' ) ?. active ) this . _settingsProcessor = new TidyUiSettingsProcessor ( ) ; else this . _settingsProcessor = new DefaultSettingsProcessor ( ) ; this . _settingsProcessor . processSettings ( html ) ; const searchField = this . _settingsProcessor . injectSearch ( html ) ; searchField . find ( 'input' ) . on ( 'input' , function ( ) { const value = < string > $ ( this ) . val ( ) ; FuzzySearch . _settingsProcessor . performSearch ( value ) ; if ( value === '' ) searchField . find ( 'button' ) . hide ( ) ; else searchField . find ( 'button' ) . show ( ) ; } ) ; searchField . find ( 'button' ) . on ( 'click' , function ( event ) { event . preventDefault ( ) ; searchField . find ( 'input' ) . val ( '' ) ; $ ( this ) . hide ( ) ; FuzzySearch . _settingsProcessor . performSearch ( '' ) ; } ) ; _settingsConfig . _recalculateDimensions ( ) ; } ) ; } }