172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/**
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * The global object.
772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen * @type {!Object}
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst global = this;
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// TODO(estade): This should be removed and calls replaced with cr.isMac
1272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst IS_MAC = /^Mac/.test(navigator.platform);
1372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/**
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Alias for document.getElementById.
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {string} id The ID of the element to find.
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @return {HTMLElement} The found element or null if not found.
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochfunction $(id) {
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return document.getElementById(id);
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/**
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Calls chrome.send with a callback and restores the original afterwards.
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {string} name The name of the message to send.
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {!Array} params The parameters to send.
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {string} callbackName The name of the function that the backend calls.
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {!Function} The function to call.
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochfunction chromeSend(name, params, callbackName, callback) {
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  var old = global[callbackName];
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  global[callbackName] = function() {
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // restore
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    global[callbackName] = old;
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    var args = Array.prototype.slice.call(arguments);
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return callback.apply(global, args);
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  chrome.send(name, params);
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/**
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Generates a CSS url string.
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {string} s The URL to generate the CSS url for.
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @return {string} The CSS url string.
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochfunction url(s) {
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // http://www.w3.org/TR/css3-values/#uris
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Parentheses, commas, whitespace characters, single quotes (') and double
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // quotes (") appearing in a URI must be escaped with a backslash
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  var s2 = s.replace(/(\(|\)|\,|\s|\'|\"|\\)/g, '\\$1');
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // WebKit has a bug when it comes to URLs that end with \
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // https://bugs.webkit.org/show_bug.cgi?id=28885
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (/\\\\$/.test(s2)) {
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Add a space to work around the WebKit bug.
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    s2 += ' ';
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return 'url("' + s2 + '")';
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
60731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
61731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick/**
62731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick * Parses query parameters from Location.
63731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick * @param {string} s The URL to generate the CSS url for.
64731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick * @return {object} Dictionary containing name value pairs for URL
65731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick */
66731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickfunction parseQueryParams(location) {
67731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  var params = {};
68731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  var query = unescape(location.search.substring(1));
69731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  var vars = query.split("&");
70731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (var i=0; i < vars.length; i++) {
71731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    var pair = vars[i].split("=");
72731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    params[pair[0]] = pair[1];
73731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
74731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return params;
7572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
7672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
7772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenfunction findAncestorByClass(el, className) {
7872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return findAncestor(el, function(el) {
7972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (el.classList)
8072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return el.classList.contains(className);
8172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return null;
8272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  });
8372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
8472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
8572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen/**
8672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen * Return the first ancestor for which the {@code predicate} returns true.
8772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen * @param {Node} node The node to check.
8872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen * @param {function(Node) : boolean} predicate The function that tests the
8972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen *     nodes.
9072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen * @return {Node} The found ancestor or null if not found.
9172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen */
9272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenfunction findAncestor(node, predicate) {
9372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  var last = false;
9472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  while (node != null && !(last = predicate(node))) {
9572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    node = node.parentNode;
9672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
9772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return last ? node : null;
9872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
9972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
10072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenfunction swapDomNodes(a, b) {
10172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  var afterA = a.nextSibling;
10272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (afterA == b) {
10372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    swapDomNodes(b, a);
10472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return;
10572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
10672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  var aParent = a.parentNode;
10772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  b.parentNode.replaceChild(a, b);
10872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  aParent.insertBefore(b, afterA);
10972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
11072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
111dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Handle click on a link. If the link points to a chrome: or file: url, then
112dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// call into the browser to do the navigation.
113dc0f95d653279beabeb9817299e2902918ba123eKristian Monsendocument.addEventListener('click', function(e) {
11472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Allow preventDefault to work.
11572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!e.returnValue)
11672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return;
11772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
11872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  var el = e.target;
11972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (el.nodeType == Node.ELEMENT_NODE &&
12072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      el.webkitMatchesSelector('A, A *')) {
12172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    while (el.tagName != 'A') {
12272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      el = el.parentElement;
12372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
12472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
12572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if ((el.protocol == 'file:' || el.protocol == 'about:') &&
126dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        (e.button == 0 || e.button == 1)) {
127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      chrome.send('navigateToUrl', [
128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        el.href,
129ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        el.target,
130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        e.button,
131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        e.altKey,
132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        e.ctrlKey,
133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        e.metaKey,
134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        e.shiftKey
135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ]);
13672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      e.preventDefault();
13772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
13872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
139dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen});
140