jquery.accessKeyLabel: Minor code and documentation clean up
[mediawiki.git] / resources / src / jquery / jquery.accessKeyLabel.js
blob4caf072745ae1b5ff16a734a61fe997db460213c
1 /**
2  * jQuery plugin to update the tooltip to show the correct access key
3  *
4  * @class jQuery.plugin.accessKeyLabel
5  */
6 ( function ( $ ) {
8 // Cached access key prefix for used browser
9 var cachedAccessKeyPrefix,
11         // Wether 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  * Get the prefix for the access key for browsers that don't support accessKeyLabel.
20  *
21  * For browsers that support accessKeyLabel, #getAccessKeyLabel never calls here.
22  *
23  * @private
24  * @param {Object} [ua] An object with a 'userAgent' and 'platform' property.
25  * @return {string} Access key prefix
26  */
27 function getAccessKeyPrefix( ua ) {
28         // use cached prefix if possible
29         if ( !ua && cachedAccessKeyPrefix ) {
30                 return cachedAccessKeyPrefix;
31         }
33         var profile = $.client.profile( ua ),
34                 accessKeyPrefix = 'alt-';
36         // Opera on any platform
37         if ( profile.name === 'opera' ) {
38                 accessKeyPrefix = 'shift-esc-';
40         // Chrome on any platform
41         } else if ( profile.name === 'chrome' ) {
42                 accessKeyPrefix = (
43                         profile.platform === 'mac'
44                                 // Chrome on Mac
45                                 ? 'ctrl-option-'
46                                 // Chrome on Windows or Linux
47                                 // (both alt- and alt-shift work, but alt with E, D, F etc does not
48                                 // work since they are browser shortcuts)
49                                 : 'alt-shift-'
50                 );
52         // Non-Windows Safari with webkit_version > 526
53         } else if ( profile.platform !== 'win'
54                 && profile.name === 'safari'
55                 && profile.layoutVersion > 526
56         ) {
57                 accessKeyPrefix = 'ctrl-alt-';
59         // Safari/Konqueror on any platform, or any browser on Mac
60         // (but not Safari on Windows)
61         } else if ( !( profile.platform === 'win' && profile.name === 'safari' )
62                 && ( profile.name === 'safari'
63                 || profile.platform === 'mac'
64                 || profile.name === 'konqueror' )
65         ) {
66                 accessKeyPrefix = 'ctrl-';
68         // Firefox/Iceweasel 2.x and later
69         } else if ( ( profile.name === 'firefox' || profile.name === 'iceweasel' )
70                 && profile.versionBase > '1'
71         ) {
72                 accessKeyPrefix = 'alt-shift-';
73         }
75         // cache prefix
76         if ( !ua ) {
77                 cachedAccessKeyPrefix = accessKeyPrefix;
78         }
79         return accessKeyPrefix;
82 /**
83  * Get the access key label for an element.
84  *
85  * Will use native accessKeyLabel if available (currently only in Firefox 8+),
86  * falls back to #getAccessKeyPrefix.
87  *
88  * @private
89  * @param {HTMLElement} element Element to get the label for
90  * @return {string} Access key label
91  */
92 function getAccessKeyLabel( element ) {
93         // abort early if no access key
94         if ( !element.accessKey ) {
95                 return '';
96         }
97         // use accessKeyLabel if possible
98         // http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#dom-accesskeylabel
99         if ( !useTestPrefix && element.accessKeyLabel ) {
100                 return element.accessKeyLabel;
101         }
102         return ( useTestPrefix ? 'test-' : getAccessKeyPrefix() ) + element.accessKey;
106  * Update the title for an element (on the element with the access key or it's label) to show
107  * the correct access key label.
109  * @private
110  * @param {HTMLElement} element Element with the accesskey
111  * @param {HTMLElement} titleElement Element with the title to update (may be the same as `element`)
112  */
113 function updateTooltipOnElement( element, titleElement ) {
114         var oldTitle = titleElement.title,
115                 rawTitle = oldTitle.replace( / \[.*?\]$/, '' ),
116                 newTitle = rawTitle,
117                 accessKeyLabel = getAccessKeyLabel( element );
119         // don't add a title if the element didn't have one before
120         if ( !oldTitle ) {
121                 return;
122         }
124         if ( accessKeyLabel ) {
125                 newTitle += ' [' + accessKeyLabel + ']';
126         }
127         if ( oldTitle !== newTitle ) {
128                 titleElement.title = newTitle;
129         }
133  * Update the title for an element to show the correct access key label.
135  * @private
136  * @param {HTMLElement} element Element with the accesskey
137  */
138 function updateTooltip( element ) {
139         var id, $element, $label, $labelParent;
140         updateTooltipOnElement( element, element );
142         // update associated label if there is one
143         $element = $( element );
144         if ( $element.is( labelable ) ) {
145                 // Search it using 'for' attribute
146                 id = element.id.replace( /"/g, '\\"' );
147                 if ( id ) {
148                         $label = $( 'label[for="' + id + '"]' );
149                         if ( $label.length === 1 ) {
150                                 updateTooltipOnElement( element, $label[0] );
151                         }
152                 }
154                 // Search it as parent, because the form control can also inside the label element itself
155                 $labelParent = $element.parents( 'label' );
156                 if ( $labelParent.length === 1 ) {
157                         updateTooltipOnElement( element, $labelParent[0] );
158                 }
159         }
163  * Update the titles for all elements in a jQuery selection.
165  * @return {jQuery}
166  * @chainable
167  */
168 $.fn.updateTooltipAccessKeys = function () {
169         return this.each( function () {
170                 updateTooltip( this );
171         } );
175  * Exposed for testing.
177  * @method updateTooltipAccessKeys_getAccessKeyPrefix
178  * @inheritdoc #getAccessKeyPrefix
179  */
180 $.fn.updateTooltipAccessKeys.getAccessKeyPrefix = getAccessKeyPrefix;
183  * Switch test mode on and off.
185  * @method updateTooltipAccessKeys_setTestMode
186  * @param {boolean} mode New mode
187  */
188 $.fn.updateTooltipAccessKeys.setTestMode = function ( mode ) {
189         useTestPrefix = mode;
193  * @class jQuery
194  * @mixins jQuery.plugin.accessKeyLabel
195  */
197 }( jQuery ) );