import * as ko from "knockout" ; import { CreatorBase , StringEditorViewModelBase } from "@survey/creator" ; import { LocalizableString } from "survey-core" ; import { ImplementorBase } from "survey-knockout-ui" ; const template = require ( "./string-editor.html" ) ; export class StringEditorViewModel { private implementor = undefined ; private baseModel : StringEditorViewModelBase ; getEditorElement = ( element ) => { return element . nextSibling . getElementsByClassName ( "sv-string-editor" ) [ 0 ] ; } ; constructor ( public locString , private creator , element ) { this . baseModel = new StringEditorViewModelBase ( locString , creator ) ; this . implementor = new ImplementorBase ( this . baseModel ) ; this . focusEditor = ( ) => { this . getEditorElement ( element ) . focus ( ) ; } ; this . baseModel . blurEditor = ( ) => this . getEditorElement ( element ) . blur ( ) ; locString . strChanged ( ) ; } public setLocString ( locString ) { this . baseModel . setLocString ( locString ) ; return locString ; } public get koHasHtml ( ) : boolean { return this . locString . koHasHtml ( ) ; } public get editValue ( ) : string { return this . locString . koRenderedHtml ( ) ; } public get className ( ) : string { return this . baseModel . className ( this . locString . koRenderedHtml ( ) ) ; } public get placeholder ( ) : string { return this . baseModel . placeholder ; } public get contentEditable ( ) : string { return this . baseModel . contentEditable ? "true" : "false" ; } public errorText : ko . Observable < string > = ko . observable ( null ) ; public onClick ( sender , event ) { this . baseModel . onClick ( event ) ; } public onInput ( sender , event ) { this . baseModel . onInput ( event ) ; this . errorText ( this . baseModel . errorText ) ; this . locString . searchElement = undefined ; } public onFocus ( sender , event ) { this . baseModel . onFocus ( event ) ; } public onKeyDown ( sender , event ) { var res = this . baseModel . onKeyDown ( event ) ; this . errorText ( this . baseModel . errorText ) ; return res ; } public edit ( model , _ ) { model . focusEditor && model . focusEditor ( ) ; this . baseModel . onClick ( _ ) ; } public done ( _ , event ) { this . baseModel . done ( event ) ; } public focusEditor : ( ) => void ; public dispose ( ) { this . locString . onSearchChanged = undefined ; this . focusEditor = undefined ; this . baseModel . blurEditor = undefined ; this . implementor . dispose ( ) ; this . implementor = undefined ; } } function getSearchElement ( element ) { while ( ! ! element && element . nodeName !== "SPAN" ) { const elements = element . parentElement . getElementsByClassName ( "sv-string-editor" ) ; element = elements . length > 0 ? elements [ 0 ] : undefined ; } if ( ! ! element && element . childNodes . length > 0 ) return element ; return null ; } function resetLocalizationSpan ( element , locStr ) { while ( element . childNodes . length > 1 ) { element . removeChild ( element . childNodes [ 1 ] ) ; } element . childNodes [ 0 ] . textContent = locStr . renderedHtml ; } function applyLocStrOnSearchChanged ( element , locStr ) { locStr . onSearchChanged = ( ) => { if ( locStr . searchElement == undefined ) { locStr . searchElement = getSearchElement ( element ) ; } if ( locStr . searchElement == null ) return ; const el = locStr . searchElement ; if ( ! locStr . highlightDiv ) { locStr . highlightDiv = document . createElement ( "span" ) ; locStr . highlightDiv . style . backgroundColor = "lightgray" ; } if ( locStr . searchIndex != undefined ) { resetLocalizationSpan ( el , locStr ) ; const rng = document . createRange ( ) ; rng . setStart ( el . childNodes [ 0 ] , locStr . searchIndex ) ; rng . setEnd ( el . childNodes [ 0 ] , locStr . searchIndex + locStr . searchText . length ) ; rng . surroundContents ( locStr . highlightDiv ) ; } else { resetLocalizationSpan ( el , locStr ) ; locStr . searchElement = undefined ; } } ; } export const editableStringRendererName = "svc-string-editor" ; ko . components . register ( editableStringRendererName , { viewModel : { createViewModel : ( params , componentInfo ) => { const data = ko . unwrap ( params . locString ) ; const model = new StringEditorViewModel ( data . locStr , data . creator , componentInfo . element ) ; const subscrib = ko . computed ( ( ) => { const locStr = ko . unwrap ( params . locString ) . locStr ; applyLocStrOnSearchChanged ( componentInfo . element , locStr ) ; model . setLocString ( locStr ) ; } ) ; ko . utils . domNodeDisposal . addDisposeCallback ( componentInfo . element , ( ) => { subscrib . dispose ( ) ; } ) ; return model ; } , } , template : template , } ) ;