Implement extension registration from an extension.json file
[mediawiki.git] / resources / src / mediawiki / mediawiki.searchSuggest.js
blob7b7ccf3f55d08bfc0e44efb5f759f3ef1f635b2d
1 /*!
2  * Add search suggestions to the search form.
3  */
4 ( function ( mw, $ ) {
5         $( function () {
6                 var api, map, resultRenderCache, searchboxesSelectors,
7                         // Region where the suggestions box will appear directly below
8                         // (using the same width). Can be a container element or the input
9                         // itself, depending on what suits best in the environment.
10                         // For Vector the suggestion box should align with the simpleSearch
11                         // container's borders, in other skins it should align with the input
12                         // element (not the search form, as that would leave the buttons
13                         // vertically between the input and the suggestions).
14                         $searchRegion = $( '#simpleSearch, #searchInput' ).first(),
15                         $searchInput = $( '#searchInput' );
17                 // Compatibility map
18                 map = {
19                         // SimpleSearch is broken in Opera < 9.6
20                         opera: [['>=', 9.6]],
21                         // Older Konquerors are unable to position the suggestions correctly (bug 50805)
22                         konqueror: [['>=', '4.11']],
23                         docomo: false,
24                         blackberry: false,
25                         // Support for iOS 6 or higher. It has not been tested on iOS 5 or lower
26                         ipod: [['>=', 6]],
27                         iphone: [['>=', 6]]
28                 };
30                 if ( !$.client.test( map ) ) {
31                         return;
32                 }
34                 // Compute form data for search suggestions functionality.
35                 function computeResultRenderCache( context ) {
36                         var $form, baseHref, linkParams;
38                         // Compute common parameters for links' hrefs
39                         $form = context.config.$region.closest( 'form' );
41                         baseHref = $form.attr( 'action' );
42                         baseHref += baseHref.indexOf( '?' ) > -1 ? '&' : '?';
44                         linkParams = $form.serializeObject();
46                         return {
47                                 textParam: context.data.$textbox.attr( 'name' ),
48                                 linkParams: linkParams,
49                                 baseHref: baseHref
50                         };
51                 }
53                 // The function used to render the suggestions.
54                 function renderFunction( text, context ) {
55                         if ( !resultRenderCache ) {
56                                 resultRenderCache = computeResultRenderCache( context );
57                         }
59                         // linkParams object is modified and reused
60                         resultRenderCache.linkParams[ resultRenderCache.textParam ] = text;
62                         // this is the container <div>, jQueryfied
63                         this.text( text )
64                                 .wrap(
65                                         $( '<a>' )
66                                                 .attr( 'href', resultRenderCache.baseHref + $.param( resultRenderCache.linkParams ) )
67                                                 .attr( 'title', text )
68                                                 .addClass( 'mw-searchSuggest-link' )
69                                 );
70                 }
72                 function specialRenderFunction( query, context ) {
73                         var $el = this;
75                         if ( !resultRenderCache ) {
76                                 resultRenderCache = computeResultRenderCache( context );
77                         }
79                         // linkParams object is modified and reused
80                         resultRenderCache.linkParams[ resultRenderCache.textParam ] = query;
82                         if ( $el.children().length === 0 ) {
83                                 $el
84                                         .append(
85                                                 $( '<div>' )
86                                                         .addClass( 'special-label' )
87                                                         .text( mw.msg( 'searchsuggest-containing' ) ),
88                                                 $( '<div>' )
89                                                         .addClass( 'special-query' )
90                                                         .text( query )
91                                         )
92                                         .show();
93                         } else {
94                                 $el.find( '.special-query' )
95                                         .text( query );
96                         }
98                         if ( $el.parent().hasClass( 'mw-searchSuggest-link' ) ) {
99                                 $el.parent().attr( 'href', resultRenderCache.baseHref + $.param( resultRenderCache.linkParams ) + '&fulltext=1' );
100                         } else {
101                                 $el.wrap(
102                                         $( '<a>' )
103                                                 .attr( 'href', resultRenderCache.baseHref + $.param( resultRenderCache.linkParams ) + '&fulltext=1' )
104                                                 .addClass( 'mw-searchSuggest-link' )
105                                 );
106                         }
107                 }
109                 // Generic suggestions functionality for all search boxes
110                 searchboxesSelectors = [
111                         // Primary searchbox on every page in standard skins
112                         '#searchInput',
113                         // Special:Search
114                         '#powerSearchText',
115                         '#searchText',
116                         // Generic selector for skins with multiple searchboxes (used by CologneBlue)
117                         // and for MediaWiki itself (special pages with page title inputs)
118                         '.mw-searchInput'
119                 ];
120                 $( searchboxesSelectors.join( ', ' ) )
121                         .suggestions( {
122                                 fetch: function ( query, response, maxRows ) {
123                                         var node = this[0];
125                                         api = api || new mw.Api();
127                                         $.data( node, 'request', api.get( {
128                                                 action: 'opensearch',
129                                                 search: query,
130                                                 namespace: 0,
131                                                 limit: maxRows,
132                                                 suggest: ''
133                                         } ).done( function ( data ) {
134                                                 response( data[ 1 ] );
135                                         } ) );
136                                 },
137                                 cancel: function () {
138                                         var node = this[0],
139                                                 request = $.data( node, 'request' );
141                                         if ( request ) {
142                                                 request.abort();
143                                                 $.removeData( node, 'request' );
144                                         }
145                                 },
146                                 result: {
147                                         render: renderFunction,
148                                         select: function () {
149                                                 // allow the form to be submitted
150                                                 return true;
151                                         }
152                                 },
153                                 cache: true,
154                                 highlightInput: true
155                         } )
156                         .bind( 'paste cut drop', function () {
157                                 // make sure paste and cut events from the mouse and drag&drop events
158                                 // trigger the keypress handler and cause the suggestions to update
159                                 $( this ).trigger( 'keypress' );
160                         } )
161                         // In most skins (at least Monobook and Vector), the font-size is messed up in <body>.
162                         // (they use 2 elements to get a sane font-height). So, instead of making exceptions for
163                         // each skin or adding more stylesheets, just copy it from the active element so auto-fit.
164                         .each( function () {
165                                 var $this = $( this );
166                                 $this
167                                         .data( 'suggestions-context' )
168                                         .data.$container
169                                                 .css( 'fontSize', $this.css( 'fontSize' ) );
170                         } );
172                 // Ensure that the thing is actually present!
173                 if ( $searchRegion.length === 0 ) {
174                         // Don't try to set anything up if simpleSearch is disabled sitewide.
175                         // The loader code loads us if the option is present, even if we're
176                         // not actually enabled (anymore).
177                         return;
178                 }
180                 // Special suggestions functionality for skin-provided search box
181                 $searchInput.suggestions( {
182                         special: {
183                                 render: specialRenderFunction,
184                                 select: function ( $input ) {
185                                         $input.closest( 'form' )
186                                                 .append( $( '<input type="hidden" name="fulltext" value="1"/>' ) );
187                                         return true; // allow the form to be submitted
188                                 }
189                         },
190                         $region: $searchRegion
191                 } );
193                 // If the form includes any fallback fulltext search buttons, remove them
194                 $searchInput.closest( 'form' ).find( '.mw-fallbackSearchButton' ).remove();
195         } );
197 }( mediaWiki, jQuery ) );