This commit is contained in:
Ryan VanderMeulen 2014-07-17 17:28:31 -04:00
Родитель c21df7546a dc4882b221
Коммит 251b34a633
74 изменённых файлов: 6085 добавлений и 1584 удалений

Просмотреть файл

@ -1307,6 +1307,9 @@ pref("devtools.profiler.enabled", true);
// The default Profiler UI settings
pref("devtools.profiler.ui.show-platform-data", false);
// The default cache UI setting
pref("devtools.cache.disabled", false);
// Enable the Network Monitor
pref("devtools.netmonitor.enabled", true);

Просмотреть файл

@ -11,6 +11,8 @@ Cu.import("resource://gre/modules/NotificationDB.jsm");
Cu.import("resource:///modules/RecentWindow.jsm");
Cu.import("resource://gre/modules/WindowsPrefSync.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
"resource:///modules/BrowserUITelemetry.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
@ -3095,6 +3097,7 @@ const BrowserSearch = {
* SearchesProvider for allowed values.
*/
recordSearchInHealthReport: function (engine, source) {
BrowserUITelemetry.countSearchEvent(source);
#ifdef MOZ_SERVICES_HEALTHREPORT
let reporter = Cc["@mozilla.org/datareporting/service;1"]
.getService()

Просмотреть файл

@ -321,12 +321,14 @@ BrowserGlue.prototype = {
// the UI has gone should be finalized in _onQuitApplicationGranted.
this._dispose();
break;
#ifdef MOZ_SERVICES_HEALTHREPORT
case "keyword-search":
// This is very similar to code in
// browser.js:BrowserSearch.recordSearchInHealthReport(). The code could
// be consolidated if there is will. We need the observer in
// nsBrowserGlue to prevent double counting.
let win = this.getMostRecentBrowserWindow();
BrowserUITelemetry.countSearchEvent("urlbar", win.gURLBar.value);
#ifdef MOZ_SERVICES_HEALTHREPORT
let reporter = Cc["@mozilla.org/datareporting/service;1"]
.getService()
.wrappedJSObject
@ -344,8 +346,8 @@ BrowserGlue.prototype = {
Cu.reportError(ex);
}
});
break;
#endif
break;
case "browser-search-engine-modified":
if (data != "engine-default" && data != "engine-current") {
break;

Просмотреть файл

@ -45,7 +45,7 @@ function testTask() {
result = result.replace(/[\r\n]]*/g, "\n");
let correct = "function somefunc() {\n" +
" if (true) // Some comment\n" +
" doSomething();\n" +
" doSomething();\n" +
" for (let n = 0; n < 500; n++) {\n" +
" if (n % 2 == 1) {\n" +
" console.log(n);\n" +

Просмотреть файл

@ -11,9 +11,7 @@ Cu.import("resource://gre/modules/devtools/event-emitter.js", tempScope);
let EventEmitter = tempScope.EventEmitter;
function test() {
addTab("about:blank", function(aBrowser, aTab) {
runTests(aTab);
});
addTab("about:blank").then(runTests);
}
function runTests(aTab) {

Просмотреть файл

@ -37,4 +37,5 @@ function test() {
checkItem(el, prefs);
}
}
finish();
}

Просмотреть файл

@ -10,7 +10,7 @@ let toolbox, target;
let tempScope = {};
function test() {
addTab("about:blank", function(aBrowser, aTab) {
addTab("about:blank").then(function(aTab) {
target = TargetFactory.forTab(gBrowser.selectedTab);
loadWebConsole(aTab).then(function() {
console.log('loaded');

Просмотреть файл

@ -17,8 +17,6 @@ function test() {
let toolbox, iframe, target, tab;
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
target = TargetFactory.forTab(gBrowser.selectedTab);

Просмотреть файл

@ -6,8 +6,6 @@ let toolbox;
function test()
{
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
let target = TargetFactory.forTab(gBrowser.selectedTab);

Просмотреть файл

@ -9,14 +9,12 @@ temp = null;
let toolbox = null;
function test() {
waitForExplicitFinish();
const URL = "data:text/plain;charset=UTF-8,Nothing to see here, move along";
const TOOL_ID_1 = "jsdebugger";
const TOOL_ID_2 = "webconsole";
addTab(URL, () => {
addTab(URL).then(() => {
let target = TargetFactory.forTab(gBrowser.selectedTab);
gDevTools.showToolbox(target, TOOL_ID_1, Toolbox.HostType.BOTTOM)
.then(aToolbox => {

Просмотреть файл

@ -15,8 +15,6 @@ let toolbox, target;
function test()
{
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
target = TargetFactory.forTab(gBrowser.selectedTab);

Просмотреть файл

@ -4,11 +4,10 @@
let doc = null, toolbox = null, panelWin = null, modifiedPrefs = [];
function test() {
waitForExplicitFinish();
const URL = "data:text/html;charset=utf8,test for dynamically registering and unregistering tools";
Task.spawn(function* () {
let { target } = yield addTab(URL);
let tab = yield addTab(URL);
let target = TargetFactory.forTab(tab);
let toolbox = yield gDevTools.showToolbox(target);
yield testSelectTool(toolbox);
yield testOptionsShortcut();

Просмотреть файл

@ -4,8 +4,6 @@
let doc = null, toolbox = null, panelWin = null, modifiedPrefs = [];
function test() {
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
let target = TargetFactory.forTab(gBrowser.selectedTab);

Просмотреть файл

@ -1,113 +1,159 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that disabling JavaScript for a tab works as it should.
// Tests that disabling the cache for a tab works as it should.
const TEST_URI = "http://mochi.test:8888/browser/browser/devtools/framework/" +
"test/browser_toolbox_options_disable_cache.sjs";
let tabs = [
{
title: "Tab 0",
desc: "Toggles cache on.",
startToolbox: true
},
{
title: "Tab 1",
desc: "Toolbox open before Tab 1 toggles cache.",
startToolbox: true
},
{
title: "Tab 2",
desc: "Opens toolbox after Tab 1 has toggled cache. Also closes and opens.",
startToolbox: false
},
{
title: "Tab 3",
desc: "No toolbox",
startToolbox: false
}];
let doc;
let toolbox;
let test = asyncTest(function*() {
// Initialise tabs: 1 and 2 with a toolbox, 3 and 4 without.
for (let tab of tabs) {
yield initTab(tab, tab.startToolbox);
}
function test() {
waitForExplicitFinish();
// Ensure cache is enabled for all tabs.
yield checkCacheStateForAllTabs([true, true, true, true]);
gBrowser.selectedTab = gBrowser.addTab();
let target = TargetFactory.forTab(gBrowser.selectedTab);
// Check the checkbox in tab 0 and ensure cache is disabled for tabs 0 and 1.
yield setDisableCacheCheckboxChecked(tabs[0], true);
yield checkCacheStateForAllTabs([false, false, true, true]);
gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
doc = content.document;
gDevTools.showToolbox(target).then(testSelectTool);
}, true);
// Open toolbox in tab 2 and ensure the cache is then disabled.
tabs[2].toolbox = yield gDevTools.showToolbox(tabs[2].target, "options");
yield checkCacheEnabled(tabs[2], false);
content.location = TEST_URI;
// Close toolbox in tab 2 and ensure the cache is enabled again
yield tabs[2].toolbox.destroy();
tabs[2].target = TargetFactory.forTab(tabs[2].tab);
yield checkCacheEnabled(tabs[2], true);
// Open toolbox in tab 2 and ensure the cache is then disabled.
tabs[2].toolbox = yield gDevTools.showToolbox(tabs[2].target, "options");
yield checkCacheEnabled(tabs[2], false);
// Check the checkbox in tab 2 and ensure cache is enabled for all tabs.
yield setDisableCacheCheckboxChecked(tabs[2], false);
yield checkCacheStateForAllTabs([true, true, true, true]);
yield finishUp();
});
function* initTab(tabX, startToolbox) {
tabX.tab = yield addTab(TEST_URI);
tabX.target = TargetFactory.forTab(tabX.tab);
if (startToolbox) {
tabX.toolbox = yield gDevTools.showToolbox(tabX.target, "options");
}
}
function testSelectTool(aToolbox) {
toolbox = aToolbox;
toolbox.once("options-selected", testCacheEnabled);
toolbox.selectTool("options");
function* checkCacheStateForAllTabs(states) {
for (let i = 0; i < tabs.length; i ++) {
let tab = tabs[i];
yield checkCacheEnabled(tab, states[i]);
}
}
function testCacheEnabled() {
let prevTimestamp = getGUID();
function* checkCacheEnabled(tabX, expected) {
gBrowser.selectedTab = tabX.tab;
gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
doc = content.document;
is(prevTimestamp, getGUID(), "GUID has not changed (page is cached)");
yield reloadTab(tabX);
testCacheEnabled2();
}, true);
let doc = content.document;
let h1 = doc.querySelector("h1");
let oldGuid = h1.textContent;
doc.location.reload(false);
yield reloadTab(tabX);
doc = content.document;
h1 = doc.querySelector("h1");
let guid = h1.textContent;
if (expected) {
is(guid, oldGuid, tabX.title + " cache is enabled");
} else {
isnot(guid, oldGuid, tabX.title + " cache is not enabled");
}
}
function testCacheEnabled2() {
let prevTimestamp = getGUID();
function* setDisableCacheCheckboxChecked(tabX, state) {
gBrowser.selectedTab = tabX.tab;
gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
doc = content.document;
is(prevTimestamp, getGUID(),
"GUID has not changed after page refresh (page is cached)");
testCacheDisabled();
}, true);
doc.location.reload(false);
}
function testCacheDisabled() {
let prevTimestamp = getGUID();
let panel = toolbox.getCurrentPanel();
let panel = tabX.toolbox.getCurrentPanel();
let cbx = panel.panelDoc.getElementById("devtools-disable-cache");
let browser = gBrowser.selectedBrowser;
browser.addEventListener("load", function onLoad(evt) {
browser.removeEventListener(evt.type, onLoad, true);
doc = content.document;
isnot(prevTimestamp, getGUID(), "GUID has changed (page is not cached)");
testCacheDisabled2();
}, true);
info("disabling cache");
cbx.scrollIntoView();
// After uising scrollIntoView() we need to use executeSoon() to wait for the
// browser to scroll.
executeSoon(function() {
// After uising scrollIntoView() we need to wait for the browser to scroll.
yield waitForTick();
if (cbx.checked !== state) {
info("Setting disable cache checkbox to " + state + " for " + tabX.title);
EventUtils.synthesizeMouseAtCenter(cbx, {}, panel.panelWin);
});
// We need to wait for all checkboxes to be updated and the docshells to
// apply the new cache settings.
yield waitForTick();
}
}
function testCacheDisabled2() {
let prevTimestamp = getGUID();
function reloadTab(tabX) {
let def = promise.defer();
let browser = gBrowser.selectedBrowser;
browser.addEventListener("load", function onLoad(evt) {
browser.removeEventListener(evt.type, onLoad, true);
doc = content.document;
isnot(prevTimestamp, getGUID(),
"GUID has changed after page refresh (page is not cached)");
finishUp();
// once() doesn't work here so we use a standard handler instead.
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
info("Reloaded tab " + tabX.title);
def.resolve();
}, true);
doc.location.reload(false);
info("Reloading tab " + tabX.title);
content.document.location.reload(false);
return def.promise;
}
function getGUID() {
return doc.querySelector("h1").textContent;
function* destroyTab(tabX) {
let toolbox = gDevTools.getToolbox(tabX.target);
info("Removing tab " + tabX.title);
gBrowser.removeTab(tabX.tab);
info("Removed tab " + tabX.title);
if (toolbox) {
info("Waiting for toolbox-destroyed");
yield gDevTools.once("toolbox-destroyed");
info("toolbox-destroyed event received for " + tabX.title);
}
}
function finishUp() {
toolbox.destroy().then(() => {
gBrowser.removeCurrentTab();
toolbox = doc = null;
finish();
}).then(null, console.error);
function* finishUp() {
for (let tab of tabs) {
yield destroyTab(tab);
}
tabs = null;
}

Просмотреть файл

@ -10,8 +10,6 @@ let doc;
let toolbox;
function test() {
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
let target = TargetFactory.forTab(gBrowser.selectedTab);

Просмотреть файл

@ -15,8 +15,6 @@ let Toolbox = devtools.Toolbox;
let toolbox, target, tab1, tab2;
function test() {
waitForExplicitFinish();
gBrowser.selectedTab = tab1 = gBrowser.addTab();
tab2 = gBrowser.addTab();
target = TargetFactory.forTab(gBrowser.selectedTab);

Просмотреть файл

@ -4,8 +4,6 @@
function test()
{
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
let target = TargetFactory.forTab(gBrowser.selectedTab);

Просмотреть файл

@ -4,7 +4,7 @@
let toolbox;
function test() {
addTab("about:blank", function() {
addTab("about:blank").then(function() {
let target = TargetFactory.forTab(gBrowser.selectedTab);
gDevTools.showToolbox(target, "webconsole").then(testSelect);
});

Просмотреть файл

@ -45,8 +45,8 @@ function test() {
gDevTools.registerTool(toolDefinition);
addTab("about:blank", function(aBrowser, aTab) {
let target = TargetFactory.forTab(gBrowser.selectedTab);
addTab("about:blank").then(function(aTab) {
let target = TargetFactory.forTab(aTab);
gDevTools.showToolbox(target, toolDefinition.id).then(function(toolbox) {
let panel = toolbox.getPanel(toolDefinition.id);
ok(true, "Tool open");
@ -142,8 +142,9 @@ function test() {
panel.sidebar.destroy();
gDevTools.unregisterTool(toolDefinition.id);
gBrowser.removeCurrentTab();
executeSoon(function() {
gBrowser.removeCurrentTab();
finish();
});
}

Просмотреть файл

@ -7,9 +7,7 @@ let toolbox, toolIDs, idIndex, secondTime = false,
reverse = false, nextKey = null, prevKey = null;
function test() {
waitForExplicitFinish();
addTab("about:blank", function() {
addTab("about:blank").then(function() {
let target = TargetFactory.forTab(gBrowser.selectedTab);
idIndex = 0;

Просмотреть файл

@ -2,20 +2,21 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
addTab().then(function(data) {
data.target.makeRemote().then(performChecks.bind(null, data));
addTab("about:blank").then(function(tab) {
let target = TargetFactory.forTab(tab);
target.makeRemote().then(performChecks.bind(null, target));
}).then(null, console.error);
function performChecks(data) {
function performChecks(target) {
let toolIds = gDevTools.getToolDefinitionArray()
.filter(def => def.isTargetSupported(data.target))
.filter(def => def.isTargetSupported(target))
.map(def => def.id);
let open = function(index) {
let toolId = toolIds[index];
info("About to open " + index + "/" + toolId);
gDevTools.showToolbox(data.target, toolId).then(function(toolbox) {
gDevTools.showToolbox(target, toolId).then(function(toolbox) {
ok(toolbox, "toolbox exists for " + toolId);
is(toolbox.currentToolId, toolId, "currentToolId should be " + toolId);

Просмотреть файл

@ -1,17 +1,16 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_URL = "data:text/html;charset=utf-8,"+
"<html><head><title>Test reload</title></head>"+
"<body><h1>Testing reload from devtools</h1></body></html>";
let Toolbox = devtools.Toolbox;
let target, toolbox, description, reloadsSent, toolIDs;
function test() {
waitForExplicitFinish();
addTab("data:text/html;charset=utf-8,"+
"<html><head><title>Test reload</title></head>"+
"<body><h1>Testing reload from devtools</h1></body></html>",
() => {
addTab(TEST_URL).then(() => {
target = TargetFactory.forTab(gBrowser.selectedTab);
target.makeRemote().then(() => {

Просмотреть файл

@ -6,15 +6,13 @@ let Toolbox = devtools.Toolbox;
let toolbox, toolIDs, idIndex, modifiedPrefs = [];
function test() {
waitForExplicitFinish();
if (window.navigator.userAgent.indexOf("Mac OS X 10.8") != -1 ||
window.navigator.userAgent.indexOf("Windows NT 5.1") != -1) {
info("Skipping Mac OSX 10.8 and Windows xp, see bug 838069");
finish();
return;
}
addTab("about:blank", function() {
addTab("about:blank").then(function() {
toolIDs = [];
for (let [id, definition] of gDevTools._tools) {
if (definition.key) {

Просмотреть файл

@ -8,8 +8,6 @@ let Services = temp.Services;
temp = null;
function test() {
waitForExplicitFinish();
const URL_1 = "data:text/plain;charset=UTF-8,abcde";
const URL_2 = "data:text/plain;charset=UTF-8,12345";
@ -21,7 +19,7 @@ function test() {
let toolbox;
addTab(URL_1, function () {
addTab(URL_1).then(function () {
let target = TargetFactory.forTab(gBrowser.selectedTab);
gDevTools.showToolbox(target, null, Toolbox.HostType.BOTTOM)
.then(function (aToolbox) { toolbox = aToolbox; })

Просмотреть файл

@ -8,11 +8,7 @@ let modifiers = {
let toolbox;
function test() {
waitForExplicitFinish();
addTab("about:blank", function() {
openToolbox();
});
addTab("about:blank").then(openToolbox);
}
function openToolbox() {

Просмотреть файл

@ -4,50 +4,49 @@
let TargetFactory = gDevTools.TargetFactory;
let tempScope = {};
Components.utils.import("resource://gre/modules/devtools/Console.jsm", tempScope);
let console = tempScope.console;
Components.utils.import("resource://gre/modules/Promise.jsm", tempScope);
let promise = tempScope.Promise;
const { console } = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
let {devtools} = Components.utils.import("resource://gre/modules/devtools/Loader.jsm", {});
let TargetFactory = devtools.TargetFactory;
// All test are asynchronous
waitForExplicitFinish();
// Uncomment this pref to dump all devtools emitted events to the console.
// Services.prefs.setBoolPref("devtools.dump.emit", true);
gDevTools.testing = true;
SimpleTest.registerCleanupFunction(() => {
gDevTools.testing = false;
Services.prefs.clearUserPref("devtools.dump.emit");
});
/**
* Open a new tab at a URL and call a callback on load
* Define an async test based on a generator function
*/
function addTab(aURL, aCallback)
{
waitForExplicitFinish();
function asyncTest(generator) {
return () => Task.spawn(generator).then(null, ok.bind(null, false)).then(finish);
}
gBrowser.selectedTab = gBrowser.addTab();
if (aURL != null) {
content.location = aURL;
}
/**
* Add a new test tab in the browser and load the given url.
* @param {String} url The url to be loaded in the new tab
* @return a promise that resolves to the tab object when the url is loaded
*/
function addTab(url) {
info("Adding a new tab with URL: '" + url + "'");
let def = promise.defer();
let deferred = promise.defer();
let tab = gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
info("URL '" + url + "' loading complete");
def.resolve(tab);
}, true);
content.location = url;
let tab = gBrowser.selectedTab;
let target = TargetFactory.forTab(gBrowser.selectedTab);
let browser = gBrowser.getBrowserForTab(tab);
function onTabLoad() {
browser.removeEventListener("load", onTabLoad, true);
if (aCallback != null) {
aCallback(browser, tab, browser.contentDocument);
}
deferred.resolve({ browser: browser, tab: tab, target: target });
}
browser.addEventListener("load", onTabLoad, true);
return deferred.promise;
return def.promise;
}
registerCleanupFunction(function tearDown() {
@ -77,7 +76,44 @@ function synthesizeKeyFromKeyTag(aKeyId, document) {
altKey: modifiersAttr.match("alt"),
metaKey: modifiersAttr.match("meta"),
accelKey: modifiersAttr.match("accel")
}
};
EventUtils.synthesizeKey(name, modifiers);
}
/**
* Wait for eventName on target.
* @param {Object} target An observable object that either supports on/off or
* addEventListener/removeEventListener
* @param {String} eventName
* @param {Boolean} useCapture Optional, for addEventListener/removeEventListener
* @return A promise that resolves when the event has been handled
*/
function once(target, eventName, useCapture=false) {
info("Waiting for event: '" + eventName + "' on " + target + ".");
let deferred = promise.defer();
for (let [add, remove] of [
["addEventListener", "removeEventListener"],
["addListener", "removeListener"],
["on", "off"]
]) {
if ((add in target) && (remove in target)) {
target[add](eventName, function onEvent(...aArgs) {
info("Got event: '" + eventName + "' on " + target + ".");
target[remove](eventName, onEvent, useCapture);
deferred.resolve.apply(deferred, aArgs);
}, useCapture);
break;
}
}
return deferred.promise;
}
function waitForTick() {
let deferred = promise.defer();
executeSoon(deferred.resolve);
return deferred.promise;
}

Просмотреть файл

@ -37,6 +37,10 @@ function OptionsPanel(iframeWindow, toolbox) {
this.toolbox = toolbox;
this.isReady = false;
this._prefChanged = this._prefChanged.bind(this);
this._addListeners();
const EventEmitter = require("devtools/toolkit/event-emitter");
EventEmitter.decorate(this);
}
@ -63,13 +67,9 @@ OptionsPanel.prototype = {
this.populatePreferences();
this._disableJSClicked = this._disableJSClicked.bind(this);
this._disableCacheClicked = this._disableCacheClicked.bind(this);
let disableJSNode = this.panelDoc.getElementById("devtools-disable-javascript");
disableJSNode.addEventListener("click", this._disableJSClicked, false);
let disableCacheNode = this.panelDoc.getElementById("devtools-disable-cache");
disableCacheNode.addEventListener("click", this._disableCacheClicked, false);
}).then(() => {
this.isReady = true;
this.emit("ready");
@ -80,6 +80,23 @@ OptionsPanel.prototype = {
});
},
_addListeners: function() {
gDevTools.on("pref-changed", this._prefChanged);
},
_removeListeners: function() {
gDevTools.off("pref-changed", this._prefChanged);
},
_prefChanged: function(event, data) {
if (data.pref === "devtools.cache.disabled") {
let cacheDisabled = data.newValue;
let cbx = this.panelDoc.getElementById("devtools-disable-cache");
cbx.checked = cacheDisabled;
}
},
setupToolbarButtonsList: function() {
let enabledToolbarButtonsBox = this.panelDoc.getElementById("enabled-toolbox-buttons-box");
enabledToolbarButtonsBox.textContent = "";
@ -242,10 +259,8 @@ OptionsPanel.prototype = {
this.target.client.attachTab(this.target.activeTab._actor, (response) => {
this._origJavascriptEnabled = response.javascriptEnabled;
this._origCacheEnabled = response.cacheEnabled;
this._populateDisableJSCheckbox();
this._populateDisableCacheCheckbox();
});
},
@ -254,11 +269,6 @@ OptionsPanel.prototype = {
cbx.checked = !this._origJavascriptEnabled;
},
_populateDisableCacheCheckbox: function() {
let cbx = this.panelDoc.getElementById("devtools-disable-cache");
cbx.checked = !this._origCacheEnabled;
},
/**
* Disables JavaScript for the currently loaded tab. We force a page refresh
* here because setting docShell.allowJavascript to true fails to block JS
@ -279,22 +289,6 @@ OptionsPanel.prototype = {
this.target.activeTab.reconfigure(options);
},
/**
* Disables the cache for the currently loaded tab.
*
* @param {Event} event
* The event sent by checking / unchecking the disable cache checkbox.
*/
_disableCacheClicked: function(event) {
let checked = event.target.checked;
let options = {
"cacheEnabled": !checked
};
this.target.activeTab.reconfigure(options);
},
destroy: function() {
if (this.destroyPromise) {
return this.destroyPromise;
@ -307,16 +301,13 @@ OptionsPanel.prototype = {
let disableJSNode = this.panelDoc.getElementById("devtools-disable-javascript");
disableJSNode.removeEventListener("click", this._disableJSClicked, false);
let disableCacheNode = this.panelDoc.getElementById("devtools-disable-cache");
disableCacheNode.removeEventListener("click", this._disableCacheClicked, false);
this._removeListeners();
this.panelWin = this.panelDoc = null;
this._disableJSClicked = this._disableCacheClicked = null;
this._disableJSClicked = null;
// If the cache or JavaScript is disabled we need to revert them to their
// original values.
// If JavaScript is disabled we need to revert it to it's original value.
let options = {
"cacheEnabled": this._origCacheEnabled,
"javascriptEnabled": this._origJavascriptEnabled
};
this.target.activeTab.reconfigure(options, () => {

Просмотреть файл

@ -88,8 +88,9 @@
<label value="&options.context.advancedSettings;"/>
<vbox id="context-options" class="options-groupbox">
<checkbox id="devtools-disable-cache"
label="&options.disableCache.label;"
tooltiptext="&options.disableCache.tooltip;"/>
label="&options.disableCache.label2;"
tooltiptext="&options.disableCache.tooltip2;"
data-pref="devtools.cache.disabled"/>
<checkbox id="devtools-disable-javascript"
label="&options.disableJavaScript.label;"
tooltiptext="&options.disableJavaScript.tooltip;"/>

Просмотреть файл

@ -67,11 +67,12 @@ function Toolbox(target, selectedTool, hostType, hostOptions) {
this._toolRegistered = this._toolRegistered.bind(this);
this._toolUnregistered = this._toolUnregistered.bind(this);
this._refreshHostTitle = this._refreshHostTitle.bind(this);
this._splitConsoleOnKeypress = this._splitConsoleOnKeypress.bind(this)
this._splitConsoleOnKeypress = this._splitConsoleOnKeypress.bind(this);
this.destroy = this.destroy.bind(this);
this.highlighterUtils = getHighlighterUtils(this);
this._highlighterReady = this._highlighterReady.bind(this);
this._highlighterHidden = this._highlighterHidden.bind(this);
this._prefChanged = this._prefChanged.bind(this);
this._target.on("close", this.destroy);
@ -241,10 +242,13 @@ Toolbox.prototype = {
let closeButton = this.doc.getElementById("toolbox-close");
closeButton.addEventListener("command", this.destroy, true);
gDevTools.on("pref-changed", this._prefChanged);
this._buildDockButtons();
this._buildOptions();
this._buildTabs();
let buttonsPromise = this._buildButtons();
this._applyCacheSettings();
this._addKeysToWindow();
this._addReloadKeys();
this._addToolSwitchingKeys();
@ -273,6 +277,24 @@ Toolbox.prototype = {
});
},
/**
* Because our panels are lazy loaded this is a good place to watch for
* "pref-changed" events.
* @param {String} event
* The event type, "pref-changed".
* @param {Object} data
* {
* newValue: The new value
* oldValue: The old value
* pref: The name of the preference that has changed
* }
*/
_prefChanged: function(event, data) {
if (data.pref === "devtools.cache.disabled") {
this._applyCacheSettings();
}
},
_buildOptions: function() {
let key = this.doc.getElementById("toolbox-options-key");
key.addEventListener("command", () => {
@ -587,6 +609,19 @@ Toolbox.prototype = {
this._pickerButton.addEventListener("command", this._togglePicker, false);
},
/**
* Apply the current cache setting from devtools.cache.disabled to this
* toolbox's tab.
*/
_applyCacheSettings: function() {
let pref = "devtools.cache.disabled";
let cacheDisabled = Services.prefs.getBoolPref(pref);
if (this.target.activeTab) {
this.target.activeTab.reconfigure({"cacheDisabled": cacheDisabled});
}
},
/**
* Setter for the checked state of the picker button in the toolbar
* @param {Boolean} isChecked
@ -1262,6 +1297,8 @@ Toolbox.prototype = {
gDevTools.off("tool-registered", this._toolRegistered);
gDevTools.off("tool-unregistered", this._toolUnregistered);
gDevTools.off("pref-changed", this._prefChanged);
let outstanding = [];
for (let [id, panel] of this._toolPanels) {
try {
@ -1272,6 +1309,12 @@ Toolbox.prototype = {
}
}
// Now that we are closing the toolbox we can re-enable JavaScript for the
// current tab.
if (this.target.activeTab) {
this.target.activeTab.reconfigure({"cacheDisabled": false});
}
// Destroying the walker and inspector fronts
outstanding.push(this.destroyInspector());
// Removing buttons

Просмотреть файл

@ -13,7 +13,8 @@ const Cc = Components.classes;
// Services.prefs.clearUserPref("devtools.debugger.log");
// });
//Services.prefs.setBoolPref("devtools.dump.emit", true);
// Uncomment this pref to dump all devtools emitted events to the console.
// Services.prefs.setBoolPref("devtools.dump.emit", true);
const TEST_URL_ROOT = "http://example.com/browser/browser/devtools/inspector/test/";
const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});

Просмотреть файл

@ -16,8 +16,9 @@ waitForExplicitFinish();
const TEST_URL_ROOT = "http://example.com/browser/browser/devtools/layoutview/test/";
// Uncomment to log events
// Uncomment this pref to dump all devtools emitted events to the console.
// Services.prefs.setBoolPref("devtools.dump.emit", true);
// Services.prefs.setBoolPref("devtools.debugger.log", true);
// Set the testing flag on gDevTools and reset it when the test ends

Просмотреть файл

@ -12,7 +12,8 @@ let {getInplaceEditorForSpan: inplaceEditor} = devtools.require("devtools/shared
// All test are asynchronous
waitForExplicitFinish();
//Services.prefs.setBoolPref("devtools.dump.emit", true);
// Uncomment this pref to dump all devtools emitted events to the console.
// Services.prefs.setBoolPref("devtools.dump.emit", true);
// Set the testing flag on gDevTools and reset it when the test ends
gDevTools.testing = true;

Просмотреть файл

@ -362,20 +362,20 @@ let NetMonitorController = {
if (aType == ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED) {
this._currentActivity = ACTIVITY_TYPE.ENABLE_CACHE;
this._target.once("will-navigate", () => this._currentActivity = aType);
return reconfigureTabAndWaitForNavigation({ cacheEnabled: true }).then(standBy);
return reconfigureTabAndWaitForNavigation({ cacheDisabled: false, performReload: true }).then(standBy);
}
if (aType == ACTIVITY_TYPE.RELOAD.WITH_CACHE_DISABLED) {
this._currentActivity = ACTIVITY_TYPE.DISABLE_CACHE;
this._target.once("will-navigate", () => this._currentActivity = aType);
return reconfigureTabAndWaitForNavigation({ cacheEnabled: false }).then(standBy);
return reconfigureTabAndWaitForNavigation({ cacheDisabled: true, performReload: true }).then(standBy);
}
if (aType == ACTIVITY_TYPE.ENABLE_CACHE) {
this._currentActivity = aType;
return reconfigureTab({ cacheEnabled: true, performReload: false }).then(standBy);
return reconfigureTab({ cacheDisabled: false, performReload: false }).then(standBy);
}
if (aType == ACTIVITY_TYPE.DISABLE_CACHE) {
this._currentActivity = aType;
return reconfigureTab({ cacheEnabled: false, performReload: false }).then(standBy);
return reconfigureTab({ cacheDisabled: true, performReload: false }).then(standBy);
}
this._currentActivity = ACTIVITY_TYPE.NONE;
return promise.reject(new Error("Invalid activity type"));

Просмотреть файл

@ -59,6 +59,9 @@ const gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
// To enable logging for try runs, just set the pref to true.
Services.prefs.setBoolPref("devtools.debugger.log", false);
// Uncomment this pref to dump all devtools emitted events to the console.
// Services.prefs.setBoolPref("devtools.dump.emit", true);
// Always reset some prefs to their original values after the test finishes.
const gDefaultFilters = Services.prefs.getCharPref("devtools.netmonitor.filters");
@ -67,6 +70,8 @@ registerCleanupFunction(() => {
Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
Services.prefs.setCharPref("devtools.netmonitor.filters", gDefaultFilters);
Services.prefs.clearUserPref("devtools.cache.disabled");
Services.prefs.clearUserPref("devtools.dump.emit");
});
function addTab(aUrl, aWindow) {
@ -113,9 +118,13 @@ function reconfigureTab(aTarget, aOptions) {
return deferred.promise;
};
function toggleCache(aTarget, aEnabled) {
let options = { cacheEnabled: aEnabled, performReload: true };
function toggleCache(aTarget, aDisabled) {
let options = { cacheDisabled: aDisabled, performReload: true };
let navigationFinished = waitForNavigation(aTarget);
// Disable the cache for any toolbox that it is opened from this point on.
Services.prefs.setBoolPref("devtools.cache.disabled", aDisabled);
return reconfigureTab(aTarget, options).then(() => navigationFinished);
}
@ -132,8 +141,8 @@ function initNetMonitor(aUrl, aWindow) {
yield target.makeRemote();
info("Target remoted.");
yield toggleCache(target, false);
info("Network cache disabled");
yield toggleCache(target, true);
info("Cache disabled when the current and all future toolboxes are open.");
let toolbox = yield gDevTools.showToolbox(target, "netmonitor");
info("Netork monitor pane shown successfully.");

Просмотреть файл

@ -18,7 +18,8 @@ let TEMP_PATH;
// All test are asynchronous
waitForExplicitFinish();
//Services.prefs.setBoolPref("devtools.dump.emit", true);
// Uncomment this pref to dump all devtools emitted events to the console.
// Services.prefs.setBoolPref("devtools.dump.emit", true);
// Set the testing flag on gDevTools and reset it when the test ends
gDevTools.testing = true;

Просмотреть файл

@ -54,6 +54,7 @@ function runTests()
let browser = gBrowser.selectedBrowser;
let deferred = promise.defer();
browser.addEventListener("DOMWindowCreated", function onWindowCreated() {
browser.removeEventListener("DOMWindowCreated", onWindowCreated, true);
@ -64,12 +65,12 @@ function runTests()
"After reloading, HTML is different.");
Services.prefs.clearUserPref(DEVTOOLS_CHROME_ENABLED);
finish();
deferred.resolve();
}, true);
}, true);
ok(browser.contentWindow.document.body.innerHTML !== "Modified text",
"Before reloading, HTML is intact.");
sp.reloadAndRun();
sp.reloadAndRun().then(deferred.promise).then(finish);
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -34,7 +34,7 @@ registerCleanupFunction(() => {
}
});
// Uncomment to log events
// Uncomment this pref to dump all devtools emitted events to the console.
// Services.prefs.setBoolPref("devtools.dump.emit", true);
// Set the testing flag on gDevTools and reset it when the test ends

Просмотреть файл

@ -83,11 +83,11 @@
<!ENTITY options.disableJavaScript.label "Disable JavaScript *">
<!ENTITY options.disableJavaScript.tooltip "Turning this option on will disable JavaScript for the current tab. If the tab or the toolbox is closed then this setting will be forgotten.">
<!-- LOCALIZATION NOTE (options.disableCache.label,
- options.disableCache.tooltip): This is the options panel label and
<!-- LOCALIZATION NOTE (options.disableCache.label2,
- options.disableCache.tooltip2): This is the options panel label and
- tooltip for the checkbox that toggles the cache on or off. -->
<!ENTITY options.disableCache.label "Disable Cache *">
<!ENTITY options.disableCache.tooltip "Turning this option on will disable the cache for the current tab. If the tab or the toolbox is closed then this setting will be forgotten.">
<!ENTITY options.disableCache.label2 "Disable Cache (when toolbox is open)">
<!ENTITY options.disableCache.tooltip2 "Turning this option on will disable the cache for all tabs that have the toolbox open.">
<!-- LOCALIZATION NOTE (options.selectDefaultTools.label): This is the label for
- the heading of group of checkboxes corresponding to the default developer

Просмотреть файл

@ -551,6 +551,13 @@ this.BrowserUITelemetry = {
this._countEvent(["customize", aEventType]);
},
countSearchEvent: function(source, query) {
this._countEvent(["search", source]);
if ((/^[a-zA-Z]+:[^\/\\]/).test(query)) {
this._countEvent(["search", "urlbar-keyword"]);
}
},
_durations: {
customization: [],
},

Просмотреть файл

@ -2299,10 +2299,7 @@ chatbox {
%include ../shared/contextmenu.inc.css
#context-navigation {
background-color: -moz-dialog;
padding-bottom: 2px;
margin-bottom: 2px;
-moz-appearance: menuitem;
padding-top: 4px;
}
#context-navigation > .menuitem-iconic > .menu-iconic-left {
@ -2311,7 +2308,3 @@ chatbox {
-moz-padding-end: 0 !important;
-moz-margin-end: 0 !important;
}
#context-sep-navigation {
margin-top: -4px;
}

Просмотреть файл

@ -0,0 +1,97 @@
<?xml version="1.0"?>
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg"
x="0px" y="0px"
viewBox="0 0 16 16"
enable-background="new 0 0 16 16"
xml:space="preserve">
<style>
g:not(:target) {
display: none;
}
path {
fill: menutext;
}
g.active > path {
fill: -moz-menuhovertext;
}
</style>
<g id="back">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.192,8.893L2.21,9.964c0.064,0.065,0.136,0.117,0.214,0.159
l5.199,5.301c0.607,0.63,1.465,0.764,1.915,0.297l1.02-1.082c0.449-0.467,0.32-1.357-0.288-1.99l-2.116-2.158h5.705
c0.671,0,1.215-0.544,1.215-1.215v-2.43c0-0.671-0.544-1.215-1.215-1.215H8.094l2.271-2.309c0.609-0.626,0.737-1.512,0.288-1.974
L9.635,0.278C9.184-0.188,8.327-0.055,7.718,0.575L2.479,5.901C2.38,5.946,2.289,6.008,2.21,6.089L1.192,7.171
c-0.21,0.219-0.293,0.53-0.26,0.864C0.899,8.367,0.981,8.676,1.192,8.893z"/>
</g>
<g id="forward">
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.808,7.107L13.79,6.036c-0.064-0.065-0.136-0.117-0.214-0.159
L8.377,0.576C7.77-0.054,6.912-0.189,6.461,0.278L5.441,1.36c-0.449,0.467-0.32,1.357,0.288,1.99l2.116,2.158H2.14
c-0.671,0-1.215,0.544-1.215,1.215v2.43c0,0.671,0.544,1.215,1.215,1.215h5.765l-2.271,2.309c-0.609,0.626-0.737,1.512-0.288,1.974
l1.019,1.072c0.451,0.465,1.308,0.332,1.917-0.297l5.238-5.326c0.1-0.045,0.191-0.107,0.269-0.188l1.019-1.082
c0.21-0.219,0.293-0.53,0.26-0.864C15.101,7.633,15.019,7.324,14.808,7.107z"/>
</g>
<g id="reload">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.429,8h-8l3.207-3.207C9.889,4.265,8.986,3.947,8,3.947
c-2.554,0-4.625,2.071-4.625,4.625S5.446,13.196,8,13.196c1.638,0,3.069-0.857,3.891-2.141l2.576,1.104
C13.199,14.439,10.794,16,8,16c-4.103,0-7.429-3.326-7.429-7.429S3.897,1.143,8,1.143c1.762,0,3.366,0.624,4.631,1.654L15.429,0V8z"/>
</g>
<g id="stop">
<polygon fill-rule="evenodd" clip-rule="evenodd" points="16,2.748 13.338,0.079 8.038,5.391 2.661,0 0,2.669
5.377,8.059 0.157,13.292 2.819,15.961 8.039,10.728 13.298,16 15.959,13.331 10.701,8.06"/>
</g>
<g id="bookmark">
<path d="M8.008,3.632l0.986,2.012l0.452,0.922l1.014,0.169l2.326,0.389l-1.719,1.799l-0.676,0.708l0.145,0.967
L10.896,13l-1.959-1.039l-0.937-0.497l-0.937,0.497l-1.957,1.038L5.468,10.6l0.146-0.968L4.937,8.924L3.219,7.126l2.351-0.39
l1.023-0.17l0.45-0.934L8.008,3.632 M8,0C7.72,0,7.44,0.217,7.228,0.65L5.242,4.766L0.907,5.485c-0.958,0.159-1.195,0.861-0.53,1.56
l3.113,3.258l-0.69,4.583c-0.105,0.689,0.172,1.092,0.658,1.092c0.185,0,0.399-0.058,0.635-0.181l3.906-2.072l3.906,2.072
c0.236,0.123,0.45,0.181,0.635,0.181c0.486,0,0.762-0.403,0.659-1.092l-0.687-4.583l3.109-3.255c0.666-0.702,0.428-1.404-0.53-1.564
l-4.303-0.719L8.772,0.65C8.56,0.217,8.28,0,8,0L8,0z"/>
</g>
<g id="bookmark-starred">
<path d="M8,0C7.719,0,7.438,0.217,7.225,0.651L5.233,4.773l-4.35,0.72c-0.961,0.159-1.199,0.862-0.531,1.562
l3.124,3.262l-0.692,4.589C2.679,15.596,2.957,16,3.444,16c0.185,0,0.401-0.058,0.637-0.181L8,13.744l3.919,2.075
C12.156,15.942,12.372,16,12.557,16c0.487,0,0.764-0.404,0.661-1.094l-0.69-4.589l3.12-3.259c0.668-0.703,0.43-1.406-0.532-1.566
l-4.317-0.72L8.775,0.651C8.562,0.217,8.281,0,8,0L8,0z"/>
</g>
<g id="back-active" class="active">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.192,8.893L2.21,9.964c0.064,0.065,0.136,0.117,0.214,0.159
l5.199,5.301c0.607,0.63,1.465,0.764,1.915,0.297l1.02-1.082c0.449-0.467,0.32-1.357-0.288-1.99l-2.116-2.158h5.705
c0.671,0,1.215-0.544,1.215-1.215v-2.43c0-0.671-0.544-1.215-1.215-1.215H8.094l2.271-2.309c0.609-0.626,0.737-1.512,0.288-1.974
L9.635,0.278C9.184-0.188,8.327-0.055,7.718,0.575L2.479,5.901C2.38,5.946,2.289,6.008,2.21,6.089L1.192,7.171
c-0.21,0.219-0.293,0.53-0.26,0.864C0.899,8.367,0.981,8.676,1.192,8.893z"/>
</g>
<g id="forward-active" class="active">
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.808,7.107L13.79,6.036c-0.064-0.065-0.136-0.117-0.214-0.159
L8.377,0.576C7.77-0.054,6.912-0.189,6.461,0.278L5.441,1.36c-0.449,0.467-0.32,1.357,0.288,1.99l2.116,2.158H2.14
c-0.671,0-1.215,0.544-1.215,1.215v2.43c0,0.671,0.544,1.215,1.215,1.215h5.765l-2.271,2.309c-0.609,0.626-0.737,1.512-0.288,1.974
l1.019,1.072c0.451,0.465,1.308,0.332,1.917-0.297l5.238-5.326c0.1-0.045,0.191-0.107,0.269-0.188l1.019-1.082
c0.21-0.219,0.293-0.53,0.26-0.864C15.101,7.633,15.019,7.324,14.808,7.107z"/>
</g>
<g id="reload-active" class="active">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.429,8h-8l3.207-3.207C9.889,4.265,8.986,3.947,8,3.947
c-2.554,0-4.625,2.071-4.625,4.625S5.446,13.196,8,13.196c1.638,0,3.069-0.857,3.891-2.141l2.576,1.104
C13.199,14.439,10.794,16,8,16c-4.103,0-7.429-3.326-7.429-7.429S3.897,1.143,8,1.143c1.762,0,3.366,0.624,4.631,1.654L15.429,0V8z"/>
</g>
<g id="stop-active" class="active">
<polygon fill-rule="evenodd" clip-rule="evenodd" points="16,2.748 13.338,0.079 8.038,5.391 2.661,0 0,2.669
5.377,8.059 0.157,13.292 2.819,15.961 8.039,10.728 13.298,16 15.959,13.331 10.701,8.06"/>
</g>
<g id="bookmark-active" class="active">
<path d="M8.008,3.632l0.986,2.012l0.452,0.922l1.014,0.169l2.326,0.389l-1.719,1.799l-0.676,0.708l0.145,0.967
L10.896,13l-1.959-1.039l-0.937-0.497l-0.937,0.497l-1.957,1.038L5.468,10.6l0.146-0.968L4.937,8.924L3.219,7.126l2.351-0.39
l1.023-0.17l0.45-0.934L8.008,3.632 M8,0C7.72,0,7.44,0.217,7.228,0.65L5.242,4.766L0.907,5.485c-0.958,0.159-1.195,0.861-0.53,1.56
l3.113,3.258l-0.69,4.583c-0.105,0.689,0.172,1.092,0.658,1.092c0.185,0,0.399-0.058,0.635-0.181l3.906-2.072l3.906,2.072
c0.236,0.123,0.45,0.181,0.635,0.181c0.486,0,0.762-0.403,0.659-1.092l-0.687-4.583l3.109-3.255c0.666-0.702,0.428-1.404-0.53-1.564
l-4.303-0.719L8.772,0.65C8.56,0.217,8.28,0,8,0L8,0z"/>
</g>
<g id="bookmark-starred-active" class="active">
<path d="M8,0C7.719,0,7.438,0.217,7.225,0.651L5.233,4.773l-4.35,0.72c-0.961,0.159-1.199,0.862-0.531,1.562
l3.124,3.262l-0.692,4.589C2.679,15.596,2.957,16,3.444,16c0.185,0,0.401-0.058,0.637-0.181L8,13.744l3.919,2.075
C12.156,15.942,12.372,16,12.557,16c0.487,0,0.764-0.404,0.661-1.094l-0.69-4.589l3.12-3.259c0.668-0.703,0.43-1.406-0.532-1.566
l-4.317-0.72L8.775,0.651C8.562,0.217,8.281,0,8,0L8,0z"/>
</g>
</svg>

После

Ширина:  |  Высота:  |  Размер: 6.3 KiB

Просмотреть файл

@ -23,6 +23,7 @@ browser.jar:
* skin/classic/browser/browser.css
* skin/classic/browser/browser-lightweightTheme.css
skin/classic/browser/click-to-play-warning-stripes.png
* skin/classic/browser/content-contextmenu.svg
* skin/classic/browser/engineManager.css
skin/classic/browser/fullscreen-darknoise.png
skin/classic/browser/Geolocation-16.png

Просмотреть файл

@ -0,0 +1,97 @@
<?xml version="1.0"?>
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg"
x="0px" y="0px"
viewBox="0 0 16 16"
enable-background="new 0 0 16 16"
xml:space="preserve">
<style>
g:not(:target) {
display: none;
}
path {
fill: menutext;
}
g.active > path {
fill: -moz-mac-menutextselect;
}
</style>
<g id="back">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.192,8.893L2.21,9.964c0.064,0.065,0.136,0.117,0.214,0.159
l5.199,5.301c0.607,0.63,1.465,0.764,1.915,0.297l1.02-1.082c0.449-0.467,0.32-1.357-0.288-1.99l-2.116-2.158h5.705
c0.671,0,1.215-0.544,1.215-1.215v-2.43c0-0.671-0.544-1.215-1.215-1.215H8.094l2.271-2.309c0.609-0.626,0.737-1.512,0.288-1.974
L9.635,0.278C9.184-0.188,8.327-0.055,7.718,0.575L2.479,5.901C2.38,5.946,2.289,6.008,2.21,6.089L1.192,7.171
c-0.21,0.219-0.293,0.53-0.26,0.864C0.899,8.367,0.981,8.676,1.192,8.893z"/>
</g>
<g id="forward">
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.808,7.107L13.79,6.036c-0.064-0.065-0.136-0.117-0.214-0.159
L8.377,0.576C7.77-0.054,6.912-0.189,6.461,0.278L5.441,1.36c-0.449,0.467-0.32,1.357,0.288,1.99l2.116,2.158H2.14
c-0.671,0-1.215,0.544-1.215,1.215v2.43c0,0.671,0.544,1.215,1.215,1.215h5.765l-2.271,2.309c-0.609,0.626-0.737,1.512-0.288,1.974
l1.019,1.072c0.451,0.465,1.308,0.332,1.917-0.297l5.238-5.326c0.1-0.045,0.191-0.107,0.269-0.188l1.019-1.082
c0.21-0.219,0.293-0.53,0.26-0.864C15.101,7.633,15.019,7.324,14.808,7.107z"/>
</g>
<g id="reload">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.429,8h-8l3.207-3.207C9.889,4.265,8.986,3.947,8,3.947
c-2.554,0-4.625,2.071-4.625,4.625S5.446,13.196,8,13.196c1.638,0,3.069-0.857,3.891-2.141l2.576,1.104
C13.199,14.439,10.794,16,8,16c-4.103,0-7.429-3.326-7.429-7.429S3.897,1.143,8,1.143c1.762,0,3.366,0.624,4.631,1.654L15.429,0V8z"/>
</g>
<g id="stop">
<polygon fill-rule="evenodd" clip-rule="evenodd" points="16,2.748 13.338,0.079 8.038,5.391 2.661,0 0,2.669
5.377,8.059 0.157,13.292 2.819,15.961 8.039,10.728 13.298,16 15.959,13.331 10.701,8.06"/>
</g>
<g id="bookmark">
<path d="M8.008,3.632l0.986,2.012l0.452,0.922l1.014,0.169l2.326,0.389l-1.719,1.799l-0.676,0.708l0.145,0.967
L10.896,13l-1.959-1.039l-0.937-0.497l-0.937,0.497l-1.957,1.038L5.468,10.6l0.146-0.968L4.937,8.924L3.219,7.126l2.351-0.39
l1.023-0.17l0.45-0.934L8.008,3.632 M8,0C7.72,0,7.44,0.217,7.228,0.65L5.242,4.766L0.907,5.485c-0.958,0.159-1.195,0.861-0.53,1.56
l3.113,3.258l-0.69,4.583c-0.105,0.689,0.172,1.092,0.658,1.092c0.185,0,0.399-0.058,0.635-0.181l3.906-2.072l3.906,2.072
c0.236,0.123,0.45,0.181,0.635,0.181c0.486,0,0.762-0.403,0.659-1.092l-0.687-4.583l3.109-3.255c0.666-0.702,0.428-1.404-0.53-1.564
l-4.303-0.719L8.772,0.65C8.56,0.217,8.28,0,8,0L8,0z"/>
</g>
<g id="bookmark-starred">
<path d="M8,0C7.719,0,7.438,0.217,7.225,0.651L5.233,4.773l-4.35,0.72c-0.961,0.159-1.199,0.862-0.531,1.562
l3.124,3.262l-0.692,4.589C2.679,15.596,2.957,16,3.444,16c0.185,0,0.401-0.058,0.637-0.181L8,13.744l3.919,2.075
C12.156,15.942,12.372,16,12.557,16c0.487,0,0.764-0.404,0.661-1.094l-0.69-4.589l3.12-3.259c0.668-0.703,0.43-1.406-0.532-1.566
l-4.317-0.72L8.775,0.651C8.562,0.217,8.281,0,8,0L8,0z"/>
</g>
<g id="back-active" class="active">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.192,8.893L2.21,9.964c0.064,0.065,0.136,0.117,0.214,0.159
l5.199,5.301c0.607,0.63,1.465,0.764,1.915,0.297l1.02-1.082c0.449-0.467,0.32-1.357-0.288-1.99l-2.116-2.158h5.705
c0.671,0,1.215-0.544,1.215-1.215v-2.43c0-0.671-0.544-1.215-1.215-1.215H8.094l2.271-2.309c0.609-0.626,0.737-1.512,0.288-1.974
L9.635,0.278C9.184-0.188,8.327-0.055,7.718,0.575L2.479,5.901C2.38,5.946,2.289,6.008,2.21,6.089L1.192,7.171
c-0.21,0.219-0.293,0.53-0.26,0.864C0.899,8.367,0.981,8.676,1.192,8.893z"/>
</g>
<g id="forward-active" class="active">
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.808,7.107L13.79,6.036c-0.064-0.065-0.136-0.117-0.214-0.159
L8.377,0.576C7.77-0.054,6.912-0.189,6.461,0.278L5.441,1.36c-0.449,0.467-0.32,1.357,0.288,1.99l2.116,2.158H2.14
c-0.671,0-1.215,0.544-1.215,1.215v2.43c0,0.671,0.544,1.215,1.215,1.215h5.765l-2.271,2.309c-0.609,0.626-0.737,1.512-0.288,1.974
l1.019,1.072c0.451,0.465,1.308,0.332,1.917-0.297l5.238-5.326c0.1-0.045,0.191-0.107,0.269-0.188l1.019-1.082
c0.21-0.219,0.293-0.53,0.26-0.864C15.101,7.633,15.019,7.324,14.808,7.107z"/>
</g>
<g id="reload-active" class="active">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.429,8h-8l3.207-3.207C9.889,4.265,8.986,3.947,8,3.947
c-2.554,0-4.625,2.071-4.625,4.625S5.446,13.196,8,13.196c1.638,0,3.069-0.857,3.891-2.141l2.576,1.104
C13.199,14.439,10.794,16,8,16c-4.103,0-7.429-3.326-7.429-7.429S3.897,1.143,8,1.143c1.762,0,3.366,0.624,4.631,1.654L15.429,0V8z"/>
</g>
<g id="stop-active" class="active">
<polygon fill-rule="evenodd" clip-rule="evenodd" points="16,2.748 13.338,0.079 8.038,5.391 2.661,0 0,2.669
5.377,8.059 0.157,13.292 2.819,15.961 8.039,10.728 13.298,16 15.959,13.331 10.701,8.06"/>
</g>
<g id="bookmark-active" class="active">
<path d="M8.008,3.632l0.986,2.012l0.452,0.922l1.014,0.169l2.326,0.389l-1.719,1.799l-0.676,0.708l0.145,0.967
L10.896,13l-1.959-1.039l-0.937-0.497l-0.937,0.497l-1.957,1.038L5.468,10.6l0.146-0.968L4.937,8.924L3.219,7.126l2.351-0.39
l1.023-0.17l0.45-0.934L8.008,3.632 M8,0C7.72,0,7.44,0.217,7.228,0.65L5.242,4.766L0.907,5.485c-0.958,0.159-1.195,0.861-0.53,1.56
l3.113,3.258l-0.69,4.583c-0.105,0.689,0.172,1.092,0.658,1.092c0.185,0,0.399-0.058,0.635-0.181l3.906-2.072l3.906,2.072
c0.236,0.123,0.45,0.181,0.635,0.181c0.486,0,0.762-0.403,0.659-1.092l-0.687-4.583l3.109-3.255c0.666-0.702,0.428-1.404-0.53-1.564
l-4.303-0.719L8.772,0.65C8.56,0.217,8.28,0,8,0L8,0z"/>
</g>
<g id="bookmark-starred-active" class="active">
<path d="M8,0C7.719,0,7.438,0.217,7.225,0.651L5.233,4.773l-4.35,0.72c-0.961,0.159-1.199,0.862-0.531,1.562
l3.124,3.262l-0.692,4.589C2.679,15.596,2.957,16,3.444,16c0.185,0,0.401-0.058,0.637-0.181L8,13.744l3.919,2.075
C12.156,15.942,12.372,16,12.557,16c0.487,0,0.764-0.404,0.661-1.094l-0.69-4.589l3.12-3.259c0.668-0.703,0.43-1.406-0.532-1.566
l-4.317-0.72L8.775,0.651C8.562,0.217,8.281,0,8,0L8,0z"/>
</g>
</svg>

После

Ширина:  |  Высота:  |  Размер: 6.3 KiB

Просмотреть файл

@ -23,6 +23,7 @@ browser.jar:
* skin/classic/browser/browser.css (browser.css)
* skin/classic/browser/browser-lightweightTheme.css
skin/classic/browser/click-to-play-warning-stripes.png
* skin/classic/browser/content-contextmenu.svg
* skin/classic/browser/engineManager.css (engineManager.css)
skin/classic/browser/fullscreen-darknoise.png
skin/classic/browser/Geolocation-16.png

Просмотреть файл

@ -13,29 +13,44 @@ menugroup > .menuitem-iconic[disabled="true"] > .menu-iconic-left {
-moz-appearance: none;
}
#context-navigation > #context-back > .menu-iconic-left {
list-style-image: url("chrome://browser/skin/Toolbar.png");
-moz-image-region: rect(0, 36px, 18px, 18px);
#context-back > .menu-iconic-left {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#back");
}
#context-navigation > #context-forward > .menu-iconic-left {
list-style-image: url("chrome://browser/skin/Toolbar.png");
-moz-image-region: rect(0, 72px, 18px, 54px);
#context-back[_moz-menuactive=true]:not([disabled]) > .menu-iconic-left {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#back-active");
}
#context-navigation > #context-reload > .menu-iconic-left {
list-style-image: url("chrome://browser/skin/reload-stop-go.png");
-moz-image-region: rect(0, 14px, 14px, 0);
#context-forward > .menu-iconic-left {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#forward");
}
#context-navigation > #context-stop > .menu-iconic-left {
list-style-image: url("chrome://browser/skin/reload-stop-go.png");
-moz-image-region: rect(0, 28px, 14px, 14px);
#context-forward[_moz-menuactive=true]:not([disabled]) > .menu-iconic-left {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#forward-active");
}
#context-navigation > #context-bookmarkpage > .menu-iconic-left {
list-style-image: url("chrome://browser/skin/Toolbar.png");
-moz-image-region: rect(0, 144px, 18px, 126px);
#context-reload > .menu-iconic-left {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#reload");
}
#context-reload[_moz-menuactive=true]:not([disabled]) > .menu-iconic-left {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#reload-active");
}
#context-stop > .menu-iconic-left {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#stop");
}
#context-stop[_moz-menuactive=true]:not([disabled]) > .menu-iconic-left {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#stop-active");
}
#context-bookmarkpage > .menu-iconic-left {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#bookmark");
}
#context-bookmarkpage[_moz-menuactive=true]:not([disabled]) > .menu-iconic-left {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#bookmark-active");
}
#context-back:-moz-locale-dir(rtl),
@ -45,7 +60,7 @@ menugroup > .menuitem-iconic[disabled="true"] > .menu-iconic-left {
}
#context-navigation > .menuitem-iconic > .menu-iconic-left > .menu-iconic-icon {
width: 18px;
height: 18px;
width: 16px;
height: 16px;
margin: 7px;
}

Просмотреть файл

@ -52,6 +52,8 @@ svg|line.box-model-guide-left {
/* Avoid cases where the infobar is smaller than the arrow, when the text is
short */
min-width: 75px;
/* Avoid a shadow with lightweight themes - Bug 1037908 */
text-shadow: none;
}
/* Highlighter - Node Infobar - text */

Просмотреть файл

@ -2991,9 +2991,8 @@ chatbox {
%include ../shared/contextmenu.inc.css
#context-navigation {
background-color: -moz-dialog;
padding-bottom: 2px;
margin-bottom: 2px;
background-color: menu;
padding-bottom: 4px;
}
#context-sep-navigation {

Просмотреть файл

@ -0,0 +1,97 @@
<?xml version="1.0"?>
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg"
x="0px" y="0px"
viewBox="0 0 16 16"
enable-background="new 0 0 16 16"
xml:space="preserve">
<style>
g:not(:target) {
display: none;
}
path {
fill: menutext;
}
g.active > path {
fill: -moz-menuhovertext;
}
</style>
<g id="back">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.192,8.893L2.21,9.964c0.064,0.065,0.136,0.117,0.214,0.159
l5.199,5.301c0.607,0.63,1.465,0.764,1.915,0.297l1.02-1.082c0.449-0.467,0.32-1.357-0.288-1.99l-2.116-2.158h5.705
c0.671,0,1.215-0.544,1.215-1.215v-2.43c0-0.671-0.544-1.215-1.215-1.215H8.094l2.271-2.309c0.609-0.626,0.737-1.512,0.288-1.974
L9.635,0.278C9.184-0.188,8.327-0.055,7.718,0.575L2.479,5.901C2.38,5.946,2.289,6.008,2.21,6.089L1.192,7.171
c-0.21,0.219-0.293,0.53-0.26,0.864C0.899,8.367,0.981,8.676,1.192,8.893z"/>
</g>
<g id="forward">
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.808,7.107L13.79,6.036c-0.064-0.065-0.136-0.117-0.214-0.159
L8.377,0.576C7.77-0.054,6.912-0.189,6.461,0.278L5.441,1.36c-0.449,0.467-0.32,1.357,0.288,1.99l2.116,2.158H2.14
c-0.671,0-1.215,0.544-1.215,1.215v2.43c0,0.671,0.544,1.215,1.215,1.215h5.765l-2.271,2.309c-0.609,0.626-0.737,1.512-0.288,1.974
l1.019,1.072c0.451,0.465,1.308,0.332,1.917-0.297l5.238-5.326c0.1-0.045,0.191-0.107,0.269-0.188l1.019-1.082
c0.21-0.219,0.293-0.53,0.26-0.864C15.101,7.633,15.019,7.324,14.808,7.107z"/>
</g>
<g id="reload">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.429,8h-8l3.207-3.207C9.889,4.265,8.986,3.947,8,3.947
c-2.554,0-4.625,2.071-4.625,4.625S5.446,13.196,8,13.196c1.638,0,3.069-0.857,3.891-2.141l2.576,1.104
C13.199,14.439,10.794,16,8,16c-4.103,0-7.429-3.326-7.429-7.429S3.897,1.143,8,1.143c1.762,0,3.366,0.624,4.631,1.654L15.429,0V8z"/>
</g>
<g id="stop">
<polygon fill-rule="evenodd" clip-rule="evenodd" points="16,2.748 13.338,0.079 8.038,5.391 2.661,0 0,2.669
5.377,8.059 0.157,13.292 2.819,15.961 8.039,10.728 13.298,16 15.959,13.331 10.701,8.06"/>
</g>
<g id="bookmark">
<path d="M8.008,3.632l0.986,2.012l0.452,0.922l1.014,0.169l2.326,0.389l-1.719,1.799l-0.676,0.708l0.145,0.967
L10.896,13l-1.959-1.039l-0.937-0.497l-0.937,0.497l-1.957,1.038L5.468,10.6l0.146-0.968L4.937,8.924L3.219,7.126l2.351-0.39
l1.023-0.17l0.45-0.934L8.008,3.632 M8,0C7.72,0,7.44,0.217,7.228,0.65L5.242,4.766L0.907,5.485c-0.958,0.159-1.195,0.861-0.53,1.56
l3.113,3.258l-0.69,4.583c-0.105,0.689,0.172,1.092,0.658,1.092c0.185,0,0.399-0.058,0.635-0.181l3.906-2.072l3.906,2.072
c0.236,0.123,0.45,0.181,0.635,0.181c0.486,0,0.762-0.403,0.659-1.092l-0.687-4.583l3.109-3.255c0.666-0.702,0.428-1.404-0.53-1.564
l-4.303-0.719L8.772,0.65C8.56,0.217,8.28,0,8,0L8,0z"/>
</g>
<g id="bookmark-starred">
<path d="M8,0C7.719,0,7.438,0.217,7.225,0.651L5.233,4.773l-4.35,0.72c-0.961,0.159-1.199,0.862-0.531,1.562
l3.124,3.262l-0.692,4.589C2.679,15.596,2.957,16,3.444,16c0.185,0,0.401-0.058,0.637-0.181L8,13.744l3.919,2.075
C12.156,15.942,12.372,16,12.557,16c0.487,0,0.764-0.404,0.661-1.094l-0.69-4.589l3.12-3.259c0.668-0.703,0.43-1.406-0.532-1.566
l-4.317-0.72L8.775,0.651C8.562,0.217,8.281,0,8,0L8,0z"/>
</g>
<g id="back-active" class="active">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.192,8.893L2.21,9.964c0.064,0.065,0.136,0.117,0.214,0.159
l5.199,5.301c0.607,0.63,1.465,0.764,1.915,0.297l1.02-1.082c0.449-0.467,0.32-1.357-0.288-1.99l-2.116-2.158h5.705
c0.671,0,1.215-0.544,1.215-1.215v-2.43c0-0.671-0.544-1.215-1.215-1.215H8.094l2.271-2.309c0.609-0.626,0.737-1.512,0.288-1.974
L9.635,0.278C9.184-0.188,8.327-0.055,7.718,0.575L2.479,5.901C2.38,5.946,2.289,6.008,2.21,6.089L1.192,7.171
c-0.21,0.219-0.293,0.53-0.26,0.864C0.899,8.367,0.981,8.676,1.192,8.893z"/>
</g>
<g id="forward-active" class="active">
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.808,7.107L13.79,6.036c-0.064-0.065-0.136-0.117-0.214-0.159
L8.377,0.576C7.77-0.054,6.912-0.189,6.461,0.278L5.441,1.36c-0.449,0.467-0.32,1.357,0.288,1.99l2.116,2.158H2.14
c-0.671,0-1.215,0.544-1.215,1.215v2.43c0,0.671,0.544,1.215,1.215,1.215h5.765l-2.271,2.309c-0.609,0.626-0.737,1.512-0.288,1.974
l1.019,1.072c0.451,0.465,1.308,0.332,1.917-0.297l5.238-5.326c0.1-0.045,0.191-0.107,0.269-0.188l1.019-1.082
c0.21-0.219,0.293-0.53,0.26-0.864C15.101,7.633,15.019,7.324,14.808,7.107z"/>
</g>
<g id="reload-active" class="active">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.429,8h-8l3.207-3.207C9.889,4.265,8.986,3.947,8,3.947
c-2.554,0-4.625,2.071-4.625,4.625S5.446,13.196,8,13.196c1.638,0,3.069-0.857,3.891-2.141l2.576,1.104
C13.199,14.439,10.794,16,8,16c-4.103,0-7.429-3.326-7.429-7.429S3.897,1.143,8,1.143c1.762,0,3.366,0.624,4.631,1.654L15.429,0V8z"/>
</g>
<g id="stop-active" class="active">
<polygon fill-rule="evenodd" clip-rule="evenodd" points="16,2.748 13.338,0.079 8.038,5.391 2.661,0 0,2.669
5.377,8.059 0.157,13.292 2.819,15.961 8.039,10.728 13.298,16 15.959,13.331 10.701,8.06"/>
</g>
<g id="bookmark-active" class="active">
<path d="M8.008,3.632l0.986,2.012l0.452,0.922l1.014,0.169l2.326,0.389l-1.719,1.799l-0.676,0.708l0.145,0.967
L10.896,13l-1.959-1.039l-0.937-0.497l-0.937,0.497l-1.957,1.038L5.468,10.6l0.146-0.968L4.937,8.924L3.219,7.126l2.351-0.39
l1.023-0.17l0.45-0.934L8.008,3.632 M8,0C7.72,0,7.44,0.217,7.228,0.65L5.242,4.766L0.907,5.485c-0.958,0.159-1.195,0.861-0.53,1.56
l3.113,3.258l-0.69,4.583c-0.105,0.689,0.172,1.092,0.658,1.092c0.185,0,0.399-0.058,0.635-0.181l3.906-2.072l3.906,2.072
c0.236,0.123,0.45,0.181,0.635,0.181c0.486,0,0.762-0.403,0.659-1.092l-0.687-4.583l3.109-3.255c0.666-0.702,0.428-1.404-0.53-1.564
l-4.303-0.719L8.772,0.65C8.56,0.217,8.28,0,8,0L8,0z"/>
</g>
<g id="bookmark-starred-active" class="active">
<path d="M8,0C7.719,0,7.438,0.217,7.225,0.651L5.233,4.773l-4.35,0.72c-0.961,0.159-1.199,0.862-0.531,1.562
l3.124,3.262l-0.692,4.589C2.679,15.596,2.957,16,3.444,16c0.185,0,0.401-0.058,0.637-0.181L8,13.744l3.919,2.075
C12.156,15.942,12.372,16,12.557,16c0.487,0,0.764-0.404,0.661-1.094l-0.69-4.589l3.12-3.259c0.668-0.703,0.43-1.406-0.532-1.566
l-4.317-0.72L8.775,0.651C8.562,0.217,8.281,0,8,0L8,0z"/>
</g>
</svg>

После

Ширина:  |  Высота:  |  Размер: 6.3 KiB

Просмотреть файл

@ -25,6 +25,7 @@ browser.jar:
* skin/classic/browser/browser.css
* skin/classic/browser/browser-lightweightTheme.css
skin/classic/browser/click-to-play-warning-stripes.png
* skin/classic/browser/content-contextmenu.svg
* skin/classic/browser/engineManager.css
skin/classic/browser/fullscreen-darknoise.png
skin/classic/browser/Geolocation-16.png
@ -429,6 +430,7 @@ browser.jar:
* skin/classic/aero/browser/browser.css (browser-aero.css)
* skin/classic/aero/browser/browser-lightweightTheme.css
skin/classic/aero/browser/click-to-play-warning-stripes.png
* skin/classic/aero/browser/content-contextmenu.svg
* skin/classic/aero/browser/engineManager.css
skin/classic/aero/browser/fullscreen-darknoise.png
skin/classic/aero/browser/Geolocation-16.png

Просмотреть файл

@ -9,7 +9,7 @@
android:sharedUserId="@MOZ_ANDROID_SHARED_ID@"
#endif
>
<uses-sdk android:minSdkVersion="8"
<uses-sdk android:minSdkVersion="9"
android:targetSdkVersion="@ANDROID_TARGET_SDK@"/>
#include ../services/manifests/AnnouncementsAndroidManifest_permissions.xml.in

Просмотреть файл

@ -249,8 +249,12 @@ public class RecentTabsPanel extends HomeFragment
public void run() {
mClosedTabs = closedTabs;
// Reload the cursor to show recently closed tabs.
getLoaderManager().restartLoader(LOADER_ID_RECENT_TABS, null, mCursorLoaderCallbacks);
// The fragment might have been detached before this code
// runs in the UI thread.
if (getActivity() != null) {
// Reload the cursor to show recently closed tabs.
getLoaderManager().restartLoader(LOADER_ID_RECENT_TABS, null, mCursorLoaderCallbacks);
}
}
});
}

Просмотреть файл

@ -12,6 +12,7 @@ import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
@ -20,29 +21,23 @@ public class PostSearchFragment extends Fragment {
private static final String LOGTAG = "PostSearchFragment";
private WebView webview;
public PostSearchFragment() {}
private static String HIDE_BANNER_SCRIPT = "javascript:(function(){var tag=document.createElement('style');" +
"tag.type='text/css';document.getElementsByTagName('head')[0].appendChild(tag);tag.innerText='#nav,#header{display:none}'})();";
public PostSearchFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View mainView = inflater.inflate(R.layout.search_activity_detail, container, false);
final View mainView = inflater.inflate(R.layout.search_activity_detail, container, false);
webview = (WebView) mainView.findViewById(R.id.webview);
webview.setWebViewClient(new WebViewClient(){
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
if (isSearchResultsPage(url)) {
super.onPageStarted(view, url, favicon);
} else {
webview.stopLoading();
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
startActivity(i);
}
}
});
webview.setWebViewClient(new LinkInterceptingClient());
webview.setWebChromeClient(new StyleInjectingClient());
webview.getSettings().setJavaScriptEnabled(true);
return mainView;
}
@ -66,4 +61,41 @@ public class PostSearchFragment extends Fragment {
public void setUrl(String url) {
webview.loadUrl(url);
}
/**
* A custom WebViewClient that intercepts every page load. This allows
* us to decide whether to load the url here, or send it to Android
* as an intent.
*/
private class LinkInterceptingClient extends WebViewClient {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
if (isSearchResultsPage(url)) {
super.onPageStarted(view, url, favicon);
} else {
view.stopLoading();
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
startActivity(i);
}
}
}
/**
* A custom WebChromeClient that allows us to inject CSS into
* the head of the HTML.
*
* We use the WebChromeClient because it provides a hook to the titleReceived
* event. Once the title is available, the page will have started parsing the
* head element. The script injects its CSS into the head element.
*/
private class StyleInjectingClient extends WebChromeClient {
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
view.loadUrl(HIDE_BANNER_SCRIPT);
}
}
}

Просмотреть файл

@ -14,6 +14,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="org.mozilla.search.PostSearchFragment"
android:layout_marginTop="@dimen/webview_height_offset"
android:id="@+id/postsearch"
/>

Просмотреть файл

@ -3,7 +3,8 @@
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<!--This is used to offset the webview so that it is not covered-->
<!--by the search bar. If we change the height of the search bar-->
<!--then this will need to be updated.-->
<dimen name="webview_height_offset">55dp</dimen>
</resources>

Просмотреть файл

@ -96,6 +96,7 @@ BuiltinProvider.prototype = {
"devtools/touch-events": "resource://gre/modules/devtools/touch-events",
"devtools/client": "resource://gre/modules/devtools/client",
"devtools/pretty-fast": "resource://gre/modules/devtools/pretty-fast.js",
"devtools/jsbeautify": "resource://gre/modules/devtools/jsbeautify/beautify.js",
"devtools/async-utils": "resource://gre/modules/devtools/async-utils",
"devtools/content-observer": "resource://gre/modules/devtools/content-observer",
"gcli": "resource://gre/modules/devtools/gcli",
@ -151,6 +152,7 @@ SrcdirProvider.prototype = {
let touchEventsURI = this.fileURI(OS.Path.join(toolkitDir, "touch-events"));
let clientURI = this.fileURI(OS.Path.join(toolkitDir, "client"));
let prettyFastURI = this.fileURI(OS.Path.join(toolkitDir), "pretty-fast.js");
let jsBeautifyURI = this.fileURI(OS.Path.join(toolkitDir, "jsbeautify", "beautify.js"));
let asyncUtilsURI = this.fileURI(OS.Path.join(toolkitDir), "async-utils.js");
let contentObserverURI = this.fileURI(OS.Path.join(toolkitDir), "content-observer.js");
let gcliURI = this.fileURI(OS.Path.join(toolkitDir, "gcli", "source", "lib", "gcli"));
@ -176,6 +178,7 @@ SrcdirProvider.prototype = {
"devtools/touch-events": touchEventsURI,
"devtools/client": clientURI,
"devtools/pretty-fast": prettyFastURI,
"devtools/jsbeautify": jsBeautifyURI,
"devtools/async-utils": asyncUtilsURI,
"devtools/content-observer": contentObserverURI,
"gcli": gcliURI,

Просмотреть файл

@ -447,7 +447,7 @@ DebuggerClient.prototype = {
if (this._clients.has(aTabActor)) {
let cachedTab = this._clients.get(aTabActor);
let cachedResponse = {
cacheEnabled: cachedTab.cacheEnabled,
cacheDisabled: cachedTab.cacheDisabled,
javascriptEnabled: cachedTab.javascriptEnabled,
traits: cachedTab.traits,
};
@ -1256,7 +1256,7 @@ function TabClient(aClient, aForm) {
this._actor = aForm.from;
this._threadActor = aForm.threadActor;
this.javascriptEnabled = aForm.javascriptEnabled;
this.cacheEnabled = aForm.cacheEnabled;
this.cacheDisabled = aForm.cacheDisabled;
this.thread = null;
this.request = this.client.request;
this.traits = aForm.traits || {};

Просмотреть файл

@ -7,9 +7,11 @@
const { Cc, Ci, Cu } = require("chrome");
const gcli = require("gcli/index");
const XMLHttpRequest = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"];
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
loader.lazyImporter(this, "Preferences", "resource://gre/modules/Preferences.jsm");
loader.lazyImporter(this, "js_beautify", "resource:///modules/devtools/Jsbeautify.jsm");
devtools.lazyRequireGetter(this, "beautify", "devtools/jsbeautify");
exports.items = [
{
@ -116,7 +118,7 @@ exports.items = [
let browserDoc = context.environment.chromeDocument;
let browserWindow = browserDoc.defaultView;
let gBrowser = browserWindow.gBrowser;
let result = js_beautify(xhr.responseText, opts);
let result = beautify.js(xhr.responseText, opts);
browserWindow.Scratchpad.ScratchpadManager.openScratchpad({text: result});

Просмотреть файл

@ -0,0 +1,37 @@
# UPGRADING
1. `git clone https://github.com/beautify-web/js-beautify.git`
2. Copy `js/lib/beautify.js` to `toolkit/devtools/jsbeautify/src/beautify-js.js`
3. Remove the acorn section from the file and add the following to the top:
```
const acorn = require("acorn/acorn");
```
4. Just above `function Beautifier(js_source_text, options) {` add:
```
exports.jsBeautify = js_beautify;
```
5. Copy `beautify-html.js` to `toolkit/devtools/jsbeautify/src/beautify-html.js`
6. Replace the require blocks at the bottom of the file with:
```
var beautify = require('devtools/jsbeautify');
exports.htmlBeautify = function(html_source, options) {
return style_html(html_source, options, beautify.js, beautify.css);
};
```
7. Copy `beautify-css.js` to `toolkit/devtools/jsbeautify/src/beautify-css.js`
8. Replace the global define block at the bottom of the file with:
```
exports.cssBeautify = css_beautify;
```
9. Copy `js/test/beautify-tests.js` to `toolkit/devtools/jsbeautify/src/beautify-tests.js`

Просмотреть файл

@ -0,0 +1,7 @@
var { cssBeautify } = require("devtools/toolkit/jsbeautify/beautify-css");
var { htmlBeautify } = require("devtools/toolkit/jsbeautify/beautify-html");
var { jsBeautify } = require("devtools/toolkit/jsbeautify/beautify-js");
exports.css = cssBeautify;
exports.html = htmlBeautify;
exports.js = jsBeautify;

Просмотреть файл

@ -0,0 +1,137 @@
//
// simple testing interface
// written by Einar Lielmanis, einar@jsbeautifier.org
//
// usage:
//
// var t = new SanityTest(function (x) { return x; }, 'my function');
// t.expect('input', 'output');
// t.expect('a', 'a');
// output_somewhere(t.results()); // good for <pre>, html safe-ish
// alert(t.results_raw()); // html unescaped
function SanityTest (func, name_of_test) {
var test_func = func || function (x) {
return x;
};
var test_name = name_of_test || '';
var n_failed = 0;
var n_succeeded = 0;
this.failures = [];
this.successes = [];
this.test_function = function(func, name) {
test_func = func;
test_name = name || '';
};
this.get_exitcode = function() {
return n_succeeded === 0 || n_failed !== 0 ? 1 : 0;
};
this.expect = function(parameters, expected_value) {
// multi-parameter calls not supported (I don't need them now).
var result = test_func(parameters);
// proper array checking is a pain. i'll maybe do it later, compare strings representations instead
if ((result === expected_value) || (expected_value instanceof Array && result.join(', ') == expected_value.join(', '))) {
n_succeeded += 1;
this.successes.push([test_name, parameters, expected_value, result]);
} else {
n_failed += 1;
this.failures.push([test_name, parameters, expected_value, result]);
}
};
this.results_raw = function() {
var results = '';
if (n_failed === 0) {
if (n_succeeded === 0) {
results = 'No tests run.';
} else {
results = 'All ' + n_succeeded + ' tests passed.';
}
} else {
for (var i = 0 ; i < this.failures.length; i++) {
var f = this.failures[i];
if (f[0]) {
f[0] = f[0] + ' ';
}
results += '---- ' + f[0] + 'input -------\n' + this.prettyprint(f[1]) + '\n';
results += '---- ' + f[0] + 'expected ----\n' + this.prettyprint(f[2]) + '\n';
results += '---- ' + f[0] + 'output ------\n' + this.prettyprint(f[3]) + '\n\n';
}
results += n_failed + ' tests failed.\n';
}
return results;
};
this.results = function() {
return this.lazy_escape(this.results_raw());
};
this.prettyprint = function(something, quote_strings) {
var type = typeof something;
switch(type.toLowerCase()) {
case 'string':
if (quote_strings) {
return "'" + something.replace("'", "\\'") + "'";
} else {
return something;
}
case 'number':
return '' + something;
case 'boolean':
return something ? 'true' : 'false';
case 'undefined':
return 'undefined';
case 'object':
if (something instanceof Array) {
var x = [];
var expected_index = 0;
for (var k in something) {
if (k == expected_index) {
x.push(this.prettyprint(something[k], true));
expected_index += 1;
} else {
x.push('\n' + k + ': ' + this.prettyprint(something[k], true));
}
}
return '[' + x.join(', ') + ']';
} else {
return 'object: ' + something;
}
default:
return type + ': ' + something;
}
};
this.lazy_escape = function (str) {
return str.replace(/</g, '&lt;').replace(/\>/g, '&gt;').replace(/\n/g, '<br />');
};
this.log = function () {
if (window.console) {
if (console.firebug) {
console.log.apply(console, Array.prototype.slice.call(arguments));
} else {
console.log.call(console, Array.prototype.slice.call(arguments));
}
}
};
}
if (typeof module !== 'undefined' && module.exports) {
module.exports = SanityTest;
}

Просмотреть файл

@ -0,0 +1,73 @@
/*global unescape */
/*jshint curly: false, scripturl: true */
//
// trivial bookmarklet/escaped script detector for the javascript beautifier
// written by Einar Lielmanis <einar@jsbeautifier.org>
//
// usage:
//
// if (Urlencoded.detect(some_string)) {
// var unpacked = Urlencoded.unpack(some_string);
// }
//
//
var isNode = (typeof module !== 'undefined' && module.exports);
if (isNode) {
var SanityTest = require("devtools/toolkit/jsbeautify/sanitytest");
}
var Urlencoded = {
detect: function (str) {
// the fact that script doesn't contain any space, but has %20 instead
// should be sufficient check for now.
if (str.indexOf(' ') == -1) {
if (str.indexOf('%2') != -1) return true;
if (str.replace(/[^%]+/g, '').length > 3) return true;
}
return false;
},
unpack: function (str) {
if (Urlencoded.detect(str)) {
if (str.indexOf('%2B') != -1 || str.indexOf('%2b') != -1) {
// "+" escaped as "%2B"
return unescape(str.replace(/\+/g, '%20'));
} else {
return unescape(str);
}
}
return str;
},
run_tests: function (sanity_test) {
var t = sanity_test || new SanityTest();
t.test_function(Urlencoded.detect, "Urlencoded.detect");
t.expect('', false);
t.expect('var a = b', false);
t.expect('var%20a+=+b', true);
t.expect('var%20a=b', true);
t.expect('var%20%21%22', true);
t.expect('javascript:(function(){var%20whatever={init:function(){alert(%22a%22+%22b%22)}};whatever.init()})();', true);
t.test_function(Urlencoded.unpack, 'Urlencoded.unpack');
t.expect('javascript:(function(){var%20whatever={init:function(){alert(%22a%22+%22b%22)}};whatever.init()})();',
'javascript:(function(){var whatever={init:function(){alert("a"+"b")}};whatever.init()})();'
);
t.expect('', '');
t.expect('abcd', 'abcd');
t.expect('var a = b', 'var a = b');
t.expect('var%20a=b', 'var a=b');
t.expect('var%20a=b+1', 'var a=b+1');
t.expect('var%20a=b%2b1', 'var a=b+1');
return t;
}
};
if (isNode) {
module.exports = Urlencoded;
}

Просмотреть файл

@ -0,0 +1,19 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
JS_MODULES_PATH = 'modules/devtools/jsbeautify'
EXTRA_JS_MODULES += [
'beautify.js',
'lib/sanitytest.js',
'lib/urlencode_unpacker.js',
'src/beautify-css.js',
'src/beautify-html.js',
'src/beautify-js.js',
'src/beautify-tests.js'
]

Просмотреть файл

@ -0,0 +1,367 @@
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
/*
The MIT License (MIT)
Copyright (c) 2007-2013 Einar Lielmanis and contributors.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
CSS Beautifier
---------------
Written by Harutyun Amirjanyan, (amirjanyan@gmail.com)
Based on code initially developed by: Einar Lielmanis, <einar@jsbeautifier.org>
http://jsbeautifier.org/
Usage:
css_beautify(source_text);
css_beautify(source_text, options);
The options are (default in brackets):
indent_size (4) indentation size,
indent_char (space) character to indent with,
selector_separator_newline (true) - separate selectors with newline or
not (e.g. "a,\nbr" or "a, br")
end_with_newline (false) - end with a newline
e.g
css_beautify(css_source_text, {
'indent_size': 1,
'indent_char': '\t',
'selector_separator': ' ',
'end_with_newline': false,
});
*/
// http://www.w3.org/TR/CSS21/syndata.html#tokenization
// http://www.w3.org/TR/css3-syntax/
(function () {
function css_beautify(source_text, options) {
options = options || {};
var indentSize = options.indent_size || 4;
var indentCharacter = options.indent_char || ' ';
var selectorSeparatorNewline = (options.selector_separator_newline === undefined) ? true : options.selector_separator_newline;
var endWithNewline = (options.end_with_newline === undefined) ? false : options.end_with_newline;
// compatibility
if (typeof indentSize === "string") {
indentSize = parseInt(indentSize, 10);
}
// tokenizer
var whiteRe = /^\s+$/;
var wordRe = /[\w$\-_]/;
var pos = -1,
ch;
function next() {
ch = source_text.charAt(++pos);
return ch;
}
function peek() {
return source_text.charAt(pos + 1);
}
function eatString(endChar) {
var start = pos;
while (next()) {
if (ch === "\\") {
next();
next();
} else if (ch === endChar) {
break;
} else if (ch === "\n") {
break;
}
}
return source_text.substring(start, pos + 1);
}
function eatWhitespace() {
var start = pos;
while (whiteRe.test(peek())) {
pos++;
}
return pos !== start;
}
function skipWhitespace() {
var start = pos;
do {} while (whiteRe.test(next()));
return pos !== start + 1;
}
function eatComment(singleLine) {
var start = pos;
next();
while (next()) {
if (ch === "*" && peek() === "/") {
pos++;
break;
} else if (singleLine && ch === "\n") {
break;
}
}
return source_text.substring(start, pos + 1);
}
function lookBack(str) {
return source_text.substring(pos - str.length, pos).toLowerCase() ===
str;
}
function isCommentOnLine() {
var endOfLine = source_text.indexOf('\n', pos);
if (endOfLine === -1) {
return false;
}
var restOfLine = source_text.substring(pos, endOfLine);
return restOfLine.indexOf('//') !== -1;
}
// printer
var indentString = source_text.match(/^[\r\n]*[\t ]*/)[0];
var singleIndent = new Array(indentSize + 1).join(indentCharacter);
var indentLevel = 0;
var nestedLevel = 0;
function indent() {
indentLevel++;
indentString += singleIndent;
}
function outdent() {
indentLevel--;
indentString = indentString.slice(0, -indentSize);
}
var print = {};
print["{"] = function (ch) {
print.singleSpace();
output.push(ch);
print.newLine();
};
print["}"] = function (ch) {
print.newLine();
output.push(ch);
print.newLine();
};
print._lastCharWhitespace = function () {
return whiteRe.test(output[output.length - 1]);
};
print.newLine = function (keepWhitespace) {
if (!keepWhitespace) {
while (print._lastCharWhitespace()) {
output.pop();
}
}
if (output.length) {
output.push('\n');
}
if (indentString) {
output.push(indentString);
}
};
print.singleSpace = function () {
if (output.length && !print._lastCharWhitespace()) {
output.push(' ');
}
};
var output = [];
if (indentString) {
output.push(indentString);
}
/*_____________________--------------------_____________________*/
var insideRule = false;
var enteringConditionalGroup = false;
while (true) {
var isAfterSpace = skipWhitespace();
if (!ch) {
break;
} else if (ch === '/' && peek() === '*') { /* css comment */
print.newLine();
output.push(eatComment(), "\n", indentString);
var header = lookBack("");
if (header) {
print.newLine();
}
} else if (ch === '/' && peek() === '/') { // single line comment
output.push(eatComment(true), indentString);
} else if (ch === '@') {
// strip trailing space, if present, for hash property checks
var atRule = eatString(" ").replace(/ $/, '');
// pass along the space we found as a separate item
output.push(atRule, ch);
// might be a nesting at-rule
if (atRule in css_beautify.NESTED_AT_RULE) {
nestedLevel += 1;
if (atRule in css_beautify.CONDITIONAL_GROUP_RULE) {
enteringConditionalGroup = true;
}
}
} else if (ch === '{') {
eatWhitespace();
if (peek() === '}') {
next();
output.push(" {}");
} else {
indent();
print["{"](ch);
// when entering conditional groups, only rulesets are allowed
if (enteringConditionalGroup) {
enteringConditionalGroup = false;
insideRule = (indentLevel > nestedLevel);
} else {
// otherwise, declarations are also allowed
insideRule = (indentLevel >= nestedLevel);
}
}
} else if (ch === '}') {
outdent();
print["}"](ch);
insideRule = false;
if (nestedLevel) {
nestedLevel--;
}
} else if (ch === ":") {
eatWhitespace();
if (insideRule || enteringConditionalGroup) {
// 'property: value' delimiter
// which could be in a conditional group query
output.push(ch, " ");
} else {
if (peek() === ":") {
// pseudo-element
next();
output.push("::");
} else {
// pseudo-class
output.push(ch);
}
}
} else if (ch === '"' || ch === '\'') {
output.push(eatString(ch));
} else if (ch === ';') {
if (isCommentOnLine()) {
var beforeComment = eatString('/');
var comment = eatComment(true);
output.push(beforeComment, comment.substring(1, comment.length - 1), '\n', indentString);
} else {
output.push(ch, '\n', indentString);
}
} else if (ch === '(') { // may be a url
if (lookBack("url")) {
output.push(ch);
eatWhitespace();
if (next()) {
if (ch !== ')' && ch !== '"' && ch !== '\'') {
output.push(eatString(')'));
} else {
pos--;
}
}
} else {
if (isAfterSpace) {
print.singleSpace();
}
output.push(ch);
eatWhitespace();
}
} else if (ch === ')') {
output.push(ch);
} else if (ch === ',') {
eatWhitespace();
output.push(ch);
if (!insideRule && selectorSeparatorNewline) {
print.newLine();
} else {
print.singleSpace();
}
} else if (ch === ']') {
output.push(ch);
} else if (ch === '[') {
if (isAfterSpace) {
print.singleSpace();
}
output.push(ch);
} else if (ch === '=') { // no whitespace before or after
eatWhitespace();
output.push(ch);
} else {
if (isAfterSpace) {
print.singleSpace();
}
output.push(ch);
}
}
var sweetCode = output.join('').replace(/[\n ]+$/, '');
// establish end_with_newline
var should = endWithNewline;
var actually = /\n$/.test(sweetCode);
if (should && !actually) {
sweetCode += "\n";
} else if (!should && actually) {
sweetCode = sweetCode.slice(0, -1);
}
return sweetCode;
}
// https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule
css_beautify.NESTED_AT_RULE = {
"@page": true,
"@font-face": true,
"@keyframes": true,
// also in CONDITIONAL_GROUP_RULE below
"@media": true,
"@supports": true,
"@document": true
};
css_beautify.CONDITIONAL_GROUP_RULE = {
"@media": true,
"@supports": true,
"@document": true
};
exports.cssBeautify = css_beautify;
}());

Просмотреть файл

@ -0,0 +1,822 @@
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
/*
The MIT License (MIT)
Copyright (c) 2007-2013 Einar Lielmanis and contributors.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Style HTML
---------------
Written by Nochum Sossonko, (nsossonko@hotmail.com)
Based on code initially developed by: Einar Lielmanis, <einar@jsbeautifier.org>
http://jsbeautifier.org/
Usage:
style_html(html_source);
style_html(html_source, options);
The options are:
indent_inner_html (default false) indent <head> and <body> sections,
indent_size (default 4) indentation size,
indent_char (default space) character to indent with,
wrap_line_length (default 250) - maximum amount of characters per line (0 = disable)
brace_style (default "collapse") - "collapse" | "expand" | "end-expand"
put braces on the same line as control statements (default), or put braces on own line (Allman / ANSI style), or just put end braces on own line.
unformatted (defaults to inline tags) - list of tags, that shouldn't be reformatted
indent_scripts (default normal) - "keep"|"separate"|"normal"
preserve_newlines (default true) - whether existing line breaks before elements should be preserved
Only works before elements, not inside tags or for text.
max_preserve_newlines (default unlimited) - maximum number of line breaks to be preserved in one chunk
indent_handlebars (default false) - format and indent {{#foo}} and {{/foo}}
e.g.
style_html(html_source, {
'indent_inner_html': false,
'indent_size': 2,
'indent_char': ' ',
'wrap_line_length': 78,
'brace_style': 'expand',
'unformatted': ['a', 'sub', 'sup', 'b', 'i', 'u'],
'preserve_newlines': true,
'max_preserve_newlines': 5,
'indent_handlebars': false
});
*/
(function() {
function trim(s) {
return s.replace(/^\s+|\s+$/g, '');
}
function ltrim(s) {
return s.replace(/^\s+/g, '');
}
function style_html(html_source, options, js_beautify, css_beautify) {
//Wrapper function to invoke all the necessary constructors and deal with the output.
var multi_parser,
indent_inner_html,
indent_size,
indent_character,
wrap_line_length,
brace_style,
unformatted,
preserve_newlines,
max_preserve_newlines,
indent_handlebars;
options = options || {};
// backwards compatibility to 1.3.4
if ((options.wrap_line_length === undefined || parseInt(options.wrap_line_length, 10) === 0) &&
(options.max_char !== undefined && parseInt(options.max_char, 10) !== 0)) {
options.wrap_line_length = options.max_char;
}
indent_inner_html = (options.indent_inner_html === undefined) ? false : options.indent_inner_html;
indent_size = (options.indent_size === undefined) ? 4 : parseInt(options.indent_size, 10);
indent_character = (options.indent_char === undefined) ? ' ' : options.indent_char;
brace_style = (options.brace_style === undefined) ? 'collapse' : options.brace_style;
wrap_line_length = parseInt(options.wrap_line_length, 10) === 0 ? 32786 : parseInt(options.wrap_line_length || 250, 10);
unformatted = options.unformatted || ['a', 'span', 'bdo', 'em', 'strong', 'dfn', 'code', 'samp', 'kbd', 'var', 'cite', 'abbr', 'acronym', 'q', 'sub', 'sup', 'tt', 'i', 'b', 'big', 'small', 'u', 's', 'strike', 'font', 'ins', 'del', 'pre', 'address', 'dt', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
preserve_newlines = (options.preserve_newlines === undefined) ? true : options.preserve_newlines;
max_preserve_newlines = preserve_newlines ?
(isNaN(parseInt(options.max_preserve_newlines, 10)) ? 32786 : parseInt(options.max_preserve_newlines, 10))
: 0;
indent_handlebars = (options.indent_handlebars === undefined) ? false : options.indent_handlebars;
function Parser() {
this.pos = 0; //Parser position
this.token = '';
this.current_mode = 'CONTENT'; //reflects the current Parser mode: TAG/CONTENT
this.tags = { //An object to hold tags, their position, and their parent-tags, initiated with default values
parent: 'parent1',
parentcount: 1,
parent1: ''
};
this.tag_type = '';
this.token_text = this.last_token = this.last_text = this.token_type = '';
this.newlines = 0;
this.indent_content = indent_inner_html;
this.Utils = { //Uilities made available to the various functions
whitespace: "\n\r\t ".split(''),
single_token: 'br,input,link,meta,!doctype,basefont,base,area,hr,wbr,param,img,isindex,?xml,embed,?php,?,?='.split(','), //all the single tags for HTML
extra_liners: 'head,body,/html'.split(','), //for tags that need a line of whitespace before them
in_array: function(what, arr) {
for (var i = 0; i < arr.length; i++) {
if (what === arr[i]) {
return true;
}
}
return false;
}
};
this.traverse_whitespace = function() {
var input_char = '';
input_char = this.input.charAt(this.pos);
if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
this.newlines = 0;
while (this.Utils.in_array(input_char, this.Utils.whitespace)) {
if (preserve_newlines && input_char === '\n' && this.newlines <= max_preserve_newlines) {
this.newlines += 1;
}
this.pos++;
input_char = this.input.charAt(this.pos);
}
return true;
}
return false;
};
this.get_content = function() { //function to capture regular content between tags
var input_char = '',
content = [],
space = false; //if a space is needed
while (this.input.charAt(this.pos) !== '<') {
if (this.pos >= this.input.length) {
return content.length ? content.join('') : ['', 'TK_EOF'];
}
if (this.traverse_whitespace()) {
if (content.length) {
space = true;
}
continue; //don't want to insert unnecessary space
}
if (indent_handlebars) {
// Handlebars parsing is complicated.
// {{#foo}} and {{/foo}} are formatted tags.
// {{something}} should get treated as content, except:
// {{else}} specifically behaves like {{#if}} and {{/if}}
var peek3 = this.input.substr(this.pos, 3);
if (peek3 === '{{#' || peek3 === '{{/') {
// These are tags and not content.
break;
} else if (this.input.substr(this.pos, 2) === '{{') {
if (this.get_tag(true) === '{{else}}') {
break;
}
}
}
input_char = this.input.charAt(this.pos);
this.pos++;
if (space) {
if (this.line_char_count >= this.wrap_line_length) { //insert a line when the wrap_line_length is reached
this.print_newline(false, content);
this.print_indentation(content);
} else {
this.line_char_count++;
content.push(' ');
}
space = false;
}
this.line_char_count++;
content.push(input_char); //letter at-a-time (or string) inserted to an array
}
return content.length ? content.join('') : '';
};
this.get_contents_to = function(name) { //get the full content of a script or style to pass to js_beautify
if (this.pos === this.input.length) {
return ['', 'TK_EOF'];
}
var input_char = '';
var content = '';
var reg_match = new RegExp('</' + name + '\\s*>', 'igm');
reg_match.lastIndex = this.pos;
var reg_array = reg_match.exec(this.input);
var end_script = reg_array ? reg_array.index : this.input.length; //absolute end of script
if (this.pos < end_script) { //get everything in between the script tags
content = this.input.substring(this.pos, end_script);
this.pos = end_script;
}
return content;
};
this.record_tag = function(tag) { //function to record a tag and its parent in this.tags Object
if (this.tags[tag + 'count']) { //check for the existence of this tag type
this.tags[tag + 'count']++;
this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
} else { //otherwise initialize this tag type
this.tags[tag + 'count'] = 1;
this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
}
this.tags[tag + this.tags[tag + 'count'] + 'parent'] = this.tags.parent; //set the parent (i.e. in the case of a div this.tags.div1parent)
this.tags.parent = tag + this.tags[tag + 'count']; //and make this the current parent (i.e. in the case of a div 'div1')
};
this.retrieve_tag = function(tag) { //function to retrieve the opening tag to the corresponding closer
if (this.tags[tag + 'count']) { //if the openener is not in the Object we ignore it
var temp_parent = this.tags.parent; //check to see if it's a closable tag.
while (temp_parent) { //till we reach '' (the initial value);
if (tag + this.tags[tag + 'count'] === temp_parent) { //if this is it use it
break;
}
temp_parent = this.tags[temp_parent + 'parent']; //otherwise keep on climbing up the DOM Tree
}
if (temp_parent) { //if we caught something
this.indent_level = this.tags[tag + this.tags[tag + 'count']]; //set the indent_level accordingly
this.tags.parent = this.tags[temp_parent + 'parent']; //and set the current parent
}
delete this.tags[tag + this.tags[tag + 'count'] + 'parent']; //delete the closed tags parent reference...
delete this.tags[tag + this.tags[tag + 'count']]; //...and the tag itself
if (this.tags[tag + 'count'] === 1) {
delete this.tags[tag + 'count'];
} else {
this.tags[tag + 'count']--;
}
}
};
this.indent_to_tag = function(tag) {
// Match the indentation level to the last use of this tag, but don't remove it.
if (!this.tags[tag + 'count']) {
return;
}
var temp_parent = this.tags.parent;
while (temp_parent) {
if (tag + this.tags[tag + 'count'] === temp_parent) {
break;
}
temp_parent = this.tags[temp_parent + 'parent'];
}
if (temp_parent) {
this.indent_level = this.tags[tag + this.tags[tag + 'count']];
}
};
this.get_tag = function(peek) { //function to get a full tag and parse its type
var input_char = '',
content = [],
comment = '',
space = false,
tag_start, tag_end,
tag_start_char,
orig_pos = this.pos,
orig_line_char_count = this.line_char_count;
peek = peek !== undefined ? peek : false;
do {
if (this.pos >= this.input.length) {
if (peek) {
this.pos = orig_pos;
this.line_char_count = orig_line_char_count;
}
return content.length ? content.join('') : ['', 'TK_EOF'];
}
input_char = this.input.charAt(this.pos);
this.pos++;
if (this.Utils.in_array(input_char, this.Utils.whitespace)) { //don't want to insert unnecessary space
space = true;
continue;
}
if (input_char === "'" || input_char === '"') {
input_char += this.get_unformatted(input_char);
space = true;
}
if (input_char === '=') { //no space before =
space = false;
}
if (content.length && content[content.length - 1] !== '=' && input_char !== '>' && space) {
//no space after = or before >
if (this.line_char_count >= this.wrap_line_length) {
this.print_newline(false, content);
this.print_indentation(content);
} else {
content.push(' ');
this.line_char_count++;
}
space = false;
}
if (indent_handlebars && tag_start_char === '<') {
// When inside an angle-bracket tag, put spaces around
// handlebars not inside of strings.
if ((input_char + this.input.charAt(this.pos)) === '{{') {
input_char += this.get_unformatted('}}');
if (content.length && content[content.length - 1] !== ' ' && content[content.length - 1] !== '<') {
input_char = ' ' + input_char;
}
space = true;
}
}
if (input_char === '<' && !tag_start_char) {
tag_start = this.pos - 1;
tag_start_char = '<';
}
if (indent_handlebars && !tag_start_char) {
if (content.length >= 2 && content[content.length - 1] === '{' && content[content.length - 2] == '{') {
if (input_char === '#' || input_char === '/') {
tag_start = this.pos - 3;
} else {
tag_start = this.pos - 2;
}
tag_start_char = '{';
}
}
this.line_char_count++;
content.push(input_char); //inserts character at-a-time (or string)
if (content[1] && content[1] === '!') { //if we're in a comment, do something special
// We treat all comments as literals, even more than preformatted tags
// we just look for the appropriate close tag
content = [this.get_comment(tag_start)];
break;
}
if (indent_handlebars && tag_start_char === '{' && content.length > 2 && content[content.length - 2] === '}' && content[content.length - 1] === '}') {
break;
}
} while (input_char !== '>');
var tag_complete = content.join('');
var tag_index;
var tag_offset;
if (tag_complete.indexOf(' ') !== -1) { //if there's whitespace, thats where the tag name ends
tag_index = tag_complete.indexOf(' ');
} else if (tag_complete[0] === '{') {
tag_index = tag_complete.indexOf('}');
} else { //otherwise go with the tag ending
tag_index = tag_complete.indexOf('>');
}
if (tag_complete[0] === '<' || !indent_handlebars) {
tag_offset = 1;
} else {
tag_offset = tag_complete[2] === '#' ? 3 : 2;
}
var tag_check = tag_complete.substring(tag_offset, tag_index).toLowerCase();
if (tag_complete.charAt(tag_complete.length - 2) === '/' ||
this.Utils.in_array(tag_check, this.Utils.single_token)) { //if this tag name is a single tag type (either in the list or has a closing /)
if (!peek) {
this.tag_type = 'SINGLE';
}
} else if (indent_handlebars && tag_complete[0] === '{' && tag_check === 'else') {
if (!peek) {
this.indent_to_tag('if');
this.tag_type = 'HANDLEBARS_ELSE';
this.indent_content = true;
this.traverse_whitespace();
}
} else if (tag_check === 'script' &&
(tag_complete.search('type') === -1 ||
(tag_complete.search('type') > -1 &&
tag_complete.search(/\b(text|application)\/(x-)?(javascript|ecmascript|jscript|livescript)/) > -1))) {
if (!peek) {
this.record_tag(tag_check);
this.tag_type = 'SCRIPT';
}
} else if (tag_check === 'style' &&
(tag_complete.search('type') === -1 ||
(tag_complete.search('type') > -1 && tag_complete.search('text/css') > -1))) {
if (!peek) {
this.record_tag(tag_check);
this.tag_type = 'STYLE';
}
} else if (this.is_unformatted(tag_check, unformatted)) { // do not reformat the "unformatted" tags
comment = this.get_unformatted('</' + tag_check + '>', tag_complete); //...delegate to get_unformatted function
content.push(comment);
// Preserve collapsed whitespace either before or after this tag.
if (tag_start > 0 && this.Utils.in_array(this.input.charAt(tag_start - 1), this.Utils.whitespace)) {
content.splice(0, 0, this.input.charAt(tag_start - 1));
}
tag_end = this.pos - 1;
if (this.Utils.in_array(this.input.charAt(tag_end + 1), this.Utils.whitespace)) {
content.push(this.input.charAt(tag_end + 1));
}
this.tag_type = 'SINGLE';
} else if (tag_check.charAt(0) === '!') { //peek for <! comment
// for comments content is already correct.
if (!peek) {
this.tag_type = 'SINGLE';
this.traverse_whitespace();
}
} else if (!peek) {
if (tag_check.charAt(0) === '/') { //this tag is a double tag so check for tag-ending
this.retrieve_tag(tag_check.substring(1)); //remove it and all ancestors
this.tag_type = 'END';
this.traverse_whitespace();
} else { //otherwise it's a start-tag
this.record_tag(tag_check); //push it on the tag stack
if (tag_check.toLowerCase() !== 'html') {
this.indent_content = true;
}
this.tag_type = 'START';
// Allow preserving of newlines after a start tag
this.traverse_whitespace();
}
if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) { //check if this double needs an extra line
this.print_newline(false, this.output);
if (this.output.length && this.output[this.output.length - 2] !== '\n') {
this.print_newline(true, this.output);
}
}
}
if (peek) {
this.pos = orig_pos;
this.line_char_count = orig_line_char_count;
}
return content.join(''); //returns fully formatted tag
};
this.get_comment = function(start_pos) { //function to return comment content in its entirety
// this is will have very poor perf, but will work for now.
var comment = '',
delimiter = '>',
matched = false;
this.pos = start_pos;
input_char = this.input.charAt(this.pos);
this.pos++;
while (this.pos <= this.input.length) {
comment += input_char;
// only need to check for the delimiter if the last chars match
if (comment[comment.length - 1] === delimiter[delimiter.length - 1] &&
comment.indexOf(delimiter) !== -1) {
break;
}
// only need to search for custom delimiter for the first few characters
if (!matched && comment.length < 10) {
if (comment.indexOf('<![if') === 0) { //peek for <![if conditional comment
delimiter = '<![endif]>';
matched = true;
} else if (comment.indexOf('<![cdata[') === 0) { //if it's a <[cdata[ comment...
delimiter = ']]>';
matched = true;
} else if (comment.indexOf('<![') === 0) { // some other ![ comment? ...
delimiter = ']>';
matched = true;
} else if (comment.indexOf('<!--') === 0) { // <!-- comment ...
delimiter = '-->';
matched = true;
}
}
input_char = this.input.charAt(this.pos);
this.pos++;
}
return comment;
};
this.get_unformatted = function(delimiter, orig_tag) { //function to return unformatted content in its entirety
if (orig_tag && orig_tag.toLowerCase().indexOf(delimiter) !== -1) {
return '';
}
var input_char = '';
var content = '';
var min_index = 0;
var space = true;
do {
if (this.pos >= this.input.length) {
return content;
}
input_char = this.input.charAt(this.pos);
this.pos++;
if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
if (!space) {
this.line_char_count--;
continue;
}
if (input_char === '\n' || input_char === '\r') {
content += '\n';
/* Don't change tab indention for unformatted blocks. If using code for html editing, this will greatly affect <pre> tags if they are specified in the 'unformatted array'
for (var i=0; i<this.indent_level; i++) {
content += this.indent_string;
}
space = false; //...and make sure other indentation is erased
*/
this.line_char_count = 0;
continue;
}
}
content += input_char;
this.line_char_count++;
space = true;
if (indent_handlebars && input_char === '{' && content.length && content[content.length - 2] === '{') {
// Handlebars expressions in strings should also be unformatted.
content += this.get_unformatted('}}');
// These expressions are opaque. Ignore delimiters found in them.
min_index = content.length;
}
} while (content.toLowerCase().indexOf(delimiter, min_index) === -1);
return content;
};
this.get_token = function() { //initial handler for token-retrieval
var token;
if (this.last_token === 'TK_TAG_SCRIPT' || this.last_token === 'TK_TAG_STYLE') { //check if we need to format javascript
var type = this.last_token.substr(7);
token = this.get_contents_to(type);
if (typeof token !== 'string') {
return token;
}
return [token, 'TK_' + type];
}
if (this.current_mode === 'CONTENT') {
token = this.get_content();
if (typeof token !== 'string') {
return token;
} else {
return [token, 'TK_CONTENT'];
}
}
if (this.current_mode === 'TAG') {
token = this.get_tag();
if (typeof token !== 'string') {
return token;
} else {
var tag_name_type = 'TK_TAG_' + this.tag_type;
return [token, tag_name_type];
}
}
};
this.get_full_indent = function(level) {
level = this.indent_level + level || 0;
if (level < 1) {
return '';
}
return Array(level + 1).join(this.indent_string);
};
this.is_unformatted = function(tag_check, unformatted) {
//is this an HTML5 block-level link?
if (!this.Utils.in_array(tag_check, unformatted)) {
return false;
}
if (tag_check.toLowerCase() !== 'a' || !this.Utils.in_array('a', unformatted)) {
return true;
}
//at this point we have an tag; is its first child something we want to remain
//unformatted?
var next_tag = this.get_tag(true /* peek. */ );
// test next_tag to see if it is just html tag (no external content)
var tag = (next_tag || "").match(/^\s*<\s*\/?([a-z]*)\s*[^>]*>\s*$/);
// if next_tag comes back but is not an isolated tag, then
// let's treat the 'a' tag as having content
// and respect the unformatted option
if (!tag || this.Utils.in_array(tag, unformatted)) {
return true;
} else {
return false;
}
};
this.printer = function(js_source, indent_character, indent_size, wrap_line_length, brace_style) { //handles input/output and some other printing functions
this.input = js_source || ''; //gets the input for the Parser
this.output = [];
this.indent_character = indent_character;
this.indent_string = '';
this.indent_size = indent_size;
this.brace_style = brace_style;
this.indent_level = 0;
this.wrap_line_length = wrap_line_length;
this.line_char_count = 0; //count to see if wrap_line_length was exceeded
for (var i = 0; i < this.indent_size; i++) {
this.indent_string += this.indent_character;
}
this.print_newline = function(force, arr) {
this.line_char_count = 0;
if (!arr || !arr.length) {
return;
}
if (force || (arr[arr.length - 1] !== '\n')) { //we might want the extra line
arr.push('\n');
}
};
this.print_indentation = function(arr) {
for (var i = 0; i < this.indent_level; i++) {
arr.push(this.indent_string);
this.line_char_count += this.indent_string.length;
}
};
this.print_token = function(text) {
if (text || text !== '') {
if (this.output.length && this.output[this.output.length - 1] === '\n') {
this.print_indentation(this.output);
text = ltrim(text);
}
}
this.print_token_raw(text);
};
this.print_token_raw = function(text) {
if (text && text !== '') {
if (text.length > 1 && text[text.length - 1] === '\n') {
// unformatted tags can grab newlines as their last character
this.output.push(text.slice(0, -1));
this.print_newline(false, this.output);
} else {
this.output.push(text);
}
}
for (var n = 0; n < this.newlines; n++) {
this.print_newline(n > 0, this.output);
}
this.newlines = 0;
};
this.indent = function() {
this.indent_level++;
};
this.unindent = function() {
if (this.indent_level > 0) {
this.indent_level--;
}
};
};
return this;
}
/*_____________________--------------------_____________________*/
multi_parser = new Parser(); //wrapping functions Parser
multi_parser.printer(html_source, indent_character, indent_size, wrap_line_length, brace_style); //initialize starting values
while (true) {
var t = multi_parser.get_token();
multi_parser.token_text = t[0];
multi_parser.token_type = t[1];
if (multi_parser.token_type === 'TK_EOF') {
break;
}
switch (multi_parser.token_type) {
case 'TK_TAG_START':
multi_parser.print_newline(false, multi_parser.output);
multi_parser.print_token(multi_parser.token_text);
if (multi_parser.indent_content) {
multi_parser.indent();
multi_parser.indent_content = false;
}
multi_parser.current_mode = 'CONTENT';
break;
case 'TK_TAG_STYLE':
case 'TK_TAG_SCRIPT':
multi_parser.print_newline(false, multi_parser.output);
multi_parser.print_token(multi_parser.token_text);
multi_parser.current_mode = 'CONTENT';
break;
case 'TK_TAG_END':
//Print new line only if the tag has no content and has child
if (multi_parser.last_token === 'TK_CONTENT' && multi_parser.last_text === '') {
var tag_name = multi_parser.token_text.match(/\w+/)[0];
var tag_extracted_from_last_output = null;
if (multi_parser.output.length) {
tag_extracted_from_last_output = multi_parser.output[multi_parser.output.length - 1].match(/(?:<|{{#)\s*(\w+)/);
}
if (tag_extracted_from_last_output === null ||
tag_extracted_from_last_output[1] !== tag_name) {
multi_parser.print_newline(false, multi_parser.output);
}
}
multi_parser.print_token(multi_parser.token_text);
multi_parser.current_mode = 'CONTENT';
break;
case 'TK_TAG_SINGLE':
// Don't add a newline before elements that should remain unformatted.
var tag_check = multi_parser.token_text.match(/^\s*<([a-z]+)/i);
if (!tag_check || !multi_parser.Utils.in_array(tag_check[1], unformatted)) {
multi_parser.print_newline(false, multi_parser.output);
}
multi_parser.print_token(multi_parser.token_text);
multi_parser.current_mode = 'CONTENT';
break;
case 'TK_TAG_HANDLEBARS_ELSE':
multi_parser.print_token(multi_parser.token_text);
if (multi_parser.indent_content) {
multi_parser.indent();
multi_parser.indent_content = false;
}
multi_parser.current_mode = 'CONTENT';
break;
case 'TK_CONTENT':
multi_parser.print_token(multi_parser.token_text);
multi_parser.current_mode = 'TAG';
break;
case 'TK_STYLE':
case 'TK_SCRIPT':
if (multi_parser.token_text !== '') {
multi_parser.print_newline(false, multi_parser.output);
var text = multi_parser.token_text,
_beautifier,
script_indent_level = 1;
if (multi_parser.token_type === 'TK_SCRIPT') {
_beautifier = typeof js_beautify === 'function' && js_beautify;
} else if (multi_parser.token_type === 'TK_STYLE') {
_beautifier = typeof css_beautify === 'function' && css_beautify;
}
if (options.indent_scripts === "keep") {
script_indent_level = 0;
} else if (options.indent_scripts === "separate") {
script_indent_level = -multi_parser.indent_level;
}
var indentation = multi_parser.get_full_indent(script_indent_level);
if (_beautifier) {
// call the Beautifier if avaliable
text = _beautifier(text.replace(/^\s*/, indentation), options);
} else {
// simply indent the string otherwise
var white = text.match(/^\s*/)[0];
var _level = white.match(/[^\n\r]*$/)[0].split(multi_parser.indent_string).length - 1;
var reindent = multi_parser.get_full_indent(script_indent_level - _level);
text = text.replace(/^\s*/, indentation)
.replace(/\r\n|\r|\n/g, '\n' + reindent)
.replace(/\s+$/, '');
}
if (text) {
multi_parser.print_token_raw(indentation + trim(text));
multi_parser.print_newline(false, multi_parser.output);
}
}
multi_parser.current_mode = 'TAG';
break;
}
multi_parser.last_token = multi_parser.token_type;
multi_parser.last_text = multi_parser.token_text;
}
return multi_parser.output.join('');
}
var beautify = require('devtools/jsbeautify');
exports.htmlBeautify = function(html_source, options) {
return style_html(html_source, options, beautify.js, beautify.css);
};
}());

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,18 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { require } = devtools;
var beautify = require("devtools/jsbeautify");
var SanityTest = require('devtools/toolkit/jsbeautify/sanitytest');
var Urlencoded = require('devtools/toolkit/jsbeautify/urlencode_unpacker');
var {run_beautifier_tests} = require('devtools/toolkit/jsbeautify/beautify-tests');

Просмотреть файл

@ -0,0 +1,23 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2; fill-column: 80 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
function run_test() {
var sanityTest = new SanityTest();
var results = run_beautifier_tests(sanityTest,
Urlencoded,
beautify.js,
beautify.html,
beautify.css);
for (let [test_name, parameters, expected_value, result] of sanityTest.successes) {
equal(result, expected_value, "actual result matches expected");
}
for (let [test_name, parameters, expected_value, result] of sanityTest.failures) {
equal(result, expected_value, "actual result matches expected");
}
}

Просмотреть файл

@ -0,0 +1,5 @@
[DEFAULT]
head = head_jsbeautify.js
tail =
[test.js]

Просмотреть файл

@ -8,6 +8,7 @@ PARALLEL_DIRS += [
'server',
'client',
'gcli',
'jsbeautify',
'sourcemap',
'webconsole',
'apps',

Просмотреть файл

@ -812,7 +812,7 @@ TabActor.prototype = {
return {
type: "tabAttached",
threadActor: this.threadActor.actorID,
cacheEnabled: this._getCacheEnabled(),
cacheDisabled: this._getCacheDisabled(),
javascriptEnabled: this._getJavascriptEnabled(),
traits: this.traits,
};
@ -875,10 +875,9 @@ TabActor.prototype = {
this._setJavascriptEnabled(options.javascriptEnabled);
reload = true;
}
if (typeof options.cacheEnabled !== "undefined" &&
options.cacheEnabled !== this._getCacheEnabled()) {
this._setCacheEnabled(options.cacheEnabled);
reload = true;
if (typeof options.cacheDisabled !== "undefined" &&
options.cacheDisabled !== this._getCacheDisabled()) {
this._setCacheDisabled(options.cacheDisabled);
}
// Reload if:
@ -894,12 +893,13 @@ TabActor.prototype = {
/**
* Disable or enable the cache via docShell.
*/
_setCacheEnabled: function(allow) {
_setCacheDisabled: function(disabled) {
let enable = Ci.nsIRequest.LOAD_NORMAL;
let disable = Ci.nsIRequest.LOAD_BYPASS_CACHE |
Ci.nsIRequest.INHIBIT_CACHING;
if (this.docShell) {
this.docShell.defaultLoadFlags = allow ? enable : disable;
this.docShell.defaultLoadFlags = disabled ? disable : enable;
}
},
@ -915,7 +915,7 @@ TabActor.prototype = {
/**
* Return cache allowed status.
*/
_getCacheEnabled: function() {
_getCacheDisabled: function() {
if (!this.docShell) {
// The tab is already closed.
return null;
@ -923,7 +923,7 @@ TabActor.prototype = {
let disable = Ci.nsIRequest.LOAD_BYPASS_CACHE |
Ci.nsIRequest.INHIBIT_CACHING;
return this.docShell.defaultLoadFlags !== disable;
return this.docShell.defaultLoadFlags === disable;
},
/**
@ -1152,7 +1152,11 @@ BrowserTabActor.prototype.constructor = BrowserTabActor;
Object.defineProperty(BrowserTabActor.prototype, "docShell", {
get: function() {
return this._browser.docShell;
if (this._browser) {
return this._browser.docShell;
}
// The tab is closed.
return null;
},
enumerable: true,
configurable: false

Просмотреть файл

@ -161,6 +161,11 @@ let OpenH264Provider = {
Services.obs.addObserver(this, AddonManager.OPTIONS_NOTIFICATION_DISPLAYED, false);
prefs.observe(OPENH264_PREF_ENABLED, this.onPrefEnabledChanged, this);
prefs.observe(OPENH264_PREF_PATH, this.onPrefPathChanged, this);
this.gmpPath = prefs.get(OPENH264_PREF_PATH, null);
if (this.gmpPath) {
gmpService.addPluginDirectory(this.gmpPath);
}
},
shutdown: function() {

Просмотреть файл

@ -3,7 +3,7 @@
"use strict";
const Ci = Components.interfaces;
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
const OPENH264_PLUGIN_ID = "openh264-plugin@cisco.com";
const OPENH264_PREF_BRANCH = "media.openh264.";
@ -146,3 +146,49 @@ add_task(function* test_autoUpdatePrefPersistance() {
addon.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DEFAULT;
Assert.ok(!prefs.prefHasUserValue(OPENH264_PREF_AUTOUPDATE));
});
add_task(function* test_pluginRegistration() {
let file = Services.dirsvc.get("ProfD", Ci.nsIFile);
file.append("openh264");
file.append("testDir");
let addedPath = null
let removedPath = null;
let clearPaths = () => addedPath = removedPath = null;
let MockGMPService = {
addPluginDirectory: path => addedPath = path,
removePluginDirectory: path => removedPath = path,
};
let OpenH264Scope = Cu.import("resource://gre/modules/addons/OpenH264Provider.jsm");
OpenH264Scope.gmpService = MockGMPService;
// Check that the OpenH264 plugin gets registered after startup.
Services.prefs.setCharPref(OPENH264_PREF_PATH, file.path);
clearPaths();
yield promiseRestartManager();
Assert.equal(addedPath, file.path);
Assert.equal(removedPath, null);
// Check that clearing the path doesn't trigger registration.
clearPaths();
Services.prefs.clearUserPref(OPENH264_PREF_PATH);
Assert.equal(addedPath, null);
Assert.equal(removedPath, file.path);
// Restarting with no path set should not trigger registration.
clearPaths();
yield promiseRestartManager();
Assert.equal(addedPath, null);
Assert.equal(removedPath, null);
// Changing the pref mid-session should cause unregistration and registration.
Services.prefs.setCharPref(OPENH264_PREF_PATH, file.path);
clearPaths();
let file2 = file.clone();
file2.append("foo");
Services.prefs.setCharPref(OPENH264_PREF_PATH, file2.path);
Assert.equal(addedPath, file2.path);
Assert.equal(removedPath, file.path);
});