mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-30 00:55:00 +00:00
16211cdc09
Change-Id: Id0be3207219a6d93cebff2b6b5061cd24898d5cb
186 lines
5.3 KiB
JavaScript
186 lines
5.3 KiB
JavaScript
/*!
|
|
* VisualEditor UserInterface MWWikitextStringTransferHandler class.
|
|
*
|
|
* @copyright 2011-2018 VisualEditor Team and others; see http://ve.mit-license.org
|
|
*/
|
|
|
|
/**
|
|
* Detect an attempt to paste wikitext, and convert it to proper
|
|
* HTML.
|
|
*
|
|
* @class
|
|
* @extends ve.ui.PlainTextStringTransferHandler
|
|
*
|
|
* @constructor
|
|
* @param {ve.ui.Surface} surface
|
|
* @param {ve.ui.DataTransferItem} item
|
|
*/
|
|
ve.ui.MWWikitextStringTransferHandler = function VeUiMWWikitextStringTransferHandler() {
|
|
// Parent constructor
|
|
ve.ui.MWWikitextStringTransferHandler.super.apply( this, arguments );
|
|
|
|
// Properties
|
|
this.parsoidRequest = null;
|
|
};
|
|
|
|
/* Inheritance */
|
|
|
|
OO.inheritClass( ve.ui.MWWikitextStringTransferHandler, ve.ui.PlainTextStringTransferHandler );
|
|
|
|
/* Static properties */
|
|
|
|
ve.ui.MWWikitextStringTransferHandler.static.name = 'wikitextString';
|
|
|
|
ve.ui.MWWikitextStringTransferHandler.static.types =
|
|
ve.ui.MWWikitextStringTransferHandler.super.static.types.concat(
|
|
[ 'text/x-wiki' ]
|
|
);
|
|
|
|
ve.ui.MWWikitextStringTransferHandler.static.handlesPaste = true;
|
|
|
|
ve.ui.MWWikitextStringTransferHandler.static.matchFunction = function ( item ) {
|
|
var i, rule,
|
|
text = item.getAsString(),
|
|
registry = ve.ui.mwWikitextTransferRegistry;
|
|
|
|
// If the mime type is explicitly wikitext (ie, not plain text),
|
|
// always accept.
|
|
if ( item.type === 'text/x-wiki' ) {
|
|
return true;
|
|
}
|
|
|
|
// Detect autolink opportunities for magic words.
|
|
// (The link should be the only contents of paste to match this heuristic)
|
|
if ( ve.dm.MWMagicLinkNode.static.validateContent( text.trim() ) ) {
|
|
return true;
|
|
}
|
|
|
|
// Use a heuristic regexp to find text likely to be wikitext.
|
|
// This test could be made more sophisticated in the future.
|
|
for ( i in registry.registry ) {
|
|
rule = registry.registry[ i ];
|
|
if ( rule instanceof RegExp ) {
|
|
if ( registry.registry[ i ].test( text ) ) {
|
|
return true;
|
|
}
|
|
} else if ( text.indexOf( rule ) !== -1 ) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
/* Methods */
|
|
|
|
/**
|
|
* @inheritdoc
|
|
*/
|
|
ve.ui.MWWikitextStringTransferHandler.prototype.process = function () {
|
|
var i, data,
|
|
handler = this,
|
|
wikitext = this.item.getAsString();
|
|
|
|
// We already know how to handle wikitext magic links, no need for the API call
|
|
if ( ve.dm.MWMagicLinkNode.static.validateContent( wikitext.trim() ) ) {
|
|
handler.resolve( [
|
|
{
|
|
type: 'link/mwMagic',
|
|
attributes: {
|
|
content: wikitext.trim()
|
|
}
|
|
},
|
|
{
|
|
type: '/link/mwMagic'
|
|
}
|
|
] );
|
|
return;
|
|
}
|
|
|
|
function failure() {
|
|
// There's no DTH fallback handling for failures, so just paste
|
|
// the raw wikitext if things go wrong.
|
|
handler.resolve( wikitext );
|
|
}
|
|
|
|
// Convert wikitext to html using Parsoid.
|
|
this.parsoidRequest = ve.init.target.parseWikitextFragment( wikitext, false, this.surface.getModel().getDocument() );
|
|
|
|
// Don't immediately chain, as this.parsoidRequest must be abortable
|
|
this.parsoidRequest.then( function ( response ) {
|
|
var htmlDoc, doc, surface, elementsWithIds, len;
|
|
|
|
if ( ve.getProp( response, 'visualeditor', 'result' ) !== 'success' ) {
|
|
return failure();
|
|
}
|
|
|
|
htmlDoc = ve.createDocumentFromHtml( response.visualeditor.content );
|
|
|
|
// Strip RESTBase IDs
|
|
elementsWithIds = htmlDoc.querySelectorAll( '[id]' );
|
|
for ( i = 0, len = elementsWithIds.length; i < len; i++ ) {
|
|
if ( elementsWithIds[ i ].getAttribute( 'id' ).match( ve.init.platform.getMetadataIdRegExp() ) ) {
|
|
elementsWithIds[ i ].removeAttribute( 'id' );
|
|
}
|
|
}
|
|
|
|
// Strip legacy IDs, for example in section headings
|
|
ve.stripParsoidFallbackIds( htmlDoc.body );
|
|
|
|
// Pass an empty object for the second argument (importRules) so that clipboard mode is used
|
|
// TODO: Fix that API
|
|
doc = handler.surface.getModel().getDocument().newFromHtml( htmlDoc, {} );
|
|
data = doc.data.data;
|
|
surface = new ve.dm.Surface( doc );
|
|
|
|
// Filter out auto-generated items, e.g. reference lists
|
|
// This is done after conversion as the autoGenerated item may contain data
|
|
// required by other non-autoGenerated items, e.g. reference contents
|
|
for ( i = data.length - 1; i >= 0; i-- ) {
|
|
if ( ve.getProp( data[ i ], 'attributes', 'mw', 'autoGenerated' ) ) {
|
|
surface.change(
|
|
ve.dm.TransactionBuilder.static.newFromRemoval(
|
|
doc,
|
|
surface.getDocument().getDocumentNode().getNodeFromOffset( i + 1 ).getOuterRange()
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
if ( !doc.data.hasContent() ) {
|
|
return failure();
|
|
}
|
|
|
|
// Attempt to undo outermost p-wrapping if possible
|
|
try {
|
|
surface.change(
|
|
ve.dm.TransactionBuilder.static.newFromWrap( doc, new ve.Range( 0, doc.data.countNonInternalElements() ), [], [], [ { type: 'paragraph' } ], [] )
|
|
);
|
|
} catch ( e ) {
|
|
// Sometimes there is no p-wrapping, for example: "* foo"
|
|
// Sometimes there are multiple <p> tags in the output.
|
|
// That's okay: ignore the error and paste what we've got.
|
|
}
|
|
handler.resolve( doc );
|
|
}, failure );
|
|
|
|
this.createProgress( this.parsoidRequest, ve.msg( 'visualeditor-wikitext-progress' ) );
|
|
// Indeterminate progress
|
|
this.setProgress( null );
|
|
};
|
|
|
|
/**
|
|
* @inheritdoc
|
|
*/
|
|
ve.ui.MWWikitextStringTransferHandler.prototype.abort = function () {
|
|
// Parent method
|
|
ve.ui.MWWikitextStringTransferHandler.super.prototype.abort.apply( this, arguments );
|
|
|
|
if ( this.parsoidRequest ) {
|
|
this.parsoidRequest.abort();
|
|
}
|
|
};
|
|
|
|
/* Registration */
|
|
|
|
ve.ui.dataTransferHandlerFactory.register( ve.ui.MWWikitextStringTransferHandler );
|