Commit 1ab833b2 authored by stuartmorgan's avatar stuartmorgan Committed by Commit bot

Upstream ios/web/ JS files

This upstreams all the injected JS for the web layer (but not any of
the packaging bits, which will come later)

BUG=464810

Review URL: https://codereview.chromium.org/1029983002

Cr-Commit-Position: refs/heads/master@{#322080}
parent 187d3948
......@@ -8,6 +8,8 @@
// this.style because member identifiers are minified by default.
// See http://goo.gl/FwOgy
goog.provide('__crweb.base');
// This object is checked on the main app to know when to inject (or not).
window['__gCrWeb'] = {};
......@@ -4,6 +4,8 @@
// This file provides common methods that can be shared by other JavaScripts.
goog.provide('__crweb.common');
/**
* Namespace for this file. It depends on |__gCrWeb| having already been
* injected. String 'common' is used in |__gCrWeb['common']| as it needs to be
......@@ -576,4 +578,115 @@ new function() {
element.dispatchEvent(changeEvent);
}, 0);
};
/**
* Retrieves favicon information.
*
* @return {Object} Object containing favicon data.
*/
__gCrWeb.common.getFavicons = function() {
var favicons = [];
var hasFavicon = false;
favicons.toJSON = null; // Never inherit Array.prototype.toJSON.
var links = document.getElementsByTagName('link');
var linkCount = links.length;
for (var i = 0; i < linkCount; ++i) {
if (links[i].rel) {
var rel = links[i].rel.toLowerCase();
if (rel == 'shortcut icon' ||
rel == 'icon' ||
rel == 'apple-touch-icon' ||
rel == 'apple-touch-icon-precomposed') {
var favicon = {
rel: links[i].rel.toLowerCase(),
href: links[i].href
};
favicons.push(favicon);
if (rel == 'icon' || rel == 'shortcut icon') {
hasFavicon = true;
}
}
}
}
if (!hasFavicon) {
// If an HTTP(S)? webpage does not reference a "favicon" then search
// for a file named "favicon.ico" at the root of the website (legacy).
// http://en.wikipedia.org/wiki/Favicon
var location = document.location;
if (location.protocol == 'http:' || location.protocol == 'https:') {
var favicon = {
rel: 'icon',
href: location.origin + '/favicon.ico'
};
favicons.push(favicon);
}
}
return favicons;
};
/**
* Checks whether an <object> node is plugin content (as <object> can also be
* used to embed images).
* @param {HTMLElement} node The <object> node to check.
* @return {Boolean} Whether the node appears to be a plugin.
* @private
*/
var objectNodeIsPlugin_ = function(node) {
return node.hasAttribute('classid') ||
(node.hasAttribute('type') && node.type.indexOf('image/') != 0);
};
/**
* Checks whether plugin a node has fallback content.
* @param {HTMLElement} node The node to check.
* @return {Boolean} Whether the node has fallback.
* @private
*/
var pluginHasFallbackContent_ = function(node) {
return node.textContent.trim().length > 0 ||
node.getElementsByTagName('img').length > 0;
};
/**
* Returns a list of plugin elements in the document that have no fallback
* content. For nested plugins, only the innermost plugin element is returned.
* @return {Array} A list of plugin elements.
* @private
*/
var findPluginNodesWithoutFallback_ = function() {
var pluginNodes = [];
var objects = document.getElementsByTagName('object');
var objectCount = objects.length;
for (var i = 0; i < objectCount; i++) {
var object = objects[i];
if (objectNodeIsPlugin_(object) &&
!pluginHasFallbackContent_(object)) {
pluginNodes.push(object);
}
}
var applets = document.getElementsByTagName('applet');
var appletsCount = applets.length;
for (var i = 0; i < appletsCount; i++) {
var applet = applets[i];
if (!pluginHasFallbackContent_(applet)) {
pluginNodes.push(applet);
}
}
return pluginNodes;
};
/**
* Finds and stores any plugins that don't have placeholders.
* Returns true if any plugins without placeholders are found.
*/
__gCrWeb.common.updatePluginPlaceholders = function() {
var plugins = findPluginNodesWithoutFallback_();
if (plugins.length > 0) {
// Store the list of plugins in a known place for the replacement script
// to use, then trigger it.
__gCrWeb['placeholderTargetPlugins'] = plugins;
return true;
}
return false;
};
} // End of anonymous object
// Copyright 2015 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 to allow page console.log() etc. output to be seen on the console
// of the host application.
goog.provide('__crweb.console');
/**
* Namespace for this module.
*/
__gCrWeb.console = {};
/* Beginning of anonymous object. */
new function() {
function sendConsoleMessage(method, originalArguments) {
message = Array.prototype.slice.call(originalArguments).join(' ');
__gCrWeb.message.invokeOnHost({'command': 'console',
'method': method,
'message': message,
'origin': document.location.origin});
}
console.log = function() {
sendConsoleMessage('log', arguments);
};
console.debug = function() {
sendConsoleMessage('debug', arguments);
};
console.info = function() {
sendConsoleMessage('info', arguments);
};
console.warn = function() {
sendConsoleMessage('warn', arguments);
};
console.error = function() {
sendConsoleMessage('error', arguments);
};
}
This diff is collapsed.
// 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();
}
};
}
// 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 WKWebView-specific
// details/behaviors.
goog.provide('__crweb.core_dynamic_wk');
/**
* Namespace for this module.
*/
__gCrWeb.core_dynamic = {};
/* Beginning of anonymous object. */
new function() {
/**
* Adds WKWebView specific event listeners.
*/
__gCrWeb.core_dynamic.addEventListeners = function() {
// So far there are no WKWebView specific event listeners.
};
/**
* Applies WKWebView specific document-level overrides. Script injection for
* WKWebView always happens after the document is presented; therefore, there
* is no need to provide for invoking documentInject at a later time.
*/
__gCrWeb.core_dynamic.documentInject = function() {
// Flush the message queue.
if (__gCrWeb.message) {
__gCrWeb.message.invokeQueues();
}
return true;
};
/**
* Handles document load completion tasks. Invoked from
* [WKNavigationDelegate webView:didFinishNavigation:], when document load is
* complete.
*/
__gCrWeb.didFinishNavigation = function() {
// Send the favicons to the browser.
__gCrWeb.message.invokeOnHost({'command': 'document.favicons',
'favicons': __gCrWeb.common.getFavicons()});
// Add placeholders for plugin content.
if (__gCrWeb.common.updatePluginPlaceholders())
__gCrWeb.message.invokeOnHost({'command': 'addPluginPlaceholders'});
}
/**
* Sends window.history.willChangeState message. Called when
* history.pushState and history.replaceState are invoked.
*/
__gCrWeb.core_dynamic.historyWillChangeState = function() {
__gCrWeb.message.invokeOnHost(
{'command': 'window.history.willChangeState'});
};
}
// 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.
goog.provide('__crweb.dialog_overrides');
// Namespace for this module.
__gCrWeb.dialogOverrides = {};
// Beginning of anonymous object.
new function() {
/*
* Install a wrapper around functions displaying dialogs in order to catch
* code displaying dialog.
*
* Since the Javascript on the page may cache the value of those functions
* and invoke them later, we must only install the wrapper once and change
* their behaviour when required.
*
* Returns a function that allows changing the value of the two booleans
* |suppressDialogs| and |notifyAboutDialogs| that are tested by the wrappers.
*/
var installDialogOverridesMethods = function() {
var suppressDialogs = false;
var notifyAboutDialogs = false;
// Returns a wrapper function around |originalDialog|. The wrapper may
// suppress the dialog and notify host about show/suppress.
var makeDialogWrapper = function(originalDialogGetter) {
return function() {
if (!suppressDialogs) {
if (notifyAboutDialogs) {
__gCrWeb.message.invokeOnHost({'command': 'dialog.willShow'});
}
return originalDialogGetter().apply(null, arguments);
} else if (notifyAboutDialogs) {
__gCrWeb.message.invokeOnHost({'command': 'dialog.suppressed'});
}
};
};
// Install wrapper around the following properties of |window|.
var wrappedFunctionNames = ['alert', 'confirm', 'prompt', 'open'];
var len = wrappedFunctionNames.length;
for (var i = 0; i < len; i++) {
(function(wrappedFunctionName) {
var wrappedDialogMethod = window[wrappedFunctionName];
window[wrappedFunctionName] = makeDialogWrapper(
function() { return wrappedDialogMethod; });
})(wrappedFunctionNames[i]);
}
// Reading or writing to the property 'geolocation' too early breaks
// the API. Make a copy of navigator and stub in the required methods
// without touching the property. See crbug.com/280818 for more
// details.
var stubNavigator = {};
// Copy all properties and functions without touching 'geolocation'.
var oldNavigator = navigator;
for (var keyName in navigator) {
if (keyName !== 'geolocation') {
var value = navigator[keyName];
if (typeof(value) == 'function') {
// Forward functions calls to real navigator.
stubNavigator[keyName] = function() {
return value.apply(oldNavigator, arguments);
}
} else {
Object['defineProperty'](stubNavigator, keyName, {
value: value,
configurable: false,
writable: false,
enumerable: true
});
}
}
}
// Stub in 'geolocation' if necessary, using delayed accessor for the
// 'geolocation' property of the original |navigator|.
if ('geolocation' in navigator) {
var geolocation = {};
var geoPropNames = ['getCurrentPosition', 'watchPosition', 'clearWatch'];
var len = geoPropNames.length;
for (var i = 0; i < len; i++) {
(function(geoPropName) {
geolocation[geoPropName] = makeDialogWrapper(function() {
return function() {
return oldNavigator.geolocation[geoPropName].apply(
oldNavigator.geolocation, arguments);
};
});
})(geoPropNames[i]);
}
stubNavigator.geolocation = geolocation;
}
// Install |stubNavigator| as |navigator|.
navigator = stubNavigator;
// Returns the closure allowing to change |suppressDialogs| and
// |notifyAboutDialogs| variables.
return function(setEnabled, setNotify) {
suppressDialogs = setEnabled;
notifyAboutDialogs = setNotify;
};
};
// Override certain methods that produce dialogs. This needs to be installed
// after other window methods overrides.
__gCrWeb['setSuppressDialogs'] = installDialogOverridesMethods();
} // End of anonymous object
......@@ -4,6 +4,8 @@
// Scripts for the message handler.
goog.provide('__crweb.message');
/**
* Namespace for this module.
*/
......
......@@ -4,6 +4,8 @@
// Scripts for the message handler for use with UIWebView.
goog.provide('__crweb.message_dynamic_ui');
/**
* Namespace for this module.
*/
......
......@@ -4,6 +4,8 @@
// Scripts for the message handler for use with WKWebView.
goog.provide('__crweb.message_dynamic_wk');
/**
* Namespace for this module.
*/
......
// Copyright 2013 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.
// This file adheres to closure-compiler conventions in order to enable
// compilation with ADVANCED_OPTIMIZATIONS. See http://goo.gl/FwOgy
//
// Installs and runs the plugin placeholder function on the |__gCrWeb| object.
/**
* Namespace for this file. It depends on |__gCrWeb| having already been
* injected.
*/
__gCrWeb['plugin'] = {};
/* Beginning of anonymous object. */
new function() {
/* Data-URL version of plugin_blocked_android.png. Served this way rather
* than with an intercepted URL to avoid messing up https pages.
*/
__gCrWeb['plugin'].imageData_ =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAQAAABLCVATAAAD' +
'aklEQVR4Xn2Wz2tcVRTHP/e+O28mMxONJKlF4kIkP4luXFgQuuxCBaG41IWrLupOXLur+A' +
'e4cmV3LiS6qujSLgq2CIKQUqS2YnWsRkzGSTIz7zyHw+EdchnkcOd+7+OeT84578tMwmet' +
'O1fkar1RRNAgUJuqbeEn/0RUcdS6UX7w0X54/93qw4V+m0IReBiizhAYpG52kfrO86+F9/' +
'YXNnukHOTpc5SHgpiOu1cT623FBELeGvgTXfppOAjN3dCKm7GIkWiY4LsBnqBPpGqAgN/z' +
'CDMMBsCWX+pwibd5hzdZZmLNOsxDm8VAzIkt1hX5NLucqgrZm3RlIC/XscKTNlAQpvncMi' +
'tAnEM33D4nqgbcosBSPT3DRTJ3+Cx+4UfV3/CQniMQQ5g2WMJkoGKHNodUCBDpsYEQ2KGm' +
'JBKIFPT4nYckB9ueaPxRscamWczco3qXLcR9wx4ndBsziqFSjaOCAWLm4kj0xhhSMVFli4' +
'opyYuLlJ7s+/xTE6IgcVBthUuW6goHZDiA5IeCAnFEhkKVxxQh+pnoqSeMCEw4Uvt5kEHP' +
'c8IyF3iJ5De1NYSAMOYvOtxgwBqv0wcE5rR4gcQGq9Sc5wt7bq2JtfYtI0Ys8mCmLhFg7q' +
'w6XKRStUHJiMJmpC8vglqypAOU/MwRiw7KYGKqxZSKqE/iTKrQAwGxv5oU4ZbzGHCTf1QN' +
'OTXbQhJ/gbxKjy85IPECHQSQ3EFUfM0+93iZgluM6LuzDUTJOXpc5jcWeDb3DjQrsMhj9t' +
'TdPcAq8mtjjunyFEtN8ohfOWaVZR88Qd2WKK15a5zoRY8ZmRaNIZ/yCZ/P1u0zY+9TASjc' +
'q04YMzBhqAAUBXf5iWcITGdql3aTtpIZVnxGYvSxj1VPXUB0EtHnxBoT6iwgeXEwQfwC69' +
'xmROAcr5DwESxa3XLGW9G9AgPGVKahzzb/UvEcq81PwCl/MyDMrUgxQeMH7tNniQW6nPKA' +
'e5TU3KUFjPmTRxyofUsFeFVQqyENBHDAYyodJhR0CFrnfaYECgvAjdogEwZCVySQaJ8Zeq' +
'AL874rsy+2ofT1ev5fkSdmihwF0jpOra/kskTHkGMckkG9Gg7Xvw9XtifXOy/GEgCr7H/r' +
'yepFOFy5fu1agI9XH71RbRWRrDmHOhrfLYrx9ndv3Wz98R+P7LgG2uyMvgAAAABJRU5Erk' +
'Jggg==';
/**
* Returns the first <embed> child of the given node, if any.
* @param {HTMLElement} node The node to check.
* @return {HTMLElement} The first <embed> child, or null.
* @private
*/
__gCrWeb['plugin'].getEmbedChild_ = function(node) {
if (node.hasChildNodes()) {
for (var i = 0; i < node.childNodes.length; i++) {
if (node.childNodes[i].nodeName === 'EMBED') {
return node.childNodes[i];
}
}
}
return null;
};
/**
* Returns the size for the given plugin element. For the common
* pattern of an IE-specific <object> wrapping an all-other-browsers <embed>,
* the object doesn't have real style info (most notably size), so this uses
* the embed in that case.
* @param {HTMLElement} plugin The <object> node to check.
* @return {Object} The size (width and height) for the plugin element.
* @private
*/
__gCrWeb['plugin'].getPluginSize_ = function(plugin) {
var style;
// For the common pattern of an IE-specific <object> wrapping an
// all-other-browsers <embed>, the object doesn't have real style info
// (most notably size), so this uses the embed in that case.
var embedChild = __gCrWeb['plugin'].getEmbedChild_(plugin);
if (embedChild) {
style = window.getComputedStyle(embedChild);
} else {
style = window.getComputedStyle(plugin);
}
var width = parseFloat(style.width);
var height = parseFloat(style.height);
if (plugin.tagName === 'APPLET') {
// Size computation doesn't always work correctly with applets in
// UIWebView, so use the attributes as fallbacks.
if (isNaN(width)) {
width = parseFloat(plugin.width);
}
if (isNaN(height)) {
height = parseFloat(plugin.height);
}
}
return {
'width': width,
'height': height
};
};
/**
* Checks whether an element is "significant". Whether a plugin is
* "significant" is a heuristic that attempts to determine if it's a critical
* visual element for the page (i.e., not invisible, or an incidental ad).
* @param {HTMLElement} plugin The <object> node to check.
* @return {Boolean} Whether the node is significant.
* @private
*/
__gCrWeb['plugin'].isSignificantPlugin_ = function(plugin) {
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
var pluginSize = __gCrWeb['plugin'].getPluginSize_(plugin);
var pluginWidth = parseFloat(pluginSize.width);
var pluginHeight = parseFloat(pluginSize.height);
// A plugin must be at least |significantFraction| of one dimension of the
// page, and a minimum size in the other dimension (to weed out banners and
// tall side ads).
var minSize = Math.min(200, windowWidth / 2, windowHeight / 2);
var significantFraction = 0.5;
return (pluginWidth > windowWidth * significantFraction &&
pluginHeight > minSize) ||
(pluginHeight > windowHeight * significantFraction &&
pluginWidth > minSize);
};
/**
* Walks the list of detected plugin elements, adding a placeholder to any
* that are "significant" (see above).
* @param {string} message The message to show in the placeholder.
*/
__gCrWeb['plugin']['addPluginPlaceholders'] = function(message) {
var plugins = __gCrWeb['placeholderTargetPlugins'];
for (i = 0; i < plugins.length; i++) {
var plugin = plugins[i];
if (!__gCrWeb['plugin'].isSignificantPlugin_(plugin)) {
continue;
}
var pluginSize = __gCrWeb['plugin'].getPluginSize_(plugin);
var widthStyle = pluginSize.width + 'px';
var heightStyle = pluginSize.height + 'px';
// The outer wrapper is a div with relative positioning, as an anchor for
// an inner absolute-position element, whose height is based on whether or
// not there's an embed. If there is, then it's zero height, to avoid
// affecting the layout of the (presumably-full-size) <embed> fallback. If
// not, it's full-height to ensure the placeholder takes up the right
// amount of space in the page layout. Width is full-width either way, to
// avoid being affected by container alignment.
var placeholder = document.createElement('div');
placeholder.style.width = widthStyle;
if (__gCrWeb['plugin'].getEmbedChild_(plugin)) {
placeholder.style.height = '0';
} else {
placeholder.style.height = heightStyle;
}
placeholder.style.position = 'relative';
// Inside is a full-plugin-size solid box.
var placeholderBox = document.createElement('div');
placeholderBox.style.position = 'absolute';
placeholderBox.style.boxSizing = 'border-box';
placeholderBox.style.width = widthStyle;
placeholderBox.style.height = heightStyle;
placeholderBox.style.border = '1px solid black';
placeholderBox.style.backgroundColor = '#808080';
placeholder.appendChild(placeholderBox);
// Inside that is the plugin placeholder image, centered.
var pluginImg = document.createElement('img');
var imageSize = 36;
pluginImg.width = imageSize;
pluginImg.height = imageSize;
pluginImg.style.position = 'absolute';
// Center vertically and horizontally.
var halfSize = imageSize / 2;
pluginImg.style.top = '50%';
pluginImg.style.marginTop = '-' + halfSize + 'px';
pluginImg.style.left = '50%';
pluginImg.style.marginLeft = '-' + halfSize + 'px';
pluginImg.src = __gCrWeb['plugin'].imageData_;
placeholderBox.appendChild(pluginImg);
// And below that, the message.
var label = document.createElement('p');
label.style.width = widthStyle;
label.style.height = '1.5em';
label.style.position = 'absolute';
// Position below the image.
label.style.top = '50%';
label.style.marginTop = imageSize + 'px';
// Center horizontally.
label.style.textAlign = 'center';
label.textContent = message;
placeholderBox.appendChild(label);
plugin.insertBefore(placeholder, plugin.firstChild);
}
};
} // End of anonymous object
// Copyright 2015 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.
// Set of scripts required by web layer backed up by UIWebView.
goog.provide('__crweb.web_bundle_ui');
goog.require('__crweb.base');
goog.require('__crweb.common');
goog.require('__crweb.core');
goog.require('__crweb.core_dynamic_ui');
goog.require('__crweb.console');
goog.require('__crweb.dialog_overrides');
goog.require('__crweb.message');
goog.require('__crweb.message_dynamic_ui');
goog.require('__crweb.window_open_ui');
// Copyright 2015 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.
// Set of scripts required by web layer backed up by WKWebView.
goog.provide('__crweb.web_bundle_wk');
goog.require('__crweb.base');
goog.require('__crweb.common');
goog.require('__crweb.core');
goog.require('__crweb.core_dynamic_wk');
goog.require('__crweb.console');
goog.require('__crweb.dialog_overrides');
goog.require('__crweb.message');
goog.require('__crweb.message_dynamic_wk');
// 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.
// This file adheres to closure-compiler conventions in order to enable
// compilation with ADVANCED_OPTIMIZATIONS. See http://goo.gl/FwOgy
// Script to set windowId.
// Namespace for module, used as presence beacon for injection checks.
__gCrWeb['windowIdObject'] = {};
new function() {
// CRWJSWindowIdManager replaces $(WINDOW_ID) with appropriate string upon
// injection.
__gCrWeb['windowId'] = '$(WINDOW_ID)';
// Wrap queues flushing in setTimeout to avoid reentrant calls.
// In some circumstances setTimeout does not work on iOS8 if set from
// injected script. There is an assumption that it's happen when the script
// has been injected too early. Do not place anything important to delayed
// function body, since there is no guarantee that it will ever be executed.
// TODO(eugenebut): Find out why setTimeout does not work (crbug.com/402682).
window.setTimeout(function() {
// Send messages queued since message.js injection.
if (__gCrWeb.message) {
__gCrWeb.message.invokeQueues();
}
}, 0);
}
// 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.window_open_ui');
// Namespace for this module.
__gCrWeb.windowOpen = {};
// Beginning of anonymous object.
new function() {
// Preserve a reference to the original window.open method.
__gCrWeb['originalWindowOpen'] = window.open;
// Object used to keep track of all windows opened from this window.
var openedWindows = {};
/**
* Checks if a child window exists with the given name and if so, sets its
* closed property to true and removes it from |openedWindows|.
* @param {String} windowName The name of the window to mark as closed.
*/
__gCrWeb['windowClosed'] = function(windowName) {
if (openedWindows.hasOwnProperty(windowName)) {
openedWindows[windowName].closed = true;
delete openedWindows[windowName];
}
};
function invokeOnHost_(command) {
__gCrWeb.message.invokeOnHost(command);
};
var invokeNotImplementedOnHost_ = function(methodName) {
invokeOnHost_({'command': 'window.error',
'message': methodName + ' is not implemented'});
};
// Define Object watch/unwatch functions to detect assignments to
// certain object properties. Handles defineProperty case only because
// this code runs in UIWebView (i.e. Safari).
var objectWatch = function(obj, prop, handler) {
var val = obj[prop];
if (delete obj[prop]) {
Object['defineProperty'](obj, prop, {
'get': function() {
return val;
},
'set': function(newVal) {
return val = handler.call(obj, prop, val, newVal);
}
});
}
};
/**
* Creates and returns a window proxy used to represent the window object and
* intercept calls made on it.
* @param {String} target The name of the window.
* @return {Object} A window proxy object for intercepting window methods.
* @private
*/
var createWindowProxy_ = function(target) {
// Create return window object.
// 'name' is always the original supplied name.
var windowProxy = {name: target};
// Define window object methods.
windowProxy.alert = function() {
invokeNotImplementedOnHost_('windowProxy.alert');
};
windowProxy.blur = function() {
invokeNotImplementedOnHost_('windowProxy.blur');
};
windowProxy.clearInterval = function() {
invokeNotImplementedOnHost_('windowProxy.clearInterval');
};
windowProxy.clearTimeout = function() {
invokeNotImplementedOnHost_('windowProxy.clearTimeout');
};
windowProxy.close = function() {
invokeOnHost_({'command': 'window.close',
'target': target});
};
windowProxy.confirm = function() {
invokeNotImplementedOnHost_('windowProxy.confirm');
};
windowProxy.createPopup = function() {
invokeNotImplementedOnHost_('windowProxy.createPopup');
};
windowProxy.focus = function() {
// Noop as the opened window always gets focus.
};
windowProxy.moveBy = function() {
invokeNotImplementedOnHost_('windowProxy.moveBy');
};
windowProxy.moveTo = function() {
invokeNotImplementedOnHost_('windowProxy.moveTo');
};
windowProxy.stop = function() {
invokeOnHost_({'command': 'window.stop',
'target': target});
};
windowProxy.open = function() {
invokeNotImplementedOnHost_('windowProxy.open');
};
windowProxy.print = function() {
invokeNotImplementedOnHost_('windowProxy.print');
};
windowProxy.prompt = function() {
invokeNotImplementedOnHost_('windowProxy.prompt');
};
windowProxy.resizeBy = function() {
invokeNotImplementedOnHost_('windowProxy.resizeBy');
};
windowProxy.resizeTo = function() {
invokeNotImplementedOnHost_('windowProxy.resizeTo');
};
windowProxy.scroll = function() {
invokeNotImplementedOnHost_('windowProxy.scroll');
};
windowProxy.scrollBy = function() {
invokeNotImplementedOnHost_('windowProxy.scrollBy');
};
windowProxy.scrollTo = function() {
invokeNotImplementedOnHost_('windowProxy.scrollTo');
};
windowProxy.setInterval = function() {
invokeNotImplementedOnHost_('windowProxy.setInterval');
};
windowProxy.setTimeout = function() {
invokeNotImplementedOnHost_('windowProxy.setTimeout');
};
// Define window object properties.
// The current window.
windowProxy.self = windowProxy;
// The topmost browser window.
windowProxy.top = windowProxy;
// Provide proxy document which supplies one method, document.write().
windowProxy.document = {};
windowProxy.document.title = '';
windowProxy.document.write = function(html) {
invokeOnHost_({'command': 'window.document.write',
'html': html,
'target': target});
};
windowProxy.document.open = function() {
// The open() method should open an output stream to collect the output
// from any document.write() or document.writeln() methods.
invokeNotImplementedOnHost_('windowProxy.document.open');
};
windowProxy.document.close = function() {
// The close() method should close the output stream previously opened
// with the document.open() method, and displays the collected data in
// this process.
invokeNotImplementedOnHost_('windowProxy.document.close');
};
windowProxy.location = {};
windowProxy.location.assign = function(url) {
windowProxy.location = url;
};
// Watch assignments to window.location and window.location.href.
// Invoke equivalent method in ObjC code.
var onWindowProxyLocationChange = function(prop, oldVal, newVal) {
invokeOnHost_({'command': 'window.location',
'value': __gCrWeb['getFullyQualifiedURL'](newVal),
'target': target});
return newVal;
};
objectWatch(windowProxy, 'location', onWindowProxyLocationChange);
objectWatch(windowProxy.location, 'href', onWindowProxyLocationChange);
windowProxy.closed = false;
return windowProxy;
};
// Intercept window.open calls.
window.open = function(url, target, features) {
if (target == '_parent' || target == '_self' || target == '_top') {
return __gCrWeb['originalWindowOpen'].call(window, url, target, features);
}
// Because of the difficulty of returning data from JS->ObjC calls, in the
// event of a blank window name the JS side chooses a pseudo-GUID to
// use as the window name which is passed to ObjC and mapped to the real
// Tab there.
var isTargetBlank = (typeof target == 'undefined' || target == '_blank' ||
target == '' || target == null);
if (isTargetBlank) {
target = '' + Date.now() + '-' + Math.random();
}
if (typeof(url) == 'undefined') {
// W3C recommended behavior.
url = 'about:blank';
}
invokeOnHost_({
'command': 'window.open',
'target': target,
'url': url,
'referrerPolicy': __gCrWeb.getPageReferrerPolicy()
});
// Create a new |windowProxy| if none already exists with |target| as its
// name.
var windowProxy;
if (openedWindows.hasOwnProperty(target)) {
windowProxy = openedWindows[target];
} else {
windowProxy = createWindowProxy_(target);
openedWindows[target] = windowProxy;
}
return windowProxy;
};
} // End of anonymous object
// 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.
goog.provide('__crweb.window_open_wk');
// WKWebView natively supports window.open so there is no need to install
// JavaScript-based fix. CRWJSWindowOpenManager always injected as multiple
// JS managers depend on it. The script does not have any content except
// presenceBeacon.
// Namespace for this module.
__gCrWeb.windowOpen = {};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment