mediawiki-extensions-Visual.../modules/ve-mw/init/ve.init.mw.trackSubscriber.js
Roan Kattouw 6d21d83244 Add instrumentation for edit schema
Move ve.track() subscriber to its own file, and have it
route mwtiming.* events (for TimingData) and mwedit.* events
(for Edit schema) differently. Most of the data population
lives in the subscriber, so actual ve.track() calls are
pretty lightweight.

Existing ve.track() calls with timing data were kept with
their names intact for backwards compatibility, but
we may eventually want to throw them out and start from scratch.

ve.init.mw.ViewPageTarget.init.js:
* Remove old track subscriber
* Track init and ready events
* Remove old ve.track( 'Edit', ... ) crap that didn't work

ve.init.mw.ViewPageTarget.js:
* Fire the saveWorkflowBegin event before the save dialog
  loads rather than after
* Remove unnecessary this.events.trackSaveError() calls:
  TargetEvents already listens to these events itself
* Remove badtoken handler because all it was was an
  unnecessary trackSaveError() call
* Add abort tracking
** Pass trackMechanism through deactivate() and cancel()

ve.init.mw.Target.js:
* Add static.integrationType to populate the 'integration'
  field in the schema

ve.init.mw.TargetEvents.js:
* Simplify onSaveError* methods away into connect bindings
* Map track topics to mwtiming.* so they can be routed separately
* Track save-related mwedit.* events

Depends on I978eda96c in WikimediaEvents

Change-Id: Iae677d9b15c71d2b18e795bd5179d11876c06abd
2014-11-21 11:59:15 -08:00

106 lines
3.2 KiB
JavaScript

/*!
* VisualEditor MediaWiki event subscriber.
*
* Subscribes to ve.track() events and routes them to mw.track().
*
* @copyright 2011-2014 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
( function () {
var lastEventWithAction = {},
editingSessionId = mw.user.generateRandomSessionId();
function getDefaultTiming( action, data, now ) {
switch ( action ) {
case 'init':
// Account for second opening
return now - Math.max(
Math.floor( window.mediaWikiLoadStart ),
lastEventWithAction.saveSuccess || 0,
lastEventWithAction.abort || 0
);
case 'ready':
return now - lastEventWithAction.init;
case 'saveIntent':
return now - lastEventWithAction.ready;
case 'saveAttempt':
return now - lastEventWithAction.saveIntent;
case 'saveSuccess':
case 'saveFailure':
// HERE BE DRAGONS: the caller must compute these themselves
// for sensible results. Deliberately sabotage any attempts to
// use the default by returning -1
mw.log.warn( 've.init.mw.trackSubscriber: Do not rely on default timing value for saveSuccess/saveFailure' );
return -1;
case 'abort':
switch ( data.type ) {
case 'preinit':
return now - lastEventWithAction.init;
case 'nochange':
case 'switchwith':
case 'switchwithout':
case 'abandon':
return now - lastEventWithAction.ready;
case 'abandonMidsave':
return now - lastEventWithAction.saveAttempt;
}
}
mw.log.warn( 've.init.mw.trackSubscriber: Unrecognized action', action );
return -1;
}
ve.trackSubscribeAll( function ( topic, data ) {
data = data || {};
var newData, action, now = Math.floor( ve.now() ), prefix = topic.substr( 0, topic.indexOf( '.' ) );
if ( prefix === 'mwtiming' ) {
// Legacy TimingData events
// Map timing.foo --> ve.foo
topic = 've.' + topic.substr( prefix.length + 1 );
} else if ( prefix === 'mwedit' ) {
// Edit schema
action = topic.split( '.' )[1];
if ( action === 'init' ) {
// Regenerate editingSessionId
editingSessionId = mw.user.generateRandomSessionId();
}
newData = $.extend( {
version: 1,
action: action,
editor: 'visualeditor',
platform: 'desktop', // FIXME
integration: ve.init.target && ve.init.target.constructor.static.integrationType || 'page',
'page.id': mw.config.get( 'wgArticleId' ),
'page.title': mw.config.get( 'wgPageName' ),
'page.ns': mw.config.get( 'wgNamespaceNumber' ),
'page.revid': mw.config.get( 'wgRevisionId' ),
'page.length': -1, // FIXME
editingSessionId: editingSessionId,
'user.id': mw.user.getId(),
'user.editCount': mw.config.get( 'wgUserEditCount', 0 )
}, data );
if ( mw.user.isAnon() ) {
newData['user.class'] = 'IP';
}
newData['action.' + action + '.type'] = data.type;
newData['action.' + action + '.mechanism'] = data.mechanism;
newData['action.' + action + '.timing'] = data.timing !== undefined ?
Math.floor( data.timing ) : getDefaultTiming( action, data, now );
// Remove renamed properties
delete newData.type;
delete newData.mechanism;
delete newData.timing;
data = newData;
topic = 'event.Edit';
lastEventWithAction[action] = now;
}
mw.track( topic, data );
} );
} )();