123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
- "use strict";
- const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
- Cu.importGlobalProperties(["URL"]);
- this.EXPORTED_SYMBOLS = ["navigate"];
- this.navigate = {};
- /**
- * Determines if we expect to get a DOM load event (DOMContentLoaded)
- * on navigating to the |future| URL.
- *
- * @param {string} current
- * URL the browser is currently visiting.
- * @param {string=} future
- * Destination URL, if known.
- *
- * @return {boolean}
- * Full page load would be expected if future is followed.
- *
- * @throws TypeError
- * If |current| is not defined, or any of |current| or |future|
- * are invalid URLs.
- */
- navigate.isLoadEventExpected = function (current, future = undefined) {
- if (typeof current == "undefined") {
- throw TypeError("Expected at least one URL");
- }
- // assume we will go somewhere exciting
- if (typeof future == "undefined") {
- return true;
- }
- let cur = new navigate.IdempotentURL(current);
- let fut = new navigate.IdempotentURL(future);
- // assume javascript:<whatever> will modify current document
- // but this is not an entirely safe assumption to make,
- // considering it could be used to set window.location
- if (fut.protocol == "javascript:") {
- return false;
- }
- // navigating to same url, but with any hash
- if (cur.origin == fut.origin &&
- cur.pathname == fut.pathname &&
- fut.hash != "") {
- return false;
- }
- return true;
- };
- /**
- * Sane URL implementation that normalises URL fragments (hashes) and
- * path names for "data:" URLs, and makes them idempotent.
- *
- * At the time of writing this, the web is approximately 10 000 days (or
- * ~27.39 years) old. One should think that by this point we would have
- * solved URLs. The following code is prudent example that we have not.
- *
- * When a URL with a fragment identifier but no explicit name for the
- * fragment is given, i.e. "#", the {@code hash} property a {@code URL}
- * object computes is an empty string. This is incidentally the same as
- * the default value of URLs without fragments, causing a lot of confusion.
- *
- * This means that the URL "http://a/#b" produces a hash of "#b", but that
- * "http://a/#" produces "". This implementation rectifies this behaviour
- * by returning the actual full fragment, which is "#".
- *
- * "data:" URLs that contain fragments, which if they have the same origin
- * and path name are not meant to cause a page reload on navigation,
- * confusingly adds the fragment to the {@code pathname} property.
- * This implementation remedies this behaviour by trimming it off.
- *
- * The practical result of this is that while {@code URL} objects are
- * not idempotent, the returned URL elements from this implementation
- * guarantees that |url.hash == url.hash|.
- *
- * @param {string|URL} o
- * Object to make an URL of.
- *
- * @return {navigate.IdempotentURL}
- * Considered by some to be a somewhat saner URL.
- *
- * @throws TypeError
- * If |o| is not a valid type or if is a string that cannot be parsed
- * as a URL.
- */
- navigate.IdempotentURL = function (o) {
- let url = new URL(o);
- let hash = url.hash;
- if (hash == "" && url.href[url.href.length - 1] == "#") {
- hash = "#";
- }
- return {
- hash: hash,
- host: url.host,
- hostname: url.hostname,
- href: url.href,
- origin: url.origin,
- password: url.password,
- pathname: url.pathname,
- port: url.port,
- protocol: url.protocol,
- search: url.search,
- searchParams: url.searchParams,
- username: url.username,
- };
- };
|