summaryrefslogtreecommitdiffstats
path: root/remoting/webapp/clipboard.js
blob: 90759bd5bfd8e9ef881d01199f8a15c6a98a5df3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @fileoverview
 * A class for moving clipboard items between the plugin and the OS.
 */

'use strict';

/** @suppress {duplicate} */
var remoting = remoting || {};

/**
 * @constructor
 */
remoting.Clipboard = function() {
};

/**
 * @private
 * @enum {string}
 */
remoting.Clipboard.prototype.ItemTypes = {
  TEXT_TYPE: 'text/plain',
  TEXT_UTF8_TYPE: 'text/plain; charset=UTF-8'
};

/**
 * @private
 * @type {string}
 */
remoting.Clipboard.prototype.itemToHostText = "";

/**
 * @private
 * @type {string}
 */
remoting.Clipboard.prototype.itemFromHostText = "";

/**
 * @private
 * @type {boolean}
 */
remoting.Clipboard.prototype.itemFromHostTextPending = false;

/**
 * @private
 * @type {boolean}
 */
remoting.Clipboard.prototype.blockOneClipboardSend_ = false;

/**
 * Notifies this object that a session has started.
 *
 * @return {void} Nothing.
 */
remoting.Clipboard.prototype.startSession = function() {
  // Clear the store of items sent and received. Those items now relate to a
  // previous session.
  this.itemToHostText = "";
  this.itemFromHostText = "";
  this.itemFromHostTextPending = false;

  // Do a paste operation, but make sure the resulting clipboard data isn't sent
  // to the host. This stops the host seeing items that were placed on the
  // clipboard before the session began. The user may not have intended such
  // items to be sent to the host.
  this.blockOneClipboardSend_ = true;
  this.initiateToHost();
};

/**
 * Accepts a clipboard from the OS, and sends any changed clipboard items to
 * the host.
 *
 * Currently only text items are supported.
 *
 * @param {remoting.ClipboardData} clipboardData
 * @return {void} Nothing.
 */
remoting.Clipboard.prototype.toHost = function(clipboardData) {
  if (!clipboardData || !clipboardData.types || !clipboardData.getData) {
    return;
  }
  if (!remoting.clientSession || !remoting.clientSession.plugin) {
    return;
  }
  var plugin = remoting.clientSession.plugin;
  for (var i = 0; i < clipboardData.types.length; i++) {
    var type = clipboardData.types[i];
    // The browser presents text clipboard items as 'text/plain'.
    if (type == this.ItemTypes.TEXT_TYPE) {
      var item = clipboardData.getData(type);
      if (!item) {
        item = "";
      }
      // Don't send an item that's already been sent to the host.
      // And don't send an item that we received from the host: if we do, we
      // may send the same item to and fro indefinitely.
      if ((item != this.itemToHostText) && (item != this.itemFromHostText)) {
        if (!this.blockOneClipboardSend_) {
          // The plugin's JSON reader emits UTF-8.
          plugin.sendClipboardItem(this.ItemTypes.TEXT_UTF8_TYPE, item);
        }
        this.itemToHostText = item;
      }
    }
  }
  this.blockOneClipboardSend_ = false;
};

/**
 * Accepts a clipboard item from the host, and stores it so that toOs() will
 * subsequently send it to the OS clipboard.
 *
 * @param {string} mimeType The MIME type of the clipboard item.
 * @param {string} item The clipboard item.
 * @return {void} Nothing.
 */
remoting.Clipboard.prototype.fromHost = function(mimeType, item) {
  // The plugin's JSON layer will correctly convert only UTF-8 data sent from
  // the host.
  if (mimeType != this.ItemTypes.TEXT_UTF8_TYPE) {
    return;
  }
  if (item == this.itemToHostText) {
    return;
  }
  this.itemFromHostText = item;
  this.itemFromHostTextPending = true;
  this.initiateToOs();
};

/**
 * Moves any pending clipboard items to a ClipboardData object.
 *
 * @param {remoting.ClipboardData} clipboardData
 * @return {boolean} Whether any clipboard items were moved to the ClipboardData
 *     object.
 */
remoting.Clipboard.prototype.toOs = function(clipboardData) {
  if (!this.itemFromHostTextPending) {
    return false;
  }
  // The JSON layer between the plugin and this webapp converts UTF-8 to the
  // JS string encoding. The browser will convert JS strings to the correct
  // encoding, per OS and locale conventions, provided the data type is
  // 'text/plain'.
  clipboardData.setData(this.ItemTypes.TEXT_TYPE, this.itemFromHostText);
  this.itemFromHostTextPending = false;
  return true;
};

/**
 * Initiates the process of sending any fresh items on the OS clipboard, to the
 * host.
 *
 * This method makes the browser fire a paste event, which provides access to
 * the OS clipboard. That event will be caught by a handler in the document,
 * which will call toHost().
 */
remoting.Clipboard.prototype.initiateToHost = function() {
  // It would be cleaner to send a paste command to the plugin element,
  // but that's not supported.
  document.execCommand("paste");
};

/**
 * Initiates the process of sending any items freshly received from the host,
 * to the OS clipboard.
 *
 * This method makes the browser fire a copy event, which provides access to
 * the OS clipboard. That event will be caught by a handler in the document,
 * which will call toOs().
 */
remoting.Clipboard.prototype.initiateToOs = function() {
  // It would be cleaner to send a paste command to the plugin element,
  // but that's not supported.
  document.execCommand("copy");
};

/** @type {remoting.Clipboard} */
remoting.clipboard = null;