diff --git a/atom/browser/api/lib/auto-updater/auto-updater-win.js b/atom/browser/api/lib/auto-updater/auto-updater-win.js index bbe02555a0b8..097ac9d33294 100644 --- a/atom/browser/api/lib/auto-updater/auto-updater-win.js +++ b/atom/browser/api/lib/auto-updater/auto-updater-win.js @@ -2,70 +2,62 @@ const app = require('electron').app; const EventEmitter = require('events').EventEmitter; const url = require('url'); const squirrelUpdate = require('./squirrel-update-win'); +const util = require('util'); -var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, -hasProp = {}.hasOwnProperty; +function AutoUpdater() { + AutoUpdater.super_.call(this); +} -var AutoUpdater = (function(superClass) { - extend(AutoUpdater, superClass); +util.inherits(AutoUpdater, EventEmitter); - function AutoUpdater() { - return AutoUpdater.__super__.constructor.apply(this, arguments); +AutoUpdater.prototype.quitAndInstall = function() { + squirrelUpdate.processStart(); + return app.quit(); +}; + +AutoUpdater.prototype.setFeedURL = function(updateURL) { + return this.updateURL = updateURL; +}; + +AutoUpdater.prototype.checkForUpdates = function() { + if (!this.updateURL) { + return this.emitError('Update URL is not set'); } - - AutoUpdater.prototype.quitAndInstall = function() { - squirrelUpdate.processStart(); - return app.quit(); - }; - - AutoUpdater.prototype.setFeedURL = function(updateURL) { - return this.updateURL = updateURL; - }; - - AutoUpdater.prototype.checkForUpdates = function() { - if (!this.updateURL) { - return this.emitError('Update URL is not set'); - } - if (!squirrelUpdate.supported()) { - return this.emitError('Can not find Squirrel'); - } - this.emit('checking-for-update'); - return squirrelUpdate.download(this.updateURL, (function(_this) { - return function(error, update) { + if (!squirrelUpdate.supported()) { + return this.emitError('Can not find Squirrel'); + } + this.emit('checking-for-update'); + return squirrelUpdate.download(this.updateURL, (function(_this) { + return function(error, update) { + if (error != null) { + return _this.emitError(error); + } + if (update == null) { + return _this.emit('update-not-available'); + } + _this.emit('update-available'); + return squirrelUpdate.update(_this.updateURL, function(error) { + var date, releaseNotes, version; if (error != null) { return _this.emitError(error); } - if (update == null) { - return _this.emit('update-not-available'); - } - _this.emit('update-available'); - return squirrelUpdate.update(_this.updateURL, function(error) { - var date, releaseNotes, version; - if (error != null) { - return _this.emitError(error); - } - releaseNotes = update.releaseNotes, version = update.version; + releaseNotes = update.releaseNotes, version = update.version; - // Following information is not available on Windows, so fake them. - date = new Date; - url = _this.updateURL; - return _this.emit('update-downloaded', {}, releaseNotes, version, date, url, function() { - return _this.quitAndInstall(); - }); + // Following information is not available on Windows, so fake them. + date = new Date; + url = _this.updateURL; + return _this.emit('update-downloaded', {}, releaseNotes, version, date, url, function() { + return _this.quitAndInstall(); }); - }; - })(this)); - }; + }); + }; + })(this)); +}; - - // Private: Emit both error object and message, this is to keep compatibility - // with Old APIs. - AutoUpdater.prototype.emitError = function(message) { - return this.emit('error', new Error(message), message); - }; - - return AutoUpdater; - -})(EventEmitter); +// Private: Emit both error object and message, this is to keep compatibility +// with Old APIs. +AutoUpdater.prototype.emitError = function(message) { + return this.emit('error', new Error(message), message); +}; module.exports = new AutoUpdater; diff --git a/atom/browser/lib/objects-registry.js b/atom/browser/lib/objects-registry.js index 953b2f47c9fd..a712662318c6 100644 --- a/atom/browser/lib/objects-registry.js +++ b/atom/browser/lib/objects-registry.js @@ -1,115 +1,110 @@ const EventEmitter = require('events').EventEmitter; +const util = require('util'); const v8Util = process.atomBinding('v8_util'); -var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; -var hasProp = {}.hasOwnProperty; +function ObjectsRegistry() { + ObjectsRegistry.super_.call(this); -var ObjectsRegistry = (function(superClass) { - extend(ObjectsRegistry, superClass); + this.setMaxListeners(Number.MAX_VALUE); + this.nextId = 0; - function ObjectsRegistry() { - this.setMaxListeners(Number.MAX_VALUE); - this.nextId = 0; + // Stores all objects by ref-counting. + // (id) => {object, count} + this.storage = {}; - // Stores all objects by ref-counting. - // (id) => {object, count} - this.storage = {}; + // Stores the IDs of objects referenced by WebContents. + // (webContentsId) => {(id) => (count)} + this.owners = {}; +} - // Stores the IDs of objects referenced by WebContents. - // (webContentsId) => {(id) => (count)} - this.owners = {}; +util.inherits(ObjectsRegistry, EventEmitter); + +// Register a new object, the object would be kept referenced until you release +// it explicitly. +ObjectsRegistry.prototype.add = function(webContentsId, obj) { + var base, base1, id; + id = this.saveToStorage(obj); + + // Remember the owner. + if ((base = this.owners)[webContentsId] == null) { + base[webContentsId] = {}; } + if ((base1 = this.owners[webContentsId])[id] == null) { + base1[id] = 0; + } + this.owners[webContentsId][id]++; - // Register a new object, the object would be kept referenced until you release - // it explicitly. - ObjectsRegistry.prototype.add = function(webContentsId, obj) { - var base, base1, id; - id = this.saveToStorage(obj); - - // Remember the owner. - if ((base = this.owners)[webContentsId] == null) { - base[webContentsId] = {}; - } - if ((base1 = this.owners[webContentsId])[id] == null) { - base1[id] = 0; - } - this.owners[webContentsId][id]++; - - // Returns object's id - return id; - }; + // Returns object's id + return id; +}; - // Get an object according to its ID. - ObjectsRegistry.prototype.get = function(id) { - var ref; - return (ref = this.storage[id]) != null ? ref.object : void 0; - }; +// Get an object according to its ID. +ObjectsRegistry.prototype.get = function(id) { + var ref; + return (ref = this.storage[id]) != null ? ref.object : void 0; +}; - // Dereference an object according to its ID. - ObjectsRegistry.prototype.remove = function(webContentsId, id) { - var pointer; - this.dereference(id, 1); +// Dereference an object according to its ID. +ObjectsRegistry.prototype.remove = function(webContentsId, id) { + var pointer; + this.dereference(id, 1); - // Also reduce the count in owner. - pointer = this.owners[webContentsId]; - if (pointer == null) { - return; - } - --pointer[id]; - if (pointer[id] === 0) { - return delete pointer[id]; - } - }; + // Also reduce the count in owner. + pointer = this.owners[webContentsId]; + if (pointer == null) { + return; + } + --pointer[id]; + if (pointer[id] === 0) { + return delete pointer[id]; + } +}; - // Clear all references to objects refrenced by the WebContents. - ObjectsRegistry.prototype.clear = function(webContentsId) { - var count, id, ref; - this.emit("clear-" + webContentsId); - if (this.owners[webContentsId] == null) { - return; - } - ref = this.owners[webContentsId]; - for (id in ref) { - count = ref[id]; - this.dereference(id, count); - } - return delete this.owners[webContentsId]; - }; +// Clear all references to objects refrenced by the WebContents. +ObjectsRegistry.prototype.clear = function(webContentsId) { + var count, id, ref; + this.emit("clear-" + webContentsId); + if (this.owners[webContentsId] == null) { + return; + } + ref = this.owners[webContentsId]; + for (id in ref) { + count = ref[id]; + this.dereference(id, count); + } + return delete this.owners[webContentsId]; +}; - // Private: Saves the object into storage and assigns an ID for it. - ObjectsRegistry.prototype.saveToStorage = function(object) { - var id; - id = v8Util.getHiddenValue(object, 'atomId'); - if (!id) { - id = ++this.nextId; - this.storage[id] = { - count: 0, - object: object - }; - v8Util.setHiddenValue(object, 'atomId', id); - } - ++this.storage[id].count; - return id; - }; +// Private: Saves the object into storage and assigns an ID for it. +ObjectsRegistry.prototype.saveToStorage = function(object) { + var id; + id = v8Util.getHiddenValue(object, 'atomId'); + if (!id) { + id = ++this.nextId; + this.storage[id] = { + count: 0, + object: object + }; + v8Util.setHiddenValue(object, 'atomId', id); + } + ++this.storage[id].count; + return id; +}; - // Private: Dereference the object from store. - ObjectsRegistry.prototype.dereference = function(id, count) { - var pointer; - pointer = this.storage[id]; - if (pointer == null) { - return; - } - pointer.count -= count; - if (pointer.count === 0) { - v8Util.deleteHiddenValue(pointer.object, 'atomId'); - return delete this.storage[id]; - } - }; - - return ObjectsRegistry; - -})(EventEmitter); +// Private: Dereference the object from store. +ObjectsRegistry.prototype.dereference = function(id, count) { + var pointer; + pointer = this.storage[id]; + if (pointer == null) { + return; + } + pointer.count -= count; + if (pointer.count === 0) { + v8Util.deleteHiddenValue(pointer.object, 'atomId'); + return delete this.storage[id]; + } +}; module.exports = new ObjectsRegistry; diff --git a/atom/renderer/lib/web-view/web-view-attributes.js b/atom/renderer/lib/web-view/web-view-attributes.js index 90ce9f1290fc..7cb64006bb52 100644 --- a/atom/renderer/lib/web-view/web-view-attributes.js +++ b/atom/renderer/lib/web-view/web-view-attributes.js @@ -2,10 +2,7 @@ const WebViewImpl = require('./web-view'); const guestViewInternal = require('./guest-view-internal'); const webViewConstants = require('./web-view-constants'); const remote = require('electron').remote; - -var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - -var hasProp = {}.hasOwnProperty; +var util = require('util'); // Helper function to resolve url set in attribute. var a = document.createElement('a'); @@ -17,326 +14,275 @@ var resolveURL = function(url) { // Attribute objects. // Default implementation of a WebView attribute. -var WebViewAttribute = (function() { - function WebViewAttribute(name, webViewImpl) { - this.name = name; - this.value = webViewImpl.webviewNode[name] || ''; - this.webViewImpl = webViewImpl; - this.ignoreMutation = false; - this.defineProperty(); - } +function WebViewAttribute(name, webViewImpl) { + this.name = name; + this.value = webViewImpl.webviewNode[name] || ''; + this.webViewImpl = webViewImpl; + this.ignoreMutation = false; + this.defineProperty(); +} - // Retrieves and returns the attribute's value. - WebViewAttribute.prototype.getValue = function() { - return this.webViewImpl.webviewNode.getAttribute(this.name) || this.value; - }; +// Retrieves and returns the attribute's value. +WebViewAttribute.prototype.getValue = function() { + return this.webViewImpl.webviewNode.getAttribute(this.name) || this.value; +}; - // Sets the attribute's value. - WebViewAttribute.prototype.setValue = function(value) { - return this.webViewImpl.webviewNode.setAttribute(this.name, value || ''); - }; +// Sets the attribute's value. +WebViewAttribute.prototype.setValue = function(value) { + return this.webViewImpl.webviewNode.setAttribute(this.name, value || ''); +}; - // Changes the attribute's value without triggering its mutation handler. - WebViewAttribute.prototype.setValueIgnoreMutation = function(value) { - this.ignoreMutation = true; - this.setValue(value); - return this.ignoreMutation = false; - }; +// Changes the attribute's value without triggering its mutation handler. +WebViewAttribute.prototype.setValueIgnoreMutation = function(value) { + this.ignoreMutation = true; + this.setValue(value); + return this.ignoreMutation = false; +}; - // Defines this attribute as a property on the webview node. - WebViewAttribute.prototype.defineProperty = function() { - return Object.defineProperty(this.webViewImpl.webviewNode, this.name, { - get: (function(_this) { - return function() { - return _this.getValue(); - }; - })(this), - set: (function(_this) { - return function(value) { - return _this.setValue(value); - }; - })(this), - enumerable: true - }); - }; +// Defines this attribute as a property on the webview node. +WebViewAttribute.prototype.defineProperty = function() { + return Object.defineProperty(this.webViewImpl.webviewNode, this.name, { + get: (function(_this) { + return function() { + return _this.getValue(); + }; + })(this), + set: (function(_this) { + return function(value) { + return _this.setValue(value); + }; + })(this), + enumerable: true + }); +}; - // Called when the attribute's value changes. - WebViewAttribute.prototype.handleMutation = function() {}; - - return WebViewAttribute; - -})(); +// Called when the attribute's value changes. +WebViewAttribute.prototype.handleMutation = function() {}; // An attribute that is treated as a Boolean. -var BooleanAttribute = (function(superClass) { - extend(BooleanAttribute, superClass); +function BooleanAttribute(name, webViewImpl) { + BooleanAttribute.super_.call(this, name, webViewImpl) +} - function BooleanAttribute(name, webViewImpl) { - BooleanAttribute.__super__.constructor.call(this, name, webViewImpl); +util.inherits(BooleanAttribute, WebViewAttribute); + +BooleanAttribute.prototype.getValue = function() { + return this.webViewImpl.webviewNode.hasAttribute(this.name); +}; + +BooleanAttribute.prototype.setValue = function(value) { + if (!value) { + return this.webViewImpl.webviewNode.removeAttribute(this.name); + } else { + return this.webViewImpl.webviewNode.setAttribute(this.name, ''); } - - BooleanAttribute.prototype.getValue = function() { - return this.webViewImpl.webviewNode.hasAttribute(this.name); - }; - - BooleanAttribute.prototype.setValue = function(value) { - if (!value) { - return this.webViewImpl.webviewNode.removeAttribute(this.name); - } else { - return this.webViewImpl.webviewNode.setAttribute(this.name, ''); - } - }; - - return BooleanAttribute; - -})(WebViewAttribute); +}; // Attribute that specifies whether transparency is allowed in the webview. -var AllowTransparencyAttribute = (function(superClass) { - extend(AllowTransparencyAttribute, superClass); +function AllowTransparencyAttribute(webViewImpl) { + AllowTransparencyAttribute.super_.call(this, webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, webViewImpl); +} - function AllowTransparencyAttribute(webViewImpl) { - AllowTransparencyAttribute.__super__.constructor.call(this, webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, webViewImpl); +util.inherits(AllowTransparencyAttribute, BooleanAttribute); + +AllowTransparencyAttribute.prototype.handleMutation = function(oldValue, newValue) { + if (!this.webViewImpl.guestInstanceId) { + return; } - - AllowTransparencyAttribute.prototype.handleMutation = function(oldValue, newValue) { - if (!this.webViewImpl.guestInstanceId) { - return; - } - return guestViewInternal.setAllowTransparency(this.webViewImpl.guestInstanceId, this.getValue()); - }; - - return AllowTransparencyAttribute; - -})(BooleanAttribute); + return guestViewInternal.setAllowTransparency(this.webViewImpl.guestInstanceId, this.getValue()); +}; // Attribute used to define the demension limits of autosizing. -var AutosizeDimensionAttribute = (function(superClass) { - extend(AutosizeDimensionAttribute, superClass); +function AutosizeDimensionAttribute(name, webViewImpl) { + AutosizeDimensionAttribute.super_.call(this, name, webViewImpl); +} - function AutosizeDimensionAttribute(name, webViewImpl) { - AutosizeDimensionAttribute.__super__.constructor.call(this, name, webViewImpl); +util.inherits(AutosizeDimensionAttribute, WebViewAttribute); + +AutosizeDimensionAttribute.prototype.getValue = function() { + return parseInt(this.webViewImpl.webviewNode.getAttribute(this.name)) || 0; +}; + +AutosizeDimensionAttribute.prototype.handleMutation = function(oldValue, newValue) { + if (!this.webViewImpl.guestInstanceId) { + return; } - - AutosizeDimensionAttribute.prototype.getValue = function() { - return parseInt(this.webViewImpl.webviewNode.getAttribute(this.name)) || 0; - }; - - AutosizeDimensionAttribute.prototype.handleMutation = function(oldValue, newValue) { - if (!this.webViewImpl.guestInstanceId) { - return; + return guestViewInternal.setSize(this.webViewImpl.guestInstanceId, { + enableAutoSize: this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_AUTOSIZE].getValue(), + min: { + width: parseInt(this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_MINWIDTH].getValue() || 0), + height: parseInt(this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_MINHEIGHT].getValue() || 0) + }, + max: { + width: parseInt(this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() || 0), + height: parseInt(this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() || 0) } - return guestViewInternal.setSize(this.webViewImpl.guestInstanceId, { - enableAutoSize: this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_AUTOSIZE].getValue(), - min: { - width: parseInt(this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_MINWIDTH].getValue() || 0), - height: parseInt(this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_MINHEIGHT].getValue() || 0) - }, - max: { - width: parseInt(this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() || 0), - height: parseInt(this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() || 0) - } - }); - }; - - return AutosizeDimensionAttribute; - -})(WebViewAttribute); + }); +}; // Attribute that specifies whether the webview should be autosized. -var AutosizeAttribute = (function(superClass) { - extend(AutosizeAttribute, superClass); +function AutosizeAttribute(webViewImpl) { + AutosizeAttribute.super_.constructor.call(this, webViewConstants.ATTRIBUTE_AUTOSIZE, webViewImpl); +} - function AutosizeAttribute(webViewImpl) { - AutosizeAttribute.__super__.constructor.call(this, webViewConstants.ATTRIBUTE_AUTOSIZE, webViewImpl); - } +util.inherits(AutosizeAttribute, BooleanAttribute); - AutosizeAttribute.prototype.handleMutation = AutosizeDimensionAttribute.prototype.handleMutation; - - return AutosizeAttribute; - -})(BooleanAttribute); +AutosizeAttribute.prototype.handleMutation = AutosizeDimensionAttribute.prototype.handleMutation; // Attribute representing the state of the storage partition. -var PartitionAttribute = (function(superClass) { - extend(PartitionAttribute, superClass); +function PartitionAttribute(webViewImpl) { + PartitionAttribute.super_.constructor.call(this, webViewConstants.ATTRIBUTE_PARTITION, webViewImpl); + this.validPartitionId = true; +} - function PartitionAttribute(webViewImpl) { - PartitionAttribute.__super__.constructor.call(this, webViewConstants.ATTRIBUTE_PARTITION, webViewImpl); - this.validPartitionId = true; +util.inherits(PartitionAttribute, WebViewAttribute); + +PartitionAttribute.prototype.handleMutation = function(oldValue, newValue) { + newValue = newValue || ''; + + // The partition cannot change if the webview has already navigated. + if (!this.webViewImpl.beforeFirstNavigation) { + window.console.error(webViewConstants.ERROR_MSG_ALREADY_NAVIGATED); + this.setValueIgnoreMutation(oldValue); + return; } - - PartitionAttribute.prototype.handleMutation = function(oldValue, newValue) { - newValue = newValue || ''; - - // The partition cannot change if the webview has already navigated. - if (!this.webViewImpl.beforeFirstNavigation) { - window.console.error(webViewConstants.ERROR_MSG_ALREADY_NAVIGATED); - this.setValueIgnoreMutation(oldValue); - return; - } - if (newValue === 'persist:') { - this.validPartitionId = false; - return window.console.error(webViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE); - } - }; - - return PartitionAttribute; - -})(WebViewAttribute); + if (newValue === 'persist:') { + this.validPartitionId = false; + return window.console.error(webViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE); + } +}; // Attribute that handles the location and navigation of the webview. -var SrcAttribute = (function(superClass) { - extend(SrcAttribute, superClass); +function SrcAttribute(webViewImpl) { + SrcAttribute.super_.constructor.call(this, webViewConstants.ATTRIBUTE_SRC, webViewImpl); + this.setupMutationObserver(); +} - function SrcAttribute(webViewImpl) { - SrcAttribute.__super__.constructor.call(this, webViewConstants.ATTRIBUTE_SRC, webViewImpl); - this.setupMutationObserver(); +util.inherits(SrcAttribute, WebViewAttribute); + +SrcAttribute.prototype.getValue = function() { + if (this.webViewImpl.webviewNode.hasAttribute(this.name)) { + return resolveURL(this.webViewImpl.webviewNode.getAttribute(this.name)); + } else { + return this.value; + } +}; + +SrcAttribute.prototype.setValueIgnoreMutation = function(value) { + WebViewAttribute.prototype.setValueIgnoreMutation.call(this, value); + + // takeRecords() is needed to clear queued up src mutations. Without it, it + // is possible for this change to get picked up asyncronously by src's + // mutation observer |observer|, and then get handled even though we do not + // want to handle this mutation. + return this.observer.takeRecords(); +}; + +SrcAttribute.prototype.handleMutation = function(oldValue, newValue) { + + // Once we have navigated, we don't allow clearing the src attribute. + // Once enters a navigated state, it cannot return 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.setValueIgnoreMutation(oldValue); + return; + } + return this.parse(); +}; + +// 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. +SrcAttribute.prototype.setupMutationObserver = function() { + var params; + this.observer = new MutationObserver((function(_this) { + return function(mutations) { + var i, len, mutation, newValue, oldValue; + for (i = 0, len = mutations.length; i < len; i++) { + mutation = mutations[i]; + oldValue = mutation.oldValue; + newValue = _this.getValue(); + if (oldValue !== newValue) { + return; + } + _this.handleMutation(oldValue, newValue); + } + }; + })(this)); + params = { + attributes: true, + attributeOldValue: true, + attributeFilter: [this.name] + }; + return this.observer.observe(this.webViewImpl.webviewNode, params); +}; + +SrcAttribute.prototype.parse = function() { + var guestContents, httpreferrer, opts, useragent; + if (!this.webViewImpl.elementAttached || !this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId || !this.getValue()) { + return; + } + if (this.webViewImpl.guestInstanceId == null) { + if (this.webViewImpl.beforeFirstNavigation) { + this.webViewImpl.beforeFirstNavigation = false; + this.webViewImpl.createGuest(); + } + return; } - SrcAttribute.prototype.getValue = function() { - if (this.webViewImpl.webviewNode.hasAttribute(this.name)) { - return resolveURL(this.webViewImpl.webviewNode.getAttribute(this.name)); - } else { - return this.value; - } - }; - - SrcAttribute.prototype.setValueIgnoreMutation = function(value) { - WebViewAttribute.prototype.setValueIgnoreMutation.call(this, value); - - // takeRecords() is needed to clear queued up src mutations. Without it, it - // is possible for this change to get picked up asyncronously by src's - // mutation observer |observer|, and then get handled even though we do not - // want to handle this mutation. - return this.observer.takeRecords(); - }; - - SrcAttribute.prototype.handleMutation = function(oldValue, newValue) { - - // Once we have navigated, we don't allow clearing the src attribute. - // Once enters a navigated state, it cannot return 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.setValueIgnoreMutation(oldValue); - return; - } - return this.parse(); - }; - - - // 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. - SrcAttribute.prototype.setupMutationObserver = function() { - var params; - this.observer = new MutationObserver((function(_this) { - return function(mutations) { - var i, len, mutation, newValue, oldValue; - for (i = 0, len = mutations.length; i < len; i++) { - mutation = mutations[i]; - oldValue = mutation.oldValue; - newValue = _this.getValue(); - if (oldValue !== newValue) { - return; - } - _this.handleMutation(oldValue, newValue); - } - }; - })(this)); - params = { - attributes: true, - attributeOldValue: true, - attributeFilter: [this.name] - }; - return this.observer.observe(this.webViewImpl.webviewNode, params); - }; - - SrcAttribute.prototype.parse = function() { - var guestContents, httpreferrer, opts, useragent; - if (!this.webViewImpl.elementAttached || !this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId || !this.getValue()) { - return; - } - if (this.webViewImpl.guestInstanceId == null) { - if (this.webViewImpl.beforeFirstNavigation) { - this.webViewImpl.beforeFirstNavigation = false; - this.webViewImpl.createGuest(); - } - return; - } - - // Navigate to |this.src|. - opts = {}; - httpreferrer = this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER].getValue(); - if (httpreferrer) { - opts.httpReferrer = httpreferrer; - } - useragent = this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_USERAGENT].getValue(); - if (useragent) { - opts.userAgent = useragent; - } - guestContents = remote.getGuestWebContents(this.webViewImpl.guestInstanceId); - return guestContents.loadURL(this.getValue(), opts); - }; - - return SrcAttribute; - -})(WebViewAttribute); + // Navigate to |this.src|. + opts = {}; + httpreferrer = this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER].getValue(); + if (httpreferrer) { + opts.httpReferrer = httpreferrer; + } + useragent = this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_USERAGENT].getValue(); + if (useragent) { + opts.userAgent = useragent; + } + guestContents = remote.getGuestWebContents(this.webViewImpl.guestInstanceId); + return guestContents.loadURL(this.getValue(), opts); +}; // Attribute specifies HTTP referrer. -var HttpReferrerAttribute = (function(superClass) { - extend(HttpReferrerAttribute, superClass); +function HttpReferrerAttribute(webViewImpl) { + HttpReferrerAttribute.super_.constructor.call(this, webViewConstants.ATTRIBUTE_HTTPREFERRER, webViewImpl); +} - function HttpReferrerAttribute(webViewImpl) { - HttpReferrerAttribute.__super__.constructor.call(this, webViewConstants.ATTRIBUTE_HTTPREFERRER, webViewImpl); - } - - return HttpReferrerAttribute; - -})(WebViewAttribute); +util.inherits(HttpReferrerAttribute, WebViewAttribute); // Attribute specifies user agent -var UserAgentAttribute = (function(superClass) { - extend(UserAgentAttribute, superClass); +function UserAgentAttribute(webViewImpl) { + UserAgentAttribute.super_.constructor.call(this, webViewConstants.ATTRIBUTE_USERAGENT, webViewImpl); +} - function UserAgentAttribute(webViewImpl) { - UserAgentAttribute.__super__.constructor.call(this, webViewConstants.ATTRIBUTE_USERAGENT, webViewImpl); - } - - return UserAgentAttribute; - -})(WebViewAttribute); +util.inherits(UserAgentAttribute, WebViewAttribute); // Attribute that set preload script. -var PreloadAttribute = (function(superClass) { - extend(PreloadAttribute, superClass); +function PreloadAttribute(webViewImpl) { + PreloadAttribute.super_.constructor.call(this, webViewConstants.ATTRIBUTE_PRELOAD, webViewImpl); +} - function PreloadAttribute(webViewImpl) { - PreloadAttribute.__super__.constructor.call(this, webViewConstants.ATTRIBUTE_PRELOAD, webViewImpl); +util.inherits(PreloadAttribute, WebViewAttribute); + +PreloadAttribute.prototype.getValue = function() { + var preload, protocol; + if (!this.webViewImpl.webviewNode.hasAttribute(this.name)) { + return this.value; } - - PreloadAttribute.prototype.getValue = function() { - var preload, protocol; - if (!this.webViewImpl.webviewNode.hasAttribute(this.name)) { - return this.value; - } - preload = resolveURL(this.webViewImpl.webviewNode.getAttribute(this.name)); - protocol = preload.substr(0, 5); - if (protocol !== 'file:') { - console.error(webViewConstants.ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE); - preload = ''; - } - return preload; - }; - - return PreloadAttribute; - -})(WebViewAttribute); + preload = resolveURL(this.webViewImpl.webviewNode.getAttribute(this.name)); + protocol = preload.substr(0, 5); + if (protocol !== 'file:') { + console.error(webViewConstants.ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE); + preload = ''; + } + return preload; +}; // Sets up all of the webview attributes. WebViewImpl.prototype.setupWebViewAttributes = function() {