resources: Strip '$' and 'mw' from file closures
[lhc/web/wiklou.git] / resources / src / jquery / jquery.accessKeyLabel.js
1 /**
2 * jQuery plugin to update the tooltip to show the correct access key
3 *
4 * @class jQuery.plugin.accessKeyLabel
5 */
6 ( function () {
7
8 // Cached access key modifiers for used browser
9 var cachedAccessKeyModifiers,
10
11 // Whether to use 'test-' instead of correct prefix (used for testing)
12 useTestPrefix = false,
13
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';
17
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 1 or more of the string values, in this order: ctrl, option, alt, shift, esc
28 */
29 function getAccessKeyModifiers( ua ) {
30 var profile, accessKeyModifiers;
31
32 // use cached prefix if possible
33 if ( !ua && cachedAccessKeyModifiers ) {
34 return cachedAccessKeyModifiers;
35 }
36
37 profile = $.client.profile( ua );
38
39 switch ( profile.name ) {
40 case 'chrome':
41 case 'opera':
42 if ( profile.name === 'opera' && profile.versionNumber < 15 ) {
43 accessKeyModifiers = [ 'shift', 'esc' ];
44 } else if ( profile.platform === 'mac' ) {
45 accessKeyModifiers = [ 'ctrl', 'option' ];
46 } else {
47 // Chrome/Opera on Windows or Linux
48 // (both alt- and alt-shift work, but alt with E, D, F etc does not
49 // work since they are browser shortcuts)
50 accessKeyModifiers = [ 'alt', 'shift' ];
51 }
52 break;
53 case 'firefox':
54 case 'iceweasel':
55 if ( profile.versionBase < 2 ) {
56 // Before v2, Firefox used alt, though it was rebindable in about:config
57 accessKeyModifiers = [ 'alt' ];
58 } else {
59 if ( profile.platform === 'mac' ) {
60 if ( profile.versionNumber < 14 ) {
61 accessKeyModifiers = [ 'ctrl' ];
62 } else {
63 accessKeyModifiers = [ 'ctrl', 'option' ];
64 }
65 } else {
66 accessKeyModifiers = [ 'alt', 'shift' ];
67 }
68 }
69 break;
70 case 'safari':
71 case 'konqueror':
72 if ( profile.platform === 'win' ) {
73 accessKeyModifiers = [ 'alt' ];
74 } else {
75 if ( profile.layoutVersion > 526 ) {
76 // Non-Windows Safari with webkit_version > 526
77 accessKeyModifiers = [ 'ctrl', profile.platform === 'mac' ? 'option' : 'alt' ];
78 } else {
79 accessKeyModifiers = [ 'ctrl' ];
80 }
81 }
82 break;
83 case 'msie':
84 case 'edge':
85 accessKeyModifiers = [ 'alt' ];
86 break;
87 default:
88 accessKeyModifiers = profile.platform === 'mac' ? [ 'ctrl' ] : [ 'alt' ];
89 break;
90 }
91
92 // cache modifiers
93 if ( !ua ) {
94 cachedAccessKeyModifiers = accessKeyModifiers;
95 }
96 return accessKeyModifiers;
97 }
98
99 /**
100 * Get the access key label for an element.
101 *
102 * Will use native accessKeyLabel if available (currently only in Firefox 8+),
103 * falls back to #getAccessKeyModifiers.
104 *
105 * @private
106 * @param {HTMLElement} element Element to get the label for
107 * @return {string} Access key label
108 */
109 function getAccessKeyLabel( element ) {
110 // abort early if no access key
111 if ( !element.accessKey ) {
112 return '';
113 }
114 // use accessKeyLabel if possible
115 // https://html.spec.whatwg.org/multipage/interaction.html#dom-accesskeylabel
116 if ( !useTestPrefix && element.accessKeyLabel ) {
117 return element.accessKeyLabel;
118 }
119 return ( useTestPrefix ? 'test' : getAccessKeyModifiers().join( '-' ) ) + '-' + element.accessKey;
120 }
121
122 /**
123 * Update the title for an element (on the element with the access key or it's label) to show
124 * the correct access key label.
125 *
126 * @private
127 * @param {HTMLElement} element Element with the accesskey
128 * @param {HTMLElement} titleElement Element with the title to update (may be the same as `element`)
129 */
130 function updateTooltipOnElement( element, titleElement ) {
131 var oldTitle, parts, regexp, newTitle, accessKeyLabel,
132 separatorMsg = mw.message( 'word-separator' ).plain();
133
134 oldTitle = titleElement.title;
135 if ( !oldTitle ) {
136 // don't add a title if the element didn't have one before
137 return;
138 }
139
140 parts = ( separatorMsg + mw.message( 'brackets' ).plain() ).split( '$1' );
141 regexp = new RegExp( parts.map( mw.RegExp.escape ).join( '.*?' ) + '$' );
142 newTitle = oldTitle.replace( regexp, '' );
143 accessKeyLabel = getAccessKeyLabel( element );
144
145 if ( accessKeyLabel ) {
146 // Should be build the same as in Linker::titleAttrib
147 newTitle += separatorMsg + mw.message( 'brackets', accessKeyLabel ).plain();
148 }
149 if ( oldTitle !== newTitle ) {
150 titleElement.title = newTitle;
151 }
152 }
153
154 /**
155 * Update the title for an element to show the correct access key label.
156 *
157 * @private
158 * @param {HTMLElement} element Element with the accesskey
159 */
160 function updateTooltip( element ) {
161 var id, $element, $label, $labelParent;
162 updateTooltipOnElement( element, element );
163
164 // update associated label if there is one
165 $element = $( element );
166 if ( $element.is( labelable ) ) {
167 // Search it using 'for' attribute
168 id = element.id.replace( /"/g, '\\"' );
169 if ( id ) {
170 $label = $( 'label[for="' + id + '"]' );
171 if ( $label.length === 1 ) {
172 updateTooltipOnElement( element, $label[ 0 ] );
173 }
174 }
175
176 // Search it as parent, because the form control can also be inside the label element itself
177 $labelParent = $element.parents( 'label' );
178 if ( $labelParent.length === 1 ) {
179 updateTooltipOnElement( element, $labelParent[ 0 ] );
180 }
181 }
182 }
183
184 /**
185 * Update the titles for all elements in a jQuery selection.
186 *
187 * @return {jQuery}
188 * @chainable
189 */
190 $.fn.updateTooltipAccessKeys = function () {
191 return this.each( function () {
192 updateTooltip( this );
193 } );
194 };
195
196 /**
197 * getAccessKeyModifiers
198 *
199 * @method updateTooltipAccessKeys_getAccessKeyModifiers
200 * @inheritdoc #getAccessKeyModifiers
201 */
202 $.fn.updateTooltipAccessKeys.getAccessKeyModifiers = getAccessKeyModifiers;
203
204 /**
205 * getAccessKeyLabel
206 *
207 * @method updateTooltipAccessKeys_getAccessKeyLabel
208 * @inheritdoc #getAccessKeyLabel
209 */
210 $.fn.updateTooltipAccessKeys.getAccessKeyLabel = getAccessKeyLabel;
211
212 /**
213 * getAccessKeyPrefix
214 *
215 * @method updateTooltipAccessKeys_getAccessKeyPrefix
216 * @deprecated since 1.27 Use #getAccessKeyModifiers
217 * @param {Object} [ua] An object with a 'userAgent' and 'platform' property.
218 * @return {string}
219 */
220 $.fn.updateTooltipAccessKeys.getAccessKeyPrefix = function ( ua ) {
221 return getAccessKeyModifiers( ua ).join( '-' ) + '-';
222 };
223
224 /**
225 * Switch test mode on and off.
226 *
227 * @method updateTooltipAccessKeys_setTestMode
228 * @param {boolean} mode New mode
229 */
230 $.fn.updateTooltipAccessKeys.setTestMode = function ( mode ) {
231 useTestPrefix = mode;
232 };
233
234 /**
235 * @class jQuery
236 * @mixins jQuery.plugin.accessKeyLabel
237 */
238
239 }() );