diff options
Diffstat (limited to 'www/wiki/extensions/UniversalLanguageSelector/resources/js/ext.uls.interface.js')
-rw-r--r-- | www/wiki/extensions/UniversalLanguageSelector/resources/js/ext.uls.interface.js | 458 |
1 files changed, 458 insertions, 0 deletions
diff --git a/www/wiki/extensions/UniversalLanguageSelector/resources/js/ext.uls.interface.js b/www/wiki/extensions/UniversalLanguageSelector/resources/js/ext.uls.interface.js new file mode 100644 index 00000000..89e8fa0a --- /dev/null +++ b/www/wiki/extensions/UniversalLanguageSelector/resources/js/ext.uls.interface.js @@ -0,0 +1,458 @@ +/*! + * ULS interface integration logic + * + * Copyright (C) 2012-2013 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'; + + /** + * Construct the display settings link + * + * @return {jQuery} + */ + function displaySettings() { + return $( '<button>' ) + .addClass( 'display-settings-block' ) + .attr( { + title: $.i18n( 'ext-uls-display-settings-desc' ), + 'data-i18n': 'ext-uls-display-settings-title' + } ) + .i18n(); + } + + /** + * Construct the input settings link + * + * @return {jQuery} + */ + function inputSettings() { + return $( '<button>' ) + .addClass( 'input-settings-block' ) + .attr( { + title: $.i18n( 'ext-uls-input-settings-desc' ), + 'data-i18n': 'ext-uls-input-settings-title' + } ) + .i18n(); + } + + /** + * Add display settings link to the settings bar in ULS + * + * @param {Object} uls The ULS object + */ + function addDisplaySettings( uls ) { + var $displaySettings = displaySettings(); + + uls.$menu.find( '#uls-settings-block' ).append( $displaySettings ); + + // Initialize the trigger + $displaySettings.one( 'click', function () { + var displaySettingsOptions = { + defaultModule: 'display' + }, + ulsPosition = mw.config.get( 'wgULSPosition' ), + anonMode = ( mw.user.isAnon() && + !mw.config.get( 'wgULSAnonCanChangeLanguage' ) ); + + // If the ULS trigger is shown in the top personal menu, + // closing the display settings must show the main ULS + // languages list, unless we are in anon mode and thus + // cannot show the language list + if ( ulsPosition === 'personal' && !anonMode ) { + displaySettingsOptions.onClose = function () { + uls.show(); + }; + } + $.extend( displaySettingsOptions, uls.position() ); + $displaySettings.languagesettings( displaySettingsOptions ).trigger( 'click' ); + } ); + } + + /** + * Add input settings link to the settings bar in ULS + * + * @param {Object} uls The ULS object + */ + function addInputSettings( uls ) { + var $inputSettings = inputSettings(); + + uls.$menu.find( '#uls-settings-block' ).append( $inputSettings ); + + // Initialize the trigger + $inputSettings.one( 'click', function () { + var position = uls.position(); + + $inputSettings.languagesettings( { + defaultModule: 'input', + onClose: function () { + uls.show(); + }, + top: position.top, + left: position.left + } ).trigger( 'click' ); + + } ); + } + + function userCanChangeLanguage() { + return mw.config.get( 'wgULSAnonCanChangeLanguage' ) || !mw.user.isAnon(); + } + + /** + * The tooltip to be shown when language changed using ULS. + * It also allows to undo the language selection. + * + * @param {string} previousLang + * @param {string} previousAutonym + */ + function showUndoTooltip( previousLang, previousAutonym ) { + var $ulsTrigger, ulsPopup, ulsPopupPosition, + ulsPosition = mw.config.get( 'wgULSPosition' ); + + $ulsTrigger = ( ulsPosition === 'interlanguage' ) ? + $( '.uls-settings-trigger' ) : + $( '.uls-trigger' ); + + function hideTipsy() { + ulsPopup.toggle( false ); + } + + function showTipsy( timeout ) { + var tipsyTimer = 0; + + ulsPopup.toggle( true ); + ulsPopup.toggleClipping( false ); + + // if the mouse is over the tooltip, do not hide + $( '.uls-tipsy' ).on( 'mouseover', function () { + window.clearTimeout( tipsyTimer ); + } ).on( 'mouseout', function () { + tipsyTimer = window.setTimeout( hideTipsy, timeout ); + } ); + + // hide the tooltip when clicked on it + $( '.uls-tipsy' ).on( 'click', hideTipsy ); + + tipsyTimer = window.setTimeout( hideTipsy, timeout ); + } + + // remove any existing popups + if ( ulsPopup ) { + ulsPopup.$element.remove(); + } + if ( ulsPosition === 'interlanguage' ) { + if ( $ulsTrigger.offset().left > $( window ).width() / 2 ) { + ulsPopupPosition = 'before'; + } else { + ulsPopupPosition = 'after'; + } + // Reverse for RTL + if ( $( 'html' ).prop( 'dir' ) === 'rtl' ) { + ulsPopupPosition = ( ulsPopupPosition === 'after' ) ? 'before' : 'after'; + } + } else { + ulsPopupPosition = 'below'; + } + ulsPopup = new OO.ui.PopupWidget( { + padded: true, + width: 300, + classes: [ 'uls-tipsy' ], + // Automatically positioned relative to the trigger + $floatableContainer: $ulsTrigger, + position: ulsPopupPosition, + $content: ( function () { + var messageKey, $link; + + $link = $( '<a>' ) + .text( previousAutonym ) + .prop( { + href: '', + class: 'uls-prevlang-link', + lang: previousLang, + // We could get dir from uls.data, + // but we are trying to avoid loading it + // and 'auto' is safe enough in this context. + // T130390: must use attr + dir: 'auto' + } ) + .on( 'click', function ( event ) { + var deferred = $.Deferred(); + + event.preventDefault(); + deferred.done( function () { + mw.uls.changeLanguage( event.target.lang ); + } ); + + mw.hook( 'mw.uls.language.revert' ).fire( deferred ); + + // Delay is zero if event logging is not enabled + window.setTimeout( function () { + deferred.resolve(); + }, mw.config.get( 'wgULSEventLogging' ) * 500 ); + } ); + + if ( mw.storage.get( 'uls-gp' ) === '1' ) { + messageKey = 'ext-uls-undo-language-tooltip-text-local'; + } else { + messageKey = 'ext-uls-undo-language-tooltip-text'; + } + + return $( '<p>' ).append( mw.message( messageKey, $link ).parseDom() ); + }() ) + } ); + + ulsPopup.$element.appendTo( 'body' ); + + // The interlanguage position needs some time to settle down + window.setTimeout( function () { + // Show the tipsy tooltip on page load. + showTipsy( 6000 ); + }, 700 ); + + // manually show the tooltip + $ulsTrigger.on( 'mouseover', function () { + // show only if the ULS panel is not shown + if ( !$( '.uls-menu:visible' ).length ) { + showTipsy( 3000 ); + } + } ); + } + + function initInterface() { + var $pLang, + clickHandler, + $ulsTrigger = $( '.uls-trigger' ), + anonMode = ( mw.user.isAnon() && + !mw.config.get( 'wgULSAnonCanChangeLanguage' ) ), + ulsPosition = mw.config.get( 'wgULSPosition' ); + + if ( ulsPosition === 'interlanguage' ) { + // TODO: Refactor this block + // The interlanguage links section + $pLang = $( '#p-lang' ); + // Add an element near the interlanguage links header + $ulsTrigger = $( '<button>' ) + .addClass( 'uls-settings-trigger' ); + // Append ULS cog to languages section. + $pLang.prepend( $ulsTrigger ); + // Take care of any other elements with this class. + $ulsTrigger = $( '.uls-settings-trigger' ); + + if ( !$pLang.find( 'div ul' ).children().length ) { + // Replace the title of the interlanguage links area + // if there are no interlanguage links + $pLang.find( 'h3' ) + .text( mw.msg( 'uls-plang-title-languages' ) ); + } + + $ulsTrigger.attr( { + title: mw.msg( 'ext-uls-select-language-settings-icon-tooltip' ) + } ); + + clickHandler = function ( e, eventParams ) { + var languagesettings = $ulsTrigger.data( 'languagesettings' ), + languageSettingsOptions; + + if ( languagesettings ) { + if ( !languagesettings.shown ) { + mw.hook( 'mw.uls.settings.open' ).fire( eventParams && eventParams.source || 'interlanguage' ); + } + + return; + } + + // Initialize the Language settings window + languageSettingsOptions = { + defaultModule: 'display', + onVisible: function () { + var caretRadius, + ulsTriggerHeight = this.$element.height(), + ulsTriggerWidth = this.$element[ 0 ].offsetWidth, + ulsTriggerOffset = this.$element.offset(); + + this.$window.addClass( 'callout' ); + + // Same as border width in mixins.less, or near enough + caretRadius = 12; + + if ( ulsTriggerOffset.left > $( window ).width() / 2 ) { + this.left = ulsTriggerOffset.left - this.$window.width() - caretRadius; + this.$window.removeClass( 'selector-left' ).addClass( 'selector-right' ); + + } else { + this.left = ulsTriggerOffset.left + ulsTriggerWidth + caretRadius; + this.$window.removeClass( 'selector-right' ).addClass( 'selector-left' ); + } + + // The top of the dialog is aligned in relation to + // the middle of the trigger, so that middle of the + // caret aligns with it. 16 is trigger icon height in pixels + this.top = ulsTriggerOffset.top + + ( ulsTriggerHeight / 2 ) - + ( caretRadius + 16 ); + + this.position(); + } + }; + + mw.loader.using( mw.uls.languageSettingsModules, function () { + $ulsTrigger.languagesettings( languageSettingsOptions ).trigger( 'click' ); + } ); + + e.stopPropagation(); + }; + } else if ( anonMode ) { + clickHandler = function ( e, eventParams ) { + var languagesettings = $ulsTrigger.data( 'languagesettings' ); + + e.preventDefault(); + + if ( languagesettings ) { + if ( !languagesettings.shown ) { + mw.hook( 'mw.uls.settings.open' ).fire( eventParams && eventParams.source || 'personal' ); + } + } else { + mw.loader.using( mw.uls.languageSettingsModules, function () { + $ulsTrigger.languagesettings(); + + $ulsTrigger.trigger( 'click', eventParams ); + } ); + } + }; + } else { + clickHandler = function ( e, eventParams ) { + var uls = $ulsTrigger.data( 'uls' ); + + e.preventDefault(); + + if ( uls ) { + if ( !uls.shown ) { + mw.hook( 'mw.uls.settings.open' ).fire( eventParams && eventParams.source || 'personal' ); + } + } else { + mw.loader.using( 'ext.uls.mediawiki', function () { + $ulsTrigger.uls( { + quickList: function () { + return mw.uls.getFrequentLanguageList(); + }, + onReady: function () { + var uls = this; + mw.loader.using( mw.uls.languageSettingsModules, function () { + addDisplaySettings( uls ); + addInputSettings( uls ); + } ); + }, + onSelect: function ( language ) { + mw.uls.changeLanguage( language ); + }, + // Not actually used on sites with the gear icon + // in the interlanguage area, because this ULS + // will be a container for other ULS panels. + // However, this is used on sites with ULS + // in the personal bar, and in that case it has the same + // purpose as the selector in Display settings, + // so it has the same identifier. + ulsPurpose: 'interface-language' + } ); + + // Allow styles to apply first and position to work by + // delaying the activation after them. + window.setTimeout( function () { + $ulsTrigger.trigger( 'click', eventParams ); + }, 0 ); + } ); + } + }; + } + + $ulsTrigger.on( 'click', clickHandler ); + + // Bind language settings to preferences page link + $( '#uls-preferences-link' ) + .on( 'click keypress', function ( e ) { + if ( + e.type === 'click' || + e.type === 'keypress' && e.which === 13 + ) { + $ulsTrigger.trigger( 'click', { + source: 'preferences' + } ); + } + + return false; + } ); + } + + function initTooltip() { + var previousLanguage, currentLanguage, previousAutonym, currentAutonym; + + if ( !userCanChangeLanguage() ) { + return; + } + + previousLanguage = mw.storage.get( 'uls-previous-language-code' ); + currentLanguage = mw.config.get( 'wgUserLanguage' ); + previousAutonym = mw.storage.get( 'uls-previous-language-autonym' ); + currentAutonym = mw.config.get( 'wgULSCurrentAutonym' ); + + // If storage is empty, i.e. first visit, then store the current language + // immediately so that we know when it changes. + if ( !previousLanguage || !previousAutonym ) { + mw.storage.set( 'uls-previous-language-code', currentLanguage ); + mw.storage.set( 'uls-previous-language-autonym', currentAutonym ); + return; + } + + if ( previousLanguage !== currentLanguage ) { + mw.loader.using( 'oojs-ui-core' ).done( function () { + showUndoTooltip( previousLanguage, previousAutonym ); + } ); + mw.storage.set( 'uls-previous-language-code', currentLanguage ); + mw.storage.set( 'uls-previous-language-autonym', currentAutonym ); + // Store this language in a list of frequently used languages + mw.uls.addPreviousLanguage( currentLanguage ); + } + } + + function initIme() { + var imeSelector = mw.config.get( 'wgULSImeSelectors' ).join( ', ' ); + + $( 'body' ).on( 'focus.imeinit', imeSelector, function () { + var $input = $( this ); + $( 'body' ).off( '.imeinit' ); + mw.loader.using( 'ext.uls.ime', function () { + mw.ime.setup(); + mw.ime.handleFocus( $input ); + } ); + } ); + } + + function init() { + initInterface(); + initTooltip(); + initIme(); + } + + // Early execute of init + if ( document.readyState === 'interactive' ) { + init(); + } else { + $( init ); + } + +}() ); |