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} */ 13var remoting = remoting || {}; 14 15/** 16 * @constructor 17 */ 18remoting.Clipboard = function() { 19}; 20 21/** 22 * @private 23 * @enum {string} 24 */ 25remoting.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 */ 34remoting.Clipboard.prototype.previousContent = ""; 35 36/** 37 * @private 38 * @type {boolean} 39 */ 40remoting.Clipboard.prototype.itemFromHostTextPending = false; 41 42/** 43 * @private 44 * @type {boolean} 45 */ 46remoting.Clipboard.prototype.blockOneClipboardSend_ = false; 47 48/** 49 * Notifies this object that a session has started. 50 * 51 * @return {void} Nothing. 52 */ 53remoting.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 */ 76remoting.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 */ 120remoting.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 */ 144remoting.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 */ 167remoting.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 */ 182remoting.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} */ 190remoting.clipboard = null; 191