1 // Copyright 2014 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 * Apps v2 custom title bar implementation 8 */ 9 10 'use strict'; 11 12 /** @suppress {duplicate} */ 13 var remoting = remoting || {}; 14 15 /** 16 * @param {HTMLElement} titleBar The root node of the title-bar DOM hierarchy. 17 * @constructor 18 */ 19 remoting.WindowFrame = function(titleBar) { 20 /** 21 * @type {boolean} 22 * @private 23 */ 24 this.isConnected_ = false; 25 26 /** 27 * @type {HTMLElement} 28 * @private 29 */ 30 this.titleBar_ = titleBar; 31 32 /** 33 * @type {HTMLElement} 34 * @private 35 */ 36 this.hoverTarget_ = /** @type {HTMLElement} */ 37 (titleBar.querySelector('.window-controls-hover-target')); 38 base.debug.assert(this.hoverTarget_ != null); 39 40 /** 41 * @type {HTMLElement} 42 * @private 43 */ 44 this.maximizeRestoreControl_ = /** @type {HTMLElement} */ 45 (titleBar.querySelector('.window-maximize-restore')); 46 base.debug.assert(this.maximizeRestoreControl_ != null); 47 48 /** 49 * @type {Array.<{cls:string, fn: function()}>} 50 */ 51 var handlers = [ 52 { cls: 'window-disconnect', fn: this.disconnectSession_.bind(this) }, 53 { cls: 'window-maximize-restore', 54 fn: this.maximizeOrRestoreWindow_.bind(this) }, 55 { cls: 'window-minimize', fn: this.minimizeWindow_.bind(this) }, 56 { cls: 'window-close', fn: window.close.bind(window) }, 57 { cls: 'window-controls-stub', fn: this.toggleWindowControls_.bind(this) } 58 ]; 59 for (var i = 0; i < handlers.length; ++i) { 60 var element = titleBar.querySelector('.' + handlers[i].cls); 61 base.debug.assert(element != null); 62 element.addEventListener('click', handlers[i].fn, false); 63 } 64 65 // Ensure that tool-tips are always correct. 66 this.updateMaximizeOrRestoreIconTitle_(); 67 chrome.app.window.current().onMaximized.addListener( 68 this.updateMaximizeOrRestoreIconTitle_.bind(this)); 69 chrome.app.window.current().onRestored.addListener( 70 this.updateMaximizeOrRestoreIconTitle_.bind(this)); 71 chrome.app.window.current().onFullscreened.addListener( 72 this.updateMaximizeOrRestoreIconTitle_.bind(this)); 73 }; 74 75 /** 76 * @param {boolean} isConnected True if there is a connection active. 77 */ 78 remoting.WindowFrame.prototype.setConnected = function(isConnected) { 79 this.isConnected_ = isConnected; 80 if (this.isConnected_) { 81 document.body.classList.add('connected'); 82 } else { 83 document.body.classList.remove('connected'); 84 } 85 this.updateMaximizeOrRestoreIconTitle_(); 86 }; 87 88 /** 89 * @return {{width: number, height: number}} The size of the window, ignoring 90 * the title-bar and window borders, if visible. 91 */ 92 remoting.WindowFrame.prototype.getClientArea = function() { 93 if (chrome.app.window.current().isFullscreen()) { 94 return { 'height': window.innerHeight, 'width': window.innerWidth }; 95 } else { 96 var kBorderWidth = 1; 97 var titleHeight = this.titleBar_.clientHeight; 98 return { 99 'height': window.innerHeight - titleHeight - 2 * kBorderWidth, 100 'width': window.innerWidth - 2 * kBorderWidth 101 }; 102 } 103 }; 104 105 /** 106 * @private 107 */ 108 remoting.WindowFrame.prototype.disconnectSession_ = function() { 109 // When the user disconnects, exit full-screen mode. This should not be 110 // necessary, as we do the same thing in client_session.js when the plugin 111 // is removed. However, there seems to be a bug in chrome.AppWindow.restore 112 // that causes it to get stuck in full-screen mode without this. 113 if (chrome.app.window.current().isFullscreen()) { 114 chrome.app.window.current().restore(); 115 } 116 remoting.disconnect(); 117 }; 118 119 /** 120 * @private 121 */ 122 remoting.WindowFrame.prototype.maximizeOrRestoreWindow_ = function() { 123 /** @type {boolean} */ 124 var restore = 125 chrome.app.window.current().isFullscreen() || 126 chrome.app.window.current().isMaximized(); 127 if (restore) { 128 // Restore twice: once to exit full-screen and once to exit maximized. 129 // If the app is not full-screen, or went full-screen without first 130 // being maximized, then the second restore has no effect. 131 chrome.app.window.current().restore(); 132 } else if (this.isConnected_) { 133 chrome.app.window.current().fullscreen(); 134 } else { 135 chrome.app.window.current().maximize(); 136 } 137 }; 138 139 /** 140 * @private 141 */ 142 remoting.WindowFrame.prototype.minimizeWindow_ = function() { 143 chrome.app.window.current().minimize(); 144 }; 145 146 /** 147 * @private 148 */ 149 remoting.WindowFrame.prototype.toggleWindowControls_ = function() { 150 this.hoverTarget_.classList.toggle('opened'); 151 }; 152 153 /** 154 * Update the tool-top for the maximize/full-screen/restore icon to reflect 155 * its current behaviour. 156 * 157 * @private 158 */ 159 remoting.WindowFrame.prototype.updateMaximizeOrRestoreIconTitle_ = function() { 160 /** @type {string} */ 161 var tag = ''; 162 if (chrome.app.window.current().isFullscreen()) { 163 tag = /*i18n-content*/'EXIT_FULL_SCREEN'; 164 } else if (chrome.app.window.current().isMaximized()) { 165 tag = /*i18n-content*/'RESTORE_WINDOW'; 166 } else if (this.isConnected_) { 167 tag = /*i18n-content*/'FULL_SCREEN'; 168 } else { 169 tag = /*i18n-content*/'MAXIMIZE_WINDOW'; 170 } 171 this.maximizeRestoreControl_.title = l10n.getTranslationOrError(tag); 172 }; 173 174 /** @type {remoting.WindowFrame} */ 175 remoting.windowFrame = null; 176