Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Shim that simulates a <webview> tag via Mutation Observers. | 5 // Shim that simulates a <webview> tag via Mutation Observers. |
| 6 // | 6 // |
| 7 // The actual tag is implemented via the browser plugin. The internals of this | 7 // The actual tag is implemented via the browser plugin. The internals of this |
| 8 // are hidden via Shadow DOM. | 8 // are hidden via Shadow DOM. |
| 9 | 9 |
| 10 var webRequestEvent = require('webRequest').webRequestEvent; | |
| 11 | |
| 10 var watchForTag = require("tagWatcher").watchForTag; | 12 var watchForTag = require("tagWatcher").watchForTag; |
| 11 | 13 |
| 12 var WEB_VIEW_ATTRIBUTES = ['name', 'src', 'partition', 'autosize', 'minheight', | 14 var WEB_VIEW_ATTRIBUTES = ['name', 'src', 'partition', 'autosize', 'minheight', |
| 13 'minwidth', 'maxheight', 'maxwidth']; | 15 'minwidth', 'maxheight', 'maxwidth']; |
| 14 | 16 |
| 15 // All exposed api methods for <webview>, these are forwarded to the browser | 17 // All exposed api methods for <webview>, these are forwarded to the browser |
| 16 // plugin. | 18 // plugin. |
| 17 var WEB_VIEW_API_METHODS = [ | 19 var WEB_VIEW_API_METHODS = [ |
| 18 'back', | 20 'back', |
| 19 'canGoBack', | 21 'canGoBack', |
| 20 'canGoForward', | 22 'canGoForward', |
| 21 'forward', | 23 'forward', |
| 22 'getProcessId', | 24 'getProcessId', |
| 23 'go', | 25 'go', |
| 24 'reload', | 26 'reload', |
| 25 'stop', | 27 'stop', |
| 26 'terminate' | 28 'terminate' |
| 27 ]; | 29 ]; |
| 28 | 30 |
| 29 var WEB_VIEW_EVENTS = { | 31 var WEB_VIEW_EVENTS = { |
| 30 'exit' : ['processId', 'reason'], | 32 'exit' : ['processId', 'reason'], |
| 31 'loadabort' : ['url', 'isTopLevel', 'reason'], | 33 'loadabort' : ['url', 'isTopLevel', 'reason'], |
| 32 'loadcommit' : ['url', 'isTopLevel'], | 34 'loadcommit' : ['url', 'isTopLevel'], |
| 33 'loadredirect' : ['oldUrl', 'newUrl', 'isTopLevel'], | 35 'loadredirect' : ['oldUrl', 'newUrl', 'isTopLevel'], |
| 34 'loadstart' : ['url', 'isTopLevel'], | 36 'loadstart' : ['url', 'isTopLevel'], |
| 35 'loadstop' : [], | 37 'loadstop' : [], |
| 36 'sizechanged': ['oldHeight', 'oldWidth', 'newHeight', 'newWidth'], | 38 'sizechanged': ['oldHeight', 'oldWidth', 'newHeight', 'newWidth'], |
| 37 }; | 39 }; |
| 38 | 40 |
| 41 var WEB_REQUEST_EVENTS = [ | |
| 42 'onBeforeRequest', | |
| 43 'onBeforeSendHeaders', | |
| 44 'onSendHeaders', | |
| 45 'onHeadersReceived', | |
| 46 'onAuthRequired', | |
| 47 'onBeforeRedirect', | |
| 48 'onResponseStarted', | |
| 49 'onCompleted', | |
| 50 'onErrorOccurred' | |
| 51 ]; | |
| 52 | |
| 39 window.addEventListener('DOMContentLoaded', function() { | 53 window.addEventListener('DOMContentLoaded', function() { |
| 40 watchForTag('WEBVIEW', function(addedNode) { new WebView(addedNode); }); | 54 watchForTag('WEBVIEW', function(addedNode) { new WebView(addedNode); }); |
| 41 }); | 55 }); |
| 42 | 56 |
| 43 /** | 57 /** |
| 44 * @constructor | 58 * @constructor |
| 45 */ | 59 */ |
| 46 function WebView(node) { | 60 function WebView(node) { |
| 47 this.node_ = node; | 61 this.node_ = node; |
| 48 var shadowRoot = node.webkitCreateShadowRoot(); | 62 var shadowRoot = node.webkitCreateShadowRoot(); |
| 49 | 63 |
| 50 this.objectNode_ = document.createElement('object'); | 64 this.objectNode_ = document.createElement('object'); |
| 51 this.objectNode_.type = 'application/browser-plugin'; | 65 this.objectNode_.type = 'application/browser-plugin'; |
| 52 // The <object> node fills in the <webview> container. | 66 // The <object> node fills in the <webview> container. |
| 53 this.objectNode_.style.width = '100%'; | 67 this.objectNode_.style.width = '100%'; |
| 54 this.objectNode_.style.height = '100%'; | 68 this.objectNode_.style.height = '100%'; |
| 55 WEB_VIEW_ATTRIBUTES.forEach(function(attributeName) { | 69 WEB_VIEW_ATTRIBUTES.forEach(function(attributeName) { |
| 56 // Only copy attributes that have been assigned values, rather than copying | 70 // Only copy attributes that have been assigned values, rather than copying |
| 57 // a series of undefined attributes to BrowserPlugin. | 71 // a series of undefined attributes to BrowserPlugin. |
| 58 if (this.node_.hasAttribute(attributeName)) { | 72 if (this.node_.hasAttribute(attributeName)) { |
| 59 this.objectNode_.setAttribute( | 73 this.objectNode_.setAttribute( |
| 60 attributeName, this.node_.getAttribute(attributeName)); | 74 attributeName, this.node_.getAttribute(attributeName)); |
| 61 } | 75 } |
| 62 }, this); | 76 }, this); |
| 77 this.onBeforeRequest_ = null; | |
| 63 | 78 |
| 64 shadowRoot.appendChild(this.objectNode_); | 79 shadowRoot.appendChild(this.objectNode_); |
| 65 | 80 |
| 66 // this.objectNode_[apiMethod] are not necessarily defined immediately after | 81 // this.objectNode_[apiMethod] are not necessarily defined immediately after |
| 67 // the shadow object is appended to the shadow root. | 82 // the shadow object is appended to the shadow root. |
| 68 var self = this; | 83 var self = this; |
| 69 WEB_VIEW_API_METHODS.forEach(function(apiMethod) { | 84 WEB_VIEW_API_METHODS.forEach(function(apiMethod) { |
| 70 node[apiMethod] = function(var_args) { | 85 node[apiMethod] = function(var_args) { |
| 71 return self.objectNode_[apiMethod].apply(self.objectNode_, arguments); | 86 return self.objectNode_[apiMethod].apply(self.objectNode_, arguments); |
| 72 }; | 87 }; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 106 }, | 121 }, |
| 107 set: function(value) { | 122 set: function(value) { |
| 108 objectNode[attributeName] = value; | 123 objectNode[attributeName] = value; |
| 109 }, | 124 }, |
| 110 enumerable: true | 125 enumerable: true |
| 111 }); | 126 }); |
| 112 }, this); | 127 }, this); |
| 113 | 128 |
| 114 // We cannot use {writable: true} property descriptor because we want dynamic | 129 // We cannot use {writable: true} property descriptor because we want dynamic |
| 115 // getter value. | 130 // getter value. |
| 131 WEB_REQUEST_EVENTS.forEach(function(eventName) { | |
| 132 Object.defineProperty(this.node_, eventName, { | |
| 133 get: function() { | |
| 134 if (!self[eventName + '_']) { | |
| 135 self[eventName + '_'] = | |
| 136 new webRequestEvent( | |
| 137 'webRequest.' + eventName, null, {}, null, | |
|
Matt Perry
2013/02/05 00:47:25
right here, you could use a different prefix for t
| |
| 138 self.objectNode_.getProcessId(), | |
| 139 self.objectNode_.getRouteId()); | |
| 140 } | |
| 141 return self[eventName + '_']; | |
| 142 }, | |
| 143 // No setter. | |
| 144 enumerable: true | |
| 145 }); | |
| 146 }, this); | |
| 147 | |
| 116 Object.defineProperty(this.node_, 'contentWindow', { | 148 Object.defineProperty(this.node_, 'contentWindow', { |
| 117 get: function() { | 149 get: function() { |
| 118 // TODO(fsamuel): This is a workaround to enable | 150 // TODO(fsamuel): This is a workaround to enable |
| 119 // contentWindow.postMessage until http://crbug.com/152006 is fixed. | 151 // contentWindow.postMessage until http://crbug.com/152006 is fixed. |
| 120 if (objectNode.contentWindow) | 152 if (objectNode.contentWindow) |
| 121 return objectNode.contentWindow.self; | 153 return objectNode.contentWindow.self; |
| 122 console.error('contentWindow is not available at this time. ' + | 154 console.error('contentWindow is not available at this time. ' + |
| 123 'It will become available when the page has finished loading.'); | 155 'It will become available when the page has finished loading.'); |
| 124 }, | 156 }, |
| 125 // No setter. | 157 // No setter. |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 168 var node = this.node_; | 200 var node = this.node_; |
| 169 this.objectNode_.addEventListener('-internal-' + eventname, function(e) { | 201 this.objectNode_.addEventListener('-internal-' + eventname, function(e) { |
| 170 var evt = new Event(eventname, { bubbles: true }); | 202 var evt = new Event(eventname, { bubbles: true }); |
| 171 var detail = e.detail ? JSON.parse(e.detail) : {}; | 203 var detail = e.detail ? JSON.parse(e.detail) : {}; |
| 172 attribs.forEach(function(attribName) { | 204 attribs.forEach(function(attribName) { |
| 173 evt[attribName] = detail[attribName]; | 205 evt[attribName] = detail[attribName]; |
| 174 }); | 206 }); |
| 175 node.dispatchEvent(evt); | 207 node.dispatchEvent(evt); |
| 176 }); | 208 }); |
| 177 } | 209 } |
| OLD | NEW |