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