Correct blacklist entry message
[chromium-blink-merge.git] / ui / webui / resources / js / util.js
blob79f8d85d487da579bdc04e7879e08ac38fb16d87
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.
5 <include src="assert.js">
7 /**
8  * The global object.
9  * @type {!Object}
10  * @const
11  */
12 var global = this;
14 /**
15  * Alias for document.getElementById.
16  * @param {string} id The ID of the element to find.
17  * @return {HTMLElement} The found element or null if not found.
18  */
19 function $(id) {
20   return document.getElementById(id);
23 /**
24  * Calls chrome.send with a callback and restores the original afterwards.
25  * @param {string} name The name of the message to send.
26  * @param {!Array} params The parameters to send.
27  * @param {string} callbackName The name of the function that the backend calls.
28  * @param {!Function} callback The function to call.
29  */
30 function chromeSend(name, params, callbackName, callback) {
31   var old = global[callbackName];
32   global[callbackName] = function() {
33     // restore
34     global[callbackName] = old;
36     var args = Array.prototype.slice.call(arguments);
37     return callback.apply(global, args);
38   };
39   chrome.send(name, params);
42 /**
43  * Returns the scale factors supported by this platform.
44  * @return {array} The supported scale factors.
45  */
46 function getSupportedScaleFactors() {
47   var supportedScaleFactors = [];
48   if (cr.isMac || cr.isChromeOS) {
49     supportedScaleFactors.push(1);
50     supportedScaleFactors.push(2);
51   } else {
52     // Windows must be restarted to display at a different scale factor.
53     supportedScaleFactors.push(window.devicePixelRatio);
54   }
55   return supportedScaleFactors;
58 /**
59  * Generates a CSS url string.
60  * @param {string} s The URL to generate the CSS url for.
61  * @return {string} The CSS url string.
62  */
63 function url(s) {
64   // http://www.w3.org/TR/css3-values/#uris
65   // Parentheses, commas, whitespace characters, single quotes (') and double
66   // quotes (") appearing in a URI must be escaped with a backslash
67   var s2 = s.replace(/(\(|\)|\,|\s|\'|\"|\\)/g, '\\$1');
68   // WebKit has a bug when it comes to URLs that end with \
69   // https://bugs.webkit.org/show_bug.cgi?id=28885
70   if (/\\\\$/.test(s2)) {
71     // Add a space to work around the WebKit bug.
72     s2 += ' ';
73   }
74   return 'url("' + s2 + '")';
77 /**
78  * Generates a CSS -webkit-image-set for a chrome:// url.
79  * An entry in the image set is added for each of getSupportedScaleFactors().
80  * The scale-factor-specific url is generated by replacing the first instance of
81  * 'scalefactor' in |path| with the numeric scale factor.
82  * @param {string} path The URL to generate an image set for.
83  *     'scalefactor' should be a substring of |path|.
84  * @return {string} The CSS -webkit-image-set.
85  */
86 function imageset(path) {
87   var supportedScaleFactors = getSupportedScaleFactors();
89   var replaceStartIndex = path.indexOf('scalefactor');
90   if (replaceStartIndex < 0)
91     return url(path);
93   var s = '';
94   for (var i = 0; i < supportedScaleFactors.length; ++i) {
95     var scaleFactor = supportedScaleFactors[i];
96     var pathWithScaleFactor = path.substr(0, replaceStartIndex) + scaleFactor +
97         path.substr(replaceStartIndex + 'scalefactor'.length);
99     s += url(pathWithScaleFactor) + ' ' + scaleFactor + 'x';
101     if (i != supportedScaleFactors.length - 1)
102       s += ', ';
103   }
104   return '-webkit-image-set(' + s + ')';
108  * Parses query parameters from Location.
109  * @param {string} location The URL to generate the CSS url for.
110  * @return {object} Dictionary containing name value pairs for URL
111  */
112 function parseQueryParams(location) {
113   var params = {};
114   var query = unescape(location.search.substring(1));
115   var vars = query.split('&');
116   for (var i = 0; i < vars.length; i++) {
117     var pair = vars[i].split('=');
118     params[pair[0]] = pair[1];
119   }
120   return params;
123 function findAncestorByClass(el, className) {
124   return findAncestor(el, function(el) {
125     if (el.classList)
126       return el.classList.contains(className);
127     return null;
128   });
132  * Return the first ancestor for which the {@code predicate} returns true.
133  * @param {Node} node The node to check.
134  * @param {function(Node) : boolean} predicate The function that tests the
135  *     nodes.
136  * @return {Node} The found ancestor or null if not found.
137  */
138 function findAncestor(node, predicate) {
139   var last = false;
140   while (node != null && !(last = predicate(node))) {
141     node = node.parentNode;
142   }
143   return last ? node : null;
146 function swapDomNodes(a, b) {
147   var afterA = a.nextSibling;
148   if (afterA == b) {
149     swapDomNodes(b, a);
150     return;
151   }
152   var aParent = a.parentNode;
153   b.parentNode.replaceChild(a, b);
154   aParent.insertBefore(b, afterA);
158  * Disables text selection and dragging, with optional whitelist callbacks.
159  * @param {function(Event):boolean=} opt_allowSelectStart Unless this function
160  *    is defined and returns true, the onselectionstart event will be
161  *    surpressed.
162  * @param {function(Event):boolean=} opt_allowDragStart Unless this function
163  *    is defined and returns true, the ondragstart event will be surpressed.
164  */
165 function disableTextSelectAndDrag(opt_allowSelectStart, opt_allowDragStart) {
166   // Disable text selection.
167   document.onselectstart = function(e) {
168     if (!(opt_allowSelectStart && opt_allowSelectStart.call(this, e)))
169       e.preventDefault();
170   };
172   // Disable dragging.
173   document.ondragstart = function(e) {
174     if (!(opt_allowDragStart && opt_allowDragStart.call(this, e)))
175       e.preventDefault();
176   };
180  * Call this to stop clicks on <a href="#"> links from scrolling to the top of
181  * the page (and possibly showing a # in the link).
182  */
183 function preventDefaultOnPoundLinkClicks() {
184   document.addEventListener('click', function(e) {
185     var anchor = findAncestor(e.target, function(el) {
186       return el.tagName == 'A';
187     });
188     // Use getAttribute() to prevent URL normalization.
189     if (anchor && anchor.getAttribute('href') == '#')
190       e.preventDefault();
191   });
195  * Check the directionality of the page.
196  * @return {boolean} True if Chrome is running an RTL UI.
197  */
198 function isRTL() {
199   return document.documentElement.dir == 'rtl';
203  * Get an element that's known to exist by its ID. We use this instead of just
204  * calling getElementById and not checking the result because this lets us
205  * satisfy the JSCompiler type system.
206  * @param {string} id The identifier name.
207  * @return {!Element} the Element.
208  */
209 function getRequiredElement(id) {
210   var element = $(id);
211   assert(element, 'Missing required element: ' + id);
212   return element;
215 // Handle click on a link. If the link points to a chrome: or file: url, then
216 // call into the browser to do the navigation.
217 document.addEventListener('click', function(e) {
218   if (e.defaultPrevented)
219     return;
221   var el = e.target;
222   if (el.nodeType == Node.ELEMENT_NODE &&
223       el.webkitMatchesSelector('A, A *')) {
224     while (el.tagName != 'A') {
225       el = el.parentElement;
226     }
228     if ((el.protocol == 'file:' || el.protocol == 'about:') &&
229         (e.button == 0 || e.button == 1)) {
230       chrome.send('navigateToUrl', [
231         el.href,
232         el.target,
233         e.button,
234         e.altKey,
235         e.ctrlKey,
236         e.metaKey,
237         e.shiftKey
238       ]);
239       e.preventDefault();
240     }
241   }
245  * Creates a new URL which is the old URL with a GET param of key=value.
246  * @param {string} url The base URL. There is not sanity checking on the URL so
247  *     it must be passed in a proper format.
248  * @param {string} key The key of the param.
249  * @param {string} value The value of the param.
250  * @return {string} The new URL.
251  */
252 function appendParam(url, key, value) {
253   var param = encodeURIComponent(key) + '=' + encodeURIComponent(value);
255   if (url.indexOf('?') == -1)
256     return url + '?' + param;
257   return url + '&' + param;
261  * Creates a CSS -webkit-image-set for a favicon request.
262  * @param {string} url The url for the favicon.
263  * @param {number=} opt_size Optional preferred size of the favicon.
264  * @param {string=} opt_type Optional type of favicon to request. Valid values
265  *     are 'favicon' and 'touch-icon'. Default is 'favicon'.
266  * @return {string} -webkit-image-set for the favicon.
267  */
268 function getFaviconImageSet(url, opt_size, opt_type) {
269   var size = opt_size || 16;
270   var type = opt_type || 'favicon';
271   return imageset(
272       'chrome://' + type + '/size/' + size + '@scalefactorx/' + url);
276  * Creates a new URL for a favicon request for the current device pixel ratio.
277  * The URL must be updated when the user moves the browser to a screen with a
278  * different device pixel ratio. Use getFaviconImageSet() for the updating to
279  * occur automatically.
280  * @param {string} url The url for the favicon.
281  * @param {number=} opt_size Optional preferred size of the favicon.
282  * @param {string=} opt_type Optional type of favicon to request. Valid values
283  *     are 'favicon' and 'touch-icon'. Default is 'favicon'.
284  * @return {string} Updated URL for the favicon.
285  */
286 function getFaviconUrlForCurrentDevicePixelRatio(url, opt_size, opt_type) {
287   var size = opt_size || 16;
288   var type = opt_type || 'favicon';
289   return 'chrome://' + type + '/size/' + size + '@' +
290       window.devicePixelRatio + 'x/' + url;
294  * Creates an element of a specified type with a specified class name.
295  * @param {string} type The node type.
296  * @param {string} className The class name to use.
297  * @return {Element} The created element.
298  */
299 function createElementWithClassName(type, className) {
300   var elm = document.createElement(type);
301   elm.className = className;
302   return elm;
306  * webkitTransitionEnd does not always fire (e.g. when animation is aborted
307  * or when no paint happens during the animation). This function sets up
308  * a timer and emulate the event if it is not fired when the timer expires.
309  * @param {!HTMLElement} el The element to watch for webkitTransitionEnd.
310  * @param {number} timeOut The maximum wait time in milliseconds for the
311  *     webkitTransitionEnd to happen.
312  */
313 function ensureTransitionEndEvent(el, timeOut) {
314   var fired = false;
315   el.addEventListener('webkitTransitionEnd', function f(e) {
316     el.removeEventListener('webkitTransitionEnd', f);
317     fired = true;
318   });
319   window.setTimeout(function() {
320     if (!fired)
321       cr.dispatchSimpleEvent(el, 'webkitTransitionEnd');
322   }, timeOut);