Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(298)

Side by Side Diff: remoting/webapp/client_plugin_async.js

Issue 138503007: Remove remoting.ClientPlugin interface (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « remoting/webapp/client_plugin.js ('k') | remoting/webapp/client_session.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 * Class that wraps low-level details of interacting with the client plugin.
8 *
9 * This abstracts a <embed> element and controls the plugin which does
10 * the actual remoting work. It also handles differences between
11 * client plugins versions when it is necessary.
12 */
13
14 'use strict';
15
16 /** @suppress {duplicate} */
17 var remoting = remoting || {};
18
19 /**
20 * @param {remoting.ViewerPlugin} plugin The plugin embed element.
21 * @constructor
22 * @implements {remoting.ClientPlugin}
23 */
24 remoting.ClientPluginAsync = function(plugin) {
25 this.plugin = plugin;
26
27 this.desktopWidth = 0;
28 this.desktopHeight = 0;
29 this.desktopXDpi = 96;
30 this.desktopYDpi = 96;
31
32 /** @param {string} iq The Iq stanza received from the host. */
33 this.onOutgoingIqHandler = function (iq) {};
34 /** @param {string} message Log message. */
35 this.onDebugMessageHandler = function (message) {};
36 /**
37 * @param {number} state The connection state.
38 * @param {number} error The error code, if any.
39 */
40 this.onConnectionStatusUpdateHandler = function(state, error) {};
41 /** @param {boolean} ready Connection ready state. */
42 this.onConnectionReadyHandler = function(ready) {};
43 /**
44 * @param {string} tokenUrl Token-request URL, received from the host.
45 * @param {string} hostPublicKey Public key for the host.
46 * @param {string} scope OAuth scope to request the token for.
47 */
48 this.fetchThirdPartyTokenHandler = function(
49 tokenUrl, hostPublicKey, scope) {};
50 this.onDesktopSizeUpdateHandler = function () {};
51 /** @param {!Array.<string>} capabilities The negotiated capabilities. */
52 this.onSetCapabilitiesHandler = function (capabilities) {};
53 this.fetchPinHandler = function (supportsPairing) {};
54
55 /** @type {number} */
56 this.pluginApiVersion_ = -1;
57 /** @type {Array.<string>} */
58 this.pluginApiFeatures_ = [];
59 /** @type {number} */
60 this.pluginApiMinVersion_ = -1;
61 /** @type {!Array.<string>} */
62 this.capabilities_ = [];
63 /** @type {boolean} */
64 this.helloReceived_ = false;
65 /** @type {function(boolean)|null} */
66 this.onInitializedCallback_ = null;
67 /** @type {function(string, string):void} */
68 this.onPairingComplete_ = function(clientId, sharedSecret) {};
69 /** @type {remoting.ClientSession.PerfStats} */
70 this.perfStats_ = new remoting.ClientSession.PerfStats();
71
72 /** @type {remoting.ClientPluginAsync} */
73 var that = this;
74 /** @param {Event} event Message event from the plugin. */
75 this.plugin.addEventListener('message', function(event) {
76 that.handleMessage_(event.data);
77 }, false);
78 window.setTimeout(this.showPluginForClickToPlay_.bind(this), 500);
79 };
80
81 /**
82 * Chromoting session API version (for this javascript).
83 * This is compared with the plugin API version to verify that they are
84 * compatible.
85 *
86 * @const
87 * @private
88 */
89 remoting.ClientPluginAsync.prototype.API_VERSION_ = 6;
90
91 /**
92 * The oldest API version that we support.
93 * This will differ from the |API_VERSION_| if we maintain backward
94 * compatibility with older API versions.
95 *
96 * @const
97 * @private
98 */
99 remoting.ClientPluginAsync.prototype.API_MIN_VERSION_ = 5;
100
101 /**
102 * @param {string} messageStr Message from the plugin.
103 */
104 remoting.ClientPluginAsync.prototype.handleMessage_ = function(messageStr) {
105 var message = /** @type {{method:string, data:Object.<string,string>}} */
106 jsonParseSafe(messageStr);
107
108 if (!message || !('method' in message) || !('data' in message)) {
109 console.error('Received invalid message from the plugin: ' + messageStr);
110 return;
111 }
112
113 /**
114 * Splits a string into a list of words delimited by spaces.
115 * @param {string} str String that should be split.
116 * @return {!Array.<string>} List of words.
117 */
118 var tokenize = function(str) {
119 /** @type {Array.<string>} */
120 var tokens = str.match(/\S+/g);
121 return tokens ? tokens : [];
122 };
123
124 if (message.method == 'hello') {
125 // Reset the size in case we had to enlarge it to support click-to-play.
126 this.plugin.width = 0;
127 this.plugin.height = 0;
128 if (typeof message.data['apiVersion'] != 'number' ||
129 typeof message.data['apiMinVersion'] != 'number') {
130 console.error('Received invalid hello message: ' + messageStr);
131 return;
132 }
133 this.pluginApiVersion_ = /** @type {number} */ message.data['apiVersion'];
134
135 if (this.pluginApiVersion_ >= 7) {
136 if (typeof message.data['apiFeatures'] != 'string') {
137 console.error('Received invalid hello message: ' + messageStr);
138 return;
139 }
140 this.pluginApiFeatures_ =
141 /** @type {Array.<string>} */ tokenize(message.data['apiFeatures']);
142
143 // Negotiate capabilities.
144
145 /** @type {!Array.<string>} */
146 var requestedCapabilities = [];
147 if ('requestedCapabilities' in message.data) {
148 if (typeof message.data['requestedCapabilities'] != 'string') {
149 console.error('Received invalid hello message: ' + messageStr);
150 return;
151 }
152 requestedCapabilities = tokenize(message.data['requestedCapabilities']);
153 }
154
155 /** @type {!Array.<string>} */
156 var supportedCapabilities = [];
157 if ('supportedCapabilities' in message.data) {
158 if (typeof message.data['supportedCapabilities'] != 'string') {
159 console.error('Received invalid hello message: ' + messageStr);
160 return;
161 }
162 supportedCapabilities = tokenize(message.data['supportedCapabilities']);
163 }
164
165 // At the moment the webapp does not recognize any of
166 // 'requestedCapabilities' capabilities (so they all should be disabled)
167 // and do not care about any of 'supportedCapabilities' capabilities (so
168 // they all can be enabled).
169 this.capabilities_ = supportedCapabilities;
170
171 // Let the host know that the webapp can be requested to always send
172 // the client's dimensions.
173 this.capabilities_.push(
174 remoting.ClientSession.Capability.SEND_INITIAL_RESOLUTION);
175
176 // Let the host know that we're interested in knowing whether or not
177 // it rate-limits desktop-resize requests.
178 this.capabilities_.push(
179 remoting.ClientSession.Capability.RATE_LIMIT_RESIZE_REQUESTS);
180 } else if (this.pluginApiVersion_ >= 6) {
181 this.pluginApiFeatures_ = ['highQualityScaling', 'injectKeyEvent'];
182 } else {
183 this.pluginApiFeatures_ = ['highQualityScaling'];
184 }
185 this.pluginApiMinVersion_ =
186 /** @type {number} */ message.data['apiMinVersion'];
187 this.helloReceived_ = true;
188 if (this.onInitializedCallback_ != null) {
189 this.onInitializedCallback_(true);
190 this.onInitializedCallback_ = null;
191 }
192 } else if (message.method == 'sendOutgoingIq') {
193 if (typeof message.data['iq'] != 'string') {
194 console.error('Received invalid sendOutgoingIq message: ' + messageStr);
195 return;
196 }
197 this.onOutgoingIqHandler(message.data['iq']);
198 } else if (message.method == 'logDebugMessage') {
199 if (typeof message.data['message'] != 'string') {
200 console.error('Received invalid logDebugMessage message: ' + messageStr);
201 return;
202 }
203 this.onDebugMessageHandler(message.data['message']);
204 } else if (message.method == 'onConnectionStatus') {
205 if (typeof message.data['state'] != 'string' ||
206 !remoting.ClientSession.State.hasOwnProperty(message.data['state']) ||
207 typeof message.data['error'] != 'string') {
208 console.error('Received invalid onConnectionState message: ' +
209 messageStr);
210 return;
211 }
212
213 /** @type {remoting.ClientSession.State} */
214 var state = remoting.ClientSession.State[message.data['state']];
215 var error;
216 if (remoting.ClientSession.ConnectionError.hasOwnProperty(
217 message.data['error'])) {
218 error = /** @type {remoting.ClientSession.ConnectionError} */
219 remoting.ClientSession.ConnectionError[message.data['error']];
220 } else {
221 error = remoting.ClientSession.ConnectionError.UNKNOWN;
222 }
223
224 this.onConnectionStatusUpdateHandler(state, error);
225 } else if (message.method == 'onDesktopSize') {
226 if (typeof message.data['width'] != 'number' ||
227 typeof message.data['height'] != 'number') {
228 console.error('Received invalid onDesktopSize message: ' + messageStr);
229 return;
230 }
231 this.desktopWidth = /** @type {number} */ message.data['width'];
232 this.desktopHeight = /** @type {number} */ message.data['height'];
233 this.desktopXDpi = (typeof message.data['x_dpi'] == 'number') ?
234 /** @type {number} */ (message.data['x_dpi']) : 96;
235 this.desktopYDpi = (typeof message.data['y_dpi'] == 'number') ?
236 /** @type {number} */ (message.data['y_dpi']) : 96;
237 this.onDesktopSizeUpdateHandler();
238 } else if (message.method == 'onPerfStats') {
239 if (typeof message.data['videoBandwidth'] != 'number' ||
240 typeof message.data['videoFrameRate'] != 'number' ||
241 typeof message.data['captureLatency'] != 'number' ||
242 typeof message.data['encodeLatency'] != 'number' ||
243 typeof message.data['decodeLatency'] != 'number' ||
244 typeof message.data['renderLatency'] != 'number' ||
245 typeof message.data['roundtripLatency'] != 'number') {
246 console.error('Received incorrect onPerfStats message: ' + messageStr);
247 return;
248 }
249 this.perfStats_ =
250 /** @type {remoting.ClientSession.PerfStats} */ message.data;
251 } else if (message.method == 'injectClipboardItem') {
252 if (typeof message.data['mimeType'] != 'string' ||
253 typeof message.data['item'] != 'string') {
254 console.error('Received incorrect injectClipboardItem message.');
255 return;
256 }
257 if (remoting.clipboard) {
258 remoting.clipboard.fromHost(message.data['mimeType'],
259 message.data['item']);
260 }
261 } else if (message.method == 'onFirstFrameReceived') {
262 if (remoting.clientSession) {
263 remoting.clientSession.onFirstFrameReceived();
264 }
265 } else if (message.method == 'onConnectionReady') {
266 if (typeof message.data['ready'] != 'boolean') {
267 console.error('Received incorrect onConnectionReady message.');
268 return;
269 }
270 var ready = /** @type {boolean} */ message.data['ready'];
271 this.onConnectionReadyHandler(ready);
272 } else if (message.method == 'fetchPin') {
273 // The pairingSupported value in the dictionary indicates whether both
274 // client and host support pairing. If the client doesn't support pairing,
275 // then the value won't be there at all, so give it a default of false.
276 /** @type {boolean} */
277 var pairingSupported = false;
278 if ('pairingSupported' in message.data) {
279 pairingSupported =
280 /** @type {boolean} */ message.data['pairingSupported'];
281 if (typeof pairingSupported != 'boolean') {
282 console.error('Received incorrect fetchPin message.');
283 return;
284 }
285 }
286 this.fetchPinHandler(pairingSupported);
287 } else if (message.method == 'setCapabilities') {
288 if (typeof message.data['capabilities'] != 'string') {
289 console.error('Received incorrect setCapabilities message.');
290 return;
291 }
292
293 /** @type {!Array.<string>} */
294 var capabilities = tokenize(message.data['capabilities']);
295 this.onSetCapabilitiesHandler(capabilities);
296 } else if (message.method == 'fetchThirdPartyToken') {
297 if (typeof message.data['tokenUrl'] != 'string' ||
298 typeof message.data['hostPublicKey'] != 'string' ||
299 typeof message.data['scope'] != 'string') {
300 console.error('Received incorrect fetchThirdPartyToken message.');
301 return;
302 }
303 var tokenUrl = /** @type {string} */ message.data['tokenUrl'];
304 var hostPublicKey =
305 /** @type {string} */ message.data['hostPublicKey'];
306 var scope = /** @type {string} */ message.data['scope'];
307 this.fetchThirdPartyTokenHandler(tokenUrl, hostPublicKey, scope);
308 } else if (message.method == 'pairingResponse') {
309 var clientId = /** @type {string} */ message.data['clientId'];
310 var sharedSecret = /** @type {string} */ message.data['sharedSecret'];
311 if (typeof clientId != 'string' || typeof sharedSecret != 'string') {
312 console.error('Received incorrect pairingResponse message.');
313 return;
314 }
315 this.onPairingComplete_(clientId, sharedSecret);
316 } else if (message.method == 'extensionMessage') {
317 if (typeof(message.data['type']) != 'string' ||
318 typeof(message.data['data']) != 'string') {
319 console.error('Invalid extension message:', message.data);
320 return;
321 }
322 switch (message.data['type']) {
323 case 'test-echo-reply':
324 console.log('Got echo reply: ' + message.data['data']);
325 break;
326 default:
327 console.log('Unexpected message received: ' +
328 message.data['type'] + ': ' + message.data['data']);
329 }
330 }
331 };
332
333 /**
334 * Deletes the plugin.
335 */
336 remoting.ClientPluginAsync.prototype.cleanup = function() {
337 this.plugin.parentNode.removeChild(this.plugin);
338 };
339
340 /**
341 * @return {HTMLEmbedElement} HTML element that correspods to the plugin.
342 */
343 remoting.ClientPluginAsync.prototype.element = function() {
344 return this.plugin;
345 };
346
347 /**
348 * @param {function(boolean): void} onDone
349 */
350 remoting.ClientPluginAsync.prototype.initialize = function(onDone) {
351 if (this.helloReceived_) {
352 onDone(true);
353 } else {
354 this.onInitializedCallback_ = onDone;
355 }
356 };
357
358 /**
359 * @return {boolean} True if the plugin and web-app versions are compatible.
360 */
361 remoting.ClientPluginAsync.prototype.isSupportedVersion = function() {
362 if (!this.helloReceived_) {
363 console.error(
364 "isSupportedVersion() is called before the plugin is initialized.");
365 return false;
366 }
367 return this.API_VERSION_ >= this.pluginApiMinVersion_ &&
368 this.pluginApiVersion_ >= this.API_MIN_VERSION_;
369 };
370
371 /**
372 * @param {remoting.ClientPlugin.Feature} feature The feature to test for.
373 * @return {boolean} True if the plugin supports the named feature.
374 */
375 remoting.ClientPluginAsync.prototype.hasFeature = function(feature) {
376 if (!this.helloReceived_) {
377 console.error(
378 "hasFeature() is called before the plugin is initialized.");
379 return false;
380 }
381 return this.pluginApiFeatures_.indexOf(feature) > -1;
382 };
383
384 /**
385 * @return {boolean} True if the plugin supports the injectKeyEvent API.
386 */
387 remoting.ClientPluginAsync.prototype.isInjectKeyEventSupported = function() {
388 return this.pluginApiVersion_ >= 6;
389 };
390
391 /**
392 * @param {string} iq Incoming IQ stanza.
393 */
394 remoting.ClientPluginAsync.prototype.onIncomingIq = function(iq) {
395 if (this.plugin && this.plugin.postMessage) {
396 this.plugin.postMessage(JSON.stringify(
397 { method: 'incomingIq', data: { iq: iq } }));
398 } else {
399 // plugin.onIq may not be set after the plugin has been shut
400 // down. Particularly this happens when we receive response to
401 // session-terminate stanza.
402 console.warn('plugin.onIq is not set so dropping incoming message.');
403 }
404 };
405
406 /**
407 * @param {string} hostJid The jid of the host to connect to.
408 * @param {string} hostPublicKey The base64 encoded version of the host's
409 * public key.
410 * @param {string} localJid Local jid.
411 * @param {string} sharedSecret The access code for IT2Me or the PIN
412 * for Me2Me.
413 * @param {string} authenticationMethods Comma-separated list of
414 * authentication methods the client should attempt to use.
415 * @param {string} authenticationTag A host-specific tag to mix into
416 * authentication hashes.
417 * @param {string} clientPairingId For paired Me2Me connections, the
418 * pairing id for this client, as issued by the host.
419 * @param {string} clientPairedSecret For paired Me2Me connections, the
420 * paired secret for this client, as issued by the host.
421 */
422 remoting.ClientPluginAsync.prototype.connect = function(
423 hostJid, hostPublicKey, localJid, sharedSecret,
424 authenticationMethods, authenticationTag,
425 clientPairingId, clientPairedSecret) {
426 this.plugin.postMessage(JSON.stringify(
427 { method: 'connect', data: {
428 hostJid: hostJid,
429 hostPublicKey: hostPublicKey,
430 localJid: localJid,
431 sharedSecret: sharedSecret,
432 authenticationMethods: authenticationMethods,
433 authenticationTag: authenticationTag,
434 capabilities: this.capabilities_.join(" "),
435 clientPairingId: clientPairingId,
436 clientPairedSecret: clientPairedSecret
437 }
438 }));
439 };
440
441 /**
442 * Release all currently pressed keys.
443 */
444 remoting.ClientPluginAsync.prototype.releaseAllKeys = function() {
445 this.plugin.postMessage(JSON.stringify(
446 { method: 'releaseAllKeys', data: {} }));
447 };
448
449 /**
450 * Send a key event to the host.
451 *
452 * @param {number} usbKeycode The USB-style code of the key to inject.
453 * @param {boolean} pressed True to inject a key press, False for a release.
454 */
455 remoting.ClientPluginAsync.prototype.injectKeyEvent =
456 function(usbKeycode, pressed) {
457 this.plugin.postMessage(JSON.stringify(
458 { method: 'injectKeyEvent', data: {
459 'usbKeycode': usbKeycode,
460 'pressed': pressed}
461 }));
462 };
463
464 /**
465 * Remap one USB keycode to another in all subsequent key events.
466 *
467 * @param {number} fromKeycode The USB-style code of the key to remap.
468 * @param {number} toKeycode The USB-style code to remap the key to.
469 */
470 remoting.ClientPluginAsync.prototype.remapKey =
471 function(fromKeycode, toKeycode) {
472 this.plugin.postMessage(JSON.stringify(
473 { method: 'remapKey', data: {
474 'fromKeycode': fromKeycode,
475 'toKeycode': toKeycode}
476 }));
477 };
478
479 /**
480 * Enable/disable redirection of the specified key to the web-app.
481 *
482 * @param {number} keycode The USB-style code of the key.
483 * @param {Boolean} trap True to enable trapping, False to disable.
484 */
485 remoting.ClientPluginAsync.prototype.trapKey = function(keycode, trap) {
486 this.plugin.postMessage(JSON.stringify(
487 { method: 'trapKey', data: {
488 'keycode': keycode,
489 'trap': trap}
490 }));
491 };
492
493 /**
494 * Returns an associative array with a set of stats for this connecton.
495 *
496 * @return {remoting.ClientSession.PerfStats} The connection statistics.
497 */
498 remoting.ClientPluginAsync.prototype.getPerfStats = function() {
499 return this.perfStats_;
500 };
501
502 /**
503 * Sends a clipboard item to the host.
504 *
505 * @param {string} mimeType The MIME type of the clipboard item.
506 * @param {string} item The clipboard item.
507 */
508 remoting.ClientPluginAsync.prototype.sendClipboardItem =
509 function(mimeType, item) {
510 if (!this.hasFeature(remoting.ClientPlugin.Feature.SEND_CLIPBOARD_ITEM))
511 return;
512 this.plugin.postMessage(JSON.stringify(
513 { method: 'sendClipboardItem',
514 data: { mimeType: mimeType, item: item }}));
515 };
516
517 /**
518 * Notifies the host that the client has the specified size and pixel density.
519 *
520 * @param {number} width The available client width in DIPs.
521 * @param {number} height The available client height in DIPs.
522 * @param {number} device_scale The number of device pixels per DIP.
523 */
524 remoting.ClientPluginAsync.prototype.notifyClientResolution =
525 function(width, height, device_scale) {
526 if (this.hasFeature(remoting.ClientPlugin.Feature.NOTIFY_CLIENT_RESOLUTION)) {
527 var dpi = Math.floor(device_scale * 96);
528 this.plugin.postMessage(JSON.stringify(
529 { method: 'notifyClientResolution',
530 data: { width: Math.floor(width * device_scale),
531 height: Math.floor(height * device_scale),
532 x_dpi: dpi, y_dpi: dpi }}));
533 }
534 };
535
536 /**
537 * Requests that the host pause or resume sending video updates.
538 *
539 * @param {boolean} pause True to suspend video updates, false otherwise.
540 */
541 remoting.ClientPluginAsync.prototype.pauseVideo =
542 function(pause) {
543 if (!this.hasFeature(remoting.ClientPlugin.Feature.PAUSE_VIDEO))
544 return;
545 this.plugin.postMessage(JSON.stringify(
546 { method: 'pauseVideo', data: { pause: pause }}));
547 };
548
549 /**
550 * Requests that the host pause or resume sending audio updates.
551 *
552 * @param {boolean} pause True to suspend audio updates, false otherwise.
553 */
554 remoting.ClientPluginAsync.prototype.pauseAudio =
555 function(pause) {
556 if (!this.hasFeature(remoting.ClientPlugin.Feature.PAUSE_AUDIO))
557 return;
558 this.plugin.postMessage(JSON.stringify(
559 { method: 'pauseAudio', data: { pause: pause }}));
560 };
561
562 /**
563 * Called when a PIN is obtained from the user.
564 *
565 * @param {string} pin The PIN.
566 */
567 remoting.ClientPluginAsync.prototype.onPinFetched =
568 function(pin) {
569 if (!this.hasFeature(remoting.ClientPlugin.Feature.ASYNC_PIN)) {
570 return;
571 }
572 this.plugin.postMessage(JSON.stringify(
573 { method: 'onPinFetched', data: { pin: pin }}));
574 };
575
576 /**
577 * Tells the plugin to ask for the PIN asynchronously.
578 */
579 remoting.ClientPluginAsync.prototype.useAsyncPinDialog =
580 function() {
581 if (!this.hasFeature(remoting.ClientPlugin.Feature.ASYNC_PIN)) {
582 return;
583 }
584 this.plugin.postMessage(JSON.stringify(
585 { method: 'useAsyncPinDialog', data: {} }));
586 };
587
588 /**
589 * Sets the third party authentication token and shared secret.
590 *
591 * @param {string} token The token received from the token URL.
592 * @param {string} sharedSecret Shared secret received from the token URL.
593 */
594 remoting.ClientPluginAsync.prototype.onThirdPartyTokenFetched = function(
595 token, sharedSecret) {
596 this.plugin.postMessage(JSON.stringify(
597 { method: 'onThirdPartyTokenFetched',
598 data: { token: token, sharedSecret: sharedSecret}}));
599 };
600
601 /**
602 * Request pairing with the host for PIN-less authentication.
603 *
604 * @param {string} clientName The human-readable name of the client.
605 * @param {function(string, string):void} onDone, Callback to receive the
606 * client id and shared secret when they are available.
607 */
608 remoting.ClientPluginAsync.prototype.requestPairing =
609 function(clientName, onDone) {
610 if (!this.hasFeature(remoting.ClientPlugin.Feature.PINLESS_AUTH)) {
611 return;
612 }
613 this.onPairingComplete_ = onDone;
614 this.plugin.postMessage(JSON.stringify(
615 { method: 'requestPairing', data: { clientName: clientName } }));
616 };
617
618 /**
619 * Send an extension message to the host.
620 *
621 * @param {string} type The message type.
622 * @param {Object} message The message payload.
623 */
624 remoting.ClientPluginAsync.prototype.sendClientMessage =
625 function(type, message) {
626 if (!this.hasFeature(remoting.ClientPlugin.Feature.EXTENSION_MESSAGE)) {
627 return;
628 }
629 this.plugin.postMessage(JSON.stringify(
630 { method: 'extensionMessage',
631 data: { type: type, data: JSON.stringify(message) } }));
632
633 };
634
635 /**
636 * If we haven't yet received a "hello" message from the plugin, change its
637 * size so that the user can confirm it if click-to-play is enabled, or can
638 * see the "this plugin is disabled" message if it is actually disabled.
639 * @private
640 */
641 remoting.ClientPluginAsync.prototype.showPluginForClickToPlay_ = function() {
642 if (!this.helloReceived_) {
643 var width = 200;
644 var height = 200;
645 this.plugin.width = width;
646 this.plugin.height = height;
647 // Center the plugin just underneath the "Connnecting..." dialog.
648 var parentNode = this.plugin.parentNode;
649 var dialog = document.getElementById('client-dialog');
650 var dialogRect = dialog.getBoundingClientRect();
651 parentNode.style.top = (dialogRect.bottom + 16) + 'px';
652 parentNode.style.left = (window.innerWidth - width) / 2 + 'px';
653 }
654 };
OLDNEW
« no previous file with comments | « remoting/webapp/client_plugin.js ('k') | remoting/webapp/client_session.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698