<!DOCTYPE html [
<!ATTLIST foo:base
   id     ID       #IMPLIED
>
]>
<html xmlns:foo="http://foo.com" xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=209275
-->
<head>
  <title>Test for Bug 209275</title>
  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />

  <style>
    @namespace svg url("http://www.w3.org/2000/svg");
    svg|a           { fill:blue; }
    svg|a:visited   { fill:purple; }
  </style>

  <!--
    base0 should be ignored because it's not in the XHTML namespace
  -->
  <foo:base id="base0" href="http://www.foo.com" />

  <!--
    baseEmpty should be ignored because it has no href and never gets one.
  -->
  <base id="baseEmpty" />

  <!--
    baseWrongAttrNS should be ignored because its href attribute isn't in the empty
    namespace.
  -->
  <base id="baseWrongAttrNS" foo:href="http://foo.com" />

  <base id="base1" />
  <base id="base2" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=209275">Mozilla Bug 209275</a>
<p id="display">
</p>
<div id="content">
  <a href="/" id="link1">link1</a>
  <div style="display:none">
    <a href="/" id="link2">link2</a>
  </div>
  <a href="/" id="link3" style="display:none">link3</a>
  <a href="#" id="link4">link4</a>
  <a href=""  id="colorlink">colorlink</a>
  <a href="#" id="link5">link5</a>
  <iframe id="iframe"></iframe>

  <svg width="5cm" height="3cm" viewBox="0 0 5 3" version="1.1"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink">
  <a xlink:href="" id="ellipselink">
    <ellipse cx="2.5" cy="1.5" rx="2" ry="1" id="ellipse" />
  </a>
  </svg>

</div>
<pre id="test">
<script type="text/javascript;version=1.7">
<![CDATA[

/** Test for Bug 209275 **/
SimpleTest.waitForExplicitFinish();

function link123HrefIs(href, testNum) {
  is($('link1').href, href, "link1 test " + testNum);
  is($('link2').href, href, "link2 test " + testNum);
  is($('link3').href, href, "link3 test " + testNum);
}

var gGen;

function visitedDependentComputedStyle(win, elem, property) {
  var utils = SpecialPowers.getDOMWindowUtils(window);
  return utils.getVisitedDependentComputedStyle(elem, "", property);
}

function getColor(elem) {
  return visitedDependentComputedStyle(document.defaultView, elem, "color");
}

function getFill(elem) {
  return visitedDependentComputedStyle(document.defaultView, elem, "fill");
}

function setXlinkHref(elem, href) {
  elem.setAttributeNS("http://www.w3.org/1999/xlink", "href", href);
}

function continueTest() {
  gGen.next();
}

var iframe = document.getElementById("iframe");
var iframeCw = iframe.contentWindow;

function run() {
  var iframe = document.getElementById("iframe");
  var iframeCw = iframe.contentWindow;

  // First, set the visited/unvisited link/ellipse colors.
  const unvisitedColor = "rgb(0, 0, 238)";
  const visitedColor = "rgb(85, 26, 139)";
  const unvisitedFill = "rgb(0, 0, 255)";
  const visitedFill = "rgb(128, 0, 128)";

  const rand = Date.now() + "-" + Math.random();

  // Now we can start the tests in earnest.

  var loc = location;
  // everything from the location up to and including the final forward slash
  var path = /(.*\/)[^\/]*/.exec(location)[1];

  // Set colorlink's href so we can check that it changes colors after we
  // change the base href.
  $('colorlink').href = "http://example.com/" + rand;
  setXlinkHref($("ellipselink"), "http://example.com/" + rand);

  // Load http://example.com/${rand} into an iframe so we can test that changing
  // the document's base changes the visitedness of our links.
  iframe.onload = continueTest;
  iframeCw.location = "http://example.com/" + rand;
  yield undefined; // wait for onload to fire.

  // Make sure things are what as we expect them at the beginning.
  link123HrefIs("http://mochi.test:8888/", 1);
  is($('link4').href, loc + "#", "link 4 test 1");
  is($('link5').href, loc + "#", "link 5 test 1");

  // Remove link5 from the document.  We're going to test that its href changes
  // properly when we change our base.
  var link5 = $('link5');
  link5.parentNode.removeChild(link5);

  $('base1').href = "http://example.com";

  // Were the links' hrefs updated after the base change?
  link123HrefIs("http://example.com/", 2);
  is($('link4').href, "http://example.com/#", "link 4 test 2");
  is(link5.href, "http://example.com/#", "link 5 test 2");

  // Were colorlink's color and ellipse's fill updated appropriately?
  // Because link coloring is asynchronous, we wait until it is updated (or we
  // timeout and fail anyway).
  while (getColor($('colorlink')) != visitedColor) {
    setTimeout(continueTest, 0);
    yield undefined;
  }
  is(getColor($('colorlink')), visitedColor,
     "Wrong link color after base change.");
  while (getFill($('ellipselink')) != visitedFill) {
    setTimeout(continueTest, 0);
    yield undefined;
  }
  is(getFill($('ellipselink')), visitedFill,
          "Wrong ellipse fill after base change.");

  $('base1').href = "foo/";
  // Should be interpreted relative to current URI (not the current base), so
  // base should now be http://mochi.test:8888/foo/

  link123HrefIs("http://mochi.test:8888/", 3);
  is($('link4').href, path + "foo/#", "link 4 test 3");

  // Changing base2 shouldn't affect anything, because it's not the first base
  // tag.
  $('base2').href = "http://example.org/bar/";
  link123HrefIs("http://mochi.test:8888/", 4);
  is($('link4').href, path + "foo/#", "link 4 test 4");

  // If we unset base1's href attribute, the document's base should come from
  // base2, whose href is http://example.org/bar/.
  $('base1').removeAttribute("href");
  link123HrefIs("http://example.org/", 5);
  is($('link4').href, "http://example.org/bar/#", "link 4 test 5");

  // If we remove base1, base2 should become the first base tag, and the hrefs
  // of all the links should change accordingly.
  $('base1').parentNode.removeChild($('base1'));
  link123HrefIs("http://example.org/", 6);
  is($('link4').href, "http://example.org/bar/#", "link 4 test 6");

  // If we add a new base after base2, nothing should change.
  var base3 = document.createElement("base");
  base3.href = "http://base3.example.org/";
  $('base2').parentNode.insertBefore(base3, $('base2').nextSibling);
  link123HrefIs("http://example.org/", 7);
  is($('link4').href, "http://example.org/bar/#", "link 4 test 7");

  // But now if we add a new base before base 2, it should become the primary
  // base.
  var base4 = document.createElement("base");
  base4.href = "http://base4.example.org/";
  $('base2').parentNode.insertBefore(base4, $('base2'));
  link123HrefIs("http://base4.example.org/", 8);
  is($('link4').href, "http://base4.example.org/#", "link 4 test 8");

  // Now if we remove all the base tags, the base should become the page's URI
  // again.
  $('base2').parentNode.removeChild($('base2'));
  base3.parentNode.removeChild(base3);
  base4.parentNode.removeChild(base4);

  link123HrefIs("http://mochi.test:8888/", 9);
  is($('link4').href, loc + "#", "link 4 test 9");

  // Setting the href of base0 shouldn't do anything because it's not in the
  // XHTML namespace.
  $('base0').href = "http://bar.com";
  link123HrefIs("http://mochi.test:8888/", 10);
  is($('link4').href, loc + "#", "link 4 test 10");

  // We load into an iframe a document with a <base href="...">, then remove
  // the document element.  Then we add an <html>, <body>, and <a>, and make
  // sure that the <a> is resolved relative to the page's location, not its
  // original base.  We do this twice, rebuilding the document in a different
  // way each time.

  iframe.onload = null;
  iframeCw.location = "file_bug209275_1.html";
  yield undefined; // wait for our child to call us back.
  is(iframeCw.document.getElementById("link").href,
     path + "file_bug209275_1.html#",
     "Wrong href after nuking document.");

  iframeCw.location = "file_bug209275_2.html";
  yield undefined; // wait for callback from child
  is(iframeCw.document.getElementById("link").href,
     "http://mochi.test:8888/",
     "Wrong href after nuking document second time.");

  // Make sure that document.open() makes the document forget about any <base>
  // tags it has.
  iframeCw.location = "file_bug209275_3.html";
  yield undefined; // wait for callback from child
  is(iframeCw.document.getElementById("link").href,
     "http://mochi.test:8888/",
     "Wrong href after document.open().");

  SimpleTest.finish();
  yield undefined;
}

window.addEventListener("load", function() {
  gGen = run();
  gGen.next();
}, false);

]]>
</script>
</pre>
</body>
</html>