Track search events
authorBaha Man <bmansurov@wikimedia.org>
Mon, 23 Mar 2015 23:11:21 +0000 (19:11 -0400)
committerDr0ptp4kt <abaso@wikimedia.org>
Wed, 8 Apr 2015 15:56:17 +0000 (15:56 +0000)
Tracking works only for the skin-provided search box (top right search
box on desktop). Also, add the 'update' option the jQuery suggestions
extension.

Change-Id: Icc0afcd6c9fa8c82a95d9decf988a19ae3edc165

resources/src/jquery/jquery.suggestions.js
resources/src/mediawiki/mediawiki.searchSuggest.js

index 813c37c..7c9bec3 100644 (file)
  * @param {Function} options.result.select Called in context of the suggestions-result-current element.
  * @param {jQuery} options.result.select.$textbox
  *
+ * @param {Object} [options.update] Set of callbacks for listening to a change in the text input.
+ *
+ * @param {Function} options.update.before Called right after the user changes the textbox text.
+ * @param {Function} options.update.after Called after results are updated either from the cache or
+ * the API as a result of the user input.
+ *
  * @param {jQuery} [options.$region=this] The element to place the suggestions below and match width of.
  *
  * @param {string[]} [options.suggestions] Array of suggestions to display.
@@ -83,7 +89,7 @@
  * @param {boolean} [options.positionFromLeft] Sets `expandFrom=left`, for backwards
  *  compatibility.
  *
- * @param {boolean} [options.highlightInput=false] Whether to hightlight matched portions of the
+ * @param {boolean} [options.highlightInput=false] Whether to highlight matched portions of the
  *  input or not.
  */
 ( function ( $ ) {
@@ -144,6 +150,10 @@ $.suggestions = {
                                cache = context.data.cache,
                                cacheHit;
 
+                       if ( typeof context.config.update.before === 'function' ) {
+                               context.config.update.before.call( context.data.$textbox );
+                       }
+
                        // Only fetch if the value in the textbox changed and is not empty, or if the results were hidden
                        // if the textbox is empty then clear the result div, but leave other settings intouched
                        if ( val.length === 0 ) {
@@ -158,6 +168,9 @@ $.suggestions = {
                                if ( context.config.cache && hasOwn.call( cache, val ) ) {
                                        if ( +new Date() - cache[ val ].timestamp < context.config.cacheMaxAge ) {
                                                context.data.$textbox.suggestions( 'suggestions', cache[ val ].suggestions );
+                                               if ( typeof context.config.update.after === 'function' ) {
+                                                       context.config.update.after.call( context.data.$textbox );
+                                               }
                                                cacheHit = true;
                                        } else {
                                                // Cache expired
@@ -171,6 +184,9 @@ $.suggestions = {
                                                function ( suggestions ) {
                                                        suggestions = suggestions.slice( 0, context.config.maxRows );
                                                        context.data.$textbox.suggestions( 'suggestions', suggestions );
+                                                       if ( typeof context.config.update.after === 'function' ) {
+                                                               context.config.update.after.call( context.data.$textbox );
+                                                       }
                                                        if ( context.config.cache ) {
                                                                cache[ val ] = {
                                                                        suggestions: suggestions,
@@ -227,6 +243,7 @@ $.suggestions = {
                        case 'cancel':
                        case 'special':
                        case 'result':
+                       case 'update':
                        case '$region':
                        case 'expandFrom':
                                context.config[property] = value;
@@ -559,6 +576,7 @@ $.fn.suggestions = function () {
                                        cancel: function () {},
                                        special: {},
                                        result: {},
+                                       update: {},
                                        $region: $( this ),
                                        suggestions: [],
                                        maxRows: 10,
index 7b7ccf3..f981b90 100644 (file)
@@ -12,7 +12,8 @@
                        // 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 = {
                        };
                }
 
+               /**
+                * 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;
+               }
+
+               /**
+                * 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' );
+
+                       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 ) {
                                );
                }
 
+               // The function used when the user makes a selection
+               function selectFunction( $input ) {
+                       var context = $input.data( 'suggestionsContext' ),
+                               text = $input.val();
+
+                       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;
 
                        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 ) {