Просмотр исходного кода

Implement "copy to clipboard" functionality

Danilo Bargen 7 лет назад
Родитель
Сommit
4c3260cb2f

+ 1 - 1
src/directives/message.html

@@ -12,7 +12,7 @@
             ui-sref="messenger.home.conversation({ type: 'contact', id: ctrl.contact.id, initParams: null })"></eee-avatar>
 
     <div class="bubble-triangle"></div>
-    <section class="message-body" ng-class="ctrl.message.type + '-message-body'">
+    <section class="message-body {{ ctrl.message.type + '-message-body' }}">
         <eee-message-contact
             ng-if="ctrl.showName"
             class="message-name"

+ 23 - 2
src/directives/message.ts

@@ -103,8 +103,29 @@ export default [
                     }, () => { /* do nothing */});
                 };
 
-                this.copy = (ev) => {
-                    $log.debug('TODO implement copy');
+                this.copyToClipboard = (ev: MouseEvent) => {
+                    // Get copyable text
+                    const text = messageService.getQuoteText(this.message);
+                    if (text === null) {
+                        return;
+                    }
+
+                    // In order to copy the text to the clipboard,
+                    // put it into a temporary textarea element.
+                    const textArea = document.createElement('textarea');
+                    textArea.value = text;
+                    document.body.appendChild(textArea);
+                    textArea.focus();
+                    textArea.select();
+                    try {
+                        const successful = document.execCommand('copy');
+                        if (!successful) {
+                            $log.warn('Could not copy text to clipboard');
+                        }
+                    } catch (err) {
+                        $log.warn('Could not copy text to clipboard:', err);
+                    }
+                    document.body.removeChild(textArea);
                 };
 
                 this.download = (ev) => {

+ 1 - 1
src/directives/message_menu.html

@@ -29,7 +29,7 @@
             </md-button>
         </md-menu-item>
         <md-menu-item ng-if="ctrl.access.copy">
-            <md-button ng-click="ctrl.copy($event)">
+            <md-button ng-click="ctrl.copyToClipboard($event)">
                 <md-icon aria-label="Copy" class="material-icons md-24">content_copy</md-icon>
                 <span translate>messenger.COPY</span>
             </md-button>

+ 45 - 21
src/services/message.ts

@@ -40,35 +40,59 @@ export class MessageService {
     public getAccess(message: threema.Message, receiver: threema.Receiver): MessageAccess  {
         const access = new MessageAccess();
 
-        if (message !== undefined && receiver !== undefined && message.temporaryId === undefined) {
-            access.quote =  (message.type === 'text')
-                || (message.type === 'location')
-                || (message.caption !== undefined);
-            // disable copy for current version
-            // access.copy = access.quote;
-
-            if (message !== undefined
-                && message.isOutbox === false
-                && this.receiverService.isContact(receiver)
-                && message.type !== 'voipStatus') {
-                access.ack = message.state !== 'user-ack';
-                access.dec = message.state !== 'user-dec';
+        if (message !== undefined) {
+            access.quote = (message.type === 'text')
+                        || (message.type === 'location')
+                        || (message.caption !== undefined);
+            access.copy = access.quote;
+
+            if (receiver !== undefined && message.temporaryId === undefined) {
+                if (message.isOutbox === false
+                    && this.receiverService.isContact(receiver)
+                    && message.type !== 'voipStatus') {
+                    access.ack = message.state !== 'user-ack';
+                    access.dec = message.state !== 'user-dec';
+                }
+
+                switch (message.type) {
+                    case 'image':
+                    case 'video':
+                    case 'audio':
+                    case 'file':
+                        access.download = true;
+                        break;
+                    default:
+                        access.download = false;
+                }
+                access.delete = true;
             }
+        }
+
+        return access;
+    }
 
+    /**
+     * Return the quotable text in this message, or null.
+     */
+    public getQuoteText(message: threema.Message): string | null {
+        let quoteText = null;
+        if (message !== null && message !== undefined) {
             switch (message.type) {
-                case 'image':
-                case 'video':
-                case 'audio':
+                case 'text':
+                    quoteText = message.body;
+                    break;
+                case 'location':
+                    quoteText = message.location.description;
+                    break;
                 case 'file':
-                    access.download = true;
+                case 'image':
+                    quoteText = message.caption;
                     break;
                 default:
-                    access.download = false;
+                    // Ignore (handled below)
             }
-            access.delete = true;
         }
-
-        return access;
+        return quoteText;
     }
 
     public showStatusIcon(message: threema.Message, receiver: threema.Receiver): boolean {

+ 2 - 16
src/services/webclient.ts

@@ -1559,23 +1559,9 @@ export class WebClientService {
         this.drafts.removeQuote(receiver);
 
         if (message !== null) {
-            let quoteText;
-            switch (message.type) {
-                case 'text':
-                    quoteText = message.body;
-                    break;
-                case 'location':
-                    quoteText = message.location.description;
-                    break;
-                case 'file':
-                case 'image':
-                    quoteText = message.caption;
-                    break;
-                default:
-                    // Ignore (handled below)
-            }
+            const quoteText = this.messageService.getQuoteText(message);
 
-            if (quoteText !== undefined) {
+            if (quoteText !== undefined && quoteText !== null) {
                 const quote = {
                     identity: message.isOutbox ? this.me.id : message.partnerId,
                     text: quoteText,

+ 13 - 13
tests/service/message.js

@@ -24,11 +24,11 @@ describe('MessageService', function() {
         it('invalid arguments', () => {
             test().toEqual(jasmine.objectContaining({
                 quote: false,
+                copy: false,
                 ack: false,
                 dec: false,
                 delete: false,
                 download: false,
-                copy: false,
             }));
         })
 
@@ -48,42 +48,42 @@ describe('MessageService', function() {
                     test({isOutbox: false, type: 'text'}, receiver)
                         .toEqual(jasmine.objectContaining({
                             quote: true,
+                            copy: true,
                             ack: true && canAckDec,
                             dec: true && canAckDec,
                             delete: true,
                             download: false,
-                            copy: false,
                         }));
 
                     test({isOutbox: true, type: 'text'}, receiver)
                         .toEqual(jasmine.objectContaining({
                             quote: true,
+                            copy: true,
                             ack: false,
                             dec: false,
                             delete: true,
                             download: false,
-                            copy: false,
                         }));
 
                     test({isOutbox: false, type: 'text', state: 'user-ack'}, receiver)
                         .toEqual(jasmine.objectContaining({
                             quote: true,
+                            copy: true,
                             ack: false,
                             dec: true && canAckDec,
                             delete: true,
                             download: false,
-                            copy: false,
                         }));
 
 
                     test({isOutbox: false, type: 'text', state: 'user-dec'}, receiver)
                         .toEqual(jasmine.objectContaining({
                             quote: true,
+                            copy: true,
                             ack: true && canAckDec,
                             dec: false,
                             delete: true,
                             download: false,
-                            copy: false,
                         }));
                 });
 
@@ -91,42 +91,42 @@ describe('MessageService', function() {
                     test({isOutbox: false, type: 'text'}, receiver)
                         .toEqual(jasmine.objectContaining({
                             quote: true,
+                            copy: true,
                             ack: true && canAckDec,
                             dec: true && canAckDec,
                             delete: true,
                             download: false,
-                            copy: false,
                         }));
 
                     test({isOutbox: true, type: 'text'}, receiver)
                         .toEqual(jasmine.objectContaining({
                             quote: true,
+                            copy: true,
                             ack: false,
                             dec: false,
                             delete: true,
                             download: false,
-                            copy: false,
                         }));
 
                     test({isOutbox: false, type: 'text', state: 'user-ack'}, receiver)
                         .toEqual(jasmine.objectContaining({
                             quote: true,
+                            copy: true,
                             ack: false,
                             dec: true && canAckDec,
                             delete: true,
                             download: false,
-                            copy: false,
                         }));
 
 
                     test({isOutbox: false, type: 'text', state: 'user-dec'}, receiver)
                         .toEqual(jasmine.objectContaining({
                             quote: true,
+                            copy: true,
                             ack: true && canAckDec,
                             dec: false,
                             delete: true,
                             download: false,
-                            copy: false,
                         }));
                 });
 
@@ -135,11 +135,11 @@ describe('MessageService', function() {
                         test({isOutbox: false, type: type}, receiver)
                             .toEqual(jasmine.objectContaining({
                                 quote: false,
+                                copy: false,
                                 ack: true && canAckDec,
                                 dec: true && canAckDec,
                                 delete: true,
                                 download: true,
-                                copy: false,
                             }));
                     });
 
@@ -147,11 +147,11 @@ describe('MessageService', function() {
                         test({isOutbox: false, type: type, caption: 'test'}, receiver)
                             .toEqual(jasmine.objectContaining({
                                 quote: true,
+                                copy: true,
                                 ack: true && canAckDec,
                                 dec: true && canAckDec,
                                 delete: true,
                                 download: true,
-                                copy: false,
                             }));
                     });
 
@@ -159,11 +159,11 @@ describe('MessageService', function() {
                         test({isOutbox: false, type: type}, receiver)
                             .toEqual(jasmine.objectContaining({
                                 quote: false,
+                                copy: false,
                                 ack: true && canAckDec,
                                 dec: true && canAckDec,
                                 delete: true,
                                 download: true,
-                                copy: false,
                             }));
                     });
 
@@ -172,11 +172,11 @@ describe('MessageService', function() {
                         test({isOutbox: false, type: type, caption: 'test'}, receiver)
                             .toEqual(jasmine.objectContaining({
                                 quote: true,
+                                copy: true,
                                 ack: true && canAckDec,
                                 dec: true && canAckDec,
                                 delete: true,
                                 download: true,
-                                copy: false,
                             }));
                     });
                 });