| Index: ios/web/web_state/js/resources/context_menu.js
|
| diff --git a/ios/web/web_state/js/resources/context_menu.js b/ios/web/web_state/js/resources/context_menu.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ffd654bc361ad3ac54019befef6a87f13cc96606
|
| --- /dev/null
|
| +++ b/ios/web/web_state/js/resources/context_menu.js
|
| @@ -0,0 +1,269 @@
|
| +// Copyright 2017 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.
|
| +
|
| +/**
|
| + * @fileoverview APIs used by CRWContextMenuController.
|
| + */
|
| +
|
| +goog.provide('__crWeb.contextMenu');
|
| +
|
| +/** Beginning of anonymous object */
|
| +(function() {
|
| +
|
| + /**
|
| + * Returns the url of the image or link under the selected point. Returns an
|
| + * empty string if no links or images are found.
|
| + * @param {number} x Horizontal center of the selected point.
|
| + * @param {number} y Vertical center of the selected point.
|
| + * @return {!Object} An object of the form {
|
| + * href, // URL of the link under the point
|
| + * innerText, // innerText of the link, if the selected element is a link
|
| + * src, // src of the image, if the selected element is an image
|
| + * title, // title of the image, if the selected
|
| + * referrerPolicy
|
| + * }
|
| + * where:
|
| + * <ul>
|
| + * <li>href, innerText are set if the selected element is a link.
|
| + * <li>src, title are set if the selected element is an image.
|
| + * <li>href is also set if the selected element is an image with a link.
|
| + * <li>referrerPolicy is the referrer policy to use for navigations away
|
| + * from the current page.
|
| + * </ul>
|
| + */
|
| + __gCrWeb['getElementFromPoint'] = function(x, y) {
|
| + var hitCoordinates = spiralCoordinates_(x, y);
|
| + for (var index = 0; index < hitCoordinates.length; index++) {
|
| + var coordinates = hitCoordinates[index];
|
| +
|
| + var element = elementFromPoint_(coordinates.x, coordinates.y);
|
| + if (!element || !element.tagName) {
|
| + // Nothing under the hit point. Try the next hit point.
|
| + continue;
|
| + }
|
| +
|
| + if (getComputedWebkitTouchCallout_(element) === 'none')
|
| + continue;
|
| + // Also check element's ancestors. A bound on the level is used here to
|
| + // avoid large overhead when no links or images are found.
|
| + var level = 0;
|
| + while (++level < 8 && element && element != document) {
|
| + var tagName = element.tagName;
|
| + if (!tagName)
|
| + continue;
|
| + tagName = tagName.toLowerCase();
|
| +
|
| + if (tagName === 'input' || tagName === 'textarea' ||
|
| + tagName === 'select' || tagName === 'option') {
|
| + // If the element is a known input element, stop the spiral search and
|
| + // return empty results.
|
| + return {};
|
| + }
|
| +
|
| + if (tagName === 'a' && element.href) {
|
| + // Found a link.
|
| + return {
|
| + href: element.href,
|
| + referrerPolicy: getReferrerPolicy_(element),
|
| + innerText: element.innerText
|
| + };
|
| + }
|
| +
|
| + if (tagName === 'img' && element.src) {
|
| + // Found an image.
|
| + var result = {
|
| + src: element.src,
|
| + referrerPolicy: getReferrerPolicy_()
|
| + };
|
| + // Copy the title, if any.
|
| + if (element.title) {
|
| + result.title = element.title;
|
| + }
|
| + // Check if the image is also a link.
|
| + var parent = element.parentNode;
|
| + while (parent) {
|
| + if (parent.tagName &&
|
| + parent.tagName.toLowerCase() === 'a' &&
|
| + parent.href) {
|
| + // This regex identifies strings like void(0),
|
| + // void(0) ;void(0);, ;;;;
|
| + // which result in a NOP when executed as JavaScript.
|
| + var regex = RegExp("^javascript:(?:(?:void\\(0\\)|;)\\s*)+$");
|
| + if (parent.href.match(regex)) {
|
| + parent = parent.parentNode;
|
| + continue;
|
| + }
|
| + result.href = parent.href;
|
| + result.referrerPolicy = getReferrerPolicy_(parent);
|
| + break;
|
| + }
|
| + parent = parent.parentNode;
|
| + }
|
| + return result;
|
| + }
|
| + element = element.parentNode;
|
| + }
|
| + }
|
| + return {};
|
| + };
|
| +
|
| + /**
|
| + * Suppresses the next click such that they are not handled by JS click
|
| + * event handlers.
|
| + * @type {void}
|
| + */
|
| + __gCrWeb['suppressNextClick'] = function() {
|
| + var suppressNextClick = function(evt) {
|
| + evt.preventDefault();
|
| + document.removeEventListener('click', suppressNextClick, false);
|
| + };
|
| + document.addEventListener('click', suppressNextClick);
|
| + };
|
| +
|
| + /**
|
| + * Returns the margin in points around touchable elements (e.g. links for
|
| + * custom context menu).
|
| + * @type {number}
|
| + */
|
| + __gCrWeb['getPageWidth'] = function() {
|
| + var documentElement = document.documentElement;
|
| + var documentBody = document.body;
|
| + return Math.max(documentElement.clientWidth,
|
| + documentElement.scrollWidth,
|
| + documentElement.offsetWidth,
|
| + documentBody.scrollWidth,
|
| + documentBody.offsetWidth);
|
| + };
|
| +
|
| + /**
|
| + * Implementation of document.elementFromPoint that is working for iOS4 and
|
| + * iOS5 and that also goes into frames and iframes.
|
| + * @private
|
| + */
|
| + var elementFromPoint_ = function(x, y) {
|
| + var elementFromPointIsUsingViewPortCoordinates = function(win) {
|
| + if (win.pageYOffset > 0) { // Page scrolled down.
|
| + return (win.document.elementFromPoint(
|
| + 0, win.pageYOffset + win.innerHeight - 1) === null);
|
| + }
|
| + if (win.pageXOffset > 0) { // Page scrolled to the right.
|
| + return (win.document.elementFromPoint(
|
| + win.pageXOffset + win.innerWidth - 1, 0) === null);
|
| + }
|
| + return false; // No scrolling, don't care.
|
| + };
|
| +
|
| + var newCoordinate = function(x, y) {
|
| + var coordinates = {
|
| + x: x, y: y,
|
| + viewPortX: x - window.pageXOffset, viewPortY: y - window.pageYOffset,
|
| + useViewPortCoordinates: false,
|
| + window: window
|
| + };
|
| + return coordinates;
|
| + };
|
| +
|
| + // Returns the coordinates of the upper left corner of |obj| in the
|
| + // coordinates of the window that |obj| is in.
|
| + var getPositionInWindow = function(obj) {
|
| + var coord = { x: 0, y: 0 };
|
| + while (obj.offsetParent) {
|
| + coord.x += obj.offsetLeft;
|
| + coord.y += obj.offsetTop;
|
| + obj = obj.offsetParent;
|
| + }
|
| + return coord;
|
| + };
|
| +
|
| + var elementsFromCoordinates = function(coordinates) {
|
| + coordinates.useViewPortCoordinates = coordinates.useViewPortCoordinates ||
|
| + elementFromPointIsUsingViewPortCoordinates(coordinates.window);
|
| +
|
| + var currentElement = null;
|
| + if (coordinates.useViewPortCoordinates) {
|
| + currentElement = coordinates.window.document.elementFromPoint(
|
| + coordinates.viewPortX, coordinates.viewPortY);
|
| + } else {
|
| + currentElement = coordinates.window.document.elementFromPoint(
|
| + coordinates.x, coordinates.y);
|
| + }
|
| + // We have to check for tagName, because if a selection is made by the
|
| + // UIWebView, the element we will get won't have one.
|
| + if (!currentElement || !currentElement.tagName) {
|
| + return null;
|
| + }
|
| + if (currentElement.tagName.toLowerCase() === 'iframe' ||
|
| + currentElement.tagName.toLowerCase() === 'frame') {
|
| + // The following condition is true if the iframe is in a different
|
| + // domain; no further information is accessible.
|
| + if (typeof(currentElement.contentWindow.document) == 'undefined') {
|
| + return currentElement;
|
| + }
|
| + var framePosition = getPositionInWindow(currentElement);
|
| + coordinates.viewPortX -=
|
| + framePosition.x - coordinates.window.pageXOffset;
|
| + coordinates.viewPortY -=
|
| + framePosition.y - coordinates.window.pageYOffset;
|
| + coordinates.window = currentElement.contentWindow;
|
| + coordinates.x -= framePosition.x + coordinates.window.pageXOffset;
|
| + coordinates.y -= framePosition.y + coordinates.window.pageYOffset;
|
| + return elementsFromCoordinates(coordinates);
|
| + }
|
| + return currentElement;
|
| + };
|
| +
|
| + return elementsFromCoordinates(newCoordinate(x, y));
|
| + };
|
| +
|
| + /** @private */
|
| + var spiralCoordinates_ = function(x, y) {
|
| + var MAX_ANGLE = Math.PI * 2.0 * 3.0;
|
| + var POINT_COUNT = 30;
|
| + var ANGLE_STEP = MAX_ANGLE / POINT_COUNT;
|
| + var TOUCH_MARGIN = 25;
|
| + var SPEED = TOUCH_MARGIN / MAX_ANGLE;
|
| +
|
| + var coordinates = [];
|
| + for (var index = 0; index < POINT_COUNT; index++) {
|
| + var angle = ANGLE_STEP * index;
|
| + var radius = angle * SPEED;
|
| +
|
| + coordinates.push({x: x + Math.round(Math.cos(angle) * radius),
|
| + y: y + Math.round(Math.sin(angle) * radius)});
|
| + }
|
| +
|
| + return coordinates;
|
| + };
|
| +
|
| + /** @private */
|
| + var getComputedWebkitTouchCallout_ = function(element) {
|
| + return window.getComputedStyle(element, null)['webkitTouchCallout'];
|
| + };
|
| +
|
| + /**
|
| + * Gets the referrer policy to use for navigations away from the current page.
|
| + * If a link element is passed, and it includes a rel=noreferrer tag, that
|
| + * will override the page setting.
|
| + * @param {HTMLElement=} opt_linkElement The link triggering the navigation.
|
| + * @return {string} The policy string.
|
| + * @private
|
| + */
|
| + var getReferrerPolicy_ = function(opt_linkElement) {
|
| + if (opt_linkElement) {
|
| + var rel = opt_linkElement.getAttribute('rel');
|
| + if (rel && rel.toLowerCase() == 'noreferrer') {
|
| + return 'never';
|
| + }
|
| + }
|
| +
|
| + var metaTags = document.getElementsByTagName('meta');
|
| + for (var i = 0; i < metaTags.length; ++i) {
|
| + if (metaTags[i].name.toLowerCase() == 'referrer') {
|
| + return metaTags[i].content.toLowerCase();
|
| + }
|
| + }
|
| + return 'default';
|
| + };
|
| +
|
| +}()); // End of anonymouse object
|
|
|