WebViewImpl = require './web-view' guestViewInternal = require './guest-view-internal' webViewConstants = require './web-view-constants' remote = require 'remote' # Helper function to resolve url set in attribute. a = document.createElement 'a' resolveUrl = (url) -> a.href = url a.href # Attribute objects. # Default implementation of a WebView attribute. class WebViewAttribute constructor: (name, webViewImpl) -> @name = name @webViewImpl = webViewImpl @ignoreMutation = false @defineProperty() # Retrieves and returns the attribute's value. getValue: -> @webViewImpl.webviewNode.getAttribute(@name) || '' # Sets the attribute's value. setValue: (value) -> @webViewImpl.webviewNode.setAttribute(@name, value || '') # Changes the attribute's value without triggering its mutation handler. setValueIgnoreMutation: (value) -> @ignoreMutation = true @setValue value @ignoreMutation = false # Defines this attribute as a property on the webview node. defineProperty: -> Object.defineProperty @webViewImpl.webviewNode, @name, get: => @getValue() set: (value) => @setValue value enumerable: true # Called when the attribute's value changes. handleMutation: -> # An attribute that is treated as a Boolean. class BooleanAttribute extends WebViewAttribute constructor: (name, webViewImpl) -> super name, webViewImpl getValue: -> @webViewImpl.webviewNode.hasAttribute @name setValue: (value) -> unless value @webViewImpl.webviewNode.removeAttribute @name else @webViewImpl.webviewNode.setAttribute @name, '' # Attribute that specifies whether transparency is allowed in the webview. class AllowTransparencyAttribute extends BooleanAttribute constructor: (webViewImpl) -> super webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, webViewImpl handleMutation: (oldValue, newValue) -> return unless @webViewImpl.guestInstanceId guestViewInternal.setAllowTransparency @webViewImpl.guestInstanceId, @getValue() # Attribute used to define the demension limits of autosizing. class AutosizeDimensionAttribute extends WebViewAttribute constructor: (name, webViewImpl) -> super name, webViewImpl getValue: -> parseInt(@webViewImpl.webviewNode.getAttribute(@name)) || 0 handleMutation: (oldValue, newValue) -> return unless @webViewImpl.guestInstanceId guestViewInternal.setSize @webViewImpl.guestInstanceId, enableAutoSize: @webViewImpl.attributes[webViewConstants.ATTRIBUTE_AUTOSIZE].getValue() min: width: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MINWIDTH].getValue() || 0 height: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MINHEIGHT].getValue() || 0 max: width: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() || 0 height: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() || 0 # Attribute that specifies whether the webview should be autosized. class AutosizeAttribute extends BooleanAttribute constructor: (webViewImpl) -> super webViewConstants.ATTRIBUTE_AUTOSIZE, webViewImpl handleMutation: AutosizeDimensionAttribute::handleMutation # Attribute representing the state of the storage partition. class PartitionAttribute extends WebViewAttribute constructor: (webViewImpl) -> super webViewConstants.ATTRIBUTE_PARTITION, webViewImpl @validPartitionId = true handleMutation: (oldValue, newValue) -> newValue = newValue || '' # The partition cannot change if the webview has already navigated. unless @webViewImpl.beforeFirstNavigation window.console.error webViewConstants.ERROR_MSG_ALREADY_NAVIGATED @setValueIgnoreMutation oldValue return if newValue is 'persist:' @validPartitionId = false window.console.error webViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE # Attribute that handles the location and navigation of the webview. class SrcAttribute extends WebViewAttribute constructor: (webViewImpl) -> super webViewConstants.ATTRIBUTE_SRC, webViewImpl @setupMutationObserver() getValue: -> if @webViewImpl.webviewNode.hasAttribute @name resolveUrl @webViewImpl.webviewNode.getAttribute(@name) else '' setValueIgnoreMutation: (value) -> WebViewAttribute::setValueIgnoreMutation 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. @observer.takeRecords() handleMutation: (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 not newValue and 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. @setValueIgnoreMutation oldValue return @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. setupMutationObserver: -> @observer = new MutationObserver (mutations) => for mutation in mutations oldValue = mutation.oldValue newValue = @getValue() return if oldValue isnt newValue @handleMutation oldValue, newValue params = attributes: true, attributeOldValue: true, attributeFilter: [@name] @observer.observe @webViewImpl.webviewNode, params parse: -> if not @webViewImpl.elementAttached or not @webViewImpl.attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId or not @.getValue() return unless @webViewImpl.guestInstanceId? if @webViewImpl.beforeFirstNavigation @webViewImpl.beforeFirstNavigation = false @webViewImpl.createGuest() return # Navigate to |this.src|. opts = {} httpreferrer = @webViewImpl.attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER].getValue() if httpreferrer then opts.httpReferrer = httpreferrer useragent = @webViewImpl.attributes[webViewConstants.ATTRIBUTE_USERAGENT].getValue() if useragent then opts.userAgent = useragent guestContents = remote.getGuestWebContents(@webViewImpl.guestInstanceId) guestContents.loadUrl @getValue(), opts # Attribute specifies HTTP referrer. class HttpReferrerAttribute extends WebViewAttribute constructor: (webViewImpl) -> super webViewConstants.ATTRIBUTE_HTTPREFERRER, webViewImpl # Attribute specifies user agent class UserAgentAttribute extends WebViewAttribute constructor: (webViewImpl) -> super webViewConstants.ATTRIBUTE_USERAGENT, webViewImpl # Attribute that set preload script. class PreloadAttribute extends WebViewAttribute constructor: (webViewImpl) -> super webViewConstants.ATTRIBUTE_PRELOAD, webViewImpl getValue: -> return '' unless @webViewImpl.webviewNode.hasAttribute @name preload = resolveUrl @webViewImpl.webviewNode.getAttribute(@name) protocol = preload.substr 0, 5 unless protocol is 'file:' console.error webViewConstants.ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE preload = '' preload # Sets up all of the webview attributes. WebViewImpl::setupWebViewAttributes = -> @attributes = {} @attributes[webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY] = new AllowTransparencyAttribute(this) @attributes[webViewConstants.ATTRIBUTE_AUTOSIZE] = new AutosizeAttribute(this) @attributes[webViewConstants.ATTRIBUTE_PARTITION] = new PartitionAttribute(this) @attributes[webViewConstants.ATTRIBUTE_SRC] = new SrcAttribute(this) @attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER] = new HttpReferrerAttribute(this) @attributes[webViewConstants.ATTRIBUTE_USERAGENT] = new UserAgentAttribute(this) @attributes[webViewConstants.ATTRIBUTE_NODEINTEGRATION] = new BooleanAttribute(webViewConstants.ATTRIBUTE_NODEINTEGRATION, this) @attributes[webViewConstants.ATTRIBUTE_PLUGINS] = new BooleanAttribute(webViewConstants.ATTRIBUTE_PLUGINS, this) @attributes[webViewConstants.ATTRIBUTE_DISABLEWEBSECURITY] = new BooleanAttribute(webViewConstants.ATTRIBUTE_DISABLEWEBSECURITY, this) @attributes[webViewConstants.ATTRIBUTE_PRELOAD] = new PreloadAttribute(this) autosizeAttributes = [ webViewConstants.ATTRIBUTE_MAXHEIGHT webViewConstants.ATTRIBUTE_MAXWIDTH webViewConstants.ATTRIBUTE_MINHEIGHT webViewConstants.ATTRIBUTE_MINWIDTH ] for attribute in autosizeAttributes @attributes[attribute] = new AutosizeDimensionAttribute(attribute, this)