| Index: extensions/renderer/resources/web_view.js
|
| diff --git a/extensions/renderer/resources/web_view.js b/extensions/renderer/resources/web_view.js
|
| deleted file mode 100644
|
| index 3965e6106a67f1cc16eeac40817c1283af41aedf..0000000000000000000000000000000000000000
|
| --- a/extensions/renderer/resources/web_view.js
|
| +++ /dev/null
|
| @@ -1,936 +0,0 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -// This module implements WebView (<webview>) as a custom element that wraps a
|
| -// BrowserPlugin object element. The object element is hidden within
|
| -// the shadow DOM of the WebView element.
|
| -
|
| -var DocumentNatives = requireNative('document_natives');
|
| -var GuestViewInternal =
|
| - require('binding').Binding.create('guestViewInternal').generate();
|
| -var IdGenerator = requireNative('id_generator');
|
| -// TODO(lazyboy): Rename this to WebViewInternal and call WebViewInternal
|
| -// something else.
|
| -var WebView = require('webViewInternal').WebView;
|
| -var WebViewEvents = require('webViewEvents').WebViewEvents;
|
| -var guestViewInternalNatives = requireNative('guest_view_internal');
|
| -
|
| -// Attributes.
|
| -var WEB_VIEW_ATTRIBUTE_ALLOWTRANSPARENCY = 'allowtransparency';
|
| -var WEB_VIEW_ATTRIBUTE_AUTOSIZE = 'autosize';
|
| -var WEB_VIEW_ATTRIBUTE_MAXHEIGHT = 'maxheight';
|
| -var WEB_VIEW_ATTRIBUTE_MAXWIDTH = 'maxwidth';
|
| -var WEB_VIEW_ATTRIBUTE_MINHEIGHT = 'minheight';
|
| -var WEB_VIEW_ATTRIBUTE_MINWIDTH = 'minwidth';
|
| -var WEB_VIEW_ATTRIBUTE_PARTITION = 'partition';
|
| -var AUTO_SIZE_ATTRIBUTES = [
|
| - WEB_VIEW_ATTRIBUTE_AUTOSIZE,
|
| - WEB_VIEW_ATTRIBUTE_MAXHEIGHT,
|
| - WEB_VIEW_ATTRIBUTE_MAXWIDTH,
|
| - WEB_VIEW_ATTRIBUTE_MINHEIGHT,
|
| - WEB_VIEW_ATTRIBUTE_MINWIDTH
|
| -];
|
| -
|
| -// Error messages.
|
| -var ERROR_MSG_ALREADY_NAVIGATED =
|
| - 'The object has already navigated, so its partition cannot be changed.';
|
| -var ERROR_MSG_CANNOT_INJECT_SCRIPT = '<webview>: ' +
|
| - 'Script cannot be injected into content until the page has loaded.';
|
| -var ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE = '<webview>: ' +
|
| - 'contentWindow is not available at this time. It will become available ' +
|
| - 'when the page has finished loading.';
|
| -var ERROR_MSG_INVALID_PARTITION_ATTRIBUTE = 'Invalid partition attribute.';
|
| -
|
| -// Represents the state of the storage partition.
|
| -function Partition() {
|
| - this.validPartitionId = true;
|
| - this.persistStorage = false;
|
| - this.storagePartitionId = '';
|
| -}
|
| -
|
| -Partition.prototype.toAttribute = function() {
|
| - if (!this.validPartitionId) {
|
| - return '';
|
| - }
|
| - return (this.persistStorage ? 'persist:' : '') + this.storagePartitionId;
|
| -};
|
| -
|
| -Partition.prototype.fromAttribute = function(value, hasNavigated) {
|
| - var result = {};
|
| - if (hasNavigated) {
|
| - result.error = ERROR_MSG_ALREADY_NAVIGATED;
|
| - return result;
|
| - }
|
| - if (!value) {
|
| - value = '';
|
| - }
|
| -
|
| - var LEN = 'persist:'.length;
|
| - if (value.substr(0, LEN) == 'persist:') {
|
| - value = value.substr(LEN);
|
| - if (!value) {
|
| - this.validPartitionId = false;
|
| - result.error = ERROR_MSG_INVALID_PARTITION_ATTRIBUTE;
|
| - return result;
|
| - }
|
| - this.persistStorage = true;
|
| - } else {
|
| - this.persistStorage = false;
|
| - }
|
| -
|
| - this.storagePartitionId = value;
|
| - return result;
|
| -};
|
| -
|
| -// Represents the internal state of the WebView node.
|
| -function WebViewInternal(webviewNode) {
|
| - privates(webviewNode).internal = this;
|
| - this.webviewNode = webviewNode;
|
| - this.attached = false;
|
| - this.pendingGuestCreation = false;
|
| - this.elementAttached = false;
|
| -
|
| - this.beforeFirstNavigation = true;
|
| - this.contentWindow = null;
|
| - this.validPartitionId = true;
|
| - // Used to save some state upon deferred attachment.
|
| - // If <object> bindings is not available, we defer attachment.
|
| - // This state contains whether or not the attachment request was for
|
| - // newwindow.
|
| - this.deferredAttachState = null;
|
| -
|
| - // on* Event handlers.
|
| - this.on = {};
|
| -
|
| - this.browserPluginNode = this.createBrowserPluginNode();
|
| - var shadowRoot = this.webviewNode.createShadowRoot();
|
| - this.partition = new Partition();
|
| -
|
| - this.setupWebViewSrcAttributeMutationObserver();
|
| - this.setupFocusPropagation();
|
| - this.setupWebviewNodeProperties();
|
| -
|
| - this.viewInstanceId = IdGenerator.GetNextId();
|
| -
|
| - new WebViewEvents(this, this.viewInstanceId);
|
| -
|
| - shadowRoot.appendChild(this.browserPluginNode);
|
| -}
|
| -
|
| -WebViewInternal.prototype.createBrowserPluginNode = function() {
|
| - // We create BrowserPlugin as a custom element in order to observe changes
|
| - // to attributes synchronously.
|
| - var browserPluginNode = new WebViewInternal.BrowserPlugin();
|
| - privates(browserPluginNode).internal = this;
|
| - return browserPluginNode;
|
| -};
|
| -
|
| -WebViewInternal.prototype.getGuestInstanceId = function() {
|
| - return this.guestInstanceId;
|
| -};
|
| -
|
| -// Resets some state upon reattaching <webview> element to the DOM.
|
| -WebViewInternal.prototype.reset = function() {
|
| - // If guestInstanceId is defined then the <webview> has navigated and has
|
| - // already picked up a partition ID. Thus, we need to reset the initialization
|
| - // state. However, it may be the case that beforeFirstNavigation is false BUT
|
| - // guestInstanceId has yet to be initialized. This means that we have not
|
| - // heard back from createGuest yet. We will not reset the flag in this case so
|
| - // that we don't end up allocating a second guest.
|
| - if (this.guestInstanceId) {
|
| - GuestViewInternal.destroyGuest(this.guestInstanceId);
|
| - this.guestInstanceId = undefined;
|
| - this.beforeFirstNavigation = true;
|
| - this.validPartitionId = true;
|
| - this.partition.validPartitionId = true;
|
| - this.contentWindow = null;
|
| - }
|
| - this.internalInstanceId = 0;
|
| -};
|
| -
|
| -// Sets the <webview>.request property.
|
| -WebViewInternal.prototype.setRequestPropertyOnWebViewNode = function(request) {
|
| - Object.defineProperty(
|
| - this.webviewNode,
|
| - 'request',
|
| - {
|
| - value: request,
|
| - enumerable: true
|
| - }
|
| - );
|
| -};
|
| -
|
| -WebViewInternal.prototype.setupFocusPropagation = function() {
|
| - if (!this.webviewNode.hasAttribute('tabIndex')) {
|
| - // <webview> needs a tabIndex in order to be focusable.
|
| - // TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute
|
| - // to allow <webview> to be focusable.
|
| - // See http://crbug.com/231664.
|
| - this.webviewNode.setAttribute('tabIndex', -1);
|
| - }
|
| - this.webviewNode.addEventListener('focus', function(e) {
|
| - // Focus the BrowserPlugin when the <webview> takes focus.
|
| - this.browserPluginNode.focus();
|
| - }.bind(this));
|
| - this.webviewNode.addEventListener('blur', function(e) {
|
| - // Blur the BrowserPlugin when the <webview> loses focus.
|
| - this.browserPluginNode.blur();
|
| - }.bind(this));
|
| -};
|
| -
|
| -// Validation helper function for executeScript() and insertCSS().
|
| -WebViewInternal.prototype.validateExecuteCodeCall = function() {
|
| - if (!this.guestInstanceId) {
|
| - throw new Error(ERROR_MSG_CANNOT_INJECT_SCRIPT);
|
| - }
|
| -};
|
| -
|
| -WebViewInternal.prototype.setupAutoSizeProperties = function() {
|
| - $Array.forEach(AUTO_SIZE_ATTRIBUTES, function(attributeName) {
|
| - this[attributeName] = this.webviewNode.getAttribute(attributeName);
|
| - Object.defineProperty(this.webviewNode, attributeName, {
|
| - get: function() {
|
| - return this[attributeName];
|
| - }.bind(this),
|
| - set: function(value) {
|
| - this.webviewNode.setAttribute(attributeName, value);
|
| - }.bind(this),
|
| - enumerable: true
|
| - });
|
| - }.bind(this), this);
|
| -};
|
| -
|
| -WebViewInternal.prototype.setupWebviewNodeProperties = function() {
|
| - this.setupAutoSizeProperties();
|
| -
|
| - Object.defineProperty(this.webviewNode,
|
| - WEB_VIEW_ATTRIBUTE_ALLOWTRANSPARENCY, {
|
| - get: function() {
|
| - return this.allowtransparency;
|
| - }.bind(this),
|
| - set: function(value) {
|
| - this.webviewNode.setAttribute(WEB_VIEW_ATTRIBUTE_ALLOWTRANSPARENCY,
|
| - value);
|
| - }.bind(this),
|
| - enumerable: true
|
| - });
|
| -
|
| - // We cannot use {writable: true} property descriptor because we want a
|
| - // dynamic getter value.
|
| - Object.defineProperty(this.webviewNode, 'contentWindow', {
|
| - get: function() {
|
| - if (this.contentWindow) {
|
| - return this.contentWindow;
|
| - }
|
| - window.console.error(ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE);
|
| - }.bind(this),
|
| - // No setter.
|
| - enumerable: true
|
| - });
|
| -
|
| - Object.defineProperty(this.webviewNode, 'name', {
|
| - get: function() {
|
| - return this.name;
|
| - }.bind(this),
|
| - set: function(value) {
|
| - this.webviewNode.setAttribute('name', value);
|
| - }.bind(this),
|
| - enumerable: true
|
| - });
|
| -
|
| - Object.defineProperty(this.webviewNode, 'partition', {
|
| - get: function() {
|
| - return this.partition.toAttribute();
|
| - }.bind(this),
|
| - set: function(value) {
|
| - var result = this.partition.fromAttribute(value, this.hasNavigated());
|
| - if (result.error) {
|
| - throw result.error;
|
| - }
|
| - this.webviewNode.setAttribute('partition', value);
|
| - }.bind(this),
|
| - enumerable: true
|
| - });
|
| -
|
| - this.src = this.webviewNode.getAttribute('src');
|
| - Object.defineProperty(this.webviewNode, 'src', {
|
| - get: function() {
|
| - return this.src;
|
| - }.bind(this),
|
| - set: function(value) {
|
| - this.webviewNode.setAttribute('src', value);
|
| - }.bind(this),
|
| - // No setter.
|
| - enumerable: true
|
| - });
|
| -};
|
| -
|
| -// The purpose of this mutation observer is to catch assignment to the src
|
| -// attribute without any changes to its value. This is useful in the case
|
| -// where the webview guest has crashed and navigating to the same address
|
| -// spawns off a new process.
|
| -WebViewInternal.prototype.setupWebViewSrcAttributeMutationObserver =
|
| - function() {
|
| - this.srcAndPartitionObserver = new MutationObserver(function(mutations) {
|
| - $Array.forEach(mutations, function(mutation) {
|
| - var oldValue = mutation.oldValue;
|
| - var newValue = this.webviewNode.getAttribute(mutation.attributeName);
|
| - if (oldValue != newValue) {
|
| - return;
|
| - }
|
| - this.handleWebviewAttributeMutation(
|
| - mutation.attributeName, oldValue, newValue);
|
| - }.bind(this));
|
| - }.bind(this));
|
| - var params = {
|
| - attributes: true,
|
| - attributeOldValue: true,
|
| - attributeFilter: ['src', 'partition']
|
| - };
|
| - this.srcAndPartitionObserver.observe(this.webviewNode, params);
|
| -};
|
| -
|
| -// This observer monitors mutations to attributes of the <webview> and
|
| -// updates the BrowserPlugin properties accordingly. In turn, updating
|
| -// a BrowserPlugin property will update the corresponding BrowserPlugin
|
| -// attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more
|
| -// details.
|
| -WebViewInternal.prototype.handleWebviewAttributeMutation =
|
| - function(name, oldValue, newValue) {
|
| - if (AUTO_SIZE_ATTRIBUTES.indexOf(name) > -1) {
|
| - this[name] = newValue;
|
| - if (!this.guestInstanceId) {
|
| - return;
|
| - }
|
| - // Convert autosize attribute to boolean.
|
| - var autosize = this.webviewNode.hasAttribute(WEB_VIEW_ATTRIBUTE_AUTOSIZE);
|
| - GuestViewInternal.setAutoSize(this.guestInstanceId, {
|
| - 'enableAutoSize': autosize,
|
| - 'min': {
|
| - 'width': parseInt(this.minwidth || 0),
|
| - 'height': parseInt(this.minheight || 0)
|
| - },
|
| - 'max': {
|
| - 'width': parseInt(this.maxwidth || 0),
|
| - 'height': parseInt(this.maxheight || 0)
|
| - }
|
| - });
|
| - return;
|
| - } else if (name == WEB_VIEW_ATTRIBUTE_ALLOWTRANSPARENCY) {
|
| - // We treat null attribute (attribute removed) and the empty string as
|
| - // one case.
|
| - oldValue = oldValue || '';
|
| - newValue = newValue || '';
|
| -
|
| - if (oldValue === newValue) {
|
| - return;
|
| - }
|
| - this.allowtransparency = newValue != '';
|
| -
|
| - if (!this.guestInstanceId) {
|
| - return;
|
| - }
|
| -
|
| - WebView.setAllowTransparency(this.guestInstanceId, this.allowtransparency);
|
| - return;
|
| - } else if (name == 'name') {
|
| - // We treat null attribute (attribute removed) and the empty string as
|
| - // one case.
|
| - oldValue = oldValue || '';
|
| - newValue = newValue || '';
|
| -
|
| - if (oldValue === newValue) {
|
| - return;
|
| - }
|
| - this.name = newValue;
|
| - if (!this.guestInstanceId) {
|
| - return;
|
| - }
|
| - WebView.setName(this.guestInstanceId, newValue);
|
| - return;
|
| - } else if (name == 'src') {
|
| - // We treat null attribute (attribute removed) and the empty string as
|
| - // one case.
|
| - oldValue = oldValue || '';
|
| - newValue = newValue || '';
|
| - // Once we have navigated, we don't allow clearing the src attribute.
|
| - // Once <webview> enters a navigated state, it cannot be return back to a
|
| - // placeholder state.
|
| - if (newValue == '' && oldValue != '') {
|
| - // src attribute changes normally initiate a navigation. We suppress
|
| - // the next src attribute handler call to avoid reloading the page
|
| - // on every guest-initiated navigation.
|
| - this.ignoreNextSrcAttributeChange = true;
|
| - this.webviewNode.setAttribute('src', oldValue);
|
| - return;
|
| - }
|
| - this.src = newValue;
|
| - if (this.ignoreNextSrcAttributeChange) {
|
| - // Don't allow the src mutation observer to see this change.
|
| - this.srcAndPartitionObserver.takeRecords();
|
| - this.ignoreNextSrcAttributeChange = false;
|
| - return;
|
| - }
|
| - var result = {};
|
| - this.parseSrcAttribute(result);
|
| -
|
| - if (result.error) {
|
| - throw result.error;
|
| - }
|
| - } else if (name == 'partition') {
|
| - // Note that throwing error here won't synchronously propagate.
|
| - this.partition.fromAttribute(newValue, this.hasNavigated());
|
| - }
|
| -};
|
| -
|
| -WebViewInternal.prototype.handleBrowserPluginAttributeMutation =
|
| - function(name, oldValue, newValue) {
|
| - if (name == 'internalinstanceid' && !oldValue && !!newValue) {
|
| - this.browserPluginNode.removeAttribute('internalinstanceid');
|
| - this.internalInstanceId = parseInt(newValue);
|
| -
|
| - if (!!this.guestInstanceId && this.guestInstanceId != 0) {
|
| - var isNewWindow = this.deferredAttachState ?
|
| - this.deferredAttachState.isNewWindow : false;
|
| - var params = this.buildAttachParams(isNewWindow);
|
| - guestViewInternalNatives.AttachGuest(
|
| - this.internalInstanceId,
|
| - this.guestInstanceId,
|
| - params,
|
| - function(w) {
|
| - this.contentWindow = w;
|
| - }.bind(this)
|
| - );
|
| - }
|
| -
|
| - return;
|
| - }
|
| -};
|
| -
|
| -WebViewInternal.prototype.onSizeChanged = function(webViewEvent) {
|
| - var newWidth = webViewEvent.newWidth;
|
| - var newHeight = webViewEvent.newHeight;
|
| -
|
| - var node = this.webviewNode;
|
| -
|
| - var width = node.offsetWidth;
|
| - var height = node.offsetHeight;
|
| -
|
| - // Check the current bounds to make sure we do not resize <webview>
|
| - // outside of current constraints.
|
| - var maxWidth;
|
| - if (node.hasAttribute(WEB_VIEW_ATTRIBUTE_MAXWIDTH) &&
|
| - node[WEB_VIEW_ATTRIBUTE_MAXWIDTH]) {
|
| - maxWidth = node[WEB_VIEW_ATTRIBUTE_MAXWIDTH];
|
| - } else {
|
| - maxWidth = width;
|
| - }
|
| -
|
| - var minWidth;
|
| - if (node.hasAttribute(WEB_VIEW_ATTRIBUTE_MINWIDTH) &&
|
| - node[WEB_VIEW_ATTRIBUTE_MINWIDTH]) {
|
| - minWidth = node[WEB_VIEW_ATTRIBUTE_MINWIDTH];
|
| - } else {
|
| - minWidth = width;
|
| - }
|
| - if (minWidth > maxWidth) {
|
| - minWidth = maxWidth;
|
| - }
|
| -
|
| - var maxHeight;
|
| - if (node.hasAttribute(WEB_VIEW_ATTRIBUTE_MAXHEIGHT) &&
|
| - node[WEB_VIEW_ATTRIBUTE_MAXHEIGHT]) {
|
| - maxHeight = node[WEB_VIEW_ATTRIBUTE_MAXHEIGHT];
|
| - } else {
|
| - maxHeight = height;
|
| - }
|
| -
|
| - var minHeight;
|
| - if (node.hasAttribute(WEB_VIEW_ATTRIBUTE_MINHEIGHT) &&
|
| - node[WEB_VIEW_ATTRIBUTE_MINHEIGHT]) {
|
| - minHeight = node[WEB_VIEW_ATTRIBUTE_MINHEIGHT];
|
| - } else {
|
| - minHeight = height;
|
| - }
|
| - if (minHeight > maxHeight) {
|
| - minHeight = maxHeight;
|
| - }
|
| -
|
| - if (!this.webviewNode.hasAttribute(WEB_VIEW_ATTRIBUTE_AUTOSIZE) ||
|
| - (newWidth >= minWidth &&
|
| - newWidth <= maxWidth &&
|
| - newHeight >= minHeight &&
|
| - newHeight <= maxHeight)) {
|
| - node.style.width = newWidth + 'px';
|
| - node.style.height = newHeight + 'px';
|
| - // Only fire the DOM event if the size of the <webview> has actually
|
| - // changed.
|
| - this.dispatchEvent(webViewEvent);
|
| - }
|
| -};
|
| -
|
| -// Returns if <object> is in the render tree.
|
| -WebViewInternal.prototype.isPluginInRenderTree = function() {
|
| - return !!this.internalInstanceId && this.internalInstanceId != 0;
|
| -};
|
| -
|
| -WebViewInternal.prototype.hasNavigated = function() {
|
| - return !this.beforeFirstNavigation;
|
| -};
|
| -
|
| -WebViewInternal.prototype.parseSrcAttribute = function(result) {
|
| - if (!this.partition.validPartitionId) {
|
| - result.error = ERROR_MSG_INVALID_PARTITION_ATTRIBUTE;
|
| - return;
|
| - }
|
| - this.src = this.webviewNode.getAttribute('src');
|
| -
|
| - if (!this.src) {
|
| - return;
|
| - }
|
| -
|
| - if (this.guestInstanceId == undefined) {
|
| - if (this.beforeFirstNavigation) {
|
| - this.beforeFirstNavigation = false;
|
| - this.createGuest();
|
| - }
|
| - return;
|
| - }
|
| -
|
| - // Navigate to |this.src|.
|
| - WebView.navigate(this.guestInstanceId, this.src);
|
| -};
|
| -
|
| -WebViewInternal.prototype.parseAttributes = function() {
|
| - if (!this.elementAttached) {
|
| - return;
|
| - }
|
| - var hasNavigated = this.hasNavigated();
|
| - var attributeValue = this.webviewNode.getAttribute('partition');
|
| - var result = this.partition.fromAttribute(attributeValue, hasNavigated);
|
| - this.parseSrcAttribute(result);
|
| -};
|
| -
|
| -WebViewInternal.prototype.createGuest = function() {
|
| - if (this.pendingGuestCreation) {
|
| - return;
|
| - }
|
| - var storagePartitionId =
|
| - this.webviewNode.getAttribute(WEB_VIEW_ATTRIBUTE_PARTITION) ||
|
| - this.webviewNode[WEB_VIEW_ATTRIBUTE_PARTITION];
|
| - var params = {
|
| - 'storagePartitionId': storagePartitionId
|
| - };
|
| - GuestViewInternal.createGuest(
|
| - 'webview',
|
| - params,
|
| - function(guestInstanceId) {
|
| - this.pendingGuestCreation = false;
|
| - if (!this.elementAttached) {
|
| - GuestViewInternal.destroyGuest(guestInstanceId);
|
| - return;
|
| - }
|
| - this.attachWindow(guestInstanceId, false);
|
| - }.bind(this)
|
| - );
|
| - this.pendingGuestCreation = true;
|
| -};
|
| -
|
| -WebViewInternal.prototype.onFrameNameChanged = function(name) {
|
| - this.name = name || '';
|
| - if (this.name === '') {
|
| - this.webviewNode.removeAttribute('name');
|
| - } else {
|
| - this.webviewNode.setAttribute('name', this.name);
|
| - }
|
| -};
|
| -
|
| -WebViewInternal.prototype.dispatchEvent = function(webViewEvent) {
|
| - return this.webviewNode.dispatchEvent(webViewEvent);
|
| -};
|
| -
|
| -// Adds an 'on<event>' property on the webview, which can be used to set/unset
|
| -// an event handler.
|
| -WebViewInternal.prototype.setupEventProperty = function(eventName) {
|
| - var propertyName = 'on' + eventName.toLowerCase();
|
| - Object.defineProperty(this.webviewNode, propertyName, {
|
| - get: function() {
|
| - return this.on[propertyName];
|
| - }.bind(this),
|
| - set: function(value) {
|
| - if (this.on[propertyName])
|
| - this.webviewNode.removeEventListener(eventName, this.on[propertyName]);
|
| - this.on[propertyName] = value;
|
| - if (value)
|
| - this.webviewNode.addEventListener(eventName, value);
|
| - }.bind(this),
|
| - enumerable: true
|
| - });
|
| -};
|
| -
|
| -// Updates state upon loadcommit.
|
| -WebViewInternal.prototype.onLoadCommit = function(
|
| - baseUrlForDataUrl, currentEntryIndex, entryCount,
|
| - processId, url, isTopLevel) {
|
| - this.baseUrlForDataUrl = baseUrlForDataUrl;
|
| - this.currentEntryIndex = currentEntryIndex;
|
| - this.entryCount = entryCount;
|
| - this.processId = processId;
|
| - var oldValue = this.webviewNode.getAttribute('src');
|
| - var newValue = url;
|
| - if (isTopLevel && (oldValue != newValue)) {
|
| - // Touching the src attribute triggers a navigation. To avoid
|
| - // triggering a page reload on every guest-initiated navigation,
|
| - // we use the flag ignoreNextSrcAttributeChange here.
|
| - this.ignoreNextSrcAttributeChange = true;
|
| - this.webviewNode.setAttribute('src', newValue);
|
| - }
|
| -};
|
| -
|
| -WebViewInternal.prototype.onAttach = function(storagePartitionId) {
|
| - this.webviewNode.setAttribute('partition', storagePartitionId);
|
| - this.partition.fromAttribute(storagePartitionId, this.hasNavigated());
|
| -};
|
| -
|
| -WebViewInternal.prototype.buildAttachParams = function(isNewWindow) {
|
| - var params = {
|
| - 'allowtransparency': this.allowtransparency || false,
|
| - 'autosize': this.webviewNode.hasAttribute(WEB_VIEW_ATTRIBUTE_AUTOSIZE),
|
| - 'instanceId': this.viewInstanceId,
|
| - 'maxheight': parseInt(this.maxheight || 0),
|
| - 'maxwidth': parseInt(this.maxwidth || 0),
|
| - 'minheight': parseInt(this.minheight || 0),
|
| - 'minwidth': parseInt(this.minwidth || 0),
|
| - 'name': this.name,
|
| - // We don't need to navigate new window from here.
|
| - 'src': isNewWindow ? undefined : this.src,
|
| - // If we have a partition from the opener, that will also be already
|
| - // set via this.onAttach().
|
| - 'storagePartitionId': this.partition.toAttribute(),
|
| - 'userAgentOverride': this.userAgentOverride
|
| - };
|
| - return params;
|
| -};
|
| -
|
| -WebViewInternal.prototype.attachWindow = function(guestInstanceId,
|
| - isNewWindow) {
|
| - this.guestInstanceId = guestInstanceId;
|
| - var params = this.buildAttachParams(isNewWindow);
|
| -
|
| - if (!this.isPluginInRenderTree()) {
|
| - this.deferredAttachState = {isNewWindow: isNewWindow};
|
| - return true;
|
| - }
|
| -
|
| - this.deferredAttachState = null;
|
| - return guestViewInternalNatives.AttachGuest(
|
| - this.internalInstanceId,
|
| - this.guestInstanceId,
|
| - params, function(w) {
|
| - this.contentWindow = w;
|
| - }.bind(this)
|
| - );
|
| -};
|
| -
|
| -// -----------------------------------------------------------------------------
|
| -// Public-facing API methods.
|
| -
|
| -
|
| -// Navigates to the previous history entry.
|
| -WebViewInternal.prototype.back = function(callback) {
|
| - return this.go(-1, callback);
|
| -};
|
| -
|
| -// Returns whether there is a previous history entry to navigate to.
|
| -WebViewInternal.prototype.canGoBack = function() {
|
| - return this.entryCount > 1 && this.currentEntryIndex > 0;
|
| -};
|
| -
|
| -// Returns whether there is a subsequent history entry to navigate to.
|
| -WebViewInternal.prototype.canGoForward = function() {
|
| - return this.currentEntryIndex >= 0 &&
|
| - this.currentEntryIndex < (this.entryCount - 1);
|
| -};
|
| -
|
| -// Clears browsing data for the WebView partition.
|
| -WebViewInternal.prototype.clearData = function() {
|
| - if (!this.guestInstanceId) {
|
| - return;
|
| - }
|
| - var args = $Array.concat([this.guestInstanceId], $Array.slice(arguments));
|
| - $Function.apply(WebView.clearData, null, args);
|
| -};
|
| -
|
| -// Injects JavaScript code into the guest page.
|
| -WebViewInternal.prototype.executeScript = function(var_args) {
|
| - this.validateExecuteCodeCall();
|
| - var webviewSrc = this.src;
|
| - if (this.baseUrlForDataUrl != '') {
|
| - webviewSrc = this.baseUrlForDataUrl;
|
| - }
|
| - var args = $Array.concat([this.guestInstanceId, webviewSrc],
|
| - $Array.slice(arguments));
|
| - $Function.apply(WebView.executeScript, null, args);
|
| -};
|
| -
|
| -// Initiates a find-in-page request.
|
| -WebViewInternal.prototype.find = function(search_text, options, callback) {
|
| - if (!this.guestInstanceId) {
|
| - return;
|
| - }
|
| - WebView.find(this.guestInstanceId, search_text, options, callback);
|
| -};
|
| -
|
| -// Navigates to the subsequent history entry.
|
| -WebViewInternal.prototype.forward = function(callback) {
|
| - return this.go(1, callback);
|
| -};
|
| -
|
| -// Returns Chrome's internal process ID for the guest web page's current
|
| -// process.
|
| -WebViewInternal.prototype.getProcessId = function() {
|
| - return this.processId;
|
| -};
|
| -
|
| -// Returns the user agent string used by the webview for guest page requests.
|
| -WebViewInternal.prototype.getUserAgent = function() {
|
| - return this.userAgentOverride || navigator.userAgent;
|
| -};
|
| -
|
| -// Gets the current zoom factor.
|
| -WebViewInternal.prototype.getZoom = function(callback) {
|
| - if (!this.guestInstanceId) {
|
| - return;
|
| - }
|
| - WebView.getZoom(this.guestInstanceId, callback);
|
| -};
|
| -
|
| -// Navigates to a history entry using a history index relative to the current
|
| -// navigation.
|
| -WebViewInternal.prototype.go = function(relativeIndex, callback) {
|
| - if (!this.guestInstanceId) {
|
| - return;
|
| - }
|
| - WebView.go(this.guestInstanceId, relativeIndex, callback);
|
| -};
|
| -
|
| -// Injects CSS into the guest page.
|
| -WebViewInternal.prototype.insertCSS = function(var_args) {
|
| - this.validateExecuteCodeCall();
|
| - var webviewSrc = this.src;
|
| - if (this.baseUrlForDataUrl != '') {
|
| - webviewSrc = this.baseUrlForDataUrl;
|
| - }
|
| - var args = $Array.concat([this.guestInstanceId, webviewSrc],
|
| - $Array.slice(arguments));
|
| - $Function.apply(WebView.insertCSS, null, args);
|
| -};
|
| -
|
| -// Indicates whether or not the webview's user agent string has been overridden.
|
| -WebViewInternal.prototype.isUserAgentOverridden = function() {
|
| - return !!this.userAgentOverride &&
|
| - this.userAgentOverride != navigator.userAgent;
|
| -};
|
| -
|
| -// Prints the contents of the webview.
|
| -WebViewInternal.prototype.print = function() {
|
| - this.executeScript({code: 'window.print();'});
|
| -};
|
| -
|
| -// Reloads the current top-level page.
|
| -WebViewInternal.prototype.reload = function() {
|
| - if (!this.guestInstanceId) {
|
| - return;
|
| - }
|
| - WebView.reload(this.guestInstanceId);
|
| -};
|
| -
|
| -// Override the user agent string used by the webview for guest page requests.
|
| -WebViewInternal.prototype.setUserAgentOverride = function(userAgentOverride) {
|
| - this.userAgentOverride = userAgentOverride;
|
| - if (!this.guestInstanceId) {
|
| - // If we are not attached yet, then we will pick up the user agent on
|
| - // attachment.
|
| - return;
|
| - }
|
| - WebView.overrideUserAgent(this.guestInstanceId, userAgentOverride);
|
| -};
|
| -
|
| -// Changes the zoom factor of the page.
|
| -WebViewInternal.prototype.setZoom = function(zoomFactor, callback) {
|
| - if (!this.guestInstanceId) {
|
| - return;
|
| - }
|
| - WebView.setZoom(this.guestInstanceId, zoomFactor, callback);
|
| -};
|
| -
|
| -// Stops loading the current navigation if one is in progress.
|
| -WebViewInternal.prototype.stop = function() {
|
| - if (!this.guestInstanceId) {
|
| - return;
|
| - }
|
| - WebView.stop(this.guestInstanceId);
|
| -};
|
| -
|
| -// Ends the current find session.
|
| -WebViewInternal.prototype.stopFinding = function(action) {
|
| - if (!this.guestInstanceId) {
|
| - return;
|
| - }
|
| - WebView.stopFinding(this.guestInstanceId, action);
|
| -};
|
| -
|
| -// Forcibly kills the guest web page's renderer process.
|
| -WebViewInternal.prototype.terminate = function() {
|
| - if (!this.guestInstanceId) {
|
| - return;
|
| - }
|
| - WebView.terminate(this.guestInstanceId);
|
| -};
|
| -
|
| -// -----------------------------------------------------------------------------
|
| -
|
| -// Registers browser plugin <object> custom element.
|
| -function registerBrowserPluginElement() {
|
| - var proto = Object.create(HTMLObjectElement.prototype);
|
| -
|
| - proto.createdCallback = function() {
|
| - this.setAttribute('type', 'application/browser-plugin');
|
| - this.setAttribute('id', 'browser-plugin-' + IdGenerator.GetNextId());
|
| - // The <object> node fills in the <webview> container.
|
| - this.style.width = '100%';
|
| - this.style.height = '100%';
|
| - };
|
| -
|
| - proto.attributeChangedCallback = function(name, oldValue, newValue) {
|
| - var internal = privates(this).internal;
|
| - if (!internal) {
|
| - return;
|
| - }
|
| - internal.handleBrowserPluginAttributeMutation(name, oldValue, newValue);
|
| - };
|
| -
|
| - proto.attachedCallback = function() {
|
| - // Load the plugin immediately.
|
| - var unused = this.nonExistentAttribute;
|
| - };
|
| -
|
| - WebViewInternal.BrowserPlugin =
|
| - DocumentNatives.RegisterElement('browserplugin', {extends: 'object',
|
| - prototype: proto});
|
| -
|
| - delete proto.createdCallback;
|
| - delete proto.attachedCallback;
|
| - delete proto.detachedCallback;
|
| - delete proto.attributeChangedCallback;
|
| -}
|
| -
|
| -// Registers <webview> custom element.
|
| -function registerWebViewElement() {
|
| - var proto = Object.create(HTMLElement.prototype);
|
| -
|
| - proto.createdCallback = function() {
|
| - new WebViewInternal(this);
|
| - };
|
| -
|
| - proto.attributeChangedCallback = function(name, oldValue, newValue) {
|
| - var internal = privates(this).internal;
|
| - if (!internal) {
|
| - return;
|
| - }
|
| - internal.handleWebviewAttributeMutation(name, oldValue, newValue);
|
| - };
|
| -
|
| - proto.detachedCallback = function() {
|
| - var internal = privates(this).internal;
|
| - if (!internal) {
|
| - return;
|
| - }
|
| - internal.elementAttached = false;
|
| - internal.reset();
|
| - };
|
| -
|
| - proto.attachedCallback = function() {
|
| - var internal = privates(this).internal;
|
| - if (!internal) {
|
| - return;
|
| - }
|
| - if (!internal.elementAttached) {
|
| - internal.elementAttached = true;
|
| - internal.parseAttributes();
|
| - }
|
| - };
|
| -
|
| - // Public-facing API methods.
|
| - var methods = [
|
| - 'back',
|
| - 'canGoBack',
|
| - 'canGoForward',
|
| - 'clearData',
|
| - 'executeScript',
|
| - 'find',
|
| - 'forward',
|
| - 'getProcessId',
|
| - 'getUserAgent',
|
| - 'getZoom',
|
| - 'go',
|
| - 'insertCSS',
|
| - 'isUserAgentOverridden',
|
| - 'print',
|
| - 'reload',
|
| - 'setUserAgentOverride',
|
| - 'setZoom',
|
| - 'stop',
|
| - 'stopFinding',
|
| - 'terminate'
|
| - ];
|
| -
|
| - // Add the experimental API methods, if available.
|
| - var experimentalMethods =
|
| - WebViewInternal.maybeGetExperimentalAPIs();
|
| - methods = $Array.concat(methods, experimentalMethods);
|
| -
|
| - // Forward proto.foo* method calls to WebViewInternal.foo*.
|
| - var createHandler = function(m) {
|
| - return function(var_args) {
|
| - var internal = privates(this).internal;
|
| - return $Function.apply(internal[m], internal, arguments);
|
| - };
|
| - };
|
| - for (var i = 0; methods[i]; ++i) {
|
| - proto[methods[i]] = createHandler(methods[i]);
|
| - }
|
| -
|
| - window.WebView =
|
| - DocumentNatives.RegisterElement('webview', {prototype: proto});
|
| -
|
| - // Delete the callbacks so developers cannot call them and produce unexpected
|
| - // behavior.
|
| - delete proto.createdCallback;
|
| - delete proto.attachedCallback;
|
| - delete proto.detachedCallback;
|
| - delete proto.attributeChangedCallback;
|
| -}
|
| -
|
| -var useCapture = true;
|
| -window.addEventListener('readystatechange', function listener(event) {
|
| - if (document.readyState == 'loading')
|
| - return;
|
| -
|
| - registerBrowserPluginElement();
|
| - registerWebViewElement();
|
| - window.removeEventListener(event.type, listener, useCapture);
|
| -}, useCapture);
|
| -
|
| -// Implemented when the ChromeWebView API is available.
|
| -WebViewInternal.prototype.maybeGetChromeWebViewEvents = function() {};
|
| -
|
| -// Implemented when the experimental WebView API is available.
|
| -WebViewInternal.maybeGetExperimentalAPIs = function() {};
|
| -WebViewInternal.prototype.maybeGetExperimentalEvents = function() {};
|
| -WebViewInternal.prototype.setupExperimentalContextMenus = function() {};
|
| -
|
| -// Exports.
|
| -exports.WebView = WebView;
|
| -exports.WebViewInternal = WebViewInternal;
|
|
|