ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chrome / browser / resources / extensions / extension_options_overlay.js
blob593407387c92883cf9af1c2aded9f72705745f02
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() {
6   'use strict';
8   /**
9    * The ExtensionOptionsOverlay will show an extension's options page using
10    * an <extensionoptions> element.
11    * @constructor
12    */
13   function ExtensionOptionsOverlay() {}
15   cr.addSingletonGetter(ExtensionOptionsOverlay);
17   ExtensionOptionsOverlay.prototype = {
18     /**
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.
22      * @private
23      */
24     showOverlay_: null,
26     /**
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.
32      */
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;
41     },
43     setInitialFocus: function() {
44       this.getExtensionOptions_().focus();
45     },
47     /**
48      * @return {?Element}
49      * @private
50      */
51     getExtensionOptions_: function() {
52       return $('extension-options-overlay-guest').querySelector(
53           'extensionoptions');
54     },
56     /**
57      * Handles a click on the close button.
58      * @param {Event} event The click event.
59      * @private
60      */
61     handleDismiss_: function(event) {
62       this.setVisible_(false);
63       var extensionoptions = this.getExtensionOptions_();
64       if (extensionoptions)
65         $('extension-options-overlay-guest').removeChild(extensionoptions);
67       $('extension-options-overlay-icon').removeAttribute('src');
69       // Remove the options query string.
70       uber.replaceState({}, '');
71     },
73     /**
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
81      *     showing completes.
82      * @suppress {checkTypes}
83      * TODO(vitalyp): remove the suppression after adding
84      * chrome/renderer/resources/extensions/extension_options.js
85      * to dependencies.
86      */
87     setExtensionAndShowOverlay: function(extensionId,
88                                          extensionName,
89                                          extensionIcon,
90                                          shownCallback) {
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(overlay.style.maxHeight, 10) -
110                       overlayHeader.offsetHeight;
111       var minWidth = parseInt(overlayStyle.minWidth, 10);
113       extensionoptions.onclose = function() {
114         cr.dispatchSimpleEvent($('overlay'), 'cancelOverlay');
115       }.bind(this);
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;
123       /**
124        * Resize the overlay if the <extensionoptions> changes preferred size.
125        * @param {{width: number, height: number}} evt
126        */
127       extensionoptions.onpreferredsizechanged = function(evt) {
128         var oldWidth = parseInt(overlayStyle.width, 10);
129         var oldHeight = 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
135         // and corrected.
136         var newWidth = Math.max(evt.width + 2, minWidth);
137         var newHeight = Math.min(evt.height + 2, maxHeight);
139         // animationTime is the amount of time in ms that will be used to resize
140         // the overlay. It is calculated by multiplying the pythagorean distance
141         // between old and the new size (in px) with a constant speed of
142         // 0.25 ms/px.
143         var loading = document.documentElement.classList.contains('loading');
144         var animationTime = loading ? 0 :
145             0.25 * Math.sqrt(Math.pow(newWidth - oldWidth, 2) +
146                              Math.pow(newHeight - oldHeight, 2));
148         if (animation)
149           animation.cancel();
151         animation = overlay.animate([
152           {width: oldWidth + 'px', height: oldHeight + 'px'},
153           {width: newWidth + 'px', height: newHeight + 'px'}
154         ], {
155           duration: animationTime,
156           delay: 0
157         });
159         animation.onfinish = function(e) {
160           animation = null;
162           // The <extensionoptions> element is ready to place back in the
163           // overlay. Make sure that it's sized to take up the full width/height
164           // of the overlay.
165           overlayGuest.style.position = '';
166           overlayGuest.style.left = '';
167           overlayGuest.style.width = newWidth + 'px';
168           overlayGuest.style.height = newHeight + 'px';
170           if (shownCallback) {
171             shownCallback();
172             shownCallback = null;
173           }
174         };
175       }.bind(this);
177       // Move the <extensionoptions> off screen until the overlay is ready.
178       overlayGuest.style.position = 'fixed';
179       overlayGuest.style.left = window.outerWidth + 'px';
180       // Begin rendering at the default dimensions. This is also necessary to
181       // cancel any width/height set on a previous render.
182       // TODO(kalman): This causes a visual jag where the overlay guest shows
183       // up briefly. It would be better to render this off-screen first, then
184       // swap it in place. See crbug.com/408274.
185       // This may also solve crbug.com/431001 (width is 0 on initial render).
186       overlayGuest.style.width = '';
187       overlayGuest.style.height = '';
189       overlayGuest.appendChild(extensionoptions);
190     },
192     /**
193      * Toggles the visibility of the ExtensionOptionsOverlay.
194      * @param {boolean} isVisible Whether the overlay should be visible.
195      * @private
196      */
197     setVisible_: function(isVisible) {
198       this.showOverlay_(isVisible ?
199           /** @type {HTMLDivElement} */($('extension-options-overlay')) :
200           null);
201     }
202   };
204   // Export
205   return {
206     ExtensionOptionsOverlay: ExtensionOptionsOverlay
207   };