Roll src/third_party/WebKit 3529d49:06e8485 (svn 202554:202555)
[chromium-blink-merge.git] / remoting / webapp / base / js / clipboard.js
blob9d2b48c0bd75bc6fb080c002eb812e13eb5f8885
1 // Copyright 2015 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.
5 /**
6  * @fileoverview
7  * A class for moving clipboard items between the plugin and the OS.
8  */
10 /** @suppress {duplicate} */
11 var remoting = remoting || {};
13 (function() {
15 'use strict';
17 /**
18  * @private
19  * @enum {string}
20  */
21 var ItemTypes = {
22   TEXT_TYPE: 'text/plain',
23   TEXT_UTF8_TYPE: 'text/plain; charset=UTF-8'
26 /**
27  * @constructor
28  * @param {remoting.ClientPlugin} plugin
29  * @implements {base.Disposable}
30  */
31 remoting.Clipboard = function(plugin) {
32   /** @private {string} */
33   this.previousContent_ = '';
35   /** @private {boolean} */
36   this.itemFromHostTextPending_ = false;
38   /** @private {boolean} */
39   this.blockOneClipboardSend_ = true;
41   /** @private */
42   this.plugin_ = plugin;
44   /** @private */
45   this.eventHooks_ = new base.Disposables(
46       new base.DomEventHook(plugin.element(), 'focus',
47                             this.initiateToHost_.bind(this), false),
48       new base.DomEventHook(window, 'paste', this.onPaste_.bind(this), false),
49       new base.DomEventHook(window, 'copy', this.onCopy_.bind(this), false));
51   // Do a paste operation, but make sure the resulting clipboard data isn't sent
52   // to the host. This stops the host seeing items that were placed on the
53   // clipboard before the session began. The user may not have intended such
54   // items to be sent to the host.
55   this.initiateToHost_();
56   this.plugin_.setClipboardHandler(this.fromHost_.bind(this));
59 remoting.Clipboard.prototype.dispose = function() {
60   this.plugin_.setClipboardHandler(base.doNothing);
61   this.plugin_ = null;
62   base.dispose(this.eventHooks_);
63   this.eventHooks_ = null;
66 /**
67  * Accepts a clipboard from the OS, and sends any changed clipboard items to
68  * the host.
69  *
70  * Currently only text items are supported.
71  *
72  * @param {ClipboardData} clipboardData
73  * @return {void} Nothing.
74  * @private
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   for (var i = 0; i < clipboardData.types.length; i++) {
82     var type = clipboardData.types[i];
83     var item = clipboardData.getData(type);
84     if (!item) {
85       item = '';
86     }
87     console.log('Got clipboard from OS, type: ' + type +
88                 ' length: ' + item.length + ' new: ' +
89                 (item != this.previousContent_) + ' blocking-send: ' +
90                 this.blockOneClipboardSend_);
91     // The browser presents text clipboard items as 'text/plain'.
92     if (type == ItemTypes.TEXT_TYPE) {
93       // Don't send the same item more than once. Otherwise the item may be
94       // sent to and fro indefinitely.
95       if (item != this.previousContent_) {
96         if (!this.blockOneClipboardSend_) {
97           // The plugin's JSON reader emits UTF-8.
98           console.log('Sending clipboard to host.');
99           this.plugin_.sendClipboardItem(ItemTypes.TEXT_UTF8_TYPE, item);
100         }
101         this.previousContent_ = item;
102       }
103     }
104   }
105   this.blockOneClipboardSend_ = false;
109  * Accepts a clipboard item from the host, and stores it so that toOs() will
110  * subsequently send it to the OS clipboard.
112  * @param {string} mimeType The MIME type of the clipboard item.
113  * @param {string} item The clipboard item.
114  * @return {void} Nothing.
115  */
116 remoting.Clipboard.prototype.fromHost_ = function(mimeType, item) {
117   // The plugin's JSON layer will correctly convert only UTF-8 data sent from
118   // the host.
119   console.log('Got clipboard from host, type: ' + mimeType +
120               ' length: ' + item.length + ' new: ' +
121               (item != this.previousContent_));
122   if (mimeType != ItemTypes.TEXT_UTF8_TYPE) {
123     return;
124   }
125   if (item == this.previousContent_) {
126     return;
127   }
128   this.previousContent_ = item;
129   this.itemFromHostTextPending_ = true;
130   this.initiateToOs_();
134  * Moves any pending clipboard items to a ClipboardData object.
136  * @param {ClipboardData} clipboardData
137  * @return {boolean} Whether any clipboard items were moved to the ClipboardData
138  *     object.
139  * @private
140  */
141 remoting.Clipboard.prototype.toOs_ = function(clipboardData) {
142   if (!this.itemFromHostTextPending_) {
143     console.log('Got unexpected clipboard copy event.');
144     return false;
145   }
146   // The JSON layer between the plugin and this webapp converts UTF-8 to the
147   // JS string encoding. The browser will convert JS strings to the correct
148   // encoding, per OS and locale conventions, provided the data type is
149   // 'text/plain'.
150   console.log('Setting OS clipboard, length: ' + this.previousContent_.length);
151   clipboardData.setData(ItemTypes.TEXT_TYPE, this.previousContent_);
152   this.itemFromHostTextPending_ = false;
153   return true;
157  * Initiates the process of sending any fresh items on the OS clipboard, to the
158  * host.
160  * This method makes the browser fire a paste event, which provides access to
161  * the OS clipboard. That event will be caught by a handler in the document,
162  * which will call toHost().
163  * @private
164  */
165 remoting.Clipboard.prototype.initiateToHost_ = function() {
166   // It would be cleaner to send a paste command to the plugin element,
167   // but that's not supported.
168   //console.log('Initiating clipboard paste.');
169   document.execCommand('paste');
173  * Initiates the process of sending any items freshly received from the host,
174  * to the OS clipboard.
176  * This method makes the browser fire a copy event, which provides access to
177  * the OS clipboard. That event will be caught by a handler in the document,
178  * which will call toOs().
179  * @private
180  */
181 remoting.Clipboard.prototype.initiateToOs_ = function() {
182   // It would be cleaner to send a paste command to the plugin element,
183   // but that's not supported.
184   console.log('Initiating clipboard copy.');
185   document.execCommand('copy');
189  * Callback function called when the browser window gets a paste operation.
191  * @param {Event} event
192  * @return {void} Nothing.
193  * @private
194  */
195 remoting.Clipboard.prototype.onPaste_ = function(event) {
196   if (event && event.clipboardData) {
197     this.toHost_(event.clipboardData);
198   }
202  * Callback function called when the browser window gets a copy operation.
204  * @param {Event} event
205  * @return {void} Nothing.
206  * @private
207  */
208 remoting.Clipboard.prototype.onCopy_ = function(event) {
209   if (event && event.clipboardData && this.toOs_(event.clipboardData)) {
210     // The default action may overwrite items that we added to clipboardData.
211     event.preventDefault();
212   }
215 })();