mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-15 02:23:58 +00:00
Replace mediawiki.Uri with native URL (ArticleTarget)
Persistent global-ish properties in ArticleTarget and friends. A lot of our own code re-uses them, and code elsewhere could refer to them as well (although I didn't find any uses). In one case we need to keep using mediawiki.Uri, to handle building an array from query parameters exactly like PHP would handle it. Bug: T325249 Change-Id: I57699ff9dd39179ca29a87b6e2d9b12c2b86eb7d
This commit is contained in:
parent
1cab012fec
commit
2770809d1a
|
@ -48,8 +48,7 @@ ve.init.mw.ArticleTarget = function VeInitMwArticleTarget( config ) {
|
|||
var enableVisualSectionEditing = mw.config.get( 'wgVisualEditorConfig' ).enableVisualSectionEditing;
|
||||
this.enableVisualSectionEditing = enableVisualSectionEditing === true || enableVisualSectionEditing === this.constructor.static.trackingName;
|
||||
this.toolbarScrollOffset = mw.config.get( 'wgVisualEditorToolbarScrollOffset', 0 );
|
||||
// A workaround, as default URI does not get updated after pushState (T74334)
|
||||
this.currentUri = new mw.Uri( location.href );
|
||||
this.currentUrl = new URL( location.href );
|
||||
this.section = null;
|
||||
this.visibleSection = null;
|
||||
this.visibleSectionOffset = null;
|
||||
|
@ -58,10 +57,10 @@ ve.init.mw.ArticleTarget = function VeInitMwArticleTarget( config ) {
|
|||
this.initialEditSummary = null;
|
||||
this.initialCheckboxes = {};
|
||||
|
||||
this.viewUri = new mw.Uri( mw.util.getUrl( this.getPageName() ) );
|
||||
this.viewUrl = new URL( mw.util.getUrl( this.getPageName() ), location.href );
|
||||
this.isViewPage = (
|
||||
mw.config.get( 'wgAction' ) === 'view' &&
|
||||
this.currentUri.query.diff === undefined
|
||||
!this.currentUrl.searchParams.has( 'diff' )
|
||||
);
|
||||
|
||||
this.copyrightWarning = null;
|
||||
|
@ -302,7 +301,7 @@ ve.init.mw.ArticleTarget.prototype.loadSuccess = function ( response ) {
|
|||
// to make the VE API non-blocking in the future we will need to handle
|
||||
// special-cases like this where the content doesn't come from RESTBase.
|
||||
this.fromEditedState = !!data.fromEditedState || !!data.preloaded;
|
||||
this.switched = data.switched || 'wteswitched' in new mw.Uri( location.href ).query;
|
||||
this.switched = data.switched || new URL( location.href ).searchParams.has( 'wteswitched' );
|
||||
var mode = this.getDefaultMode();
|
||||
var section = ( mode === 'source' || this.enableVisualSectionEditing ) ? this.section : null;
|
||||
this.doc = this.constructor.static.parseDocument( this.originalHtml, mode, section );
|
||||
|
@ -637,20 +636,20 @@ ve.init.mw.ArticleTarget.prototype.saveComplete = function ( data ) {
|
|||
if ( !this.pageExists || this.restoring || !this.isViewPage ) {
|
||||
// Teardown the target, ensuring auto-save data is cleared
|
||||
this.teardown().then( function () {
|
||||
var newUrlParams = {};
|
||||
var newUrl = new URL( target.viewUrl );
|
||||
if ( data.newrevid !== undefined ) {
|
||||
if ( target.restoring ) {
|
||||
newUrlParams.venotify = 'restored';
|
||||
newUrl.searchParams.set( 'venotify', 'restored' );
|
||||
} else if ( !target.pageExists ) {
|
||||
newUrlParams.venotify = 'created';
|
||||
newUrl.searchParams.set( 'venotify', 'created' );
|
||||
} else {
|
||||
newUrlParams.venotify = 'saved';
|
||||
newUrl.searchParams.set( 'venotify', 'saved' );
|
||||
}
|
||||
}
|
||||
if ( data.isRedirect ) {
|
||||
newUrlParams.redirect = 'no';
|
||||
newUrl.searchParams.set( 'redirect', 'no' );
|
||||
}
|
||||
location.href = target.viewUri.extend( newUrlParams );
|
||||
location.href = newUrl;
|
||||
} );
|
||||
} else {
|
||||
// Update watch link to match 'watch checkbox' in save dialog.
|
||||
|
@ -2058,7 +2057,7 @@ ve.init.mw.ArticleTarget.prototype.restoreEditSection = function () {
|
|||
} );
|
||||
if ( headingModel ) {
|
||||
var headingView = surface.getView().getDocument().getDocumentNode().getNodeFromOffset( headingModel.getRange().start );
|
||||
if ( setEditSummary && new mw.Uri().query.summary === undefined ) {
|
||||
if ( setEditSummary && !new URL( location.href ).searchParams.has( 'summary' ) ) {
|
||||
headingText = headingView.$element.text();
|
||||
}
|
||||
if ( setExactScrollOffset ) {
|
||||
|
@ -2148,13 +2147,13 @@ ve.init.mw.ArticleTarget.prototype.scrollToHeading = function ( headingNode, hea
|
|||
};
|
||||
|
||||
/**
|
||||
* Get the hash fragment for the current section's ID using the page's HTML.
|
||||
* Get the URL hash for the current section's ID using the page's HTML.
|
||||
*
|
||||
* TODO: Do this in a less skin-dependent way
|
||||
*
|
||||
* @return {string} Hash fragment, or empty string if not found
|
||||
* @return {string} URL hash with leading '#', or empty string if not found
|
||||
*/
|
||||
ve.init.mw.ArticleTarget.prototype.getSectionFragmentFromPage = function () {
|
||||
ve.init.mw.ArticleTarget.prototype.getSectionHashFromPage = function () {
|
||||
// Assume there are section edit links, as the user just did a section edit. This also means
|
||||
// that the section numbers line up correctly, as not every H_ tag is a numbered section.
|
||||
var $sections = this.$editableContent.find( '.mw-editsection' );
|
||||
|
@ -2170,7 +2169,7 @@ ve.init.mw.ArticleTarget.prototype.getSectionFragmentFromPage = function () {
|
|||
var $section = $sections.eq( section - 1 ).parent().find( '.mw-headline' );
|
||||
|
||||
if ( $section.length && $section.attr( 'id' ) ) {
|
||||
return $section.attr( 'id' ) || '';
|
||||
return '#' + $section.attr( 'id' );
|
||||
}
|
||||
}
|
||||
return '';
|
||||
|
|
|
@ -53,7 +53,7 @@ ve.init.mw.DesktopArticleTarget = function VeInitMwDesktopArticleTarget( config
|
|||
if ( $( '#wpSummary' ).length ) {
|
||||
this.initialEditSummary = $( '#wpSummary' ).val();
|
||||
} else {
|
||||
this.initialEditSummary = this.currentUri.query.summary;
|
||||
this.initialEditSummary = this.currentUrl.searchParams.get( 'summary' );
|
||||
}
|
||||
this.initialCheckboxes = $( '.editCheckboxes input' ).toArray()
|
||||
.reduce( function ( initialCheckboxes, node ) {
|
||||
|
@ -75,7 +75,7 @@ ve.init.mw.DesktopArticleTarget = function VeInitMwDesktopArticleTarget( config
|
|||
// use the Back button to exit the editor we can restore Read mode. This is because we want
|
||||
// to ignore foreign states in onWindowPopState. Without this, the Read state is foreign.
|
||||
// FIXME: There should be a much better solution than this.
|
||||
history.replaceState( this.popState, '', this.currentUri );
|
||||
history.replaceState( this.popState, '', this.currentUrl );
|
||||
|
||||
this.setupSkinTabs();
|
||||
|
||||
|
@ -304,7 +304,7 @@ ve.init.mw.DesktopArticleTarget.prototype.setupToolbarSaveButton = function () {
|
|||
*/
|
||||
ve.init.mw.DesktopArticleTarget.prototype.setupLocalNoticeMessages = function () {
|
||||
if ( !(
|
||||
'vesupported' in this.currentUri.query ||
|
||||
this.currentUrl.searchParams.has( 'vesupported' ) ||
|
||||
$.client.test( this.constructor.static.compatibility.supportedList, null, true )
|
||||
) ) {
|
||||
// Show warning in unknown browsers that pass the support test
|
||||
|
@ -512,8 +512,8 @@ ve.init.mw.DesktopArticleTarget.prototype.setupNewSection = function ( surface )
|
|||
surface.setPlaceholder( ve.msg( 'visualeditor-section-body-placeholder' ) );
|
||||
this.$editableContent.before( this.sectionTitle.$element );
|
||||
|
||||
if ( this.currentUri.query.preloadtitle ) {
|
||||
this.sectionTitle.setValue( this.currentUri.query.preloadtitle );
|
||||
if ( this.currentUrl.searchParams.has( 'preloadtitle' ) ) {
|
||||
this.sectionTitle.setValue( this.currentUrl.searchParams.get( 'preloadtitle' ) );
|
||||
}
|
||||
surface.once( 'destroy', this.teardownNewSection.bind( this, surface ) );
|
||||
} else {
|
||||
|
@ -631,7 +631,7 @@ ve.init.mw.DesktopArticleTarget.prototype.teardown = function ( trackMechanism )
|
|||
}
|
||||
|
||||
target.clearState();
|
||||
target.initialEditSummary = new mw.Uri().query.summary;
|
||||
target.initialEditSummary = new URL( location.href ).searchParams.get( 'summary' );
|
||||
target.editSummaryValue = null;
|
||||
|
||||
// Move original content back out of the target
|
||||
|
@ -654,9 +654,11 @@ ve.init.mw.DesktopArticleTarget.prototype.teardown = function ( trackMechanism )
|
|||
}
|
||||
|
||||
if ( !target.isViewPage ) {
|
||||
location.href = target.viewUri.clone().extend( {
|
||||
redirect: mw.config.get( 'wgIsRedirect' ) ? 'no' : undefined
|
||||
} );
|
||||
var newUrl = new URL( target.viewUrl );
|
||||
if ( mw.config.get( 'wgIsRedirect' ) ) {
|
||||
newUrl.searchParams.set( 'redirect', 'no' );
|
||||
}
|
||||
location.href = newUrl;
|
||||
}
|
||||
} );
|
||||
};
|
||||
|
@ -673,7 +675,10 @@ ve.init.mw.DesktopArticleTarget.prototype.loadFail = function ( code, errorDetai
|
|||
if ( this.wikitextFallbackLoading ) {
|
||||
// Failed twice now
|
||||
mw.log.warn( 'Failed to fall back to wikitext', code, errorDetails );
|
||||
location.href = this.viewUri.clone().extend( { action: 'edit', veswitched: 1 } );
|
||||
var newUrl = new URL( target.viewUrl );
|
||||
newUrl.searchParams.set( 'action', 'edit' );
|
||||
newUrl.searchParams.set( 'veswitched', '1' );
|
||||
location.href = newUrl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -859,9 +864,9 @@ ve.init.mw.DesktopArticleTarget.prototype.saveComplete = function ( data ) {
|
|||
// Fix permalinks
|
||||
if ( data.newrevid !== undefined ) {
|
||||
$( '#t-permalink' ).add( '#coll-download-as-rl' ).find( 'a' ).each( function () {
|
||||
var uri = new mw.Uri( $( this ).attr( 'href' ) );
|
||||
uri.query.oldid = data.newrevid;
|
||||
$( this ).attr( 'href', uri.toString() );
|
||||
var permalinkUrl = new URL( this.href );
|
||||
permalinkUrl.searchParams.set( 'oldid', data.newrevid );
|
||||
$( this ).attr( 'href', permalinkUrl.toString() );
|
||||
} );
|
||||
}
|
||||
|
||||
|
@ -1078,36 +1083,36 @@ ve.init.mw.DesktopArticleTarget.prototype.transformCategoryLinks = function ( $c
|
|||
*/
|
||||
ve.init.mw.DesktopArticleTarget.prototype.updateHistoryState = function () {
|
||||
var veaction = this.getDefaultMode() === 'visual' ? 'edit' : 'editsource',
|
||||
section = this.section !== null ? this.section : undefined;
|
||||
section = this.section;
|
||||
|
||||
// Push veaction=edit(source) url in history (if not already. If we got here by a veaction=edit(source)
|
||||
// permalink then it will be there already and the constructor called #activate)
|
||||
if (
|
||||
!this.actFromPopState &&
|
||||
(
|
||||
this.currentUri.query.veaction !== veaction ||
|
||||
this.currentUri.query.section !== section
|
||||
this.currentUrl.searchParams.get( 'veaction' ) !== veaction ||
|
||||
this.currentUrl.searchParams.get( 'section' ) !== section
|
||||
) &&
|
||||
this.currentUri.query.action !== 'edit'
|
||||
this.currentUrl.searchParams.get( 'action' ) !== 'edit'
|
||||
) {
|
||||
// Set the current URL
|
||||
var uri = this.currentUri;
|
||||
var url = this.currentUrl;
|
||||
|
||||
if ( mw.libs.ve.isSingleEditTab ) {
|
||||
uri.query.action = 'edit';
|
||||
url.searchParams.set( 'action', 'edit' );
|
||||
mw.config.set( 'wgAction', 'edit' );
|
||||
} else {
|
||||
uri.query.veaction = veaction;
|
||||
delete uri.query.action;
|
||||
url.searchParams.set( 'veaction', veaction );
|
||||
url.searchParams.delete( 'action' );
|
||||
mw.config.set( 'wgAction', 'view' );
|
||||
}
|
||||
if ( this.section !== null ) {
|
||||
uri.query.section = this.section;
|
||||
url.searchParams.set( 'section', this.section );
|
||||
} else {
|
||||
delete uri.query.section;
|
||||
url.searchParams.delete( 'section' );
|
||||
}
|
||||
|
||||
history.pushState( this.popState, '', uri );
|
||||
history.pushState( this.popState, '', url );
|
||||
}
|
||||
this.actFromPopState = false;
|
||||
};
|
||||
|
@ -1131,19 +1136,19 @@ ve.init.mw.DesktopArticleTarget.prototype.restorePage = function () {
|
|||
// Push article url into history
|
||||
if ( !this.actFromPopState ) {
|
||||
// Remove the VisualEditor query parameters
|
||||
var uri = this.currentUri;
|
||||
if ( 'veaction' in uri.query ) {
|
||||
delete uri.query.veaction;
|
||||
var url = this.currentUrl;
|
||||
if ( url.searchParams.has( 'veaction' ) ) {
|
||||
url.searchParams.delete( 'veaction' );
|
||||
}
|
||||
if ( this.section !== null ) {
|
||||
// Translate into a fragment for the new URI:
|
||||
// Translate into a hash for the new URL:
|
||||
// This should be after replacePageContent if this is post-save, so we can just look
|
||||
// at the headers on the page.
|
||||
var fragment = this.getSectionFragmentFromPage();
|
||||
if ( fragment ) {
|
||||
uri.fragment = fragment;
|
||||
this.viewUri.fragment = fragment;
|
||||
var target = document.getElementById( fragment );
|
||||
var hash = this.getSectionHashFromPage();
|
||||
if ( hash ) {
|
||||
url.hash = hash;
|
||||
this.viewUrl.hash = hash;
|
||||
var target = document.getElementById( hash.slice( 1 ) );
|
||||
|
||||
if ( target ) {
|
||||
// Scroll the page to the edited section
|
||||
|
@ -1152,25 +1157,28 @@ ve.init.mw.DesktopArticleTarget.prototype.restorePage = function () {
|
|||
} );
|
||||
}
|
||||
}
|
||||
delete uri.query.section;
|
||||
url.searchParams.delete( 'section' );
|
||||
}
|
||||
if ( 'action' in uri.query && $( '#wpTextbox1:not(.ve-dummyTextbox)' ).length === 0 ) {
|
||||
if ( url.searchParams.has( 'action' ) && $( '#wpTextbox1:not(.ve-dummyTextbox)' ).length === 0 ) {
|
||||
// If we're not overlaid on an edit page, remove action=edit
|
||||
delete uri.query.action;
|
||||
url.searchParams.delete( 'action' );
|
||||
mw.config.set( 'wgAction', 'view' );
|
||||
}
|
||||
if ( 'oldid' in uri.query && !this.restoring ) {
|
||||
if ( url.searchParams.has( 'oldid' ) && !this.restoring ) {
|
||||
// We have an oldid in the query string but it's the most recent one, so remove it
|
||||
delete uri.query.oldid;
|
||||
url.searchParams.delete( 'oldid' );
|
||||
}
|
||||
|
||||
// If there are any other query parameters left, re-use that uri object.
|
||||
// Otherwise use the canonical style view url (T44553, T102363).
|
||||
var keys = Object.keys( uri.query );
|
||||
// If there are any other query parameters left, re-use that URL object.
|
||||
// Otherwise use the canonical style view URL (T44553, T102363).
|
||||
var keys = [];
|
||||
url.searchParams.forEach( function ( val, key ) {
|
||||
keys.push( key );
|
||||
} );
|
||||
if ( !keys.length || ( keys.length === 1 && keys[ 0 ] === 'title' ) ) {
|
||||
history.pushState( this.popState, '', this.viewUri );
|
||||
history.pushState( this.popState, '', this.viewUrl );
|
||||
} else {
|
||||
history.pushState( this.popState, '', uri );
|
||||
history.pushState( this.popState, '', url );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1187,11 +1195,11 @@ ve.init.mw.DesktopArticleTarget.prototype.onWindowPopState = function ( e ) {
|
|||
return;
|
||||
}
|
||||
|
||||
var oldUri = this.currentUri;
|
||||
var oldUrl = this.currentUrl;
|
||||
|
||||
this.currentUri = new mw.Uri( location.href );
|
||||
var veaction = this.currentUri.query.veaction;
|
||||
var action = this.currentUri.query.action;
|
||||
this.currentUrl = new URL( location.href );
|
||||
var veaction = this.currentUrl.searchParams.get( 'veaction' );
|
||||
var action = this.currentUrl.searchParams.get( 'action' );
|
||||
|
||||
if ( !veaction && action === 'edit' ) {
|
||||
veaction = this.getDefaultMode() === 'source' ? 'editsource' : 'edit';
|
||||
|
@ -1213,8 +1221,8 @@ ve.init.mw.DesktopArticleTarget.prototype.onWindowPopState = function ( e ) {
|
|||
if ( this.active && veaction !== 'edit' && veaction !== 'editsource' ) {
|
||||
this.actFromPopState = true;
|
||||
// "Undo" the pop-state, as the event is not cancellable
|
||||
history.pushState( this.popState, '', oldUri );
|
||||
this.currentUri = oldUri;
|
||||
history.pushState( this.popState, '', oldUrl );
|
||||
this.currentUrl = oldUrl;
|
||||
this.tryTeardown( false, 'navigate-back' ).then( function () {
|
||||
// Teardown was successful, re-apply the undone state
|
||||
history.back();
|
||||
|
@ -1434,19 +1442,22 @@ ve.init.mw.DesktopArticleTarget.prototype.switchToFallbackWikitextEditor = funct
|
|||
ve.track( 'mwedit.abort', { type: 'switchnochange', mechanism: 'navigate', mode: 'visual' } );
|
||||
this.submitting = true;
|
||||
return prefPromise.then( function () {
|
||||
var uri = target.viewUri.clone().extend( {
|
||||
action: 'edit',
|
||||
// No changes, safe to stay in section mode
|
||||
section: target.section !== null ? target.section : undefined,
|
||||
veswitched: 1
|
||||
} );
|
||||
var url = new URL( target.viewUrl );
|
||||
url.searchParams.set( 'action', 'edit' );
|
||||
// No changes, safe to stay in section mode
|
||||
if ( target.section !== null ) {
|
||||
url.searchParams.set( 'section', target.section );
|
||||
} else {
|
||||
url.searchParams.delete( 'section' );
|
||||
}
|
||||
url.searchParams.set( 'veswitched', '1' );
|
||||
if ( oldId && oldId !== mw.config.get( 'wgCurRevisionId' ) ) {
|
||||
uri.extend( { oldid: oldId } );
|
||||
url.searchParams.set( 'oldid', oldId );
|
||||
}
|
||||
if ( mw.libs.ve.isWelcomeDialogSuppressed() ) {
|
||||
uri.extend( { vehidebetadialog: 1 } );
|
||||
url.searchParams.set( 'vehidebetadialog', '1' );
|
||||
}
|
||||
location.href = uri.toString();
|
||||
location.href = url.toString();
|
||||
} );
|
||||
} else {
|
||||
return this.serialize( this.getDocToSave() ).then( function ( data ) {
|
||||
|
|
|
@ -429,7 +429,7 @@ ve.init.mw.MobileArticleTarget.prototype.saveComplete = function ( data ) {
|
|||
// Parent method
|
||||
ve.init.mw.MobileArticleTarget.super.prototype.saveComplete.apply( this, arguments );
|
||||
|
||||
var fragment = this.getSectionFragmentFromPage();
|
||||
var fragment = this.getSectionHashFromPage().slice( 1 );
|
||||
|
||||
this.overlay.sectionId = fragment;
|
||||
this.overlay.onSaveComplete( data.newrevid );
|
||||
|
@ -460,9 +460,11 @@ ve.init.mw.MobileArticleTarget.prototype.teardown = function () {
|
|||
// Parent method
|
||||
return ve.init.mw.MobileArticleTarget.super.prototype.teardown.call( this ).then( function () {
|
||||
if ( !target.isViewPage ) {
|
||||
location.href = target.viewUri.clone().extend( {
|
||||
redirect: mw.config.get( 'wgIsRedirect' ) ? 'no' : undefined
|
||||
} );
|
||||
var newUrl = new URL( target.viewUrl );
|
||||
if ( mw.config.get( 'wgIsRedirect' ) ) {
|
||||
newUrl.searchParams.set( 'redirect', 'no' );
|
||||
}
|
||||
location.href = newUrl;
|
||||
}
|
||||
} );
|
||||
};
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
* @singleton
|
||||
*/
|
||||
( function () {
|
||||
var conf, tabMessages, uri, pageExists, viewUri, veEditUri, veEditSourceUri,
|
||||
var conf, tabMessages, url, pageExists, viewUrl, veEditUrl, veEditSourceUrl,
|
||||
init, targetPromise,
|
||||
tabPreference, initialWikitext, oldId,
|
||||
isLoading, tempWikitextEditor, tempWikitextEditorData,
|
||||
|
@ -200,7 +200,7 @@
|
|||
updateTabs( false );
|
||||
// Push read tab URL to history
|
||||
if ( $( '#ca-view a' ).length ) {
|
||||
history.pushState( { tag: 'visualeditor' }, '', new mw.Uri( $( '#ca-view a' ).attr( 'href' ) ) );
|
||||
history.pushState( { tag: 'visualeditor' }, '', $( '#ca-view a' ).attr( 'href' ) );
|
||||
}
|
||||
clearLoading();
|
||||
}
|
||||
|
@ -216,7 +216,7 @@
|
|||
* Parse a section value from a query string object
|
||||
*
|
||||
* @example
|
||||
* parseSection( uri.query.section )
|
||||
* parseSection( new URL( location.href ).searchParams.get( 'section' ) )
|
||||
*
|
||||
* @param {string|undefined} section Section value from query object
|
||||
* @return {string|null} Section if valid, null otherwise
|
||||
|
@ -280,16 +280,10 @@
|
|||
updateTabs( false );
|
||||
} );
|
||||
target.on( 'reactivate', function () {
|
||||
try {
|
||||
// T270331, see below.
|
||||
uri = new mw.Uri( null, { arrayParams: true } );
|
||||
} catch ( e ) {
|
||||
uri = viewUri;
|
||||
}
|
||||
|
||||
url = new URL( location.href );
|
||||
activateTarget(
|
||||
getEditModeFromUri( uri ),
|
||||
parseSection( uri.query.section )
|
||||
getEditModeFromUrl( url ),
|
||||
parseSection( url.searchParams.get( 'section' ) )
|
||||
);
|
||||
} );
|
||||
target.setContainer( $targetContainer );
|
||||
|
@ -308,12 +302,13 @@
|
|||
}
|
||||
|
||||
function trackActivateStart( initData, link ) {
|
||||
var linkUrl;
|
||||
if ( link ) {
|
||||
link = new mw.Uri( $( link ).closest( 'a' ).attr( 'href' ) );
|
||||
linkUrl = new URL( $( link ).closest( 'a' ).attr( 'href' ), location.href );
|
||||
} else {
|
||||
link = uri;
|
||||
linkUrl = url;
|
||||
}
|
||||
if ( link && link.query.wvprov === 'sticky-header' ) {
|
||||
if ( linkUrl.searchParams.get( 'wvprov' ) === 'sticky-header' ) {
|
||||
initData.mechanism += '-sticky-header';
|
||||
}
|
||||
ve.track( 'trace.activate.enter', { mode: initData.mode } );
|
||||
|
@ -450,8 +445,8 @@
|
|||
|
||||
var $heading;
|
||||
$( '#mw-content-text .mw-editsection a:not( .mw-editsection-visualeditor )' ).each( function () {
|
||||
var linkUri = new mw.Uri( this.href );
|
||||
if ( section === parseSection( linkUri.query.section ) ) {
|
||||
var linkUrl = new URL( this.href );
|
||||
if ( section === parseSection( linkUrl.searchParams.get( 'section' ) ) ) {
|
||||
$heading = $( this ).closest( 'h1, h2, h3, h4, h5, h6' );
|
||||
return false;
|
||||
}
|
||||
|
@ -531,9 +526,10 @@
|
|||
// This is used for stats tracking, so do not change!
|
||||
targetName: 'mwTarget',
|
||||
modified: modified,
|
||||
editintro: uri.query.editintro,
|
||||
preload: uri.query.preload,
|
||||
preloadparams: uri.query.preloadparams,
|
||||
editintro: url.searchParams.get( 'editintro' ),
|
||||
preload: url.searchParams.get( 'preload' ),
|
||||
// Handle numbered array parameters like MediaWiki's PHP code does (T231382)
|
||||
preloadparams: new mw.Uri( url.toString(), { arrayParams: true } ).query.preloadparams,
|
||||
// If switching to visual with modifications, check if we have wikitext to convert
|
||||
wikitext: mode === 'visual' && modified ? $( '#wpTextbox1' ).textSelection( 'getContents' ) : undefined
|
||||
} );
|
||||
|
@ -574,8 +570,8 @@
|
|||
|
||||
if ( firstVisibleEditSection && firstVisibleEditSection.id !== 'firstHeading' ) {
|
||||
var firstVisibleSectionLink = firstVisibleEditSection.querySelector( 'a' );
|
||||
var linkUri = new mw.Uri( firstVisibleSectionLink.href );
|
||||
visibleSection = parseSection( linkUri.query.section );
|
||||
var linkUrl = new URL( firstVisibleSectionLink.href );
|
||||
visibleSection = parseSection( linkUrl.searchParams.get( 'section' ) );
|
||||
|
||||
var firstVisibleHeading = $( firstVisibleEditSection ).closest( 'h1, h2, h3, h4, h5, h6' )[ 0 ];
|
||||
visibleSectionOffset = firstVisibleHeading.getBoundingClientRect().top;
|
||||
|
@ -635,16 +631,16 @@
|
|||
trackActivateStart( { type: 'page', mechanism: mw.config.get( 'wgArticleId' ) ? 'click' : 'new', mode: mode }, link );
|
||||
|
||||
if ( !active ) {
|
||||
if ( uri.query.action !== 'edit' && !( uri.query.veaction in veactionToMode ) ) {
|
||||
if ( url.searchParams.get( 'action' ) !== 'edit' && !( url.searchParams.get( 'veaction' ) in veactionToMode ) ) {
|
||||
// Replace the current state with one that is tagged as ours, to prevent the
|
||||
// back button from breaking when used to exit VE. FIXME: there should be a better
|
||||
// way to do this. See also similar code in the DesktopArticleTarget constructor.
|
||||
history.replaceState( { tag: 'visualeditor' }, '', uri );
|
||||
history.replaceState( { tag: 'visualeditor' }, '', url );
|
||||
// Set action=edit or veaction=edit/editsource
|
||||
history.pushState( { tag: 'visualeditor' }, '', mode === 'source' ? veEditSourceUri : veEditUri );
|
||||
history.pushState( { tag: 'visualeditor' }, '', mode === 'source' ? veEditSourceUrl : veEditUrl );
|
||||
|
||||
// Update mw.Uri instance
|
||||
uri = veEditUri;
|
||||
// Update URL instance
|
||||
url = veEditUrl;
|
||||
}
|
||||
|
||||
activateTarget( mode, section, undefined, modified );
|
||||
|
@ -678,7 +674,7 @@
|
|||
function getEditPageEditor() {
|
||||
// This logic matches VisualEditorHooks::getEditPageEditor
|
||||
// !!+ casts '0' to false
|
||||
var isRedLink = !!+uri.query.redlink;
|
||||
var isRedLink = !!+url.searchParams.get( 'redlink' );
|
||||
// On dual-edit-tab wikis, the edit page must mean the user wants wikitext,
|
||||
// unless following a redlink
|
||||
if ( !mw.config.get( 'wgVisualEditorConfig' ).singleEditTab && !isRedLink ) {
|
||||
|
@ -752,16 +748,9 @@
|
|||
|
||||
conf = mw.config.get( 'wgVisualEditorConfig' );
|
||||
tabMessages = conf.tabMessages;
|
||||
viewUri = new mw.Uri( mw.util.getUrl( mw.config.get( 'wgRelevantPageName' ) ) );
|
||||
try {
|
||||
uri = new mw.Uri( null, { arrayParams: true } );
|
||||
} catch ( e ) {
|
||||
// URI failed to parse, probably because of query string parameters. (T270331)
|
||||
// Fall back to the viewUri so that initialization completes.
|
||||
// Ideally mw.Uri would ignore invalid parameters or characters.
|
||||
uri = viewUri;
|
||||
}
|
||||
// T156998: Don't trust uri.query.oldid, it'll be wrong if uri.query.diff or uri.query.direction
|
||||
viewUrl = new URL( mw.util.getUrl( mw.config.get( 'wgRelevantPageName' ) ), location.href );
|
||||
url = new URL( location.href );
|
||||
// T156998: Don't trust 'oldid' query parameter, it'll be wrong if 'diff' or 'direction'
|
||||
// is set to 'next' or 'prev'.
|
||||
oldId = mw.config.get( 'wgRevisionId' ) || $( 'input[name=parentRevId]' ).val();
|
||||
// wgFlaggedRevsEditLatestRevision is set by FlaggedRevs extension when viewing a stable revision
|
||||
|
@ -771,7 +760,7 @@
|
|||
oldId = undefined;
|
||||
}
|
||||
pageExists = !!mw.config.get( 'wgRelevantArticleId' );
|
||||
var isViewPage = mw.config.get( 'wgIsArticle' ) && !( 'diff' in uri.query );
|
||||
var isViewPage = mw.config.get( 'wgIsArticle' ) && !url.searchParams.has( 'diff' );
|
||||
var wgAction = mw.config.get( 'wgAction' );
|
||||
var isEditPage = wgAction === 'edit' || wgAction === 'submit';
|
||||
var pageCanLoadEditor = isViewPage || isEditPage;
|
||||
|
@ -851,17 +840,11 @@
|
|||
// Add section is currently a wikitext-only feature
|
||||
'#ca-addsection a'
|
||||
).each( function () {
|
||||
var linkUri;
|
||||
try {
|
||||
linkUri = new mw.Uri( this.href );
|
||||
} catch ( e ) {
|
||||
// T66884
|
||||
return;
|
||||
}
|
||||
if ( 'action' in linkUri.query ) {
|
||||
delete linkUri.query.action;
|
||||
linkUri.query.veaction = 'editsource';
|
||||
$( this ).attr( 'href', linkUri.toString() );
|
||||
var linkUrl = new URL( this.href );
|
||||
if ( linkUrl.searchParams.has( 'action' ) ) {
|
||||
linkUrl.searchParams.delete( 'action' );
|
||||
linkUrl.searchParams.set( 'veaction', 'editsource' );
|
||||
$( this ).attr( 'href', linkUrl.toString() );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
@ -949,7 +932,7 @@
|
|||
// onEditTabClick is bound.
|
||||
// 2) when onEditTabClick is not bound (!pageCanLoadEditor) it will
|
||||
// just work.
|
||||
veEditUri,
|
||||
veEditUrl,
|
||||
getTabMessage( action ),
|
||||
'ca-ve-edit',
|
||||
mw.msg( 'tooltip-ca-ve-edit' ),
|
||||
|
@ -1056,9 +1039,10 @@
|
|||
if ( !$( '#ca-view-foreign' ).length ) {
|
||||
$editLink
|
||||
.attr( 'href', function ( i, href ) {
|
||||
var veUri = new mw.Uri( veEditUri );
|
||||
veUri.query.section = ( new mw.Uri( href ) ).query.section;
|
||||
return veUri.toString();
|
||||
var veUrl = new URL( veEditUrl );
|
||||
var section = new URL( href, location.href ).searchParams.get( 'section' );
|
||||
veUrl.searchParams.set( 'section', section );
|
||||
return veUrl.toString();
|
||||
} )
|
||||
.addClass( 'mw-editsection-visualeditor' );
|
||||
|
||||
|
@ -1206,14 +1190,14 @@
|
|||
windowManager.addWindows( [ switchWindow ] );
|
||||
windowManager.openWindow( switchWindow )
|
||||
.closed.then( function ( data ) {
|
||||
var oldUri;
|
||||
// TODO: windowManager.destroy()?
|
||||
if ( data && data.action === 'discard' ) {
|
||||
releaseOldEditWarning();
|
||||
setEditorPreference( 'visualeditor' );
|
||||
oldUri = veEditUri.clone();
|
||||
delete oldUri.query.veswitched;
|
||||
location.href = oldUri.extend( { wteswitched: 1 } );
|
||||
var oldUrl = new URL( veEditUrl );
|
||||
oldUrl.searchParams.delete( 'veswitched' );
|
||||
oldUrl.searchParams.set( 'wteswitched', '1' );
|
||||
location.href = oldUrl;
|
||||
}
|
||||
} );
|
||||
} );
|
||||
|
@ -1231,16 +1215,16 @@
|
|||
* @param {string} [section] Override edit section, taken from link URL if not specified
|
||||
*/
|
||||
onEditSectionLinkClick: function ( mode, e, section ) {
|
||||
var linkUri = new mw.Uri( e.target.href ),
|
||||
title = mw.Title.newFromText( linkUri.query.title || '' );
|
||||
var linkUrl = new URL( e.target.href ),
|
||||
title = mw.Title.newFromText( linkUrl.searchParams.get( 'title' ) || '' );
|
||||
|
||||
if (
|
||||
// Modified click (e.g. ctrl+click)
|
||||
!init.isUnmodifiedLeftClick( e ) ||
|
||||
// Not an edit action
|
||||
!( 'action' in linkUri.query || 'veaction' in linkUri.query ) ||
|
||||
!( linkUrl.searchParams.has( 'action' ) || linkUrl.searchParams.has( 'veaction' ) ) ||
|
||||
// Edit target is on another host (e.g. commons file)
|
||||
linkUri.getHostPort() !== location.host ||
|
||||
linkUrl.host !== location.host ||
|
||||
// Title param doesn't match current page
|
||||
title && title.getPrefixedText() !== new mw.Title( mw.config.get( 'wgRelevantPageName' ) ).getPrefixedText()
|
||||
) {
|
||||
|
@ -1254,20 +1238,20 @@
|
|||
trackActivateStart( { type: 'section', mechanism: section === 'new' ? 'new' : 'click', mode: mode }, e.target );
|
||||
|
||||
if ( !active ) {
|
||||
if ( uri.query.action !== 'edit' && !( uri.query.veaction in veactionToMode ) ) {
|
||||
if ( url.searchParams.get( 'action' ) !== 'edit' && !( url.searchParams.get( 'veaction' ) in veactionToMode ) ) {
|
||||
// Replace the current state with one that is tagged as ours, to prevent the
|
||||
// back button from breaking when used to exit VE. FIXME: there should be a better
|
||||
// way to do this. See also similar code in the DesktopArticleTarget constructor.
|
||||
history.replaceState( { tag: 'visualeditor' }, '', uri );
|
||||
// Use linkUri
|
||||
history.pushState( { tag: 'visualeditor' }, '', linkUri );
|
||||
history.replaceState( { tag: 'visualeditor' }, '', url );
|
||||
// Use linkUrl
|
||||
history.pushState( { tag: 'visualeditor' }, '', linkUrl );
|
||||
}
|
||||
// Update mw.Uri instance
|
||||
uri = linkUri;
|
||||
// Update URL instance
|
||||
url = linkUrl;
|
||||
|
||||
// Use section from URL
|
||||
if ( section === undefined ) {
|
||||
section = parseSection( linkUri.query.section );
|
||||
section = parseSection( linkUrl.searchParams.get( 'section' ) );
|
||||
}
|
||||
var tPromise = getTarget( mode, section );
|
||||
activateTarget( mode, section, tPromise, e.target );
|
||||
|
@ -1304,9 +1288,9 @@
|
|||
// Disabled by calling disableWelcomeDialog()?
|
||||
welcomeDialogDisabled ||
|
||||
// Hidden using URL parameter?
|
||||
'vehidebetadialog' in new mw.Uri().query ||
|
||||
new URL( location.href ).searchParams.has( 'vehidebetadialog' ) ||
|
||||
// Check for deprecated hidewelcomedialog parameter (T249954)
|
||||
'hidewelcomedialog' in new mw.Uri().query
|
||||
new URL( location.href ).searchParams.has( 'hidewelcomedialog' )
|
||||
);
|
||||
},
|
||||
|
||||
|
@ -1370,27 +1354,28 @@
|
|||
|
||||
init.isSingleEditTab = conf.singleEditTab && tabPreference !== 'multi-tab';
|
||||
|
||||
// On a view page, extend the current URI so parameters like oldid are carried over
|
||||
// On a non-view page, use viewUri
|
||||
var veEditBaseUri = pageCanLoadEditor ? uri : viewUri;
|
||||
if ( init.isSingleEditTab ) {
|
||||
veEditSourceUri = veEditUri = veEditBaseUri.clone().extend( { action: 'edit' } );
|
||||
delete veEditUri.query.veaction;
|
||||
} else {
|
||||
veEditUri = veEditBaseUri.clone().extend( { veaction: 'edit' } );
|
||||
veEditSourceUri = veEditBaseUri.clone().extend( { veaction: 'editsource' } );
|
||||
delete veEditUri.query.action;
|
||||
delete veEditSourceUri.query.action;
|
||||
}
|
||||
// On a view page, extend the current URL so extra parameters are carried over
|
||||
// On a non-view page, use viewUrl
|
||||
veEditUrl = new URL( pageCanLoadEditor ? url : viewUrl );
|
||||
if ( oldId ) {
|
||||
veEditUri.extend( { oldid: oldId } );
|
||||
veEditUrl.searchParams.set( 'oldid', oldId );
|
||||
}
|
||||
veEditUrl.searchParams.delete( 'veaction' );
|
||||
veEditUrl.searchParams.delete( 'action' );
|
||||
if ( init.isSingleEditTab ) {
|
||||
veEditUrl.searchParams.set( 'action', 'edit' );
|
||||
veEditSourceUrl = veEditUrl;
|
||||
} else {
|
||||
veEditSourceUrl = new URL( veEditUrl );
|
||||
veEditUrl.searchParams.set( 'veaction', 'edit' );
|
||||
veEditSourceUrl.searchParams.set( 'veaction', 'editsource' );
|
||||
}
|
||||
|
||||
// Whether VisualEditor should be available for the current user, page, wiki, mediawiki skin,
|
||||
// browser etc.
|
||||
init.isAvailable = (
|
||||
VisualEditorSupportCheck() &&
|
||||
( ( 'vesupported' in uri.query ) || !$.client.test( init.unsupportedList, null, true ) )
|
||||
( url.searchParams.has( 'vesupported' ) || !$.client.test( init.unsupportedList, null, true ) )
|
||||
// Extensions can disable VE in certain circumstances using the VisualEditorBeforeEditor hook (T174180)
|
||||
);
|
||||
|
||||
|
@ -1406,7 +1391,7 @@
|
|||
init.isAvailable &&
|
||||
|
||||
// If forced by the URL parameter, skip the namespace check (T221892) and preference check
|
||||
( uri.query.veaction === 'edit' || (
|
||||
( url.searchParams.get( 'veaction' ) === 'edit' || (
|
||||
// Only in enabled namespaces
|
||||
conf.namespaces.indexOf( new mw.Title( mw.config.get( 'wgRelevantPageName' ) ).getNamespaceId() ) !== -1 &&
|
||||
|
||||
|
@ -1465,32 +1450,32 @@
|
|||
// for e.g. "Edit" > "Edit source" even when VE is not available.
|
||||
}
|
||||
|
||||
function isSupportedEditPage( editUri ) {
|
||||
function isSupportedEditPage( editUrl ) {
|
||||
return configData.unsupportedEditParams.every( function ( param ) {
|
||||
return editUri.query[ param ] === undefined;
|
||||
return !editUrl.searchParams.has( param );
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the edit mode for the given URI
|
||||
* Get the edit mode for the given URL
|
||||
*
|
||||
* @param {mw.Uri} editUri Edit URI
|
||||
* @param {URL} editUrl Edit URL
|
||||
* @return {string} 'visual' or 'source'
|
||||
*/
|
||||
function getEditModeFromUri( editUri ) {
|
||||
function getEditModeFromUrl( editUrl ) {
|
||||
if ( mw.config.get( 'wgDiscussionToolsStartNewTopicTool' ) ) {
|
||||
// Avoid conflicts with DiscussionTools
|
||||
return false;
|
||||
}
|
||||
// On view pages if veaction is correctly set
|
||||
var m = veactionToMode[ editUri.query.veaction ];
|
||||
var m = veactionToMode[ editUrl.searchParams.get( 'veaction' ) ];
|
||||
if ( isViewPage && init.isAvailable && availableModes.indexOf( m ) !== -1 ) {
|
||||
return m;
|
||||
}
|
||||
// Edit pages
|
||||
if ( isEditPage && isSupportedEditPage( editUri ) ) {
|
||||
if ( isEditPage && isSupportedEditPage( editUrl ) ) {
|
||||
// Just did a discard-switch from wikitext editor to VE (in no RESTBase mode)
|
||||
if ( editUri.query.wteswitched === '1' ) {
|
||||
if ( editUrl.searchParams.get( 'wteswitched' ) === '1' ) {
|
||||
return init.isVisualAvailable ? 'visual' : null;
|
||||
}
|
||||
// User has disabled VE, or we are in view source only mode, or we have landed here with posted data
|
||||
|
@ -1513,7 +1498,7 @@
|
|||
|
||||
var showWikitextWelcome = true,
|
||||
numEditButtons = $( '#ca-edit, #ca-viewsource' ).length,
|
||||
section = parseSection( uri.query.section );
|
||||
section = parseSection( url.searchParams.get( 'section' ) );
|
||||
|
||||
var requiredSkinElements =
|
||||
$targetContainer.length &&
|
||||
|
@ -1521,7 +1506,7 @@
|
|||
// A link to open the editor is technically not necessary if it's going to open itself
|
||||
( isEditPage || numEditButtons );
|
||||
|
||||
if ( uri.query.action === 'edit' && $( '#wpTextbox1' ).length ) {
|
||||
if ( url.searchParams.get( 'action' ) === 'edit' && $( '#wpTextbox1' ).length ) {
|
||||
initialWikitext = $( '#wpTextbox1' ).textSelection( 'getContents' );
|
||||
}
|
||||
|
||||
|
@ -1543,7 +1528,7 @@
|
|||
mw.errorLogger.logError( err, 'error.visualeditor' );
|
||||
}
|
||||
} else if ( init.isAvailable ) {
|
||||
var mode = getEditModeFromUri( uri );
|
||||
var mode = getEditModeFromUrl( url );
|
||||
if ( mode ) {
|
||||
showWikitextWelcome = false;
|
||||
trackActivateStart( {
|
||||
|
@ -1561,7 +1546,7 @@
|
|||
// with accesskey 'v' so create one
|
||||
$( document.body ).append(
|
||||
$( '<a>' )
|
||||
.attr( { accesskey: mw.msg( 'accesskey-ca-ve-edit' ), href: veEditUri } )
|
||||
.attr( { accesskey: mw.msg( 'accesskey-ca-ve-edit' ), href: veEditUrl } )
|
||||
// Accesskey fires a click event
|
||||
.on( 'click.ve-target', init.onEditTabClick.bind( init, 'visual' ) )
|
||||
.addClass( 'oo-ui-element-hidden' )
|
||||
|
@ -1578,7 +1563,7 @@
|
|||
$( '#wpTextbox1' ).on( 'wikiEditor-toolbar-doneInitialSections', function () {
|
||||
mw.loader.using( 'ext.visualEditor.switching' ).done( function () {
|
||||
var windowManager, editingTabDialog, switchToolbar, popup,
|
||||
showPopup = !!uri.query.veswitched && !mw.user.options.get( 'visualeditor-hidesourceswitchpopup' ),
|
||||
showPopup = url.searchParams.has( 'veswitched' ) && !mw.user.options.get( 'visualeditor-hidesourceswitchpopup' ),
|
||||
toolFactory = new OO.ui.ToolFactory(),
|
||||
toolGroupFactory = new OO.ui.ToolGroupFactory();
|
||||
|
||||
|
@ -1628,7 +1613,7 @@
|
|||
windowManager.destroy();
|
||||
|
||||
if ( data && data.action === 'prefer-ve' ) {
|
||||
location.href = veEditUri;
|
||||
location.href = veEditUrl;
|
||||
} else if ( data && data.action === 'multi-tab' ) {
|
||||
location.reload();
|
||||
}
|
||||
|
@ -1690,19 +1675,19 @@
|
|||
} );
|
||||
}
|
||||
|
||||
if ( uri.query.venotify ) {
|
||||
var notify = uri.query.venotify;
|
||||
if ( url.searchParams.has( 'venotify' ) ) {
|
||||
var notify = url.searchParams.get( 'venotify' );
|
||||
|
||||
// wgPostEdit can be "saved", "created", "restored" or null for null edits.
|
||||
// TODO: Also set wgPostEdit on non-redirecting edits (T240041)
|
||||
mw.config.set( 'wgPostEdit', notify );
|
||||
|
||||
// Loadomg postEdit code will trigger the post edit notification as wgPostEdit is set
|
||||
// Loading postEdit code will trigger the post edit notification as wgPostEdit is set
|
||||
mw.loader.load( 'mediawiki.action.view.postEdit' );
|
||||
|
||||
delete uri.query.venotify;
|
||||
url.searchParams.delete( 'venotify' );
|
||||
// Get rid of the ?venotify= from the URL
|
||||
history.replaceState( null, '', uri );
|
||||
history.replaceState( null, '', url );
|
||||
}
|
||||
} );
|
||||
}() );
|
||||
|
|
Loading…
Reference in a new issue