mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-12 09:09:25 +00:00
Section editing in NWE
Bug: T144654 Change-Id: Ida6e721e0d980b47e3fda6a1f0744cbce1b2235a
This commit is contained in:
parent
9694ef6e63
commit
4040442ad8
|
@ -190,13 +190,15 @@ class ApiVisualEditor extends ApiBase {
|
|||
);
|
||||
}
|
||||
|
||||
protected function diffWikitext( $title, $wikitext ) {
|
||||
protected function diffWikitext( $title, $wikitext, $section = null ) {
|
||||
$apiParams = [
|
||||
'action' => 'query',
|
||||
'prop' => 'revisions',
|
||||
'titles' => $title->getPrefixedDBkey(),
|
||||
'rvdifftotext' => $this->pstWikitext( $title, $wikitext )
|
||||
'rvdifftotext' => $this->pstWikitext( $title, $wikitext ),
|
||||
'rvsection' => $section
|
||||
];
|
||||
|
||||
$api = new ApiMain(
|
||||
new DerivativeRequest(
|
||||
$this->getRequest(),
|
||||
|
@ -345,6 +347,11 @@ class ApiVisualEditor extends ApiBase {
|
|||
'prop' => 'revisions',
|
||||
'rvprop' => 'content'
|
||||
];
|
||||
|
||||
if ( isset( $params['section'] ) ) {
|
||||
$apiParams['rvsection'] = $params['section'];
|
||||
}
|
||||
|
||||
$api = new ApiMain(
|
||||
new DerivativeRequest(
|
||||
$this->getRequest(),
|
||||
|
@ -623,7 +630,8 @@ class ApiVisualEditor extends ApiBase {
|
|||
}
|
||||
}
|
||||
|
||||
$diff = $this->diffWikitext( $title, $wikitext );
|
||||
$section = isset( $params['section'] ) ? $params['section'] : null;
|
||||
$diff = $this->diffWikitext( $title, $wikitext, $section );
|
||||
if ( $diff['result'] === 'fail' ) {
|
||||
$this->dieUsage( 'Diff failed', 'difffailed' );
|
||||
}
|
||||
|
@ -759,6 +767,7 @@ class ApiVisualEditor extends ApiBase {
|
|||
],
|
||||
],
|
||||
'wikitext' => null,
|
||||
'section' => null,
|
||||
'oldid' => null,
|
||||
'html' => null,
|
||||
'etag' => null,
|
||||
|
|
|
@ -252,6 +252,7 @@ class ApiVisualEditorEdit extends ApiVisualEditor {
|
|||
ApiBase::PARAM_REQUIRED => true,
|
||||
],
|
||||
'wikitext' => null,
|
||||
'section' => null,
|
||||
'basetimestamp' => null,
|
||||
'starttimestamp' => null,
|
||||
'oldid' => null,
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
"apihelp-visualeditor-param-paction": "Action to perform.",
|
||||
"apihelp-visualeditor-param-page": "The page to perform actions on.",
|
||||
"apihelp-visualeditor-param-pst": "Pre-save transform wikitext before sending it to Parsoid (paction=parsefragment).",
|
||||
"apihelp-visualeditor-param-section": "The section on which to act.",
|
||||
"apihelp-visualeditor-param-starttimestamp": "When saving, set this to the timestamp of when the page was loaded. Used to detect edit conflicts.",
|
||||
"apihelp-visualeditor-param-wikitext": "Wikitext to send to Parsoid to convert to HTML (paction=parsefragment).",
|
||||
"apihelp-visualeditoredit-description": "Save an HTML5 page to MediaWiki (converted to wikitext via the Parsoid service).",
|
||||
|
@ -41,6 +42,7 @@
|
|||
"apihelp-visualeditoredit-param-needcheck": "When saving, set this parameter if the revision might have roundtrip problems. This will result in the edit being tagged.",
|
||||
"apihelp-visualeditoredit-param-oldid": "The revision number to use. Defaults to latest revision. Use 0 for a new page.",
|
||||
"apihelp-visualeditoredit-param-page": "The page to perform actions on.",
|
||||
"apihelp-visualeditoredit-param-section": "The section on which to act.",
|
||||
"apihelp-visualeditoredit-param-starttimestamp": "When saving, set this to the timestamp of when the page was loaded. Used to detect edit conflicts.",
|
||||
"apihelp-visualeditoredit-param-summary": "Edit summary.",
|
||||
"apihelp-visualeditoredit-param-watch": "",
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
"apihelp-visualeditor-param-paction": "{{doc-apihelp-param|visualeditor|paction}}",
|
||||
"apihelp-visualeditor-param-page": "{{doc-apihelp-param|visualeditor|page}}",
|
||||
"apihelp-visualeditor-param-pst": "{{doc-apihelp-param|visualeditor|pst}}",
|
||||
"apihelp-visualeditor-param-section": "{{doc-apihelp-param|visualeditor|section}}",
|
||||
"apihelp-visualeditor-param-starttimestamp": "{{doc-apihelp-param|visualeditor|starttimestamp}}",
|
||||
"apihelp-visualeditor-param-wikitext": "{{doc-apihelp-param|visualeditor|wikitext}}",
|
||||
"apihelp-visualeditoredit-description": "{{doc-apihelp-description|visualeditoredit}}",
|
||||
|
@ -54,6 +55,7 @@
|
|||
"apihelp-visualeditoredit-param-needcheck": "{{doc-apihelp-param|visualeditoredit|needcheck}}",
|
||||
"apihelp-visualeditoredit-param-oldid": "{{doc-apihelp-param|visualeditoredit|oldid}}",
|
||||
"apihelp-visualeditoredit-param-page": "{{doc-apihelp-param|visualeditoredit|page}}",
|
||||
"apihelp-visualeditoredit-param-section": "{{doc-apihelp-param|visualeditoredit|section}}",
|
||||
"apihelp-visualeditoredit-param-starttimestamp": "{{doc-apihelp-param|visualeditoredit|starttimestamp}}",
|
||||
"apihelp-visualeditoredit-param-summary": "{{doc-apihelp-param|visualeditoredit|summary}}\n{{Identical|Edit summary}}",
|
||||
"apihelp-visualeditoredit-param-watch": "{{doc-apihelp-param|visualeditoredit|watch}}",
|
||||
|
|
|
@ -197,7 +197,7 @@
|
|||
uri = veEditUri;
|
||||
}
|
||||
|
||||
activateTarget( mode, null, modified );
|
||||
activateTarget( mode, null, undefined, modified );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -210,10 +210,11 @@
|
|||
*
|
||||
* @private
|
||||
* @param {string} mode Target mode: 'visual' or 'source'
|
||||
* @param {number} [section] Section to edit (currently just source mode)
|
||||
* @param {jQuery.Promise} [targetPromise] Promise that will be resolved with a ve.init.mw.DesktopArticleTarget
|
||||
* @param {boolean} [modified] The page was been modified before loading (e.g. in source mode)
|
||||
*/
|
||||
function activateTarget( mode, targetPromise, modified ) {
|
||||
function activateTarget( mode, section, targetPromise, modified ) {
|
||||
var dataPromise;
|
||||
// Only call requestPageData early if the target object isn't there yet.
|
||||
// If the target object is there, this is a second or subsequent load, and the
|
||||
|
@ -226,6 +227,7 @@
|
|||
return mw.libs.ve.targetLoader.requestPageData(
|
||||
mode,
|
||||
mw.config.get( 'wgRelevantPageName' ),
|
||||
section,
|
||||
oldid,
|
||||
'mwTarget', // ve.init.mw.DesktopArticleTarget.static.name
|
||||
modified
|
||||
|
@ -459,10 +461,10 @@
|
|||
$caVeEdit.remove();
|
||||
} else if ( pageCanLoadVE ) {
|
||||
// Allow instant switching to edit mode, without refresh
|
||||
$caVeEdit.on( 'click', init.onEditTabClick );
|
||||
$caVeEdit.on( 'click', init.onEditTabClick.bind( init, 'visual' ) );
|
||||
}
|
||||
if ( conf.enableWikitext && mw.user.options.get( 'visualeditor-newwikitext' ) ) {
|
||||
$caEdit.on( 'click', init.onEditSourceTabClick );
|
||||
$caEdit.on( 'click', init.onEditTabClick.bind( init, 'source' ) );
|
||||
}
|
||||
|
||||
// Alter the edit tab (#ca-edit)
|
||||
|
@ -526,6 +528,7 @@
|
|||
} );
|
||||
} )
|
||||
.addClass( 'mw-editsection-visualeditor' );
|
||||
|
||||
if ( conf.tabPosition === 'before' ) {
|
||||
$editSourceLink.before( $editLink, $divider );
|
||||
} else {
|
||||
|
@ -543,8 +546,13 @@
|
|||
// and would preserve the wrong DOM with a diff on top.
|
||||
$editsections
|
||||
.find( '.mw-editsection-visualeditor' )
|
||||
.on( 'click', init.onEditSectionLinkClick )
|
||||
;
|
||||
.on( 'click', init.onEditSectionLinkClick.bind( init, 'visual' ) );
|
||||
if ( conf.enableWikitext ) {
|
||||
$editsections
|
||||
// TOOD: Make this less fragile
|
||||
.find( 'a:not( .mw-editsection-visualeditor )' )
|
||||
.on( 'click', init.onEditSectionLinkClick.bind( init, 'source' ) );
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -562,7 +570,7 @@
|
|||
return e && e.which && e.which === 1 && !( e.shiftKey || e.altKey || e.ctrlKey || e.metaKey );
|
||||
},
|
||||
|
||||
onEditTabClick: function ( e ) {
|
||||
onEditTabClick: function ( mode, e ) {
|
||||
if ( !init.isUnmodifiedLeftClick( e ) ) {
|
||||
return;
|
||||
}
|
||||
|
@ -577,21 +585,10 @@
|
|||
}
|
||||
} );
|
||||
} else {
|
||||
init.activateVe( 'visual' );
|
||||
init.activateVe( mode );
|
||||
}
|
||||
},
|
||||
|
||||
onEditSourceTabClick: function ( e ) {
|
||||
if ( !init.isUnmodifiedLeftClick( e ) ) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
if ( isLoading ) {
|
||||
return;
|
||||
}
|
||||
init.activateVe( 'source' );
|
||||
},
|
||||
|
||||
activateVe: function ( mode ) {
|
||||
var wikitext = $( '#wpTextbox1' ).textSelection( 'getContents' );
|
||||
|
||||
|
@ -639,8 +636,8 @@
|
|||
}
|
||||
},
|
||||
|
||||
onEditSectionLinkClick: function ( e ) {
|
||||
var targetPromise;
|
||||
onEditSectionLinkClick: function ( mode, e ) {
|
||||
var section, targetPromise;
|
||||
if ( !init.isUnmodifiedLeftClick( e ) ) {
|
||||
return;
|
||||
}
|
||||
|
@ -661,11 +658,20 @@
|
|||
history.pushState( { tag: 'visualeditor' }, document.title, this.href );
|
||||
}
|
||||
|
||||
targetPromise = getTarget( 'visual' ).then( function ( target ) {
|
||||
target.saveEditSection( $( e.target ).closest( 'h1, h2, h3, h4, h5, h6' ).get( 0 ) );
|
||||
return target;
|
||||
} );
|
||||
activateTarget( 'visual', targetPromise );
|
||||
targetPromise = getTarget( mode );
|
||||
if ( mode === 'visual' ) {
|
||||
targetPromise = targetPromise.then( function ( target ) {
|
||||
target.saveEditSection( $( e.target ).closest( 'h1, h2, h3, h4, h5, h6' ).get( 0 ) );
|
||||
return target;
|
||||
} );
|
||||
} else {
|
||||
section = +( new mw.Uri( e.target.href ).query.section );
|
||||
targetPromise = targetPromise.then( function ( target ) {
|
||||
target.section = section;
|
||||
return target;
|
||||
} );
|
||||
}
|
||||
activateTarget( mode, section, targetPromise );
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -765,6 +771,7 @@
|
|||
|
||||
$( function () {
|
||||
var showWikitextWelcome = true,
|
||||
section = uri.query.vesection !== undefined ? uri.query.vesection : null,
|
||||
isLoggedIn = !mw.user.isAnon(),
|
||||
prefSaysShowWelcome = isLoggedIn && !mw.user.options.get( 'visualeditor-hidebetawelcome' ),
|
||||
urlSaysHideWelcome = 'hidewelcomedialog' in new mw.Uri( location.href ).query,
|
||||
|
@ -838,7 +845,7 @@
|
|||
) {
|
||||
showWikitextWelcome = false;
|
||||
trackActivateStart( {
|
||||
type: uri.query.vesection === undefined ? 'page' : 'section',
|
||||
type: section === null ? 'page' : 'section',
|
||||
mechanism: 'url'
|
||||
} );
|
||||
if ( isViewPage && uri.query.veaction in editModes ) {
|
||||
|
@ -857,7 +864,7 @@
|
|||
) {
|
||||
action = 'editsource';
|
||||
}
|
||||
activateTarget( editModes[ action ] );
|
||||
activateTarget( editModes[ action ], section );
|
||||
}
|
||||
} else if (
|
||||
init.isVisualAvailable &&
|
||||
|
|
|
@ -56,7 +56,7 @@ ve.init.mw.DesktopArticleTarget = function VeInitMwDesktopArticleTarget( config
|
|||
};
|
||||
this.scrollTop = null;
|
||||
this.currentUri = currentUri;
|
||||
this.section = currentUri.query.vesection;
|
||||
this.section = currentUri.query.vesection !== undefined ? +currentUri.query.vesection : null;
|
||||
if ( $( '#wpSummary' ).length ) {
|
||||
this.initialEditSummary = $( '#wpSummary' ).val();
|
||||
} else {
|
||||
|
|
|
@ -66,19 +66,40 @@ ve.init.mw.DesktopWikitextArticleTarget.prototype.switchToWikitextEditor = funct
|
|||
* Switch to the visual editor.
|
||||
*/
|
||||
ve.init.mw.DesktopWikitextArticleTarget.prototype.switchToVisualEditor = function () {
|
||||
var dataPromise;
|
||||
var dataPromise, windowManager, switchWindow,
|
||||
target = this;
|
||||
|
||||
dataPromise = mw.libs.ve.targetLoader.requestParsoidData(
|
||||
this.pageName,
|
||||
this.revid,
|
||||
this.constructor.name,
|
||||
this.edited,
|
||||
this.getDocToSave()
|
||||
);
|
||||
if ( this.section !== null ) {
|
||||
// WT -> VE switching is not yet supported in sections, so
|
||||
// show a discard-only confirm dialog, then reload the whole page.
|
||||
windowManager = new OO.ui.WindowManager();
|
||||
switchWindow = new mw.libs.ve.SwitchConfirmDialog();
|
||||
$( 'body' ).append( windowManager.$element );
|
||||
windowManager.addWindows( [ switchWindow ] );
|
||||
windowManager.openWindow( switchWindow, { mode: 'simple' } )
|
||||
.then( function ( opened ) {
|
||||
return opened;
|
||||
} )
|
||||
.then( function ( closing ) { return closing; } )
|
||||
.then( function ( data ) {
|
||||
if ( data && data.action === 'discard' ) {
|
||||
target.setMode( 'visual' );
|
||||
target.reloadSurface();
|
||||
}
|
||||
windowManager.destroy();
|
||||
} );
|
||||
} else {
|
||||
dataPromise = mw.libs.ve.targetLoader.requestParsoidData(
|
||||
this.pageName,
|
||||
this.revid,
|
||||
this.constructor.name,
|
||||
this.edited,
|
||||
this.getDocToSave()
|
||||
);
|
||||
|
||||
this.setMode( 'visual' );
|
||||
|
||||
this.reloadSurface( dataPromise );
|
||||
this.setMode( 'visual' );
|
||||
this.reloadSurface( dataPromise );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -205,6 +226,16 @@ ve.init.mw.DesktopWikitextArticleTarget.prototype.createSurface = function ( dmD
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
ve.init.mw.DesktopWikitextArticleTarget.prototype.restoreEditSection = function () {
|
||||
if ( this.mode !== 'source' ) {
|
||||
// Parent method
|
||||
return ve.init.mw.DesktopWikitextArticleTarget.super.prototype.restoreEditSection.apply( this, arguments );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a wikitext fragment from a document
|
||||
*
|
||||
|
@ -309,11 +340,17 @@ ve.init.mw.DesktopWikitextArticleTarget.prototype.createDocToSave = function ()
|
|||
* @inheritdoc
|
||||
*/
|
||||
ve.init.mw.DesktopWikitextArticleTarget.prototype.tryWithPreparedCacheKey = function ( doc, options ) {
|
||||
var data;
|
||||
if ( this.mode === 'source' ) {
|
||||
return new mw.Api().post( ve.extendObject( {}, options, {
|
||||
wikitext: doc,
|
||||
format: 'json'
|
||||
} ),
|
||||
data = {
|
||||
wikitext: doc,
|
||||
format: 'json'
|
||||
};
|
||||
if ( this.section !== null ) {
|
||||
data.section = this.section;
|
||||
}
|
||||
return new mw.Api().post(
|
||||
ve.extendObject( {}, options, data ),
|
||||
{ contentType: 'multipart/form-data' }
|
||||
);
|
||||
} else {
|
||||
|
|
|
@ -64,10 +64,12 @@ mw.libs.ve.SwitchConfirmDialog.static.actions = [
|
|||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
mw.libs.ve.SwitchConfirmDialog.prototype.getSetupProcess = function () {
|
||||
mw.libs.ve.SwitchConfirmDialog.prototype.getSetupProcess = function ( data ) {
|
||||
return mw.libs.ve.SwitchConfirmDialog.super.prototype.getSetupProcess.apply( this, arguments )
|
||||
.next( function () {
|
||||
if (
|
||||
if ( data && data.mode ) {
|
||||
this.actions.setMode( data.mode );
|
||||
} else if (
|
||||
mw.config.get( 'wgVisualEditorConfig' ).fullRestbaseUrl &&
|
||||
!$( 'input[name=wpSection]' ).val()
|
||||
) {
|
||||
|
|
|
@ -40,6 +40,7 @@ ve.init.mw.ArticleTarget = function VeInitMwArticleTarget( pageName, revisionId,
|
|||
this.pageExists = mw.config.get( 'wgRelevantArticleId', 0 ) !== 0;
|
||||
this.toolbarScrollOffset = mw.config.get( 'wgVisualEditorToolbarScrollOffset', 0 );
|
||||
this.mode = config.mode || 'visual';
|
||||
this.section = null;
|
||||
|
||||
// Sometimes we actually don't want to send a useful oldid
|
||||
// if we do, PostEdit will give us a 'page restored' message
|
||||
|
@ -1022,6 +1023,7 @@ ve.init.mw.ArticleTarget.prototype.load = function ( dataPromise ) {
|
|||
this.loading = dataPromise || mw.libs.ve.targetLoader.requestPageData(
|
||||
this.mode,
|
||||
this.pageName,
|
||||
this.section,
|
||||
this.requestedRevId,
|
||||
this.constructor.name
|
||||
);
|
||||
|
@ -1046,6 +1048,7 @@ ve.init.mw.ArticleTarget.prototype.clearState = function () {
|
|||
this.startTimeStamp = null;
|
||||
this.doc = null;
|
||||
this.originalHtml = null;
|
||||
this.section = null;
|
||||
this.editNotices = [];
|
||||
this.remoteNotices = [];
|
||||
this.localNoticeMessages = [];
|
||||
|
@ -1704,7 +1707,7 @@ ve.init.mw.ArticleTarget.prototype.getSaveDialogOpeningData = function () {
|
|||
ve.init.mw.ArticleTarget.prototype.restoreEditSection = function () {
|
||||
var surfaceView, $documentNode, $section, headingNode;
|
||||
|
||||
if ( this.section !== undefined && this.section > 0 ) {
|
||||
if ( this.section !== null && this.section > 0 ) {
|
||||
surfaceView = this.getSurface().getView();
|
||||
$documentNode = surfaceView.getDocument().getDocumentNode().$element;
|
||||
$section = $documentNode.find( 'h1, h2, h3, h4, h5, h6' ).eq( this.section - 1 );
|
||||
|
@ -1718,8 +1721,6 @@ ve.init.mw.ArticleTarget.prototype.restoreEditSection = function () {
|
|||
if ( headingNode ) {
|
||||
this.goToHeading( headingNode );
|
||||
}
|
||||
|
||||
this.section = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -107,14 +107,15 @@
|
|||
*
|
||||
* @param {string} mode Target mode: 'visual' or 'source'
|
||||
* @param {string} pageName Page name to request
|
||||
* @param {number} [section] Section to edit (currently just source mode)
|
||||
* @param {string} [oldid] Old revision ID, current if omitted
|
||||
* @param {string} [targetName] Optional target name for tracking
|
||||
* @param {boolean} [modified] The page was been modified before loading (e.g. in source mode)
|
||||
* @return {jQuery.Promise} Abortable promise resolved with a JSON object
|
||||
*/
|
||||
requestPageData: function ( mode, pageName, oldid, targetName, modified ) {
|
||||
requestPageData: function ( mode, pageName, section, oldid, targetName, modified ) {
|
||||
if ( mode === 'source' ) {
|
||||
return this.requestWikitext( pageName, oldid, targetName, modified );
|
||||
return this.requestWikitext( pageName, section, oldid, targetName, modified );
|
||||
} else {
|
||||
return this.requestParsoidData( pageName, oldid, targetName, modified );
|
||||
}
|
||||
|
@ -245,7 +246,7 @@
|
|||
return dataPromise;
|
||||
},
|
||||
|
||||
requestWikitext: function ( pageName, oldid /*, targetName */ ) {
|
||||
requestWikitext: function ( pageName, section, oldid /*, targetName */ ) {
|
||||
var data = {
|
||||
action: 'visualeditor',
|
||||
paction: 'wikitext',
|
||||
|
@ -253,6 +254,11 @@
|
|||
uselang: mw.config.get( 'wgUserLanguage' )
|
||||
};
|
||||
|
||||
// section should never really be undefined, but check just in case
|
||||
if ( section !== null && section !== undefined ) {
|
||||
data.section = section;
|
||||
}
|
||||
|
||||
if ( oldid !== undefined ) {
|
||||
data.oldid = oldid;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue