|  | // Copyright 2014 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 | 
|  | * Apps v2 custom title bar implementation | 
|  | */ | 
|  |  | 
|  | 'use strict'; | 
|  |  | 
|  | /** @suppress {duplicate} */ | 
|  | var remoting = remoting || {}; | 
|  |  | 
|  | /** | 
|  | * @param {HTMLElement} titleBar The root node of the title-bar DOM hierarchy. | 
|  | * @param {function()} disconnectCallback Callback for disconnecting the | 
|  | *     session. | 
|  | * @constructor | 
|  | */ | 
|  | remoting.WindowFrame = function(titleBar, disconnectCallback) { | 
|  | /** @private {remoting.DesktopConnectedView} */ | 
|  | this.desktopConnectedView_ = null; | 
|  |  | 
|  | /** @private {HTMLElement} */ | 
|  | this.titleBar_ = titleBar; | 
|  |  | 
|  | /** @private {HTMLElement} */ | 
|  | this.title_ = /** @type {HTMLElement} */ | 
|  | (titleBar.querySelector('.window-title')); | 
|  | console.assert(this.title_ != null, 'Missing title element.'); | 
|  |  | 
|  | /** @private {HTMLElement} */ | 
|  | this.maximizeRestoreControl_ = /** @type {HTMLElement} */ | 
|  | (titleBar.querySelector('.window-maximize-restore')); | 
|  | console.assert(this.maximizeRestoreControl_ != null, | 
|  | 'Missing maximize/restore control.'); | 
|  |  | 
|  | var optionsButton = titleBar.querySelector('.window-options'); | 
|  | console.assert(optionsButton != null, 'Missing options button.'); | 
|  | this.optionMenuButton_ = new remoting.MenuButton( | 
|  | optionsButton, | 
|  | this.onShowOptionsMenu_.bind(this), | 
|  | this.onHideOptionsMenu_.bind(this)); | 
|  |  | 
|  | /** @private {HTMLElement} */ | 
|  | this.optionsMenuList_ = /** @type {HTMLElement} */ | 
|  | (optionsButton.querySelector('.window-options-menu')); | 
|  | console.assert(this.optionsMenuList_ != null, 'Missing options menu.'); | 
|  |  | 
|  | /** | 
|  | * @type {Array<{cls:string, fn: function()}>} | 
|  | */ | 
|  | var handlers = [ | 
|  | { cls: 'window-disconnect', fn: disconnectCallback }, | 
|  | { cls: 'window-maximize-restore', | 
|  | fn: this.maximizeOrRestoreWindow_.bind(this) }, | 
|  | { cls: 'window-minimize', fn: this.minimizeWindow_.bind(this) }, | 
|  | { cls: 'window-close', fn: remoting.app.quit.bind(remoting.app) }, | 
|  | { cls: 'window-controls-stub', fn: this.toggleWindowControls_.bind(this) } | 
|  | ]; | 
|  | for (var i = 0; i < handlers.length; ++i) { | 
|  | var element = titleBar.querySelector('.' + handlers[i].cls); | 
|  | console.assert(element != null, 'Missing class: ' + handlers[i].cls + '.'); | 
|  | element.addEventListener('click', handlers[i].fn, false); | 
|  | } | 
|  |  | 
|  | // Ensure that tool-tips are always correct. | 
|  | this.handleWindowStateChange_(); | 
|  | chrome.app.window.current().onMaximized.addListener( | 
|  | this.handleWindowStateChange_.bind(this)); | 
|  | chrome.app.window.current().onRestored.addListener( | 
|  | this.handleWindowStateChange_.bind(this)); | 
|  | chrome.app.window.current().onFullscreened.addListener( | 
|  | this.handleWindowStateChange_.bind(this)); | 
|  | chrome.app.window.current().onFullscreened.addListener( | 
|  | this.showWindowControlsPreview_.bind(this)); | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * @return {remoting.OptionsMenu} | 
|  | */ | 
|  | remoting.WindowFrame.prototype.createOptionsMenu = function() { | 
|  | return new remoting.OptionsMenu( | 
|  | this.titleBar_.querySelector('.menu-send-ctrl-alt-del'), | 
|  | this.titleBar_.querySelector('.menu-send-print-screen'), | 
|  | this.titleBar_.querySelector('.menu-map-right-ctrl-to-meta'), | 
|  | this.titleBar_.querySelector('.menu-resize-to-client'), | 
|  | this.titleBar_.querySelector('.menu-shrink-to-fit'), | 
|  | this.titleBar_.querySelector('.menu-new-window'), | 
|  | this.titleBar_.querySelector('.window-fullscreen'), | 
|  | this.titleBar_.querySelector('.menu-toggle-connection-stats')); | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * @param {remoting.DesktopConnectedView} desktopConnectedView The view for the | 
|  | *     current session, or null if there is no connection. | 
|  | */ | 
|  | remoting.WindowFrame.prototype.setDesktopConnectedView = function( | 
|  | desktopConnectedView) { | 
|  | this.desktopConnectedView_ = desktopConnectedView; | 
|  | var windowTitle = document.head.querySelector('title'); | 
|  | if (this.desktopConnectedView_) { | 
|  | this.title_.innerText = desktopConnectedView.getHostDisplayName(); | 
|  | windowTitle.innerText = desktopConnectedView.getHostDisplayName() + ' - ' + | 
|  | remoting.app.getApplicationName(); | 
|  | } else { | 
|  | this.title_.innerHTML = ' '; | 
|  | windowTitle.innerText = remoting.app.getApplicationName(); | 
|  | } | 
|  | this.handleWindowStateChange_(); | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * @return {{width: number, height: number}} The size of the window, ignoring | 
|  | *     the title-bar and window borders, if visible. | 
|  | */ | 
|  | remoting.WindowFrame.prototype.getClientArea = function() { | 
|  | if (chrome.app.window.current().isFullscreen()) { | 
|  | return { 'height': window.innerHeight, 'width': window.innerWidth }; | 
|  | } else { | 
|  | var kBorderWidth = 1; | 
|  | var titleHeight = this.titleBar_.clientHeight; | 
|  | return { | 
|  | 'height': window.innerHeight - titleHeight - 2 * kBorderWidth, | 
|  | 'width': window.innerWidth - 2 * kBorderWidth | 
|  | }; | 
|  | } | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * @private | 
|  | */ | 
|  | remoting.WindowFrame.prototype.maximizeOrRestoreWindow_ = function() { | 
|  | /** @type {boolean} */ | 
|  | var restore = | 
|  | chrome.app.window.current().isFullscreen() || | 
|  | chrome.app.window.current().isMaximized(); | 
|  | if (restore) { | 
|  | chrome.app.window.current().restore(); | 
|  | } else { | 
|  | chrome.app.window.current().maximize(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * @private | 
|  | */ | 
|  | remoting.WindowFrame.prototype.minimizeWindow_ = function() { | 
|  | chrome.app.window.current().minimize(); | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * @private | 
|  | */ | 
|  | remoting.WindowFrame.prototype.toggleWindowControls_ = function() { | 
|  | this.titleBar_.classList.toggle('opened'); | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Update the tool-top for the maximize/full-screen/restore icon to reflect | 
|  | * its current behaviour. | 
|  | * | 
|  | * @private | 
|  | */ | 
|  | remoting.WindowFrame.prototype.handleWindowStateChange_ = function() { | 
|  | // Set the title for the maximize/restore/full-screen button | 
|  | /** @type {string} */ | 
|  | var tag = ''; | 
|  | if (chrome.app.window.current().isFullscreen()) { | 
|  | tag = /*i18n-content*/'EXIT_FULL_SCREEN'; | 
|  | } else if (chrome.app.window.current().isMaximized()) { | 
|  | tag = /*i18n-content*/'RESTORE_WINDOW'; | 
|  | } else { | 
|  | tag = /*i18n-content*/'MAXIMIZE_WINDOW'; | 
|  | } | 
|  | this.maximizeRestoreControl_.title = l10n.getTranslationOrError(tag); | 
|  |  | 
|  | // Ensure that the options menu aligns correctly for the side of the window | 
|  | // it occupies. | 
|  | if (chrome.app.window.current().isFullscreen()) { | 
|  | this.optionsMenuList_.classList.add('right-align'); | 
|  | } else { | 
|  | this.optionsMenuList_.classList.remove('right-align'); | 
|  | } | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Callback invoked when the options menu is shown. | 
|  | * @private | 
|  | */ | 
|  | remoting.WindowFrame.prototype.onShowOptionsMenu_ = function() { | 
|  | remoting.optionsMenu.onShow(); | 
|  | this.titleBar_.classList.add('menu-opened'); | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Callback invoked when the options menu is shown. | 
|  | * @private | 
|  | */ | 
|  | remoting.WindowFrame.prototype.onHideOptionsMenu_ = function() { | 
|  | this.titleBar_.classList.remove('menu-opened'); | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Show the window controls for a few seconds | 
|  | * | 
|  | * @private | 
|  | */ | 
|  | remoting.WindowFrame.prototype.showWindowControlsPreview_ = function() { | 
|  | /** | 
|  | * @type {HTMLElement} | 
|  | */ | 
|  | var target =  this.titleBar_; | 
|  | var kPreviewTimeoutMs = 3000; | 
|  | var hidePreview = function() { | 
|  | target.classList.remove('preview'); | 
|  | }; | 
|  | target.classList.add('preview'); | 
|  | window.setTimeout(hidePreview, kPreviewTimeoutMs); | 
|  | }; | 
|  |  | 
|  |  | 
|  | /** @type {remoting.WindowFrame} */ | 
|  | remoting.windowFrame = null; |