diff options
Diffstat (limited to 'www/wiki/extensions/UniversalLanguageSelector/resources/js/ext.uls.inputsettings.js')
-rw-r--r-- | www/wiki/extensions/UniversalLanguageSelector/resources/js/ext.uls.inputsettings.js | 595 |
1 files changed, 595 insertions, 0 deletions
diff --git a/www/wiki/extensions/UniversalLanguageSelector/resources/js/ext.uls.inputsettings.js b/www/wiki/extensions/UniversalLanguageSelector/resources/js/ext.uls.inputsettings.js new file mode 100644 index 00000000..fe22f9f6 --- /dev/null +++ b/www/wiki/extensions/UniversalLanguageSelector/resources/js/ext.uls.inputsettings.js @@ -0,0 +1,595 @@ +/*! + * ULS-based ime settings panel + * + * Copyright (C) 2012 Alolita Sharma, Amir Aharoni, Arun Ganesh, Brandon Harris, + * Niklas Laxström, Pau Giner, Santhosh Thottingal, Siebrand Mazeland and other + * contributors. See CREDITS for a list. + * + * UniversalLanguageSelector is dual licensed GPLv2 or later and MIT. You don't + * have to do anything special to choose one license or the other and you don't + * have to notify anyone which license you are using. You are free to use + * UniversalLanguageSelector in commercial projects as long as the copyright + * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details. + * + * @file + * @ingroup Extensions + * @licence GNU General Public Licence 2.0 or later + * @licence MIT License + */ + +( function () { + 'use strict'; + + var template = '<div class="uls-input-settings">' + + // Top "Display settings" title + '<div class="row">' + + '<div class="twelve columns">' + + '<h3 data-i18n="ext-uls-input-settings-title"></h3>' + + '</div>' + + '</div>' + + + // "Language for ime", title above the buttons row + '<div class="row enabled-only uls-input-settings-languages-title">' + + '<div class="twelve columns">' + + '<h4 data-i18n="ext-uls-input-settings-ui-language"></h4>' + + '</div>' + + '</div>' + + + // UI languages buttons row + '<div class="row enabled-only">' + + '<div class="uls-ui-languages twelve columns"></div>' + + '</div>' + + + // Web IMEs enabling chechbox with label + '<div class="row enabled-only">' + + '<div class="twelve columns">' + + '<div class="uls-input-settings-inputmethods-list">' + + // "Input settings for language xyz" title + '<h4 class="ext-uls-input-settings-imes-title"></h4>' + + '</div>' + + '</div>' + + '</div>' + + + // Disable IME system button + '<div class="row">' + + '<div class="twelve columns uls-input-settings-disable-info"></div>' + + '<div class="ten columns uls-input-settings-toggle">' + + '<button class="mw-ui-button mw-ui-progressive active uls-input-toggle-button"></button>' + + '</div>' + + '</div>'; + + function InputSettings( $parent ) { + this.nameI18n = 'ext-uls-input-settings-title-short'; + this.descriptionI18n = 'ext-uls-input-settings-desc'; + this.$template = $( template ); + this.uiLanguage = this.getInterfaceLanguage(); + this.contentLanguage = this.getContentLanguage(); + this.$imes = null; + this.$parent = $parent; + // ime system is lazy loaded, make sure it is initialized + mw.ime.init(); + this.savedRegistry = $.extend( true, {}, $.ime.preferences.registry ); + } + + InputSettings.prototype = { + + constructor: InputSettings, + + /** + * Render the module into a given target + */ + render: function () { + var $enabledOnly, + webfonts = $( 'body' ).data( 'webfonts' ); + + this.dirty = false; + this.$parent.$settingsPanel.empty(); + this.$imes = $( 'body' ).data( 'ime' ); + this.$parent.$settingsPanel.append( this.$template ); + $enabledOnly = this.$template.find( '.enabled-only' ); + if ( $.ime.preferences.isEnabled() ) { + $enabledOnly.removeClass( 'hide' ); + } else { + // Hide the language list and ime selector + $enabledOnly.addClass( 'hide' ); + } + + this.prepareLanguages(); + this.prepareToggleButton(); + this.$parent.i18n(); + + if ( webfonts ) { + webfonts.refresh(); + } + + this.listen(); + }, + + /** + * Mark dirty, there are unsaved changes. Enable the apply button. + * Useful in many places when something changes. + */ + markDirty: function () { + this.dirty = true; + this.$parent.$window.find( 'button.uls-settings-apply' ).prop( 'disabled', false ); + }, + + prepareInputmethods: function ( language ) { + var index, inputSettings, $imeListContainer, defaultInputmethod, + imes, selected, imeId, $imeListTitle; + + imes = $.ime.languages[ language ]; + + $imeListTitle = this.$template.find( '.ext-uls-input-settings-imes-title' ); + $imeListContainer = this.$template.find( '.uls-input-settings-inputmethods-list' ); + + $imeListContainer.empty(); + + if ( !imes ) { + $imeListContainer.append( $( '<label>' ) + .addClass( 'uls-input-settings-no-inputmethods' ) + .text( $.i18n( 'ext-uls-input-settings-noime' ) ) ); + $imeListTitle.text( '' ); + return; + } + + $imeListTitle.text( $.i18n( 'ext-uls-input-settings-ime-settings', + $.uls.data.getAutonym( language ) ) ); + + inputSettings = this; + + defaultInputmethod = $.ime.preferences.getIM( language ) || imes.inputmethods[ 0 ]; + + for ( index in imes.inputmethods ) { + imeId = imes.inputmethods[ index ]; + selected = defaultInputmethod === imeId; + $imeListContainer.append( inputSettings.renderInputmethodOption( imeId, + selected ) ); + } + + $imeListContainer.append( inputSettings.renderInputmethodOption( 'system', + defaultInputmethod === 'system' ) ); + + // Added input methods may increase the height of window. Make sure + // the entire window is in view port + this.$parent.position(); + }, + + /** + * For the given input method id, render the selection option. + * + * @param {string} imeId Input method id + * @param {boolean} selected Whether the input is the currently selected one. + * @return {Object} jQuery object corresponding to the input method item. + */ + renderInputmethodOption: function ( imeId, selected ) { + var $imeLabel, name, description, $helplink, inputmethod, $inputMethodItem; + + if ( imeId !== 'system' && !$.ime.sources[ imeId ] ) { + // imeId not known for jquery.ime. + // It is very rare, but still validate it. + return $(); + } + + $imeLabel = $( '<label>' ).attr( 'for', imeId ); + + $inputMethodItem = $( '<input>' ).attr( { + type: 'radio', + name: 'ime', + id: imeId, + value: imeId + } ) + .prop( 'checked', selected ); + + if ( imeId === 'system' ) { + name = $.i18n( 'ext-uls-disable-input-method' ); + description = ''; + $helplink = ''; + } else { + inputmethod = $.ime.inputmethods[ imeId ]; + $helplink = $( '<a>' ) + .addClass( 'uls-ime-help' ) + .text( $.i18n( 'ext-uls-ime-help' ) ) + .attr( 'href', mw.msg( 'uls-ime-helppage', imeId ) ) + .attr( 'target', '_blank' ); + if ( !inputmethod ) { + // The input method definition(rules) not loaded. + // We will show the name from $.ime.sources + name = $.ime.sources[ imeId ].name; + description = ''; + } else { + name = inputmethod.name; + description = $.ime.inputmethods[ imeId ].description; + } + } + + $imeLabel.append( + $( '<strong>' ) + .addClass( 'uls-input-settings-name' ) + .text( name + ' ' ), + $( '<span>' ) + .addClass( 'uls-input-settings-description' ) + .text( description ), + $helplink + ); + + return $( '<div>' ) + .addClass( 'mw-ui-radio' ) + .append( $inputMethodItem, $imeLabel ); + }, + + /** + * Prepare the UI language selector + */ + prepareLanguages: function () { + var inputSettings = this, + SUGGESTED_LANGUAGES_NUMBER = 3, + selectedImeLanguage = $.ime.preferences.getLanguage(), + languagesForButtons, $languages, suggestedLanguages, + lang, i, language, $button, $caret; + + $languages = this.$template.find( '.uls-ui-languages' ); + + suggestedLanguages = this.frequentLanguageList() + // Common world languages, for the case that there are + // too few suggested languages + .concat( [ 'en', 'zh', 'fr' ] ); + + // Content language is always on the first button + + languagesForButtons = [ this.contentLanguage ]; + + // This is needed when drawing the panel for the second time + // after selecting a different language + $languages.empty(); + + // Selected IME language may be different, and it must be present, too + if ( $.uls.data.languages[ selectedImeLanguage ] && + languagesForButtons.indexOf( selectedImeLanguage ) === -1 + ) { + languagesForButtons.push( selectedImeLanguage ); + } + + // UI language must always be present + if ( this.uiLanguage !== this.contentLanguage && + $.uls.data.languages[ this.uiLanguage ] && + languagesForButtons.indexOf( this.uiLanguage ) === -1 ) { + languagesForButtons.push( this.uiLanguage ); + } + + for ( lang in suggestedLanguages ) { + // Skip already found languages + if ( languagesForButtons.indexOf( suggestedLanguages[ lang ] ) > -1 ) { + continue; + } + + languagesForButtons.push( suggestedLanguages[ lang ] ); + + // No need to add more languages than buttons + if ( languagesForButtons.length >= SUGGESTED_LANGUAGES_NUMBER ) { + break; + } + } + + function buttonHandler( button ) { + return function () { + var language = button.data( 'language' ); + + if ( language !== $.ime.preferences.getLanguage() ) { + inputSettings.markDirty(); + $.ime.preferences.setLanguage( language ); + } + // Mark the button selected + $( '.uls-ui-languages .mw-ui-button' ).removeClass( 'mw-ui-pressed' ); + button.addClass( 'mw-ui-pressed' ); + inputSettings.prepareInputmethods( language ); + }; + } + + // In case no preference exist for IME, selected language is contentLanguage + selectedImeLanguage = selectedImeLanguage || this.contentLanguage; + // Add the buttons for the most likely languages + for ( i = 0; i < SUGGESTED_LANGUAGES_NUMBER; i++ ) { + language = languagesForButtons[ i ]; + $button = $( '<button>' ) + .addClass( 'mw-ui-button uls-language-button autonym' ) + .text( $.uls.data.getAutonym( language ) ) + .prop( { + lang: language, + dir: $.uls.data.getDir( language ) + } ); + + $button.data( 'language', language ); + $caret = $( '<span>' ).addClass( 'uls-input-settings-caret' ); + + $languages.append( $button, $caret ); + + $button.on( 'click', buttonHandler( $button ) ); + + if ( language === selectedImeLanguage ) { + $button.trigger( 'click' ); + } + } + + this.prepareMoreLanguages(); + }, + + /** + * Prepare the more languages button. It is a ULS trigger + */ + prepareMoreLanguages: function () { + var inputSettings = this, + $languages, $moreLanguagesButton; + + $languages = this.$template.find( '.uls-ui-languages' ); + $moreLanguagesButton = $( '<button>' ) + .prop( 'class', 'uls-more-languages' ) + .addClass( 'mw-ui-button' ).text( '...' ); + + $languages.append( $moreLanguagesButton ); + // Show the long language list to select a language for ime settings + $moreLanguagesButton.uls( { + left: inputSettings.$parent.left, + top: inputSettings.$parent.top, + onReady: function () { + var uls = this, + $wrap, + $back = $( '<div>' ) + .addClass( 'uls-icon-back' ) + .data( 'i18n', 'ext-uls-back-to-input-settings' ) + .i18n() + .text( ' ' ); + + $back.on( 'click', function () { + uls.hide(); + inputSettings.$parent.show(); + } ); + + $wrap = $( '<div>' ) + .addClass( 'uls-search-wrapper-wrapper' ); + + uls.$menu.find( '.uls-search-wrapper' ).wrap( $wrap ); + uls.$menu.find( '.uls-search-wrapper-wrapper' ).prepend( $back ); + + if ( $( '.uls-settings-trigger' ).offset().left > $( window ).width() / 2 ) { + uls.$menu.removeClass( 'selector-left' ).addClass( 'selector-right' ); + } else { + uls.$menu.removeClass( 'selector-right' ).addClass( 'selector-left' ); + } + }, + onVisible: function () { + var $parent; + + this.$menu.find( '.uls-languagefilter' ) + .prop( 'placeholder', $.i18n( 'ext-uls-input-settings-ui-language' ) ); + + if ( !inputSettings.$parent.$window.hasClass( 'callout' ) ) { + // callout menus will have position rules. others use + // default position + return; + } + + $parent = $( '#language-settings-dialog' ); + + // Re-position the element according to the window that called it + if ( parseInt( $parent.css( 'left' ), 10 ) ) { + this.$menu.css( 'left', $parent.css( 'left' ) ); + } + if ( parseInt( $parent.css( 'top' ), 10 ) ) { + this.$menu.css( 'top', $parent.css( 'top' ) ); + } + + if ( inputSettings.$parent.$window.hasClass( 'callout' ) ) { + this.$menu.addClass( 'callout callout--languageselection' ); + } else { + this.$menu.removeClass( 'callout' ); + } + }, + onSelect: function ( langCode ) { + $.ime.preferences.setLanguage( langCode ); + inputSettings.$parent.show(); + inputSettings.prepareLanguages(); + inputSettings.markDirty(); + }, + languages: mw.ime.getLanguagesWithIME(), + ulsPurpose: 'input-settings' + } ); + + $moreLanguagesButton.on( 'click', function () { + inputSettings.$parent.hide(); + mw.hook( 'mw.uls.ime.morelanguages' ).fire(); + } ); + }, + + prepareToggleButton: function () { + var $toggleButton, $toggleButtonDesc; + + $toggleButton = this.$template.find( '.uls-input-toggle-button' ); + $toggleButtonDesc = this.$template + .find( '.uls-input-settings-disable-info' ); + + if ( $.ime.preferences.isEnabled() ) { + $toggleButton.data( 'i18n', 'ext-uls-input-disable' ); + $toggleButtonDesc.hide(); + } else { + $toggleButton.data( 'i18n', 'ext-uls-input-enable' ); + $toggleButtonDesc.data( 'i18n', 'ext-uls-input-disable-info' ).show(); + } + + $toggleButton.i18n(); + $toggleButtonDesc.i18n(); + }, + + /** + * Get previous languages + * + * @return {Array} + */ + frequentLanguageList: function () { + return mw.uls.getFrequentLanguageList(); + }, + + /** + * Get the current user interface language. + * + * @return {string} Current UI language + */ + getInterfaceLanguage: function () { + return mw.config.get( 'wgUserLanguage' ); + }, + + /** + * Get the current content language. + * + * @return {string} Current content language + */ + getContentLanguage: function () { + return mw.config.get( 'wgContentLanguage' ); + }, + + /** + * Register general event listeners + */ + listen: function () { + var inputSettings = this, + $imeListContainer; + + $imeListContainer = this.$template.find( '.uls-input-settings-inputmethods-list' ); + + $imeListContainer.on( 'change', 'input:radio[name=ime]:checked', function () { + inputSettings.markDirty(); + $.ime.preferences.setIM( $( this ).val() ); + } ); + + inputSettings.$template.find( 'button.uls-input-toggle-button' ) + .on( 'click', function () { + inputSettings.markDirty(); + + if ( $.ime.preferences.isEnabled() ) { + inputSettings.disableInputTools(); + } else { + inputSettings.enableInputTools(); + } + } ); + + }, + + /** + * Disable input tools + */ + disableInputTools: function () { + $.ime.preferences.disable(); + mw.ime.disable(); + this.$template.find( '.enabled-only' ).addClass( 'hide' ); + this.prepareToggleButton(); + }, + + /** + * Enable input tools + */ + enableInputTools: function () { + $.ime.preferences.enable(); + mw.ime.setup(); + this.$template.find( '.enabled-only' ).removeClass( 'hide' ); + this.$template.scrollIntoView(); + this.prepareToggleButton(); + }, + + /** + * Close the language settings window. + * Depending on the context, actions vary. + */ + close: function () { + this.$parent.close(); + }, + + /** + * Callback for save preferences + * + * @param {boolean} success + */ + onSave: function ( success ) { + if ( success ) { + // Live ime update + this.$parent.hide(); + // Disable apply button + this.$parent.disableApplyButton(); + } + // FIXME in case of failure. what to do?! + }, + + /** + * Handle the apply button press. + * Note that the button press may not be from the input settings module. + * For example, a user can change input settings and then go to display settings panel, + * do some changes and press apply button there. That press is applicable for all + * modules. + */ + apply: function () { + var previousIM, + inputSettings = this, + previousLanguage = inputSettings.savedRegistry.language, + currentlyEnabled = $.ime.preferences.isEnabled(), + currentLanguage = $.ime.preferences.getLanguage(), + currentIM = $.ime.preferences.getIM( currentLanguage ); + + if ( !inputSettings.dirty ) { + // No changes to save in this module. + return; + } + inputSettings.$parent.setBusy( true ); + + if ( previousLanguage ) { + previousIM = inputSettings.savedRegistry.imes[ previousLanguage ]; + } + + if ( currentLanguage !== inputSettings.savedRegistry.language || + currentIM !== previousIM + ) { + mw.hook( 'mw.uls.ime.change' ).fire( currentIM ); + } + + if ( inputSettings.savedRegistry.enable !== currentlyEnabled ) { + mw.hook( currentlyEnabled ? 'mw.uls.ime.enable' : 'mw.uls.ime.disable' ) + .fire( 'inputsettings' ); + } + + // Save the preferences + $.ime.preferences.save( function ( result ) { + // closure for not losing the scope + inputSettings.onSave( result ); + inputSettings.dirty = false; + // Update the back-up preferences for the case of canceling + inputSettings.savedRegistry = $.extend( true, {}, $.ime.preferences.registry ); + inputSettings.$parent.setBusy( false ); + } ); + }, + + /** + * Cancel the changes done by user for input settings + */ + cancel: function () { + if ( !this.dirty ) { + this.close(); + return; + } + // Reload preferences + $.ime.preferences.registry = $.extend( true, {}, this.savedRegistry ); + this.uiLanguage = this.getInterfaceLanguage(); + this.contentLanguage = this.getContentLanguage(); + // Restore the state of IME + if ( $.ime.preferences.isEnabled() ) { + mw.ime.setup(); + } else { + mw.ime.disable(); + } + this.close(); + } + }; + + // Register this module to language settings modules + $.fn.languagesettings.modules = $.extend( $.fn.languagesettings.modules, { + input: InputSettings + } ); + +}() ); |