# HG changeset patch
# Parent 541ccce39563cf1e660747e1bcbede359a6cccaf
# User Eklavya Mirani (eklavyamirani@hotmail.com)
Bug 558882: Fixed entries in winstripe/jar.mn for reader mode files under aero section. Reader mode is now working on Windows.
* * *
Bug 793920: Moved Readability.js and JSDOMparser.js to reader/toolkit
* * *
Bug 795973:Kevin added a preference
* * *
Bug 795981:Made fixes to previous patch.
* * *
Bug test: Reader Mode is working.
diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -16,16 +16,18 @@
#
#ifdef XP_UNIX
#ifndef XP_MACOSX
#define UNIX_BUT_NOT_MAC
#endif
#endif
+
+
pref("browser.chromeURL","chrome://browser/content/");
pref("browser.hiddenWindowChromeURL", "chrome://browser/content/hiddenWindow.xul");
// Enables some extra Extension System Logging (can reduce performance)
pref("extensions.logging.enabled", false);
// Disables strict compatibility, making addons compatible-by-default.
pref("extensions.strictCompatibility", false);
@@ -1187,8 +1189,15 @@ pref("social.manifest.facebook", "{\"ori
// built-in social functionality.
pref("social.activation.whitelist", "https://www.facebook.com");
pref("social.sidebar.open", true);
pref("social.sidebar.unload_timeout_ms", 10000);
pref("social.active", false);
pref("social.toast-notifications.enabled", true);
pref("dom.identity.enabled", false);
+
+//Reader settings
+pref("reader.margin_size", 5);
+pref("reader.font_size", 12);
+pref("reader.color_scheme", "light");
+pref("reader.has_used_toolbar", false);
+pref("reader.enabled", false);
\ No newline at end of file
diff --git a/browser/base/content/aboutReader.html b/browser/base/content/aboutReader.html
new file mode 100644
--- /dev/null
+++ b/browser/base/content/aboutReader.html
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/base/content/aboutReader.js b/browser/base/content/aboutReader.js
new file mode 100644
--- /dev/null
+++ b/browser/base/content/aboutReader.js
@@ -0,0 +1,561 @@
+/* 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/. */
+
+let Ci = Components.interfaces, Cc = Components.classes, Cu = Components.utils;
+
+Cu.import("resource://gre/modules/Services.jsm")
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyGetter(window, "gChromeWin", function ()
+ window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShellTreeItem)
+ .rootTreeItem
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow)
+ .QueryInterface(Ci.nsIDOMChromeWindow));
+
+function dump(s) {
+ Services.console.logStringMessage("AboutReader: " + s);
+}
+
+let gStrings = Services.strings.createBundle("chrome://browser/locale/aboutReader.properties");
+
+let AboutReader = function(doc, win) {
+ this._docRef = Cu.getWeakReference(doc);
+ this._winRef = Cu.getWeakReference(win);
+
+ this._article = null;
+
+ dump("Feching toolbar, header and content notes from about:reader");
+ this._headerElementRef = Cu.getWeakReference(doc.getElementById("reader-header"));
+ this._domainElementRef = Cu.getWeakReference(doc.getElementById("reader-domain"));
+
+ this._titleElementRef = Cu.getWeakReference(doc.getElementById("reader-title"));
+
+ this._creditsElementRef = Cu.getWeakReference(doc.getElementById("reader-credits"));
+ this._contentElementRef = Cu.getWeakReference(doc.getElementById("reader-content"));
+ this._toolbarElementRef = Cu.getWeakReference(doc.getElementById("reader-toolbar"));
+
+ this._toolbarEnabled = true;
+
+ this._scrollOffset = win.pageYOffset;
+
+ win.addEventListener("click", this, false);
+
+ win.addEventListener("scroll", this, false);
+ win.addEventListener("popstate", this, false);
+ win.addEventListener("resize", this, false);
+
+ this._setupAllDropdowns();
+
+ let colorSchemeOptions = [
+ { name: gStrings.GetStringFromName("aboutReader.colorSchemeLight"),
+ value: "light"},
+ { name: gStrings.GetStringFromName("aboutReader.colorSchemeDark"),
+ value: "dark"}
+ ];
+
+ let colorScheme = Services.prefs.getCharPref("reader.color_scheme");
+ this._setupSegmentedButton("color-scheme-buttons", colorSchemeOptions, colorScheme, this._setColorScheme.bind(this));
+ this._setColorScheme(colorScheme);
+
+ let fontTitle = gStrings.GetStringFromName("aboutReader.textTitle");
+ this._setupStepControl("font-size-control", fontTitle, this._onFontSizeChange.bind(this));
+ this._fontSize = 0;
+ this._setFontSize(Services.prefs.getIntPref("reader.font_size"));
+
+ let marginTitle = gStrings.GetStringFromName("aboutReader.marginTitle");
+ this._setupStepControl("margin-size-control", marginTitle, this._onMarginSizeChange.bind(this));
+ this._marginSize = 0;
+ this._setMarginSize(Services.prefs.getIntPref("reader.margin_size"));
+
+ dump("Decoding query arguments");
+ let queryArgs = this._decodeQueryString(win.location.href);
+
+ let url = queryArgs.url;
+ let tabId = 1;
+ if (tabId) {
+ dump("Loading from tab with ID: " + tabId + ", URL: " + url);
+ this._loadFromTab(tabId, url);
+ } else {
+ dump("Fetching page with URL: " + url);
+ this._loadFromURL(url);
+ }
+}
+
+AboutReader.prototype = {
+ _STEP_INCREMENT: 0,
+ _STEP_DECREMENT: 1,
+
+ _BLOCK_IMAGES_SELECTOR: ".content p > img:only-child, " +
+ ".content p > a:only-child > img:only-child, " +
+ ".content .wp-caption img, " +
+ ".content figure img",
+
+ get _doc() {
+ return this._docRef.get();
+ },
+
+ get _win() {
+ return this._winRef.get();
+ },
+
+ get _headerElement() {
+ return this._headerElementRef.get();
+ },
+
+ get _domainElement() {
+ return this._domainElementRef.get();
+ },
+
+ get _titleElement() {
+ return this._titleElementRef.get();
+ },
+
+ get _creditsElement() {
+ return this._creditsElementRef.get();
+ },
+
+ get _contentElement() {
+ return this._contentElementRef.get();
+ },
+
+ get _toolbarElement() {
+ return this._toolbarElementRef.get();
+ },
+
+ handleEvent: function Reader_handleEvent(aEvent) {
+ if (!aEvent.isTrusted)
+ return;
+
+ switch (aEvent.type) {
+ case "click":
+ this._scrolled = false;
+ if (!this._scrolled)
+ this._toggleToolbarVisibility();
+ break;
+ case "scroll":
+ if (!this._scrolled) {
+ this._scrolled = true;
+ this._setToolbarVisibility(false);
+ }
+ break;
+ case "popstate":
+ if (!aEvent.state)
+ this._closeAllDropdowns();
+ break;
+ case "resize":
+ this._updateImageMargins();
+ break;
+ }
+ },
+
+ _onMarginSizeChange: function Reader_onMarginSizeChange(operation) {
+ if (operation == this._STEP_INCREMENT)
+ this._setMarginSize(this._marginSize + 5);
+ else
+ this._setMarginSize(this._marginSize - 5);
+ },
+
+ _setMarginSize: function Reader_setMarginSize(newMarginSize) {
+ if (this._marginSize === newMarginSize)
+ return;
+
+ let doc = this._doc;
+
+ this._marginSize = Math.max(5, Math.min(25, newMarginSize));
+ doc.body.style.marginLeft = this._marginSize + "%";
+ doc.body.style.marginRight = this._marginSize + "%";
+
+ this._updateImageMargins();
+
+ Services.prefs.setIntPref("reader.margin_size", this._marginSize);
+ },
+
+ _onFontSizeChange: function Reader_onFontSizeChange(operation) {
+ if (operation == this._STEP_INCREMENT)
+ this._setFontSize(this._fontSize + 1);
+ else
+ this._setFontSize(this._fontSize - 1);
+ },
+
+ _setFontSize: function Reader_setFontSize(newFontSize) {
+ if (this._fontSize === newFontSize)
+ return;
+
+ let bodyClasses = this._doc.body.classList;
+
+ if (this._fontSize > 0)
+ bodyClasses.remove("font-size" + this._fontSize);
+
+ this._fontSize = Math.max(1, Math.min(7, newFontSize));
+ bodyClasses.add("font-size" + this._fontSize);
+
+ Services.prefs.setIntPref("reader.font_size", this._fontSize);
+ },
+
+ _setColorScheme: function Reader_setColorScheme(newColorScheme) {
+ if (this._colorScheme === newColorScheme)
+ return;
+
+ let bodyClasses = this._doc.body.classList;
+
+ if (this._colorScheme)
+ bodyClasses.remove(this._colorScheme);
+
+ this._colorScheme = newColorScheme;
+ bodyClasses.add(this._colorScheme);
+
+ Services.prefs.setCharPref("reader.color_scheme", this._colorScheme);
+ },
+
+ _getToolbarVisibility: function Reader_getToolbarVisibility() {
+ return !this._toolbarElement.classList.contains("toolbar-hidden");
+ },
+
+ _setToolbarVisibility: function Reader_setToolbarVisibility(visible) {
+ let win = this._win;
+ if (win.history.state)
+ win.history.back();
+
+ if (!this._toolbarEnabled)
+ return;
+
+ if (this._getToolbarVisibility() === visible)
+ return;
+
+ this._toolbarElement.classList.toggle("toolbar-hidden");
+
+ if (!visible && !this._hasUsedToolbar) {
+ this._hasUsedToolbar = Services.prefs.getBoolPref("reader.has_used_toolbar");
+ if (!this._hasUsedToolbar) {
+ Services.prefs.setBoolPref("reader.has_used_toolbar", true);
+ this._hasUsedToolbar = true;
+ }
+ }
+ },
+
+ _toggleToolbarVisibility: function Reader_toggleToolbarVisibility(visible) {
+ this._setToolbarVisibility(!this._getToolbarVisibility());
+ },
+
+ _loadFromURL: function Reader_loadFromURL(url) {
+ this._showProgress();
+ gChromeWin.Reader.parseDocumentFromURL(url, function(article) {
+
+ if (article) {
+ this._showContent(article);
+ }
+ else {
+ this._showError(gStrings.GetStringFromName("aboutReader.loadError"));
+ }
+ }.bind(this));
+ },
+
+ _loadFromTab: function Reader_loadFromTab(tabId, url) {
+ this._showProgress();
+
+ gChromeWin.Reader.getArticleForTab(tabId, url, function(article) {
+ if (article)
+ this._showContent(article);
+ else
+ this._showError(gStrings.GetStringFromName("aboutReader.loadError"));
+ }.bind(this));
+ },
+
+
+
+ _updateImageMargins: function Reader_updateImageMargins() {
+ let windowWidth = this._win.innerWidth;
+ let contentWidth = this._contentElement.offsetWidth;
+ let maxWidthStyle = windowWidth + "px !important";
+
+ let setImageMargins = function(img) {
+ if (!img._originalWidth)
+ img._originalWidth = img.offsetWidth;
+
+ let imgWidth = img._originalWidth;
+
+ // If the image is taking more than half of the screen, just make
+ // it fill edge-to-edge.
+ if (imgWidth < contentWidth && imgWidth > windowWidth * 0.55)
+ imgWidth = windowWidth;
+
+ let sideMargin = Math.max((contentWidth - windowWidth) / 2,
+ (contentWidth - imgWidth) / 2);
+
+ let imageStyle = sideMargin + "px !important";
+ let widthStyle = imgWidth + "px !important";
+
+ let cssText = "max-width: " + maxWidthStyle + ";" +
+ "width: " + widthStyle + ";" +
+ "margin-left: " + imageStyle + ";" +
+ "margin-right: " + imageStyle + ";";
+
+ img.style.cssText = cssText;
+ }
+
+ let imgs = this._doc.querySelectorAll(this._BLOCK_IMAGES_SELECTOR);
+ for (let i = imgs.length; --i >= 0;) {
+ let img = imgs[i];
+
+ if (img.width > 0) {
+ setImageMargins(img);
+ } else {
+ img.onload = function() {
+ setImageMargins(img);
+ }
+ }
+ }
+ },
+
+ _showError: function Reader_showError(error) {
+ this._headerElement.style.display = "none";
+ this._contentElement.innerHTML = error;
+ this._contentElement.style.display = "block";
+
+ this._doc.title = error;
+ },
+
+ _showContent: function Reader_showContent(article) {
+ this._article = article;
+
+ let domain = Services.io.newURI(article.url, null, null).host;
+ this._domainElement.innerHTML = domain;
+
+ this._creditsElement.innerHTML = article.byline;
+
+ this._titleElement.innerHTML = article.title;
+ this._doc.title = article.title;
+
+ this._headerElement.style.display = "block";
+
+ this._contentElement.innerHTML = article.content;
+ this._updateImageMargins();
+
+ this._contentElement.style.display = "block";
+
+
+ this._toolbarEnabled = true;
+ this._setToolbarVisibility(true);
+ },
+
+ _hideContent: function Reader_hideContent() {
+ this._headerElement.style.display = "none";
+ this._contentElement.style.display = "none";
+ },
+
+ _showProgress: function Reader_showProgress() {
+ this._headerElement.style.display = "none";
+ this._contentElement.innerHTML = gStrings.GetStringFromName("aboutReader.loading");
+ this._contentElement.style.display = "block";
+ },
+
+ _decodeQueryString: function Reader_decodeQueryString(url) {
+ let result = {};
+ let query = url.split("?")[1];
+ if (query) {
+ let pairs = query.split("&");
+ for (let i = 0; i < pairs.length; i++) {
+ let [name, value] = pairs[i].split("=");
+ result[name] = decodeURIComponent(value);
+ }
+ }
+
+ return result;
+ },
+
+ _setupStepControl: function Reader_setupStepControl(id, name, callback) {
+ let doc = this._doc;
+ let stepControl = doc.getElementById(id);
+
+ while (stepControl.hasChildNodes()) {
+ stepControl.removeChild(stepControl.lastChild);
+ }
+
+ let title = this._doc.createElement("h1");
+ title.innerHTML = name;
+ stepControl.appendChild(title);
+
+ let plusButton = doc.createElement("div");
+ plusButton.className = "button plus-button";
+ stepControl.appendChild(plusButton);
+
+ let minusButton = doc.createElement("div");
+ minusButton.className = "button minus-button";
+ stepControl.appendChild(minusButton);
+
+ plusButton.addEventListener("click", function(aEvent) {
+ if (!aEvent.isTrusted)
+ return;
+
+ aEvent.stopPropagation();
+ callback(this._STEP_INCREMENT);
+ }.bind(this), true);
+
+ minusButton.addEventListener("click", function(aEvent) {
+ if (!aEvent.isTrusted)
+ return;
+
+ aEvent.stopPropagation();
+ callback(this._STEP_DECREMENT);
+ }.bind(this), true);
+ },
+
+ _setupSegmentedButton: function Reader_setupSegmentedButton(id, options, initialValue, callback) {
+ let doc = this._doc;
+ let segmentedButton = doc.getElementById(id);
+
+ if (segmentedButton != null) {
+ while (segmentedButton.hasChildNodes()) {
+ if (segmentedButton.lastChild.tagName == "LI") {
+ segmentedButton.removeChild(segmentedButton.lastChild);
+ }
+ }
+ }
+ for (let i = 0; i < options.length; i++) {
+ let option = options[i];
+
+ let item = doc.createElement("li");
+ let link = doc.createElement("a");
+ link.innerHTML = option.name;
+ item.appendChild(link);
+
+ segmentedButton.appendChild(item);
+
+ link.addEventListener("click", function(aEvent) {
+ if (!aEvent.isTrusted)
+ return;
+
+ aEvent.stopPropagation();
+
+ let items = segmentedButton.children;
+ for (let j = items.length - 1; j >= 0; j--) {
+ items[j].classList.remove("selected");
+ }
+
+ item.classList.add("selected");
+ callback(option.value);
+ }.bind(this), true);
+
+ if (option.value === initialValue)
+ item.classList.add("selected");
+ }
+ },
+
+ _setupButton: function Reader_setupButton(id, callback) {
+ let button = this._doc.getElementById(id);
+
+ button.addEventListener("click", function(aEvent) {
+ if (!aEvent.isTrusted)
+ return;
+
+ aEvent.stopPropagation();
+ callback();
+ }, true);
+ },
+
+ _setupAllDropdowns: function Reader_setupAllDropdowns() {
+ let doc = this._doc;
+ let win = this._win;
+
+ let dropdowns = doc.getElementsByClassName("dropdown");
+
+ for (let i = dropdowns.length - 1; i >= 0; i--) {
+ let dropdown = dropdowns[i];
+
+ let dropdownToggle = dropdown.getElementsByClassName("dropdown-toggle")[0];
+ let dropdownPopup = dropdown.getElementsByClassName("dropdown-popup")[0];
+
+ if (!dropdownToggle || !dropdownPopup)
+ continue;
+
+ for (var j = 0; j < dropdownPopup.childNodes.length; j++) {
+ if (dropdownPopup.childNodes[j].className == "dropdown-arrow") {
+ dropdownPopup.removeChild(dropdownPopup.childNodes[j]);
+ }
+ }
+
+ let dropdownArrow = doc.createElement("div");
+ dropdownArrow.className = "dropdown-arrow";
+ dropdownPopup.appendChild(dropdownArrow);
+
+ let updatePopupPosition = function() {
+ let popupWidth = dropdownPopup.offsetWidth + 30;
+ let arrowWidth = dropdownArrow.offsetWidth;
+ let toggleWidth = dropdownToggle.offsetWidth;
+ let toggleLeft = dropdownToggle.offsetLeft;
+
+ let popupShift = (toggleWidth - popupWidth) / 2;
+ let popupLeft = Math.max(0, Math.min(win.innerWidth - popupWidth, toggleLeft + popupShift));
+ dropdownPopup.style.left = popupLeft + "px";
+
+ let arrowShift = (toggleWidth - arrowWidth) / 2;
+ let arrowLeft = toggleLeft - popupLeft + arrowShift;
+ dropdownArrow.style.left = arrowLeft + "px";
+ };
+
+ win.addEventListener("resize", function(aEvent) {
+ if (!aEvent.isTrusted)
+ return;
+
+ updatePopupPosition();
+ }, true);
+
+ dropdownToggle.addEventListener("click", function(aEvent) {
+ if (!aEvent.isTrusted)
+ return;
+
+ aEvent.stopPropagation();
+
+ let dropdownClasses = dropdown.classList;
+
+ if (dropdownClasses.contains("open")) {
+ win.history.back();
+ } else {
+ updatePopupPosition();
+ if (!this._closeAllDropdowns())
+ this._pushDropdownState();
+
+ dropdownClasses.add("open");
+ }
+ }.bind(this), true);
+ }
+ },
+
+ _pushDropdownState: function Reader_pushDropdownState() {
+ // FIXME: We're getting a NS_ERROR_UNEXPECTED error when we try
+ // to do win.history.pushState() here (see bug 682296). This is
+ // a workaround that allows us to push history state on the target
+ // content document.
+
+ let doc = this._doc;
+ let body = doc.body;
+
+ if (this._pushStateScript)
+ body.removeChild(this._pushStateScript);
+
+ for (var j = 0; j < body.childNodes.length; j++) {
+ if (body.childNodes[j].type == "text/javascript") {
+ body.removeChild(body.childNodes[j]);
+ }
+ }
+
+ this._pushStateScript = doc.createElement('script');
+ this._pushStateScript.type = "text/javascript";
+ this._pushStateScript.innerHTML = 'history.pushState({ dropdown: 1 }, document.title);';
+
+ body.appendChild(this._pushStateScript);
+ },
+
+ _closeAllDropdowns : function Reader_closeAllDropdowns() {
+ let dropdowns = this._doc.querySelectorAll(".dropdown.open");
+ for (let i = dropdowns.length - 1; i >= 0; i--) {
+ dropdowns[i].classList.remove("open");
+ }
+
+ return (dropdowns.length > 0)
+ }
+};
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -38,17 +38,24 @@ var gEditUIVisible = true;
delete window[name];
return window[name] = element;
});
window.__defineSetter__(name, function (val) {
delete window[name];
return window[name] = val;
});
});
-
+
+let readerName = "AboutReader", readerScript = "chrome://browser/content/aboutReader.js";
+XPCOMUtils.defineLazyGetter(window, readerName, function() {
+ let sandbox = {};
+ Services.scriptloader.loadSubScript(readerScript, sandbox);
+ return sandbox[readerName];
+});
+
// Smart getter for the findbar. If you don't wish to force the creation of
// the findbar, check gFindBarInitialized first.
var gFindBarInitialized = false;
XPCOMUtils.defineLazyGetter(window, "gFindBar", function() {
let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
let findbar = document.createElementNS(XULNS, "findbar");
findbar.id = "FindToolbar";
@@ -149,17 +156,18 @@ XPCOMUtils.defineLazyModuleGetter(this,
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
let gInitialPages = [
"about:blank",
"about:newtab",
"about:home",
"about:privatebrowsing",
- "about:sessionrestore"
+ "about:sessionrestore",
+ "about:reader"
];
#include browser-addons.js
#include browser-feeds.js
#include browser-fullScreen.js
#include browser-fullZoom.js
#include browser-places.js
#include browser-plugins.js
@@ -206,24 +214,27 @@ XPCOMUtils.defineLazyGetter(this, "PageM
return new tmp.PageMenu();
});
/**
* We can avoid adding multiple load event listeners and save some time by adding
* one listener that calls all real handlers.
*/
function pageShowEventHandlers(event) {
- charsetLoadListener();
- XULBrowserWindow.asyncUpdateUI();
-
- // The PluginClickToPlay events are not fired when navigating using the
- // BF cache. |event.persisted| is true when the page is loaded from the
- // BF cache, so this code reshows the notification if necessary.
- if (event.persisted)
- gPluginHandler.reshowClickToPlayNotification();
+ charsetLoadListener();
+ XULBrowserWindow.asyncUpdateUI();
+
+ // The PluginClickToPlay events are not fired when navigating using the
+ // BF cache. |event.persisted| is true when the page is loaded from the
+ // BF cache, so this code reshows the notification if necessary.
+ if (event.persisted) {
+ gPluginHandler.reshowClickToPlayNotification();
+ }
+
+ ReaderMode.PageShowHandler();
}
function UpdateBackForwardCommands(aWebNavigation) {
var backBroadcaster = document.getElementById("Browser:Back");
var forwardBroadcaster = document.getElementById("Browser:Forward");
// Avoid setting attributes on broadcasters if the value hasn't changed!
// Remember, guys, setting attributes on elements is expensive! They
@@ -1175,16 +1186,18 @@ var gBrowserInit = {
goSetCommandEnabled("cmd_newNavigatorTab", false);
}
#ifdef MENUBAR_CAN_AUTOHIDE
updateAppButtonDisplay();
#endif
// Misc. inits.
+ ReaderMode.init();
+ Reader.init();
CombinedStopReload.init();
allTabs.readPref();
TabsOnTop.init();
BookmarksMenuButton.init();
TabsInTitlebar.init();
gPrivateBrowsingUI.init();
retrieveToolbarIconsizesFromTheme();
@@ -1261,24 +1274,26 @@ var gBrowserInit = {
Services.obs.addObserver(gFormSubmitObserver, "invalidformsubmit", false);
BrowserOffline.init();
OfflineApps.init();
IndexedDBPromptHelper.init();
gFormSubmitObserver.init();
SocialUI.init();
AddonManager.addAddonListener(AddonsMgrListener);
-
+
gBrowser.addEventListener("pageshow", function(event) {
- // Filter out events that are not about the document load we are interested in
- if (event.target == content.document)
- setTimeout(pageShowEventHandlers, 0, event);
- }, true);
-
- // Ensure login manager is up and running.
+ // Filter out events that are not about the document load we are interested in
+ if (event.target == content.document)
+ setTimeout(pageShowEventHandlers, 0, event);
+ }, true);
+
+ gBrowser.tabContainer.addEventListener("TabSelect", function(evt) { setTimeout(ReaderMode.TabSwitchHandler, 0, evt); }, true);
+
+ // Ensure login manager is up and running.
Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
if (mustLoadSidebar) {
let sidebar = document.getElementById("sidebar");
let sidebarBox = document.getElementById("sidebar-box");
sidebar.setAttribute("src", sidebarBox.getAttribute("src"));
}
@@ -5652,16 +5667,83 @@ var stylesheetFillPopup = gPageStyleMenu
function stylesheetSwitchAll(contentWindow, title) {
gPageStyleMenu.switchStyleSheet(title, contentWindow);
}
function setStyleDisabled(disabled) {
if (disabled)
gPageStyleMenu.disableStyle();
}
+var savedArticle = null;
+
+var ReaderMode = {
+
+ ////////////////////////////
+ // ReaderMode Public Methods
+ init: function ()
+ {
+ //Reader Button disable/enable
+ document.getElementById("reader-button").hidden = true;//!gPrefService.getBoolPref("reader.enabled");
+ },
+
+ //Reader Mode On-Click
+ BrowserOpenReaderMode: function(aEvent) {
+ document.getElementById("reader-button").hidden = true;
+ openUILink("about:reader?url=" + gBrowser.currentURI.specIgnoringRef, {target:gBrowser.selectedTab});
+ ReaderMode.selectedReaderTab.addEventListener("DOMContentLoaded", ReaderMode.handleDomContentLoaded, true);
+ },
+
+ PageShowHandler: function() {
+ ReaderMode.checkReaderMode();
+ ReaderMode.readerButton.hidden = (savedArticle == null);
+ },
+
+ TabSwitchHandler: function(event) {
+ ReaderMode.checkReaderMode();
+ ReaderMode.readerButton.hidden = (savedArticle == null);
+ },
+
+ handleDomContentLoaded: function(event) {
+ if(/^about:reader/.test(ReaderMode.selectedReaderTab.currentURI.specIgnoringRef)) {
+ new AboutReader(ReaderMode.selectedReaderTab.contentDocument, ReaderMode.selectedReaderTab.contentWindow);
+ ReaderMode.selectedReaderTab.removeEventListener("DOMContentLoaded", ReaderMode.handleDomContentLoaded, true);
+ }
+ },
+
+ checkReaderMode: function() {
+ savedArticle = null;
+ if (gPrefService.getBoolPref("reader.enabled")) {
+
+ Reader.parseDocumentFromTab(gBrowser.selectedTab, function (article) {
+ // Do nothing if there's no article or the page in this tab has
+ // changed
+ let tabURL = gBrowser.currentURI.specIgnoringRef;
+ if (article == null || (article.url != tabURL)) {
+ // Don't clear the article for about:reader pages since we want to
+ // use the article from the previous page
+ if (tabURL.startsWith("about:reader"))
+ savedArticle = null;
+
+ return;
+ }
+ savedArticle = article;
+ ReaderMode.readerButton.hidden = (savedArticle == null);
+ }.bind(this));
+ }
+ },
+
+ get readerButton () {
+ return document.getElementById("reader-button");
+ },
+
+ get selectedReaderTab () {
+ return gBrowser.getBrowserForTab(gBrowser.selectedTab);
+ },
+
+};
var BrowserOffline = {
_inited: false,
/////////////////////////////////////////////////////////////////////////////
// BrowserOffline Public Methods
init: function ()
{
@@ -7652,8 +7734,436 @@ var MousePosTracker = {
function focusNextFrame(event) {
let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
let dir = event.shiftKey ? fm.MOVEFOCUS_BACKWARDDOC : fm.MOVEFOCUS_FORWARDDOC;
let element = fm.moveFocus(window, null, dir, fm.FLAG_BYKEY);
if (element.ownerDocument == document)
focusAndSelectUrlBar();
}
+
+
+let Reader = {
+ // Version of the cache database schema
+DB_VERSION: 1,
+
+DEBUG: 1,
+
+ // Don't try to parse the page if it has too many elements (for memory and
+ // performance reasons)
+MAX_ELEMS_TO_PARSE: 3000,
+
+init: function Reader_init() {
+ this.log("Init()");
+ this._requests = {};
+
+ Services.obs.addObserver(this, "Reader:Add", false);
+ Services.obs.addObserver(this, "Reader:Remove", false);
+},
+
+observe: function(aMessage, aTopic, aData) {
+ switch(aTopic) {
+ case "Reader:Add": {
+ //let tab = gBrowser.selectedTab;
+ let currentURI = gBrowser.currentURI;
+ let url = currentURI.spec;
+
+ let sendResult = function(success, title) {
+ this.log("Reader:Add success=" + success + ", url=" + url + ", title=" + title);
+ }.bind(this);
+
+ this.getArticleForTab(aData, currentURI.specIgnoringRef, function (article) {
+ if (!article) {
+ sendResult(false, "");
+ return;
+ }
+
+ this.storeArticleInCache(article, function(success) {
+ sendResult(success, article.title);
+ });
+ }.bind(this));
+ break;
+ }
+
+ case "Reader:Remove": {
+ this.removeArticleFromCache(aData, function(success) {
+ this.log("Reader:Remove success=" + success + ", url=" + aData);
+ }.bind(this));
+ break;
+ }
+ }
+},
+
+parseDocumentFromURL: function Reader_parseDocumentFromURL(url, callback) {
+ // If there's an on-going request for the same URL, simply append one
+ // more callback to it to be called when the request is done.
+ if (url in this._requests) {
+ let request = this._requests[url];
+ request.callbacks.push(callback);
+ return;
+ }
+
+ let request = { url: url, callbacks: [callback] };
+ this._requests[url] = request;
+
+ try {
+ this.log("parseDocumentFromURL: " + url);
+
+ // First, try to find a cached parsed article in the DB
+ this.getArticleFromCache(url, function(article) {
+ if (article) {
+ //this.log("Page found in cache, return article immediately");
+ this._runCallbacksAndFinish(request, article);
+ return;
+ }
+
+ if (!this._requests) {
+ this.log("Reader has been destroyed, abort");
+ return;
+ }
+
+ // Article hasn't been found in the cache DB, we need to
+ // download the page and parse the article out of it.
+ this._downloadAndParseDocument(url, request);
+ }.bind(this));
+ } catch (e) {
+ this.log("Error parsing document from URL: " + e);
+ this._runCallbacksAndFinish(request, null);
+ }
+},
+
+getArticleForTab: function Reader_getArticleForTab(tabId, url, callback) {
+ var article;
+ try {
+ article = savedArticle;
+ }
+ catch (e) {}
+ if (article && article.url == url) {
+ this.log("Saved article found in tab");
+ callback(article);
+ } else {
+ this.parseDocumentFromURL(url, callback);
+ }
+},
+
+parseDocumentFromTab: function(tabId, callback) {
+ try {
+ this.log("parseDocumentFromTab: " + tabId);
+
+ //let tab = gBrowser.getTabForId(tabId);
+ let url = gBrowser.contentWindow.location.href;
+ let uri = Services.io.newURI(url, null, null);
+
+ if (!this._shouldCheckUri(uri)) {
+ callback(null);
+ return;
+ }
+
+ // First, try to find a cached parsed article in the DB
+ this.getArticleFromCache(url, function(article) {
+ if (article) {
+ this.log("Page found in cache, return article immediately");
+ callback(article);
+ return;
+ }
+
+ let doc = gBrowser.contentWindow.document;
+ this._readerParse(uri, doc, function (article) {
+ if (!article) {
+ this.log("Failed to parse page");
+ callback(null);
+ return;
+ }
+ callback(article);
+ }.bind(this));
+ }.bind(this));
+ } catch (e) {
+ this.log("Error parsing document from tab: " + e);
+ callback(null);
+ }
+},
+
+getArticleFromCache: function Reader_getArticleFromCache(url, callback) {
+ this._getCacheDB(function(cacheDB) {
+ if (!cacheDB) {
+ callback(false);
+ return;
+ }
+ let transaction = cacheDB.transaction(cacheDB.objectStoreNames);
+ let articles = transaction.objectStore(cacheDB.objectStoreNames[0]);
+
+ let request = articles.get(url);
+
+ request.onerror = function(event) {
+ this.log("Error getting article from the cache DB: " + url);
+ callback(null);
+ }.bind(this);
+
+ request.onsuccess = function(event) {
+ this.log("Got article from the cache DB! ");
+ callback(event.target.result);
+ }.bind(this);
+ }.bind(this));
+},
+
+storeArticleInCache: function Reader_storeArticleInCache(article, callback) {
+ this._getCacheDB(function(cacheDB) {
+ if (!cacheDB) {
+ callback(false);
+ return;
+ }
+
+ let transaction = cacheDB.transaction(cacheDB.objectStoreNames, "readwrite");
+ let articles = transaction.objectStore(cacheDB.objectStoreNames[0]);
+
+ let request = articles.add(article);
+
+ request.onerror = function(event) {
+ this.log("Error storing article in the cache DB: " + article.url);
+ callback(false);
+ }.bind(this);
+
+ request.onsuccess = function(event) {
+ //this.log("Stored article in the cache DB: " + article.url);
+ callback(true);
+ }.bind(this);
+ }.bind(this));
+},
+
+removeArticleFromCache: function Reader_removeArticleFromCache(url, callback) {
+ this._getCacheDB(function(cacheDB) {
+ if (!cacheDB) {
+ callback(false);
+ return;
+ }
+
+ let transaction = cacheDB.transaction(cacheDB.objectStoreNames, "readwrite");
+ let articles = transaction.objectStore(cacheDB.objectStoreNames[0]);
+
+ let request = articles.delete(url);
+
+ request.onerror = function(event) {
+ this.log("Error removing article from the cache DB: " + url);
+ callback(false);
+ }.bind(this);
+
+ request.onsuccess = function(event) {
+ this.log("Removed article from the cache DB: " + url);
+ callback(true);
+ }.bind(this);
+ }.bind(this));
+},
+
+uninit: function Reader_uninit() {
+ Services.obs.removeObserver(this, "Reader:Add", false);
+ Services.obs.removeObserver(this, "Reader:Remove", false);
+
+ let requests = this._requests;
+ for (let url in requests) {
+ let request = requests[url];
+ if (request.browser) {
+ let browser = request.browser;
+ browser.parentNode.removeChild(browser);
+ }
+ }
+ delete this._requests;
+
+ if (this._cacheDB) {
+ this._cacheDB.close();
+ delete this._cacheDB;
+ }
+},
+
+log: function(msg) {
+ if (this.DEBUG)
+ dump("Reader: " + msg);
+},
+
+_shouldCheckUri: function Reader_shouldCheckUri(uri) {
+ if ((uri.prePath + "/") === uri.spec) {
+ //this.log("Not parsing home page: " + uri.spec);
+ return false;
+ }
+
+ if (!(uri.schemeIs("http") || uri.schemeIs("https") || uri.schemeIs("file"))) {
+ //this.log("Not parsing URI scheme: " + uri.scheme);
+ return false;
+ }
+
+ return true;
+},
+
+_readerParse: function Reader_readerParse(uri, doc, callback) {
+ let numTags = doc.getElementsByTagName("*").length;
+ if (numTags > this.MAX_ELEMS_TO_PARSE) {
+ //this.log("Aborting parse for " + uri.spec + "; " + numTags + " elements found");
+ callback(null);
+ return;
+ }
+
+ let worker = new ChromeWorker("resource://gre/modules/readerWorker.jsm");
+ worker.onmessage = function (evt) {
+ let article = evt.data;
+
+ // Append URL to the article data. specIgnoringRef will ignore any hash
+ // in the URL.
+ if (article)
+ article.url = uri.specIgnoringRef;
+
+ callback(article);
+ };
+
+ try {
+ worker.postMessage({
+ uri: {
+ spec: uri.spec,
+ host: uri.host,
+ prePath: uri.prePath,
+ scheme: uri.scheme,
+ pathBase: Services.io.newURI(".", null, uri).spec
+ },
+ doc: new XMLSerializer().serializeToString(doc)
+ });
+ } catch (e) {
+ this.log("Reader: could not build Readability arguments: " + e);
+ callback(null);
+ }
+},
+
+_runCallbacksAndFinish: function Reader_runCallbacksAndFinish(request, result) {
+ delete this._requests[request.url];
+
+ request.callbacks.forEach(function(callback) {
+ callback(result);
+ });
+},
+
+_downloadDocument: function Reader_downloadDocument(url, callback) {
+ // We want to parse those arbitrary pages safely, outside the privileged
+ // context of chrome. We create a hidden browser element to fetch the
+ // loaded page's document object then discard the browser element.
+
+ let browser = document.createElement("browser");
+ browser.setAttribute("type", "content");
+ browser.setAttribute("collapsed", "true");
+
+ document.documentElement.appendChild(browser);
+ browser.stop();
+
+ browser.webNavigation.allowAuth = false;
+ browser.webNavigation.allowImages = false;
+ browser.webNavigation.allowJavascript = false;
+ browser.webNavigation.allowMetaRedirects = true;
+ browser.webNavigation.allowPlugins = false;
+
+ browser.addEventListener("DOMContentLoaded", function (event) {
+ let doc = event.originalTarget;
+
+ // ignore on frames and other documents
+ if (doc != browser.contentDocument)
+ return;
+
+ this.log("Done loading: " + doc);
+ if (doc.location.href == "about:blank") {
+ callback(null);
+
+ // Request has finished with error, remove browser element
+ browser.parentNode.removeChild(browser);
+ return;
+ }
+
+ callback(doc);
+ }.bind(this));
+
+ browser.loadURIWithFlags(url, Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
+ null, null, null);
+
+ return browser;
+},
+
+_downloadAndParseDocument: function Reader_downloadAndParseDocument(url, request) {
+ try {
+ this.log("Needs to fetch page, creating request: " + url);
+
+ request.browser = this._downloadDocument(url, function(doc) {
+ this.log("Finished loading page: " + doc);
+
+ if (!doc) {
+ this.log("Error loading page");
+ this._runCallbacksAndFinish(request, null);
+ return;
+ }
+
+ this.log("Parsing response with Readability");
+
+ let uri = Services.io.newURI(url, null, null);
+ this._readerParse(uri, doc, function (article) {
+ // Delete reference to the browser element as we've finished parsing.
+ let browser = request.browser;
+ if (browser) {
+ browser.parentNode.removeChild(browser);
+ delete request.browser;
+ }
+
+ if (!article) {
+ this.log("Failed to parse page");
+ this._runCallbacksAndFinish(request, null);
+ return;
+ }
+
+ this.log("Parsing has been successful");
+
+ this._runCallbacksAndFinish(request, article);
+ }.bind(this));
+ }.bind(this));
+ } catch (e) {
+ this.log("Error downloading and parsing document: " + e);
+ this._runCallbacksAndFinish(request, null);
+ }
+},
+
+_getCacheDB: function Reader_getCacheDB(callback) {
+ if (this._cacheDB) {
+ callback(this._cacheDB);
+ return;
+ }
+
+ // Throws a silent error, and does not call the onerror callback. request object itself becomes null.
+ let request = window.indexedDB.open("about:reader", this.DB_VERSION);
+
+ if (!request){
+ this.log("Error connecting to the cache DB\n");
+ this._cacheDB = null;
+ callback(null);
+ return;
+ }
+
+ request.onerror = function(event) {
+ //this.log("Error connecting to the cache DB");
+ this._cacheDB = null;
+ callback(null);
+
+
+ }.bind(this);
+
+ request.onsuccess = function(event) {
+ //this.log("Successfully connected to the cache DB");
+ this._cacheDB = event.target.result;
+ callback(this._cacheDB);
+ }.bind(this);
+
+ request.onupgradeneeded = function(event) {
+ this.log("Database schema upgrade from " +
+ event.oldVersion + " to " + event.newVersion);
+
+ let cacheDB = event.target.result;
+
+ // Create the articles object store
+ this.log("Creating articles object store");
+ cacheDB.createObjectStore("articles", { keyPath: "url" });
+
+ this.log("Database upgrade done: " + this.DB_VERSION);
+ }.bind(this);
+}
+};
+
+
+
diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -601,17 +601,19 @@
tooltiptext="&pageReportIcon.tooltip;"
onclick="gPopupBlockerObserver.onReportButtonClick(event);"/>
-
+
diff --git a/browser/base/jar.mn b/browser/base/jar.mn
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -14,16 +14,18 @@ browser.jar:
% overlay chrome://global/content/viewSource.xul chrome://browser/content/viewSourceOverlay.xul
% overlay chrome://global/content/viewPartialSource.xul chrome://browser/content/viewSourceOverlay.xul
% style chrome://global/content/customizeToolbar.xul chrome://browser/content/browser.css
% style chrome://global/content/customizeToolbar.xul chrome://browser/skin/
* content/browser/aboutDialog.xul (content/aboutDialog.xul)
* content/browser/aboutDialog.js (content/aboutDialog.js)
content/browser/aboutDialog.css (content/aboutDialog.css)
content/browser/aboutRobots.xhtml (content/aboutRobots.xhtml)
+ content/browser/aboutReader.html (content/aboutReader.html)
+ content/browser/aboutReader.js (content/aboutReader.js)
content/browser/abouthome/aboutHome.xhtml (content/abouthome/aboutHome.xhtml)
* content/browser/abouthome/aboutHome.js (content/abouthome/aboutHome.js)
* content/browser/abouthome/aboutHome.css (content/abouthome/aboutHome.css)
content/browser/abouthome/noise.png (content/abouthome/noise.png)
content/browser/abouthome/snippet1.png (content/abouthome/snippet1.png)
content/browser/abouthome/snippet2.png (content/abouthome/snippet2.png)
content/browser/abouthome/downloads.png (content/abouthome/downloads.png)
content/browser/abouthome/bookmarks.png (content/abouthome/bookmarks.png)
diff --git a/browser/components/about/AboutRedirector.cpp b/browser/components/about/AboutRedirector.cpp
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -75,16 +75,19 @@ static RedirEntry kRedirMap[] = {
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
nsIAboutModule::ALLOW_SCRIPT },
{ "newtab", "chrome://browser/content/newtab/newTab.xul",
nsIAboutModule::ALLOW_SCRIPT },
{ "permissions", "chrome://browser/content/preferences/aboutPermissions.xul",
nsIAboutModule::ALLOW_SCRIPT },
{ "preferences", "chrome://browser/content/preferences/in-content/preferences.xul",
nsIAboutModule::ALLOW_SCRIPT },
+ { "reader", "chrome://browser/content/aboutReader.html",
+ nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
+ nsIAboutModule::ALLOW_SCRIPT },
};
static const int kRedirTotal = NS_ARRAY_LENGTH(kRedirMap);
static nsAutoCString
GetAboutModuleName(nsIURI *aURI)
{
nsAutoCString path;
aURI->GetPath(path);
diff --git a/browser/components/build/nsModule.cpp b/browser/components/build/nsModule.cpp
--- a/browser/components/build/nsModule.cpp
+++ b/browser/components/build/nsModule.cpp
@@ -103,16 +103,17 @@ static const mozilla::Module::ContractID
#ifdef MOZ_SERVICES_SYNC
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "sync-tabs", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "sync-progress", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
#endif
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "home", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "newtab", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "permissions", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "preferences", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
+ { NS_ABOUT_MODULE_CONTRACTID_PREFIX "reader", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
#if defined(XP_WIN)
{ NS_IEHISTORYENUMERATOR_CONTRACTID, &kNS_WINIEHISTORYENUMERATOR_CID },
#elif defined(XP_MACOSX)
{ NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
#endif
{ NS_PRIVATE_BROWSING_SERVICE_CONTRACTID, &kNS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID },
{ NULL }
};
diff --git a/mobile/android/locales/en-US/chrome/aboutReader.properties b/browser/locales/en-US/chrome/browser/aboutReader.properties
copy from mobile/android/locales/en-US/chrome/aboutReader.properties
copy to browser/locales/en-US/chrome/browser/aboutReader.properties
diff --git a/browser/locales/jar.mn b/browser/locales/jar.mn
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -4,16 +4,17 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@AB_CD@.jar:
% locale browser @AB_CD@ %locale/browser/
locale/browser/aboutCertError.dtd (%chrome/browser/aboutCertError.dtd)
locale/browser/aboutDialog.dtd (%chrome/browser/aboutDialog.dtd)
locale/browser/aboutPrivateBrowsing.dtd (%chrome/browser/aboutPrivateBrowsing.dtd)
+ locale/browser/aboutReader.properties (%chrome/browser/aboutReader.properties)
locale/browser/aboutRobots.dtd (%chrome/browser/aboutRobots.dtd)
locale/browser/aboutHome.dtd (%chrome/browser/aboutHome.dtd)
locale/browser/aboutSessionRestore.dtd (%chrome/browser/aboutSessionRestore.dtd)
#ifdef MOZ_SERVICES_SYNC
locale/browser/syncProgress.dtd (%chrome/browser/syncProgress.dtd)
locale/browser/aboutSyncTabs.dtd (%chrome/browser/aboutSyncTabs.dtd)
#endif
locale/browser/browser.dtd (%chrome/browser/browser.dtd)
diff --git a/browser/themes/gnomestripe/browser.css b/browser/themes/gnomestripe/browser.css
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -1425,16 +1425,21 @@ richlistitem[type~="action"][actiontype=
#star-button {
list-style-image: url("chrome://browser/skin/places/starPage.png");
}
#star-button[starred="true"] {
list-style-image: url("chrome://browser/skin/places/pageStarred.png");
}
+/* Reader Button */
+#reader-button {
+ list-style-image: url("chrome://browser/skin/places/reader.png");
+}
+
/* Bookmarking panel */
#editBookmarkPanelStarIcon {
list-style-image: url("chrome://browser/skin/places/starred48.png");
width: 48px;
height: 48px;
}
#editBookmarkPanelStarIcon[unstarred] {
diff --git a/browser/themes/gnomestripe/jar.mn b/browser/themes/gnomestripe/jar.mn
--- a/browser/themes/gnomestripe/jar.mn
+++ b/browser/themes/gnomestripe/jar.mn
@@ -70,16 +70,23 @@ browser.jar:
skin/classic/browser/places/pageStarred.png (places/pageStarred.png)
skin/classic/browser/places/starred48.png (places/starred48.png)
skin/classic/browser/places/unstarred48.png (places/unstarred48.png)
skin/classic/browser/places/places.css (places/places.css)
skin/classic/browser/places/organizer.css (places/organizer.css)
skin/classic/browser/places/organizer.xml (places/organizer.xml)
skin/classic/browser/places/query.png (places/query.png)
skin/classic/browser/places/starPage.png (places/starPage.png)
+ skin/classic/browser/places/reader.png (places/reader.png)
+ skin/classic/browser/places/readerDropdownArrow@2x.png (places/readerDropdownArrow@2x.png)
+ skin/classic/browser/places/readerMinusIcon@2x.png (places/readerMinusIcon@2x.png)
+ skin/classic/browser/places/readerPlusIcon@2x.png (places/readerPlusIcon@2x.png)
+ skin/classic/browser/places/readerStyleIcon@2x.png (places/readerStyleIcon@2x.png)
+ skin/classic/browser/places/readerToolbarBg@2x.png (places/readerToolbarBg@2x.png)
+ skin/classic/browser/places/aboutReader.css (places/aboutReader.css)
skin/classic/browser/places/tag.png (places/tag.png)
skin/classic/browser/places/toolbarDropMarker.png (places/toolbarDropMarker.png)
skin/classic/browser/places/unsortedBookmarks.png (places/unsortedBookmarks.png)
skin/classic/browser/places/downloads.png (places/downloads.png)
skin/classic/browser/preferences/alwaysAsk.png (preferences/alwaysAsk.png)
skin/classic/browser/preferences/mail.png (preferences/mail.png)
skin/classic/browser/preferences/Options.png (preferences/Options.png)
#ifdef MOZ_SERVICES_SYNC
diff --git a/mobile/android/themes/core/aboutReader.css b/browser/themes/gnomestripe/places/aboutReader.css
copy from mobile/android/themes/core/aboutReader.css
copy to browser/themes/gnomestripe/places/aboutReader.css
--- a/mobile/android/themes/core/aboutReader.css
+++ b/browser/themes/gnomestripe/places/aboutReader.css
@@ -2,17 +2,17 @@
* 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/. */
html {
-moz-text-size-adjust: none;
}
body {
- font-family: "OpenSansRegular","Droid Sans",sans-serif;
+ font-family: sans-serif;
margin-top: 20px;
margin-bottom: 20px;
}
.light {
background-color: #ffffff;
color: #222222;
}
@@ -37,17 +37,17 @@ body {
.header > .domain {
margin-top: 10px;
padding-bottom: 10px;
border-bottom: 2px solid;
}
.header > h1 {
- font-family: "OpenSansLight","Droid Sans",sans-serif;
+ font-family: sans-serif;
font-weight: normal;
line-height: 1.1em;
width: 100%;
margin: 0px;
margin-top: 32px;
margin-bottom: 16px;
padding: 0px;
}
@@ -316,42 +316,41 @@ body {
font-size: 20px !important;
}
.font-size7 > .content {
font-size: 22px !important;
}
.toolbar {
- font-family: "Droid Sans",helvetica,arial,clean,sans-serif;
- -moz-transition-property: visibility, opacity;
- -moz-transition-duration: 0.7s;
- visibility: visible;
- opacity: 1.0;
- position: fixed;
- width: 100%;
- bottom: 0px;
- left: 0px;
- margin: 0;
- padding: 0;
- list-style: none;
- background-repeat: repeat;
+ font-family: helvetica,arial,clean,sans-serif;
+ visibility: visible;
+ opacity: 1.0;
+ position: fixed;
+ width: 3%;
+ height: 45px;
+ bottom: 0px;
+ margin: 0;
+ padding: 10px 4px 0 24px;
+ list-style: none;
+ background-repeat: repeat;
+ left: 1%;
}
.toolbar-hidden {
-moz-transition-property: visibility, opacity;
-moz-transition-duration: 0.7s;
visibility: hidden;
opacity: 0.0;
}
-.toolbar > * {
+/*.toolbar > * {
float: right;
- width: 25%;
-}
+ width: 5%;
+}*/
.button {
color: white;
display: block;
background-position: center;
background-repeat: no-repeat;
}
@@ -359,43 +358,44 @@ body {
background-color: #ff9500;
}
.dropdown {
text-align: center;
display: inline-block;
list-style: none;
margin: 0px;
+ margin-left: -15px;
padding: 0px;
}
.dropdown li {
margin: 0px;
padding: 0px;
}
.dropdown-toggle {
margin: 0px;
padding: 0px;
}
.dropdown-popup {
text-align: left;
position: absolute;
- left: 0px;
z-index: 1000;
float: left;
background: #dde2e7;
margin-top: 12px;
margin-bottom: 10px;
padding-top: 4px;
padding-bottom: 8px;
font-size: 14px;
box-shadow: 0px -1px 12px #333;
visibility: hidden;
+ width: 225px;
}
.dropdown-popup > hr {
width: 100%;
height: 0px;
border: 0px;
border-top: 1px solid #ccc;
border-bottom: 1px solid white;
@@ -411,21 +411,21 @@ body {
margin-top: 0px;
margin-bottom: 6px;
bottom: 100%;
visibility: visible;
}
.dropdown-arrow {
position: absolute;
- width: 40px;
- height: 18px;
+ width: 60px;
+ height: 24px;
bottom: -18px;
- background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-mdpi.png');
- background-size: 40px 18px;
+ background-image: url('chrome://browser/skin/places/readerDropdownArrow@2x.png');
+ background-size: 60px 24px;
background-position: center;
display: block;
}
.segmented-button {
list-style: none;
margin: 0;
padding: 5px;
@@ -477,301 +477,32 @@ body {
float: right;
text-align: center;
width: 56px;
height: 43px;
background-size: 20px;
}
.step-control > .plus-button {
- background-image: url('chrome://browser/skin/images/reader-plus-icon-mdpi.png');
+ background-image: url('chrome://browser/skin/places/readerPlusIcon@2x.png');
border-left: 1px solid #ccc;
margin-right: 4px;
+ width: 30px;
+ height: 30px;
}
.step-control > .minus-button {
- background-image: url('chrome://browser/skin/images/reader-minus-icon-mdpi.png');
+ background-image: url('chrome://browser/skin/places/readerMinusIcon@2x.png');
+ width: 30px;
+ height: 30px;
}
-@media screen and (orientation: portrait) {
- .button {
- height: 48px;
- background-size: 30px 24px
- }
-
- .toolbar {
- background-size: 48px;
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-port-mdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-port-mdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-port-mdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-port-mdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-port-mdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-port-mdpi.png');
- }
+.toolbar {
+ background-image: url('chrome://browser/skin/places/readerToolbarBg@2x.png');
}
-@media screen and (orientation: landscape) {
- .button {
- height: 40px;
- background-size: 24px 20px
- }
-
- .toolbar {
- background-size: 40px;
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-land-mdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-land-mdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-land-mdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-land-mdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-land-mdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-land-mdpi.png');
- }
+.style-button {
+ background-image: url('chrome://browser/skin/places/readerStyleIcon@2x.png');
+ width: 45px;
+ height: 36px;
+ left: -10px;
}
-@media screen and (min-width: 960px) {
- .button {
- width: 56px;
- height: 56px;
- background-size: 36px 28px
- }
-
- .toolbar {
- background-size: 56px;
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-xlarge-mdpi.png');
- }
-
- .toolbar > * {
- width: 56px;
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xlarge-mdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xlarge-mdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-xlarge-mdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-xlarge-mdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-xlarge-mdpi.png');
- }
-}
-
-@media screen and (min-resolution: 200dpi) {
- .dropdown-arrow {
- background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-hdpi.png');
- }
-
- .step-control > .plus-button {
- background-image: url('chrome://browser/skin/images/reader-plus-icon-hdpi.png');
- }
-
- .step-control > .minus-button {
- background-image: url('chrome://browser/skin/images/reader-minus-icon-hdpi.png');
- }
-}
-
-@media screen and (min-resolution: 300dpi) {
- .dropdown-arrow {
- background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-xhdpi.png');
- }
-
- .step-control > .plus-button {
- background-image: url('chrome://browser/skin/images/reader-plus-icon-xhdpi.png');
- }
-
- .step-control > .minus-button {
- background-image: url('chrome://browser/skin/images/reader-minus-icon-xhdpi.png');
- }
-}
-
-@media screen and (orientation: portrait) and (min-resolution: 200dpi) {
- .toolbar {
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-port-hdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-port-hdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-port-hdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-port-hdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-port-hdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-port-hdpi.png');
- }
-}
-
-@media screen and (orientation: landscape) and (min-resolution: 200dpi) {
- .toolbar {
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-land-hdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-land-hdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-land-hdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-land-hdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-land-hdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-land-hdpi.png');
- }
-}
-
-@media screen and (orientation: portrait) and (min-resolution: 300dpi) {
- .toolbar {
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-port-xhdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-port-xhdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-port-xhdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-port-xhdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-port-xhdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-port-xhdpi.png');
- }
-}
-
-@media screen and (orientation: landscape) and (min-resolution: 300dpi) {
- .toolbar {
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-land-xhdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-land-xhdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-land-xhdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-land-xhdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-land-xhdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-land-xhdpi.png');
- }
-}
-
-@media screen and (min-width: 960px) and (min-resolution: 200dpi) {
- .toolbar {
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-xlarge-hdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xlarge-hdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xlarge-hdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-xlarge-hdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-xlarge-hdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-xlarge-hdpi.png');
- }
-}
-
-@media screen and (min-width: 960px) and (min-resolution: 300dpi) {
- .toolbar {
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-xlarge-xhdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xlarge-xhdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xlarge-xhdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-xlarge-xhdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-xlarge-xhdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-xlarge-xhdpi.png');
- }
-}
diff --git a/browser/themes/gnomestripe/places/reader.png b/browser/themes/gnomestripe/places/reader.png
new file mode 100644
index 0000000000000000000000000000000000000000..8fc9457f4f280bcbd05af7add0ccc26a18678eb6
GIT binary patch
literal 1306
zc%17D@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z`KN7#X@aTAI0-I+_?7x*9r~xHwz7nYo%-8kt#|
zxH-f0dgc|EB<3Zj!t`b$^qS(;Yvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|FgJ5_GdDAKGBiZ^+||v@(#6RM=oCvA
zC8*vMazafX=oo#pu^El!~gYja^C!P*k>nDoEZ3f
z$;x#xVyjsV4xgW6*Z9g;O-+oE(a|>2vh^nqPfz{(yL;DuczC$Ft^WVNg)58=wCbEEchU{U{`*I;s^PBfrm^1&0&nX
zRcuTCGyOb%vWwXy+@2+<$iu0>f$em#$jOX#)0S6hNqs%o@S|a$>(PFBdkG5*iw&s~
z0n_$={rvoVNrKz&qvy^UN}jmRoMcwQT>tl1=j|r#>H2qAf?mCtHKQ?=b$`QxwmnUc
zm@)zveiDob`Qxgswcr7xQTxOhQoIrm_b7DDk54%E|Nnmp``TYq_`1{*Y--h(OrJPK
vOE_bq^@Lx%CKd7 .domain {
margin-top: 10px;
padding-bottom: 10px;
border-bottom: 2px solid;
}
.header > h1 {
- font-family: "OpenSansLight","Droid Sans",sans-serif;
+ font-family: sans-serif;
font-weight: normal;
line-height: 1.1em;
width: 100%;
margin: 0px;
margin-top: 32px;
margin-bottom: 16px;
padding: 0px;
}
@@ -316,86 +316,81 @@ body {
font-size: 20px !important;
}
.font-size7 > .content {
font-size: 22px !important;
}
.toolbar {
- font-family: "Droid Sans",helvetica,arial,clean,sans-serif;
- -moz-transition-property: visibility, opacity;
- -moz-transition-duration: 0.7s;
- visibility: visible;
- opacity: 1.0;
- position: fixed;
- width: 100%;
- bottom: 0px;
- left: 0px;
- margin: 0;
- padding: 0;
- list-style: none;
- background-repeat: repeat;
+ font-family: helvetica,arial,clean,sans-serif;
+ visibility: visible;
+ opacity: 1.0;
+ position: fixed;
+ width: 36px;
+ height: 45px;
+ bottom: 0px;
+ margin: 0;
+ padding: 10px 4px 0 24px;
+ list-style: none;
+ background-repeat: repeat;
+ left: 1%;
}
.toolbar-hidden {
-moz-transition-property: visibility, opacity;
-moz-transition-duration: 0.7s;
visibility: hidden;
opacity: 0.0;
}
-.toolbar > * {
- float: right;
- width: 25%;
-}
-
.button {
color: white;
display: block;
background-position: center;
background-repeat: no-repeat;
}
.button:active {
background-color: #ff9500;
}
.dropdown {
text-align: center;
display: inline-block;
list-style: none;
margin: 0px;
+ margin-left: -15px;
padding: 0px;
}
.dropdown li {
margin: 0px;
padding: 0px;
}
.dropdown-toggle {
margin: 0px;
padding: 0px;
}
.dropdown-popup {
text-align: left;
position: absolute;
- left: 0px;
z-index: 1000;
float: left;
background: #dde2e7;
margin-top: 12px;
margin-bottom: 10px;
padding-top: 4px;
padding-bottom: 8px;
font-size: 14px;
box-shadow: 0px -1px 12px #333;
visibility: hidden;
+ width: 225px;
}
.dropdown-popup > hr {
width: 100%;
height: 0px;
border: 0px;
border-top: 1px solid #ccc;
border-bottom: 1px solid white;
@@ -411,21 +406,21 @@ body {
margin-top: 0px;
margin-bottom: 6px;
bottom: 100%;
visibility: visible;
}
.dropdown-arrow {
position: absolute;
- width: 40px;
- height: 18px;
+ width: 60px;
+ height: 24px;
bottom: -18px;
- background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-mdpi.png');
- background-size: 40px 18px;
+ background-image: url('chrome://browser/skin/places/readerDropdownArrow@2x.png');
+ background-size: 60px 24px;
background-position: center;
display: block;
}
.segmented-button {
list-style: none;
margin: 0;
padding: 5px;
@@ -477,301 +472,32 @@ body {
float: right;
text-align: center;
width: 56px;
height: 43px;
background-size: 20px;
}
.step-control > .plus-button {
- background-image: url('chrome://browser/skin/images/reader-plus-icon-mdpi.png');
+ background-image: url('chrome://browser/skin/places/readerPlusIcon@2x.png');
border-left: 1px solid #ccc;
margin-right: 4px;
+ width: 30px;
+ height: 30px;
}
.step-control > .minus-button {
- background-image: url('chrome://browser/skin/images/reader-minus-icon-mdpi.png');
+ background-image: url('chrome://browser/skin/places/readerMinusIcon@2x.png');
+ width: 30px;
+ height: 30px;
}
-@media screen and (orientation: portrait) {
- .button {
- height: 48px;
- background-size: 30px 24px
- }
-
- .toolbar {
- background-size: 48px;
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-port-mdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-port-mdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-port-mdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-port-mdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-port-mdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-port-mdpi.png');
- }
+.toolbar {
+ background-image: url('chrome://browser/skin/places/readerToolbarBg@2x.png');
}
-@media screen and (orientation: landscape) {
- .button {
- height: 40px;
- background-size: 24px 20px
- }
-
- .toolbar {
- background-size: 40px;
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-land-mdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-land-mdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-land-mdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-land-mdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-land-mdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-land-mdpi.png');
- }
+.style-button {
+ background-image: url('chrome://browser/skin/places/readerStyleIcon@2x.png');
+ width: 45px;
+ height: 36px;
+ left: -10px;
}
-@media screen and (min-width: 960px) {
- .button {
- width: 56px;
- height: 56px;
- background-size: 36px 28px
- }
-
- .toolbar {
- background-size: 56px;
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-xlarge-mdpi.png');
- }
-
- .toolbar > * {
- width: 56px;
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xlarge-mdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xlarge-mdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-xlarge-mdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-xlarge-mdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-xlarge-mdpi.png');
- }
-}
-
-@media screen and (min-resolution: 200dpi) {
- .dropdown-arrow {
- background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-hdpi.png');
- }
-
- .step-control > .plus-button {
- background-image: url('chrome://browser/skin/images/reader-plus-icon-hdpi.png');
- }
-
- .step-control > .minus-button {
- background-image: url('chrome://browser/skin/images/reader-minus-icon-hdpi.png');
- }
-}
-
-@media screen and (min-resolution: 300dpi) {
- .dropdown-arrow {
- background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-xhdpi.png');
- }
-
- .step-control > .plus-button {
- background-image: url('chrome://browser/skin/images/reader-plus-icon-xhdpi.png');
- }
-
- .step-control > .minus-button {
- background-image: url('chrome://browser/skin/images/reader-minus-icon-xhdpi.png');
- }
-}
-
-@media screen and (orientation: portrait) and (min-resolution: 200dpi) {
- .toolbar {
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-port-hdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-port-hdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-port-hdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-port-hdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-port-hdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-port-hdpi.png');
- }
-}
-
-@media screen and (orientation: landscape) and (min-resolution: 200dpi) {
- .toolbar {
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-land-hdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-land-hdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-land-hdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-land-hdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-land-hdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-land-hdpi.png');
- }
-}
-
-@media screen and (orientation: portrait) and (min-resolution: 300dpi) {
- .toolbar {
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-port-xhdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-port-xhdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-port-xhdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-port-xhdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-port-xhdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-port-xhdpi.png');
- }
-}
-
-@media screen and (orientation: landscape) and (min-resolution: 300dpi) {
- .toolbar {
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-land-xhdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-land-xhdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-land-xhdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-land-xhdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-land-xhdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-land-xhdpi.png');
- }
-}
-
-@media screen and (min-width: 960px) and (min-resolution: 200dpi) {
- .toolbar {
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-xlarge-hdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xlarge-hdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xlarge-hdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-xlarge-hdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-xlarge-hdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-xlarge-hdpi.png');
- }
-}
-
-@media screen and (min-width: 960px) and (min-resolution: 300dpi) {
- .toolbar {
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-xlarge-xhdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xlarge-xhdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xlarge-xhdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-xlarge-xhdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-xlarge-xhdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-xlarge-xhdpi.png');
- }
-}
diff --git a/browser/themes/pinstripe/places/reader.png b/browser/themes/pinstripe/places/reader.png
new file mode 100644
index 0000000000000000000000000000000000000000..8fc9457f4f280bcbd05af7add0ccc26a18678eb6
GIT binary patch
literal 1306
zc%17D@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z`KN7#X@aTAI0-I+_?7x*9r~xHwz7nYo%-8kt#|
zxH-f0dgc|EB<3Zj!t`b$^qS(;Yvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|FgJ5_GdDAKGBiZ^+||v@(#6RM=oCvA
zC8*vMazafX=oo#pu^El!~gYja^C!P*k>nDoEZ3f
z$;x#xVyjsV4xgW6*Z9g;O-+oE(a|>2vh^nqPfz{(yL;DuczC$Ft^WVNg)58=wCbEEchU{U{`*I;s^PBfrm^1&0&nX
zRcuTCGyOb%vWwXy+@2+<$iu0>f$em#$jOX#)0S6hNqs%o@S|a$>(PFBdkG5*iw&s~
z0n_$={rvoVNrKz&qvy^UN}jmRoMcwQT>tl1=j|r#>H2qAf?mCtHKQ?=b$`QxwmnUc
zm@)zveiDob`Qxgswcr7xQTxOhQoIrm_b7DDk54%E|Nnmp``TYq_`1{*Y--h(OrJPK
vOE_bq^@Lx%CKd7 .domain {
margin-top: 10px;
padding-bottom: 10px;
border-bottom: 2px solid;
}
.header > h1 {
- font-family: "OpenSansLight","Droid Sans",sans-serif;
+ font-family: sans-serif;
font-weight: normal;
line-height: 1.1em;
width: 100%;
margin: 0px;
margin-top: 32px;
margin-bottom: 16px;
padding: 0px;
}
@@ -316,42 +316,41 @@ body {
font-size: 20px !important;
}
.font-size7 > .content {
font-size: 22px !important;
}
.toolbar {
- font-family: "Droid Sans",helvetica,arial,clean,sans-serif;
- -moz-transition-property: visibility, opacity;
- -moz-transition-duration: 0.7s;
- visibility: visible;
- opacity: 1.0;
- position: fixed;
- width: 100%;
- bottom: 0px;
- left: 0px;
- margin: 0;
- padding: 0;
- list-style: none;
- background-repeat: repeat;
+ font-family: helvetica,arial,clean,sans-serif;
+ visibility: visible;
+ opacity: 1.0;
+ position: fixed;
+ width: 3%;
+ height: 45px;
+ bottom: 0px;
+ margin: 0;
+ padding: 10px 4px 0 24px;
+ list-style: none;
+ background-repeat: repeat;
+ left: 1%;
}
.toolbar-hidden {
-moz-transition-property: visibility, opacity;
-moz-transition-duration: 0.7s;
visibility: hidden;
opacity: 0.0;
}
-.toolbar > * {
+/*.toolbar > * {
float: right;
- width: 25%;
-}
+ width: 5%;
+}*/
.button {
color: white;
display: block;
background-position: center;
background-repeat: no-repeat;
}
@@ -359,43 +358,44 @@ body {
background-color: #ff9500;
}
.dropdown {
text-align: center;
display: inline-block;
list-style: none;
margin: 0px;
+ margin-left: -15px;
padding: 0px;
}
.dropdown li {
margin: 0px;
padding: 0px;
}
.dropdown-toggle {
margin: 0px;
padding: 0px;
}
.dropdown-popup {
text-align: left;
position: absolute;
- left: 0px;
z-index: 1000;
float: left;
background: #dde2e7;
margin-top: 12px;
margin-bottom: 10px;
padding-top: 4px;
padding-bottom: 8px;
font-size: 14px;
box-shadow: 0px -1px 12px #333;
visibility: hidden;
+ width: 225px;
}
.dropdown-popup > hr {
width: 100%;
height: 0px;
border: 0px;
border-top: 1px solid #ccc;
border-bottom: 1px solid white;
@@ -411,21 +411,21 @@ body {
margin-top: 0px;
margin-bottom: 6px;
bottom: 100%;
visibility: visible;
}
.dropdown-arrow {
position: absolute;
- width: 40px;
- height: 18px;
+ width: 60px;
+ height: 24px;
bottom: -18px;
- background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-mdpi.png');
- background-size: 40px 18px;
+ background-image: url('chrome://browser/skin/places/readerDropdownArrow@2x.png');
+ background-size: 60px 24px;
background-position: center;
display: block;
}
.segmented-button {
list-style: none;
margin: 0;
padding: 5px;
@@ -477,301 +477,32 @@ body {
float: right;
text-align: center;
width: 56px;
height: 43px;
background-size: 20px;
}
.step-control > .plus-button {
- background-image: url('chrome://browser/skin/images/reader-plus-icon-mdpi.png');
+ background-image: url('chrome://browser/skin/places/readerPlusIcon@2x.png');
border-left: 1px solid #ccc;
margin-right: 4px;
+ width: 30px;
+ height: 30px;
}
.step-control > .minus-button {
- background-image: url('chrome://browser/skin/images/reader-minus-icon-mdpi.png');
+ background-image: url('chrome://browser/skin/places/readerMinusIcon@2x.png');
+ width: 30px;
+ height: 30px;
}
-@media screen and (orientation: portrait) {
- .button {
- height: 48px;
- background-size: 30px 24px
- }
-
- .toolbar {
- background-size: 48px;
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-port-mdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-port-mdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-port-mdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-port-mdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-port-mdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-port-mdpi.png');
- }
+.toolbar {
+ background-image: url('chrome://browser/skin/places/readerToolbarBg@2x.png');
}
-@media screen and (orientation: landscape) {
- .button {
- height: 40px;
- background-size: 24px 20px
- }
-
- .toolbar {
- background-size: 40px;
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-land-mdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-land-mdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-land-mdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-land-mdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-land-mdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-land-mdpi.png');
- }
+.style-button {
+ background-image: url('chrome://browser/skin/places/readerStyleIcon@2x.png');
+ width: 45px;
+ height: 36px;
+ left: -10px;
}
-@media screen and (min-width: 960px) {
- .button {
- width: 56px;
- height: 56px;
- background-size: 36px 28px
- }
-
- .toolbar {
- background-size: 56px;
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-xlarge-mdpi.png');
- }
-
- .toolbar > * {
- width: 56px;
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xlarge-mdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xlarge-mdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-xlarge-mdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-xlarge-mdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-xlarge-mdpi.png');
- }
-}
-
-@media screen and (min-resolution: 200dpi) {
- .dropdown-arrow {
- background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-hdpi.png');
- }
-
- .step-control > .plus-button {
- background-image: url('chrome://browser/skin/images/reader-plus-icon-hdpi.png');
- }
-
- .step-control > .minus-button {
- background-image: url('chrome://browser/skin/images/reader-minus-icon-hdpi.png');
- }
-}
-
-@media screen and (min-resolution: 300dpi) {
- .dropdown-arrow {
- background-image: url('chrome://browser/skin/images/reader-dropdown-arrow-xhdpi.png');
- }
-
- .step-control > .plus-button {
- background-image: url('chrome://browser/skin/images/reader-plus-icon-xhdpi.png');
- }
-
- .step-control > .minus-button {
- background-image: url('chrome://browser/skin/images/reader-minus-icon-xhdpi.png');
- }
-}
-
-@media screen and (orientation: portrait) and (min-resolution: 200dpi) {
- .toolbar {
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-port-hdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-port-hdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-port-hdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-port-hdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-port-hdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-port-hdpi.png');
- }
-}
-
-@media screen and (orientation: landscape) and (min-resolution: 200dpi) {
- .toolbar {
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-land-hdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-land-hdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-land-hdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-land-hdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-land-hdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-land-hdpi.png');
- }
-}
-
-@media screen and (orientation: portrait) and (min-resolution: 300dpi) {
- .toolbar {
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-port-xhdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-port-xhdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-port-xhdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-port-xhdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-port-xhdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-port-xhdpi.png');
- }
-}
-
-@media screen and (orientation: landscape) and (min-resolution: 300dpi) {
- .toolbar {
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-land-xhdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-land-xhdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-land-xhdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-land-xhdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-land-xhdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-land-xhdpi.png');
- }
-}
-
-@media screen and (min-width: 960px) and (min-resolution: 200dpi) {
- .toolbar {
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-xlarge-hdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xlarge-hdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xlarge-hdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-xlarge-hdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-xlarge-hdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-xlarge-hdpi.png');
- }
-}
-
-@media screen and (min-width: 960px) and (min-resolution: 300dpi) {
- .toolbar {
- background-image: url('chrome://browser/skin/images/reader-toolbar-bg-xlarge-xhdpi.png');
- }
-
- .toggle-button.on {
- background-image: url('chrome://browser/skin/images/reader-toggle-on-icon-xlarge-xhdpi.png');
- }
-
- .toggle-button {
- background-image: url('chrome://browser/skin/images/reader-toggle-off-icon-xlarge-xhdpi.png');
- }
-
- .list-button {
- background-image: url('chrome://browser/skin/images/reader-list-icon-xlarge-xhdpi.png');
- }
-
- .share-button {
- background-image: url('chrome://browser/skin/images/reader-share-icon-xlarge-xhdpi.png');
- }
-
- .style-button {
- background-image: url('chrome://browser/skin/images/reader-style-icon-xlarge-xhdpi.png');
- }
-}
diff --git a/browser/themes/winstripe/places/reader.png b/browser/themes/winstripe/places/reader.png
new file mode 100644
index 0000000000000000000000000000000000000000..8fc9457f4f280bcbd05af7add0ccc26a18678eb6
GIT binary patch
literal 1306
zc%17D@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z`KN7#X@aTAI0-I+_?7x*9r~xHwz7nYo%-8kt#|
zxH-f0dgc|EB<3Zj!t`b$^qS(;Yvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|FgJ5_GdDAKGBiZ^+||v@(#6RM=oCvA
zC8*vMazafX=oo#pu^El!~gYja^C!P*k>nDoEZ3f
z$;x#xVyjsV4xgW6*Z9g;O-+oE(a|>2vh^nqPfz{(yL;DuczC$Ft^WVNg)58=wCbEEchU{U{`*I;s^PBfrm^1&0&nX
zRcuTCGyOb%vWwXy+@2+<$iu0>f$em#$jOX#)0S6hNqs%o@S|a$>(PFBdkG5*iw&s~
z0n_$={rvoVNrKz&qvy^UN}jmRoMcwQT>tl1=j|r#>H2qAf?mCtHKQ?=b$`QxwmnUc
zm@)zveiDob`Qxgswcr7xQTxOhQoIrm_b7DDk54%E|Nnmp``TYq_`1{*Y--h(OrJPK
vOE_bq^@Lx%CKd7