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.
5 cr.define('extensions', function() {
9 * The ExtensionOptionsOverlay will show an extension's options page using
10 * an <extensionoptions> element.
13 function ExtensionOptionsOverlay() {}
15 cr.addSingletonGetter(ExtensionOptionsOverlay);
17 ExtensionOptionsOverlay.prototype = {
19 * The function that shows the given element in the overlay.
20 * @type {?function(HTMLDivElement)} Function that receives the element to
21 * show in the overlay.
27 * Initialize the page.
28 * @param {function(HTMLDivElement)} showOverlay The function to show or
29 * hide the ExtensionOptionsOverlay; this should take a single parameter
30 * which is either the overlay Div if the overlay should be displayed,
31 * or null if the overlay should be hidden.
33 initializePage: function(showOverlay) {
34 var overlay = $('overlay');
36 cr.ui.overlay.setupOverlay(overlay);
37 cr.ui.overlay.globalInitialization();
38 overlay.addEventListener('cancelOverlay', this.handleDismiss_.bind(this));
40 this.showOverlay_ = showOverlay;
43 setInitialFocus: function() {
44 this.getExtensionOptions_().focus();
51 getExtensionOptions_: function() {
52 return $('extension-options-overlay-guest').querySelector(
57 * Handles a click on the close button.
58 * @param {Event} event The click event.
61 handleDismiss_: function(event) {
62 this.setVisible_(false);
63 var extensionoptions = this.getExtensionOptions_();
65 $('extension-options-overlay-guest').removeChild(extensionoptions);
67 $('extension-options-overlay-icon').removeAttribute('src');
69 // Remove the options query string.
70 uber.replaceState({}, '');
74 * Associate an extension with the overlay and display it.
75 * @param {string} extensionId The id of the extension whose options page
76 * should be displayed in the overlay.
77 * @param {string} extensionName The name of the extension, which is used
78 * as the header of the overlay.
79 * @param {string} extensionIcon The URL of the extension's icon.
80 * @param {function():void} shownCallback A function called when
82 * @suppress {checkTypes}
83 * TODO(vitalyp): remove the suppression after adding
84 * chrome/renderer/resources/extensions/extension_options.js
87 setExtensionAndShowOverlay: function(extensionId,
91 var overlay = $('extension-options-overlay');
92 var overlayHeader = $('extension-options-overlay-header');
93 var overlayGuest = $('extension-options-overlay-guest');
94 var overlayStyle = window.getComputedStyle(overlay);
96 $('extension-options-overlay-title').textContent = extensionName;
97 $('extension-options-overlay-icon').src = extensionIcon;
99 this.setVisible_(true);
101 var extensionoptions = new window.ExtensionOptions();
102 extensionoptions.extension = extensionId;
104 // The <extensionoptions> content's size needs to be restricted to the
105 // bounds of the overlay window. The overlay gives a minWidth and
106 // maxHeight, but the maxHeight does not include our header height (title
107 // and close button), so we need to subtract that to get the maxHeight
108 // for the extension options.
109 var maxHeight = parseInt(overlayStyle.maxHeight, 10) -
110 overlayHeader.offsetHeight;
111 var minWidth = parseInt(overlayStyle.minWidth, 10);
113 extensionoptions.onclose = function() {
114 cr.dispatchSimpleEvent($('overlay'), 'cancelOverlay');
117 // Track the current animation (used to grow/shrink the overlay content),
118 // if any. Preferred size changes can fire more rapidly than the
119 // animation speed, and multiple animations running at the same time has
120 // undesirable effects.
121 var animation = null;
124 * Resize the overlay if the <extensionoptions> changes preferred size.
125 * @param {{width: number, height: number}} evt
127 extensionoptions.onpreferredsizechanged = function(evt) {
128 var oldOverlayWidth = parseInt(overlayStyle.width, 10);
129 var oldOverlayHeight = parseInt(overlayStyle.height, 10);
130 // The overlay must be slightly larger than the extension options to
131 // avoid creating scrollbars.
132 // TODO(paulmeyer): This shouldn't be necessary, but the preferred size
133 // (coming from Blink) seems to be too small for some zoom levels. The
134 // 2-pixel addition should be removed once this problem is investigated
136 var newOverlayWidth = Math.max(evt.width + 2, minWidth);
137 // |evt.height| is just the new overlay guest height, and does not
138 // include the overlay header height, so it needs to be added.
139 var newOverlayHeight =
140 Math.min(evt.height + overlayHeader.offsetHeight + 2, maxHeight);
142 // animationTime is the amount of time in ms that will be used to resize
143 // the overlay. It is calculated by multiplying the pythagorean distance
144 // between old and the new size (in px) with a constant speed of
146 var loading = document.documentElement.classList.contains('loading');
147 var animationTime = loading ? 0 :
148 0.25 * Math.sqrt(Math.pow(newOverlayWidth - oldOverlayWidth, 2) +
149 Math.pow(newOverlayHeight - oldOverlayHeight, 2));
154 // The header height must be added to the (old and new) preferred
155 // heights to get the full overlay heights.
156 animation = overlay.animate([
157 {width: oldOverlayWidth + 'px', height: oldOverlayHeight + 'px'},
158 {width: newOverlayWidth + 'px', height: newOverlayHeight + 'px'}
160 duration: animationTime,
164 animation.onfinish = function(e) {
167 // The <extensionoptions> element is ready to place back in the
168 // overlay. Make sure that it's sized to take up the full width/height
170 overlayGuest.style.position = '';
171 overlayGuest.style.left = '';
172 overlayGuest.style.width = newOverlayWidth + 'px';
173 // |newOverlayHeight| includes the header height, so it needs to be
174 // subtracted to get the new guest height.
175 overlayGuest.style.height =
176 (newOverlayHeight - overlayHeader.offsetHeight) + 'px';
180 shownCallback = null;
185 // Move the <extensionoptions> off screen until the overlay is ready.
186 overlayGuest.style.position = 'fixed';
187 overlayGuest.style.left = window.outerWidth + 'px';
188 // Begin rendering at the default dimensions. This is also necessary to
189 // cancel any width/height set on a previous render.
190 // TODO(kalman): This causes a visual jag where the overlay guest shows
191 // up briefly. It would be better to render this off-screen first, then
192 // swap it in place. See crbug.com/408274.
193 // This may also solve crbug.com/431001 (width is 0 on initial render).
194 overlayGuest.style.width = '';
195 overlayGuest.style.height = '';
197 overlayGuest.appendChild(extensionoptions);
201 * Toggles the visibility of the ExtensionOptionsOverlay.
202 * @param {boolean} isVisible Whether the overlay should be visible.
205 setVisible_: function(isVisible) {
206 this.showOverlay_(isVisible ?
207 /** @type {HTMLDivElement} */($('extension-options-overlay')) :
214 ExtensionOptionsOverlay: ExtensionOptionsOverlay