| Index: netlog_viewer/ui_webui_resources_js_util.js
|
| diff --git a/netlog_viewer/ui_webui_resources_js_util.js b/netlog_viewer/ui_webui_resources_js_util.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..048a674ed1980061b6cb9802866a25fefdd75a55
|
| --- /dev/null
|
| +++ b/netlog_viewer/ui_webui_resources_js_util.js
|
| @@ -0,0 +1,374 @@
|
| +// Copyright (c) 2012 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.
|
| +
|
| +// <include src="assert.js">
|
| +
|
| +/**
|
| + * Alias for document.getElementById. Found elements must be HTMLElements.
|
| + * @param {string} id The ID of the element to find.
|
| + * @return {HTMLElement} The found element or null if not found.
|
| + */
|
| +function $(id) {
|
| + var el = document.getElementById(id);
|
| + return el ? assertInstanceof(el, HTMLElement) : null;
|
| +}
|
| +
|
| +// TODO(devlin): This should return SVGElement, but closure compiler is missing
|
| +// those externs.
|
| +/**
|
| + * Alias for document.getElementById. Found elements must be SVGElements.
|
| + * @param {string} id The ID of the element to find.
|
| + * @return {Element} The found element or null if not found.
|
| + */
|
| +function getSVGElement(id) {
|
| + var el = document.getElementById(id);
|
| + return el ? assertInstanceof(el, Element) : null;
|
| +}
|
| +
|
| +/**
|
| + * Add an accessible message to the page that will be announced to
|
| + * users who have spoken feedback on, but will be invisible to all
|
| + * other users. It's removed right away so it doesn't clutter the DOM.
|
| + * @param {string} msg The text to be pronounced.
|
| + */
|
| +function announceAccessibleMessage(msg) {
|
| + var element = document.createElement('div');
|
| + element.setAttribute('aria-live', 'polite');
|
| + element.style.position = 'relative';
|
| + element.style.left = '-9999px';
|
| + element.style.height = '0px';
|
| + element.innerText = msg;
|
| + document.body.appendChild(element);
|
| + window.setTimeout(function() {
|
| + document.body.removeChild(element);
|
| + }, 0);
|
| +}
|
| +
|
| +/**
|
| + * Generates a CSS url string.
|
| + * @param {string} s The URL to generate the CSS url for.
|
| + * @return {string} The CSS url string.
|
| + */
|
| +function url(s) {
|
| + // http://www.w3.org/TR/css3-values/#uris
|
| + // Parentheses, commas, whitespace characters, single quotes (') and double
|
| + // quotes (") appearing in a URI must be escaped with a backslash
|
| + var s2 = s.replace(/(\(|\)|\,|\s|\'|\"|\\)/g, '\\$1');
|
| + // WebKit has a bug when it comes to URLs that end with \
|
| + // https://bugs.webkit.org/show_bug.cgi?id=28885
|
| + if (/\\\\$/.test(s2)) {
|
| + // Add a space to work around the WebKit bug.
|
| + s2 += ' ';
|
| + }
|
| + return 'url("' + s2 + '")';
|
| +}
|
| +
|
| +/**
|
| + * Parses query parameters from Location.
|
| + * @param {Location} location The URL to generate the CSS url for.
|
| + * @return {Object} Dictionary containing name value pairs for URL
|
| + */
|
| +function parseQueryParams(location) {
|
| + var params = {};
|
| + var query = unescape(location.search.substring(1));
|
| + var vars = query.split('&');
|
| + for (var i = 0; i < vars.length; i++) {
|
| + var pair = vars[i].split('=');
|
| + params[pair[0]] = pair[1];
|
| + }
|
| + return params;
|
| +}
|
| +
|
| +/**
|
| + * Creates a new URL by appending or replacing the given query key and value.
|
| + * Not supporting URL with username and password.
|
| + * @param {Location} location The original URL.
|
| + * @param {string} key The query parameter name.
|
| + * @param {string} value The query parameter value.
|
| + * @return {string} The constructed new URL.
|
| + */
|
| +function setQueryParam(location, key, value) {
|
| + var query = parseQueryParams(location);
|
| + query[encodeURIComponent(key)] = encodeURIComponent(value);
|
| +
|
| + var newQuery = '';
|
| + for (var q in query) {
|
| + newQuery += (newQuery ? '&' : '?') + q + '=' + query[q];
|
| + }
|
| +
|
| + return location.origin + location.pathname + newQuery + location.hash;
|
| +}
|
| +
|
| +/**
|
| + * @param {Node} el A node to search for ancestors with |className|.
|
| + * @param {string} className A class to search for.
|
| + * @return {Element} A node with class of |className| or null if none is found.
|
| + */
|
| +function findAncestorByClass(el, className) {
|
| + return /** @type {Element} */(findAncestor(el, function(el) {
|
| + return el.classList && el.classList.contains(className);
|
| + }));
|
| +}
|
| +
|
| +/**
|
| + * Return the first ancestor for which the {@code predicate} returns true.
|
| + * @param {Node} node The node to check.
|
| + * @param {function(Node):boolean} predicate The function that tests the
|
| + * nodes.
|
| + * @return {Node} The found ancestor or null if not found.
|
| + */
|
| +function findAncestor(node, predicate) {
|
| + var last = false;
|
| + while (node != null && !(last = predicate(node))) {
|
| + node = node.parentNode;
|
| + }
|
| + return last ? node : null;
|
| +}
|
| +
|
| +function swapDomNodes(a, b) {
|
| + var afterA = a.nextSibling;
|
| + if (afterA == b) {
|
| + swapDomNodes(b, a);
|
| + return;
|
| + }
|
| + var aParent = a.parentNode;
|
| + b.parentNode.replaceChild(a, b);
|
| + aParent.insertBefore(b, afterA);
|
| +}
|
| +
|
| +/**
|
| + * Disables text selection and dragging, with optional whitelist callbacks.
|
| + * @param {function(Event):boolean=} opt_allowSelectStart Unless this function
|
| + * is defined and returns true, the onselectionstart event will be
|
| + * surpressed.
|
| + * @param {function(Event):boolean=} opt_allowDragStart Unless this function
|
| + * is defined and returns true, the ondragstart event will be surpressed.
|
| + */
|
| +function disableTextSelectAndDrag(opt_allowSelectStart, opt_allowDragStart) {
|
| + // Disable text selection.
|
| + document.onselectstart = function(e) {
|
| + if (!(opt_allowSelectStart && opt_allowSelectStart.call(this, e)))
|
| + e.preventDefault();
|
| + };
|
| +
|
| + // Disable dragging.
|
| + document.ondragstart = function(e) {
|
| + if (!(opt_allowDragStart && opt_allowDragStart.call(this, e)))
|
| + e.preventDefault();
|
| + };
|
| +}
|
| +
|
| +/**
|
| + * TODO(dbeam): DO NOT USE. THIS IS DEPRECATED. Use an action-link instead.
|
| + * Call this to stop clicks on <a href="#"> links from scrolling to the top of
|
| + * the page (and possibly showing a # in the link).
|
| + */
|
| +function preventDefaultOnPoundLinkClicks() {
|
| + document.addEventListener('click', function(e) {
|
| + var anchor = findAncestor(/** @type {Node} */(e.target), function(el) {
|
| + return el.tagName == 'A';
|
| + });
|
| + // Use getAttribute() to prevent URL normalization.
|
| + if (anchor && anchor.getAttribute('href') == '#')
|
| + e.preventDefault();
|
| + });
|
| +}
|
| +
|
| +/**
|
| + * Check the directionality of the page.
|
| + * @return {boolean} True if Chrome is running an RTL UI.
|
| + */
|
| +function isRTL() {
|
| + return document.documentElement.dir == 'rtl';
|
| +}
|
| +
|
| +/**
|
| + * Get an element that's known to exist by its ID. We use this instead of just
|
| + * calling getElementById and not checking the result because this lets us
|
| + * satisfy the JSCompiler type system.
|
| + * @param {string} id The identifier name.
|
| + * @return {!HTMLElement} the Element.
|
| + */
|
| +function getRequiredElement(id) {
|
| + return assertInstanceof($(id), HTMLElement,
|
| + 'Missing required element: ' + id);
|
| +}
|
| +
|
| +/**
|
| + * Query an element that's known to exist by a selector. We use this instead of
|
| + * just calling querySelector and not checking the result because this lets us
|
| + * satisfy the JSCompiler type system.
|
| + * @param {string} selectors CSS selectors to query the element.
|
| + * @param {(!Document|!DocumentFragment|!Element)=} opt_context An optional
|
| + * context object for querySelector.
|
| + * @return {!HTMLElement} the Element.
|
| + */
|
| +function queryRequiredElement(selectors, opt_context) {
|
| + var element = (opt_context || document).querySelector(selectors);
|
| + return assertInstanceof(element, HTMLElement,
|
| + 'Missing required element: ' + selectors);
|
| +}
|
| +
|
| +// Handle click on a link. If the link points to a chrome: or file: url, then
|
| +// call into the browser to do the navigation.
|
| +document.addEventListener('click', function(e) {
|
| + if (e.defaultPrevented)
|
| + return;
|
| +
|
| + var el = e.target;
|
| + if (el.nodeType == Node.ELEMENT_NODE &&
|
| + el.webkitMatchesSelector('A, A *')) {
|
| + while (el.tagName != 'A') {
|
| + el = el.parentElement;
|
| + }
|
| +
|
| + if ((el.protocol == 'file:' || el.protocol == 'about:') &&
|
| + (e.button == 0 || e.button == 1)) {
|
| + chrome.send('navigateToUrl', [
|
| + el.href,
|
| + el.target,
|
| + e.button,
|
| + e.altKey,
|
| + e.ctrlKey,
|
| + e.metaKey,
|
| + e.shiftKey
|
| + ]);
|
| + e.preventDefault();
|
| + }
|
| + }
|
| +});
|
| +
|
| +/**
|
| + * Creates a new URL which is the old URL with a GET param of key=value.
|
| + * @param {string} url The base URL. There is not sanity checking on the URL so
|
| + * it must be passed in a proper format.
|
| + * @param {string} key The key of the param.
|
| + * @param {string} value The value of the param.
|
| + * @return {string} The new URL.
|
| + */
|
| +function appendParam(url, key, value) {
|
| + var param = encodeURIComponent(key) + '=' + encodeURIComponent(value);
|
| +
|
| + if (url.indexOf('?') == -1)
|
| + return url + '?' + param;
|
| + return url + '&' + param;
|
| +}
|
| +
|
| +/**
|
| + * Creates an element of a specified type with a specified class name.
|
| + * @param {string} type The node type.
|
| + * @param {string} className The class name to use.
|
| + * @return {Element} The created element.
|
| + */
|
| +function createElementWithClassName(type, className) {
|
| + var elm = document.createElement(type);
|
| + elm.className = className;
|
| + return elm;
|
| +}
|
| +
|
| +/**
|
| + * webkitTransitionEnd does not always fire (e.g. when animation is aborted
|
| + * or when no paint happens during the animation). This function sets up
|
| + * a timer and emulate the event if it is not fired when the timer expires.
|
| + * @param {!HTMLElement} el The element to watch for webkitTransitionEnd.
|
| + * @param {number=} opt_timeOut The maximum wait time in milliseconds for the
|
| + * webkitTransitionEnd to happen. If not specified, it is fetched from |el|
|
| + * using the transitionDuration style value.
|
| + */
|
| +function ensureTransitionEndEvent(el, opt_timeOut) {
|
| + if (opt_timeOut === undefined) {
|
| + var style = getComputedStyle(el);
|
| + opt_timeOut = parseFloat(style.transitionDuration) * 1000;
|
| +
|
| + // Give an additional 50ms buffer for the animation to complete.
|
| + opt_timeOut += 50;
|
| + }
|
| +
|
| + var fired = false;
|
| + el.addEventListener('webkitTransitionEnd', function f(e) {
|
| + el.removeEventListener('webkitTransitionEnd', f);
|
| + fired = true;
|
| + });
|
| + window.setTimeout(function() {
|
| + if (!fired)
|
| + cr.dispatchSimpleEvent(el, 'webkitTransitionEnd', true);
|
| + }, opt_timeOut);
|
| +}
|
| +
|
| +/**
|
| + * Alias for document.scrollTop getter.
|
| + * @param {!HTMLDocument} doc The document node where information will be
|
| + * queried from.
|
| + * @return {number} The Y document scroll offset.
|
| + */
|
| +function scrollTopForDocument(doc) {
|
| + return doc.documentElement.scrollTop || doc.body.scrollTop;
|
| +}
|
| +
|
| +/**
|
| + * Alias for document.scrollTop setter.
|
| + * @param {!HTMLDocument} doc The document node where information will be
|
| + * queried from.
|
| + * @param {number} value The target Y scroll offset.
|
| + */
|
| +function setScrollTopForDocument(doc, value) {
|
| + doc.documentElement.scrollTop = doc.body.scrollTop = value;
|
| +}
|
| +
|
| +/**
|
| + * Alias for document.scrollLeft getter.
|
| + * @param {!HTMLDocument} doc The document node where information will be
|
| + * queried from.
|
| + * @return {number} The X document scroll offset.
|
| + */
|
| +function scrollLeftForDocument(doc) {
|
| + return doc.documentElement.scrollLeft || doc.body.scrollLeft;
|
| +}
|
| +
|
| +/**
|
| + * Alias for document.scrollLeft setter.
|
| + * @param {!HTMLDocument} doc The document node where information will be
|
| + * queried from.
|
| + * @param {number} value The target X scroll offset.
|
| + */
|
| +function setScrollLeftForDocument(doc, value) {
|
| + doc.documentElement.scrollLeft = doc.body.scrollLeft = value;
|
| +}
|
| +
|
| +/**
|
| + * Replaces '&', '<', '>', '"', and ''' characters with their HTML encoding.
|
| + * @param {string} original The original string.
|
| + * @return {string} The string with all the characters mentioned above replaced.
|
| + */
|
| +function HTMLEscape(original) {
|
| + return original.replace(/&/g, '&')
|
| + .replace(/</g, '<')
|
| + .replace(/>/g, '>')
|
| + .replace(/"/g, '"')
|
| + .replace(/'/g, ''');
|
| +}
|
| +
|
| +/**
|
| + * Shortens the provided string (if necessary) to a string of length at most
|
| + * |maxLength|.
|
| + * @param {string} original The original string.
|
| + * @param {number} maxLength The maximum length allowed for the string.
|
| + * @return {string} The original string if its length does not exceed
|
| + * |maxLength|. Otherwise the first |maxLength| - 1 characters with '...'
|
| + * appended.
|
| + */
|
| +function elide(original, maxLength) {
|
| + if (original.length <= maxLength)
|
| + return original;
|
| + return original.substring(0, maxLength - 1) + '\u2026';
|
| +}
|
| +
|
| +/**
|
| + * Quote a string so it can be used in a regular expression.
|
| + * @param {string} str The source string.
|
| + * @return {string} The escaped string.
|
| + */
|
| +function quoteString(str) {
|
| + return str.replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, '\\$1');
|
| +}
|
|
|