1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
|
/*!
* VisualEditor UserInterface MWWikitextStringTransferHandler class.
*
* @copyright See AUTHORS.txt
*/
/**
* 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,
'text/x-wiki'
];
ve.ui.MWWikitextStringTransferHandler.static.handlesPaste = true;
ve.ui.MWWikitextStringTransferHandler.static.matchFunction = function ( item ) {
const 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 ( const i in registry.registry ) {
const 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;
};
/**
* Create a new document from HTML from Parsoid
*
* @param {string} html HTML from Parsoid
* @param {ve.dm.Document} targetDoc DM document this will eventually be merged with
* @return {ve.dm.Document} New document
*/
ve.ui.MWWikitextStringTransferHandler.static.createDocumentFromParsoidHtml = function ( html, targetDoc ) {
const htmlDoc = ve.createDocumentFromHtml( html );
// Strip RESTBase IDs
mw.libs.ve.stripRestbaseIds( htmlDoc );
// Strip legacy IDs, for example in section headings
mw.libs.ve.stripParsoidFallbackIds( htmlDoc.body );
// Pass an empty object for the second argument (importRules) so that clipboard mode is used
// TODO: Fix that API
const doc = targetDoc.newFromHtml( htmlDoc, {} );
const data = doc.data.data;
const 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 ( let 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()
)
);
}
}
// Clone elements to avoid about attribute conflicts (T204007)
doc.data.cloneElements( true );
return doc;
};
/* Methods */
/**
* @inheritdoc
*/
ve.ui.MWWikitextStringTransferHandler.prototype.process = function () {
const 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() ) ) {
this.resolve( [
{
type: 'link/mwMagic',
attributes: {
content: wikitext.trim()
}
},
{
type: '/link/mwMagic'
}
] );
return;
}
const failure = () => {
// There's no DTH fallback handling for failures, so just paste
// the raw wikitext if things go wrong.
this.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( ( response ) => {
if ( ve.getProp( response, 'visualeditor', 'result' ) !== 'success' ) {
return failure();
}
const doc = this.constructor.static.createDocumentFromParsoidHtml(
response.visualeditor.content,
this.surface.getModel().getDocument()
);
if ( !doc.data.hasContent() ) {
return failure();
}
this.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 );
|