519e39bc8ea351991250622f12d8fe72cb97999c
[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 array = ( mw.msg( 'word-separator' ) + mw.msg( 'brackets' ) ).split( '$1' ),
117 regexp = new RegExp( $.map( array, mw.RegExp.escape ).join( '.*?' ) + '$' ),
118 oldTitle = titleElement.title,
119 rawTitle = oldTitle.replace( regexp, '' ),
120 newTitle = rawTitle,
121 accessKeyLabel = getAccessKeyLabel( element );
122
123 // don't add a title if the element didn't have one before
124 if ( !oldTitle ) {
125 return;
126 }
127
128 if ( accessKeyLabel ) {
129 // Should be build the same as in Linker::titleAttrib
130 newTitle += mw.msg( 'word-separator' ) + mw.msg( 'brackets', accessKeyLabel );
131 }
132 if ( oldTitle !== newTitle ) {
133 titleElement.title = newTitle;
134 }
135 }
136
137 /**
138 * Update the title for an element to show the correct access key label.
139 *
140 * @private
141 * @param {HTMLElement} element Element with the accesskey
142 */
143 function updateTooltip( element ) {
144 var id, $element, $label, $labelParent;
145 updateTooltipOnElement( element, element );
146
147 // update associated label if there is one
148 $element = $( element );
149 if ( $element.is( labelable ) ) {
150 // Search it using 'for' attribute
151 id = element.id.replace( /"/g, '\\"' );
152 if ( id ) {
153 $label = $( 'label[for="' + id + '"]' );
154 if ( $label.length === 1 ) {
155 updateTooltipOnElement( element, $label[ 0 ] );
156 }
157 }
158
159 // Search it as parent, because the form control can also be inside the label element itself
160 $labelParent = $element.parents( 'label' );
161 if ( $labelParent.length === 1 ) {
162 updateTooltipOnElement( element, $labelParent[ 0 ] );
163 }
164 }
165 }
166
167 /**
168 * Update the titles for all elements in a jQuery selection.
169 *
170 * @return {jQuery}
171 * @chainable
172 */
173 $.fn.updateTooltipAccessKeys = function () {
174 return this.each( function () {
175 updateTooltip( this );
176 } );
177 };
178
179 /**
180 * getAccessKeyModifiers
181 *
182 * @method updateTooltipAccessKeys_getAccessKeyModifiers
183 * @inheritdoc #getAccessKeyModifiers
184 */
185 $.fn.updateTooltipAccessKeys.getAccessKeyModifiers = getAccessKeyModifiers;
186
187 /**
188 * getAccessKeyLabel
189 *
190 * @method updateTooltipAccessKeys_getAccessKeyLabel
191 * @inheritdoc #getAccessKeyLabel
192 */
193 $.fn.updateTooltipAccessKeys.getAccessKeyLabel = getAccessKeyLabel;
194
195 /**
196 * getAccessKeyPrefix
197 *
198 * @method updateTooltipAccessKeys_getAccessKeyPrefix
199 * @deprecated 1.27 Use #getAccessKeyModifiers
200 */
201 $.fn.updateTooltipAccessKeys.getAccessKeyPrefix = function ( ua ) {
202 return getAccessKeyModifiers( ua ).join( '-' ) + '-';
203 };
204
205 /**
206 * Switch test mode on and off.
207 *
208 * @method updateTooltipAccessKeys_setTestMode
209 * @param {boolean} mode New mode
210 */
211 $.fn.updateTooltipAccessKeys.setTestMode = function ( mode ) {
212 useTestPrefix = mode;
213 };
214
215 /**
216 * @class jQuery
217 * @mixins jQuery.plugin.accessKeyLabel
218 */
219
220 }( jQuery, mediaWiki ) );