Avoid pointless use of isset() in LBFactoryMulti()
[mediawiki.git] / resources / src / jquery / jquery.accessKeyLabel.js
blobf25944c94efcd28be443385eb5f22e9990aa8a52
1 /**
2  * jQuery plugin to update the tooltip to show the correct access key
3  *
4  * @class jQuery.plugin.accessKeyLabel
5  */
6 ( function ( $, mw ) {
8         // Cached access key modifiers for used browser
9         var cachedAccessKeyModifiers,
11                 // Whether to use 'test-' instead of correct prefix (used for testing)
12                 useTestPrefix = false,
14                 // tag names which can have a label tag
15                 // https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_categories#Form-associated_content
16                 labelable = 'button, input, textarea, keygen, meter, output, progress, select';
18         /**
19          * Find the modifier keys that need to be pressed together with the accesskey to trigger the input.
20          *
21          * The result is dependant on the ua paramater or the current platform.
22          * For browsers that support accessKeyLabel, #getAccessKeyLabel never calls here.
23          * Valid key values that are returned can be: ctrl, alt, option, shift, esc
24          *
25          * @private
26          * @param {Object} [ua] An object with a 'userAgent' and 'platform' property.
27          * @return {Array} Array with 0 or more of the string values: ctrl, option, alt, shift, esc
28          */
29         function getAccessKeyModifiers( ua ) {
30                 var profile, accessKeyModifiers;
32                 // use cached prefix if possible
33                 if ( !ua && cachedAccessKeyModifiers ) {
34                         return cachedAccessKeyModifiers;
35                 }
37                 profile = $.client.profile( ua );
38                 accessKeyModifiers = [ 'alt' ];
40                 // Classic Opera on any platform
41                 if ( profile.name === 'opera' && profile.versionNumber < 15 ) {
42                         accessKeyModifiers = [ 'shift', 'esc' ];
44                 // Chrome and modern Opera on any platform
45                 } else if ( profile.name === 'chrome' || profile.name === 'opera' ) {
46                         accessKeyModifiers = (
47                                 profile.platform === 'mac' ?
48                                         // Chrome on Mac
49                                         [ 'ctrl', 'option' ] :
50                                         // Chrome on Windows or Linux
51                                         // (both alt- and alt-shift work, but alt with E, D, F etc does not
52                                         // work since they are browser shortcuts)
53                                         [ 'alt', 'shift' ]
54                         );
56                 // Non-Windows Safari with webkit_version > 526
57                 } else if ( profile.platform !== 'win' &&
58                         profile.name === 'safari' &&
59                         profile.layoutVersion > 526
60                 ) {
61                         accessKeyModifiers = [ 'ctrl', 'alt' ];
63                 // Safari/Konqueror on any platform, or any browser on Mac
64                 // (but not Safari on Windows)
65                 } else if (
66                         !( profile.platform === 'win' && profile.name === 'safari' ) &&
67                         (
68                                 profile.name === 'safari' ||
69                                 profile.platform === 'mac' ||
70                                 profile.name === 'konqueror'
71                         )
72                 ) {
73                         accessKeyModifiers = [ 'ctrl' ];
75                 // Firefox/Iceweasel 2.x and later
76                 } else if (
77                         ( profile.name === 'firefox' || profile.name === 'iceweasel' ) &&
78                         profile.versionBase > '1'
79                 ) {
80                         accessKeyModifiers = [ 'alt', 'shift' ];
81                 }
83                 // cache modifiers
84                 if ( !ua ) {
85                         cachedAccessKeyModifiers = accessKeyModifiers;
86                 }
87                 return accessKeyModifiers;
88         }
90         /**
91          * Get the access key label for an element.
92          *
93          * Will use native accessKeyLabel if available (currently only in Firefox 8+),
94          * falls back to #getAccessKeyModifiers.
95          *
96          * @private
97          * @param {HTMLElement} element Element to get the label for
98          * @return {string} Access key label
99          */
100         function getAccessKeyLabel( element ) {
101                 // abort early if no access key
102                 if ( !element.accessKey ) {
103                         return '';
104                 }
105                 // use accessKeyLabel if possible
106                 // https://html.spec.whatwg.org/multipage/interaction.html#dom-accesskeylabel
107                 if ( !useTestPrefix && element.accessKeyLabel ) {
108                         return element.accessKeyLabel;
109                 }
110                 return ( useTestPrefix ? 'test' : getAccessKeyModifiers().join( '-' ) ) + '-' + element.accessKey;
111         }
113         /**
114          * Update the title for an element (on the element with the access key or it's label) to show
115          * the correct access key label.
116          *
117          * @private
118          * @param {HTMLElement} element Element with the accesskey
119          * @param {HTMLElement} titleElement Element with the title to update (may be the same as `element`)
120          */
121         function updateTooltipOnElement( element, titleElement ) {
122                 var oldTitle, parts, regexp, newTitle, accessKeyLabel;
124                 oldTitle = titleElement.title;
125                 if ( !oldTitle ) {
126                         // don't add a title if the element didn't have one before
127                         return;
128                 }
130                 parts = ( mw.msg( 'word-separator' ) + mw.msg( 'brackets' ) ).split( '$1' );
131                 regexp = new RegExp( $.map( parts, mw.RegExp.escape ).join( '.*?' ) + '$' );
132                 newTitle = oldTitle.replace( regexp, '' );
133                 accessKeyLabel = getAccessKeyLabel( element );
135                 if ( accessKeyLabel ) {
136                         // Should be build the same as in Linker::titleAttrib
137                         newTitle += mw.msg( 'word-separator' ) + mw.msg( 'brackets', accessKeyLabel );
138                 }
139                 if ( oldTitle !== newTitle ) {
140                         titleElement.title = newTitle;
141                 }
142         }
144         /**
145          * Update the title for an element to show the correct access key label.
146          *
147          * @private
148          * @param {HTMLElement} element Element with the accesskey
149          */
150         function updateTooltip( element ) {
151                 var id, $element, $label, $labelParent;
152                 updateTooltipOnElement( element, element );
154                 // update associated label if there is one
155                 $element = $( element );
156                 if ( $element.is( labelable ) ) {
157                         // Search it using 'for' attribute
158                         id = element.id.replace( /"/g, '\\"' );
159                         if ( id ) {
160                                 $label = $( 'label[for="' + id + '"]' );
161                                 if ( $label.length === 1 ) {
162                                         updateTooltipOnElement( element, $label[ 0 ] );
163                                 }
164                         }
166                         // Search it as parent, because the form control can also be inside the label element itself
167                         $labelParent = $element.parents( 'label' );
168                         if ( $labelParent.length === 1 ) {
169                                 updateTooltipOnElement( element, $labelParent[ 0 ] );
170                         }
171                 }
172         }
174         /**
175          * Update the titles for all elements in a jQuery selection.
176          *
177          * @return {jQuery}
178          * @chainable
179          */
180         $.fn.updateTooltipAccessKeys = function () {
181                 return this.each( function () {
182                         updateTooltip( this );
183                 } );
184         };
186         /**
187          * getAccessKeyModifiers
188          *
189          * @method updateTooltipAccessKeys_getAccessKeyModifiers
190          * @inheritdoc #getAccessKeyModifiers
191          */
192         $.fn.updateTooltipAccessKeys.getAccessKeyModifiers = getAccessKeyModifiers;
194         /**
195          * getAccessKeyLabel
196          *
197          * @method updateTooltipAccessKeys_getAccessKeyLabel
198          * @inheritdoc #getAccessKeyLabel
199          */
200         $.fn.updateTooltipAccessKeys.getAccessKeyLabel = getAccessKeyLabel;
202         /**
203          * getAccessKeyPrefix
204          *
205          * @method updateTooltipAccessKeys_getAccessKeyPrefix
206          * @deprecated since 1.27 Use #getAccessKeyModifiers
207          * @param {Object} [ua] An object with a 'userAgent' and 'platform' property.
208          * @return {string}
209          */
210         $.fn.updateTooltipAccessKeys.getAccessKeyPrefix = function ( ua ) {
211                 return getAccessKeyModifiers( ua ).join( '-' ) + '-';
212         };
214         /**
215          * Switch test mode on and off.
216          *
217          * @method updateTooltipAccessKeys_setTestMode
218          * @param {boolean} mode New mode
219          */
220         $.fn.updateTooltipAccessKeys.setTestMode = function ( mode ) {
221                 useTestPrefix = mode;
222         };
224         /**
225          * @class jQuery
226          * @mixins jQuery.plugin.accessKeyLabel
227          */
229 }( jQuery, mediaWiki ) );