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 var DocumentNatives = requireNative('document_natives');
6 var ExtensionOptionsEvents =
7 require('extensionOptionsEvents').ExtensionOptionsEvents;
8 var GuestView = require('guestView').GuestView;
9 var GuestViewContainer = require('guestViewContainer').GuestViewContainer;
10 var GuestViewInternal =
11 require('binding').Binding.create('guestViewInternal').generate();
12 var IdGenerator = requireNative('id_generator');
13 var utils = require('utils');
15 // Mapping of the autosize attribute names to default values
16 var AUTO_SIZE_ATTRIBUTES = {
18 'maxheight': window.innerHeight,
19 'maxwidth': window.innerWidth,
24 function ExtensionOptionsImpl(extensionoptionsElement) {
25 GuestViewContainer.call(this, extensionoptionsElement, 'extensionoptions');
27 // on* Event handlers.
28 this.eventHandlers = {};
30 // setupEventProperty is normally called in extension_options_events.js to
31 // register events, but the createfailed event is registered here because
32 // the event is fired from here instead of through
33 // extension_options_events.js.
34 this.setupEventProperty('createfailed');
35 new ExtensionOptionsEvents(this, this.viewInstanceId);
37 this.autosizeDeferred = false;
39 this.setupElementProperties();
40 this.parseExtensionAttribute();
43 ExtensionOptionsImpl.prototype.__proto__ = GuestViewContainer.prototype;
45 ExtensionOptionsImpl.VIEW_TYPE = 'ExtensionOptions';
47 // Add extra functionality to |this.element|.
48 ExtensionOptionsImpl.setupElement = function(proto) {
51 'resumeDeferredAutoSize'
54 // Forward proto.foo* method calls to ExtensionOptionsImpl.foo*.
55 GuestViewContainer.forwardApiMethods(proto, apiMethods);
58 ExtensionOptionsImpl.prototype.onElementAttached = function() {
59 this.parseExtensionAttribute();
63 ExtensionOptionsImpl.prototype.buildAttachParams = function() {
65 'autosize': this.element.hasAttribute('autosize'),
66 'maxheight': parseInt(this.maxheight || 0),
67 'maxwidth': parseInt(this.maxwidth || 0),
68 'minheight': parseInt(this.minheight || 0),
69 'minwidth': parseInt(this.minwidth || 0)
74 ExtensionOptionsImpl.prototype.createGuest = function() {
75 if (!this.elementAttached) {
79 'extensionId': this.extensionId,
82 this.guest.create(params, function() {
83 if (!this.guest.getId()) {
84 // Fire a createfailed event here rather than in ExtensionOptionsGuest
85 // because the guest will not be created, and cannot fire an event.
86 this.initCalled = false;
87 var createFailedEvent = new Event('createfailed', { bubbles: true });
88 this.dispatchEvent(createFailedEvent);
95 ExtensionOptionsImpl.prototype.dispatchEvent =
96 function(extensionOptionsEvent) {
97 return this.element.dispatchEvent(extensionOptionsEvent);
100 ExtensionOptionsImpl.prototype.handleAttributeMutation =
101 function(name, oldValue, newValue) {
102 // We treat null attribute (attribute removed) and the empty string as
104 oldValue = oldValue || '';
105 newValue = newValue || '';
107 if (oldValue === newValue)
110 if (name == 'extension' && !oldValue && !!newValue) {
111 this.extensionId = newValue;
112 // If the browser plugin is not ready then don't create the guest until
113 // it is ready (in handleBrowserPluginAttributeMutation).
114 if (!this.internalInstanceId)
117 // If a guest view does not exist then create one.
118 if (!this.guest.getId()) {
122 // TODO(ericzeng): Implement navigation to another guest view if we want
123 // that functionality.
124 } else if (AUTO_SIZE_ATTRIBUTES.hasOwnProperty(name) > -1) {
125 this[name] = newValue;
126 this.resetSizeConstraintsIfInvalid();
128 if (!this.guest.getId())
132 'enableAutoSize': this.element.hasAttribute('autosize'),
134 'width': parseInt(this.minwidth || 0),
135 'height': parseInt(this.minheight || 0)
138 'width': parseInt(this.maxwidth || 0),
139 'height': parseInt(this.maxheight || 0)
145 ExtensionOptionsImpl.prototype.onSizeChanged =
146 function(newWidth, newHeight, oldWidth, oldHeight) {
147 if (this.autosizeDeferred) {
148 this.deferredAutoSizeState = {
150 newHeight: newHeight,
155 this.resize(newWidth, newHeight, oldWidth, oldHeight);
159 ExtensionOptionsImpl.prototype.parseExtensionAttribute = function() {
160 if (this.element.hasAttribute('extension')) {
161 this.extensionId = this.element.getAttribute('extension');
167 ExtensionOptionsImpl.prototype.resize =
168 function(newWidth, newHeight, oldWidth, oldHeight) {
169 this.element.style.width = newWidth + 'px';
170 this.element.style.height = newHeight + 'px';
172 // Do not allow the options page's dimensions to shrink. This ensures that the
173 // options page has a consistent UI. If the new size is larger than the
174 // minimum, make that the new minimum size.
175 if (newWidth > this.minwidth)
176 this.minwidth = newWidth;
177 if (newHeight > this.minheight)
178 this.minheight = newHeight;
181 'enableAutoSize': this.element.hasAttribute('autosize'),
183 'width': parseInt(this.minwidth || 0),
184 'height': parseInt(this.minheight || 0)
187 'width': parseInt(this.maxwidth || 0),
188 'height': parseInt(this.maxheight || 0)
193 // Adds an 'on<event>' property on the view, which can be used to set/unset
195 ExtensionOptionsImpl.prototype.setupEventProperty = function(eventName) {
196 var propertyName = 'on' + eventName.toLowerCase();
197 var element = this.element;
198 Object.defineProperty(element, propertyName, {
200 return this.eventHandlers[propertyName];
202 set: function(value) {
203 if (this.eventHandlers[propertyName])
204 element.removeEventListener(
205 eventName, this.eventHandlers[propertyName]);
206 this.eventHandlers[propertyName] = value;
208 element.addEventListener(eventName, value);
214 ExtensionOptionsImpl.prototype.setupElementProperties = function() {
215 utils.forEach(AUTO_SIZE_ATTRIBUTES, function(attributeName) {
216 // Get the size constraints from the <extensionoptions> tag, or use the
217 // defaults if not specified
218 if (this.element.hasAttribute(attributeName)) {
219 this[attributeName] =
220 this.element.getAttribute(attributeName);
222 this[attributeName] = AUTO_SIZE_ATTRIBUTES[attributeName];
225 Object.defineProperty(this.element, attributeName, {
227 return this[attributeName];
229 set: function(value) {
230 this.element.setAttribute(attributeName, value);
236 this.resetSizeConstraintsIfInvalid();
238 Object.defineProperty(this.element, 'extension', {
240 return this.extensionId;
242 set: function(value) {
243 this.element.setAttribute('extension', value);
249 ExtensionOptionsImpl.prototype.resetSizeConstraintsIfInvalid = function () {
250 if (this.minheight > this.maxheight || this.minheight < 0) {
251 this.minheight = AUTO_SIZE_ATTRIBUTES.minheight;
252 this.maxheight = AUTO_SIZE_ATTRIBUTES.maxheight;
254 if (this.minwidth > this.maxwidth || this.minwidth < 0) {
255 this.minwidth = AUTO_SIZE_ATTRIBUTES.minwidth;
256 this.maxwidth = AUTO_SIZE_ATTRIBUTES.maxwidth;
261 * Toggles whether the element should automatically resize to its preferred
262 * size. If set to true, when the element receives new autosize dimensions,
263 * it passes them to the embedder in a sizechanged event, but does not resize
264 * itself to those dimensions until the embedder calls resumeDeferredAutoSize.
265 * This allows the embedder to defer the resizing until it is ready.
266 * When set to false, the element resizes whenever it receives new autosize
269 ExtensionOptionsImpl.prototype.setDeferAutoSize = function(value) {
271 resumeDeferredAutoSize();
272 this.autosizeDeferred = value;
276 * Allows the element to resize to most recent set of autosize dimensions if
277 * autosizing is being deferred.
279 ExtensionOptionsImpl.prototype.resumeDeferredAutoSize = function() {
280 if (this.autosizeDeferred) {
281 this.resize(this.deferredAutoSizeState.newWidth,
282 this.deferredAutoSizeState.newHeight,
283 this.deferredAutoSizeState.oldWidth,
284 this.deferredAutoSizeState.oldHeight);
288 GuestViewContainer.registerElement(ExtensionOptionsImpl);