diff --git a/modules/ve-mw/init/targets/ve.init.mw.ArticleTarget.js b/modules/ve-mw/init/targets/ve.init.mw.ArticleTarget.js index 8b5978eafa..dee572d9ef 100644 --- a/modules/ve-mw/init/targets/ve.init.mw.ArticleTarget.js +++ b/modules/ve-mw/init/targets/ve.init.mw.ArticleTarget.js @@ -953,21 +953,31 @@ ve.init.mw.ArticleTarget.prototype.onSaveDialogPreview = function () { this.emit( 'savePreview' ); this.saveDialog.pushPending(); - var wikitext = this.getDocToSave(); - if ( this.sectionTitle && this.sectionTitle.getValue() ) { - wikitext = '== ' + this.sectionTitle.getValue() + ' ==\n\n' + wikitext; + var params = {}; + + var sectionTitle = this.sectionTitle && this.sectionTitle.getValue(); + if ( sectionTitle ) { + params.section = 'new'; + params.sectiontitle = sectionTitle; + } + if ( mw.config.get( 'wgUserVariant' ) ) { + params.variant = mw.config.get( 'wgUserVariant' ); } - api.post( { - action: 'visualeditor', - paction: 'parsedoc', - page: this.getPageName(), - wikitext: wikitext, - pst: true - } ).then( function ( response ) { - var baseDoc = target.getSurface().getModel().getDocument().getHtmlDocument(); - var doc = target.constructor.static.parseDocument( response.visualeditor.content, 'visual' ); - target.saveDialog.showPreview( doc, baseDoc ); + api.post( ve.extendObject( params, { + action: 'parse', + title: this.getPageName(), + text: this.getDocToSave(), + pst: true, + preview: true, + sectionpreview: this.section !== null, + disableeditsection: true, + uselang: mw.config.get( 'wgUserLanguage' ), + useskin: mw.config.get( 'skin' ), + mobileformat: OO.ui.isMobile(), + prop: [ 'text', 'categorieshtml', 'displaytitle', 'subtitle', 'modules', 'jsconfigvars' ] + } ) ).then( function ( response ) { + target.saveDialog.showPreview( response ); }, function ( errorCode, details ) { target.saveDialog.showPreview( target.extractErrorMessages( details ) ); } ).always( function () { diff --git a/modules/ve-mw/preinit/styles/ve.init.mw.DesktopArticleTarget.init.less b/modules/ve-mw/preinit/styles/ve.init.mw.DesktopArticleTarget.init.less index 396cafcc37..4cca028f95 100644 --- a/modules/ve-mw/preinit/styles/ve.init.mw.DesktopArticleTarget.init.less +++ b/modules/ve-mw/preinit/styles/ve.init.mw.DesktopArticleTarget.init.less @@ -86,7 +86,7 @@ } } - #catlinks { + .ve-init-mw-desktopArticleTarget-originalContent #catlinks { cursor: pointer; &:hover { diff --git a/modules/ve-mw/preinit/ve.utils.parsoid.js b/modules/ve-mw/preinit/ve.utils.parsoid.js index 6ab357103d..22e37b7d13 100644 --- a/modules/ve-mw/preinit/ve.utils.parsoid.js +++ b/modules/ve-mw/preinit/ve.utils.parsoid.js @@ -214,31 +214,40 @@ mw.libs.ve.fixFragmentLinks = function ( container, docTitle, prefix ) { var docTitleText = docTitle.getPrefixedText(); prefix = prefix || ''; Array.prototype.forEach.call( container.querySelectorAll( 'a[href*="#"]' ), function ( el ) { - var fragment = new mw.Uri( el.href ).fragment, - targetData = mw.libs.ve.getTargetDataFromHref( el.href, el.ownerDocument ); + var fragment = null; + if ( el.getAttribute( 'href' )[ 0 ] === '#' ) { + // Leagcy parser + fragment = el.getAttribute( 'href' ).slice( 1 ); + } else { + // Parsoid HTML + var targetData = mw.libs.ve.getTargetDataFromHref( el.href, el.ownerDocument ); - if ( targetData.isInternal ) { - var title = mw.Title.newFromText( targetData.title ); - if ( title && title.getPrefixedText() === docTitleText ) { - if ( !fragment ) { - // Special case for empty fragment, even if prefix set - el.setAttribute( 'href', '#' ); - } else { - if ( prefix ) { - var target = container.querySelector( '#' + $.escapeSelector( fragment ) ); - // There may be multiple links to a specific target, so check the target - // hasn't already been fixed (in which case it would be null) - if ( target ) { - target.setAttribute( 'id', prefix + fragment ); - target.setAttribute( 'data-mw-id-fixed', '' ); - } - } - el.setAttribute( 'href', '#' + prefix + fragment ); + if ( targetData.isInternal ) { + var title = mw.Title.newFromText( targetData.title ); + if ( title && title.getPrefixedText() === docTitleText ) { + fragment = new mw.Uri( el.href ).fragment; } - el.removeAttribute( 'target' ); - } } + + if ( fragment !== null ) { + if ( !fragment ) { + // Special case for empty fragment, even if prefix set + el.setAttribute( 'href', '#' ); + } else { + if ( prefix ) { + var target = container.querySelector( '#' + $.escapeSelector( fragment ) ); + // There may be multiple links to a specific target, so check the target + // hasn't already been fixed (in which case it would be null) + if ( target ) { + target.setAttribute( 'id', prefix + fragment ); + target.setAttribute( 'data-mw-id-fixed', '' ); + } + } + el.setAttribute( 'href', '#' + prefix + fragment ); + } + el.removeAttribute( 'target' ); + } } ); // Remove any section heading anchors which weren't fixed above (T218492) Array.prototype.forEach.call( container.querySelectorAll( 'h1, h2, h3, h4, h5, h6' ), function ( el ) { @@ -314,44 +323,6 @@ mw.libs.ve.getTargetDataFromHref = function ( href, doc ) { return data; }; -/** - * Expand a string of the form jquery.foo,bar|jquery.ui.baz,quux to - * an array of module names like [ 'jquery.foo', 'jquery.bar', - * 'jquery.ui.baz', 'jquery.ui.quux' ] - * - * Implementation of ResourceLoaderContext::expandModuleNames - * TODO: Consider upstreaming this to MW core. - * - * @param {string} moduleNames Packed module name list - * @return {string[]} Array of module names - */ -mw.libs.ve.expandModuleNames = function ( moduleNames ) { - var modules = []; - - moduleNames.split( '|' ).forEach( function ( group ) { - if ( group.indexOf( ',' ) === -1 ) { - // This is not a set of modules in foo.bar,baz notation - // but a single module - modules.push( group ); - } else { - // This is a set of modules in foo.bar,baz notation - var matches = group.match( /(.*)\.([^.]*)/ ); - if ( !matches ) { - // Prefixless modules, i.e. without dots - modules = modules.concat( group.split( ',' ) ); - } else { - // We have a prefix and a bunch of suffixes - var prefix = matches[ 1 ]; - var suffixes = matches[ 2 ].split( ',' ); // [ 'bar', 'baz' ] - suffixes.forEach( function ( suffix ) { - modules.push( prefix + '.' + suffix ); - } ); - } - } - } ); - return modules; -}; - /** * Split Parsoid resource name into the href prefix and the page title. * diff --git a/modules/ve-mw/ui/dialogs/ve.ui.MWSaveDialog.js b/modules/ve-mw/ui/dialogs/ve.ui.MWSaveDialog.js index b9acc4e278..91aee49306 100644 --- a/modules/ve-mw/ui/dialogs/ve.ui.MWSaveDialog.js +++ b/modules/ve-mw/ui/dialogs/ve.ui.MWSaveDialog.js @@ -204,107 +204,39 @@ ve.ui.MWSaveDialog.prototype.setDiffAndReview = function ( wikitextDiffPromise, /** * Set preview content and show preview panel. * - * @param {HTMLDocument|jQuery} docOrMsg Document to preview, or error message - * @param {HTMLDocument} [baseDoc] Base document against which to normalise links, if document provided + * @param {Object|jQuery} response action=parse API response, or error message */ -ve.ui.MWSaveDialog.prototype.showPreview = function ( docOrMsg, baseDoc ) { - var dialog = this; - - if ( docOrMsg instanceof HTMLDocument ) { - var modules = []; - // Extract required modules for stylesheet tags (avoids re-loading styles) - Array.prototype.forEach.call( docOrMsg.head.querySelectorAll( 'link[rel~=stylesheet]' ), function ( link ) { - var uri = new mw.Uri( link.href ); - if ( uri.query.modules ) { - modules = modules.concat( mw.libs.ve.expandModuleNames( uri.query.modules ) ); - } - } ); - // Remove skin-specific modules (T187075 / T185284) - modules = modules.filter( function ( module ) { - return !/^(skins|mediawiki\.skinning)\./.test( module ); - } ); - mw.loader.using( modules ); - var body = docOrMsg.body; - var categories = []; - // Take a snapshot of all categories - Array.prototype.forEach.call( body.querySelectorAll( 'link[rel~="mw:PageProp/Category"]' ), function ( element ) { - categories.push( ve.dm.nodeFactory.createFromElement( ve.dm.MWCategoryMetaItem.static.toDataElement( [ element ] ) ) ); - } ); - // Import body to current document, then resolve attributes against original document (parseDocument called #fixBase) - document.adoptNode( body ); - - // TODO: This code is very similar to ve.ui.PreviewElement+ve.ui.MWPreviewElement - ve.resolveAttributes( body, docOrMsg, ve.dm.Converter.static.computedAttributes ); - - // Document title will only be set if wikitext contains {{DISPLAYTITLE}} - if ( docOrMsg.title ) { - // HACK: Parse title as it can contain basic wikitext (T122976) - ve.init.target.getContentApi().post( { - action: 'parse', - title: ve.init.target.getPageName(), - prop: 'displaytitle', - text: '{{DISPLAYTITLE:' + docOrMsg.title + '}}\n' - } ).then( function ( response ) { - if ( ve.getProp( response, 'parse', 'displaytitle' ) ) { - // eslint-disable-next-line no-jquery/no-html - dialog.$previewHeading.html( response.parse.displaytitle ); - } - } ); - } - - // Redirect - var $redirect = $( [] ); - var redirectMeta = body.querySelector( 'link[rel="mw:PageProp/redirect"]' ); - if ( redirectMeta ) { - $redirect = ve.init.mw.ArticleTarget.static.buildRedirectMsg( - mw.libs.ve.getTargetDataFromHref( - redirectMeta.getAttribute( 'href' ), - document - ).title - ); - } - - // TODO: This won't work with formatted titles (T122976) - this.$previewHeading.text( docOrMsg.title || mw.Title.newFromText( ve.init.target.getPageName() ).getPrefixedText() ); +ve.ui.MWSaveDialog.prototype.showPreview = function ( response ) { + if ( response instanceof $ ) { + this.$previewViewer.empty().append( + // eslint-disable-next-line no-jquery/no-append-html + $( '' ).append( response ) + ); + } else { + var data = response.parse; + + mw.config.set( data.jsconfigvars ); + mw.loader.using( ( data.modules || [] ).concat( data.modulestyles || [] ) ); + + // eslint-disable-next-line no-jquery/no-html + this.$previewHeading.html( data.displaytitle ); + // eslint-disable-next-line no-jquery/no-append-html this.$previewViewer.empty().append( - $redirect, // The following classes are used here: // * mw-content-ltr // * mw-content-rtl - // eslint-disable-next-line no-jquery/no-append-html - $( '
' ).addClass( 'mw-content-' + mw.config.get( 'wgVisualEditor' ).pageLanguageDir ).append( - body.childNodes - ) + // eslint-disable-next-line no-jquery/no-html + $( '
' ).addClass( 'mw-content-' + mw.config.get( 'wgVisualEditor' ).pageLanguageDir ).html( + data.text + ), + data.categorieshtml ); ve.targetLinksToNewWindow( this.$previewViewer[ 0 ] ); - // Add styles so links render with their appropriate classes - ve.init.platform.linkCache.styleParsoidElements( this.$previewViewer, baseDoc ); mw.libs.ve.fixFragmentLinks( this.$previewViewer[ 0 ], mw.Title.newFromText( ve.init.target.getPageName() ), 'mw-save-preview-' ); - var deferred; - if ( categories.length ) { - // If there are categories, we need to render them. This involves - // a delay, since they might be hidden categories. - deferred = ve.init.target.renderCategories( categories ).done( function ( $categories ) { - dialog.$previewViewer.append( $categories ); - - ve.targetLinksToNewWindow( $categories[ 0 ] ); - // Add styles so links render with their appropriate classes - ve.init.platform.linkCache.styleParsoidElements( $categories, baseDoc ); - } ); - } else { - deferred = ve.createDeferred().resolve(); - } - deferred.done( function () { - // Run hooks so other things can alter the document - mw.hook( 'wikipage.content' ).fire( dialog.$previewViewer ); - } ); - } else if ( docOrMsg instanceof $ ) { - this.$previewViewer.empty().append( - // eslint-disable-next-line no-jquery/no-append-html - $( '' ).append( docOrMsg ) - ); + // Run hooks so other things can alter the document + mw.hook( 'wikipage.content' ).fire( this.$previewViewer ); } this.popPending();