jenkins-bot has submitted this change and it was merged.
Change subject: Support for generic file drop handlers
......................................................................
Support for generic file drop handlers
Includes PlainTextFileDropHandler as an example implementation.
Change-Id: I1de3363a959d8297f73e650f2cc7fb6feb981d00
---
M .docs/categories.json
M .docs/config.json
M .docs/eg-iframe.html
M build/modules.json
M demos/ve/desktop.html
M demos/ve/mobile.html
M src/ce/ve.ce.Surface.js
A src/ui/ve.ui.FileDropHandler.js
A src/ui/ve.ui.FileDropHandlerFactory.js
A src/ui/ve.ui.PlainTextFileDropHandler.js
M src/ui/ve.ui.js
M tests/index.html
12 files changed, 257 insertions(+), 3 deletions(-)
Approvals:
Trevor Parscal: Looks good to me, approved
jenkins-bot: Verified
diff --git a/.docs/categories.json b/.docs/categories.json
index d7b835f..b9764a1 100644
--- a/.docs/categories.json
+++ b/.docs/categories.json
@@ -124,7 +124,8 @@
"ve.ui.DebugBar",
"ve.ui.Action",
"ve.ui.Trigger",
- "ve.ui.Command"
+ "ve.ui.Command",
+ "ve.ui.*FileDropHandler"
]
},
{
diff --git a/.docs/config.json b/.docs/config.json
index dbcc1ea..335c1af 100644
--- a/.docs/config.json
+++ b/.docs/config.json
@@ -6,7 +6,7 @@
"--warnings": ["-nodoc(class,public)"],
"--builtin-classes": true,
"--warnings-exit-nonzero": true,
- "--external": "HTMLDocument,Window,Node,Set,Range,Selection,ClientRect",
+ "--external":
"HTMLDocument,Window,Node,Set,Range,Selection,ClientRect,File",
"--output": "../docs",
"--": [
"./external.js",
diff --git a/.docs/eg-iframe.html b/.docs/eg-iframe.html
index 9551cf5..6d489de 100644
--- a/.docs/eg-iframe.html
+++ b/.docs/eg-iframe.html
@@ -282,6 +282,9 @@
<script src="../src/ui/ve.ui.Action.js"></script>
<script src="../src/ui/ve.ui.ActionFactory.js"></script>
<script src="../src/ui/ve.ui.WindowManager.js"></script>
+ <script
src="../src/ui/ve.ui.FileDropHandlerFactory.js"></script>
+ <script src="../src/ui/ve.ui.FileDropHandler.js"></script>
+ <script
src="../src/ui/ve.ui.PlainTextFileDropHandler.js"></script>
<script
src="../src/ui/actions/ve.ui.AnnotationAction.js"></script>
<script src="../src/ui/actions/ve.ui.ContentAction.js"></script>
<script src="../src/ui/actions/ve.ui.FormatAction.js"></script>
diff --git a/build/modules.json b/build/modules.json
index ac78df2..4aeffb9 100644
--- a/build/modules.json
+++ b/build/modules.json
@@ -306,6 +306,9 @@
"src/ui/ve.ui.Action.js",
"src/ui/ve.ui.ActionFactory.js",
"src/ui/ve.ui.WindowManager.js",
+ "src/ui/ve.ui.FileDropHandlerFactory.js",
+ "src/ui/ve.ui.FileDropHandler.js",
+ "src/ui/ve.ui.PlainTextFileDropHandler.js",
"src/ui/actions/ve.ui.AnnotationAction.js",
"src/ui/actions/ve.ui.ContentAction.js",
"src/ui/actions/ve.ui.FormatAction.js",
diff --git a/demos/ve/desktop.html b/demos/ve/desktop.html
index 341a701..8d38ad2 100644
--- a/demos/ve/desktop.html
+++ b/demos/ve/desktop.html
@@ -295,6 +295,9 @@
<script src="../../src/ui/ve.ui.Action.js"></script>
<script src="../../src/ui/ve.ui.ActionFactory.js"></script>
<script src="../../src/ui/ve.ui.WindowManager.js"></script>
+ <script
src="../../src/ui/ve.ui.FileDropHandlerFactory.js"></script>
+ <script src="../../src/ui/ve.ui.FileDropHandler.js"></script>
+ <script
src="../../src/ui/ve.ui.PlainTextFileDropHandler.js"></script>
<script
src="../../src/ui/actions/ve.ui.AnnotationAction.js"></script>
<script
src="../../src/ui/actions/ve.ui.ContentAction.js"></script>
<script
src="../../src/ui/actions/ve.ui.FormatAction.js"></script>
diff --git a/demos/ve/mobile.html b/demos/ve/mobile.html
index a829446..d8cedce 100644
--- a/demos/ve/mobile.html
+++ b/demos/ve/mobile.html
@@ -296,6 +296,9 @@
<script src="../../src/ui/ve.ui.Action.js"></script>
<script src="../../src/ui/ve.ui.ActionFactory.js"></script>
<script src="../../src/ui/ve.ui.WindowManager.js"></script>
+ <script
src="../../src/ui/ve.ui.FileDropHandlerFactory.js"></script>
+ <script src="../../src/ui/ve.ui.FileDropHandler.js"></script>
+ <script
src="../../src/ui/ve.ui.PlainTextFileDropHandler.js"></script>
<script
src="../../src/ui/actions/ve.ui.AnnotationAction.js"></script>
<script
src="../../src/ui/actions/ve.ui.ContentAction.js"></script>
<script
src="../../src/ui/actions/ve.ui.FormatAction.js"></script>
diff --git a/src/ce/ve.ce.Surface.js b/src/ce/ve.ce.Surface.js
index dfd7b40..0e346cb 100644
--- a/src/ce/ve.ce.Surface.js
+++ b/src/ce/ve.ce.Surface.js
@@ -888,6 +888,8 @@
var selectionJSON, dragSelection, dragRange, originFragment, originData,
targetRange, targetOffset, targetFragment, dragHtml, dragText,
htmlDoc, doc, data, pasteRules,
+ i, l, name, insert,
+ fileHandlers = [],
dataTransfer = e.originalEvent.dataTransfer,
$dropTarget = this.$lastDropTarget,
dropPosition = this.lastDropPosition;
@@ -913,6 +915,15 @@
if ( dragSelection instanceof ve.dm.LinearSelection ) {
dragRange = dragSelection.getRange();
}
+ } else if ( dataTransfer.files.length ) {
+ for ( i = 0, l = dataTransfer.files.length; i < l; i++ ) {
+ name =
ve.ui.fileDropHandlerFactory.getHandlerNameForType( dataTransfer.files[i].type
);
+ if ( name ) {
+ fileHandlers.push(
+ ve.ui.fileDropHandlerFactory.create(
name, this.surface, dataTransfer.files[i] )
+ );
+ }
+ }
} else {
try {
dragHtml = dataTransfer.getData( 'text/html' );
@@ -924,7 +935,7 @@
}
}
- if ( ( dragRange && !dragRange.isCollapsed() ) || dragHtml || dragText
) {
+ if ( ( dragRange && !dragRange.isCollapsed() ) || fileHandlers.length
|| dragHtml || dragText ) {
if ( this.relocatingNode &&
!this.relocatingNode.getModel().isContent() ) {
// Block level drag and drop: use the lastDropTarget to
get the targetOffset
if ( $dropTarget ) {
@@ -959,6 +970,13 @@
// Re-insert data at new location
targetFragment.insertContent( originData );
+ } else if ( fileHandlers.length ) {
+ insert = function ( data ) {
+ targetFragment.collapseToEnd().insertContent(
data );
+ };
+ for ( i = 0, l = fileHandlers.length; i < l; i++ ) {
+ fileHandlers[i].getInsertableData().done(
insert );
+ }
} else if ( dragHtml ) {
pasteRules = this.getSurface().getPasteRules();
htmlDoc = ve.createDocumentFromHtml( dragHtml );
diff --git a/src/ui/ve.ui.FileDropHandler.js b/src/ui/ve.ui.FileDropHandler.js
new file mode 100644
index 0000000..4da35cf
--- /dev/null
+++ b/src/ui/ve.ui.FileDropHandler.js
@@ -0,0 +1,97 @@
+/*!
+ * VisualEditor UserInterface file drop handler class.
+ *
+ * @copyright 2011-2014 VisualEditor Team and others; see
http://ve.mit-license.org
+ */
+
+/**
+ * File drop handler.
+ *
+ * @class
+ * @abstract
+ *
+ * @constructor
+ * @param {ve.ui.Surface} surface Surface
+ * @param {File} file File to handle
+ */
+ve.ui.FileDropHandler = function VeUiFileDropHandler( surface, file ) {
+ // Properties
+ this.surface = surface;
+ this.file = file;
+
+ this.insertableDataDeferred = $.Deferred();
+
+ this.reader = new FileReader();
+
+ // Events
+ this.reader.addEventListener( 'progress', this.onFileProgress.bind(
this ) );
+ this.reader.addEventListener( 'load', this.onFileLoad.bind( this ) );
+ this.reader.addEventListener( 'loadend', this.onFileLoadEnd.bind( this
) );
+};
+
+/* Inheritance */
+
+OO.initClass( ve.ui.FileDropHandler );
+
+/* Static properties */
+
+/**
+ * Symbolic name for this handler. Must be unique.
+ *
+ * @static
+ * @property {string}
+ * @inheritable
+ */
+ve.ui.FileDropHandler.static.name = null;
+
+/**
+ * List of mime types supported by this handler
+ *
+ * @static
+ * @property {string[]}
+ * @inheritable
+ */
+ve.ui.FileDropHandler.static.types = [];
+
+/* Methods */
+
+/**
+ * Process the file
+ *
+ * Implementations should aim to resolve this.insertableDataDeferred.
+ */
+ve.ui.FileDropHandler.prototype.process = function () {
+ throw new Error( 've.ui.FileDropHandler subclass must implement
process' );
+};
+
+/**
+ * Insert the file at a specified fragment
+ *
+ * @return {jQuery.Promise} Promise which resolves with data to insert
+ */
+ve.ui.FileDropHandler.prototype.getInsertableData = function () {
+ this.process();
+
+ return this.insertableDataDeferred.promise();
+};
+
+/**
+ * Handle progress events from the file reader
+ *
+ * @param {Event} e Progress event
+ */
+ve.ui.FileDropHandler.prototype.onFileProgress = function () {};
+
+/**
+ * Handle load events from the file reader
+ *
+ * @param {Event} e Load event
+ */
+ve.ui.FileDropHandler.prototype.onFileLoad = function () {};
+
+/**
+ * Handle load end events from the file reader
+ *
+ * @param {Event} e Load end event
+ */
+ve.ui.FileDropHandler.prototype.onFileLoadEnd = function () {};
diff --git a/src/ui/ve.ui.FileDropHandlerFactory.js
b/src/ui/ve.ui.FileDropHandlerFactory.js
new file mode 100644
index 0000000..2005505
--- /dev/null
+++ b/src/ui/ve.ui.FileDropHandlerFactory.js
@@ -0,0 +1,52 @@
+/*!
+ * VisualEditor FileDropHandlerFactory class.
+ *
+ * @copyright 2011-2014 VisualEditor Team and others; see
http://ve.mit-license.org
+ */
+
+/**
+ * Drop handler Factory.
+ *
+ * @class
+ * @extends OO.Factory
+ * @constructor
+ */
+ve.ui.FileDropHandlerFactory = function VeUiFileDropHandlerFactory() {
+ // Parent constructor
+ ve.ui.FileDropHandlerFactory.super.apply( this, arguments );
+
+ this.handlerNamesByType = {};
+};
+
+/* Inheritance */
+
+OO.inheritClass( ve.ui.FileDropHandlerFactory, OO.Factory );
+
+/* Methods */
+
+/**
+ * @inheritdoc
+ */
+ve.ui.FileDropHandlerFactory.prototype.register = function ( constructor ) {
+ // Parent method
+ ve.ui.FileDropHandlerFactory.super.prototype.register.call( this,
constructor );
+
+ var i, l, types = constructor.static.types;
+ for ( i = 0, l = types.length; i < l; i++ ) {
+ this.handlerNamesByType[types[i]] = constructor.static.name;
+ }
+};
+
+/**
+ * Returns the primary command for for node.
+ *
+ * @param {string} type File type
+ * @returns {string|undefined} Handler name, or undefined if not found
+ */
+ve.ui.FileDropHandlerFactory.prototype.getHandlerNameForType = function ( type
) {
+ return this.handlerNamesByType[type];
+};
+
+/* Initialization */
+
+ve.ui.fileDropHandlerFactory = new ve.ui.FileDropHandlerFactory();
diff --git a/src/ui/ve.ui.PlainTextFileDropHandler.js
b/src/ui/ve.ui.PlainTextFileDropHandler.js
new file mode 100644
index 0000000..64f298b
--- /dev/null
+++ b/src/ui/ve.ui.PlainTextFileDropHandler.js
@@ -0,0 +1,70 @@
+/*!
+ * VisualEditor UserInterface plain text file drop handler class.
+ *
+ * @copyright 2011-2014 VisualEditor Team and others; see
http://ve.mit-license.org
+ */
+
+/**
+ * Plain text file drop handler.
+ *
+ * @class
+ * @extends ve.ui.FileDropHandler
+ *
+ * @constructor
+ * @param {ve.ui.Surface} surface
+ * @param {File} file
+ */
+ve.ui.PlainTextFileDropHandler = function VeUiPlainTextFileDropHandler() {
+ // Parent constructor
+ ve.ui.PlainTextFileDropHandler.super.apply( this, arguments );
+};
+
+/* Inheritance */
+
+OO.inheritClass( ve.ui.PlainTextFileDropHandler, ve.ui.FileDropHandler );
+
+/* Static properties */
+
+ve.ui.PlainTextFileDropHandler.static.name = 'plainText';
+
+ve.ui.PlainTextFileDropHandler.static.types = ['text/plain'];
+
+/* Methods */
+
+/**
+ * @inheritdoc
+ */
+ve.ui.PlainTextFileDropHandler.prototype.process = function () {
+ this.reader.readAsText( this.file );
+};
+
+/**
+ * @inheritdoc
+ */
+ve.ui.PlainTextFileDropHandler.prototype.onFileLoad = function () {
+ var i, l,
+ data = [],
+ lines = this.reader.result.split( /[\r\n]+/ );
+
+ for ( i = 0, l = lines.length; i < l; i++ ) {
+ if ( lines[i].length ) {
+ data.push( { type: 'paragraph' } );
+ data = data.concat( lines[i].split( '' ) );
+ data.push( { type: '/paragraph' } );
+ }
+ }
+ this.insertableDataDeferred.resolve( data );
+};
+
+/**
+ * @inheritdoc
+ */
+ve.ui.PlainTextFileDropHandler.prototype.onFileLoadEnd = function () {
+ // 'loadend' fires after 'load'/'abort'/'error'.
+ // Reject the deferred if it hasn't already resolved.
+ this.insertableDataDeferred.reject();
+};
+
+/* Registration */
+
+ve.ui.fileDropHandlerFactory.register( ve.ui.PlainTextFileDropHandler );
diff --git a/src/ui/ve.ui.js b/src/ui/ve.ui.js
index 9e79453..f89b6b2 100644
--- a/src/ui/ve.ui.js
+++ b/src/ui/ve.ui.js
@@ -15,6 +15,7 @@
//'commandRegistry' instantiated in ve.ui.CommandRegistry.js
//'triggerRegistry' instantiated in ve.ui.TriggerRegistry.js
//'toolFactory' instantiated in ve.ui.ToolFactory.js
+ //'fileDropHandlerFactory' instantiated in
ve.ui.FileDropHandlerFactory.js
windowFactory: new OO.Factory()
};
diff --git a/tests/index.html b/tests/index.html
index 6491934..23e4d74 100644
--- a/tests/index.html
+++ b/tests/index.html
@@ -246,6 +246,9 @@
<script src="../src/ui/ve.ui.Action.js"></script>
<script src="../src/ui/ve.ui.ActionFactory.js"></script>
<script src="../src/ui/ve.ui.WindowManager.js"></script>
+ <script
src="../src/ui/ve.ui.FileDropHandlerFactory.js"></script>
+ <script src="../src/ui/ve.ui.FileDropHandler.js"></script>
+ <script
src="../src/ui/ve.ui.PlainTextFileDropHandler.js"></script>
<script
src="../src/ui/actions/ve.ui.AnnotationAction.js"></script>
<script src="../src/ui/actions/ve.ui.ContentAction.js"></script>
<script src="../src/ui/actions/ve.ui.FormatAction.js"></script>
--
To view, visit https://gerrit.wikimedia.org/r/170907
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I1de3363a959d8297f73e650f2cc7fb6feb981d00
Gerrit-PatchSet: 9
Gerrit-Project: VisualEditor/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Esanders <[email protected]>
Gerrit-Reviewer: Esanders <[email protected]>
Gerrit-Reviewer: Trevor Parscal <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits