Merge "Make NumericUppercaseCollation use localized digit transforms"
[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 ( $, mw ) {
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 0 or more of the string values: 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 accessKeyModifiers = [ 'alt' ];
39
40 // Classic Opera on any platform
41 if ( profile.name === 'opera' && profile.versionNumber < 15 ) {
42 accessKeyModifiers = [ 'shift', 'esc' ];
43
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 );
55
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' ];
62
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' ];
74
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 }
82
83 // cache modifiers
84 if ( !ua ) {
85 cachedAccessKeyModifiers = accessKeyModifiers;
86 }
87 return accessKeyModifiers;
88 }
89
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 }
112
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;
123
124 oldTitle = titleElement.title;
125 if ( !oldTitle ) {
126 // don't add a title if the element didn't have one before
127 return;
128 }
129
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 );
134
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 }
143
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 );
153
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 }
165
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 }
173
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 };
185
186 /**
187 * getAccessKeyModifiers
188 *
189 * @method updateTooltipAccessKeys_getAccessKeyModifiers
190 * @inheritdoc #getAccessKeyModifiers
191 */
192 $.fn.updateTooltipAccessKeys.getAccessKeyModifiers = getAccessKeyModifiers;
193
194 /**
195 * getAccessKeyLabel
196 *
197 * @method updateTooltipAccessKeys_getAccessKeyLabel
198 * @inheritdoc #getAccessKeyLabel
199 */
200 $.fn.updateTooltipAccessKeys.getAccessKeyLabel = getAccessKeyLabel;
201
202 /**
203 * getAccessKeyPrefix
204 *
205 * @method updateTooltipAccessKeys_getAccessKeyPrefix
206 * @deprecated since 1.27 Use #getAccessKeyModifiers
207 */
208 $.fn.updateTooltipAccessKeys.getAccessKeyPrefix = function ( ua ) {
209 return getAccessKeyModifiers( ua ).join( '-' ) + '-';
210 };
211
212 /**
213 * Switch test mode on and off.
214 *
215 * @method updateTooltipAccessKeys_setTestMode
216 * @param {boolean} mode New mode
217 */
218 $.fn.updateTooltipAccessKeys.setTestMode = function ( mode ) {
219 useTestPrefix = mode;
220 };
221
222 /**
223 * @class jQuery
224 * @mixins jQuery.plugin.accessKeyLabel
225 */
226
227 }( jQuery, mediaWiki ) );