diff options
Diffstat (limited to 'resources/src/mediawiki/mediawiki.searchSuggest.js')
-rw-r--r-- | resources/src/mediawiki/mediawiki.searchSuggest.js | 161 |
1 files changed, 117 insertions, 44 deletions
diff --git a/resources/src/mediawiki/mediawiki.searchSuggest.js b/resources/src/mediawiki/mediawiki.searchSuggest.js index 7b7ccf3f..6c7484e2 100644 --- a/resources/src/mediawiki/mediawiki.searchSuggest.js +++ b/resources/src/mediawiki/mediawiki.searchSuggest.js @@ -2,8 +2,22 @@ * Add search suggestions to the search form. */ ( function ( mw, $ ) { + mw.searchSuggest = { + request: function ( api, query, response, maxRows ) { + return api.get( { + action: 'opensearch', + search: query, + namespace: 0, + limit: maxRows, + suggest: '' + } ).done( function ( data ) { + response( data[ 1 ] ); + } ); + } + }; + $( function () { - var api, map, resultRenderCache, searchboxesSelectors, + var api, map, searchboxesSelectors, // Region where the suggestions box will appear directly below // (using the same width). Can be a container element or the input // itself, depending on what suits best in the environment. @@ -12,19 +26,20 @@ // element (not the search form, as that would leave the buttons // vertically between the input and the suggestions). $searchRegion = $( '#simpleSearch, #searchInput' ).first(), - $searchInput = $( '#searchInput' ); + $searchInput = $( '#searchInput' ), + previousSearchText = $searchInput.val(); // Compatibility map map = { // SimpleSearch is broken in Opera < 9.6 - opera: [['>=', 9.6]], + opera: [ [ '>=', 9.6 ] ], // Older Konquerors are unable to position the suggestions correctly (bug 50805) - konqueror: [['>=', '4.11']], + konqueror: [ [ '>=', '4.11' ] ], docomo: false, blackberry: false, // Support for iOS 6 or higher. It has not been tested on iOS 5 or lower - ipod: [['>=', 6]], - iphone: [['>=', 6]] + ipod: [ [ '>=', 6 ] ], + iphone: [ [ '>=', 6 ] ] }; if ( !$.client.test( map ) ) { @@ -32,52 +47,101 @@ } // Compute form data for search suggestions functionality. - function computeResultRenderCache( context ) { + function getFormData( context ) { var $form, baseHref, linkParams; - // Compute common parameters for links' hrefs - $form = context.config.$region.closest( 'form' ); + if ( !context.formData ) { + // Compute common parameters for links' hrefs + $form = context.config.$region.closest( 'form' ); + + baseHref = $form.attr( 'action' ); + baseHref += baseHref.indexOf( '?' ) > -1 ? '&' : '?'; + + linkParams = $form.serializeObject(); + + context.formData = { + textParam: context.data.$textbox.attr( 'name' ), + linkParams: linkParams, + baseHref: baseHref + }; + } + + return context.formData; + } - baseHref = $form.attr( 'action' ); - baseHref += baseHref.indexOf( '?' ) > -1 ? '&' : '?'; + /** + * Callback that's run when the user changes the search input text + * 'this' is the search input box (jQuery object) + * + * @ignore + */ + function onBeforeUpdate() { + var searchText = this.val(); + + if ( searchText && searchText !== previousSearchText ) { + mw.track( 'mediawiki.searchSuggest', { + action: 'session-start' + } ); + } + previousSearchText = searchText; + } - linkParams = $form.serializeObject(); + /** + * Callback that's run when suggestions have been updated either from the cache or the API + * 'this' is the search input box (jQuery object) + * + * @ignore + */ + function onAfterUpdate() { + var context = this.data( 'suggestionsContext' ); - return { - textParam: context.data.$textbox.attr( 'name' ), - linkParams: linkParams, - baseHref: baseHref - }; + mw.track( 'mediawiki.searchSuggest', { + action: 'impression-results', + numberOfResults: context.config.suggestions.length, + // FIXME: when other types of search become available change this value accordingly + // See the API call below (opensearch = prefix) + resultSetType: 'prefix' + } ); } // The function used to render the suggestions. function renderFunction( text, context ) { - if ( !resultRenderCache ) { - resultRenderCache = computeResultRenderCache( context ); - } + var formData = getFormData( context ); // linkParams object is modified and reused - resultRenderCache.linkParams[ resultRenderCache.textParam ] = text; + formData.linkParams[ formData.textParam ] = text; // this is the container <div>, jQueryfied this.text( text ) .wrap( $( '<a>' ) - .attr( 'href', resultRenderCache.baseHref + $.param( resultRenderCache.linkParams ) ) + .attr( 'href', formData.baseHref + $.param( formData.linkParams ) ) .attr( 'title', text ) .addClass( 'mw-searchSuggest-link' ) ); } - function specialRenderFunction( query, context ) { - var $el = this; + // The function used when the user makes a selection + function selectFunction( $input ) { + var context = $input.data( 'suggestionsContext' ), + text = $input.val(); - if ( !resultRenderCache ) { - resultRenderCache = computeResultRenderCache( context ); - } + mw.track( 'mediawiki.searchSuggest', { + action: 'click-result', + numberOfResults: context.config.suggestions.length, + clickIndex: context.config.suggestions.indexOf( text ) + 1 + } ); + + // allow the form to be submitted + return true; + } + + function specialRenderFunction( query, context ) { + var $el = this, + formData = getFormData( context ); // linkParams object is modified and reused - resultRenderCache.linkParams[ resultRenderCache.textParam ] = query; + formData.linkParams[ formData.textParam ] = query; if ( $el.children().length === 0 ) { $el @@ -96,11 +160,11 @@ } if ( $el.parent().hasClass( 'mw-searchSuggest-link' ) ) { - $el.parent().attr( 'href', resultRenderCache.baseHref + $.param( resultRenderCache.linkParams ) + '&fulltext=1' ); + $el.parent().attr( 'href', formData.baseHref + $.param( formData.linkParams ) + '&fulltext=1' ); } else { $el.wrap( $( '<a>' ) - .attr( 'href', resultRenderCache.baseHref + $.param( resultRenderCache.linkParams ) + '&fulltext=1' ) + .attr( 'href', formData.baseHref + $.param( formData.linkParams ) + '&fulltext=1' ) .addClass( 'mw-searchSuggest-link' ) ); } @@ -120,22 +184,14 @@ $( searchboxesSelectors.join( ', ' ) ) .suggestions( { fetch: function ( query, response, maxRows ) { - var node = this[0]; + var node = this[ 0 ]; api = api || new mw.Api(); - $.data( node, 'request', api.get( { - action: 'opensearch', - search: query, - namespace: 0, - limit: maxRows, - suggest: '' - } ).done( function ( data ) { - response( data[ 1 ] ); - } ) ); + $.data( node, 'request', mw.searchSuggest.request( api, query, response, maxRows ) ); }, cancel: function () { - var node = this[0], + var node = this[ 0 ], request = $.data( node, 'request' ); if ( request ) { @@ -177,8 +233,16 @@ return; } - // Special suggestions functionality for skin-provided search box + // Special suggestions functionality and tracking for skin-provided search box $searchInput.suggestions( { + update: { + before: onBeforeUpdate, + after: onAfterUpdate + }, + result: { + render: renderFunction, + select: selectFunction + }, special: { render: specialRenderFunction, select: function ( $input ) { @@ -190,8 +254,17 @@ $region: $searchRegion } ); - // If the form includes any fallback fulltext search buttons, remove them - $searchInput.closest( 'form' ).find( '.mw-fallbackSearchButton' ).remove(); + $searchInput.closest( 'form' ) + // track the form submit event + .on( 'submit', function () { + var context = $searchInput.data( 'suggestionsContext' ); + mw.track( 'mediawiki.searchSuggest', { + action: 'submit-form', + numberOfResults: context.config.suggestions.length + } ); + } ) + // If the form includes any fallback fulltext search buttons, remove them + .find( '.mw-fallbackSearchButton' ).remove(); } ); }( mediaWiki, jQuery ) ); |