Cscott has uploaded a new change for review.
https://gerrit.wikimedia.org/r/231145
Change subject: Autolink pasted links.
......................................................................
Autolink pasted links.
Requires I76f7ab81fdf3cafd551b9f04b19e0074a4d4b701 in order to link
text/plain pastes.
Adds a pointer to the original DataTransfer object in each DataTransferItem
so that we can consult additional representations in our DataTransferHandler.
Change-Id: I80bc95e436563f797849ebd0204e04ae0e277308
---
M build/modules.json
M demos/ve/desktop.html
M demos/ve/mobile.html
M src/ce/ve.ce.Surface.js
A src/ui/datatransferhandlers/ve.ui.UrlStringTransferHandler.js
M src/ui/ve.ui.DataTransferItem.js
M tests/ce/ve.ce.Surface.test.js
M tests/index.html
8 files changed, 171 insertions(+), 14 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/VisualEditor/VisualEditor
refs/changes/45/231145/1
diff --git a/build/modules.json b/build/modules.json
index 02718c4..78050c6 100644
--- a/build/modules.json
+++ b/build/modules.json
@@ -426,6 +426,7 @@
"src/ui/datatransferhandlers/ve.ui.DSVFileTransferHandler.js",
"src/ui/datatransferhandlers/ve.ui.PlainTextFileTransferHandler.js",
"src/ui/datatransferhandlers/ve.ui.HTMLFileTransferHandler.js",
+
"src/ui/datatransferhandlers/ve.ui.UrlStringTransferHandler.js",
"src/ui/windowmanagers/ve.ui.ToolbarDialogWindowManager.js",
"src/ui/widgets/ve.ui.AlignWidget.js",
"src/ui/widgets/ve.ui.LanguageSearchWidget.js",
diff --git a/demos/ve/desktop.html b/demos/ve/desktop.html
index 0a6289b..a035aee 100644
--- a/demos/ve/desktop.html
+++ b/demos/ve/desktop.html
@@ -387,6 +387,7 @@
<script
src="../../src/ui/datatransferhandlers/ve.ui.DSVFileTransferHandler.js"></script>
<script
src="../../src/ui/datatransferhandlers/ve.ui.PlainTextFileTransferHandler.js"></script>
<script
src="../../src/ui/datatransferhandlers/ve.ui.HTMLFileTransferHandler.js"></script>
+ <script
src="../../src/ui/datatransferhandlers/ve.ui.UrlStringTransferHandler.js"></script>
<script
src="../../src/ui/windowmanagers/ve.ui.ToolbarDialogWindowManager.js"></script>
<script
src="../../src/ui/widgets/ve.ui.AlignWidget.js"></script>
<script
src="../../src/ui/widgets/ve.ui.LanguageSearchWidget.js"></script>
diff --git a/demos/ve/mobile.html b/demos/ve/mobile.html
index 210d3b4..47eeb5a 100644
--- a/demos/ve/mobile.html
+++ b/demos/ve/mobile.html
@@ -389,6 +389,7 @@
<script
src="../../src/ui/datatransferhandlers/ve.ui.DSVFileTransferHandler.js"></script>
<script
src="../../src/ui/datatransferhandlers/ve.ui.PlainTextFileTransferHandler.js"></script>
<script
src="../../src/ui/datatransferhandlers/ve.ui.HTMLFileTransferHandler.js"></script>
+ <script
src="../../src/ui/datatransferhandlers/ve.ui.UrlStringTransferHandler.js"></script>
<script
src="../../src/ui/windowmanagers/ve.ui.ToolbarDialogWindowManager.js"></script>
<script
src="../../src/ui/widgets/ve.ui.AlignWidget.js"></script>
<script
src="../../src/ui/widgets/ve.ui.LanguageSearchWidget.js"></script>
diff --git a/src/ce/ve.ce.Surface.js b/src/ce/ve.ce.Surface.js
index 7cf42a1..bbee4f3 100644
--- a/src/ce/ve.ce.Surface.js
+++ b/src/ce/ve.ce.Surface.js
@@ -1890,11 +1890,12 @@
*
* @param {jQuery.Event} e Paste event
*/
-ve.ce.Surface.prototype.afterPaste = function () {
+ve.ce.Surface.prototype.afterPaste = function ( e ) {
var clipboardKey, clipboardId, clipboardIndex, clipboardHash, range,
$elements, parts, pasteData, slice, tx, internalListRange,
data, doc, htmlDoc, $images, i,
context, left, right, contextRange,
+ clipboardData = e.originalEvent.clipboardData,
items = [],
importantElement = '[id],[typeof],[rel]',
importRules = !this.pasteSpecial ?
this.getSurface().getImportRules() : { all: { plainText: true } },
@@ -2069,7 +2070,7 @@
$images = $( htmlDoc.body ).find( 'img[src^=data\\:]' );
if ( $images.length ) {
for ( i = 0; i < $images.length; i++ ) {
- items.push(
ve.ui.DataTransferItem.static.newFromDataUri( $images.eq( i ).attr( 'src' ) ) );
+ items.push(
ve.ui.DataTransferItem.static.newFromDataUri( clipboardData, $images.eq( i
).attr( 'src' ) ) );
}
if ( this.handleDataTransferItems( items, true ) ) {
return;
@@ -2180,19 +2181,19 @@
if ( dataTransfer.items ) {
for ( i = 0, l = dataTransfer.items.length; i < l; i++ ) {
if ( dataTransfer.items[i].kind !== 'string' ) {
- items.push(
ve.ui.DataTransferItem.static.newFromItem( dataTransfer.items[i] ) );
+ items.push(
ve.ui.DataTransferItem.static.newFromItem( dataTransfer, dataTransfer.items[i]
) );
}
}
} else if ( dataTransfer.files ) {
for ( i = 0, l = dataTransfer.files.length; i < l; i++ ) {
- items.push( ve.ui.DataTransferItem.static.newFromBlob(
dataTransfer.files[i] ) );
+ items.push( ve.ui.DataTransferItem.static.newFromBlob(
dataTransfer, dataTransfer.files[i] ) );
}
}
for ( i = 0, l = stringTypes.length; i < stringTypes.length; i++ ) {
stringData = dataTransfer.getData( stringTypes[i] );
if ( stringData ) {
- items.push(
ve.ui.DataTransferItem.static.newFromString( stringData, stringTypes[i] ) );
+ items.push(
ve.ui.DataTransferItem.static.newFromString( dataTransfer, stringData,
stringTypes[i] ) );
}
}
diff --git a/src/ui/datatransferhandlers/ve.ui.UrlStringTransferHandler.js
b/src/ui/datatransferhandlers/ve.ui.UrlStringTransferHandler.js
new file mode 100644
index 0000000..f5a4272
--- /dev/null
+++ b/src/ui/datatransferhandlers/ve.ui.UrlStringTransferHandler.js
@@ -0,0 +1,147 @@
+/*!
+ * VisualEditor UserInterface UrlStringTransferHandler class.
+ *
+ * @copyright 2011-2015 VisualEditor Team and others; see
http://ve.mit-license.org
+ */
+
+/**
+ * Handle pastes and drag-and-drop of URLs and links.
+ * Attempts to preserve link titles when possible.
+ *
+ * @class
+ * @extends ve.ui.PlainTextStringTransferHandler
+ *
+ * @constructor
+ * @param {ve.ui.Surface} surface
+ * @param {ve.ui.DataTransferItem} item
+ */
+ve.ui.UrlStringTransferHandler = function VeUiUrlStringTransferHandler() {
+ // Parent constructor
+ ve.ui.UrlStringTransferHandler.super.apply( this, arguments );
+};
+
+/* Inheritance */
+
+OO.inheritClass( ve.ui.UrlStringTransferHandler,
ve.ui.PlainTextStringTransferHandler );
+
+/* Static properties */
+
+ve.ui.UrlStringTransferHandler.static.name = 'urlString';
+
+ve.ui.UrlStringTransferHandler.static.types = [
+ // DnD standard, no title information
+ 'text/uri-list',
+ // Firefox type, preserves title
+ 'text/x-moz-url',
+ // Used in GNOME drag-and-drop
+ 'text/x-uri',
+ // Identify links in pasted plain text as well
+ 'text/plain'
+];
+
+ve.ui.UrlStringTransferHandler.static.handlesPaste = true;
+
+/**
+ * RegExp matching an external url.
+ * @property {RegExp}
+ * @private
+ */
+ve.ui.UrlStringTransferHandler.static.urlRegExp = null; // Initialized below
+
+ve.init.Platform.static.initializedPromise.then( function () {
+ ve.ui.UrlStringTransferHandler.static.urlRegExp =
+ new RegExp(
+
ve.init.platform.getExternalLinkUrlProtocolsRegExp().source +
+ '\\S+$'
+ );
+} );
+
+/* Methods */
+
+ve.ui.UrlStringTransferHandler.static.matchFunction = function ( item ) {
+ // Match all specific mime types
+ if ( ve.ui.UrlStringTransferHandler.static.types.indexOf( item.type )
>= 0 &&
+ item.type !== 'text/plain' ) {
+ return true;
+ }
+
+ // If the type if unspecified or text/plain, then let's check whether it
+ // is a valid URL.
+ return ve.ui.UrlStringTransferHandler.static.urlRegExp.test(
+ item.getAsString()
+ );
+};
+
+/**
+ * @inheritdoc
+ */
+ve.ui.UrlStringTransferHandler.prototype.process = function () {
+ var links,
+ htmldoc,
+ result,
+ surface = this.surface,
+ linkAction = ve.ui.actionFactory.create( 'link', surface ),
+ data = this.item.getAsString();
+
+ switch ( this.item.type ) {
+ case 'text/uri-list':
+ // text/uri-list has embedded comments; remove them before
autolinking.
+ // In theory the embedded comments can be used for link titles,
+ // but I've never seen this done by real apps. You could add
+ // code here to annotate the links with the comment information
+ // if you can find a spec for how it should be done.
+ links = data.replace( /^#.*(\r\n?|\n|$)/mg, '' ).trim()
+ .split( /[\r\n]+/g ).map( function ( line ) {
+ return { href: line, title: line };
+ } );
+
+ // When Google Chrome uses this mime type the link titles can
+ // be extracted from the 'text/html' version of the item.
+ // Let's try that.
+ if ( ve.getProp( this.item.data, 'dataTransfer', 'getData' ) ) {
+ htmldoc = this.item.data.dataTransfer.getData(
'text/html' );
+ if ( htmldoc ) {
+ htmldoc = ve.createDocumentFromHtml( htmldoc );
+ links = $.makeArray( htmldoc.querySelectorAll(
'a[href]' ) )
+ .map( function ( a ) {
+ return { href: a.href, title:
a.textContent };
+ } );
+ }
+ }
+ break;
+ case 'text/x-moz-url':
+ // text/x-moz-url includes titles with the links
+ // Use 'trim' to eliminate trailing newline, if present
+ links = data.match( /^(.*)(\r\n?|\n)(.*)$/mg ).map( function (
item ) {
+ item = item.split( /[\r\n]+/ );
+ return { href: item[0], title: item[1] };
+ } );
+ break;
+ default:
+ // A single URL
+ links = [ { href: data.trim(), title: data } ];
+ break;
+ }
+
+ // Create linked text.
+ result = [];
+ links.forEach( function ( link ) {
+ var i,
+ store = surface.getModel().getDocument().getStore(),
+ annotation = linkAction.getLinkAnnotation( link.href ),
+ annotationSet = new ve.dm.AnnotationSet( store,
store.indexes( [
+ annotation
+ ] ) ),
+ content = link.title.split( '' );
+ ve.dm.Document.static.addAnnotationsToData( content,
annotationSet );
+ for ( i = 0; i < content.length; i++ ) {
+ result.push( content[i] );
+ }
+ result.push( ' ' );
+ } );
+ this.resolve( result );
+};
+
+/* Registration */
+
+ve.ui.dataTransferHandlerFactory.register( ve.ui.UrlStringTransferHandler );
diff --git a/src/ui/ve.ui.DataTransferItem.js b/src/ui/ve.ui.DataTransferItem.js
index 0c85d6e..bccd3c2 100644
--- a/src/ui/ve.ui.DataTransferItem.js
+++ b/src/ui/ve.ui.DataTransferItem.js
@@ -9,6 +9,7 @@
* @param {string} [data.dataUri] Data URI to convert to a blob
* @param {Blob} [data.blob] File blob
* @param {string} [data.stringData] String data
+ * @param {DataTransfer} [data.dataTransfer] Native data transfer object
* @param {DataTransferItem} [data.item] Native data transfer item
* @param {string} [name] Item's name, for types which support it, e.g. File
*/
@@ -30,43 +31,47 @@
/**
* Create a data transfer item from a file blob.
*
+ * @param {DataTransfer} dataTransfer Native data transfer object
* @param {Blob} blob File blob
* @return {ve.ui.DataTransferItem} New data transfer item
*/
-ve.ui.DataTransferItem.static.newFromBlob = function ( blob ) {
- return new ve.ui.DataTransferItem( 'file', blob.type, { blob: blob },
blob.name );
+ve.ui.DataTransferItem.static.newFromBlob = function ( dataTransfer, blob ) {
+ return new ve.ui.DataTransferItem( 'file', blob.type, { dataTransfer:
dataTransfer, blob: blob }, blob.name );
};
/**
* Create a data transfer item from a data URI.
*
+ * @param {DataTransfer} dataTransfer Native data transfer object
* @param {string} dataUri Data URI
* @return {ve.ui.DataTransferItem} New data transfer item
*/
-ve.ui.DataTransferItem.static.newFromDataUri = function ( dataUri ) {
+ve.ui.DataTransferItem.static.newFromDataUri = function ( dataTransfer,
dataUri ) {
var parts = dataUri.split( ',' );
- return new ve.ui.DataTransferItem( 'file', parts[0].match(
/^data:([^;]+)/ )[1], { dataUri: parts[1] } );
+ return new ve.ui.DataTransferItem( 'file', parts[0].match(
/^data:([^;]+)/ )[1], { dataTransfer: dataTransfer, dataUri: parts[1] } );
};
/**
* Create a data transfer item from string data.
*
+ * @param {DataTransfer} dataTransfer Native data transfer object
* @param {string} stringData String data
* @param {string} type MIME type
* @return {ve.ui.DataTransferItem} New data transfer item
*/
-ve.ui.DataTransferItem.static.newFromString = function ( stringData, type ) {
- return new ve.ui.DataTransferItem( 'string', type || 'text/plain', {
stringData: stringData } );
+ve.ui.DataTransferItem.static.newFromString = function ( dataTransfer,
stringData, type ) {
+ return new ve.ui.DataTransferItem( 'string', type || 'text/plain', {
dataTransfer: dataTransfer, stringData: stringData } );
};
/**
* Create a data transfer item from a native data transfer item.
*
+ * @param {DataTransfer} dataTransfer Native data transfer object
* @param {DataTransferItem} item Native data transfer item
* @return {ve.ui.DataTransferItem} New data transfer item
*/
-ve.ui.DataTransferItem.static.newFromItem = function ( item ) {
- return new ve.ui.DataTransferItem( item.kind, item.type, { item: item
}, item.getAsFile().name );
+ve.ui.DataTransferItem.static.newFromItem = function ( dataTransfer, item ) {
+ return new ve.ui.DataTransferItem( item.kind, item.type, {
dataTransfer: dataTransfer, item: item }, item.getAsFile().name );
};
/**
diff --git a/tests/ce/ve.ce.Surface.test.js b/tests/ce/ve.ce.Surface.test.js
index 9bc6460..6ee0aa5 100644
--- a/tests/ce/ve.ce.Surface.test.js
+++ b/tests/ce/ve.ce.Surface.test.js
@@ -1138,7 +1138,7 @@
} else {
document.execCommand( 'insertHTML', false, pasteHtml );
}
- view.afterPaste();
+ view.afterPaste( new TestEvent( e ) );
if ( expectedOps ) {
ops = [];
diff --git a/tests/index.html b/tests/index.html
index bef18fc..875f9fc 100644
--- a/tests/index.html
+++ b/tests/index.html
@@ -316,6 +316,7 @@
<script
src="../src/ui/datatransferhandlers/ve.ui.DSVFileTransferHandler.js"></script>
<script
src="../src/ui/datatransferhandlers/ve.ui.PlainTextFileTransferHandler.js"></script>
<script
src="../src/ui/datatransferhandlers/ve.ui.HTMLFileTransferHandler.js"></script>
+ <script
src="../src/ui/datatransferhandlers/ve.ui.UrlStringTransferHandler.js"></script>
<script
src="../src/ui/windowmanagers/ve.ui.ToolbarDialogWindowManager.js"></script>
<script src="../src/ui/widgets/ve.ui.AlignWidget.js"></script>
<script
src="../src/ui/widgets/ve.ui.LanguageSearchWidget.js"></script>
--
To view, visit https://gerrit.wikimedia.org/r/231145
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I80bc95e436563f797849ebd0204e04ae0e277308
Gerrit-PatchSet: 1
Gerrit-Project: VisualEditor/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Cscott <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits