OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 /** | |
6 * The global object. | |
7 * @type {!Object} | |
8 * @const | |
9 */ | |
10 var global = this; | |
11 | |
12 /** | |
13 * Alias for document.getElementById. | |
14 * @param {string} id The ID of the element to find. | |
15 * @return {HTMLElement} The found element or null if not found. | |
16 */ | |
17 function $(id) { | |
18 return document.getElementById(id); | |
19 } | |
20 | |
21 /** | |
22 * Calls chrome.send with a callback and restores the original afterwards. | |
23 * @param {string} name The name of the message to send. | |
24 * @param {!Array} params The parameters to send. | |
25 * @param {string} callbackName The name of the function that the backend calls. | |
26 * @param {!Function} callback The function to call. | |
27 */ | |
28 function chromeSend(name, params, callbackName, callback) { | |
29 var old = global[callbackName]; | |
30 global[callbackName] = function() { | |
31 // restore | |
32 global[callbackName] = old; | |
33 | |
34 var args = Array.prototype.slice.call(arguments); | |
35 return callback.apply(global, args); | |
36 }; | |
37 chrome.send(name, params); | |
38 } | |
39 | |
40 /** | |
41 * Generates a CSS url string. | |
42 * @param {string} s The URL to generate the CSS url for. | |
43 * @return {string} The CSS url string. | |
44 */ | |
45 function url(s) { | |
46 // http://www.w3.org/TR/css3-values/#uris | |
47 // Parentheses, commas, whitespace characters, single quotes (') and double | |
48 // quotes (") appearing in a URI must be escaped with a backslash | |
49 var s2 = s.replace(/(\(|\)|\,|\s|\'|\"|\\)/g, '\\$1'); | |
50 // WebKit has a bug when it comes to URLs that end with \ | |
51 // https://bugs.webkit.org/show_bug.cgi?id=28885 | |
52 if (/\\\\$/.test(s2)) { | |
53 // Add a space to work around the WebKit bug. | |
54 s2 += ' '; | |
55 } | |
56 return 'url("' + s2 + '")'; | |
57 } | |
58 | |
59 /** | |
60 * Parses query parameters from Location. | |
61 * @param {string} location The URL to generate the CSS url for. | |
62 * @return {object} Dictionary containing name value pairs for URL | |
63 */ | |
64 function parseQueryParams(location) { | |
65 var params = {}; | |
66 var query = unescape(location.search.substring(1)); | |
67 var vars = query.split('&'); | |
68 for (var i = 0; i < vars.length; i++) { | |
69 var pair = vars[i].split('='); | |
70 params[pair[0]] = pair[1]; | |
71 } | |
72 return params; | |
73 } | |
74 | |
75 function findAncestorByClass(el, className) { | |
76 return findAncestor(el, function(el) { | |
77 if (el.classList) | |
78 return el.classList.contains(className); | |
79 return null; | |
80 }); | |
81 } | |
82 | |
83 /** | |
84 * Return the first ancestor for which the {@code predicate} returns true. | |
85 * @param {Node} node The node to check. | |
86 * @param {function(Node) : boolean} predicate The function that tests the | |
87 * nodes. | |
88 * @return {Node} The found ancestor or null if not found. | |
89 */ | |
90 function findAncestor(node, predicate) { | |
91 var last = false; | |
92 while (node != null && !(last = predicate(node))) { | |
93 node = node.parentNode; | |
94 } | |
95 return last ? node : null; | |
96 } | |
97 | |
98 function swapDomNodes(a, b) { | |
99 var afterA = a.nextSibling; | |
100 if (afterA == b) { | |
101 swapDomNodes(b, a); | |
102 return; | |
103 } | |
104 var aParent = a.parentNode; | |
105 b.parentNode.replaceChild(a, b); | |
106 aParent.insertBefore(b, afterA); | |
107 } | |
108 | |
109 /** | |
110 * Disables text selection and dragging, with optional whitelist callbacks. | |
111 * @param {function(Event):boolean=} opt_allowSelectStart Unless this function | |
112 * is defined and returns true, the onselectionstart event will be | |
113 * surpressed. | |
114 * @param {function(Event):boolean=} opt_allowDragStart Unless this function | |
115 * is defined and returns true, the ondragstart event will be surpressed. | |
116 */ | |
117 function disableTextSelectAndDrag(opt_allowSelectStart, opt_allowDragStart) { | |
118 // Disable text selection. | |
119 document.onselectstart = function(e) { | |
120 if (!(opt_allowSelectStart && opt_allowSelectStart.call(this, e))) | |
121 e.preventDefault(); | |
122 }; | |
123 | |
124 // Disable dragging. | |
125 document.ondragstart = function(e) { | |
126 if (!(opt_allowDragStart && opt_allowDragStart.call(this, e))) | |
127 e.preventDefault(); | |
128 }; | |
129 } | |
130 | |
131 /** | |
132 * Call this to stop clicks on <a href="#"> links from scrolling to the top of | |
133 * the page (and possibly showing a # in the link). | |
134 */ | |
135 function preventDefaultOnPoundLinkClicks() { | |
136 document.addEventListener('click', function(e) { | |
137 var anchor = findAncestor(e.target, function(el) { | |
138 return el.tagName == 'A'; | |
139 }); | |
140 // Use getAttribute() to prevent URL normalization. | |
141 if (anchor && anchor.getAttribute('href') == '#') | |
142 e.preventDefault(); | |
143 }); | |
144 } | |
145 | |
146 /** | |
147 * Check the directionality of the page. | |
148 * @return {boolean} True if Chrome is running an RTL UI. | |
149 */ | |
150 function isRTL() { | |
151 return document.documentElement.dir == 'rtl'; | |
152 } | |
153 | |
154 /** | |
155 * Simple common assertion API | |
156 * @param {*} condition The condition to test. Note that this may be used to | |
157 * test whether a value is defined or not, and we don't want to force a | |
158 * cast to Boolean. | |
159 * @param {string=} opt_message A message to use in any error. | |
160 */ | |
161 function assert(condition, opt_message) { | |
162 'use strict'; | |
163 if (!condition) { | |
164 var msg = 'Assertion failed'; | |
165 if (opt_message) | |
166 msg = msg + ': ' + opt_message; | |
167 throw new Error(msg); | |
168 } | |
169 } | |
170 | |
171 /** | |
172 * Get an element that's known to exist by its ID. We use this instead of just | |
173 * calling getElementById and not checking the result because this lets us | |
174 * satisfy the JSCompiler type system. | |
175 * @param {string} id The identifier name. | |
176 * @return {!Element} the Element. | |
177 */ | |
178 function getRequiredElement(id) { | |
179 var element = $(id); | |
180 assert(element, 'Missing required element: ' + id); | |
181 return element; | |
182 } | |
183 | |
184 // Handle click on a link. If the link points to a chrome: or file: url, then | |
185 // call into the browser to do the navigation. | |
186 document.addEventListener('click', function(e) { | |
187 // Allow preventDefault to work. | |
188 if (!e.returnValue) | |
189 return; | |
190 | |
191 var el = e.target; | |
192 if (el.nodeType == Node.ELEMENT_NODE && | |
193 el.webkitMatchesSelector('A, A *')) { | |
194 while (el.tagName != 'A') { | |
195 el = el.parentElement; | |
196 } | |
197 | |
198 if ((el.protocol == 'file:' || el.protocol == 'about:') && | |
199 (e.button == 0 || e.button == 1)) { | |
200 chrome.send('navigateToUrl', [ | |
201 el.href, | |
202 el.target, | |
203 e.button, | |
204 e.altKey, | |
205 e.ctrlKey, | |
206 e.metaKey, | |
207 e.shiftKey | |
208 ]); | |
209 e.preventDefault(); | |
210 } | |
211 } | |
212 }); | |
213 | |
214 /** | |
215 * Creates a new URL which is the old URL with a GET param of key=value. | |
216 * @param {string} url The base URL. There is not sanity checking on the URL so | |
217 * it must be passed in a proper format. | |
218 * @param {string} key The key of the param. | |
219 * @param {string} value The value of the param. | |
220 * @return {string} The new URL. | |
221 */ | |
222 function appendParam(url, key, value) { | |
223 var param = encodeURIComponent(key) + '=' + encodeURIComponent(value); | |
224 | |
225 if (url.indexOf('?') == -1) | |
226 return url + '?' + param; | |
227 return url + '&' + param; | |
228 } | |
OLD | NEW |