Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F1431407
ext.uls.interface.js
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
25 KB
Referenced Files
None
Subscribers
None
ext.uls.interface.js
View Options
/*!
* 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'
;
var
languageSettingsModules
=
[
'ext.uls.displaysettings'
],
launchULS
=
require
(
'./ext.uls.launch.js'
),
ActionsMenu
=
require
(
'./ext.uls.actions.menu.js'
),
ActionsMenuItem
=
require
(
'./ext.uls.actions.menu.item.js'
);
require
(
'./ext.uls.actions.menu.items.registry.js'
);
/**
* For Vector, check if the language button id exists.
* For other skins, check wgULSDisplaySettingsInInterlanguage for the current skin.
*
* @return {boolean}
*/
function
isUsingStandaloneLanguageButton
()
{
// Checking for the ULS language button id returns true for Vector, false for other skins.
return
$
(
'#p-lang-btn'
).
length
>
0
||
mw
.
config
.
get
(
'wgULSDisplaySettingsInInterlanguage'
);
}
/**
* @param {jQuery} $element
* @param {Function} onCloseHandler
* @param {Object} uls
*/
function
openLanguageSettings
(
$element
,
onCloseHandler
,
uls
)
{
mw
.
loader
.
using
(
languageSettingsModules
).
then
(
function
()
{
$element
.
languagesettings
(
{
defaultModule
:
'display'
,
onClose
:
onCloseHandler
,
onPosition
:
uls
.
position
.
bind
(
uls
),
onVisible
:
uls
.
hide
.
bind
(
uls
)
}
).
trigger
(
'click'
);
}
);
}
/**
* Provide entry points to create article in other languages. T290436
*
* @param {Object} uls The ULS object
*/
function
addEmptyState
(
uls
)
{
var
$emptyStateContainer
=
$
(
'<section>'
).
addClass
(
'uls-empty-state'
);
function
openActionsMenuEventHandler
(
event
)
{
event
.
stopPropagation
();
function
onMenuClose
()
{
uls
.
show
();
}
openLanguageSettings
(
$
(
event
.
target
),
onMenuClose
,
uls
);
}
var
languageSettingsMenuItem
=
{
name
:
'languageSettings'
,
icon
:
'settings'
,
text
:
$
.
i18n
(
'ext-uls-actions-menu-language-settings-item-label'
),
handler
:
openActionsMenuEventHandler
};
var
actionItemsRegistry
=
mw
.
uls
.
ActionsMenuItemsRegistry
;
actionItemsRegistry
.
register
(
languageSettingsMenuItem
);
var
$header
=
$
(
'<h3>'
)
.
addClass
(
'uls-empty-state__header'
)
.
text
(
$
.
i18n
(
'ext-uls-empty-state-header'
)
);
var
$desc
=
$
(
'<p>'
)
.
addClass
(
'uls-empty-state__desc'
)
.
text
(
$
.
i18n
(
'ext-uls-empty-state-desc'
)
);
$emptyStateContainer
.
append
(
$header
,
$desc
);
uls
.
$resultsView
.
append
(
$emptyStateContainer
);
if
(
actionItemsRegistry
.
size
()
>
1
)
{
// languageSettingsMenuItem will be always there.
// If other actions available, change text
$header
.
text
(
$
.
i18n
(
'ext-uls-empty-state-header-actions-available'
)
);
$desc
.
text
(
$
.
i18n
(
'ext-uls-empty-state-desc-actions-available'
)
);
}
// Action menu items need OOUI widgets. Load them and register trigger event handler.
mw
.
loader
.
using
(
[
'oojs-ui-widgets'
,
'oojs-ui.styles.icons-interactions'
]
).
done
(
function
()
{
var
$actionsList
=
$
(
'<ul>'
).
addClass
(
'uls-language-action-items'
);
actionItemsRegistry
.
getItems
().
forEach
(
function
(
actionItem
)
{
var
actionButton
=
new
ActionsMenuItem
(
actionItem
.
icon
,
actionItem
.
text
,
actionItem
.
handler
,
actionItem
.
href
).
render
();
$actionsList
.
append
(
$
(
'<li>'
).
append
(
actionButton
.
$element
)
);
}
);
$emptyStateContainer
.
append
(
$actionsList
);
}
);
}
/**
* Helper method for creating jQuery buttons, used in "addActionsMenuTriggers" method below
*
* @param {string} buttonClass a class to be added to the created button class list
* @return {jQuery}
*/
function
createMenuButton
(
buttonClass
)
{
var
classes
=
[
'cdx-button'
,
'cdx-button--weight-quiet'
,
buttonClass
];
// eslint-disable-next-line mediawiki/class-doc
return
$
(
'<button>'
).
addClass
(
classes
);
}
/**
* @param {Object} uls The ULS object
* @return {jQuery}
*/
function
addLanguageSettingsTrigger
(
uls
)
{
var
$ulsSettingsBlock
=
uls
.
$menu
.
find
(
'#uls-settings-block'
).
eq
(
0
);
$ulsSettingsBlock
.
addClass
(
'uls-settings-block--vector-2022'
);
var
$languageSettingsMenuButton
=
createMenuButton
(
'uls-language-settings-button'
);
$languageSettingsMenuButton
.
one
(
'click'
,
function
()
{
openLanguageSettings
(
$languageSettingsMenuButton
,
uls
.
show
.
bind
(
uls
),
uls
);
}
);
$ulsSettingsBlock
.
append
(
$languageSettingsMenuButton
);
uls
.
$menu
.
addClass
(
'notheme skin-invert'
);
// T365990
return
$ulsSettingsBlock
;
}
/**
* Add the button that opens the "Add languages" menu (that contain options
* like "Translate this page" and "Edit language links") and the button that
* opens the "Language settings" menu.
*
* @param {Object} uls The ULS object
*/
function
addActionsMenuTriggers
(
uls
)
{
var
$ulsSettingsBlock
=
addLanguageSettingsTrigger
(
uls
);
var
actionItemsRegistry
=
mw
.
uls
.
ActionsMenuItemsRegistry
;
actionItemsRegistry
.
on
(
'register'
,
onActionItemAdded
);
var
addLanguagesMenuDialog
;
var
$addLanguagesMenuButton
;
var
prependAddLanguagesMenuButton
=
function
()
{
$addLanguagesMenuButton
=
createMenuButton
(
'uls-add-languages-button'
).
attr
(
{
'data-i18n'
:
'ext-uls-add-languages-button-label'
}
).
i18n
();
$ulsSettingsBlock
.
addClass
(
'uls-settings-block--with-add-languages'
);
$ulsSettingsBlock
.
prepend
(
$addLanguagesMenuButton
);
// Action menu items need OOUI widgets. Load them and register trigger event handler.
mw
.
loader
.
using
(
[
'oojs-ui-widgets'
,
'oojs-ui.styles.icons-interactions'
]
).
done
(
function
()
{
$addLanguagesMenuButton
.
on
(
'click'
,
function
()
{
addLanguagesMenuDialog
=
addLanguagesMenuDialog
||
new
ActionsMenu
(
{
actions
:
actionItemsRegistry
.
getItems
(),
onPosition
:
uls
.
position
.
bind
(
uls
),
onClose
:
uls
.
show
.
bind
(
uls
)
}
);
addLanguagesMenuDialog
.
render
();
uls
.
hide
();
}
);
}
);
};
if
(
actionItemsRegistry
.
size
()
)
{
prependAddLanguagesMenuButton
();
}
function
onActionItemAdded
(
itemName
,
item
)
{
if
(
!
$addLanguagesMenuButton
)
{
prependAddLanguagesMenuButton
();
}
else
if
(
addLanguagesMenuDialog
)
{
addLanguagesMenuDialog
.
renderAction
(
item
);
}
}
}
function
userCanChangeLanguage
()
{
return
mw
.
config
.
get
(
'wgULSAnonCanChangeLanguage'
)
||
mw
.
user
.
isNamed
();
}
/**
* 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
trigger
,
popup
,
popupPosition
,
configPosition
=
mw
.
config
.
get
(
'wgULSPosition'
),
triggerSelector
=
(
configPosition
===
'interlanguage'
)
?
'.uls-settings-trigger, .mw-interlanguage-selector'
:
'.uls-trigger'
;
// Fallback if no entry point is present
trigger
=
document
.
querySelector
(
triggerSelector
)
||
document
.
querySelector
(
'#pt-preferences'
);
// Skip tooltip if there is no element to attach the tooltip to.
// It will cause errors otherwise.
if
(
!
trigger
)
{
return
;
}
function
hideTipsy
()
{
popup
.
toggle
(
false
);
}
function
showTipsy
(
timeout
)
{
var
tipsyTimer
=
0
;
popup
.
toggle
(
true
);
popup
.
toggleClipping
(
false
);
// if the mouse is over the tooltip, do not hide
$
(
'.uls-tipsy'
).
on
(
'mouseover'
,
function
()
{
clearTimeout
(
tipsyTimer
);
}
).
on
(
'mouseout'
,
function
()
{
tipsyTimer
=
setTimeout
(
hideTipsy
,
timeout
);
}
).
on
(
'click'
,
hideTipsy
);
tipsyTimer
=
setTimeout
(
hideTipsy
,
timeout
);
}
if
(
configPosition
===
'interlanguage'
)
{
popupPosition
=
'after'
;
}
else
{
popupPosition
=
'below'
;
}
popup
=
new
OO
.
ui
.
PopupWidget
(
{
padded
:
true
,
width
:
300
,
classes
:
[
'uls-tipsy'
],
// Automatically positioned relative to the trigger
$floatableContainer
:
$
(
trigger
),
position
:
popupPosition
,
$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
)
{
event
.
preventDefault
();
// Track if event logging is enabled
mw
.
hook
(
'mw.uls.language.revert'
).
fire
();
mw
.
loader
.
using
(
[
'ext.uls.common'
]
).
then
(
function
()
{
mw
.
uls
.
changeLanguage
(
event
.
target
.
lang
);
}
);
}
);
if
(
mw
.
storage
.
get
(
'uls-gp'
)
===
'1'
)
{
messageKey
=
'ext-uls-undo-language-tooltip-text-local'
;
}
else
{
messageKey
=
'ext-uls-undo-language-tooltip-text'
;
}
// Message keys listed above
// eslint-disable-next-line mediawiki/msg-doc
return
$
(
'<p>'
).
append
(
mw
.
message
(
messageKey
,
$link
).
parseDom
()
);
}()
)
}
);
popup
.
$element
.
appendTo
(
document
.
body
);
// The interlanguage position needs some time to settle down
setTimeout
(
function
()
{
// Show the tipsy tooltip on page load.
showTipsy
(
6000
);
},
700
);
// manually show the tooltip
$
(
trigger
).
on
(
'mouseover'
,
function
()
{
// show only if the ULS panel is not shown
// eslint-disable-next-line no-jquery/no-sizzle
if
(
!
$
(
'.uls-menu:visible'
).
length
)
{
showTipsy
(
3000
);
}
}
);
}
function
initSecondaryEntryPoints
()
{
$
(
'.uls-settings-trigger'
).
one
(
'click'
,
function
(
e
)
{
e
.
preventDefault
();
mw
.
loader
.
using
(
languageSettingsModules
,
function
()
{
$
(
e
.
target
).
languagesettings
();
$
(
e
.
target
).
trigger
(
'click'
);
}
);
}
);
}
function
initInterlanguageEntryPoint
()
{
var
$pLang
=
$
(
'#p-lang'
);
var
$trigger
=
$
(
'<button>'
)
.
addClass
(
'uls-settings-trigger'
)
.
prop
(
'title'
,
mw
.
msg
(
'ext-uls-select-language-settings-icon-tooltip'
)
);
// Append ULS cog to interlanguage section header in the sidebar
$pLang
.
prepend
(
$trigger
);
// Replace the title of the interlanguage links area from "In other languages" to
// "Languages" if there are no language links. TODO: Remove this feature?
if
(
!
$pLang
.
find
(
'div ul'
).
children
().
length
&&
isUsingStandaloneLanguageButton
)
{
$pLang
.
find
(
'h3'
).
text
(
mw
.
msg
(
'uls-plang-title-languages'
)
);
}
var
clickHandler
=
function
(
e
)
{
var
languagesettings
=
$trigger
.
data
(
'languagesettings'
),
languageSettingsOptions
;
if
(
languagesettings
)
{
if
(
!
languagesettings
.
shown
)
{
mw
.
hook
(
'mw.uls.settings.open'
).
fire
(
'interlanguage'
);
}
return
;
}
// Initialize the Language settings window
languageSettingsOptions
=
{
defaultModule
:
'display'
,
onPosition
:
function
()
{
var
caretRadius
,
top
,
left
,
ulsTriggerHeight
=
this
.
$element
.
height
(),
ulsTriggerWidth
=
this
.
$element
[
0
].
offsetWidth
,
ulsTriggerOffset
=
this
.
$element
.
offset
();
// Same as border width in mixins.less, or near enough
caretRadius
=
12
;
if
(
ulsTriggerOffset
.
left
>
$
(
window
).
width
()
/
2
)
{
left
=
ulsTriggerOffset
.
left
-
this
.
$window
.
width
()
-
caretRadius
;
this
.
$window
.
removeClass
(
'selector-left'
).
addClass
(
'selector-right'
);
}
else
{
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
top
=
ulsTriggerOffset
.
top
+
(
ulsTriggerHeight
/
2
)
-
(
caretRadius
+
16
);
return
{
top
:
top
,
left
:
left
};
},
onVisible
:
function
()
{
this
.
$window
.
addClass
(
'callout'
);
}
};
mw
.
loader
.
using
(
languageSettingsModules
,
function
()
{
$trigger
.
languagesettings
(
languageSettingsOptions
).
trigger
(
'click'
);
}
);
e
.
stopPropagation
();
};
$trigger
.
on
(
'click'
,
clickHandler
);
}
function
initPersonalEntryPoint
()
{
var
$trigger
=
$
(
'.uls-trigger'
);
var
clickHandler
;
if
(
!
userCanChangeLanguage
()
)
{
clickHandler
=
function
(
e
)
{
var
languagesettings
=
$trigger
.
data
(
'languagesettings'
);
e
.
preventDefault
();
if
(
languagesettings
)
{
if
(
!
languagesettings
.
shown
)
{
mw
.
hook
(
'mw.uls.settings.open'
).
fire
(
'personal'
);
}
}
else
{
mw
.
loader
.
using
(
languageSettingsModules
,
function
()
{
$trigger
.
languagesettings
(
{
autoOpen
:
true
}
);
mw
.
hook
(
'mw.uls.settings.open'
).
fire
(
'personal'
);
}
);
// Stop propagating the event to avoid closing the languagesettings dialog
// when the event propagates to the document click handler inside
// languagesettings
e
.
stopPropagation
();
}
};
}
else
{
clickHandler
=
function
(
e
,
eventParams
)
{
var
uls
=
$trigger
.
data
(
'uls'
);
e
.
preventDefault
();
if
(
uls
)
{
if
(
!
uls
.
shown
)
{
mw
.
hook
(
'mw.uls.settings.open'
).
fire
(
'personal'
);
}
}
else
{
mw
.
loader
.
using
(
'ext.uls.mediawiki'
,
function
()
{
$trigger
.
uls
(
{
quickList
:
function
()
{
return
mw
.
uls
.
getFrequentLanguageList
();
},
// partially copied from ext.uls.lauch
onPosition
:
function
()
{
// Default positioning of jquery.uls is middle of the screen under
// the trigger. This code aligns it under the trigger and to the
// trigger edge depending on which side of the page the trigger is
// It should work automatically both LTR and RTL.
var
offset
,
height
,
width
,
positionCSS
;
offset
=
$trigger
.
offset
();
width
=
$trigger
.
outerWidth
();
height
=
$trigger
.
outerHeight
();
if
(
offset
.
left
+
(
width
/
2
)
>
$
(
window
).
width
()
/
2
)
{
// Midpoint of the trigger is on the right side of the viewport.
positionCSS
=
{
// Right dialog edge aligns with right edge of the trigger.
right
:
$
(
window
).
width
()
-
(
offset
.
left
+
width
),
top
:
offset
.
top
+
height
};
}
else
{
// Midpoint of the trigger is on the left side of the viewport.
positionCSS
=
{
// Left dialog edge aligns with left edge of the trigger.
left
:
offset
.
left
,
top
:
offset
.
top
+
height
};
}
return
positionCSS
;
},
onReady
:
function
()
{
addLanguageSettingsTrigger
(
this
);
},
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.
setTimeout
(
function
()
{
$trigger
.
trigger
(
'click'
,
eventParams
);
},
0
);
}
);
}
};
}
$trigger
.
on
(
'click'
,
clickHandler
);
// Optimization: Prefetch the Resource loader modules for ULS on mouseover
$trigger
.
one
(
'mouseover'
,
function
()
{
mw
.
loader
.
load
(
languageSettingsModules
);
}
);
}
function
initLanguageChangeUndoTooltip
()
{
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
=
require
(
'../data.json'
).
currentAutonym
;
// 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
.
loader
.
using
(
[
'ext.uls.common'
]
).
then
(
function
()
{
mw
.
uls
.
addPreviousLanguage
(
currentLanguage
);
}
);
}
}
function
initIme
()
{
var
imeSelector
=
mw
.
config
.
get
(
'wgULSImeSelectors'
).
join
(
', '
);
$
(
document
.
body
).
on
(
'focus.imeinit'
,
imeSelector
,
function
()
{
var
$input
=
$
(
this
);
$
(
document
.
body
).
off
(
'.imeinit'
);
mw
.
loader
.
using
(
'ext.uls.ime'
,
function
()
{
mw
.
ime
.
setup
();
mw
.
ime
.
handleFocus
(
$input
);
}
);
}
);
}
/**
* Special handling for checkbox hack.
* Disable default checkbox behavior and bind click to "Enter" keyboard events
*/
function
handleCheckboxSelector
()
{
// If the ULS button is also a checkbox, we can
// conclude that it's using the checkbox hack.
$
(
document
).
on
(
'input'
,
'input.mw-interlanguage-selector[type="checkbox"]'
,
function
(
ev
)
{
var
elem
=
ev
.
currentTarget
;
elem
.
checked
=
false
;
}
);
$
(
document
).
on
(
'keydown'
,
'input.mw-interlanguage-selector[type="checkbox"]'
,
function
(
ev
)
{
var
elem
=
ev
.
currentTarget
;
if
(
ev
.
key
!==
'Enter'
)
{
return
;
}
elem
.
click
();
}
);
}
/**
* Load and open ULS for content language selection.
*
* This dialog is primarily for selecting the language of the content, but may also provide
* access to display and input settings if isUsingStandaloneLanguageButton() returns true.
*
* @param {jQuery.Event} ev
*/
function
loadContentLanguageSelector
(
ev
)
{
var
$target
=
$
(
ev
.
currentTarget
);
// Avoid reinitializing ULS multiple times for an element
if
(
$target
.
attr
(
'data-uls-loaded'
)
)
{
return
;
}
$target
.
attr
(
'data-uls-loaded'
,
true
);
ev
.
preventDefault
();
mw
.
loader
.
using
(
[
'ext.uls.mediawiki'
,
'@wikimedia/codex'
]
).
then
(
function
()
{
var
parent
,
languageNodes
,
standalone
,
uls
;
parent
=
document
.
querySelectorAll
(
'.mw-portlet-lang, #p-lang'
)[
0
];
languageNodes
=
parent
?
parent
.
querySelectorAll
(
'.interlanguage-link-target'
)
:
[];
standalone
=
isUsingStandaloneLanguageButton
();
// Setup click handler for ULS
launchULS
(
$target
,
mw
.
uls
.
getInterlanguageListFromNodes
(
languageNodes
),
// Using this as heuristic for now. May need to reconsider later. Enables
// behavior specific to compact language links.
!
standalone
);
// Trigger the click handler to open ULS once ready
if
(
standalone
)
{
// Provide access to display and input settings if this entry point is the single
// point of access to all language settings.
uls
=
$target
.
data
(
'uls'
);
if
(
languageNodes
.
length
)
{
addActionsMenuTriggers
(
uls
);
}
else
{
// first hide #uls-settings-block div since it's unused, and it causes
// an unwanted extra border to show up at the bottom of the menu
uls
.
$menu
.
find
(
'#uls-settings-block'
).
eq
(
0
).
hide
();
// There are no languages - The article exist only the current language wiki
// Provide entry points to create article in other languages. T290436
addEmptyState
(
uls
);
}
$target
.
trigger
(
'click'
);
}
else
{
$target
.
trigger
(
'click'
);
}
}
);
}
/** Setup lazy-loading for content language selector */
function
initContentLanguageSelectorClickHandler
()
{
// FIXME: In Timeless ULS is embedded in a menu which stops event propagation
if
(
$
(
'.sidebar-inner'
).
length
)
{
$
(
'.sidebar-inner #p-lang'
)
.
one
(
'click'
,
'.mw-interlanguage-selector'
,
loadContentLanguageSelector
);
}
else
{
// This button may be created by the new Vector skin, or ext.uls.compactlinks module
// if there are many languages. Warning: Both this module and ext.uls.compactlinks
// module may run simultaneously. Using event delegation to avoid race conditions where
// the trigger may be created after this code.
$
(
document
).
on
(
'click'
,
'.mw-interlanguage-selector'
,
loadContentLanguageSelector
);
// Special handling for checkbox hack.
handleCheckboxSelector
();
}
}
/**
* The new Vector 2022 skin uses a less prominent language button for non-content pages.
* For these pages, the ULS should not be displayed, but a dropdown with an appropriate message
* should appear. The UniversalLanguageSelector extension should add a button to open the
* language settings, inside this dropdown.
* This method adds this button inside the dropdown.
*/
function
addLanguageSettingsToNonContentPages
()
{
var
$languageBtn
=
$
(
'#p-lang-btn'
);
var
clickHandler
=
function
(
event
)
{
event
.
stopPropagation
();
mw
.
loader
.
using
(
languageSettingsModules
).
then
(
function
()
{
$
(
event
.
target
).
languagesettings
(
{
autoOpen
:
true
,
onPosition
:
function
()
{
var
offset
=
$languageBtn
.
offset
();
var
top
=
offset
.
top
+
$languageBtn
.
outerHeight
();
var
right
=
$
(
window
).
width
()
-
offset
.
left
-
$languageBtn
.
outerWidth
();
return
{
top
:
top
,
right
:
right
};
}
}
);
}
);
};
// the first time the language button is clicked inside a non-content page,
// we should add the "Open language settings" button inside the dropdown
$languageBtn
.
one
(
'mouseover'
,
function
()
{
mw
.
loader
.
using
(
[
'oojs-ui-widgets'
,
'oojs-ui.styles.icons-interactions'
,
'ext.uls.messages'
]
)
.
done
(
function
()
{
var
actionButton
=
new
ActionsMenuItem
(
'settings'
,
$
.
i18n
(
'ext-uls-actions-menu-language-settings-item-label'
),
clickHandler
,
null
).
render
();
actionButton
.
$element
.
addClass
(
'empty-language-selector__language-settings-button'
);
var
$emptyLanguageSelectorBody
=
$
(
'.mw-portlet-empty-language-selector-body'
);
$emptyLanguageSelectorBody
.
after
(
actionButton
.
$element
);
}
);
}
);
}
function
init
()
{
// if it's not Vector skin, nothing to be done here
if
(
mw
.
config
.
get
(
'skin'
)
===
'vector-2022'
&&
mw
.
config
.
get
(
'wgULSisLanguageSelectorEmpty'
)
)
{
// if this is a non-content page, we should add the "Open language settings" button
// inside the language dropdown
addLanguageSettingsToNonContentPages
();
}
initLanguageChangeUndoTooltip
();
initIme
();
// There are three basic components of ULS interface:
// - language selection for interface
// - language selection for content
// - settings view (access to language selection for interface, fonts, input methods)
//
// These can be combined in different ways:
// - Vector skin (recently) has an omni selector that has content language selection as
// primary action with access to the settings view. It is on top right corner (LTR) of
// the page content area. It may not be present on all pages.
// - Compact language links provides access to content language selection only and it is in
// the interlanguage section of the sidebar. This is in addition to one of the main entry
// points below.
// - Personal entry point appears at the top of the page. It provides quick access to the
// interface language selection with access to the settings view, except if user is not
// logged in and not allowed to change a language. In this case it defaults to settings
// view without language selection.
// - Interlanguage entry point (a cog) appears in the interlanguage section in the sidebar.
// It defaults to the settings view.
//
// The three main entry points (omni selector, personal, interlanguage) are mutually
// exclusive. There may be secondary entry points anywhere on the page using the
// uls-settings-trigger class.
// First init secondary to avoid initing the interlanguage entry point multiple times
initSecondaryEntryPoints
();
var
position
=
mw
.
config
.
get
(
'wgULSPosition'
);
if
(
position
===
'interlanguage'
)
{
initInterlanguageEntryPoint
();
}
else
{
initPersonalEntryPoint
();
}
// whether to load compact language links
var
compact
=
mw
.
config
.
get
(
'wgULSisCompactLinksEnabled'
);
// whether to show the omni box or not
var
languageInHeader
=
mw
.
config
.
get
(
'wgVector2022LanguageInHeader'
);
if
(
compact
||
languageInHeader
)
{
// Init compact languages OR omni selector using the mw-interlanguage-selector class
initContentLanguageSelectorClickHandler
();
}
else
{
$
(
'.mw-interlanguage-selector'
).
removeClass
(
'mw-interlanguage-selector'
);
document
.
body
.
classList
.
add
(
'mw-interlanguage-selector-disabled'
);
}
}
// Early execute of init
if
(
document
.
readyState
===
'interactive'
)
{
init
();
}
else
{
$
(
init
);
}
}()
);
File Metadata
Details
Attached
Mime Type
text/x-asm
Expires
Sat, May 16, 20:26 (1 d, 4 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
39/3c/7f02ce3ca85d2d981f0b6932e2c2
Default Alt Text
ext.uls.interface.js (25 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment