Commit 985bcbf8 authored by Kathleen Brade's avatar Kathleen Brade Committed by Georg Koppen
Browse files

Bug 26960: implement new about:tor start page

Implement new design from UX team.
Remove "update needed" notification (will be addressed by bug 25694).
parent e9b4af29
......@@ -12,8 +12,6 @@
* the code in torbutton.js:
* AboutTor:Loaded page loaded content -> chrome
* AboutTor:ChromeData privileged data chrome -> content
* AboutTor:GetToolbarData request toolbar info content -> chrome
* AboutTor:ToolbarData toolbar info chrome -> content
*/
var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
......@@ -24,7 +22,8 @@ let { bindPrefAndInit } = Cu.import("resource://torbutton/modules/utils.js", {})
var AboutTorListener = {
kAboutTorMessages: [ "AboutTor:ChromeData", "AboutTor:ToolbarData" ],
kAboutTorLoadedMessage: "AboutTor:Loaded",
kAboutTorChromeDataMessage: "AboutTor:ChromeData",
get isAboutTor() {
return content.document.documentURI.toLowerCase() == "about:tor";
......@@ -45,9 +44,6 @@ var AboutTorListener = {
case "pagehide":
this.onPageHide();
break;
case "resize":
sendAsyncMessage("AboutTor:GetToolbarData");
break;
}
},
......@@ -56,12 +52,9 @@ var AboutTorListener = {
return;
switch (aMessage.name) {
case "AboutTor:ChromeData":
case this.kAboutTorChromeDataMessage:
this.onChromeDataUpdate(aMessage.data);
break;
case "AboutTor:ToolbarData":
this.onToolbarDataUpdate(aMessage.data);
break;
}
},
......@@ -74,70 +67,42 @@ var AboutTorListener = {
});
// Add message and event listeners.
this.kAboutTorMessages.forEach(aMsg => addMessageListener(aMsg, this));
addMessageListener("AboutTor:ChromeData", this);
addMessageListener(this.kAboutTorChromeDataMessage, this);
addEventListener("pagehide", this, false);
addEventListener("resize", this, false);
sendAsyncMessage("AboutTor:Loaded");
sendAsyncMessage(this.kAboutTorLoadedMessage);
},
onPageHide: function() {
removeEventListener("resize", this, false);
removeEventListener("pagehide", this, false);
this.kAboutTorMessages.forEach(aMsg => removeMessageListener(aMsg, this));
removeMessageListener(this.kAboutTorChromeDataMessage, this);
},
onChromeDataUpdate: function(aData) {
let body = content.document.body;
// Update status: tor on/off, update needed, Tor Browser manual shown.
// Update status: tor on/off, Tor Browser manual shown.
if (aData.torOn)
body.setAttribute("toron", "yes");
else
body.removeAttribute("toron");
if (aData.updateNeeded)
body.setAttribute("torNeedsUpdate", "yes");
else
body.removeAttribute("torNeedsUpdate");
if (aData.showManual)
body.setAttribute("showmanual", "yes");
else
body.removeAttribute("showmanual");
// Setting body.initialized="yes" displays the body, which must be done
// at this point because our remaining initialization depends on elements
// being visible so that their size and position are accurate.
// Setting body.initialized="yes" displays the body.
body.setAttribute("initialized", "yes");
let containerName = "torstatus-" + (aData.torOn ? "on" : "off") +
"-container";
this.adjustFontSizes(containerName);
this.onToolbarDataUpdate(aData);
},
onToolbarDataUpdate: function(aData) {
this.adjustArrow(aData.toolbarButtonXPos);
},
onLocaleChange: function(aLocale) {
this.insertPropertyStrings();
// Set Tor Browser manual link.
content.document.getElementById("manualLink").href =
"https://tb-manual.torproject.org/" + aLocale;
// Insert "Test Tor Network Settings" url.
let elem = content.document.getElementById("testTorSettings");
if (elem) {
let url = Services.prefs.getCharPref(
"extensions.torbutton.test_url_interactive");
elem.href = url.replace(/__LANG__/g, aLocale.replace(/-/g, '_'));
}
// Display the Tor Browser product name and version.
try {
const kBrandBundle = "chrome://branding/locale/brand.properties";
......@@ -153,177 +118,6 @@ var AboutTorListener = {
elem.appendChild(content.document.createTextNode(productName + '\n'
+ tbbVersion));
} catch (e) {}
},
insertPropertyStrings: function() {
try {
let kPropertiesURL = "chrome://torbutton/locale/aboutTor.properties";
let stringBundle = Services.strings.createBundle(kPropertiesURL);
let s1 = stringBundle.GetStringFromName("aboutTor.searchDDG.privacy.link");
let s2 = stringBundle.GetStringFromName("aboutTor.searchDDG.search.link");
let result = stringBundle.formatStringFromName(
"aboutTor.searchDDG.privacy", [s1, s2], 2);
if (result) {
let elem = content.document.getElementById("searchProviderInfo");
if (elem)
elem.innerHTML = result;
}
} catch(e) {}
},
// Ensure that text in top area does not overlap the tor on/off (onion) image.
// This is done by reducing the font sizes as necessary.
adjustFontSizes: function(aContainerName)
{
let imgElem = content.document.getElementById("torstatus-image");
let containerElem = content.document.getElementById(aContainerName);
if (!imgElem || !containerElem)
return;
try
{
let imgRect = imgElem.getBoundingClientRect();
for (let textElem = containerElem.firstChild; textElem;
textElem = textElem.nextSibling)
{
if ((textElem.nodeType != textElem.ELEMENT_NODE) ||
(textElem.nodeName.toLowerCase() == "br"))
{
continue;
}
let textRect = textElem.getBoundingClientRect();
if (0 == textRect.width)
continue;
// Reduce font to 90% of previous size, repeating the process up to 7
// times. This allows for a maximum reduction to just less than 50% of
// the original size.
let maxTries = 7;
while ((textRect.left < imgRect.right) && (--maxTries >= 0))
{
let style = content.document.defaultView
.getComputedStyle(textElem, null);
let fontSize = parseFloat(style.getPropertyValue("font-size"));
textElem.style.fontSize = (fontSize * 0.9) + "px";
textRect = textElem.getBoundingClientRect();
}
}
} catch (e) {}
},
adjustArrow: function(aToolbarButtonXPos)
{
let win = content;
let doc = content.document;
let textElem = doc.getElementById("updatePrompt");
let arrowHeadDiv = doc.getElementById("toolbarIconArrowHead");
let vertExtDiv = doc.getElementById("toolbarIconArrowVertExtension");
let bendDiv = doc.getElementById("toolbarIconArrowBend");
let horzExtDiv = doc.getElementById("toolbarIconArrowHorzExtension");
if (!textElem || !arrowHeadDiv || !vertExtDiv || !bendDiv || !horzExtDiv)
return;
let arrowTailElems = [ vertExtDiv, bendDiv, horzExtDiv ];
if (!aToolbarButtonXPos || isNaN(aToolbarButtonXPos) ||
(aToolbarButtonXPos < 0))
{
arrowHeadDiv.style.display = "none";
for (let elem of arrowTailElems)
elem.style.display = "none";
return;
}
const kArrowMargin = 6; // Horizontal margin between line and text.
const kArrowHeadExtraWidth = 9; // Horizontal margin to the line.
const kArrowLineThickness = 11;
const kBendWidth = 22;
const kBendHeight = 22;
try {
// Compensate for any content zoom that may be in effect on about:tor.
// Because window.devicePixelRatio always returns 1.0 for non-Chrome
// windows (see bug 13875), we use screenPixelsPerCSSPixel for the
// content window.
let pixRatio = content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.screenPixelsPerCSSPixel;
let tbXpos = Math.round(aToolbarButtonXPos / pixRatio);
arrowHeadDiv.style.display = "block"; // Must be visible to get offsetWidth.
let arrowHalfWidth = Math.round(arrowHeadDiv.offsetWidth / 2);
let leftAnchor = textElem.offsetLeft - kArrowMargin
- kBendWidth + Math.round(kArrowLineThickness / 2);
let rightAnchor = textElem.offsetLeft + textElem.offsetWidth
+ kArrowMargin + arrowHalfWidth;
let isArrowOnLeft = (tbXpos < leftAnchor);
let isArrowOnRight = (tbXpos > rightAnchor) &&
(tbXpos < (win.innerWidth - arrowHalfWidth));
let isArrowInMiddle = (tbXpos >= leftAnchor) && (tbXpos <= rightAnchor);
if (isArrowOnLeft || isArrowOnRight || isArrowInMiddle)
{
// Position the arrow head.
let arrowHeadLeft = tbXpos - arrowHalfWidth;
arrowHeadDiv.style.left = arrowHeadLeft + "px";
if (isArrowOnLeft || isArrowOnRight)
{
let horzExtBottom = textElem.offsetTop +
Math.round((textElem.offsetHeight + kArrowLineThickness) / 2);
// Position the vertical (extended) line.
let arrowHeadBottom = arrowHeadDiv.offsetTop +
arrowHeadDiv.offsetHeight;
vertExtDiv.style.top = arrowHeadBottom + "px";
vertExtDiv.style.left = (arrowHeadLeft + kArrowHeadExtraWidth) + "px";
let ht = horzExtBottom - kBendHeight - arrowHeadBottom;
vertExtDiv.style.height = ht + "px";
// Position the bend (elbow).
bendDiv.style.top = (horzExtBottom - kBendHeight) + "px";
let bendDivLeft;
if (isArrowOnLeft)
{
bendDiv.setAttribute("pos", "left");
bendDivLeft = arrowHeadLeft + kArrowHeadExtraWidth;
}
else if (isArrowOnRight)
{
bendDiv.setAttribute("pos", "right");
bendDivLeft = arrowHeadLeft + kArrowHeadExtraWidth
+ kArrowLineThickness - kBendWidth;
}
bendDiv.style.left = bendDivLeft + "px";
// Position the horizontal (extended) line.
horzExtDiv.style.top = (horzExtBottom - kArrowLineThickness) + "px";
let horzExtLeft, w;
if (isArrowOnLeft)
{
horzExtLeft = bendDivLeft + kBendWidth;
w = (textElem.offsetLeft - horzExtLeft - kArrowMargin);
}
else
{
horzExtLeft = rightAnchor - arrowHalfWidth;
w = tbXpos - arrowHalfWidth - horzExtLeft;
}
horzExtDiv.style.left = horzExtLeft + "px";
horzExtDiv.style.width = w + "px";
}
}
let headDisplay = (isArrowOnLeft || isArrowInMiddle || isArrowOnRight)
? "block" : "none";
arrowHeadDiv.style.display = headDisplay;
let tailDisplay = (isArrowOnLeft || isArrowOnRight) ? "block" : "none";
for (let elem of arrowTailElems)
elem.style.display = tailDisplay;
} catch (e) {}
}
};
......
......@@ -31,87 +31,173 @@ window.addEventListener("pageshow", function() {
</script>
</head>
<body dir="&locale.dir;">
<div class="hideIfTorIsUpToDate">
<div id="toolbarIconArrowHead" class="arrow"/>
<div id="toolbarIconArrowVertExtension" class="arrow"/>
<div id="toolbarIconArrowBend" class="arrow"/>
<div id="toolbarIconArrowHorzExtension" class="arrow"/>
</div>
<div class="torcontent-container">
<div id="torstatus-version"/>
<div id="torstatus" class="top">
<div id="torstatus-image"/>
<div id="torstatus-on-container" class="hideIfTorOff torstatus-container">
<h1>&aboutTor.success.label;</h1>
<br/>
<h3 class="hideIfTBBNeedsUpdate">&aboutTor.success3.label;</h3>
<div class="heading1">&aboutTor.ready.label;</div>
<br/>
<div style="margin-top: 20px;">
<a id="testTorSettings" href="about:blank">&aboutTor.check.label;</a>
</div>
<div class="heading2">&aboutTor.ready2.label;</div>
</div>
<div id="torstatus-off-container" class="hideIfTorOn torstatus-container">
<h1>&aboutTor.failure.label;</h1>
<div class="heading1">&aboutTor.failure.label;</div>
<br/>
<h2>&aboutTor.failure2.label;</h2>
</div>
</div>
<div class="top">
<div class="hideIfTorIsUpToDate">
<h1 class="hideIfTorOff">&aboutTor.outOfDateTorOn.label;</h1>
<h1 class="hideIfTorOn">&aboutTor.outOfDateTorOff.label;</h1>
<div>
<h3 id="updatePrompt">&aboutTor.outOfDate2.label;</h3>
</div>
<div class="heading2">&aboutTor.failure2.label;</div>
</div>
</div>
<div class="searchbox hideIfTorOff"> <!-- begin form based search -->
<form action="&aboutTor.searchDDGPost.link;" method="post">
<div id="sxw">
<div id="sbutton">
<input name="b" id="sb" value="" title="&aboutTor.search.label;"
alt="&aboutTor.search.label;" type="submit"/>
<div class="searchwrapper">
<label class="searchlabel" for="search-text">&nbsp;</label>
<input name="q" id="search-text" placeholder="&aboutTor.search.label;"
autocomplete="off" type="text"/>
<input name="b" id="search-button" value=""
title="&aboutTor.search.label;"
alt="&aboutTor.search.label;" type="submit"/>
</div>
<input name="q" autocomplete="off" id="sx" type="text"/>
</div>
<h4 id="searchProviderInfo" />
</form>
</div>
<div class="hideIfTorOn" style="height:100px"/>
<div id="middle" class="hideIfTorOff">
<div class="bubble">
<h1>&aboutTor.whatnextQuestion.label;</h1>
<p>&aboutTor.whatnextAnswer.label;</p>
<ul>
<li>
<a href="&aboutTor.whatnext.link;">
&aboutTor.whatnext.label;
</a>
</li>
<li class="showForManual">
<a id="manualLink">
&aboutTor.torbrowser_user_manual.label; &raquo;
</a>
</li>
</ul>
</div>
<div class="bubble">
<h1>&aboutTor.helpInfo1.label;</h1>
<p>&aboutTor.helpInfo2.label;</p>
<ul>
<li><a href="&aboutTor.helpInfo3.link;">&aboutTor.helpInfo3.label;</a></li>
<li><a href="&aboutTor.helpInfo4.link;">&aboutTor.helpInfo4.label;</a></li>
<li><a href="&aboutTor.helpInfo5.link;">&aboutTor.helpInfo5.label;</a></li>
</ul>
</div>
</div> <!-- middle -->
<div id="bottom">
<p>&aboutTor.footer.label;
<a href="&aboutTor.learnMore.link;">&aboutTor.learnMore.label;</a></p>
<p class="showForManual moreInfoLink">&aboutTor.torbrowser_user_manual_questions.label;
<a id="manualLink">&aboutTor.torbrowser_user_manual_link.label;</a></p>
<p>&aboutTor.tor_mission.label;
<a href="&aboutTor.getInvolved.link;">&aboutTor.getInvolved.label;</a></p>
</div>
</div>
<!--
- The abstract onion pattern begins here. There are two
- "onion-pattern-row" elements, each containing 14 circles. The width
- of "onion-pattern-row" is fixed at a value that is wide enough so the
- circles are not distorted by the flex-based layout. The parent
- "onion-pattern-container" element has overflow: hidden and is designed
- to expand to the width of the page, until it reaches a maximum width
- that can accommodate all 14 circles. Since the rows are wider than
- most browser windows, typically the two rows of onions will fill the
- bottom of the page. On really wide pages, the onions are centered at
- the bottom of the page.
-->
<div class="onion-pattern-container">
<div class="onion-pattern-row">
<div class="circle solid"></div>
<div class="circle border"></div>
<div class="circle border">
<div class="inner border"></div>
<div class="inner border"></div>
<div class="inner border"></div>
</div>
<div class="circle">
<div class="half solid"></div>
<div class="half dotted"></div>
</div>
<div class="circle dotted"></div>
<div class="circle dotted">
<div class="inner dotted"></div>
<div class="inner dotted"></div>
<div class="inner dotted"></div>
</div>
<div class="circle dashed"></div>
<div class="circle dashed">
<div class="inner dashed"></div>
<div class="inner dashed"></div>
<div class="inner dashed"></div>
</div>
<div class="circle bold"></div>
<div class="circle solid"></div>
<div class="circle dotted">
<div class="inner dotted"></div>
<div class="inner dotted"></div>
<div class="inner dotted"></div>
</div>
<div class="circle border">
<div class="inner border"></div>
<div class="inner border"></div>
<div class="inner border"></div>
</div>
<div class="circle">
<div class="half solid"></div>
<div class="half solid"></div>
</div>
<div class="circle dashed">
<div class="inner dashed"></div>
<div class="inner dashed"></div>
<div class="inner dashed"></div>
</div>
</div>
<div class="onion-pattern-row onion-pattern-offset-row">
<div class="circle dashed">
<div class="inner dashed"></div>
<div class="inner dashed"></div>
<div class="inner dashed"></div>
</div>
<div class="circle bold"></div>
<div class="circle solid"></div>
<div class="circle dotted">
<div class="inner dotted"></div>
<div class="inner dotted"></div>
<div class="inner dotted"></div>
</div>
<div class="circle border">
<div class="inner border"></div>
<div class="inner border"></div>
<div class="inner border"></div>
</div>
<div class="circle">
<div class="half solid"></div>
<div class="half solid"></div>
</div>
<div class="circle dashed">
<div class="inner dashed"></div>
<div class="inner dashed"></div>
<div class="inner dashed"></div>
</div>
<div class="circle solid"></div>
<div class="circle border"></div>
<div class="circle border">
<div class="inner border"></div>
<div class="inner border"></div>
<div class="inner border"></div>
</div>
<div class="circle">
<div class="half solid"></div>
<div class="half dotted"></div>
</div>
<div class="circle dotted"></div>
<div class="circle dotted">
<div class="inner dotted"></div>
<div class="inner dotted"></div>
<div class="inner dotted"></div>
</div>
<div class="circle dashed"></div>
</div>
</div>
</body>
......
......@@ -338,10 +338,9 @@ function torbutton_init() {
}
}
// Add about:tor IPC message listeners.
let aboutTorMessages = [ "AboutTor:Loaded", "AboutTor:GetToolbarData" ];
aboutTorMessages.forEach(aMsg => window.messageManager.addMessageListener(
aMsg, torbutton_abouttor_message_handler));
// Add about:tor IPC message listener.
window.messageManager.addMessageListener("AboutTor:Loaded",
torbutton_abouttor_message_handler);
// XXX: Get rid of the cached asmjs (or IndexedDB) files on disk in case we
// don't allow things saved to disk. This is an ad-hoc fix to work around
......@@ -369,11 +368,6 @@ function torbutton_init() {
torbutton_log(1, "registering Tor check observer");
torbutton_tor_check_observer.register();
// Detect toolbar customization and update arrow on about:tor pages.
window.addEventListener("aftercustomization", function() {
torbutton_abouttor_message_handler.updateAllOpenPages();
}, false);
//setting up context menu
//var contextMenu = document.getElementById("contentAreaContextMenu");
//if (contextMenu)
......@@ -425,10 +419,6 @@ var torbutton_abouttor_message_handler = {
aMessage.target.messageManager.sendAsyncMessage("AboutTor:ChromeData",
this.chromeData);
break;
case "AboutTor:GetToolbarData":
aMessage.target.messageManager.sendAsyncMessage("AboutTor:ToolbarData",
this.toolbarData);
break;
}
},
......@@ -441,23 +431,12 @@ var torbutton_abouttor_message_handler = {
// The chrome data contains all of the data needed by the about:tor
// content process that is only available here (in the chrome process).
// It is sent to the content process when an about:tor window is opened
// and in response to events such as the browser noticing that an update
// is available.
// and in response to events such as the browser noticing that Tor is
// not working.
get chromeData() {
return {
torOn: torbutton_tor_check_ok(),
updateNeeded: torbutton_update_is_needed(),
showManual: torbutton_show_torbrowser_manual(),
toolbarButtonXPos: torbutton_get_toolbarbutton_xpos()
};
},
// The toolbar data only contains the x coordinate of Torbutton's toolbar
// item; it is sent back to the content process as the about:tor window
// is resized.
get toolbarData() {
return {
toolbarButtonXPos: torbutton_get_toolbarbutton_xpos()
showManual: torbutton_show_torbrowser_manual()
};
}
};
......@@ -593,9 +572,6 @@ function torbutton_notify_if_update_needed() {
var btn = torbutton_get_toolbutton();
setOrClearAttribute(btn, "tbUpdateNeeded", updateNeeded);
// Update all open about:tor pages.
torbutton_abouttor_message_handler.updateAllOpenPages();