diff --git a/atom.gyp b/atom.gyp index 283c2c4eec49..0e651b1aa225 100644 --- a/atom.gyp +++ b/atom.gyp @@ -49,6 +49,7 @@ 'atom/renderer/lib/override.coffee', 'atom/renderer/lib/web-view/guest-view-internal.coffee', 'atom/renderer/lib/web-view/web-view.coffee', + 'atom/renderer/lib/web-view/web-view-attributes.coffee', 'atom/renderer/lib/web-view/web-view-constants.coffee', 'atom/renderer/api/lib/ipc.coffee', 'atom/renderer/api/lib/remote.coffee', diff --git a/atom/renderer/lib/init.coffee b/atom/renderer/lib/init.coffee index 13b928573bb8..c2ca2feb325e 100644 --- a/atom/renderer/lib/init.coffee +++ b/atom/renderer/lib/init.coffee @@ -36,17 +36,19 @@ for arg in process.argv if location.protocol is 'chrome-devtools:' # Override some inspector APIs. - require path.join(__dirname, 'inspector') + require './inspector' nodeIntegration = 'true' else if location.protocol is 'chrome-extension:' # Add implementations of chrome API. - require path.join(__dirname, 'chrome-api') + require './chrome-api' nodeIntegration = 'true' else # Override default web functions. - require path.join(__dirname, 'override') + require './override' # Load webview tag implementation. - require path.join(__dirname, 'web-view/web-view') unless process.guestInstanceId? + unless process.guestInstanceId? + require './web-view/web-view' + require './web-view/web-view-attributes' if nodeIntegration in ['true', 'all', 'except-iframe', 'manual-enable-iframe'] # Export node bindings to global. diff --git a/atom/renderer/lib/web-view/web-view-attributes.coffee b/atom/renderer/lib/web-view/web-view-attributes.coffee new file mode 100644 index 000000000000..5279ed3a9176 --- /dev/null +++ b/atom/renderer/lib/web-view/web-view-attributes.coffee @@ -0,0 +1,71 @@ +WebView = require './web-view' +webViewConstants = require './web-view-constants' + +# Attribute objects. +# Default implementation of a WebView attribute. +class WebViewAttribute + constructor: (name, webViewImpl) -> + @name = name + @value = '' + @webViewImpl = webViewImpl + + getValue: -> @value || '' + + setValue: (value) -> @value = value + +# Attribute representing the state of the storage partition. +class Partition extends WebViewAttribute + constructor: (webViewImpl) -> + super webViewConstants.ATTRIBUTE_PARTITION, webViewImpl + + @validPartitionId = true + @persistStorage = false + @storagePartitionId = '' + @webViewImpl = webViewImpl + + getValue: -> + return '' unless @validPartitionId + (if @persistStorage then 'persist:' else '') + @storagePartitionId + + setValue: (value) -> + result = {} + hasNavigated = !@webViewImpl.beforeFirstNavigation + if hasNavigated + result.error = webViewConstants.ERROR_MSG_ALREADY_NAVIGATED + return result + value = '' unless value + LEN = 'persist:'.length + if value.substr(0, LEN) == 'persist:' + value = value.substr LEN + unless value + @validPartitionId = false + result.error = webViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE + return result + @persistStorage = true + else + @persistStorage = false + @storagePartitionId = value + result + +# Sets up all of the webview attributes. +WebView::setupWebViewAttributes = -> + @attributes = {} + + # Initialize the attributes with special behavior (and custom attribute + # objects). + @attributes[webViewConstants.ATTRIBUTE_PARTITION] = new Partition(this) + + # Initialize the remaining attributes, which have default behavior. + defaultAttributes = [ + webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY + webViewConstants.ATTRIBUTE_AUTOSIZE + webViewConstants.ATTRIBUTE_MAXHEIGHT + webViewConstants.ATTRIBUTE_MAXWIDTH + webViewConstants.ATTRIBUTE_MINHEIGHT + webViewConstants.ATTRIBUTE_MINWIDTH + webViewConstants.ATTRIBUTE_SRC + webViewConstants.ATTRIBUTE_HTTPREFERRER + ] + + for attribute in defaultAttributes + @attributes[attribute] = new WebViewAttribute(attribute, this) diff --git a/atom/renderer/lib/web-view/web-view-constants.coffee b/atom/renderer/lib/web-view/web-view-constants.coffee index 37738a8b4b6c..f40f14c4d757 100644 --- a/atom/renderer/lib/web-view/web-view-constants.coffee +++ b/atom/renderer/lib/web-view/web-view-constants.coffee @@ -6,11 +6,17 @@ module.exports = ATTRIBUTE_MAXWIDTH: 'maxwidth' ATTRIBUTE_MINHEIGHT: 'minheight' ATTRIBUTE_MINWIDTH: 'minwidth' + ATTRIBUTE_NAME: 'name' ATTRIBUTE_PARTITION: 'partition' + ATTRIBUTE_SRC: 'src' + ATTRIBUTE_HTTPREFERRER: 'httpreferrer' ATTRIBUTE_NODEINTEGRATION: 'nodeintegration' ATTRIBUTE_PLUGINS: 'plugins' ATTRIBUTE_PRELOAD: 'preload' + # Internal attribute. + ATTRIBUTE_INTERNALINSTANCEID: 'internalinstanceid' + # Error messages. ERROR_MSG_ALREADY_NAVIGATED: 'The object has already navigated, so its partition cannot be changed.' ERROR_MSG_CANNOT_INJECT_SCRIPT: ': ' + diff --git a/atom/renderer/lib/web-view/web-view.coffee b/atom/renderer/lib/web-view/web-view.coffee index fef673659099..99f555f43182 100644 --- a/atom/renderer/lib/web-view/web-view.coffee +++ b/atom/renderer/lib/web-view/web-view.coffee @@ -4,6 +4,7 @@ webViewConstants = require './web-view-constants' webFrame = require 'web-frame' remote = require 'remote' +# Attributes. AUTO_SIZE_ATTRIBUTES = [ webViewConstants.ATTRIBUTE_AUTOSIZE, webViewConstants.ATTRIBUTE_MAXHEIGHT, @@ -16,38 +17,6 @@ AUTO_SIZE_ATTRIBUTES = [ nextId = 0 getNextId = -> ++nextId -# Represents the state of the storage partition. -class Partition - constructor: -> - @validPartitionId = true - @persistStorage = false - @storagePartitionId = '' - - toAttribute: -> - return '' unless @validPartitionId - (if @persistStorage then 'persist:' else '') + @storagePartitionId - - fromAttribute: (value, hasNavigated) -> - result = {} - if hasNavigated - result.error = webViewConstants.ERROR_MSG_ALREADY_NAVIGATED - return result - value ?= '' - - LEN = 'persist:'.length - if value.substr(0, LEN) == 'persist:' - value = value.substr LEN - unless value - @validPartitionId = false - result.error = webViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE - return result - @persistStorage = true - else - @persistStorage = false - - @storagePartitionId = value - result - # Represents the internal state of the WebView node. class WebView constructor: (@webviewNode) -> @@ -70,8 +39,7 @@ class WebView @browserPluginNode = @createBrowserPluginNode() shadowRoot = @webviewNode.createShadowRoot() - @partition = new Partition() - + @setupWebViewAttributes() @setupWebViewSrcAttributeMutationObserver() @setupFocusPropagation() @setupWebviewNodeProperties() @@ -107,7 +75,7 @@ class WebView @guestInstanceId = undefined @beforeFirstNavigation = true @validPartitionId = true - @partition.validPartitionId = true + @attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId = true @contentWindow = null @internalInstanceId = 0 @@ -135,9 +103,9 @@ class WebView setupAutoSizeProperties: -> for attributeName in AUTO_SIZE_ATTRIBUTES - this[attributeName] = @webviewNode.getAttribute attributeName + @attributes[attributeName].setValue @webviewNode.getAttribute(attributeName) Object.defineProperty @webviewNode, attributeName, - get: => this[attributeName] + get: => @attributes[attributeName].getValue() set: (value) => @webviewNode.setAttribute attributeName, value enumerable: true @@ -145,7 +113,7 @@ class WebView @setupAutoSizeProperties() Object.defineProperty @webviewNode, webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, - get: => @allowtransparency + get: => @attributes[webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY].getValue() set: (value) => @webviewNode.setAttribute webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, value enumerable: true @@ -159,25 +127,24 @@ class WebView # No setter. enumerable: true - Object.defineProperty @webviewNode, 'partition', - get: => @partition.toAttribute() + Object.defineProperty @webviewNode, webViewConstants.ATTRIBUTE_PARTITION, + get: => @attributes[webViewConstants.ATTRIBUTE_PARTITION].getValue() set: (value) => - result = @partition.fromAttribute value, @hasNavigated() + result = @attributes[webViewConstants.ATTRIBUTE_PARTITION].setValue value throw result.error if result.error? - @webviewNode.setAttribute 'partition', value + @webviewNode.setAttribute webViewConstants.ATTRIBUTE_PARTITION, value enumerable: true - @src = @webviewNode.getAttribute 'src' - Object.defineProperty @webviewNode, 'src', - get: => @src - set: (value) => @webviewNode.setAttribute 'src', value - # No setter. + @attributes[webViewConstants.ATTRIBUTE_SRC].setValue @webviewNode.getAttribute(webViewConstants.ATTRIBUTE_SRC) + Object.defineProperty @webviewNode, webViewConstants.ATTRIBUTE_SRC, + get: => @attributes[webViewConstants.ATTRIBUTE_SRC].getValue() + set: (value) => @webviewNode.setAttribute webViewConstants.ATTRIBUTE_SRC, value enumerable: true - @httpreferrer = @webviewNode.getAttribute 'httpreferrer' - Object.defineProperty @webviewNode, 'httpreferrer', - get: => @httpreferrer - set: (value) => @webviewNode.setAttribute 'httpreferrer', value + @attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER].setValue @webviewNode.getAttribute(webViewConstants.ATTRIBUTE_HTTPREFERRER) + Object.defineProperty @webviewNode, webViewConstants.ATTRIBUTE_HTTPREFERRER, + get: => @attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER].getValue() + set: (value) => @webviewNode.setAttribute webViewConstants.ATTRIBUTE_HTTPREFERRER, value enumerable: true # The purpose of this mutation observer is to catch assignment to the src @@ -194,7 +161,11 @@ class WebView params = attributes: true, attributeOldValue: true, - attributeFilter: ['src', 'partition', 'httpreferrer'] + attributeFilter: [ + webViewConstants.ATTRIBUTE_SRC + webViewConstants.ATTRIBUTE_PARTITION + webViewConstants.ATTRIBUTE_HTTPREFERRER + ] @srcAndPartitionObserver.observe @webviewNode, params # This observer monitors mutations to attributes of the and @@ -204,18 +175,18 @@ class WebView # details. handleWebviewAttributeMutation: (name, oldValue, newValue) -> if name in AUTO_SIZE_ATTRIBUTES - this[name] = newValue + @attributes[name].setValue newValue return unless @guestInstanceId # Convert autosize attribute to boolean. autosize = @webviewNode.hasAttribute webViewConstants.ATTRIBUTE_AUTOSIZE guestViewInternal.setAutoSize @guestInstanceId, enableAutoSize: autosize, min: - width: parseInt @minwidth || 0 - height: parseInt @minheight || 0 + width: parseInt @attributes[webViewConstants.ATTRIBUTE_MINWIDTH].getValue() || 0 + height: parseInt @attributes[webViewConstants.ATTRIBUTE_MINHEIGHT].getValue() || 0 max: - width: parseInt @maxwidth || 0 - height: parseInt @maxheight || 0 + width: parseInt @attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() || 0 + height: parseInt @attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() || 0 else if name is webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY # We treat null attribute (attribute removed) and the empty string as # one case. @@ -223,19 +194,19 @@ class WebView newValue ?= '' return if oldValue is newValue - @allowtransparency = newValue != '' + @attributes[webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY].setValue(newValue != '') return unless @guestInstanceId - guestViewInternal.setAllowTransparency @guestInstanceId, @allowtransparency - else if name is 'httpreferrer' + guestViewInternal.setAllowTransparency @guestInstanceId, @attributes[webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY].getValue() + else if name is webViewConstants.ATTRIBUTE_HTTPREFERRER oldValue ?= '' newValue ?= '' if newValue == '' and oldValue != '' - @webviewNode.setAttribute 'httpreferrer', oldValue + @webviewNode.setAttribute webViewConstants.ATTRIBUTE_HTTPREFERRER, oldValue - @httpreferrer = newValue + @attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER].setValue newValue result = {} # If the httpreferrer changes treat it as though the src changes and reload @@ -243,7 +214,7 @@ class WebView @parseSrcAttribute result throw result.error if result.error? - else if name is 'src' + else if name is webViewConstants.ATTRIBUTE_SRC # We treat null attribute (attribute removed) and the empty string as # one case. oldValue ?= '' @@ -256,7 +227,7 @@ class WebView # the next src attribute handler call to avoid reloading the page # on every guest-initiated navigation. @ignoreNextSrcAttributeChange = true - @webviewNode.setAttribute 'src', oldValue + @webviewNode.setAttribute webViewConstants.ATTRIBUTE_SRC, oldValue @src = newValue if @ignoreNextSrcAttributeChange # Don't allow the src mutation observer to see this change. @@ -267,13 +238,13 @@ class WebView @parseSrcAttribute result throw result.error if result.error? - else if name is 'partition' + else if name is webViewConstants.ATTRIBUTE_PARTITION # Note that throwing error here won't synchronously propagate. - @partition.fromAttribute newValue, @hasNavigated() + @attributes[webViewConstants.ATTRIBUTE_PARTITION].setValue newValue handleBrowserPluginAttributeMutation: (name, oldValue, newValue) -> - if name is 'internalinstanceid' and !oldValue and !!newValue - @browserPluginNode.removeAttribute 'internalinstanceid' + if name is webViewConstants.ATTRIBUTE_INTERNALINSTANCEID and !oldValue and !!newValue + @browserPluginNode.removeAttribute webViewConstants.ATTRIBUTE_INTERNALINSTANCEID @internalInstanceId = parseInt newValue if !!@guestInstanceId and @guestInstanceId != 0 @@ -337,12 +308,12 @@ class WebView not @beforeFirstNavigation parseSrcAttribute: (result) -> - unless @partition.validPartitionId + unless @attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId result.error = webViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE return - @src = @webviewNode.getAttribute 'src' + @attributes[webViewConstants.ATTRIBUTE_SRC].setValue @webviewNode.getAttribute(webViewConstants.ATTRIBUTE_SRC) - return unless @src + return unless @attributes[webViewConstants.ATTRIBUTE_SRC].getValue() unless @guestInstanceId? if @beforeFirstNavigation @@ -351,14 +322,15 @@ class WebView return # Navigate to |this.src|. - urlOptions = if @httpreferrer then {@httpreferrer} else {} - remote.getGuestWebContents(@guestInstanceId).loadUrl @src, urlOptions + httpreferrer = @attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER].getValue() + urlOptions = if httpreferrer then {httpreferrer} else {} + remote.getGuestWebContents(@guestInstanceId).loadUrl @attributes[webViewConstants.ATTRIBUTE_SRC].getValue(), urlOptions parseAttributes: -> return unless @elementAttached hasNavigated = @hasNavigated() - attributeValue = @webviewNode.getAttribute 'partition' - result = @partition.fromAttribute attributeValue, hasNavigated + attributeValue = @webviewNode.getAttribute webViewConstants.ATTRIBUTE_PARTITION + result = @attributes[webViewConstants.ATTRIBUTE_PARTITION].setValue attributeValue @parseSrcAttribute result createGuest: -> @@ -408,34 +380,34 @@ class WebView # Updates state upon loadcommit. onLoadCommit: (@baseUrlForDataUrl, @currentEntryIndex, @entryCount, @processId, url, isTopLevel) -> - oldValue = @webviewNode.getAttribute 'src' + oldValue = @webviewNode.getAttribute webViewConstants.ATTRIBUTE_SRC newValue = url if isTopLevel and (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 + this.webviewNode.setAttribute webViewConstants.ATTRIBUTE_SRC, newValue onAttach: (storagePartitionId) -> - @webviewNode.setAttribute 'partition', storagePartitionId - @partition.fromAttribute storagePartitionId, this.hasNavigated() + @webviewNode.setAttribute webViewConstants.ATTRIBUTE_PARTITION, storagePartitionId + @attributes[webViewConstants.ATTRIBUTE_PARTITION].setValue storagePartitionId buildAttachParams: (isNewWindow) -> - allowtransparency: @allowtransparency || false + allowtransparency: @attributes[webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY].getValue() || false autosize: @webviewNode.hasAttribute webViewConstants.ATTRIBUTE_AUTOSIZE instanceId: @viewInstanceId - maxheight: parseInt @maxheight || 0 - maxwidth: parseInt @maxwidth || 0 - minheight: parseInt @minheight || 0 - minwidth: parseInt @minwidth || 0 + maxheight: parseInt @attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() || 0 + maxwidth: parseInt @attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() || 0 + minheight: parseInt @attributes[webViewConstants.ATTRIBUTE_MINHEIGHT].getValue() || 0 + minwidth: parseInt @attributes[webViewConstants.ATTRIBUTE_MINWIDTH].getValue() || 0 # We don't need to navigate new window from here. - src: if isNewWindow then undefined else @src + src: if isNewWindow then undefined else @attributes[webViewConstants.ATTRIBUTE_SRC].getValue() # If we have a partition from the opener, that will also be already # set via this.onAttach(). - storagePartitionId: @partition.toAttribute() + storagePartitionId: @attributes[webViewConstants.ATTRIBUTE_PARTITION].getValue() userAgentOverride: @userAgentOverride - httpreferrer: @httpreferrer + httpreferrer: @attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER].getValue() attachWindow: (guestInstanceId, isNewWindow) -> @guestInstanceId = guestInstanceId @@ -552,3 +524,5 @@ listener = (event) -> registerWebViewElement() window.removeEventListener event.type, listener, useCapture window.addEventListener 'readystatechange', listener, true + +module.exports = WebView