Home | History | Annotate | Download | only in webapp
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 /**
      6  * @fileoverview
      7  * A class for moving clipboard items between the plugin and the OS.
      8  */
      9 
     10 'use strict';
     11 
     12 /** @suppress {duplicate} */
     13 var remoting = remoting || {};
     14 
     15 /**
     16  * @constructor
     17  */
     18 remoting.Clipboard = function() {
     19 };
     20 
     21 /**
     22  * @private
     23  * @enum {string}
     24  */
     25 remoting.Clipboard.prototype.ItemTypes = {
     26   TEXT_TYPE: 'text/plain',
     27   TEXT_UTF8_TYPE: 'text/plain; charset=UTF-8'
     28 };
     29 
     30 /**
     31  * @private
     32  * @type {string}
     33  */
     34 remoting.Clipboard.prototype.previousContent = "";
     35 
     36 /**
     37  * @private
     38  * @type {boolean}
     39  */
     40 remoting.Clipboard.prototype.itemFromHostTextPending = false;
     41 
     42 /**
     43  * @private
     44  * @type {boolean}
     45  */
     46 remoting.Clipboard.prototype.blockOneClipboardSend_ = false;
     47 
     48 /**
     49  * Notifies this object that a session has started.
     50  *
     51  * @return {void} Nothing.
     52  */
     53 remoting.Clipboard.prototype.startSession = function() {
     54   // Clear the store of items sent and received. Those items now relate to a
     55   // previous session.
     56   this.previousContent = "";
     57   this.itemFromHostTextPending = false;
     58 
     59   // Do a paste operation, but make sure the resulting clipboard data isn't sent
     60   // to the host. This stops the host seeing items that were placed on the
     61   // clipboard before the session began. The user may not have intended such
     62   // items to be sent to the host.
     63   this.blockOneClipboardSend_ = true;
     64   this.initiateToHost();
     65 };
     66 
     67 /**
     68  * Accepts a clipboard from the OS, and sends any changed clipboard items to
     69  * the host.
     70  *
     71  * Currently only text items are supported.
     72  *
     73  * @param {remoting.ClipboardData} clipboardData
     74  * @return {void} Nothing.
     75  */
     76 remoting.Clipboard.prototype.toHost = function(clipboardData) {
     77   if (!clipboardData || !clipboardData.types || !clipboardData.getData) {
     78     console.log('Got invalid clipboardData.');
     79     return;
     80   }
     81   if (!remoting.clientSession) {
     82     return;
     83   }
     84   for (var i = 0; i < clipboardData.types.length; i++) {
     85     var type = clipboardData.types[i];
     86     var item = clipboardData.getData(type);
     87     if (!item) {
     88       item = "";
     89     }
     90     console.log('Got clipboard from OS, type: ' + type +
     91                 ' length: ' + item.length + ' new: ' +
     92                 (item != this.previousContent) + ' blocking-send: ' +
     93                 this.blockOneClipboardSend_);
     94     // The browser presents text clipboard items as 'text/plain'.
     95     if (type == this.ItemTypes.TEXT_TYPE) {
     96       // Don't send the same item more than once. Otherwise the item may be
     97       // sent to and fro indefinitely.
     98       if (item != this.previousContent) {
     99         if (!this.blockOneClipboardSend_) {
    100           // The plugin's JSON reader emits UTF-8.
    101           console.log('Sending clipboard to host.');
    102           remoting.clientSession.sendClipboardItem(
    103               this.ItemTypes.TEXT_UTF8_TYPE, item);
    104         }
    105         this.previousContent = item;
    106       }
    107     }
    108   }
    109   this.blockOneClipboardSend_ = false;
    110 };
    111 
    112 /**
    113  * Accepts a clipboard item from the host, and stores it so that toOs() will
    114  * subsequently send it to the OS clipboard.
    115  *
    116  * @param {string} mimeType The MIME type of the clipboard item.
    117  * @param {string} item The clipboard item.
    118  * @return {void} Nothing.
    119  */
    120 remoting.Clipboard.prototype.fromHost = function(mimeType, item) {
    121   // The plugin's JSON layer will correctly convert only UTF-8 data sent from
    122   // the host.
    123   console.log('Got clipboard from host, type: ' + mimeType +
    124               ' length: ' + item.length + ' new: ' +
    125               (item != this.previousContent));
    126   if (mimeType != this.ItemTypes.TEXT_UTF8_TYPE) {
    127     return;
    128   }
    129   if (item == this.previousContent) {
    130     return;
    131   }
    132   this.previousContent = item;
    133   this.itemFromHostTextPending = true;
    134   this.initiateToOs();
    135 };
    136 
    137 /**
    138  * Moves any pending clipboard items to a ClipboardData object.
    139  *
    140  * @param {remoting.ClipboardData} clipboardData
    141  * @return {boolean} Whether any clipboard items were moved to the ClipboardData
    142  *     object.
    143  */
    144 remoting.Clipboard.prototype.toOs = function(clipboardData) {
    145   if (!this.itemFromHostTextPending) {
    146     console.log('Got unexpected clipboard copy event.');
    147     return false;
    148   }
    149   // The JSON layer between the plugin and this webapp converts UTF-8 to the
    150   // JS string encoding. The browser will convert JS strings to the correct
    151   // encoding, per OS and locale conventions, provided the data type is
    152   // 'text/plain'.
    153   console.log('Setting OS clipboard, length: ' + this.previousContent.length);
    154   clipboardData.setData(this.ItemTypes.TEXT_TYPE, this.previousContent);
    155   this.itemFromHostTextPending = false;
    156   return true;
    157 };
    158 
    159 /**
    160  * Initiates the process of sending any fresh items on the OS clipboard, to the
    161  * host.
    162  *
    163  * This method makes the browser fire a paste event, which provides access to
    164  * the OS clipboard. That event will be caught by a handler in the document,
    165  * which will call toHost().
    166  */
    167 remoting.Clipboard.prototype.initiateToHost = function() {
    168   // It would be cleaner to send a paste command to the plugin element,
    169   // but that's not supported.
    170   //console.log('Initiating clipboard paste.');
    171   document.execCommand("paste");
    172 };
    173 
    174 /**
    175  * Initiates the process of sending any items freshly received from the host,
    176  * to the OS clipboard.
    177  *
    178  * This method makes the browser fire a copy event, which provides access to
    179  * the OS clipboard. That event will be caught by a handler in the document,
    180  * which will call toOs().
    181  */
    182 remoting.Clipboard.prototype.initiateToOs = function() {
    183   // It would be cleaner to send a paste command to the plugin element,
    184   // but that's not supported.
    185   console.log('Initiating clipboard copy.');
    186   document.execCommand("copy");
    187 };
    188 
    189 /** @type {remoting.Clipboard} */
    190 remoting.clipboard = null;
    191