/** * User script to replay conflicts. * * The conflicting edit text is stored under a special title like, * Conflict:/<base_revision_id>/<conflict_sequence> * Where the placeholders are, the page title where the conflict occurred, the base revision ID that was being edited, * and a 1-based sequence which is ignored for now, and lets multiple conflicts share the same base revision. * * TODO: * - User input for the edit summary. * - Controls to do advanced things like tweaking the branchpoint and choosing an "other" edit other than * the target page's latest revision. * - Proper namespace for these pages. */ mw.loader.using( [ 'mediawiki.api', 'moment', 'oojs-ui-core' ] ).done( function () { $( function () { // TODO: The regex is missing the start anchor "^" so that it can be used as a subpage in various places, // until the Conflict namespace exists. var conflictTitleParams = /Conflict:(.*)\/(\d+)\/(\d+)$/.exec( mw.config.get('wgPageName' ) ); if ( conflictTitleParams !== null ) { var baseTitle = conflictTitleParams[1], baseRevisionId = conflictTitleParams[2] /*, conflictSequence = conflictTitleParams[3] */; var form = new OO.ui.FormLayout( { // TODO: urlencode the title, or build the query using a helper. action: mw.config.get('wgScript' ) + '?title=' + baseTitle + '&action=submit', method: 'post' } ); form.addItems( [ new OO.ui.FieldsetLayout( { label: 'Conflict', items: [ new OO.ui.ButtonWidget( { label: 'Recreate conflict', title: 'Submit', } ).on( 'click', function () { // TODO: clean up binding form.$element.submit(); } ) ] } ) ] ); var postFields = { wpUnicodeCheck: 'ℳ𝒲β™₯π“Šπ“ƒπ’Ύπ’Έβ„΄π’Ήβ„―', editRevId: baseRevisionId, parentRevId: baseRevisionId, // TODO: stored / input / automatic summary field. //wpSummary: '', wpSave: 'Save changes', mode: 'text', wpUltimateParam: '1', }; var api = new mw.Api(); Promise.all( [ api.getEditToken().then( function ( editToken ) { postFields.wpEditToken = editToken; } ), // Pull content from the conflict page. api.get( { action: 'query', prop: 'revisions', revids: mw.config.get( 'wgCurRevisionId' ), rvprop: 'content' } ).then( function ( data ) { for ( var pageId in data.query.pages ) { for ( var index in data.query.pages[pageId].revisions ) { var revision = data.query.pages[pageId].revisions[index]; postFields.wpTextbox1 = revision['*']; postFields.format = revision.contentformat; postFields.model = revision.contentmodel; return; } } } ), // Get timestamp of the original base revision, to convince EditPage we need to conflict. // Edit time turns out to be important, conflict cannot be triggered without it! api.get( { action: 'query', prop: 'revisions', revids: baseRevisionId, rvprop: 'timestamp' } ).then( function ( data ) { for ( var pageId in data.query.pages ) { for ( var index in data.query.pages[pageId].revisions ) { var revision = data.query.pages[pageId].revisions[index]; // FIXME: date conversion from a library postFields.wpEdittime = moment( revision.timestamp ).utc().format( 'YYYYMMDDHHmmss' ); return; } } } ) ] ).then( function ( ) { var keys = Object.keys( postFields ); for ( var i = 0; i < keys.length; i++ ) { form.addItems( [ new OO.ui.HiddenInputWidget( { name: keys[i], value: postFields[keys[i]], } ) ] ); } $( '#bodyContent' ).prepend( form.$element ); } ); } }); });