Bläddra i källkod

Add support for pasting data into compose area (#84)

Fixes #82
Danilo Bargen 8 år sedan
förälder
incheckning
9d68df25e9
1 ändrade filer med 77 tillägg och 11 borttagningar
  1. 77 11
      src/directives/compose_area.ts

+ 77 - 11
src/directives/compose_area.ts

@@ -39,11 +39,18 @@ export default [
         return {
             restrict: 'EA',
             scope: {
+                // Callback to submit text or file data
                 submit: '=',
+
+                // Callbacks to update typing information
                 startTyping: '=',
                 stopTyping: '=',
                 onTyping: '=',
+
+                // Reference to drafts variable
                 draft: '=',
+
+                // Callback that is called when uploading files
                 onUploading: '=',
                 maxTextLength: '=',
             },
@@ -279,22 +286,81 @@ export default [
                 // Handle pasting
                 function onPaste(ev: ClipboardEvent) {
                     ev.preventDefault();
-                    const text = ev.clipboardData.getData('text/plain');
 
-                    // Apply filters (emojify, convert newline, etc)
-                    const formatted = applyFilters(text);
+                    // If no clipboard data is available, do nothing.
+                    if (!ev.clipboardData) {
+                        return;
+                    }
 
-                    // Replace HTML formatting with ASCII counterparts
-                    const htmlToAsciiMarkup = $filter('htmlToAsciiMarkup') as (a: string) => string;
+                    // Extract pasted items
+                    const items: DataTransferItemList = ev.clipboardData.items;
+                    if (!items) {
+                        return;
+                    }
 
-                    // Sanitize
-                    const sanitized = $sanitize(htmlToAsciiMarkup(formatted));
+                    // Find available types
+                    let fileIdx: number | null = null;
+                    let textIdx: number | null = null;
+                    for (let i = 0; i < items.length; i++) {
+                        if (items[i].type.indexOf('image/') !== -1 || items[i].type === 'application/x-moz-file') {
+                            fileIdx = i;
+                        } else if (items[i].type === 'text/plain') {
+                            textIdx = i;
+                        }
+                    }
 
-                    // Insert HTML
-                    document.execCommand('insertHTML', false, sanitized);
+                    // Handle pasting of files
+                    if (fileIdx !== null) {
+                        // Read clipboard data as blob
+                        const blob: Blob = items[fileIdx].getAsFile();
+
+                        // Convert blob to arraybuffer
+                        const reader = new FileReader();
+                        reader.onload = function() {
+                            let buffer: ArrayBuffer = this.result;
+
+                            // Construct file name
+                            let fileName: string;
+                            if ((blob as any).name) {
+                                fileName = (blob as any).name;
+                            } else if (blob.type && blob.type.match(/^[^;]*\//) !== null) {
+                                const fileExt = blob.type.split(';')[0].split('/')[1];
+                                fileName = 'clipboard.' + fileExt;
+                            } else {
+                                $log.warn(logTag, 'Pasted file has an invalid MIME type: "' + blob.type + '"');
+                                return;
+                            }
 
-                    cleanupComposeContent();
-                    updateView();
+                            // Send data as file
+                            const fileMessageData: threema.FileMessageData = {
+                                name: fileName,
+                                fileType: blob.type,
+                                size: blob.size,
+                                data: buffer,
+                            };
+                            scope.submit('file', [fileMessageData]);
+                        };
+                        reader.readAsArrayBuffer(blob);
+
+                    // Handle pasting of text
+                    } else if (textIdx !== null) {
+                        const text = ev.clipboardData.getData('text/plain');
+
+                        // Apply filters (emojify, convert newline, etc)
+                        const formatted = applyFilters(text);
+
+                        // Replace HTML formatting with ASCII counterparts
+                        const htmlToAsciiMarkup = $filter('htmlToAsciiMarkup') as (a: string) => string;
+
+                        // Sanitize
+                        const sanitized = $sanitize(htmlToAsciiMarkup(formatted));
+
+                        // Insert HTML
+                        document.execCommand('insertHTML', false, sanitized);
+
+                        cleanupComposeContent();
+                        updateView();
+                    }
                 }
 
                 // Translate placeholder texts