UNPKG

samagra-x-enketo-core

Version:

Extensible Enketo form engine

137 lines (119 loc) 5.34 kB
/** * Form languages module. * * @module language */ import { getSiblingElement } from './dom-utils'; import events from './event'; export default { /** * @param {string} overrideLang - override language IANA subtag */ init( overrideLang ) { if ( !this.form ) { throw new Error( 'Language module not correctly instantiated with form property.' ); } const root = this.form.view.html.closest( 'body' ) || this.form.view.html.parentNode; if ( !root ) { return; } const langSelector = root.querySelector( '.form-language-selector' ); const formLanguages = this.form.view.html.querySelector( '#form-languages' ); if ( !formLanguages ) { return; } this.languages = [ ...formLanguages.querySelectorAll( 'option' ) ].map( option => option.value ); if ( langSelector ) { langSelector .append( formLanguages ); if ( this.languages.length > 1 ) { langSelector.classList.remove( 'hide' ); } } this.formLanguages = root.querySelector( '#form-languages' ); this.defaultLanguage = this.formLanguages.dataset.defaultLang || undefined; if ( overrideLang && this.languages.includes( overrideLang ) && this.languages.length > 1 ) { this._currentLang = overrideLang; this.setFormUi( this._currentLang ); } else { this._currentLang = this.defaultLanguage || this.languages[ 0 ] || ''; } const langOption = this.formLanguages.querySelector( `[value="${this._currentLang}"]` ); const currentDirectionality = langOption && langOption.dataset.dir || 'ltr'; this.formLanguages.value = this._currentLang; this.form.view.html.setAttribute( 'dir', currentDirectionality ); if ( this.languages.length < 2 ) { return; } this.formLanguages.addEventListener( events.Change().type, event => { event.preventDefault(); this._currentLang = event.target.value; this.setFormUi( this._currentLang ); } ); this.form.view.html.addEventListener( events.AddRepeat().type, event => this.setFormUi( this._currentLang, event.target ) ); }, /** * @type {string} */ get currentLanguage() { return this._currentLang; }, /** * @type {string} */ get currentLangDesc() { const langOption = this.formLanguages.querySelector( `[value="${this._currentLang}"]` ); return langOption ? langOption.textContent : null; }, /** * @type {Array} */ get languagesUsed() { return this.languages || []; }, setFormUi( lang, group = this.form.view.html ) { const dir = this.formLanguages.querySelector( `[value="${lang}"]` ).dataset.dir || 'ltr'; const translations = [ ...group.querySelectorAll( '[lang]' ) ]; this.form.view.html.setAttribute( 'dir', dir ); translations.forEach( el => el.classList.remove( 'active' ) ); translations .filter( el => el.matches( `[lang="${lang}"], [lang=""]` ) && ( !el.classList.contains( 'or-form-short' ) || ( el.classList.contains( 'or-form-short' ) && !getSiblingElement( el, '.or-form-long' ) ) ) ) .forEach( el => el.classList.add( 'active' ) ); // For use in locale-sensitive XPath functions. // Don't even check whether it's a proper subtag or not. It will revert to client locale if it is not recognized. window.enketoFormLocale = lang; this.form.view.html.querySelectorAll( 'select, datalist' ).forEach( el => this.setSelect( el ) ); this.form.view.html.dispatchEvent( events.ChangeLanguage() ); }, /** * swap language of <select> and <datalist> <option>s * * @param {Element} select - select or datalist HTML element */ setSelect( select ) { const type = select.nodeName.toLowerCase(); const question = select.closest( '.question, .or-repeat-info' ); const translations = question ? question.querySelector( '.or-option-translations' ) : null; if ( !translations ) { return; } [ ...select.children ].filter( el => el.matches( 'option' ) && !el.matches( '[value=""], [data-value=""]' ) ) .forEach( option => { const curLabel = type === 'datalist' ? option.value : option.textContent; // Datalist will not have initialized when init function is called upon form load, so it is option.value until it has initialized. That is not great. const value = type === 'datalist' ? option.dataset.value || option.value : option.value; const translatedOption = translations.querySelector( `.active[data-option-value="${value}"]` ); if ( translatedOption ) { let newLabel = curLabel; if ( translatedOption && translatedOption.textContent ) { newLabel = translatedOption.textContent; } option.value = value; option.textContent = newLabel; } } ); } };