mirror of
https://gerrit.wikimedia.org/r/mediawiki/skins/Vector.git
synced 2024-11-24 07:43:47 +00:00
Merge "[search] Instrument Vue.js-based search widget"
This commit is contained in:
commit
707862df60
|
@ -357,6 +357,7 @@ class Hooks {
|
||||||
],
|
],
|
||||||
"packageFiles" => [
|
"packageFiles" => [
|
||||||
"resources/skins.vector.search/skins.vector.search.js",
|
"resources/skins.vector.search/skins.vector.search.js",
|
||||||
|
"resources/skins.vector.search/instrumentation.js",
|
||||||
"resources/skins.vector.search/App.vue",
|
"resources/skins.vector.search/App.vue",
|
||||||
[
|
[
|
||||||
"name" => "resources/skins.vector.search/config.json",
|
"name" => "resources/skins.vector.search/config.json",
|
||||||
|
|
19
resources/mediawiki.d.ts
vendored
19
resources/mediawiki.d.ts
vendored
|
@ -4,6 +4,13 @@ interface MwApi {
|
||||||
|
|
||||||
type MwApiConstructor = new( options?: Object ) => MwApi;
|
type MwApiConstructor = new( options?: Object ) => MwApi;
|
||||||
|
|
||||||
|
interface MwUri {
|
||||||
|
query: Record<string, unknown>;
|
||||||
|
toString(): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type UriConstructor = new( uri: string ) => MwUri;
|
||||||
|
|
||||||
interface MediaWiki {
|
interface MediaWiki {
|
||||||
util: {
|
util: {
|
||||||
/**
|
/**
|
||||||
|
@ -71,6 +78,18 @@ interface MediaWiki {
|
||||||
* @param messageName i18n message name
|
* @param messageName i18n message name
|
||||||
*/
|
*/
|
||||||
msg( messageName: string|null ): string;
|
msg( messageName: string|null ): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Track an analytic event.
|
||||||
|
*
|
||||||
|
* See https://gerrit.wikimedia.org/g/mediawiki/core/+/d7fe1ff0fe52735b1f41e91879c9617b376e807d/resources/src/mediawiki.base/mediawiki.base.js#375.
|
||||||
|
*
|
||||||
|
* @param topic The topic name
|
||||||
|
* @param [data] The data describing the event
|
||||||
|
*/
|
||||||
|
track(topic: string, data?: Record<string, unknown>|number|string): void;
|
||||||
|
|
||||||
|
Uri: UriConstructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare const mw: MediaWiki;
|
declare const mw: MediaWiki;
|
||||||
|
|
|
@ -16,17 +16,25 @@
|
||||||
:search-language="language"
|
:search-language="language"
|
||||||
:show-thumbnail="showThumbnail"
|
:show-thumbnail="showThumbnail"
|
||||||
:show-description="showDescription"
|
:show-description="showDescription"
|
||||||
|
@fetch-end="instrumentation.onFetchEnd"
|
||||||
|
@suggestion-click="instrumentation.onSuggestionClick"
|
||||||
>
|
>
|
||||||
<input type="hidden"
|
<input type="hidden"
|
||||||
name="title"
|
name="title"
|
||||||
value="Special:Search"
|
value="Special:Search"
|
||||||
>
|
>
|
||||||
|
<input type="hidden"
|
||||||
|
name="wprov"
|
||||||
|
:value="wprov"
|
||||||
|
>
|
||||||
</wvui-typeahead-search>
|
</wvui-typeahead-search>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var wvui = require( 'wvui' );
|
/* global SubmitEvent */
|
||||||
|
var wvui = require( 'wvui' ),
|
||||||
|
instrumentation = require( './instrumentation.js' );
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
|
@ -91,6 +99,26 @@ module.exports = {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
// -1 here is the default "active suggestion index" defined in the
|
||||||
|
// `wvui-typeahead-search` component (see
|
||||||
|
// https://gerrit.wikimedia.org/r/plugins/gitiles/wvui/+/c7af5d6d091ffb3beb4fd2723fdf50dc6bb2789b/src/components/typeahead-search/TypeaheadSearch.vue#167).
|
||||||
|
wprov: instrumentation.getWprovFromResultIndex( -1 ),
|
||||||
|
|
||||||
|
instrumentation: instrumentation.listeners
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* @param {SubmitEvent} event
|
||||||
|
*/
|
||||||
|
onSubmit: function ( event ) {
|
||||||
|
this.wprov = instrumentation.getWprovFromResultIndex( event.index );
|
||||||
|
|
||||||
|
instrumentation.listeners.onSubmit( event );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
114
resources/skins.vector.search/instrumentation.js
Normal file
114
resources/skins.vector.search/instrumentation.js
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
/* global FetchEndEvent, SuggestionClickEvent, SubmitEvent */
|
||||||
|
/** @module Instrumentation */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value of the `inputLocation` property of any and all SearchSatisfaction events sent by the
|
||||||
|
* corresponding instrumentation.
|
||||||
|
*
|
||||||
|
* @see https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/skins/Vector/+/refs/heads/master/includes/Constants.php
|
||||||
|
*/
|
||||||
|
var INPUT_LOCATION_MOVED = 'header-moved',
|
||||||
|
wgScript = mw.config.get( 'wgScript' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {FetchEndEvent} event
|
||||||
|
*/
|
||||||
|
function onFetchEnd( event ) {
|
||||||
|
mw.track( 'mediawiki.searchSuggest', {
|
||||||
|
action: 'impression-results',
|
||||||
|
numberOfResults: event.numberOfResults,
|
||||||
|
// resultSetType: '',
|
||||||
|
// searchId: '',
|
||||||
|
query: event.query,
|
||||||
|
inputLocation: INPUT_LOCATION_MOVED
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {SuggestionClickEvent|SubmitEvent} event
|
||||||
|
*/
|
||||||
|
function onSuggestionClick( event ) {
|
||||||
|
mw.track( 'mediawiki.searchSuggest', {
|
||||||
|
action: 'click-result',
|
||||||
|
numberOfResults: event.numberOfResults,
|
||||||
|
index: event.index
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the value of the `wprov` parameter to be used in the URL of a search result and the
|
||||||
|
* `wprov` hidden input.
|
||||||
|
*
|
||||||
|
* See https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/extensions/WikimediaEvents/+/refs/heads/master/modules/ext.wikimediaEvents/searchSatisfaction.js
|
||||||
|
* and also the top of that file for additional detail about the shape of the parameter.
|
||||||
|
*
|
||||||
|
* @param {number} index
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
function getWprovFromResultIndex( index ) {
|
||||||
|
|
||||||
|
// If the user hasn't highlighted an autocomplete result.
|
||||||
|
if ( index === -1 ) {
|
||||||
|
return 'acrw1';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'acrw1' + index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} SearchResultPartial
|
||||||
|
* @property {string} title
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} GenerateUrlMeta
|
||||||
|
* @property {number} index
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by the `wvui-typeahead-search` component to generate URLs for the search results. Adds a
|
||||||
|
* `wprov` paramater to the URL to satisfy the SearchSatisfaction instrumentation.
|
||||||
|
*
|
||||||
|
* @see getWprovFromResultIndex
|
||||||
|
*
|
||||||
|
* @param {SearchResultPartial|string} suggestion
|
||||||
|
* @param {GenerateUrlMeta} meta
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
function generateUrl( suggestion, meta ) {
|
||||||
|
var result = new mw.Uri( wgScript );
|
||||||
|
|
||||||
|
if ( typeof suggestion !== 'string' ) {
|
||||||
|
suggestion = suggestion.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.query.title = 'Special:Search';
|
||||||
|
result.query.suggestion = suggestion;
|
||||||
|
result.query.wprov = getWprovFromResultIndex( meta.index );
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
listeners: {
|
||||||
|
onFetchEnd: onFetchEnd,
|
||||||
|
onSuggestionClick: onSuggestionClick,
|
||||||
|
|
||||||
|
// As of writing (2020/12/08), both the "click-result" and "submit-form" kind of
|
||||||
|
// mediawiki.searchSuggestion events result in a "click" SearchSatisfaction event being
|
||||||
|
// logged [0]. However, when processing the "submit-form" kind of mediawiki.searchSuggestion
|
||||||
|
// event, the SearchSatisfaction instrument will modify the DOM, adding a hidden input
|
||||||
|
// element, in order to set the appropriate provenance parameter (see [1] for additional
|
||||||
|
// detail).
|
||||||
|
//
|
||||||
|
// In this implementation of the mediawiki.searchSuggestion protocol, we don't want to
|
||||||
|
// trigger the above behavior as we're using Vue.js, which doesn't expect the DOM to be
|
||||||
|
// modified underneath it.
|
||||||
|
//
|
||||||
|
// [0] https://gerrit.wikimedia.org/g/mediawiki/extensions/WikimediaEvents/+/df97aa9c9407507e8c48827666beeab492fd56a8/modules/ext.wikimediaEvents/searchSatisfaction.js#735
|
||||||
|
// [1] https://phabricator.wikimedia.org/T257698#6416826
|
||||||
|
onSubmit: onSuggestionClick
|
||||||
|
},
|
||||||
|
getWprovFromResultIndex: getWprovFromResultIndex,
|
||||||
|
generateUrl: generateUrl
|
||||||
|
};
|
|
@ -1,3 +1,4 @@
|
||||||
|
/** @module search */
|
||||||
var
|
var
|
||||||
Vue = require( 'vue' ).default || require( 'vue' ),
|
Vue = require( 'vue' ).default || require( 'vue' ),
|
||||||
App = require( './App.vue' ),
|
App = require( './App.vue' ),
|
||||||
|
|
17
resources/skins.vector.search/types.js
Normal file
17
resources/skins.vector.search/types.js
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
/**
|
||||||
|
* @typedef {Object} FetchEndEvent
|
||||||
|
* @property {number} numberOfResults
|
||||||
|
* @property {string} query
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} SuggestionClickEvent
|
||||||
|
* @property {number} numberOfResults
|
||||||
|
* @property {number} index
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {SuggestionClickEvent} SubmitEvent
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* exported SuggestionClickEvent, SubmitEvent, FetchEndEvent */
|
Loading…
Reference in a new issue