Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(586)

Side by Side Diff: ios/web/web_state/js/resources/core.js

Issue 2800003002: Pull context menu related APIs from core.js to their own file. (Closed)
Patch Set: git squash commit for context-menu. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 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 // This file adheres to closure-compiler conventions in order to enable 5 // This file adheres to closure-compiler conventions in order to enable
6 // compilation with ADVANCED_OPTIMIZATIONS. In particular, members that are to 6 // compilation with ADVANCED_OPTIMIZATIONS. In particular, members that are to
7 // be accessed externally should be specified in this['style'] as opposed to 7 // be accessed externally should be specified in this['style'] as opposed to
8 // this.style because member identifiers are minified by default. 8 // this.style because member identifiers are minified by default.
9 // See http://goo.gl/FwOgy 9 // See http://goo.gl/FwOgy
10 10
(...skipping 22 matching lines...) Expand all
33 // JavaScript errors are logged on the main application side. The handler is 33 // JavaScript errors are logged on the main application side. The handler is
34 // added ASAP to catch any errors in startup. Note this does not appear to 34 // added ASAP to catch any errors in startup. Note this does not appear to
35 // work in iOS < 5. 35 // work in iOS < 5.
36 window.addEventListener('error', function(event) { 36 window.addEventListener('error', function(event) {
37 // Sadly, event.filename and event.lineno are always 'undefined' and '0' 37 // Sadly, event.filename and event.lineno are always 'undefined' and '0'
38 // with UIWebView. 38 // with UIWebView.
39 invokeOnHost_({'command': 'window.error', 39 invokeOnHost_({'command': 'window.error',
40 'message': event.message.toString()}); 40 'message': event.message.toString()});
41 }); 41 });
42 42
43 /**
44 * Margin in points around touchable elements (e.g. links for custom context
45 * menu).
46 * @type {number}
47 */
48 var touchMargin_ = 25;
49
50 __gCrWeb['getPageWidth'] = function() {
51 var documentElement = document.documentElement;
52 var documentBody = document.body;
53 return Math.max(documentElement.clientWidth,
54 documentElement.scrollWidth,
55 documentElement.offsetWidth,
56 documentBody.scrollWidth,
57 documentBody.offsetWidth);
58 };
59
60 // Implementation of document.elementFromPoint that is working for iOS4 and
61 // iOS5 and that also goes into frames and iframes.
62 var elementFromPoint_ = function(x, y) {
63 var elementFromPointIsUsingViewPortCoordinates = function(win) {
64 if (win.pageYOffset > 0) { // Page scrolled down.
65 return (win.document.elementFromPoint(
66 0, win.pageYOffset + win.innerHeight - 1) === null);
67 }
68 if (win.pageXOffset > 0) { // Page scrolled to the right.
69 return (win.document.elementFromPoint(
70 win.pageXOffset + win.innerWidth - 1, 0) === null);
71 }
72 return false; // No scrolling, don't care.
73 };
74
75 var newCoordinate = function(x, y) {
76 var coordinates = {
77 x: x, y: y,
78 viewPortX: x - window.pageXOffset, viewPortY: y - window.pageYOffset,
79 useViewPortCoordinates: false,
80 window: window
81 };
82 return coordinates;
83 };
84
85 // Returns the coordinates of the upper left corner of |obj| in the
86 // coordinates of the window that |obj| is in.
87 var getPositionInWindow = function(obj) {
88 var coord = { x: 0, y: 0 };
89 while (obj.offsetParent) {
90 coord.x += obj.offsetLeft;
91 coord.y += obj.offsetTop;
92 obj = obj.offsetParent;
93 }
94 return coord;
95 };
96
97 var elementsFromCoordinates = function(coordinates) {
98 coordinates.useViewPortCoordinates = coordinates.useViewPortCoordinates ||
99 elementFromPointIsUsingViewPortCoordinates(coordinates.window);
100
101 var currentElement = null;
102 if (coordinates.useViewPortCoordinates) {
103 currentElement = coordinates.window.document.elementFromPoint(
104 coordinates.viewPortX, coordinates.viewPortY);
105 } else {
106 currentElement = coordinates.window.document.elementFromPoint(
107 coordinates.x, coordinates.y);
108 }
109 // We have to check for tagName, because if a selection is made by the
110 // UIWebView, the element we will get won't have one.
111 if (!currentElement || !currentElement.tagName) {
112 return null;
113 }
114 if (currentElement.tagName.toLowerCase() === 'iframe' ||
115 currentElement.tagName.toLowerCase() === 'frame') {
116 // The following condition is true if the iframe is in a different
117 // domain; no further information is accessible.
118 if (typeof(currentElement.contentWindow.document) == 'undefined') {
119 return currentElement;
120 }
121 var framePosition = getPositionInWindow(currentElement);
122 coordinates.viewPortX -=
123 framePosition.x - coordinates.window.pageXOffset;
124 coordinates.viewPortY -=
125 framePosition.y - coordinates.window.pageYOffset;
126 coordinates.window = currentElement.contentWindow;
127 coordinates.x -= framePosition.x + coordinates.window.pageXOffset;
128 coordinates.y -= framePosition.y + coordinates.window.pageYOffset;
129 return elementsFromCoordinates(coordinates);
130 }
131 return currentElement;
132 };
133
134 return elementsFromCoordinates(newCoordinate(x, y));
135 };
136
137 var spiralCoordinates = function(x, y) {
138 var coordinates = [];
139
140 var maxAngle = Math.PI * 2.0 * 3.0;
141 var pointCount = 30;
142 var angleStep = maxAngle / pointCount;
143 var speed = touchMargin_ / maxAngle;
144
145 for (var index = 0; index < pointCount; index++) {
146 var angle = angleStep * index;
147 var radius = angle * speed;
148
149 coordinates.push({x: x + Math.round(Math.cos(angle) * radius),
150 y: y + Math.round(Math.sin(angle) * radius)});
151 }
152
153 return coordinates;
154 };
155
156 // Returns the url of the image or link under the selected point. Returns an
157 // empty string if no links or images are found.
158 __gCrWeb['getElementFromPoint'] = function(x, y) {
159 var hitCoordinates = spiralCoordinates(x, y);
160 for (var index = 0; index < hitCoordinates.length; index++) {
161 var coordinates = hitCoordinates[index];
162
163 var element = elementFromPoint_(coordinates.x, coordinates.y);
164 if (!element || !element.tagName) {
165 // Nothing under the hit point. Try the next hit point.
166 continue;
167 }
168
169 if (getComputedWebkitTouchCallout_(element) === 'none')
170 continue;
171 // Also check element's ancestors. A bound on the level is used here to
172 // avoid large overhead when no links or images are found.
173 var level = 0;
174 while (++level < 8 && element && element != document) {
175 var tagName = element.tagName;
176 if (!tagName)
177 continue;
178 tagName = tagName.toLowerCase();
179
180 if (tagName === 'input' || tagName === 'textarea' ||
181 tagName === 'select' || tagName === 'option') {
182 // If the element is a known input element, stop the spiral search and
183 // return empty results.
184 return {};
185 }
186
187 if (tagName === 'a' && element.href) {
188 // Found a link.
189 return {
190 href: element.href,
191 referrerPolicy: getReferrerPolicy_(element),
192 innerText: element.innerText
193 };
194 }
195
196 if (tagName === 'img' && element.src) {
197 // Found an image.
198 var result = {
199 src: element.src,
200 referrerPolicy: getReferrerPolicy_()
201 };
202 // Copy the title, if any.
203 if (element.title) {
204 result.title = element.title;
205 }
206 // Check if the image is also a link.
207 var parent = element.parentNode;
208 while (parent) {
209 if (parent.tagName &&
210 parent.tagName.toLowerCase() === 'a' &&
211 parent.href) {
212 // This regex identifies strings like void(0),
213 // void(0) ;void(0);, ;;;;
214 // which result in a NOP when executed as JavaScript.
215 var regex = RegExp("^javascript:(?:(?:void\\(0\\)|;)\\s*)+$");
216 if (parent.href.match(regex)) {
217 parent = parent.parentNode;
218 continue;
219 }
220 result.href = parent.href;
221 result.referrerPolicy = getReferrerPolicy_(parent);
222 break;
223 }
224 parent = parent.parentNode;
225 }
226 return result;
227 }
228 element = element.parentNode;
229 }
230 }
231 return {};
232 };
233
234 // Suppresses the next click such that they are not handled by JS click
235 // event handlers.
236 __gCrWeb['suppressNextClick'] = function() {
237 var suppressNextClick = function(evt) {
238 evt.preventDefault();
239 document.removeEventListener('click', suppressNextClick, false);
240 };
241 document.addEventListener('click', suppressNextClick);
242 };
243 43
244 // Returns true if the top window or any frames inside contain an input 44 // Returns true if the top window or any frames inside contain an input
245 // field of type 'password'. 45 // field of type 'password'.
246 __gCrWeb['hasPasswordField'] = function() { 46 __gCrWeb['hasPasswordField'] = function() {
247 return hasPasswordField_(window); 47 return hasPasswordField_(window);
248 }; 48 };
249 49
250 // Returns a string that is formatted according to the JSON syntax rules. 50 // Returns a string that is formatted according to the JSON syntax rules.
251 // This is equivalent to the built-in JSON.stringify() function, but is 51 // This is equivalent to the built-in JSON.stringify() function, but is
252 // less likely to be overridden by the website itself. This public function 52 // less likely to be overridden by the website itself. This public function
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 } 131 }
332 } 132 }
333 133
334 return false; 134 return false;
335 }; 135 };
336 136
337 function invokeOnHost_(command) { 137 function invokeOnHost_(command) {
338 __gCrWeb.message.invokeOnHost(command); 138 __gCrWeb.message.invokeOnHost(command);
339 }; 139 };
340 140
341 /**
342 * Gets the referrer policy to use for navigations away from the current page.
343 * If a link element is passed, and it includes a rel=noreferrer tag, that
344 * will override the page setting.
345 * @param {HTMLElement=} opt_linkElement The link triggering the navigation.
346 * @return {string} The policy string.
347 * @private
348 */
349 var getReferrerPolicy_ = function(opt_linkElement) {
350 if (opt_linkElement) {
351 var rel = opt_linkElement.getAttribute('rel');
352 if (rel && rel.toLowerCase() == 'noreferrer') {
353 return 'never';
354 }
355 }
356
357 var metaTags = document.getElementsByTagName('meta');
358 for (var i = 0; i < metaTags.length; ++i) {
359 if (metaTags[i].name.toLowerCase() == 'referrer') {
360 return metaTags[i].content.toLowerCase();
361 }
362 }
363 return 'default';
364 };
365
366 // Various aspects of global DOM behavior are overridden here. 141 // Various aspects of global DOM behavior are overridden here.
367 142
368 // A popstate event needs to be fired anytime the active history entry 143 // A popstate event needs to be fired anytime the active history entry
369 // changes without an associated document change. Either via back, forward, go 144 // changes without an associated document change. Either via back, forward, go
370 // navigation or by loading the URL, clicking on a link, etc. 145 // navigation or by loading the URL, clicking on a link, etc.
371 __gCrWeb['dispatchPopstateEvent'] = function(stateObject) { 146 __gCrWeb['dispatchPopstateEvent'] = function(stateObject) {
372 var popstateEvent = window.document.createEvent('HTMLEvents'); 147 var popstateEvent = window.document.createEvent('HTMLEvents');
373 popstateEvent.initEvent('popstate', true, false); 148 popstateEvent.initEvent('popstate', true, false);
374 if (stateObject) 149 if (stateObject)
375 popstateEvent.state = JSON.parse(stateObject); 150 popstateEvent.state = JSON.parse(stateObject);
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
474 window.scrollTo = function(x, y) { 249 window.scrollTo = function(x, y) {
475 if (webViewScrollViewIsDragging_) 250 if (webViewScrollViewIsDragging_)
476 return; 251 return;
477 originalWindowScrollTo(x, y); 252 originalWindowScrollTo(x, y);
478 }; 253 };
479 254
480 window.addEventListener('hashchange', function(evt) { 255 window.addEventListener('hashchange', function(evt) {
481 invokeOnHost_({'command': 'window.hashchange'}); 256 invokeOnHost_({'command': 'window.hashchange'});
482 }); 257 });
483 258
484 var getComputedWebkitTouchCallout_ = function(element) {
485 return window.getComputedStyle(element, null)['webkitTouchCallout'];
486 };
487
488 // Flush the message queue. 259 // Flush the message queue.
489 if (__gCrWeb.message) { 260 if (__gCrWeb.message) {
490 __gCrWeb.message.invokeQueues(); 261 __gCrWeb.message.invokeQueues();
491 } 262 }
492 263
493 // Capture form submit actions. 264 // Capture form submit actions.
494 document.addEventListener('submit', function(evt) { 265 document.addEventListener('submit', function(evt) {
495 var action; 266 var action;
496 if (evt['defaultPrevented']) 267 if (evt['defaultPrevented'])
497 return; 268 return;
498 action = evt.target.getAttribute('action'); 269 action = evt.target.getAttribute('action');
499 // Default action is to re-submit to same page. 270 // Default action is to re-submit to same page.
500 if (!action) 271 if (!action)
501 action = document.location.href; 272 action = document.location.href;
502 invokeOnHost_({ 273 invokeOnHost_({
503 'command': 'document.submit', 274 'command': 'document.submit',
504 'formName': __gCrWeb.common.getFormIdentifier(evt.srcElement), 275 'formName': __gCrWeb.common.getFormIdentifier(evt.srcElement),
505 'href': __gCrWeb['getFullyQualifiedURL'](action) 276 'href': __gCrWeb['getFullyQualifiedURL'](action)
506 }); 277 });
507 }, false); 278 }, false);
508 279
509 addFormEventListeners_(); 280 addFormEventListeners_();
510 281
511 }()); // End of anonymous object 282 }()); // End of anonymous object
OLDNEW
« no previous file with comments | « ios/web/web_state/js/resources/context_menu.js ('k') | ios/web/web_state/js/resources/web_bundle.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698