- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / resources / help / help_base_page.js
1 // Copyright 2013 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 // Helper base class for all help pages and overlays, which controls
6 // overlays, focus and scroll. This class is partially based on
7 // OptionsPage, but simpler and contains only overlay- and focus-
8 // handling logic. As in OptionsPage each page can be an overlay itself,
9 // but each page contains its own list of registered overlays which can be
10 // displayed over it.
11 //
12 // TODO (ygorshenin@): crbug.com/313244.
13 cr.define('help', function() {
14   function HelpBasePage() {
15   }
16
17   HelpBasePage.prototype = {
18     __proto__: HTMLDivElement.prototype,
19
20     /**
21      * name of the page, should be the same as an id of the
22      * corresponding HTMLDivElement.
23      */
24     name: null,
25
26     /**
27      * HTML counterpart of this page.
28      */
29     pageDiv: null,
30
31     /**
32      * True if current page is overlay.
33      */
34     isOverlay: false,
35
36     /**
37      * HTMLElement that was last focused when this page was the
38      * topmost.
39      */
40     lastFocusedElement: null,
41
42     /**
43      * State of vertical scrollbars when this page was the topmost.
44      */
45     lastScrollTop: 0,
46
47     /**
48      * Dictionary of registered overlays.
49      */
50     registeredOverlays: {},
51
52     /**
53      * Stores currently focused element.
54      * @private
55      */
56     storeLastFocusedElement_: function() {
57       if (this.pageDiv.contains(document.activeElement))
58         this.lastFocusedElement = document.activeElement;
59     },
60
61     /**
62      * Restores focus to the last focused element on this page.
63      * @private
64      */
65     restoreLastFocusedElement_: function() {
66       if (this.lastFocusedElement)
67         this.lastFocusedElement.focus();
68       else
69         this.focus();
70     },
71
72     /**
73      * Shows or hides current page iff it's an overlay.
74      * @param {boolean} visible True if overlay should be displayed.
75      * @private
76      */
77     setOverlayVisible_: function(visible) {
78       assert(this.isOverlay);
79       var pageDiv = this.pageDiv;
80       this.container.hidden = !visible;
81       if (visible)
82         pageDiv.classList.add('showing');
83       else
84         pageDiv.classList.remove('showing');
85     },
86
87     /**
88      * @return {HTMLDivElement}  visible non-overlay page or
89      * null, if there are no visible non-overlay pages.
90      * @private
91      */
92     getVisibleNonOverlay_: function() {
93       if (this.isOverlay || !this.visible)
94         return null;
95       return this;
96     },
97
98     /**
99      * @return {HTMLDivElement} Visible overlay page, or null,
100      * if there are no visible overlay pages.
101      * @private
102      */
103     getVisibleOverlay_: function() {
104       for (var name in this.registeredOverlays) {
105         var overlay = this.registeredOverlays[name];
106         if (overlay.visible)
107           return overlay;
108       }
109       return null;
110     },
111
112     /**
113      * Freezes current page, makes it impossible to scroll it.
114      * @param {boolean} freeze True if the page should be frozen.
115      * @private
116      */
117     freeze_: function(freeze) {
118       if (freeze) {
119         this.lastScrollTop = document.documentElement.scrollTop;
120         document.body.style.overflow = 'hidden';
121         window.scroll(document.body.scrollLeft, 0);
122       } else {
123         document.body.style.overflow = 'auto';
124         window.scroll(document.body.scrollLeft, this.lastScrollTop);
125       }
126     },
127
128     /**
129      * Initializes current page.
130      * @param {string} name Name of the current page.
131      */
132     initialize: function(name) {
133       this.name = name;
134       this.pageDiv = $(name);
135     },
136
137     /**
138      * @return {HTMLDivElement} Topmost visible page, or null, if
139      * there are no visible pages.
140      */
141     getTopmostVisiblePage: function() {
142       return this.getVisibleOverlay_() || this.getVisibleNonOverlay_();
143     },
144
145     /**
146      * Registers overlay.
147      * @param {HelpBasePage} overlay Overlay that should be registered.
148      */
149     registerOverlay: function(overlay) {
150       this.registeredOverlays[overlay.name] = overlay;
151       overlay.isOverlay = true;
152     },
153
154     /**
155      * Shows or hides current page.
156      * @param {boolean} visible True if current page should be displayed.
157      */
158     set visible(visible) {
159       if (this.visible == visible)
160         return;
161
162       if (!visible)
163         this.storeLastFocusedElement_();
164
165       if (this.isOverlay)
166         this.setOverlayVisible_(visible);
167       else
168         this.pageDiv.hidden = !visible;
169
170       if (visible)
171         this.restoreLastFocusedElement_();
172     },
173
174     /**
175      * Returns true if current page is visible.
176      * @return {boolean} True if current page is visible.
177      */
178     get visible() {
179       if (this.isOverlay)
180         return this.pageDiv.classList.contains('showing');
181       return !this.pageDiv.hidden;
182     },
183
184     /**
185      * This method returns overlay container, it should be called only
186      * on overlays.
187      * @return {HTMLDivElement} overlay container.
188      */
189     get container() {
190       assert(this.isOverlay);
191       return this.pageDiv.parentNode;
192     },
193
194     /**
195      * Shows registered overlay.
196      * @param {string} name Name of registered overlay to show.
197      */
198     showOverlay: function(name) {
199       var currentPage = this.getTopmostVisiblePage();
200       currentPage.storeLastFocusedElement_();
201       currentPage.freeze_(true);
202
203       var overlay = this.registeredOverlays[name];
204       if (!overlay)
205         return;
206       overlay.visible = true;
207     },
208
209     /**
210      * Hides currently displayed overlay.
211      */
212     closeOverlay: function() {
213       var overlay = this.getVisibleOverlay_();
214       if (!overlay)
215         return;
216       overlay.visible = false;
217
218       var currentPage = this.getTopmostVisiblePage();
219       currentPage.restoreLastFocusedElement_();
220       currentPage.freeze_(false);
221     },
222
223     /**
224      * If the page does not contain focused elements, focuses on the
225      * first appropriate.
226      */
227     focus: function() {
228       if (this.pageDiv.contains(document.activeElement))
229         return;
230       var elements = this.pageDiv.querySelectorAll(
231         'input, list, select, textarea, button');
232       for (var i = 0; i < elements.length; i++) {
233         var element = elements[i];
234         element.focus();
235         if (document.activeElement == element)
236           return;
237       }
238     },
239   };
240
241   // Export
242   return {
243     HelpBasePage: HelpBasePage
244   };
245 });