Index: ios/web/web_state/js/resources/core_dynamic_ui.js |
diff --git a/ios/web/web_state/js/resources/core_dynamic_ui.js b/ios/web/web_state/js/resources/core_dynamic_ui.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e8988b723f0e35ff223e3126494244bc51a493d9 |
--- /dev/null |
+++ b/ios/web/web_state/js/resources/core_dynamic_ui.js |
@@ -0,0 +1,157 @@ |
+// Copyright 2014 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. |
+ |
+// Scripts that are conceptually part of core.js, but have UIWebView-specific |
+// details/behaviors. |
+ |
+goog.provide('__crweb.core_dynamic_ui'); |
+ |
+/** |
+ * Namespace for this module. |
+ */ |
+__gCrWeb.core_dynamic = {}; |
+ |
+/* Beginning of anonymous object. */ |
+new function() { |
+ /** |
+ * Resets common.JSONStringify to a clean copy. This can be called to ensure |
+ * that its copy is not of an override injected earlier by the page. This |
+ * must be called after document.body is present. |
+ */ |
+ var resetJsonStringify_ = function() { |
+ var frame = document.createElement('iframe'); |
+ // crwebnull protocol returns NO immediately to reject the load attempt. |
+ // A new frame is still created with an independent window object. |
+ frame.src = 'crwebnull://'; |
+ document.body.appendChild(frame); |
+ // One some occasions the contentWindow is not available, or the JSON object |
+ // is not available. It is not clear why, but this defense still has value |
+ // when it can be applied. |
+ if (frame.contentWindow && frame.contentWindow.JSON) { |
+ // Refresh original stringify object from new window reference (if |
+ // available) in case the originally retained version was not the native |
+ // version. |
+ __gCrWeb.common.JSONStringify = frame.contentWindow.JSON.stringify; |
+ } |
+ document.body.removeChild(frame); |
+ }; |
+ |
+ /** |
+ * Adds UIWebView specific event listeners. |
+ */ |
+ __gCrWeb.core_dynamic.addEventListeners = function() { |
+ window.addEventListener('unload', function(evt) { |
+ // In the case of a newly-created UIWebView, the URL starts as |
+ // about:blank, the window.unload event fires, and then the URL changes. |
+ // However, at this point the window object is *not* reset. After this, |
+ // when the page changes for any reason the window object *is* reset. |
+ // For this reason, we do not report the window.unload event from the |
+ // default page to the first URL. |
+ // This is sent as an immediate command because if the message arrives |
+ // after the page change has taken effect, false positive security errors |
+ // can occur. |
+ if (!document._defaultPage) |
+ __gCrWeb.message.invokeOnHostImmediate({'command': 'window.unload'}); |
+ }); |
+ }; |
+ |
+ /** |
+ * Applies UIWebView specific document-level overrides. These overrides |
+ * require the document body to be present; therefore the method sets event |
+ * listeners and timers to retry upon document body load if document body is |
+ * not yet present. Returns false if on default page or document is not |
+ * present. |
+ */ |
+ __gCrWeb.core_dynamic.documentInject = function() { |
+ // The default page gets the injections to the window object, but not the |
+ // document object. On the first occasion the page changes (from the default |
+ // about:blank) the window.unload event fires but the window object does not |
+ // actually reset. However by the time the DOMContentLoaded event fires the |
+ // document object will have been reset (to a non-default page). |
+ if (document && document['_defaultPage']) { |
+ window.addEventListener('DOMContentLoaded', __gCrWeb.core.documentInject); |
+ return false; |
+ } |
+ if (!document || !document.body) { |
+ // Either the document or document body is not yet available... retest in |
+ // 1 / 4 of a second. |
+ window.setTimeout(__gCrWeb.core.documentInject, 250); |
+ return false; |
+ } |
+ |
+ // Try to guarantee a clean copy of common.JSONStringify. |
+ resetJsonStringify_(); |
+ |
+ // Flush the message queue and send document.present message, if load has |
+ // not been aborted. |
+ if (!document._cancelled) { |
+ if (__gCrWeb.message) { |
+ __gCrWeb.message.invokeQueues(); |
+ } |
+ __gCrWeb.message.invokeOnHost({'command': 'document.present'}); |
+ } |
+ |
+ // Add event listener for title changes. |
+ var lastSeenTitle = document.title; |
+ document.addEventListener('DOMSubtreeModified', function(evt) { |
+ if (document.title !== lastSeenTitle) { |
+ lastSeenTitle = document.title; |
+ __gCrWeb.message.invokeOnHost({'command': 'document.retitled'}); |
+ } |
+ }); |
+ |
+ return true; |
+ }; |
+ |
+ /** |
+ * Notifies client and handles post-document load tasks when document has |
+ * finished loading. |
+ */ |
+ __gCrWeb.core_dynamic.handleDocumentLoaded = function() { |
+ var invokeOnHost_ = __gCrWeb.message.invokeOnHost; |
+ var loaded_ = function() { |
+ invokeOnHost_({'command': 'document.loaded'}); |
+ // Send the favicons to the browser. |
+ invokeOnHost_({'command': 'document.favicons', |
+ 'favicons': __gCrWeb.common.getFavicons()}); |
+ // Add placeholders for plugin content. |
+ if (__gCrWeb.common.updatePluginPlaceholders()) |
+ __gCrWeb.message.invokeOnHost({'command': 'addPluginPlaceholders'}); |
+ }; |
+ |
+ if (document.readyState === 'loaded' || document.readyState === 'complete') |
+ loaded_(); |
+ else |
+ window.addEventListener('load', loaded_); |
+ } |
+ |
+ |
+ /** |
+ * Sends anchor.click message. |
+ */ |
+ __gCrWeb.core_dynamic.handleInternalClickEvent = function(node) { |
+ __gCrWeb.message.invokeOnHost({'command': 'anchor.click', |
+ 'href': node.href}); |
+ } |
+ |
+ /** |
+ * Called when history.pushState and history.replaceState are invoked. |
+ */ |
+ __gCrWeb.core_dynamic.historyWillChangeState = function () { |
+ // UIWebViewWebController does not need to be notified prior to |
+ // history.pushState or history.replaceState calls. |
+ }; |
+ |
+ /** |
+ * Exits Fullscreen video by calling webkitExitFullScreen on every video |
+ * element. |
+ */ |
+ __gCrWeb['exitFullscreenVideo'] = function() { |
+ var videos = document.getElementsByTagName('video'); |
+ var videosLength = videos.length; |
+ for (var i = 0; i < videosLength; ++i) { |
+ videos[i].webkitExitFullScreen(); |
+ } |
+ }; |
+} |