Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / renderer / resources / extensions / app_window_custom_bindings.js
1 // Copyright (c) 2012 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 // Custom binding for the app_window API.
6
7 var appWindowNatives = requireNative('app_window_natives');
8 var runtimeNatives = requireNative('runtime');
9 var Binding = require('binding').Binding;
10 var Event = require('event_bindings').Event;
11 var forEach = require('utils').forEach;
12 var renderViewObserverNatives = requireNative('renderViewObserverNatives');
13
14 var appWindowData = null;
15 var currentAppWindow = null;
16
17 var appWindow = Binding.create('app.window');
18 appWindow.registerCustomHook(function(bindingsAPI) {
19   var apiFunctions = bindingsAPI.apiFunctions;
20
21   apiFunctions.setCustomCallback('create',
22                                  function(name, request, windowParams) {
23     var view = null;
24     if (windowParams.viewId) {
25       view = appWindowNatives.GetView(
26           windowParams.viewId, windowParams.injectTitlebar);
27     }
28
29     if (!view) {
30       // No route to created window. If given a callback, trigger it with an
31       // undefined object.
32       if (request.callback) {
33         request.callback();
34         delete request.callback;
35       }
36       return;
37     }
38
39     if (windowParams.existingWindow) {
40       // Not creating a new window, but activating an existing one, so trigger
41       // callback with existing window and don't do anything else.
42       if (request.callback) {
43         request.callback(view.chrome.app.window.current());
44         delete request.callback;
45       }
46       return;
47     }
48
49     // Initialize appWindowData in the newly created JS context
50     view.chrome.app.window.initializeAppWindow(windowParams);
51
52     var callback = request.callback;
53     if (callback) {
54       delete request.callback;
55       if (!view) {
56         callback(undefined);
57         return;
58       }
59
60       var willCallback =
61           renderViewObserverNatives.OnDocumentElementCreated(
62               windowParams.viewId,
63               function(success) {
64                 if (success) {
65                   callback(view.chrome.app.window.current());
66                 } else {
67                   callback(undefined);
68                 }
69               });
70       if (!willCallback) {
71         callback(undefined);
72       }
73     }
74   });
75
76   apiFunctions.setHandleRequest('current', function() {
77     if (!currentAppWindow) {
78       console.error('The JavaScript context calling ' +
79                     'chrome.app.window.current() has no associated AppWindow.');
80       return null;
81     }
82     return currentAppWindow;
83   });
84
85   apiFunctions.setHandleRequest('getAll', function() {
86     var views = runtimeNatives.GetExtensionViews(-1, 'SHELL');
87     return $Array.map(views, function(win) {
88       return win.chrome.app.window.current();
89     });
90   });
91
92   apiFunctions.setHandleRequest('get', function(id) {
93     var windows = $Array.filter(chrome.app.window.getAll(), function(win) {
94       return win.id == id;
95     });
96     return windows.length > 0 ? windows[0] : null;
97   });
98
99   // This is an internal function, but needs to be bound with setHandleRequest
100   // because it is called from a different JS context.
101   apiFunctions.setHandleRequest('initializeAppWindow', function(params) {
102     var currentWindowInternal =
103         Binding.create('app.currentWindowInternal').generate();
104     var AppWindow = function() {};
105     forEach(currentWindowInternal, function(key, value) {
106       AppWindow.prototype[key] = value;
107     });
108     AppWindow.prototype.moveTo = $Function.bind(window.moveTo, window);
109     AppWindow.prototype.resizeTo = $Function.bind(window.resizeTo, window);
110     AppWindow.prototype.contentWindow = window;
111     AppWindow.prototype.onClosed = new Event();
112     AppWindow.prototype.close = function() {
113       this.contentWindow.close();
114     };
115     AppWindow.prototype.getBounds = function() {
116       var bounds = appWindowData.bounds;
117       return { left: bounds.left, top: bounds.top,
118                width: bounds.width, height: bounds.height };
119     };
120     AppWindow.prototype.getMinWidth = function() {
121       return appWindowData.minWidth;
122     };
123     AppWindow.prototype.getMinHeight = function() {
124       return appWindowData.minHeight;
125     };
126     AppWindow.prototype.getMaxWidth = function() {
127       return appWindowData.maxWidth;
128     };
129     AppWindow.prototype.getMaxHeight = function() {
130       return appWindowData.maxHeight;
131     };
132     AppWindow.prototype.isFullscreen = function() {
133       return appWindowData.fullscreen;
134     };
135     AppWindow.prototype.isMinimized = function() {
136       return appWindowData.minimized;
137     };
138     AppWindow.prototype.isMaximized = function() {
139       return appWindowData.maximized;
140     };
141     AppWindow.prototype.isAlwaysOnTop = function() {
142       return appWindowData.alwaysOnTop;
143     };
144
145     Object.defineProperty(AppWindow.prototype, 'id', {get: function() {
146       return appWindowData.id;
147     }});
148
149     appWindowData = {
150       id: params.id || '',
151       bounds: { left: params.bounds.left, top: params.bounds.top,
152                 width: params.bounds.width, height: params.bounds.height },
153       minWidth: params.minWidth,
154       minHeight: params.minHeight,
155       maxWidth: params.maxWidth,
156       maxHeight: params.maxHeight,
157       fullscreen: params.fullscreen,
158       minimized: params.minimized,
159       maximized: params.maximized,
160       alwaysOnTop: params.alwaysOnTop
161     };
162     currentAppWindow = new AppWindow;
163   });
164 });
165
166 function boundsEqual(bounds1, bounds2) {
167   if (!bounds1 || !bounds2)
168     return false;
169   return (bounds1.left == bounds2.left && bounds1.top == bounds2.top &&
170           bounds1.width == bounds2.width && bounds1.height == bounds2.height);
171 }
172
173 function dispatchEventIfExists(target, name) {
174   // Sometimes apps like to put their own properties on the window which
175   // break our assumptions.
176   var event = target[name];
177   if (event && (typeof event.dispatch == 'function'))
178     event.dispatch();
179   else
180     console.warn('Could not dispatch ' + name + ', event has been clobbered');
181 }
182
183 function updateAppWindowProperties(update) {
184   if (!appWindowData)
185     return;
186
187   var oldData = appWindowData;
188   update.id = oldData.id;
189   appWindowData = update;
190
191   var currentWindow = currentAppWindow;
192
193   if (!boundsEqual(oldData.bounds, update.bounds))
194     dispatchEventIfExists(currentWindow, "onBoundsChanged");
195
196   if (!oldData.fullscreen && update.fullscreen)
197     dispatchEventIfExists(currentWindow, "onFullscreened");
198   if (!oldData.minimized && update.minimized)
199     dispatchEventIfExists(currentWindow, "onMinimized");
200   if (!oldData.maximized && update.maximized)
201     dispatchEventIfExists(currentWindow, "onMaximized");
202
203   if ((oldData.fullscreen && !update.fullscreen) ||
204       (oldData.minimized && !update.minimized) ||
205       (oldData.maximized && !update.maximized))
206     dispatchEventIfExists(currentWindow, "onRestored");
207 };
208
209 function onAppWindowClosed() {
210   if (!currentAppWindow)
211     return;
212   dispatchEventIfExists(currentAppWindow, "onClosed");
213 }
214
215 exports.binding = appWindow.generate();
216 exports.onAppWindowClosed = onAppWindowClosed;
217 exports.updateAppWindowProperties = updateAppWindowProperties;