mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 07:13:20 +00:00
merge fx-team to mozilla-central
This commit is contained in:
commit
fd5be0de78
@ -1082,9 +1082,10 @@ pref("devtools.toolbar.visible", false);
|
||||
pref("devtools.gcli.allowSet", false);
|
||||
pref("devtools.commands.dir", "");
|
||||
|
||||
// Disable the app manager
|
||||
// Enable the app manager
|
||||
pref("devtools.appmanager.enabled", true);
|
||||
pref("devtools.appmanager.firstrun", true);
|
||||
pref("devtools.appmanager.manifestEditor.enabled", false);
|
||||
|
||||
// Toolbox preferences
|
||||
pref("devtools.toolbox.footer.height", 250);
|
||||
|
@ -19,9 +19,9 @@ let gDataNotificationInfoBar = {
|
||||
},
|
||||
|
||||
get _log() {
|
||||
let log4moz = Cu.import("resource://services-common/log4moz.js", {}).Log4Moz;
|
||||
let Log = Cu.import("resource://gre/modules/Log.jsm", {}).Log;
|
||||
delete this._log;
|
||||
return this._log = log4moz.repository.getLogger("Services.DataReporting.InfoBar");
|
||||
return this._log = Log.repository.getLogger("Services.DataReporting.InfoBar");
|
||||
},
|
||||
|
||||
init: function() {
|
||||
|
@ -473,6 +473,9 @@ var PlacesCommandHook = {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// HistoryMenu
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "RecentlyClosedTabsAndWindowsMenuUtils",
|
||||
"resource:///modules/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm");
|
||||
|
||||
// View for the history menu.
|
||||
function HistoryMenu(aPopupShowingEvent) {
|
||||
// Workaround for Bug 610187. The sidebar does not include all the Places
|
||||
@ -531,45 +534,8 @@ HistoryMenu.prototype = {
|
||||
undoMenu.removeAttribute("disabled");
|
||||
|
||||
// populate menu
|
||||
var undoItems = JSON.parse(SessionStore.getClosedTabData(window));
|
||||
for (var i = 0; i < undoItems.length; i++) {
|
||||
var m = document.createElement("menuitem");
|
||||
m.setAttribute("label", undoItems[i].title);
|
||||
if (undoItems[i].image) {
|
||||
let iconURL = undoItems[i].image;
|
||||
// don't initiate a connection just to fetch a favicon (see bug 467828)
|
||||
if (/^https?:/.test(iconURL))
|
||||
iconURL = "moz-anno:favicon:" + iconURL;
|
||||
m.setAttribute("image", iconURL);
|
||||
}
|
||||
m.setAttribute("class", "menuitem-iconic bookmark-item menuitem-with-favicon");
|
||||
m.setAttribute("value", i);
|
||||
m.setAttribute("oncommand", "undoCloseTab(" + i + ");");
|
||||
|
||||
// Set the targetURI attribute so it will be shown in tooltip and trigger
|
||||
// onLinkHovered. SessionStore uses one-based indexes, so we need to
|
||||
// normalize them.
|
||||
let tabData = undoItems[i].state;
|
||||
let activeIndex = (tabData.index || tabData.entries.length) - 1;
|
||||
if (activeIndex >= 0 && tabData.entries[activeIndex])
|
||||
m.setAttribute("targetURI", tabData.entries[activeIndex].url);
|
||||
|
||||
m.addEventListener("click", this._undoCloseMiddleClick, false);
|
||||
if (i == 0)
|
||||
m.setAttribute("key", "key_undoCloseTab");
|
||||
undoPopup.appendChild(m);
|
||||
}
|
||||
|
||||
// "Restore All Tabs"
|
||||
var strings = gNavigatorBundle;
|
||||
undoPopup.appendChild(document.createElement("menuseparator"));
|
||||
m = undoPopup.appendChild(document.createElement("menuitem"));
|
||||
m.id = "menu_restoreAllTabs";
|
||||
m.setAttribute("label", strings.getString("menuRestoreAllTabs.label"));
|
||||
m.addEventListener("command", function() {
|
||||
for (var i = 0; i < undoItems.length; i++)
|
||||
undoCloseTab(0);
|
||||
}, false);
|
||||
let tabsFragment = RecentlyClosedTabsAndWindowsMenuUtils.getTabsFragment(window, "menuitem");
|
||||
undoPopup.appendChild(tabsFragment);
|
||||
},
|
||||
|
||||
toggleRecentlyClosedWindows: function PHM_toggleRecentlyClosedWindows() {
|
||||
@ -607,45 +573,8 @@ HistoryMenu.prototype = {
|
||||
undoMenu.removeAttribute("disabled");
|
||||
|
||||
// populate menu
|
||||
let undoItems = JSON.parse(SessionStore.getClosedWindowData());
|
||||
for (let i = 0; i < undoItems.length; i++) {
|
||||
let undoItem = undoItems[i];
|
||||
let otherTabsCount = undoItem.tabs.length - 1;
|
||||
let label = (otherTabsCount == 0) ? menuLabelStringSingleTab
|
||||
: PluralForm.get(otherTabsCount, menuLabelString);
|
||||
let menuLabel = label.replace("#1", undoItem.title)
|
||||
.replace("#2", otherTabsCount);
|
||||
let m = document.createElement("menuitem");
|
||||
m.setAttribute("label", menuLabel);
|
||||
let selectedTab = undoItem.tabs[undoItem.selected - 1];
|
||||
if (selectedTab.image) {
|
||||
let iconURL = selectedTab.image;
|
||||
// don't initiate a connection just to fetch a favicon (see bug 467828)
|
||||
if (/^https?:/.test(iconURL))
|
||||
iconURL = "moz-anno:favicon:" + iconURL;
|
||||
m.setAttribute("image", iconURL);
|
||||
}
|
||||
m.setAttribute("class", "menuitem-iconic bookmark-item menuitem-with-favicon");
|
||||
m.setAttribute("oncommand", "undoCloseWindow(" + i + ");");
|
||||
|
||||
// Set the targetURI attribute so it will be shown in tooltip.
|
||||
// SessionStore uses one-based indexes, so we need to normalize them.
|
||||
let activeIndex = (selectedTab.index || selectedTab.entries.length) - 1;
|
||||
if (activeIndex >= 0 && selectedTab.entries[activeIndex])
|
||||
m.setAttribute("targetURI", selectedTab.entries[activeIndex].url);
|
||||
|
||||
if (i == 0)
|
||||
m.setAttribute("key", "key_undoCloseWindow");
|
||||
undoPopup.appendChild(m);
|
||||
}
|
||||
|
||||
// "Open All in Windows"
|
||||
undoPopup.appendChild(document.createElement("menuseparator"));
|
||||
let m = undoPopup.appendChild(document.createElement("menuitem"));
|
||||
m.id = "menu_restoreAllWindows";
|
||||
m.setAttribute("label", gNavigatorBundle.getString("menuRestoreAllWindows.label"));
|
||||
m.setAttribute("oncommand",
|
||||
"for (var i = 0; i < " + undoItems.length + "; i++) undoCloseWindow();");
|
||||
let windowsFragment = RecentlyClosedTabsAndWindowsMenuUtils.getWindowsFragment(window, "menuitem");
|
||||
undoPopup.appendChild(windowsFragment);
|
||||
},
|
||||
|
||||
toggleTabsFromOtherComputers: function PHM_toggleTabsFromOtherComputers() {
|
||||
|
@ -7127,7 +7127,14 @@ function safeModeRestart()
|
||||
let rv = Services.prompt.confirmEx(window, promptTitle, promptMessage,
|
||||
buttonFlags, restartText, null, null,
|
||||
null, {});
|
||||
if (rv == 0) {
|
||||
if (rv != 0)
|
||||
return;
|
||||
|
||||
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
|
||||
.createInstance(Ci.nsISupportsPRBool);
|
||||
Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
|
||||
|
||||
if (!cancelQuit.data) {
|
||||
Services.startup.restartInSafeMode(Ci.nsIAppStartup.eAttemptQuit);
|
||||
}
|
||||
}
|
||||
|
@ -1671,9 +1671,26 @@
|
||||
throw new Error("Invalid argument: " + aCloseTabs);
|
||||
}
|
||||
|
||||
if (tabsToClose <= 1 ||
|
||||
aCloseTabs != this.closingTabsEnum.ALL ||
|
||||
!Services.prefs.getBoolPref("browser.tabs.warnOnClose"))
|
||||
let maxUndo =
|
||||
Services.prefs.getIntPref("browser.sessionstore.max_tabs_undo");
|
||||
let warnOnCloseOtherTabs =
|
||||
Services.prefs.getBoolPref("browser.tabs.warnOnCloseOtherTabs");
|
||||
let warnOnCloseWindow =
|
||||
Services.prefs.getBoolPref("browser.tabs.warnOnClose");
|
||||
let isWindowClosing = aCloseTabs == this.closingTabsEnum.ALL;
|
||||
|
||||
let skipWarning =
|
||||
// 1) If there is only one tab to close, we'll never warn the user.
|
||||
tabsToClose <= 1 ||
|
||||
// 2) If the whole window is going to be closed, don't warn the
|
||||
// user if the user has browser.tabs.warnOnClose set to false.
|
||||
(isWindowClosing && !warnOnCloseWindow) ||
|
||||
// 3) If the number of tabs are less than the undo threshold
|
||||
// or if the user has specifically opted-in to ignoring
|
||||
// this warning via the warnOnCloseOtherTabs pref.
|
||||
(!isWindowClosing && (!warnOnCloseOtherTabs ||
|
||||
tabsToClose <= maxUndo));
|
||||
if (skipWarning)
|
||||
return true;
|
||||
|
||||
var ps = Services.prompt;
|
||||
@ -1702,8 +1719,11 @@
|
||||
var reallyClose = (buttonPressed == 0);
|
||||
|
||||
// don't set the pref unless they press OK and it's false
|
||||
if (reallyClose && !warnOnClose.value)
|
||||
Services.prefs.setBoolPref("browser.tabs.warnOnClose", false);
|
||||
if (reallyClose && !warnOnClose.value) {
|
||||
let pref = isWindowClosing ? "browser.tabs.warnOnClose" :
|
||||
"browser.tabs.warnOnCloseOtherTabs";
|
||||
Services.prefs.setBoolPref(pref, false);
|
||||
}
|
||||
|
||||
return reallyClose;
|
||||
]]>
|
||||
|
@ -199,6 +199,7 @@ support-files =
|
||||
[browser_bug880101.js]
|
||||
[browser_bug882977.js]
|
||||
[browser_bug887515.js]
|
||||
[browser_bug896291_closeMaxSessionStoreTabs.js]
|
||||
[browser_bug902156.js]
|
||||
[browser_canonizeURL.js]
|
||||
[browser_clearplugindata.html]
|
||||
|
@ -0,0 +1,108 @@
|
||||
function numClosedTabs()
|
||||
Cc["@mozilla.org/browser/sessionstore;1"].
|
||||
getService(Ci.nsISessionStore).
|
||||
getNumberOfTabsClosedLast(window);
|
||||
|
||||
let originalTab;
|
||||
let maxTabsUndo;
|
||||
let maxTabsUndoPlusOne;
|
||||
let acceptRemoveAllTabsDialogListener;
|
||||
let cancelRemoveAllTabsDialogListener;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
Services.prefs.setBoolPref("browser.tabs.animate", false);
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref("browser.tabs.animate");
|
||||
|
||||
originalTab.linkedBrowser.loadURI("about:blank");
|
||||
originalTab = null;
|
||||
});
|
||||
|
||||
// Creating and throwing away this tab guarantees that the
|
||||
// number of tabs closed in the previous tab-close operation is 1.
|
||||
let throwaway_tab = gBrowser.addTab("http://mochi.test:8888/");
|
||||
gBrowser.removeTab(throwaway_tab);
|
||||
|
||||
let undoCloseTabElement = document.getElementById("context_undoCloseTab");
|
||||
updateTabContextMenu();
|
||||
is(undoCloseTabElement.label, undoCloseTabElement.getAttribute("singletablabel"),
|
||||
"The label should be showing that the command will restore a single tab");
|
||||
|
||||
originalTab = gBrowser.selectedTab;
|
||||
gBrowser.selectedBrowser.loadURI("http://mochi.test:8888/");
|
||||
|
||||
maxTabsUndo = Services.prefs.getIntPref("browser.sessionstore.max_tabs_undo");
|
||||
maxTabsUndoPlusOne = maxTabsUndo + 1;
|
||||
let numberOfTabsLoaded = 0;
|
||||
for (let i = 0; i < maxTabsUndoPlusOne; i++) {
|
||||
let tab = gBrowser.addTab("http://mochi.test:8888/");
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
|
||||
if (++numberOfTabsLoaded == maxTabsUndoPlusOne)
|
||||
verifyUndoMultipleClose();
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
|
||||
function verifyUndoMultipleClose() {
|
||||
info("all tabs opened and loaded");
|
||||
cancelRemoveAllTabsDialogListener = new WindowListener("chrome://global/content/commonDialog.xul", cancelRemoveAllTabsDialog);
|
||||
Services.wm.addListener(cancelRemoveAllTabsDialogListener);
|
||||
gBrowser.removeAllTabsBut(originalTab);
|
||||
}
|
||||
|
||||
function cancelRemoveAllTabsDialog(domWindow) {
|
||||
ok(true, "dialog appeared in response to multiple tab close action");
|
||||
domWindow.document.documentElement.cancelDialog();
|
||||
Services.wm.removeListener(cancelRemoveAllTabsDialogListener);
|
||||
|
||||
acceptRemoveAllTabsDialogListener = new WindowListener("chrome://global/content/commonDialog.xul", acceptRemoveAllTabsDialog);
|
||||
Services.wm.addListener(acceptRemoveAllTabsDialogListener);
|
||||
waitForCondition(function () gBrowser.tabs.length == 1 + maxTabsUndoPlusOne, function verifyCancel() {
|
||||
is(gBrowser.tabs.length, 1 + maxTabsUndoPlusOne, /* The '1 +' is for the original tab */
|
||||
"All tabs should still be open after the 'Cancel' option on the prompt is chosen");
|
||||
gBrowser.removeAllTabsBut(originalTab);
|
||||
}, "Waited too long to find that no tabs were closed.");
|
||||
}
|
||||
|
||||
function acceptRemoveAllTabsDialog(domWindow) {
|
||||
ok(true, "dialog appeared in response to multiple tab close action");
|
||||
domWindow.document.documentElement.acceptDialog();
|
||||
Services.wm.removeListener(acceptRemoveAllTabsDialogListener);
|
||||
|
||||
waitForCondition(function () gBrowser.tabs.length == 1, function verifyAccept() {
|
||||
is(gBrowser.tabs.length, 1,
|
||||
"All other tabs should be closed after the 'OK' option on the prompt is chosen");
|
||||
finish();
|
||||
}, "Waited too long for the other tabs to be closed.");
|
||||
}
|
||||
|
||||
function WindowListener(aURL, aCallback) {
|
||||
this.callback = aCallback;
|
||||
this.url = aURL;
|
||||
}
|
||||
WindowListener.prototype = {
|
||||
onOpenWindow: function(aXULWindow) {
|
||||
var domWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow);
|
||||
var self = this;
|
||||
domWindow.addEventListener("load", function() {
|
||||
domWindow.removeEventListener("load", arguments.callee, false);
|
||||
|
||||
info("domWindow.document.location.href: " + domWindow.document.location.href);
|
||||
if (domWindow.document.location.href != self.url)
|
||||
return;
|
||||
|
||||
// Allow other window load listeners to execute before passing to callback
|
||||
executeSoon(function() {
|
||||
self.callback(domWindow);
|
||||
});
|
||||
}, false);
|
||||
},
|
||||
onCloseWindow: function(aXULWindow) {},
|
||||
onWindowTitleChange: function(aXULWindow, aNewTitle) {}
|
||||
}
|
@ -58,10 +58,10 @@ function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let ns = {};
|
||||
Components.utils.import("resource://services-common/log4moz.js", ns);
|
||||
rootLogger = ns.Log4Moz.repository.rootLogger;
|
||||
dumpAppender = new ns.Log4Moz.DumpAppender();
|
||||
dumpAppender.level = ns.Log4Moz.Level.All;
|
||||
Components.utils.import("resource://gre/modules/Log.jsm", ns);
|
||||
rootLogger = ns.Log.repository.rootLogger;
|
||||
dumpAppender = new ns.Log.DumpAppender();
|
||||
dumpAppender.level = ns.Log.Level.All;
|
||||
rootLogger.addAppender(dumpAppender);
|
||||
|
||||
let notification = document.getElementById("global-notificationbox");
|
||||
|
@ -0,0 +1,139 @@
|
||||
/* 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/. */
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["RecentlyClosedTabsAndWindowsMenuUtils"];
|
||||
|
||||
const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
var Cr = Components.results;
|
||||
var Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
|
||||
"resource://gre/modules/PluralForm.jsm");
|
||||
|
||||
let navigatorBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
|
||||
let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
|
||||
|
||||
this.RecentlyClosedTabsAndWindowsMenuUtils = {
|
||||
|
||||
/**
|
||||
* Builds up a document fragment of UI items for the recently closed tabs.
|
||||
* @param aWindow
|
||||
* The window that the tabs were closed in.
|
||||
* @param aTagName
|
||||
* The tag name that will be used when creating the UI items.
|
||||
* @returns A document fragment with UI items for each recently closed tab.
|
||||
*/
|
||||
getTabsFragment: function(aWindow, aTagName) {
|
||||
let doc = aWindow.document;
|
||||
let fragment = doc.createDocumentFragment();
|
||||
if (ss.getClosedTabCount(aWindow) != 0) {
|
||||
let closedTabs = JSON.parse(ss.getClosedTabData(aWindow));
|
||||
for (let i = 0; i < closedTabs.length; i++) {
|
||||
let element = doc.createElementNS(kNSXUL, aTagName);
|
||||
element.setAttribute("label", closedTabs[i].title);
|
||||
if (closedTabs[i].image) {
|
||||
setImage(closedTabs[i], element);
|
||||
}
|
||||
element.setAttribute("value", i);
|
||||
if (aTagName == "menuitem") {
|
||||
element.setAttribute("class", "menuitem-iconic bookmark-item menuitem-with-favicon");
|
||||
}
|
||||
element.setAttribute("oncommand", "undoCloseTab(" + i + ");");
|
||||
|
||||
// Set the targetURI attribute so it will be shown in tooltip and trigger
|
||||
// onLinkHovered. SessionStore uses one-based indexes, so we need to
|
||||
// normalize them.
|
||||
let tabData = closedTabs[i].state;
|
||||
let activeIndex = (tabData.index || tabData.entries.length) - 1;
|
||||
if (activeIndex >= 0 && tabData.entries[activeIndex]) {
|
||||
element.setAttribute("targetURI", tabData.entries[activeIndex].url);
|
||||
}
|
||||
|
||||
element.addEventListener("click", this._undoCloseMiddleClick, false);
|
||||
if (i == 0)
|
||||
element.setAttribute("key", "key_undoCloseTab");
|
||||
fragment.appendChild(element);
|
||||
}
|
||||
|
||||
fragment.appendChild(doc.createElementNS(kNSXUL, "menuseparator"));
|
||||
let restoreAllTabs = fragment.appendChild(doc.createElementNS(kNSXUL, aTagName));
|
||||
restoreAllTabs.setAttribute("label", navigatorBundle.GetStringFromName("menuRestoreAllTabs.label"));
|
||||
restoreAllTabs.addEventListener("command", function() {
|
||||
for (var i = 0; i < closedTabs.length; i++)
|
||||
undoCloseTab(0);
|
||||
}, false);
|
||||
}
|
||||
return fragment;
|
||||
},
|
||||
|
||||
/**
|
||||
* Builds up a document fragment of UI items for the recently closed windows.
|
||||
* @param aWindow
|
||||
* A window that can be used to create the elements and document fragment.
|
||||
* @param aTagName
|
||||
* The tag name that will be used when creating the UI items.
|
||||
* @returns A document fragment with UI items for each recently closed window.
|
||||
*/
|
||||
getWindowsFragment: function(aWindow, aTagName) {
|
||||
let closedWindowData = JSON.parse(ss.getClosedWindowData());
|
||||
let fragment = aWindow.document.createDocumentFragment();
|
||||
if (closedWindowData.length != 0) {
|
||||
let menuLabelString = navigatorBundle.GetStringFromName("menuUndoCloseWindowLabel");
|
||||
let menuLabelStringSingleTab =
|
||||
navigatorBundle.GetStringFromName("menuUndoCloseWindowSingleTabLabel");
|
||||
|
||||
let doc = aWindow.document;
|
||||
for (let i = 0; i < closedWindowData.length; i++) {
|
||||
let undoItem = closedWindowData[i];
|
||||
let otherTabsCount = undoItem.tabs.length - 1;
|
||||
let label = (otherTabsCount == 0) ? menuLabelStringSingleTab
|
||||
: PluralForm.get(otherTabsCount, menuLabelString);
|
||||
let menuLabel = label.replace("#1", undoItem.title)
|
||||
.replace("#2", otherTabsCount);
|
||||
let item = doc.createElementNS(kNSXUL, aTagName);
|
||||
item.setAttribute("label", menuLabel);
|
||||
let selectedTab = undoItem.tabs[undoItem.selected - 1];
|
||||
if (selectedTab.image) {
|
||||
setImage(selectedTab, item);
|
||||
}
|
||||
if (aTagName == "menuitem") {
|
||||
item.setAttribute("class", "menuitem-iconic bookmark-item menuitem-with-favicon");
|
||||
}
|
||||
item.setAttribute("oncommand", "undoCloseWindow(" + i + ");");
|
||||
|
||||
// Set the targetURI attribute so it will be shown in tooltip.
|
||||
// SessionStore uses one-based indexes, so we need to normalize them.
|
||||
let activeIndex = (selectedTab.index || selectedTab.entries.length) - 1;
|
||||
if (activeIndex >= 0 && selectedTab.entries[activeIndex])
|
||||
item.setAttribute("targetURI", selectedTab.entries[activeIndex].url);
|
||||
|
||||
if (i == 0)
|
||||
item.setAttribute("key", "key_undoCloseWindow");
|
||||
fragment.appendChild(item);
|
||||
}
|
||||
|
||||
// "Open All in Windows"
|
||||
fragment.appendChild(doc.createElementNS(kNSXUL, "menuseparator"));
|
||||
let restoreAllWindows = fragment.appendChild(doc.createElementNS(kNSXUL, aTagName));
|
||||
restoreAllWindows.setAttribute("label", navigatorBundle.GetStringFromName("menuRestoreAllWindows.label"));
|
||||
restoreAllWindows.setAttribute("oncommand",
|
||||
"for (var i = 0; i < " + closedWindowData.length + "; i++) undoCloseWindow();");
|
||||
}
|
||||
return fragment;
|
||||
},
|
||||
};
|
||||
|
||||
function setImage(aItem, aElement) {
|
||||
let iconURL = aItem.image;
|
||||
// don't initiate a connection just to fetch a favicon (see bug 467828)
|
||||
if (/^https?:/.test(iconURL))
|
||||
iconURL = "moz-anno:favicon:" + iconURL;
|
||||
aElement.setAttribute("image", iconURL);
|
||||
}
|
@ -202,15 +202,6 @@ let SessionSaverInternal = {
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef XP_MACOSX
|
||||
// Don't save invalid states.
|
||||
// Looks like we currently have private windows, only.
|
||||
if (state.windows.length == 0) {
|
||||
stopWatchCancel("COLLECT_DATA_MS", "COLLECT_DATA_LONGEST_OP_MS");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Remove private windows from the list of closed windows.
|
||||
for (let i = state._closedWindows.length - 1; i >= 0; i--) {
|
||||
if (state._closedWindows[i].isPrivate) {
|
||||
@ -218,6 +209,13 @@ let SessionSaverInternal = {
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that we keep the previous session if we started with a single
|
||||
// private window and no non-private windows have been opened, yet.
|
||||
if (state.deferredInitialState) {
|
||||
state.windows = state.deferredInitialState.windows || [];
|
||||
delete state.deferredInitialState;
|
||||
}
|
||||
|
||||
#ifndef XP_MACOSX
|
||||
// We want to restore closed windows that are marked with _shouldRestore.
|
||||
// We're doing this here because we want to control this only when saving
|
||||
|
@ -352,7 +352,7 @@ let SessionStoreInternal = {
|
||||
|
||||
/* ........ Public Getters .............. */
|
||||
get canRestoreLastSession() {
|
||||
return this._lastSessionState;
|
||||
return !!this._lastSessionState;
|
||||
},
|
||||
|
||||
set canRestoreLastSession(val) {
|
||||
@ -728,7 +728,7 @@ let SessionStoreInternal = {
|
||||
// We're starting with a single private window. Save the state we
|
||||
// actually wanted to restore so that we can do it later in case
|
||||
// the user opens another, non-private window.
|
||||
this._deferredInitialState = aInitialState;
|
||||
this._deferredInitialState = gSessionStartup.state;
|
||||
|
||||
// Nothing to restore now, notify observers things are complete.
|
||||
Services.obs.notifyObservers(null, NOTIFY_WINDOWS_RESTORED, "");
|
||||
@ -1346,6 +1346,9 @@ let SessionStoreInternal = {
|
||||
// Don't include the last session state in getBrowserState().
|
||||
delete state.lastSessionState;
|
||||
|
||||
// Don't include any deferred initial state.
|
||||
delete state.deferredInitialState;
|
||||
|
||||
return this._toJSONString(state);
|
||||
},
|
||||
|
||||
@ -2074,6 +2077,13 @@ let SessionStoreInternal = {
|
||||
state.lastSessionState = this._lastSessionState;
|
||||
}
|
||||
|
||||
// If we were called by the SessionSaver and started with only a private
|
||||
// window we want to pass the deferred initial state to not lose the
|
||||
// previous session.
|
||||
if (this._deferredInitialState) {
|
||||
state.deferredInitialState = this._deferredInitialState;
|
||||
}
|
||||
|
||||
return state;
|
||||
},
|
||||
|
||||
@ -3524,6 +3534,14 @@ let SessionStoreInternal = {
|
||||
* @returns [defaultState, state]
|
||||
*/
|
||||
_prepDataForDeferredRestore: function ssi_prepDataForDeferredRestore(state) {
|
||||
// Make sure that we don't modify the global state as provided by
|
||||
// nsSessionStartup.state. Converting the object to a JSON string and
|
||||
// parsing it again is the easiest way to do that, although not the most
|
||||
// efficient one. Deferred sessions that don't have automatic session
|
||||
// restore enabled tend to be a lot smaller though so that this shouldn't
|
||||
// be a big perf hit.
|
||||
state = JSON.parse(JSON.stringify(state));
|
||||
|
||||
let defaultState = { windows: [], selectedWindow: 1 };
|
||||
|
||||
state.selectedWindow = state.selectedWindow || 1;
|
||||
@ -3715,9 +3733,9 @@ let SessionStoreInternal = {
|
||||
* @param aTab the which has been restored
|
||||
*/
|
||||
_sendTabRestoredNotification: function ssi_sendTabRestoredNotification(aTab) {
|
||||
let event = aTab.ownerDocument.createEvent("Events");
|
||||
event.initEvent("SSTabRestored", true, false);
|
||||
aTab.dispatchEvent(event);
|
||||
let event = aTab.ownerDocument.createEvent("Events");
|
||||
event.initEvent("SSTabRestored", true, false);
|
||||
aTab.dispatchEvent(event);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -4248,7 +4266,7 @@ let TabState = {
|
||||
}
|
||||
|
||||
if (disallow.length > 0) {
|
||||
tabData.disallow = disallow.join(",");
|
||||
tabData.disallow = disallow.join(",");
|
||||
}
|
||||
|
||||
// Save text and scroll data.
|
||||
@ -4395,9 +4413,9 @@ let TabState = {
|
||||
if (!options || !options.omitDocShellCapabilities) {
|
||||
let disallow = DocShellCapabilities.collect(browser.docShell);
|
||||
if (disallow.length > 0)
|
||||
tabData.disallow = disallow.join(",");
|
||||
tabData.disallow = disallow.join(",");
|
||||
else if (tabData.disallow)
|
||||
delete tabData.disallow;
|
||||
delete tabData.disallow;
|
||||
}
|
||||
|
||||
// Save tab attributes.
|
||||
@ -4604,5 +4622,3 @@ let TabState = {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -17,6 +17,7 @@ EXTRA_JS_MODULES = [
|
||||
'DocumentUtils.jsm',
|
||||
'Messenger.jsm',
|
||||
'PrivacyLevel.jsm',
|
||||
'RecentlyClosedTabsAndWindowsMenuUtils.jsm',
|
||||
'SessionCookies.jsm',
|
||||
'SessionHistory.jsm',
|
||||
'SessionMigration.jsm',
|
||||
|
@ -24,24 +24,31 @@ AppValidator.prototype.warning = function (message) {
|
||||
this.warnings.push(message);
|
||||
}
|
||||
|
||||
AppValidator.prototype._getPackagedManifestURL = function () {
|
||||
AppValidator.prototype._getPackagedManifestFile = function () {
|
||||
let manifestFile = FileUtils.File(this.project.location);
|
||||
if (!manifestFile.exists()) {
|
||||
this.error(strings.GetStringFromName("validator.nonExistingFolder"));
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
if (!manifestFile.isDirectory()) {
|
||||
this.error(strings.GetStringFromName("validator.expectProjectFolder"));
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
manifestFile.append("manifest.webapp");
|
||||
if (!manifestFile.exists() || !manifestFile.isFile()) {
|
||||
this.error(strings.GetStringFromName("validator.wrongManifestFileName"));
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
return manifestFile;
|
||||
};
|
||||
|
||||
AppValidator.prototype._getPackagedManifestURL = function () {
|
||||
let manifestFile = this._getPackagedManifestFile();
|
||||
if (!manifestFile) {
|
||||
return null;
|
||||
}
|
||||
return Services.io.newFileURI(manifestFile).spec;
|
||||
}
|
||||
};
|
||||
|
||||
AppValidator.prototype._fetchManifest = function (manifestURL) {
|
||||
let deferred = promise.defer();
|
||||
@ -54,7 +61,7 @@ AppValidator.prototype._fetchManifest = function (manifestURL) {
|
||||
deferred.resolve(null);
|
||||
return deferred.promise;
|
||||
}
|
||||
req.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
|
||||
req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_CACHING;
|
||||
req.onload = (function () {
|
||||
let manifest = null;
|
||||
try {
|
||||
|
106
browser/devtools/app-manager/content/manifest-editor.js
Normal file
106
browser/devtools/app-manager/content/manifest-editor.js
Normal file
@ -0,0 +1,106 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
const {VariablesView} =
|
||||
Cu.import("resource:///modules/devtools/VariablesView.jsm", {});
|
||||
|
||||
const VARIABLES_VIEW_URL =
|
||||
"chrome://browser/content/devtools/widgets/VariablesView.xul";
|
||||
|
||||
function ManifestEditor(project) {
|
||||
this.project = project;
|
||||
this._onContainerReady = this._onContainerReady.bind(this);
|
||||
this._onEval = this._onEval.bind(this);
|
||||
this._onSwitch = this._onSwitch.bind(this);
|
||||
this._onDelete = this._onDelete.bind(this);
|
||||
}
|
||||
|
||||
ManifestEditor.prototype = {
|
||||
get manifest() { return this.project.manifest; },
|
||||
|
||||
show: function(containerElement) {
|
||||
let deferred = promise.defer();
|
||||
let iframe = document.createElement("iframe");
|
||||
|
||||
iframe.addEventListener("load", function onIframeLoad() {
|
||||
iframe.removeEventListener("load", onIframeLoad, true);
|
||||
deferred.resolve(iframe.contentWindow);
|
||||
}, true);
|
||||
|
||||
iframe.setAttribute("src", VARIABLES_VIEW_URL);
|
||||
iframe.classList.add("variables-view");
|
||||
containerElement.appendChild(iframe);
|
||||
|
||||
return deferred.promise.then(this._onContainerReady);
|
||||
},
|
||||
|
||||
_onContainerReady: function(varWindow) {
|
||||
let variablesContainer = varWindow.document.querySelector("#variables");
|
||||
|
||||
let editor = this.editor = new VariablesView(variablesContainer);
|
||||
|
||||
editor.onlyEnumVisible = true;
|
||||
editor.eval = this._onEval;
|
||||
editor.switch = this._onSwitch;
|
||||
editor.delete = this._onDelete;
|
||||
|
||||
return this.update();
|
||||
},
|
||||
|
||||
_onEval: function(evalString) {
|
||||
let manifest = this.manifest;
|
||||
eval("manifest" + evalString);
|
||||
this.update();
|
||||
},
|
||||
|
||||
_onSwitch: function(variable, newName) {
|
||||
let manifest = this.manifest;
|
||||
let newSymbolicName = variable.ownerView.symbolicName +
|
||||
"['" + newName + "']";
|
||||
if (newSymbolicName == variable.symbolicName) {
|
||||
return;
|
||||
}
|
||||
|
||||
let evalString = "manifest" + newSymbolicName + " = " +
|
||||
"manifest" + variable.symbolicName + ";" +
|
||||
"delete manifest" + variable.symbolicName;
|
||||
|
||||
eval(evalString);
|
||||
this.update();
|
||||
},
|
||||
|
||||
_onDelete: function(variable) {
|
||||
let manifest = this.manifest;
|
||||
let evalString = "delete manifest" + variable.symbolicName;
|
||||
eval(evalString);
|
||||
},
|
||||
|
||||
update: function() {
|
||||
this.editor.createHierarchy();
|
||||
this.editor.rawObject = this.manifest;
|
||||
this.editor.commitHierarchy();
|
||||
|
||||
// Wait until the animation from commitHierarchy has completed
|
||||
let deferred = promise.defer();
|
||||
setTimeout(deferred.resolve, this.editor.lazyEmptyDelay + 1);
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
save: function() {
|
||||
if (this.project.type == "packaged") {
|
||||
let validator = new AppValidator(this.project);
|
||||
let manifestFile = validator._getPackagedManifestFile();
|
||||
let path = manifestFile.path;
|
||||
|
||||
let encoder = new TextEncoder();
|
||||
let data = encoder.encode(JSON.stringify(this.manifest, null, 2));
|
||||
|
||||
return OS.File.writeAtomic(path, data, { tmpPath: path + ".tmp" });
|
||||
}
|
||||
|
||||
return promise.resolve();
|
||||
}
|
||||
};
|
@ -15,9 +15,12 @@ const {AppValidator} = require("devtools/app-manager/app-validator");
|
||||
const {Services} = Cu.import("resource://gre/modules/Services.jsm");
|
||||
const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
const {installHosted, installPackaged, getTargetForApp} = require("devtools/app-actor-front");
|
||||
const {EventEmitter} = Cu.import("resource:///modules/devtools/shared/event-emitter.js");
|
||||
|
||||
const promise = require("sdk/core/promise");
|
||||
|
||||
const MANIFEST_EDITOR_ENABLED = "devtools.appmanager.manifestEditor.enabled";
|
||||
|
||||
window.addEventListener("message", function(event) {
|
||||
try {
|
||||
let json = JSON.parse(event.data);
|
||||
@ -35,12 +38,20 @@ window.addEventListener("message", function(event) {
|
||||
}, false);
|
||||
|
||||
let UI = {
|
||||
isReady: false,
|
||||
|
||||
onload: function() {
|
||||
if (Services.prefs.getBoolPref(MANIFEST_EDITOR_ENABLED)) {
|
||||
document.querySelector("#lense").setAttribute("manifest-editable", "");
|
||||
}
|
||||
|
||||
this.template = new Template(document.body, AppProjects.store, Utils.l10n);
|
||||
this.template.start();
|
||||
|
||||
AppProjects.load().then(() => {
|
||||
AppProjects.store.object.projects.forEach(UI.validate);
|
||||
this.isReady = true;
|
||||
this.emit("ready");
|
||||
});
|
||||
},
|
||||
|
||||
@ -88,11 +99,11 @@ let UI = {
|
||||
|
||||
let urlInput = document.querySelector("#url-input");
|
||||
let manifestURL = urlInput.value;
|
||||
AppProjects.addHosted(manifestURL)
|
||||
.then(function (project) {
|
||||
UI.validate(project);
|
||||
UI.selectProject(project.location);
|
||||
});
|
||||
return AppProjects.addHosted(manifestURL)
|
||||
.then(function (project) {
|
||||
UI.validate(project);
|
||||
UI.selectProject(project.location);
|
||||
});
|
||||
},
|
||||
|
||||
_getLocalIconURL: function(project, manifest) {
|
||||
@ -121,7 +132,6 @@ let UI = {
|
||||
return validation.validate()
|
||||
.then(function () {
|
||||
if (validation.manifest) {
|
||||
project.name = validation.manifest.name;
|
||||
project.icon = UI._getLocalIconURL(project, validation.manifest);
|
||||
project.manifest = validation.manifest;
|
||||
}
|
||||
@ -153,7 +163,10 @@ let UI = {
|
||||
update: function(button, location) {
|
||||
button.disabled = true;
|
||||
let project = AppProjects.get(location);
|
||||
this.validate(project)
|
||||
this.manifestEditor.save()
|
||||
.then(() => {
|
||||
return this.validate(project);
|
||||
})
|
||||
.then(() => {
|
||||
// Install the app to the device if we are connected,
|
||||
// and there is no error
|
||||
@ -386,5 +399,16 @@ let UI = {
|
||||
let lense = document.querySelector("#lense");
|
||||
lense.setAttribute("template-for", template);
|
||||
this.template._processFor(lense);
|
||||
|
||||
let project = projects[idx];
|
||||
this._showManifestEditor(project).then(() => this.emit("project-selected"));
|
||||
},
|
||||
}
|
||||
|
||||
_showManifestEditor: function(project) {
|
||||
let editorContainer = document.querySelector("#lense .manifest-editor");
|
||||
this.manifestEditor = new ManifestEditor(project);
|
||||
return this.manifestEditor.show(editorContainer);
|
||||
}
|
||||
};
|
||||
|
||||
EventEmitter.decorate(UI);
|
||||
|
@ -14,6 +14,10 @@
|
||||
<base href="chrome://browser/content/devtools/app-manager/"></base>
|
||||
<title>&projects.title;</title>
|
||||
<link rel="stylesheet" href="chrome://browser/skin/devtools/app-manager/projects.css" type="text/css"/>
|
||||
<script type="application/javascript;version=1.8" src="utils.js"></script>
|
||||
<script type="application/javascript;version=1.8" src="projects.js"></script>
|
||||
<script type="application/javascript;version=1.8" src="template.js"></script>
|
||||
<script type="application/javascript;version=1.8" src="manifest-editor.js"></script>
|
||||
</head>
|
||||
|
||||
<body onload="UI.onload()">
|
||||
@ -25,7 +29,7 @@
|
||||
<div id="new-packaged-project" onclick="UI.addPackaged()" title="&projects.addPackagedTooltip;">&projects.addPackaged;</div>
|
||||
<div id="new-hosted-project">&projects.addHosted;
|
||||
<form onsubmit="UI.addHosted(); return false;" id="new-hosted-project-wrapper">
|
||||
<input value="" id="url-input" type="url" required="true" pattern="https?://.+" placeholder="&projects.hostedManifestPlaceHolder2;" size="50" />
|
||||
<input value="" id="url-input" type="url" required="true" pattern="(https?|chrome)://.+" placeholder="&projects.hostedManifestPlaceHolder2;" size="50" />
|
||||
<div onclick="UI.addHosted()" id="new-hosted-project-click" title="&projects.addHostedTooltip;"></div>
|
||||
<input type="submit" hidden="true"></input>
|
||||
</form>
|
||||
@ -40,7 +44,7 @@
|
||||
<img class="project-item-icon" template='{"type":"attribute","path":"icon","name":"src"}' />
|
||||
<div class="project-item-meta">
|
||||
<div class="button-remove" onclick="UI.remove(this.dataset.location, event)" template='{"type":"attribute","path":"location","name":"data-location"}' title="&projects.removeAppFromList;"></div>
|
||||
<strong template='{"type":"textContent","path":"name"}'></strong>
|
||||
<strong template='{"type":"textContent","path":"manifest.name"}'></strong>
|
||||
<span class="project-item-type" template='{"type":"textContent","path":"type"}'></span>
|
||||
<p class="project-item-description" template='{"type":"textContent","path":"manifest.description"}'></p>
|
||||
<div template='{"type":"attribute","path":"validationStatus","name":"status"}'>
|
||||
@ -56,9 +60,9 @@
|
||||
<div class="project-details" template='{"type":"attribute","path":"validationStatus","name":"status"}'>
|
||||
<div class="project-header">
|
||||
<img class="project-icon" template='{"type":"attribute","path":"icon","name":"src"}'/>
|
||||
<div class="project-details">
|
||||
<div class="project-metadata">
|
||||
<div class="project-title">
|
||||
<h1 template='{"type":"textContent","path":"name"}'></h1>
|
||||
<h1 template='{"type":"textContent","path":"manifest.name"}'></h1>
|
||||
<div class="project-status" template='{"type":"attribute","path":"validationStatus","name":"status"}'>
|
||||
<p class="project-validation" template='{"type":"textContent","path":"validationStatus"}'></p>
|
||||
<p class="project-type" template='{"type":"textContent","path":"type"}'></p>
|
||||
@ -76,11 +80,9 @@
|
||||
<div class="project-errors" template='{"type":"textContent","path":"errors"}'></div>
|
||||
<div class="project-warnings" template='{"type":"textContent","path":"warnings"}'></div>
|
||||
</div>
|
||||
<div class="manifest-editor">
|
||||
<h2>&projects.manifestEditor;</h2>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script type="application/javascript;version=1.8" src="utils.js"></script>
|
||||
<script type="application/javascript;version=1.8" src="projects.js"></script>
|
||||
<script type="application/javascript;version=1.8" src="template.js"></script>
|
||||
</html>
|
||||
|
6
browser/devtools/app-manager/test/browser.ini
Normal file
6
browser/devtools/app-manager/test/browser.ini
Normal file
@ -0,0 +1,6 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
head.js
|
||||
hosted_app.manifest
|
||||
|
||||
[browser_manifest_editor.js]
|
54
browser/devtools/app-manager/test/browser_manifest_editor.js
Normal file
54
browser/devtools/app-manager/test/browser_manifest_editor.js
Normal file
@ -0,0 +1,54 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
const {Services} = Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const MANIFEST_EDITOR_ENABLED = "devtools.appmanager.manifestEditor.enabled";
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
Task.spawn(function() {
|
||||
Services.prefs.setBoolPref(MANIFEST_EDITOR_ENABLED, true);
|
||||
let tab = yield openAppManager();
|
||||
yield selectProjectsPanel();
|
||||
yield addSampleHostedApp();
|
||||
yield showSampleProjectDetails();
|
||||
yield changeManifestValue("name", "the best app");
|
||||
yield removeSampleHostedApp();
|
||||
yield removeTab(tab);
|
||||
Services.prefs.setBoolPref(MANIFEST_EDITOR_ENABLED, false);
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
function changeManifestValue(key, value) {
|
||||
return Task.spawn(function() {
|
||||
let manifestWindow = getManifestWindow();
|
||||
let manifestEditor = getProjectsWindow().UI.manifestEditor;
|
||||
|
||||
let propElem = manifestWindow.document
|
||||
.querySelector("[id ^= '" + key + "']");
|
||||
is(propElem.querySelector(".name").value, key,
|
||||
"Key doesn't match expected value");
|
||||
|
||||
let valueElem = propElem.querySelector(".value");
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, valueElem, manifestWindow);
|
||||
|
||||
let valueInput = propElem.querySelector(".element-value-input");
|
||||
valueInput.value = '"' + value + '"';
|
||||
EventUtils.sendKey("RETURN", manifestWindow);
|
||||
|
||||
// Wait until the animation from commitHierarchy has completed
|
||||
yield waitForTime(manifestEditor.editor.lazyEmptyDelay + 1);
|
||||
// Elements have all been replaced, re-select them
|
||||
propElem = manifestWindow.document.querySelector("[id ^= '" + key + "']");
|
||||
valueElem = propElem.querySelector(".value");
|
||||
is(valueElem.value, '"' + value + '"',
|
||||
"Value doesn't match expected value");
|
||||
|
||||
is(manifestEditor.manifest[key], value,
|
||||
"Manifest doesn't contain expected value");
|
||||
});
|
||||
}
|
152
browser/devtools/app-manager/test/head.js
Normal file
152
browser/devtools/app-manager/test/head.js
Normal file
@ -0,0 +1,152 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
const {utils: Cu} = Components;
|
||||
|
||||
const {Promise: promise} =
|
||||
Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
|
||||
const {devtools} =
|
||||
Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
const {require} = devtools;
|
||||
|
||||
const {AppProjects} = require("devtools/app-manager/app-projects");
|
||||
|
||||
const APP_MANAGER_URL = "about:app-manager";
|
||||
const TEST_BASE =
|
||||
"chrome://mochitests/content/browser/browser/devtools/app-manager/test/";
|
||||
const HOSTED_APP_MANIFEST = TEST_BASE + "hosted_app.manifest";
|
||||
|
||||
function addTab(url, targetWindow = window) {
|
||||
info("Adding tab: " + url);
|
||||
|
||||
let deferred = promise.defer();
|
||||
let targetBrowser = targetWindow.gBrowser;
|
||||
|
||||
targetWindow.focus();
|
||||
let tab = targetBrowser.selectedTab = targetBrowser.addTab(url);
|
||||
let linkedBrowser = tab.linkedBrowser;
|
||||
|
||||
linkedBrowser.addEventListener("load", function onLoad() {
|
||||
linkedBrowser.removeEventListener("load", onLoad, true);
|
||||
info("Tab added and finished loading: " + url);
|
||||
deferred.resolve(tab);
|
||||
}, true);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function removeTab(tab, targetWindow = window) {
|
||||
info("Removing tab.");
|
||||
|
||||
let deferred = promise.defer();
|
||||
let targetBrowser = targetWindow.gBrowser;
|
||||
let tabContainer = targetBrowser.tabContainer;
|
||||
|
||||
tabContainer.addEventListener("TabClose", function onClose(aEvent) {
|
||||
tabContainer.removeEventListener("TabClose", onClose, false);
|
||||
info("Tab removed and finished closing.");
|
||||
deferred.resolve();
|
||||
}, false);
|
||||
|
||||
targetBrowser.removeTab(tab);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function openAppManager() {
|
||||
return addTab(APP_MANAGER_URL);
|
||||
}
|
||||
|
||||
function addSampleHostedApp() {
|
||||
info("Adding sample hosted app");
|
||||
let projectsWindow = getProjectsWindow();
|
||||
let projectsDocument = projectsWindow.document;
|
||||
let url = projectsDocument.querySelector("#url-input");
|
||||
url.value = HOSTED_APP_MANIFEST;
|
||||
return projectsWindow.UI.addHosted();
|
||||
}
|
||||
|
||||
function removeSampleHostedApp() {
|
||||
info("Removing sample hosted app");
|
||||
return AppProjects.remove(HOSTED_APP_MANIFEST);
|
||||
}
|
||||
|
||||
function getProjectsWindow() {
|
||||
return content.document.querySelector(".projects-panel").contentWindow;
|
||||
}
|
||||
|
||||
function getManifestWindow() {
|
||||
return getProjectsWindow().document.querySelector(".variables-view")
|
||||
.contentWindow;
|
||||
}
|
||||
|
||||
function waitForProjectsPanel(deferred = promise.defer()) {
|
||||
info("Wait for projects panel");
|
||||
|
||||
let projectsWindow = getProjectsWindow();
|
||||
let projectsUI = projectsWindow.UI;
|
||||
if (!projectsUI) {
|
||||
projectsWindow.addEventListener("load", function onLoad() {
|
||||
projectsWindow.removeEventListener("load", onLoad);
|
||||
waitForProjectsPanel(deferred);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
if (projectsUI.isReady) {
|
||||
deferred.resolve();
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
projectsUI.once("ready", deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function selectProjectsPanel() {
|
||||
return Task.spawn(function() {
|
||||
let projectsButton = content.document.querySelector(".projects-button");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, projectsButton, content);
|
||||
|
||||
yield waitForProjectsPanel();
|
||||
});
|
||||
}
|
||||
|
||||
function waitForProjectSelection() {
|
||||
info("Wait for project selection");
|
||||
|
||||
let deferred = promise.defer();
|
||||
getProjectsWindow().UI.once("project-selected", deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function selectFirstProject() {
|
||||
return Task.spawn(function() {
|
||||
let projectsFrame = content.document.querySelector(".projects-panel");
|
||||
let projectsWindow = projectsFrame.contentWindow;
|
||||
let projectsDoc = projectsWindow.document;
|
||||
let projectItem = projectsDoc.querySelector(".project-item");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, projectItem, projectsWindow);
|
||||
|
||||
yield waitForProjectSelection();
|
||||
});
|
||||
}
|
||||
|
||||
function showSampleProjectDetails() {
|
||||
return Task.spawn(function() {
|
||||
yield selectProjectsPanel();
|
||||
yield selectFirstProject();
|
||||
});
|
||||
}
|
||||
|
||||
function waitForTick() {
|
||||
let deferred = promise.defer();
|
||||
executeSoon(deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function waitForTime(aDelay) {
|
||||
let deferred = promise.defer();
|
||||
setTimeout(deferred.resolve, aDelay);
|
||||
return deferred.promise;
|
||||
}
|
@ -4,5 +4,5 @@
|
||||
# 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/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser.ini']
|
||||
MOCHITEST_CHROME_MANIFESTS += ['chrome.ini']
|
||||
|
||||
|
@ -100,19 +100,26 @@ function test() {
|
||||
ok(!testScope.expanded,
|
||||
"The testScope should remember it is collapsed after it is reshown.");
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "mousedown", button: 1 },
|
||||
testScope.target.querySelector(".title"),
|
||||
aPanel.panelWin);
|
||||
|
||||
ok(!testScope.expanded,
|
||||
"Clicking the testScope title with the right mouse button should't expand it.");
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
testScope.target.querySelector(".title"),
|
||||
aPanel.panelWin);
|
||||
|
||||
ok(testScope.expanded,
|
||||
"Clicking the testScope tilte should expand it.");
|
||||
"Clicking the testScope title should expand it.");
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
testScope.target.querySelector(".title"),
|
||||
aPanel.panelWin);
|
||||
|
||||
ok(!testScope.expanded,
|
||||
"Clicking again the testScope tilte should collapse it.");
|
||||
"Clicking again the testScope title should collapse it.");
|
||||
|
||||
closeDebuggerAndFinish(aPanel);
|
||||
});
|
||||
|
@ -45,6 +45,6 @@
|
||||
<section id="connecting">
|
||||
<p><img src="chrome://browser/skin/tabbrowser/loading.png"></img> &connecting;</p>
|
||||
</section>
|
||||
<footer>&help;</footer>
|
||||
<footer>&help2;</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -743,6 +743,15 @@ InspectorPanel.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Trigger a high-priority layout change for things that need to be
|
||||
* updated immediately
|
||||
*/
|
||||
immediateLayoutChange: function Inspector_immediateLayoutChange()
|
||||
{
|
||||
this.emit("layout-change");
|
||||
},
|
||||
|
||||
/**
|
||||
* Schedule a low-priority change event for things like paint
|
||||
* and resize.
|
||||
|
@ -17,7 +17,7 @@ function test() {
|
||||
}
|
||||
|
||||
|
||||
function getInspectorProp(aName)
|
||||
function getInspectorComputedProp(aName)
|
||||
{
|
||||
let computedview = inspector.sidebar.getWindowForTab("computedview").computedview.view;
|
||||
for each (let view in computedview.propertyViews) {
|
||||
@ -28,6 +28,19 @@ function test() {
|
||||
return null;
|
||||
}
|
||||
|
||||
function getInspectorRuleProp(aName)
|
||||
{
|
||||
let ruleview = inspector.sidebar.getWindowForTab("ruleview").ruleview.view;
|
||||
let inlineStyles = ruleview._elementStyle.rules[0];
|
||||
|
||||
for each (let prop in inlineStyles.textProps) {
|
||||
if (prop.name == aName) {
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function runInspectorTests(aInspector)
|
||||
{
|
||||
inspector = aInspector;
|
||||
@ -40,59 +53,97 @@ function test() {
|
||||
testDiv.style.fontSize = "10px";
|
||||
|
||||
// Start up the style inspector panel...
|
||||
inspector.once("computed-view-refreshed", stylePanelTests);
|
||||
inspector.once("computed-view-refreshed", computedStylePanelTests);
|
||||
|
||||
inspector.selection.setNode(testDiv);
|
||||
});
|
||||
}
|
||||
|
||||
function stylePanelTests()
|
||||
function computedStylePanelTests()
|
||||
{
|
||||
let computedview = inspector.sidebar.getWindowForTab("computedview").computedview;
|
||||
ok(computedview, "Style Panel has a cssHtmlTree");
|
||||
|
||||
let propView = getInspectorProp("font-size");
|
||||
let propView = getInspectorComputedProp("font-size");
|
||||
is(propView.value, "10px", "Style inspector should be showing the correct font size.");
|
||||
|
||||
inspector.once("computed-view-refreshed", stylePanelAfterChange);
|
||||
testDiv.style.cssText = "font-size: 15px; color: red;";
|
||||
|
||||
testDiv.style.fontSize = "15px";
|
||||
|
||||
// FIXME: This shouldn't be needed but as long as we don't fix the bug
|
||||
// where the rule/computed views are not updated when the selected node's
|
||||
// styles change, it has to stay here
|
||||
inspector.emit("layout-change");
|
||||
// Wait until layout-change fires from mutation to skip earlier refresh event
|
||||
inspector.once("layout-change", () => {
|
||||
inspector.once("computed-view-refreshed", computedStylePanelAfterChange);
|
||||
});
|
||||
}
|
||||
|
||||
function stylePanelAfterChange()
|
||||
function computedStylePanelAfterChange()
|
||||
{
|
||||
let propView = getInspectorProp("font-size");
|
||||
let propView = getInspectorComputedProp("font-size");
|
||||
is(propView.value, "15px", "Style inspector should be showing the new font size.");
|
||||
|
||||
stylePanelNotActive();
|
||||
let propView = getInspectorComputedProp("color");
|
||||
is(propView.value, "#F00", "Style inspector should be showing the new color.");
|
||||
|
||||
computedStylePanelNotActive();
|
||||
}
|
||||
|
||||
function stylePanelNotActive()
|
||||
function computedStylePanelNotActive()
|
||||
{
|
||||
// Tests changes made while the style panel is not active.
|
||||
inspector.sidebar.select("ruleview");
|
||||
|
||||
executeSoon(function() {
|
||||
inspector.once("computed-view-refreshed", stylePanelAfterSwitch);
|
||||
testDiv.style.fontSize = "20px";
|
||||
inspector.sidebar.select("computedview");
|
||||
testDiv.style.fontSize = "20px";
|
||||
testDiv.style.color = "blue";
|
||||
testDiv.style.textAlign = "center";
|
||||
|
||||
// FIXME: This shouldn't be needed but as long as we don't fix the bug
|
||||
// where the rule/computed views are not updated when the selected node's
|
||||
// styles change, it has to stay here
|
||||
inspector.emit("layout-change");
|
||||
});
|
||||
inspector.once("computed-view-refreshed", computedStylePanelAfterSwitch);
|
||||
inspector.sidebar.select("computedview");
|
||||
}
|
||||
|
||||
function stylePanelAfterSwitch()
|
||||
function computedStylePanelAfterSwitch()
|
||||
{
|
||||
let propView = getInspectorProp("font-size");
|
||||
is(propView.value, "20px", "Style inspector should be showing the newest font size.");
|
||||
let propView = getInspectorComputedProp("font-size");
|
||||
is(propView.value, "20px", "Style inspector should be showing the new font size.");
|
||||
|
||||
let propView = getInspectorComputedProp("color");
|
||||
is(propView.value, "#00F", "Style inspector should be showing the new color.");
|
||||
|
||||
let propView = getInspectorComputedProp("text-align");
|
||||
is(propView.value, "center", "Style inspector should be showing the new text align.");
|
||||
|
||||
rulePanelTests();
|
||||
}
|
||||
|
||||
function rulePanelTests()
|
||||
{
|
||||
inspector.sidebar.select("ruleview");
|
||||
let ruleview = inspector.sidebar.getWindowForTab("ruleview").ruleview;
|
||||
ok(ruleview, "Style Panel has a ruleview");
|
||||
|
||||
let propView = getInspectorRuleProp("text-align");
|
||||
is(propView.value, "center", "Style inspector should be showing the new text align.");
|
||||
|
||||
testDiv.style.textAlign = "right";
|
||||
testDiv.style.color = "lightgoldenrodyellow";
|
||||
testDiv.style.fontSize = "3em";
|
||||
testDiv.style.textTransform = "uppercase";
|
||||
|
||||
|
||||
inspector.once("rule-view-refreshed", rulePanelAfterChange);
|
||||
}
|
||||
|
||||
function rulePanelAfterChange()
|
||||
{
|
||||
let propView = getInspectorRuleProp("text-align");
|
||||
is(propView.value, "right", "Style inspector should be showing the new text align.");
|
||||
|
||||
let propView = getInspectorRuleProp("color");
|
||||
is(propView.value, "#FAFAD2", "Style inspector should be showing the new color.")
|
||||
|
||||
let propView = getInspectorRuleProp("font-size");
|
||||
is(propView.value, "3em", "Style inspector should be showing the new font size.");
|
||||
|
||||
let propView = getInspectorRuleProp("text-transform");
|
||||
is(propView.value, "uppercase", "Style inspector should be showing the new text transform.");
|
||||
|
||||
finishTest();
|
||||
}
|
||||
|
@ -85,3 +85,4 @@ browser.jar:
|
||||
content/browser/devtools/app-manager/index.xul (app-manager/content/index.xul)
|
||||
content/browser/devtools/app-manager/index.js (app-manager/content/index.js)
|
||||
content/browser/devtools/app-manager/help.xhtml (app-manager/content/help.xhtml)
|
||||
content/browser/devtools/app-manager/manifest-editor.js (app-manager/content/manifest-editor.js)
|
||||
|
@ -387,6 +387,7 @@ MarkupView.prototype = {
|
||||
* Mutation observer used for included nodes.
|
||||
*/
|
||||
_mutationObserver: function(aMutations) {
|
||||
let requiresLayoutChange = false;
|
||||
for (let mutation of aMutations) {
|
||||
let type = mutation.type;
|
||||
let target = mutation.target;
|
||||
@ -409,6 +410,11 @@ MarkupView.prototype = {
|
||||
}
|
||||
if (type === "attributes" || type === "characterData") {
|
||||
container.update();
|
||||
|
||||
// Auto refresh style properties on selected node when they change.
|
||||
if (type === "attributes" && container.selected) {
|
||||
requiresLayoutChange = true;
|
||||
}
|
||||
} else if (type === "childList") {
|
||||
container.childrenDirty = true;
|
||||
// Update the children to take care of changes in the DOM
|
||||
@ -417,6 +423,10 @@ MarkupView.prototype = {
|
||||
this._updateChildren(container, {flash: true});
|
||||
}
|
||||
}
|
||||
|
||||
if (requiresLayoutChange) {
|
||||
this._inspector.immediateLayoutChange();
|
||||
}
|
||||
this._waitForChildren().then(() => {
|
||||
this._flashMutatedNodes(aMutations);
|
||||
this._inspector.emit("markupmutation");
|
||||
|
@ -32,7 +32,7 @@ Parser.prototype = {
|
||||
* @param string aSource
|
||||
* The source text content.
|
||||
*/
|
||||
get: function P_get(aUrl, aSource) {
|
||||
get: function(aUrl, aSource) {
|
||||
// Try to use the cached AST nodes, to avoid useless parsing operations.
|
||||
if (this._cache.has(aUrl)) {
|
||||
return this._cache.get(aUrl);
|
||||
@ -89,7 +89,7 @@ Parser.prototype = {
|
||||
/**
|
||||
* Clears all the parsed sources from cache.
|
||||
*/
|
||||
clearCache: function P_clearCache() {
|
||||
clearCache: function() {
|
||||
this._cache.clear();
|
||||
},
|
||||
|
||||
@ -99,7 +99,7 @@ Parser.prototype = {
|
||||
* @param String aUrl
|
||||
* The URL of the source that is being cleared.
|
||||
*/
|
||||
clearSource: function P_clearSource(aUrl) {
|
||||
clearSource: function(aUrl) {
|
||||
this._cache.delete(aUrl);
|
||||
},
|
||||
|
||||
@ -121,17 +121,10 @@ SyntaxTreesPool.prototype = {
|
||||
/**
|
||||
* @see SyntaxTree.prototype.getNamedFunctionDefinitions
|
||||
*/
|
||||
getNamedFunctionDefinitions: function STP_getNamedFunctionDefinitions(aSubstring) {
|
||||
getNamedFunctionDefinitions: function(aSubstring) {
|
||||
return this._call("getNamedFunctionDefinitions", aSubstring);
|
||||
},
|
||||
|
||||
/**
|
||||
* @see SyntaxTree.prototype.getFunctionAtLocation
|
||||
*/
|
||||
getFunctionAtLocation: function STP_getFunctionAtLocation(aLine, aColumn) {
|
||||
return this._call("getFunctionAtLocation", [aLine, aColumn]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Finds the offset and length of the script containing the specified offset
|
||||
* relative to its parent source.
|
||||
@ -141,7 +134,7 @@ SyntaxTreesPool.prototype = {
|
||||
* @return array
|
||||
* The offset and length relative to the enclosing script.
|
||||
*/
|
||||
getScriptInfo: function STP_getScriptInfo(aOffset) {
|
||||
getScriptInfo: function(aOffset) {
|
||||
for (let { offset, length } of this._trees) {
|
||||
if (offset <= aOffset && offset + length >= aOffset) {
|
||||
return [offset, length];
|
||||
@ -160,7 +153,7 @@ SyntaxTreesPool.prototype = {
|
||||
* @return array
|
||||
* The results given by all known syntax trees.
|
||||
*/
|
||||
_call: function STP__call(aFunction, aParams) {
|
||||
_call: function(aFunction, aParams) {
|
||||
let results = [];
|
||||
let requestId = aFunction + aParams; // Cache all the things!
|
||||
|
||||
@ -221,7 +214,7 @@ SyntaxTree.prototype = {
|
||||
* All the matching function declarations and expressions, as
|
||||
* { functionName, functionLocation ... } object hashes.
|
||||
*/
|
||||
getNamedFunctionDefinitions: function ST_getNamedFunctionDefinitions(aSubstring) {
|
||||
getNamedFunctionDefinitions: function(aSubstring) {
|
||||
let lowerCaseToken = aSubstring.toLowerCase();
|
||||
let store = [];
|
||||
|
||||
@ -230,7 +223,7 @@ SyntaxTree.prototype = {
|
||||
* Callback invoked for each function declaration node.
|
||||
* @param Node aNode
|
||||
*/
|
||||
onFunctionDeclaration: function STW_onFunctionDeclaration(aNode) {
|
||||
onFunctionDeclaration: function(aNode) {
|
||||
let functionName = aNode.id.name;
|
||||
if (functionName.toLowerCase().contains(lowerCaseToken)) {
|
||||
store.push({
|
||||
@ -244,31 +237,27 @@ SyntaxTree.prototype = {
|
||||
* Callback invoked for each function expression node.
|
||||
* @param Node aNode
|
||||
*/
|
||||
onFunctionExpression: function STW_onFunctionExpression(aNode) {
|
||||
let parent = aNode._parent;
|
||||
let functionName, inferredName, inferredChain, inferredLocation;
|
||||
|
||||
onFunctionExpression: function(aNode) {
|
||||
// Function expressions don't necessarily have a name.
|
||||
if (aNode.id) {
|
||||
functionName = aNode.id.name;
|
||||
}
|
||||
let functionName = aNode.id ? aNode.id.name : "";
|
||||
let functionLocation = aNode.loc || null;
|
||||
|
||||
// Infer the function's name from an enclosing syntax tree node.
|
||||
if (parent) {
|
||||
let inferredInfo = ParserHelpers.inferFunctionExpressionInfo(aNode);
|
||||
inferredName = inferredInfo.name;
|
||||
inferredChain = inferredInfo.chain;
|
||||
inferredLocation = inferredInfo.loc;
|
||||
}
|
||||
let inferredInfo = ParserHelpers.inferFunctionExpressionInfo(aNode);
|
||||
let inferredName = inferredInfo.name;
|
||||
let inferredChain = inferredInfo.chain;
|
||||
let inferredLocation = inferredInfo.loc;
|
||||
|
||||
// Current node may be part of a larger assignment expression stack.
|
||||
if (parent.type == "AssignmentExpression") {
|
||||
this.onFunctionExpression(parent);
|
||||
if (aNode._parent.type == "AssignmentExpression") {
|
||||
this.onFunctionExpression(aNode._parent);
|
||||
}
|
||||
|
||||
if ((functionName && functionName.toLowerCase().contains(lowerCaseToken)) ||
|
||||
(inferredName && inferredName.toLowerCase().contains(lowerCaseToken))) {
|
||||
store.push({
|
||||
functionName: functionName,
|
||||
functionLocation: aNode.loc,
|
||||
functionLocation: functionLocation,
|
||||
inferredName: inferredName,
|
||||
inferredChain: inferredChain,
|
||||
inferredLocation: inferredLocation
|
||||
@ -280,19 +269,16 @@ SyntaxTree.prototype = {
|
||||
* Callback invoked for each arrow expression node.
|
||||
* @param Node aNode
|
||||
*/
|
||||
onArrowExpression: function STW_onArrowExpression(aNode) {
|
||||
let parent = aNode._parent;
|
||||
let inferredName, inferredChain, inferredLocation;
|
||||
|
||||
onArrowExpression: function(aNode) {
|
||||
// Infer the function's name from an enclosing syntax tree node.
|
||||
let inferredInfo = ParserHelpers.inferFunctionExpressionInfo(aNode);
|
||||
inferredName = inferredInfo.name;
|
||||
inferredChain = inferredInfo.chain;
|
||||
inferredLocation = inferredInfo.loc;
|
||||
let inferredName = inferredInfo.name;
|
||||
let inferredChain = inferredInfo.chain;
|
||||
let inferredLocation = inferredInfo.loc;
|
||||
|
||||
// Current node may be part of a larger assignment expression stack.
|
||||
if (parent.type == "AssignmentExpression") {
|
||||
this.onFunctionExpression(parent);
|
||||
if (aNode._parent.type == "AssignmentExpression") {
|
||||
this.onFunctionExpression(aNode._parent);
|
||||
}
|
||||
|
||||
if (inferredName && inferredName.toLowerCase().contains(lowerCaseToken)) {
|
||||
@ -308,100 +294,6 @@ SyntaxTree.prototype = {
|
||||
return store;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the "new" or "call" expression at the specified location.
|
||||
*
|
||||
* @param number aLine
|
||||
* The line in the source.
|
||||
* @param number aColumn
|
||||
* The column in the source.
|
||||
* @return object
|
||||
* An { functionName, functionLocation } object hash,
|
||||
* or null if nothing is found at the specified location.
|
||||
*/
|
||||
getFunctionAtLocation: function STW_getFunctionAtLocation([aLine, aColumn]) {
|
||||
let self = this;
|
||||
let func = null;
|
||||
|
||||
SyntaxTreeVisitor.walk(this.AST, {
|
||||
/**
|
||||
* Callback invoked for each node.
|
||||
* @param Node aNode
|
||||
*/
|
||||
onNode: function STW_onNode(aNode) {
|
||||
// Make sure the node is part of a branch that's guaranteed to be
|
||||
// hovered. Otherwise, return true to abruptly halt walking this
|
||||
// syntax tree branch. This is a really efficient optimization.
|
||||
return ParserHelpers.isWithinLines(aNode, aLine);
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback invoked for each identifier node.
|
||||
* @param Node aNode
|
||||
*/
|
||||
onIdentifier: function STW_onIdentifier(aNode) {
|
||||
// Make sure the identifier itself is hovered.
|
||||
let hovered = ParserHelpers.isWithinBounds(aNode, aLine, aColumn);
|
||||
if (!hovered) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the identifier is part of a "new" expression or
|
||||
// "call" expression node.
|
||||
let expression = ParserHelpers.getEnclosingFunctionExpression(aNode);
|
||||
if (!expression) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Found an identifier node that is part of a "new" expression or
|
||||
// "call" expression node. However, it may be an argument, not a callee.
|
||||
if (ParserHelpers.isFunctionCalleeArgument(aNode)) {
|
||||
// It's an argument.
|
||||
if (self.functionIdentifiersCache.has(aNode.name)) {
|
||||
// It's a function as an argument.
|
||||
func = {
|
||||
functionName: aNode.name,
|
||||
functionLocation: aNode.loc || aNode._parent.loc
|
||||
};
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Found a valid "new" expression or "call" expression node.
|
||||
func = {
|
||||
functionName: aNode.name,
|
||||
functionLocation: ParserHelpers.getFunctionCalleeInfo(expression).loc
|
||||
};
|
||||
|
||||
// Abruptly halt walking the syntax tree.
|
||||
this.break = true;
|
||||
}
|
||||
});
|
||||
|
||||
return func;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets all the function identifiers in this syntax tree (both the
|
||||
* function names and their inferred names).
|
||||
*
|
||||
* @return array
|
||||
* An array of strings.
|
||||
*/
|
||||
get functionIdentifiersCache() {
|
||||
if (this._functionIdentifiersCache) {
|
||||
return this._functionIdentifiersCache;
|
||||
}
|
||||
let functionDefinitions = this.getNamedFunctionDefinitions("");
|
||||
let functionIdentifiers = new Set();
|
||||
|
||||
for (let { functionName, inferredName } of functionDefinitions) {
|
||||
functionIdentifiers.add(functionName);
|
||||
functionIdentifiers.add(inferredName);
|
||||
}
|
||||
return this._functionIdentifiersCache = functionIdentifiers;
|
||||
},
|
||||
|
||||
AST: null,
|
||||
url: "",
|
||||
length: 0,
|
||||
@ -422,7 +314,7 @@ let ParserHelpers = {
|
||||
* @return boolean
|
||||
* True if the line and column is contained in the node's bounds.
|
||||
*/
|
||||
isWithinLines: function PH_isWithinLines(aNode, aLine) {
|
||||
isWithinLines: function(aNode, aLine) {
|
||||
// Not all nodes have location information attached.
|
||||
if (!aNode.loc) {
|
||||
return this.isWithinLines(aNode._parent, aLine);
|
||||
@ -442,7 +334,7 @@ let ParserHelpers = {
|
||||
* @return boolean
|
||||
* True if the line and column is contained in the node's bounds.
|
||||
*/
|
||||
isWithinBounds: function PH_isWithinBounds(aNode, aLine, aColumn) {
|
||||
isWithinBounds: function(aNode, aLine, aColumn) {
|
||||
// Not all nodes have location information attached.
|
||||
if (!aNode.loc) {
|
||||
return this.isWithinBounds(aNode._parent, aLine, aColumn);
|
||||
@ -453,16 +345,16 @@ let ParserHelpers = {
|
||||
|
||||
/**
|
||||
* Try to infer a function expression's name & other details based on the
|
||||
* enclosing VariableDeclarator, AssignmentExpression or ObjectExpression node.
|
||||
* enclosing VariableDeclarator, AssignmentExpression or ObjectExpression.
|
||||
*
|
||||
* @param Node aNode
|
||||
* The function expression node to get the name for.
|
||||
* @return object
|
||||
* The inferred function name, or empty string can't infer name,
|
||||
* The inferred function name, or empty string can't infer the name,
|
||||
* along with the chain (a generic "context", like a prototype chain)
|
||||
* and location if available.
|
||||
*/
|
||||
inferFunctionExpressionInfo: function PH_inferFunctionExpressionInfo(aNode) {
|
||||
inferFunctionExpressionInfo: function(aNode) {
|
||||
let parent = aNode._parent;
|
||||
|
||||
// A function expression may be defined in a variable declarator,
|
||||
@ -480,11 +372,11 @@ let ParserHelpers = {
|
||||
// e.g. foo = function(){} or foo.bar = function(){}, in which case it is
|
||||
// possible to infer the assignee name ("foo" and "bar" respectively).
|
||||
if (parent.type == "AssignmentExpression") {
|
||||
let assigneeChain = this.getAssignmentExpressionAssigneeChain(parent);
|
||||
let assigneeLeaf = assigneeChain.pop();
|
||||
let propertyChain = this.getMemberExpressionPropertyChain(parent.left);
|
||||
let propertyLeaf = propertyChain.pop();
|
||||
return {
|
||||
name: assigneeLeaf,
|
||||
chain: assigneeChain,
|
||||
name: propertyLeaf,
|
||||
chain: propertyChain,
|
||||
loc: parent.left.loc
|
||||
};
|
||||
}
|
||||
@ -493,13 +385,13 @@ let ParserHelpers = {
|
||||
// e.g. { foo: function(){} }, then it is possible to infer the name
|
||||
// from the corresponding property.
|
||||
if (parent.type == "ObjectExpression") {
|
||||
let propertyDetails = this.getObjectExpressionPropertyKeyForValue(aNode);
|
||||
let propertyKey = this.getObjectExpressionPropertyKeyForValue(aNode);
|
||||
let propertyChain = this.getObjectExpressionPropertyChain(parent);
|
||||
let propertyLeaf = propertyDetails.name;
|
||||
let propertyLeaf = propertyKey.name;
|
||||
return {
|
||||
name: propertyLeaf,
|
||||
chain: propertyChain,
|
||||
loc: propertyDetails.loc
|
||||
loc: propertyKey.loc
|
||||
};
|
||||
}
|
||||
|
||||
@ -512,17 +404,18 @@ let ParserHelpers = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets details about an object expression's property to which a specified
|
||||
* value is assigned. For example, the node returned for the value 42 in
|
||||
* "{ foo: { bar: 42 } }" is "bar".
|
||||
* Gets the name of an object expression's property to which a specified
|
||||
* value is assigned.
|
||||
*
|
||||
* For example, if aNode represents the "bar" identifier in a hypothetical
|
||||
* "{ foo: bar }" object expression, the returned node is the "foo" identifier.
|
||||
*
|
||||
* @param Node aNode
|
||||
* The value node assigned to a property in an object expression.
|
||||
* The value node in an object expression.
|
||||
* @return object
|
||||
* The details about the assignee property node.
|
||||
* The key identifier node in the object expression.
|
||||
*/
|
||||
getObjectExpressionPropertyKeyForValue:
|
||||
function PH_getObjectExpressionPropertyKeyForValue(aNode) {
|
||||
getObjectExpressionPropertyKeyForValue: function(aNode) {
|
||||
let parent = aNode._parent;
|
||||
if (parent.type != "ObjectExpression") {
|
||||
return null;
|
||||
@ -535,9 +428,12 @@ let ParserHelpers = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets an object expression property chain to its parent variable declarator.
|
||||
* For example, the chain to "baz" in "foo = { bar: { baz: { } } }" is
|
||||
* ["foo", "bar", "baz"].
|
||||
* Gets an object expression's property chain to its parent
|
||||
* variable declarator or assignment expression, if available.
|
||||
*
|
||||
* For example, if aNode represents the "baz: {}" object expression in a
|
||||
* hypothetical "foo = { bar: { baz: {} } }" assignment expression, the
|
||||
* returned chain is ["foo", "bar", "baz"].
|
||||
*
|
||||
* @param Node aNode
|
||||
* The object expression node to begin the scan from.
|
||||
@ -546,59 +442,56 @@ let ParserHelpers = {
|
||||
* @return array
|
||||
* The chain to the parent variable declarator, as strings.
|
||||
*/
|
||||
getObjectExpressionPropertyChain:
|
||||
function PH_getObjectExpressionPropertyChain(aNode, aStore = []) {
|
||||
getObjectExpressionPropertyChain: function(aNode, aStore = []) {
|
||||
switch (aNode.type) {
|
||||
case "ObjectExpression":
|
||||
this.getObjectExpressionPropertyChain(aNode._parent, aStore);
|
||||
|
||||
let propertyDetails = this.getObjectExpressionPropertyKeyForValue(aNode);
|
||||
if (propertyDetails) {
|
||||
aStore.push(this.getObjectExpressionPropertyKeyForValue(aNode).name);
|
||||
let propertyKey = this.getObjectExpressionPropertyKeyForValue(aNode);
|
||||
if (propertyKey) {
|
||||
aStore.push(propertyKey.name);
|
||||
}
|
||||
break;
|
||||
// Handle "foo.bar = { ... }" since it's commonly used when defining an
|
||||
// object's prototype methods; for example: "Foo.prototype = { ... }".
|
||||
// Handle "var foo = { ... }" variable declarators.
|
||||
case "VariableDeclarator":
|
||||
aStore.push(aNode.id.name);
|
||||
break;
|
||||
// Handle "foo.bar = { ... }" assignment expressions, since they're
|
||||
// commonly used when defining an object's prototype methods; e.g:
|
||||
// "Foo.prototype = { ... }".
|
||||
case "AssignmentExpression":
|
||||
this.getAssignmentExpressionAssigneeChain(aNode, aStore);
|
||||
this.getMemberExpressionPropertyChain(aNode.left, aStore);
|
||||
break;
|
||||
// Additionally handle stuff like "foo = bar.baz({ ... })", because it's
|
||||
// commonly used in prototype-based inheritance in many libraries;
|
||||
// for example: "Foo.Bar = Baz.extend({ ... })".
|
||||
// commonly used in prototype-based inheritance in many libraries; e.g:
|
||||
// "Foo = Bar.extend({ ... })".
|
||||
case "NewExpression":
|
||||
case "CallExpression":
|
||||
this.getObjectExpressionPropertyChain(aNode._parent, aStore);
|
||||
break;
|
||||
// End of the chain.
|
||||
case "VariableDeclarator":
|
||||
aStore.push(aNode.id.name);
|
||||
break;
|
||||
}
|
||||
return aStore;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the assignee property chain in an assignment expression.
|
||||
* For example, the chain in "foo.bar.baz = 42" is ["foo", "bar", "baz"].
|
||||
* Gets a member expression's property chain.
|
||||
*
|
||||
* For example, if aNode represents a hypothetical "foo.bar.baz"
|
||||
* member expression, the returned chain ["foo", "bar", "baz"].
|
||||
*
|
||||
* More complex expressions like foo.bar().baz are intentionally not handled.
|
||||
*
|
||||
* @param Node aNode
|
||||
* The assignment expression node to begin the scan from.
|
||||
* @param array aStore
|
||||
* The chain to store the nodes into.
|
||||
* The member expression node to begin the scan from.
|
||||
* @param array aStore [optional]
|
||||
* The chain to store the nodes into.
|
||||
* @return array
|
||||
* The full assignee chain, as strings.
|
||||
* The full member chain, as strings.
|
||||
*/
|
||||
getAssignmentExpressionAssigneeChain:
|
||||
function PH_getAssignmentExpressionAssigneeChain(aNode, aStore = []) {
|
||||
getMemberExpressionPropertyChain: function(aNode, aStore = []) {
|
||||
switch (aNode.type) {
|
||||
case "AssignmentExpression":
|
||||
this.getAssignmentExpressionAssigneeChain(aNode.left, aStore);
|
||||
break;
|
||||
case "MemberExpression":
|
||||
this.getAssignmentExpressionAssigneeChain(aNode.object, aStore);
|
||||
this.getAssignmentExpressionAssigneeChain(aNode.property, aStore);
|
||||
this.getMemberExpressionPropertyChain(aNode.object, aStore);
|
||||
this.getMemberExpressionPropertyChain(aNode.property, aStore);
|
||||
break;
|
||||
case "ThisExpression":
|
||||
// Such expressions may appear in an assignee chain, for example
|
||||
@ -610,80 +503,6 @@ let ParserHelpers = {
|
||||
break;
|
||||
}
|
||||
return aStore;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the "new" expression or "call" expression containing the specified
|
||||
* node. If the node is not enclosed in either of these expression types,
|
||||
* null is returned.
|
||||
*
|
||||
* @param Node aNode
|
||||
* The child node of an enclosing "new" expression or "call" expression.
|
||||
* @return Node
|
||||
* The enclosing "new" expression or "call" expression node, or
|
||||
* null if nothing is found.
|
||||
*/
|
||||
getEnclosingFunctionExpression:
|
||||
function PH_getEnclosingFunctionExpression(aNode) {
|
||||
switch (aNode.type) {
|
||||
case "NewExpression":
|
||||
case "CallExpression":
|
||||
return aNode;
|
||||
case "MemberExpression":
|
||||
case "Identifier":
|
||||
return this.getEnclosingFunctionExpression(aNode._parent);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the name and { line, column } location of a "new" expression or
|
||||
* "call" expression's callee node.
|
||||
*
|
||||
* @param Node aNode
|
||||
* The "new" expression or "call" expression to get the callee info for.
|
||||
* @return object
|
||||
* An object containing the name and location as properties, or
|
||||
* null if nothing is found.
|
||||
*/
|
||||
getFunctionCalleeInfo: function PH_getFunctionCalleeInfo(aNode) {
|
||||
switch (aNode.type) {
|
||||
case "NewExpression":
|
||||
case "CallExpression":
|
||||
return this.getFunctionCalleeInfo(aNode.callee);
|
||||
case "MemberExpression":
|
||||
return this.getFunctionCalleeInfo(aNode.property);
|
||||
case "Identifier":
|
||||
return {
|
||||
name: aNode.name,
|
||||
loc: aNode.loc || (aNode._parent || {}).loc
|
||||
};
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if an identifier node is part of a "new" expression or
|
||||
* "call" expression's callee arguments.
|
||||
*
|
||||
* @param Node aNode
|
||||
* The node to determine if part of a function's arguments.
|
||||
* @return boolean
|
||||
* True if the identifier is an argument, false otherwise.
|
||||
*/
|
||||
isFunctionCalleeArgument: function PH_isFunctionCalleeArgument(aNode) {
|
||||
if (!aNode._parent) {
|
||||
return false;
|
||||
}
|
||||
switch (aNode._parent.type) {
|
||||
case "NewExpression":
|
||||
case "CallExpression":
|
||||
return aNode._parent.arguments.indexOf(aNode) != -1;
|
||||
default:
|
||||
return this.isFunctionCalleeArgument(aNode._parent);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -707,7 +526,7 @@ let SyntaxTreeVisitor = {
|
||||
* A map of all the callbacks to invoke when passing through certain
|
||||
* types of noes (e.g: onFunctionDeclaration, onBlockStatement etc.).
|
||||
*/
|
||||
walk: function STV_walk(aTree, aCallbacks) {
|
||||
walk: function(aTree, aCallbacks) {
|
||||
this[aTree.type](aTree, aCallbacks);
|
||||
},
|
||||
|
||||
@ -725,7 +544,7 @@ let SyntaxTreeVisitor = {
|
||||
* body: [ Statement ];
|
||||
* }
|
||||
*/
|
||||
Program: function STV_Program(aNode, aCallbacks) {
|
||||
Program: function(aNode, aCallbacks) {
|
||||
if (aCallbacks.onProgram) {
|
||||
aCallbacks.onProgram(aNode);
|
||||
}
|
||||
@ -739,7 +558,7 @@ let SyntaxTreeVisitor = {
|
||||
*
|
||||
* interface Statement <: Node { }
|
||||
*/
|
||||
Statement: function STV_Statement(aNode, aParent, aCallbacks) {
|
||||
Statement: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -762,7 +581,7 @@ let SyntaxTreeVisitor = {
|
||||
* type: "EmptyStatement";
|
||||
* }
|
||||
*/
|
||||
EmptyStatement: function STV_EmptyStatement(aNode, aParent, aCallbacks) {
|
||||
EmptyStatement: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -786,7 +605,7 @@ let SyntaxTreeVisitor = {
|
||||
* body: [ Statement ];
|
||||
* }
|
||||
*/
|
||||
BlockStatement: function STV_BlockStatement(aNode, aParent, aCallbacks) {
|
||||
BlockStatement: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -813,7 +632,7 @@ let SyntaxTreeVisitor = {
|
||||
* expression: Expression;
|
||||
* }
|
||||
*/
|
||||
ExpressionStatement: function STV_ExpressionStatement(aNode, aParent, aCallbacks) {
|
||||
ExpressionStatement: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -840,7 +659,7 @@ let SyntaxTreeVisitor = {
|
||||
* alternate: Statement | null;
|
||||
* }
|
||||
*/
|
||||
IfStatement: function STV_IfStatement(aNode, aParent, aCallbacks) {
|
||||
IfStatement: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -870,7 +689,7 @@ let SyntaxTreeVisitor = {
|
||||
* body: Statement;
|
||||
* }
|
||||
*/
|
||||
LabeledStatement: function STV_LabeledStatement(aNode, aParent, aCallbacks) {
|
||||
LabeledStatement: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -896,7 +715,7 @@ let SyntaxTreeVisitor = {
|
||||
* label: Identifier | null;
|
||||
* }
|
||||
*/
|
||||
BreakStatement: function STV_BreakStatement(aNode, aParent, aCallbacks) {
|
||||
BreakStatement: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -923,7 +742,7 @@ let SyntaxTreeVisitor = {
|
||||
* label: Identifier | null;
|
||||
* }
|
||||
*/
|
||||
ContinueStatement: function STV_ContinueStatement(aNode, aParent, aCallbacks) {
|
||||
ContinueStatement: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -951,7 +770,7 @@ let SyntaxTreeVisitor = {
|
||||
* body: Statement;
|
||||
* }
|
||||
*/
|
||||
WithStatement: function STV_WithStatement(aNode, aParent, aCallbacks) {
|
||||
WithStatement: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -981,7 +800,7 @@ let SyntaxTreeVisitor = {
|
||||
* lexical: boolean;
|
||||
* }
|
||||
*/
|
||||
SwitchStatement: function STV_SwitchStatement(aNode, aParent, aCallbacks) {
|
||||
SwitchStatement: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1009,7 +828,7 @@ let SyntaxTreeVisitor = {
|
||||
* argument: Expression | null;
|
||||
* }
|
||||
*/
|
||||
ReturnStatement: function STV_ReturnStatement(aNode, aParent, aCallbacks) {
|
||||
ReturnStatement: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1036,7 +855,7 @@ let SyntaxTreeVisitor = {
|
||||
* argument: Expression;
|
||||
* }
|
||||
*/
|
||||
ThrowStatement: function STV_ThrowStatement(aNode, aParent, aCallbacks) {
|
||||
ThrowStatement: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1064,7 +883,7 @@ let SyntaxTreeVisitor = {
|
||||
* finalizer: BlockStatement | null;
|
||||
* }
|
||||
*/
|
||||
TryStatement: function STV_TryStatement(aNode, aParent, aCallbacks) {
|
||||
TryStatement: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1099,7 +918,7 @@ let SyntaxTreeVisitor = {
|
||||
* body: Statement;
|
||||
* }
|
||||
*/
|
||||
WhileStatement: function STV_WhileStatement(aNode, aParent, aCallbacks) {
|
||||
WhileStatement: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1126,7 +945,7 @@ let SyntaxTreeVisitor = {
|
||||
* test: Expression;
|
||||
* }
|
||||
*/
|
||||
DoWhileStatement: function STV_DoWhileStatement(aNode, aParent, aCallbacks) {
|
||||
DoWhileStatement: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1155,7 +974,7 @@ let SyntaxTreeVisitor = {
|
||||
* body: Statement;
|
||||
* }
|
||||
*/
|
||||
ForStatement: function STV_ForStatement(aNode, aParent, aCallbacks) {
|
||||
ForStatement: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1192,7 +1011,7 @@ let SyntaxTreeVisitor = {
|
||||
* each: boolean;
|
||||
* }
|
||||
*/
|
||||
ForInStatement: function STV_ForInStatement(aNode, aParent, aCallbacks) {
|
||||
ForInStatement: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1221,7 +1040,7 @@ let SyntaxTreeVisitor = {
|
||||
* body: Statement;
|
||||
* }
|
||||
*/
|
||||
ForOfStatement: function STV_ForOfStatement(aNode, aParent, aCallbacks) {
|
||||
ForOfStatement: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1249,7 +1068,7 @@ let SyntaxTreeVisitor = {
|
||||
* body: Statement;
|
||||
* }
|
||||
*/
|
||||
LetStatement: function STV_LetStatement(aNode, aParent, aCallbacks) {
|
||||
LetStatement: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1279,7 +1098,7 @@ let SyntaxTreeVisitor = {
|
||||
* type: "DebuggerStatement";
|
||||
* }
|
||||
*/
|
||||
DebuggerStatement: function STV_DebuggerStatement(aNode, aParent, aCallbacks) {
|
||||
DebuggerStatement: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1302,7 +1121,7 @@ let SyntaxTreeVisitor = {
|
||||
*
|
||||
* interface Declaration <: Statement { }
|
||||
*/
|
||||
Declaration: function STV_Declaration(aNode, aParent, aCallbacks) {
|
||||
Declaration: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1332,7 +1151,7 @@ let SyntaxTreeVisitor = {
|
||||
* expression: boolean;
|
||||
* }
|
||||
*/
|
||||
FunctionDeclaration: function STV_FunctionDeclaration(aNode, aParent, aCallbacks) {
|
||||
FunctionDeclaration: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1368,7 +1187,7 @@ let SyntaxTreeVisitor = {
|
||||
* kind: "var" | "let" | "const";
|
||||
* }
|
||||
*/
|
||||
VariableDeclaration: function STV_VariableDeclaration(aNode, aParent, aCallbacks) {
|
||||
VariableDeclaration: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1396,7 +1215,7 @@ let SyntaxTreeVisitor = {
|
||||
* init: Expression | null;
|
||||
* }
|
||||
*/
|
||||
VariableDeclarator: function STV_VariableDeclarator(aNode, aParent, aCallbacks) {
|
||||
VariableDeclarator: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1422,7 +1241,7 @@ let SyntaxTreeVisitor = {
|
||||
*
|
||||
* interface Expression <: Node, Pattern { }
|
||||
*/
|
||||
Expression: function STV_Expression(aNode, aParent, aCallbacks) {
|
||||
Expression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1445,7 +1264,7 @@ let SyntaxTreeVisitor = {
|
||||
* type: "ThisExpression";
|
||||
* }
|
||||
*/
|
||||
ThisExpression: function STV_ThisExpression(aNode, aParent, aCallbacks) {
|
||||
ThisExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1469,7 +1288,7 @@ let SyntaxTreeVisitor = {
|
||||
* elements: [ Expression | null ];
|
||||
* }
|
||||
*/
|
||||
ArrayExpression: function STV_ArrayExpression(aNode, aParent, aCallbacks) {
|
||||
ArrayExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1505,7 +1324,7 @@ let SyntaxTreeVisitor = {
|
||||
* kind: "init" | "get" | "set" } ];
|
||||
* }
|
||||
*/
|
||||
ObjectExpression: function STV_ObjectExpression(aNode, aParent, aCallbacks) {
|
||||
ObjectExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1539,7 +1358,7 @@ let SyntaxTreeVisitor = {
|
||||
* expression: boolean;
|
||||
* }
|
||||
*/
|
||||
FunctionExpression: function STV_FunctionExpression(aNode, aParent, aCallbacks) {
|
||||
FunctionExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1581,7 +1400,7 @@ let SyntaxTreeVisitor = {
|
||||
* expression: boolean;
|
||||
* }
|
||||
*/
|
||||
ArrowExpression: function STV_ArrowExpression(aNode, aParent, aCallbacks) {
|
||||
ArrowExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1615,7 +1434,7 @@ let SyntaxTreeVisitor = {
|
||||
* expressions: [ Expression ];
|
||||
* }
|
||||
*/
|
||||
SequenceExpression: function STV_SequenceExpression(aNode, aParent, aCallbacks) {
|
||||
SequenceExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1644,7 +1463,7 @@ let SyntaxTreeVisitor = {
|
||||
* argument: Expression;
|
||||
* }
|
||||
*/
|
||||
UnaryExpression: function STV_UnaryExpression(aNode, aParent, aCallbacks) {
|
||||
UnaryExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1671,7 +1490,7 @@ let SyntaxTreeVisitor = {
|
||||
* right: Expression;
|
||||
* }
|
||||
*/
|
||||
BinaryExpression: function STV_BinaryExpression(aNode, aParent, aCallbacks) {
|
||||
BinaryExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1699,7 +1518,7 @@ let SyntaxTreeVisitor = {
|
||||
* right: Expression;
|
||||
* }
|
||||
*/
|
||||
AssignmentExpression: function STV_AssignmentExpression(aNode, aParent, aCallbacks) {
|
||||
AssignmentExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1727,7 +1546,7 @@ let SyntaxTreeVisitor = {
|
||||
* prefix: boolean;
|
||||
* }
|
||||
*/
|
||||
UpdateExpression: function STV_UpdateExpression(aNode, aParent, aCallbacks) {
|
||||
UpdateExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1754,7 +1573,7 @@ let SyntaxTreeVisitor = {
|
||||
* right: Expression;
|
||||
* }
|
||||
*/
|
||||
LogicalExpression: function STV_LogicalExpression(aNode, aParent, aCallbacks) {
|
||||
LogicalExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1782,7 +1601,7 @@ let SyntaxTreeVisitor = {
|
||||
* consequent: Expression;
|
||||
* }
|
||||
*/
|
||||
ConditionalExpression: function STV_ConditionalExpression(aNode, aParent, aCallbacks) {
|
||||
ConditionalExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1810,7 +1629,7 @@ let SyntaxTreeVisitor = {
|
||||
* arguments: [ Expression | null ];
|
||||
* }
|
||||
*/
|
||||
NewExpression: function STV_NewExpression(aNode, aParent, aCallbacks) {
|
||||
NewExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1841,7 +1660,7 @@ let SyntaxTreeVisitor = {
|
||||
* arguments: [ Expression | null ];
|
||||
* }
|
||||
*/
|
||||
CallExpression: function STV_CallExpression(aNode, aParent, aCallbacks) {
|
||||
CallExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1876,7 +1695,7 @@ let SyntaxTreeVisitor = {
|
||||
* computed: boolean;
|
||||
* }
|
||||
*/
|
||||
MemberExpression: function STV_MemberExpression(aNode, aParent, aCallbacks) {
|
||||
MemberExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1901,7 +1720,7 @@ let SyntaxTreeVisitor = {
|
||||
* argument: Expression | null;
|
||||
* }
|
||||
*/
|
||||
YieldExpression: function STV_YieldExpression(aNode, aParent, aCallbacks) {
|
||||
YieldExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1931,7 +1750,7 @@ let SyntaxTreeVisitor = {
|
||||
* filter: Expression | null;
|
||||
* }
|
||||
*/
|
||||
ComprehensionExpression: function STV_ComprehensionExpression(aNode, aParent, aCallbacks) {
|
||||
ComprehensionExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1965,7 +1784,7 @@ let SyntaxTreeVisitor = {
|
||||
* filter: Expression | null;
|
||||
* }
|
||||
*/
|
||||
GeneratorExpression: function STV_GeneratorExpression(aNode, aParent, aCallbacks) {
|
||||
GeneratorExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -1996,7 +1815,7 @@ let SyntaxTreeVisitor = {
|
||||
* expression: Literal;
|
||||
* }
|
||||
*/
|
||||
GraphExpression: function STV_GraphExpression(aNode, aParent, aCallbacks) {
|
||||
GraphExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -2020,7 +1839,7 @@ let SyntaxTreeVisitor = {
|
||||
* index: uint32;
|
||||
* }
|
||||
*/
|
||||
GraphIndexExpression: function STV_GraphIndexExpression(aNode, aParent, aCallbacks) {
|
||||
GraphIndexExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -2045,7 +1864,7 @@ let SyntaxTreeVisitor = {
|
||||
* body: Expression;
|
||||
* }
|
||||
*/
|
||||
LetExpression: function STV_LetExpression(aNode, aParent, aCallbacks) {
|
||||
LetExpression: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -2073,7 +1892,7 @@ let SyntaxTreeVisitor = {
|
||||
*
|
||||
* interface Pattern <: Node { }
|
||||
*/
|
||||
Pattern: function STV_Pattern(aNode, aParent, aCallbacks) {
|
||||
Pattern: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -2098,7 +1917,7 @@ let SyntaxTreeVisitor = {
|
||||
* properties: [ { key: Literal | Identifier, value: Pattern } ];
|
||||
* }
|
||||
*/
|
||||
ObjectPattern: function STV_ObjectPattern(aNode, aParent, aCallbacks) {
|
||||
ObjectPattern: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -2126,7 +1945,7 @@ let SyntaxTreeVisitor = {
|
||||
* elements: [ Pattern | null ];
|
||||
* }
|
||||
*/
|
||||
ArrayPattern: function STV_ArrayPattern(aNode, aParent, aCallbacks) {
|
||||
ArrayPattern: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -2157,7 +1976,7 @@ let SyntaxTreeVisitor = {
|
||||
* consequent: [ Statement ];
|
||||
* }
|
||||
*/
|
||||
SwitchCase: function STV_SwitchCase(aNode, aParent, aCallbacks) {
|
||||
SwitchCase: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -2190,7 +2009,7 @@ let SyntaxTreeVisitor = {
|
||||
* body: BlockStatement;
|
||||
* }
|
||||
*/
|
||||
CatchClause: function STV_CatchClause(aNode, aParent, aCallbacks) {
|
||||
CatchClause: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -2220,7 +2039,7 @@ let SyntaxTreeVisitor = {
|
||||
* each: boolean;
|
||||
* }
|
||||
*/
|
||||
ComprehensionBlock: function STV_ComprehensionBlock(aNode, aParent, aCallbacks) {
|
||||
ComprehensionBlock: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -2247,7 +2066,7 @@ let SyntaxTreeVisitor = {
|
||||
* name: string;
|
||||
* }
|
||||
*/
|
||||
Identifier: function STV_Identifier(aNode, aParent, aCallbacks) {
|
||||
Identifier: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
@ -2271,7 +2090,7 @@ let SyntaxTreeVisitor = {
|
||||
* value: string | boolean | null | number | RegExp;
|
||||
* }
|
||||
*/
|
||||
Literal: function STV_Literal(aNode, aParent, aCallbacks) {
|
||||
Literal: function(aNode, aParent, aCallbacks) {
|
||||
aNode._parent = aParent;
|
||||
|
||||
if (this.break) {
|
||||
|
@ -35,7 +35,10 @@
|
||||
winUtils.loadSheet(newThemeUrl, winUtils.AUTHOR_SHEET);
|
||||
|
||||
// Floating scrollbars à la osx
|
||||
if (!window.matchMedia("(-moz-overlay-scrollbars)").matches) {
|
||||
let hiddenDOMWindow = Cc["@mozilla.org/appshell/appShellService;1"]
|
||||
.getService(Ci.nsIAppShellService)
|
||||
.hiddenDOMWindow;
|
||||
if (!hiddenDOMWindow.matchMedia("(-moz-overlay-scrollbars)").matches) {
|
||||
let scrollbarsUrl = Services.io.newURI(
|
||||
DEVTOOLS_SKIN_URL + "floating-scrollbars-light.css", null, null);
|
||||
|
||||
|
@ -167,7 +167,7 @@ SideMenuWidget.prototype = {
|
||||
* The element associated with the displayed item.
|
||||
*/
|
||||
removeChild: function(aChild) {
|
||||
if (aChild.className == "side-menu-widget-item-contents") {
|
||||
if (aChild.classList.contains("side-menu-widget-item-contents")) {
|
||||
// Remove the item itself, not the contents.
|
||||
aChild.parentNode.remove();
|
||||
} else {
|
||||
|
@ -21,6 +21,7 @@ Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
||||
Cu.import("resource:///modules/devtools/shared/event-emitter.js");
|
||||
Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "devtools",
|
||||
"resource://gre/modules/devtools/Loader.jsm");
|
||||
@ -108,7 +109,9 @@ VariablesView.prototype = {
|
||||
*/
|
||||
set rawObject(aObject) {
|
||||
this.empty();
|
||||
this.addScope().addItem().populate(aObject, { sorted: true });
|
||||
this.addScope()
|
||||
.addItem("", { enumerable: true })
|
||||
.populate(aObject, { sorted: true });
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1120,14 +1123,6 @@ function Scope(aView, aName, aFlags = {}) {
|
||||
this.contextMenuId = aView.contextMenuId;
|
||||
this.separatorStr = aView.separatorStr;
|
||||
|
||||
// Creating maps and arrays thousands of times for variables or properties
|
||||
// with a large number of children fills up a lot of memory. Make sure
|
||||
// these are instantiated only if needed.
|
||||
XPCOMUtils.defineLazyGetter(this, "_store", () => new Map());
|
||||
XPCOMUtils.defineLazyGetter(this, "_enumItems", () => []);
|
||||
XPCOMUtils.defineLazyGetter(this, "_nonEnumItems", () => []);
|
||||
XPCOMUtils.defineLazyGetter(this, "_batchItems", () => []);
|
||||
|
||||
this._init(aName.trim(), aFlags);
|
||||
}
|
||||
|
||||
@ -1649,7 +1644,8 @@ Scope.prototype = {
|
||||
* The click listener for this scope's title.
|
||||
*/
|
||||
_onClick: function(e) {
|
||||
if (e.target == this._inputNode ||
|
||||
if (e.button != 0 ||
|
||||
e.target == this._inputNode ||
|
||||
e.target == this._editNode ||
|
||||
e.target == this._deleteNode) {
|
||||
return;
|
||||
@ -2036,6 +2032,14 @@ Scope.prototype = {
|
||||
_throbber: null
|
||||
};
|
||||
|
||||
// Creating maps and arrays thousands of times for variables or properties
|
||||
// with a large number of children fills up a lot of memory. Make sure
|
||||
// these are instantiated only if needed.
|
||||
DevToolsUtils.defineLazyPrototypeGetter(Scope.prototype, "_store", Map);
|
||||
DevToolsUtils.defineLazyPrototypeGetter(Scope.prototype, "_enumItems", Array);
|
||||
DevToolsUtils.defineLazyPrototypeGetter(Scope.prototype, "_nonEnumItems", Array);
|
||||
DevToolsUtils.defineLazyPrototypeGetter(Scope.prototype, "_batchItems", Array);
|
||||
|
||||
/**
|
||||
* A Variable is a Scope holding Property instances.
|
||||
* Iterable via "for (let [name, property] in instance) { }".
|
||||
@ -2776,6 +2780,10 @@ Variable.prototype = Heritage.extend(Scope.prototype, {
|
||||
* The click listener for the edit button.
|
||||
*/
|
||||
_onEdit: function(e) {
|
||||
if (e.button != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this._activateValueInput();
|
||||
@ -2785,6 +2793,10 @@ Variable.prototype = Heritage.extend(Scope.prototype, {
|
||||
* The click listener for the delete button.
|
||||
*/
|
||||
_onDelete: function(e) {
|
||||
if ("button" in e && e.button != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
|
@ -1283,13 +1283,13 @@ CssRuleView.prototype = {
|
||||
{
|
||||
// Ignore refreshes during editing or when no element is selected.
|
||||
if (this.isEditing || !this._elementStyle) {
|
||||
return promise.resolve(null);
|
||||
return;
|
||||
}
|
||||
|
||||
this._clearRules();
|
||||
|
||||
// Repopulate the element style.
|
||||
return this._populate();
|
||||
this._populate();
|
||||
},
|
||||
|
||||
_populate: function() {
|
||||
|
@ -7,6 +7,7 @@ let doc;
|
||||
let inspector;
|
||||
let ruleView;
|
||||
let testElement;
|
||||
let rule;
|
||||
|
||||
function startTest(aInspector, aRuleView)
|
||||
{
|
||||
@ -29,9 +30,7 @@ function startTest(aInspector, aRuleView)
|
||||
testElement.setAttribute("style", elementStyle);
|
||||
|
||||
inspector.selection.setNode(testElement);
|
||||
inspector.once("inspector-updated", () => {
|
||||
testRuleChanges();
|
||||
}, true);
|
||||
inspector.once("rule-view-refreshed", testRuleChanges);
|
||||
}
|
||||
|
||||
function testRuleChanges()
|
||||
@ -43,25 +42,29 @@ function testRuleChanges()
|
||||
is(selectors[2].textContent.indexOf(".testclass"), 0, "Third item is class rule.");
|
||||
|
||||
// Change the id and refresh.
|
||||
inspector.once("rule-view-refreshed", testRuleChange1);
|
||||
testElement.setAttribute("id", "differentid");
|
||||
promiseDone(ruleView.nodeChanged().then(() => {
|
||||
let selectors = ruleView.doc.querySelectorAll(".ruleview-selector");
|
||||
is(selectors.length, 2, "Two rules visible.");
|
||||
is(selectors[0].textContent.indexOf("element"), 0, "First item is inline style.");
|
||||
is(selectors[1].textContent.indexOf(".testclass"), 0, "Second item is class rule.");
|
||||
}
|
||||
|
||||
testElement.setAttribute("id", "testid");
|
||||
return ruleView.nodeChanged();
|
||||
}).then(() => {
|
||||
// Put the id back.
|
||||
let selectors = ruleView.doc.querySelectorAll(".ruleview-selector");
|
||||
is(selectors.length, 3, "Three rules visible.");
|
||||
is(selectors[0].textContent.indexOf("element"), 0, "First item is inline style.");
|
||||
is(selectors[1].textContent.indexOf("#testid"), 0, "Second item is id rule.");
|
||||
is(selectors[2].textContent.indexOf(".testclass"), 0, "Third item is class rule.");
|
||||
function testRuleChange1()
|
||||
{
|
||||
let selectors = ruleView.doc.querySelectorAll(".ruleview-selector");
|
||||
is(selectors.length, 2, "Two rules visible.");
|
||||
is(selectors[0].textContent.indexOf("element"), 0, "First item is inline style.");
|
||||
is(selectors[1].textContent.indexOf(".testclass"), 0, "Second item is class rule.");
|
||||
|
||||
testPropertyChanges();
|
||||
}));
|
||||
inspector.once("rule-view-refreshed", testRuleChange2);
|
||||
testElement.setAttribute("id", "testid");
|
||||
}
|
||||
function testRuleChange2()
|
||||
{
|
||||
let selectors = ruleView.doc.querySelectorAll(".ruleview-selector");
|
||||
is(selectors.length, 3, "Three rules visible.");
|
||||
is(selectors[0].textContent.indexOf("element"), 0, "First item is inline style.");
|
||||
is(selectors[1].textContent.indexOf("#testid"), 0, "Second item is id rule.");
|
||||
is(selectors[2].textContent.indexOf(".testclass"), 0, "Third item is class rule.");
|
||||
|
||||
testPropertyChanges();
|
||||
}
|
||||
|
||||
function validateTextProp(aProp, aEnabled, aName, aValue, aDesc)
|
||||
@ -77,65 +80,86 @@ function validateTextProp(aProp, aEnabled, aName, aValue, aDesc)
|
||||
|
||||
function testPropertyChanges()
|
||||
{
|
||||
// Add a second margin-top value, just to make things interesting.
|
||||
let rule = ruleView._elementStyle.rules[0];
|
||||
rule = ruleView._elementStyle.rules[0];
|
||||
let ruleEditor = ruleView._elementStyle.rules[0].editor;
|
||||
inspector.once("rule-view-refreshed", testPropertyChange0);
|
||||
|
||||
// Add a second margin-top value, just to make things interesting.
|
||||
ruleEditor.addProperty("margin-top", "5px", "");
|
||||
promiseDone(expectRuleChange(rule).then(() => {
|
||||
// Set the element style back to a 1px margin-top.
|
||||
testElement.setAttribute("style", "margin-top: 1px; padding-top: 5px");
|
||||
return ruleView.nodeChanged();
|
||||
}).then(() => {
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[0], true, "margin-top", "1px", "First margin property re-enabled");
|
||||
validateTextProp(rule.textProps[2], false, "margin-top", "5px", "Second margin property disabled");
|
||||
}
|
||||
|
||||
// Now set it back to 5px, the 5px value should be re-enabled.
|
||||
testElement.setAttribute("style", "margin-top: 5px; padding-top: 5px;");
|
||||
return ruleView.nodeChanged();
|
||||
function testPropertyChange0()
|
||||
{
|
||||
validateTextProp(rule.textProps[0], false, "margin-top", "1px", "Original margin property active");
|
||||
|
||||
}).then(() => {
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[0], false, "margin-top", "1px", "First margin property re-enabled");
|
||||
validateTextProp(rule.textProps[2], true, "margin-top", "5px", "Second margin property disabled");
|
||||
inspector.once("rule-view-refreshed", testPropertyChange1);
|
||||
testElement.setAttribute("style", "margin-top: 1px; padding-top: 5px");
|
||||
}
|
||||
function testPropertyChange1()
|
||||
{
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[0], true, "margin-top", "1px", "First margin property re-enabled");
|
||||
validateTextProp(rule.textProps[2], false, "margin-top", "5px", "Second margin property disabled");
|
||||
|
||||
// Set the margin property to a value that doesn't exist in the editor.
|
||||
// Should reuse the currently-enabled element (the second one.)
|
||||
testElement.setAttribute("style", "margin-top: 15px; padding-top: 5px;");
|
||||
return ruleView.nodeChanged();
|
||||
}).then(() => {
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[0], false, "margin-top", "1px", "First margin property re-enabled");
|
||||
validateTextProp(rule.textProps[2], true, "margin-top", "15px", "Second margin property disabled");
|
||||
inspector.once("rule-view-refreshed", testPropertyChange2);
|
||||
|
||||
// Remove the padding-top attribute. Should disable the padding property but not remove it.
|
||||
testElement.setAttribute("style", "margin-top: 5px;");
|
||||
return ruleView.nodeChanged();
|
||||
}).then(() => {
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[1], false, "padding-top", "5px", "Padding property disabled");
|
||||
// Now set it back to 5px, the 5px value should be re-enabled.
|
||||
testElement.setAttribute("style", "margin-top: 5px; padding-top: 5px;");
|
||||
}
|
||||
function testPropertyChange2()
|
||||
{
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[0], false, "margin-top", "1px", "First margin property re-enabled");
|
||||
validateTextProp(rule.textProps[2], true, "margin-top", "5px", "Second margin property disabled");
|
||||
|
||||
// Put the padding-top attribute back in, should re-enable the padding property.
|
||||
testElement.setAttribute("style", "margin-top: 5px; padding-top: 25px");
|
||||
return ruleView.nodeChanged();
|
||||
}).then(() => {
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[1], true, "padding-top", "25px", "Padding property enabled");
|
||||
inspector.once("rule-view-refreshed", testPropertyChange3);
|
||||
|
||||
// Add an entirely new property.
|
||||
testElement.setAttribute("style", "margin-top: 5px; padding-top: 25px; padding-left: 20px;");
|
||||
return ruleView.nodeChanged();
|
||||
}).then(() => {
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 4, "Added a property");
|
||||
validateTextProp(rule.textProps[3], true, "padding-left", "20px", "Padding property enabled");
|
||||
// Set the margin property to a value that doesn't exist in the editor.
|
||||
// Should reuse the currently-enabled element (the second one.)
|
||||
testElement.setAttribute("style", "margin-top: 15px; padding-top: 5px;");
|
||||
}
|
||||
function testPropertyChange3()
|
||||
{
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[0], false, "margin-top", "1px", "First margin property re-enabled");
|
||||
validateTextProp(rule.textProps[2], true, "margin-top", "15px", "Second margin property disabled");
|
||||
|
||||
finishTest();
|
||||
}));
|
||||
inspector.once("rule-view-refreshed", testPropertyChange4);
|
||||
|
||||
// Remove the padding-top attribute. Should disable the padding property but not remove it.
|
||||
testElement.setAttribute("style", "margin-top: 5px;");
|
||||
}
|
||||
function testPropertyChange4()
|
||||
{
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[1], false, "padding-top", "5px", "Padding property disabled");
|
||||
|
||||
inspector.once("rule-view-refreshed", testPropertyChange5);
|
||||
|
||||
// Put the padding-top attribute back in, should re-enable the padding property.
|
||||
testElement.setAttribute("style", "margin-top: 5px; padding-top: 25px");
|
||||
}
|
||||
function testPropertyChange5()
|
||||
{
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[1], true, "padding-top", "25px", "Padding property enabled");
|
||||
|
||||
inspector.once("rule-view-refreshed", testPropertyChange6);
|
||||
|
||||
// Add an entirely new property
|
||||
testElement.setAttribute("style", "margin-top: 5px; padding-top: 25px; padding-left: 20px;");
|
||||
}
|
||||
function testPropertyChange6()
|
||||
{
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 4, "Added a property");
|
||||
validateTextProp(rule.textProps[3], true, "padding-left", "20px", "Padding property enabled");
|
||||
|
||||
finishTest();
|
||||
}
|
||||
|
||||
function finishTest()
|
||||
{
|
||||
inspector = ruleView = null;
|
||||
inspector = ruleView = rule = null;
|
||||
doc = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
|
@ -73,6 +73,7 @@
|
||||
<!ENTITY projects.debugAppTooltip "Open Developer Tools connected to this app">
|
||||
<!ENTITY projects.hostedManifestPlaceHolder2 "http://example.com/app/manifest.webapp">
|
||||
<!ENTITY projects.noProjects "No projects. Add a new packaged app below (local directory) or a hosted app (link to a manifest file).">
|
||||
<!ENTITY projects.manifestEditor "Manifest Editor">
|
||||
|
||||
<!ENTITY help.title "App Manager">
|
||||
<!ENTITY help.close "Close">
|
||||
|
@ -19,4 +19,4 @@
|
||||
<!ENTITY errorTimeout "Error: connection timeout.">
|
||||
<!ENTITY errorRefused "Error: connection refused.">
|
||||
<!ENTITY errorUnexpected "Unexpected error.">
|
||||
<!ENTITY help "Firefox Developer Tools can debug remote devices (Firefox for Android and Firefox OS, for example). Make sure that you have turned on the 'Remote debugging' option in the remote device. See the <a target='_' href='https://developer.mozilla.org/docs/Tools/Debugger#Remote_Debugging'>documentation</a> for more.">
|
||||
<!ENTITY help2 "Firefox Developer Tools can debug remote devices (Firefox for Android and Firefox OS, for example). Make sure that you have turned on the 'Remote debugging' option in the remote device. See the <a target='_' href='https://developer.mozilla.org/docs/Tools/Remote_Debugging'>documentation</a> for more.">
|
||||
|
@ -548,6 +548,7 @@ let DOMEvents = {
|
||||
DOMEvents.init();
|
||||
|
||||
let ContentScroll = {
|
||||
// The most recent offset set by APZC for the root scroll frame
|
||||
_scrollOffset: { x: 0, y: 0 },
|
||||
|
||||
init: function() {
|
||||
@ -617,9 +618,13 @@ let ContentScroll = {
|
||||
|
||||
// Set the scroll offset for this element if specified
|
||||
if (json.scrollX >= 0 || json.scrollY >= 0) {
|
||||
this.setScrollOffsetForElement(element, json.scrollX, json.scrollY)
|
||||
if (json.id == 1)
|
||||
this.setScrollOffsetForElement(element, json.scrollX, json.scrollY);
|
||||
if (element == content.document.documentElement) {
|
||||
// scrollTo can make some small adjustments to the offset before
|
||||
// actually scrolling the document. To ensure that _scrollOffset
|
||||
// actually matches the offset stored in the window, re-query it.
|
||||
this._scrollOffset = this.getScrollOffset(content);
|
||||
}
|
||||
}
|
||||
|
||||
// Set displayport. We want to set this after setting the scroll offset, because
|
||||
@ -690,6 +695,9 @@ let ContentScroll = {
|
||||
|
||||
if (target == content.document) {
|
||||
if (this._scrollOffset.x == scrollOffset.x && this._scrollOffset.y == scrollOffset.y) {
|
||||
// Don't send a scroll message back to APZC if it's the same as the
|
||||
// last one set by APZC. We use this to avoid sending APZC back an
|
||||
// event that it originally triggered.
|
||||
return;
|
||||
}
|
||||
this._scrollOffset = scrollOffset;
|
||||
|
@ -66,6 +66,10 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
/* Black box message and source progress meter */
|
||||
|
||||
#black-boxed-message,
|
||||
|
@ -64,6 +64,10 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
/* Black box message and source progress meter */
|
||||
|
||||
#black-boxed-message,
|
||||
|
@ -231,6 +231,7 @@ strong {
|
||||
#lense > div {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
@ -240,8 +241,13 @@ strong {
|
||||
.project-details {
|
||||
background-color: rgb(225, 225, 225);
|
||||
padding: 10px;
|
||||
flex-grow: 1;
|
||||
line-height: 160%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.project-metadata {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.project-status {
|
||||
@ -438,3 +444,44 @@ strong {
|
||||
padding-left: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
/********* MANIFEST EDITOR ***********/
|
||||
|
||||
.manifest-editor {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
background-color: #E1E1E1;
|
||||
}
|
||||
|
||||
.manifest-editor > h2 {
|
||||
font-size: 18px;
|
||||
margin: 1em 30px;
|
||||
}
|
||||
|
||||
.variables-view {
|
||||
flex-grow: 1;
|
||||
border: 0;
|
||||
border-top: 5px solid #C9C9C9;
|
||||
}
|
||||
|
||||
/* Bug 925921: Remove when the manifest editor is always on */
|
||||
|
||||
.manifest-editor {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.project-details {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#lense[manifest-editable] .manifest-editor {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#lense[manifest-editable] .project-details {
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
/* End blocks to remove */
|
||||
|
@ -64,6 +64,10 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
/* Black box message and source progress meter */
|
||||
|
||||
#black-boxed-message,
|
||||
|
@ -77,7 +77,7 @@ class nsGeolocationRequest
|
||||
void Shutdown();
|
||||
|
||||
void SendLocation(nsIDOMGeoPosition* location);
|
||||
bool WantsHighAccuracy() {return mOptions && mOptions->mEnableHighAccuracy;}
|
||||
bool WantsHighAccuracy() {return !mShutdown && mOptions && mOptions->mEnableHighAccuracy;}
|
||||
void SetTimeoutTimer();
|
||||
nsIPrincipal* GetPrincipal();
|
||||
|
||||
@ -445,7 +445,7 @@ nsGeolocationRequest::Allow()
|
||||
maximumAge = mOptions->mMaximumAge;
|
||||
}
|
||||
}
|
||||
gs->SetHigherAccuracy(mOptions && mOptions->mEnableHighAccuracy);
|
||||
gs->UpdateAccuracy(WantsHighAccuracy());
|
||||
|
||||
bool canUseCache = lastPosition && maximumAge > 0 &&
|
||||
(PRTime(PR_Now() / PR_USEC_PER_MSEC) - maximumAge <=
|
||||
@ -585,12 +585,12 @@ nsGeolocationRequest::Shutdown()
|
||||
mTimeoutTimer = nullptr;
|
||||
}
|
||||
|
||||
// This should happen last, to ensure that this request isn't taken into consideration
|
||||
// when deciding whether existing requests still require high accuracy.
|
||||
// If there are no other high accuracy requests, the geolocation service will
|
||||
// notify the provider to switch to the default accuracy.
|
||||
if (mOptions && mOptions->mEnableHighAccuracy) {
|
||||
nsRefPtr<nsGeolocationService> gs = nsGeolocationService::GetGeolocationService();
|
||||
if (gs) {
|
||||
gs->SetHigherAccuracy(false);
|
||||
gs->UpdateAccuracy();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -901,9 +901,9 @@ nsGeolocationService::HighAccuracyRequested()
|
||||
}
|
||||
|
||||
void
|
||||
nsGeolocationService::SetHigherAccuracy(bool aEnable)
|
||||
nsGeolocationService::UpdateAccuracy(bool aForceHigh)
|
||||
{
|
||||
bool highRequired = aEnable || HighAccuracyRequested();
|
||||
bool highRequired = aForceHigh || HighAccuracyRequested();
|
||||
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
||||
ContentChild* cpc = ContentChild::GetSingleton();
|
||||
@ -1061,6 +1061,7 @@ Geolocation::Shutdown()
|
||||
|
||||
if (mService) {
|
||||
mService->RemoveLocator(this);
|
||||
mService->UpdateAccuracy();
|
||||
}
|
||||
|
||||
mService = nullptr;
|
||||
|
@ -85,8 +85,8 @@ public:
|
||||
// create, or reinitalize the callback timer
|
||||
void SetDisconnectTimer();
|
||||
|
||||
// request higher accuracy, if possible
|
||||
void SetHigherAccuracy(bool aEnable);
|
||||
// Update the accuracy and notify the provider if changed
|
||||
void UpdateAccuracy(bool aForceHigh = false);
|
||||
bool HighAccuracyRequested();
|
||||
|
||||
private:
|
||||
|
@ -73,6 +73,9 @@ function WifiGeoPositionProvider() {
|
||||
this.timer = null;
|
||||
this.hasSeenWiFi = false;
|
||||
this.started = false;
|
||||
// this is only used when logging is enabled, to debug interactions with the
|
||||
// geolocation service
|
||||
this.highAccuracy = false;
|
||||
}
|
||||
|
||||
WifiGeoPositionProvider.prototype = {
|
||||
@ -132,10 +135,12 @@ WifiGeoPositionProvider.prototype = {
|
||||
},
|
||||
|
||||
setHighAccuracy: function(enable) {
|
||||
this.highAccuracy = enable;
|
||||
LOG("setting highAccuracy to " + (this.highAccuracy?"TRUE":"FALSE"));
|
||||
},
|
||||
|
||||
onChange: function(accessPoints) {
|
||||
LOG("onChange called");
|
||||
LOG("onChange called, highAccuracy = " + (this.highAccuracy?"TRUE":"FALSE"));
|
||||
this.hasSeenWiFi = true;
|
||||
|
||||
let url = Services.urlFormatter.formatURLPref("geo.wifi.uri");
|
||||
|
104
dom/tests/unit/test_geolocation_reset_accuracy.js
Normal file
104
dom/tests/unit/test_geolocation_reset_accuracy.js
Normal file
@ -0,0 +1,104 @@
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
const providerCID = Components.ID("{14aa4b81-e266-45cb-88f8-89595dece114}");
|
||||
const providerContract = "@mozilla.org/geolocation/provider;1";
|
||||
|
||||
const categoryName = "geolocation-provider";
|
||||
|
||||
var provider = {
|
||||
QueryInterface: function eventsink_qi(iid) {
|
||||
if (iid.equals(Components.interfaces.nsISupports) ||
|
||||
iid.equals(Components.interfaces.nsIFactory) ||
|
||||
iid.equals(Components.interfaces.nsIGeolocationProvider))
|
||||
return this;
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
createInstance: function eventsink_ci(outer, iid) {
|
||||
if (outer)
|
||||
throw Components.results.NS_ERROR_NO_AGGREGATION;
|
||||
return this.QueryInterface(iid);
|
||||
},
|
||||
lockFactory: function eventsink_lockf(lock) {
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
startup: function() {
|
||||
},
|
||||
watch: function() {
|
||||
},
|
||||
shutdown: function() {
|
||||
},
|
||||
setHighAccuracy: function(enable) {
|
||||
this._isHigh = enable;
|
||||
if (enable) {
|
||||
this._seenHigh = true;
|
||||
}
|
||||
},
|
||||
_isHigh: false,
|
||||
_seenHigh: false
|
||||
};
|
||||
|
||||
let runningInParent = true;
|
||||
try {
|
||||
runningInParent = Components.classes["@mozilla.org/xre/runtime;1"].
|
||||
getService(Components.interfaces.nsIXULRuntime).processType
|
||||
== Components.interfaces.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
|
||||
}
|
||||
catch (e) { }
|
||||
|
||||
function successCallback()
|
||||
{
|
||||
do_check_true(false);
|
||||
do_test_finished();
|
||||
}
|
||||
|
||||
function errorCallback()
|
||||
{
|
||||
do_check_true(false);
|
||||
do_test_finished();
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
if (runningInParent) {
|
||||
// XPCShell does not get a profile by default. The geolocation service
|
||||
// depends on the settings service which uses IndexedDB and IndexedDB
|
||||
// needs a place where it can store databases.
|
||||
do_get_profile();
|
||||
|
||||
Components.manager.nsIComponentRegistrar.registerFactory(providerCID,
|
||||
"Unit test geo provider", providerContract, provider);
|
||||
var catMan = Components.classes["@mozilla.org/categorymanager;1"]
|
||||
.getService(Components.interfaces.nsICategoryManager);
|
||||
catMan.nsICategoryManager.addCategoryEntry(categoryName, "unit test",
|
||||
providerContract, false, true);
|
||||
|
||||
var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
|
||||
prefs.setBoolPref("geo.testing.ignore_ipc_principal", true);
|
||||
prefs.setBoolPref("geo.wifi.scan", false);
|
||||
}
|
||||
|
||||
let geolocation = Cc["@mozilla.org/geolocation;1"].createInstance(Ci.nsISupports);
|
||||
|
||||
do_test_pending();
|
||||
|
||||
let watchID1 = geolocation.watchPosition(successCallback, errorCallback);
|
||||
let watchID2 = geolocation.watchPosition(successCallback, errorCallback,
|
||||
{enableHighAccuracy: true});
|
||||
|
||||
do_timeout(1000, function() {
|
||||
geolocation.clearWatch(watchID2);
|
||||
do_timeout(1000, check_results);
|
||||
});
|
||||
}
|
||||
|
||||
function check_results()
|
||||
{
|
||||
if (runningInParent) {
|
||||
// check the provider was set to high accuracy during the test
|
||||
do_check_true(provider._seenHigh);
|
||||
// check the provider is not currently set to high accuracy
|
||||
do_check_false(provider._isHigh);
|
||||
}
|
||||
do_test_finished();
|
||||
}
|
70
dom/tests/unit/test_geolocation_reset_accuracy_wrap.js
Normal file
70
dom/tests/unit/test_geolocation_reset_accuracy_wrap.js
Normal file
@ -0,0 +1,70 @@
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
const providerCID = Components.ID("{14aa4b81-e266-45cb-88f8-89595dece114}");
|
||||
const providerContract = "@mozilla.org/geolocation/provider;1";
|
||||
|
||||
const categoryName = "geolocation-provider";
|
||||
|
||||
var provider = {
|
||||
QueryInterface: function eventsink_qi(iid) {
|
||||
if (iid.equals(Components.interfaces.nsISupports) ||
|
||||
iid.equals(Components.interfaces.nsIFactory) ||
|
||||
iid.equals(Components.interfaces.nsIGeolocationProvider))
|
||||
return this;
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
createInstance: function eventsink_ci(outer, iid) {
|
||||
if (outer)
|
||||
throw Components.results.NS_ERROR_NO_AGGREGATION;
|
||||
return this.QueryInterface(iid);
|
||||
},
|
||||
lockFactory: function eventsink_lockf(lock) {
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
startup: function() {
|
||||
},
|
||||
watch: function() {
|
||||
},
|
||||
shutdown: function() {
|
||||
},
|
||||
setHighAccuracy: function(enable) {
|
||||
this._isHigh = enable;
|
||||
if (enable) {
|
||||
this._seenHigh = true;
|
||||
}
|
||||
},
|
||||
_isHigh: false,
|
||||
_seenHigh: false
|
||||
};
|
||||
|
||||
function run_test()
|
||||
{
|
||||
// XPCShell does not get a profile by default. The geolocation service
|
||||
// depends on the settings service which uses IndexedDB and IndexedDB
|
||||
// needs a place where it can store databases.
|
||||
do_get_profile();
|
||||
|
||||
Components.manager.nsIComponentRegistrar.registerFactory(providerCID,
|
||||
"Unit test geo provider", providerContract, provider);
|
||||
var catMan = Components.classes["@mozilla.org/categorymanager;1"]
|
||||
.getService(Components.interfaces.nsICategoryManager);
|
||||
catMan.nsICategoryManager.addCategoryEntry(categoryName, "unit test",
|
||||
providerContract, false, true);
|
||||
|
||||
var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
|
||||
prefs.setBoolPref("geo.testing.ignore_ipc_principal", true);
|
||||
prefs.setBoolPref("geo.wifi.scan", false);
|
||||
|
||||
run_test_in_child("test_geolocation_reset_accuracy.js", check_results);
|
||||
}
|
||||
|
||||
function check_results()
|
||||
{
|
||||
// check the provider was set to high accuracy during the test
|
||||
do_check_true(provider._seenHigh);
|
||||
// check the provider is not currently set to high accuracy
|
||||
do_check_false(provider._isHigh);
|
||||
|
||||
do_test_finished();
|
||||
}
|
@ -12,3 +12,8 @@ skip-if = os == "android"
|
||||
skip-if = os == "android"
|
||||
[test_geolocation_timeout_wrap.js]
|
||||
skip-if = os == "mac" || os == "android"
|
||||
[test_geolocation_reset_accuracy.js]
|
||||
# Bug 919946: test hangs consistently on Android
|
||||
skip-if = os == "android"
|
||||
[test_geolocation_reset_accuracy_wrap.js]
|
||||
skip-if = os == "mac" || os == "android"
|
||||
|
@ -27,6 +27,7 @@ import org.mozilla.gecko.R;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.NoSuchFieldException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
@ -81,6 +82,19 @@ public final class BitmapUtils {
|
||||
return;
|
||||
}
|
||||
|
||||
if(data.startsWith("-moz-icon://")) {
|
||||
Uri imageUri = Uri.parse(data);
|
||||
String resource = imageUri.getSchemeSpecificPart();
|
||||
resource = resource.substring(resource.lastIndexOf('/') + 1);
|
||||
|
||||
try {
|
||||
Drawable d = context.getPackageManager().getApplicationIcon(resource);
|
||||
loader.onBitmapFound(d);
|
||||
} catch(Exception ex) { }
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(data.startsWith("drawable://")) {
|
||||
Uri imageUri = Uri.parse(data);
|
||||
int id = getResource(imageUri, R.drawable.ic_status_logo);
|
||||
@ -282,11 +296,34 @@ public final class BitmapUtils {
|
||||
if ("drawable".equals(scheme)) {
|
||||
String resource = resourceUrl.getSchemeSpecificPart();
|
||||
resource = resource.substring(resource.lastIndexOf('/') + 1);
|
||||
|
||||
try {
|
||||
return Integer.parseInt(resource);
|
||||
} catch(NumberFormatException ex) {
|
||||
// This isn't a resource id, try looking for a string
|
||||
}
|
||||
|
||||
try {
|
||||
final Class<R.drawable> drawableClass = R.drawable.class;
|
||||
final Field f = drawableClass.getField(resource);
|
||||
icon = f.getInt(null);
|
||||
} catch (final Exception e) {} // just means the resource doesn't exist
|
||||
} catch (final NoSuchFieldException e1) {
|
||||
|
||||
// just means the resource doesn't exist for fennec. Check in Android resources
|
||||
try {
|
||||
final Class<android.R.drawable> drawableClass = android.R.drawable.class;
|
||||
final Field f = drawableClass.getField(resource);
|
||||
icon = f.getInt(null);
|
||||
} catch (final NoSuchFieldException e2) {
|
||||
// This drawable doesn't seem to exist...
|
||||
} catch(Exception e3) {
|
||||
Log.i(LOGTAG, "Exception getting drawable", e3);
|
||||
}
|
||||
|
||||
} catch (Exception e4) {
|
||||
Log.i(LOGTAG, "Exception getting drawable", e4);
|
||||
}
|
||||
|
||||
resourceUrl = null;
|
||||
}
|
||||
return icon;
|
||||
|
@ -20,7 +20,6 @@ import android.widget.TextView;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* This class is an extension of BaseTest that helps with interaction with about:home
|
||||
@ -28,7 +27,7 @@ import java.util.Arrays;
|
||||
* The purpose of this class is to collect all the logically connected methods that deal with about:home
|
||||
* To use any of these methods in your test make sure it extends AboutHomeTest instead of BaseTest
|
||||
*/
|
||||
abstract class AboutHomeTest extends BaseTest {
|
||||
abstract class AboutHomeTest extends PixelTest {
|
||||
protected enum AboutHomeTabs {HISTORY, MOST_RECENT, TABS_FROM_LAST_TIME, TOP_SITES, BOOKMARKS, READING_LIST};
|
||||
private ArrayList<String> aboutHomeTabs = new ArrayList<String>() {{
|
||||
add("TOP_SITES");
|
||||
@ -98,10 +97,6 @@ abstract class AboutHomeTest extends BaseTest {
|
||||
// @return the View associated with bookmark for the provided url or null if the link is not bookmarked
|
||||
protected View getDisplayedBookmark(String url) {
|
||||
openAboutHomeTab(AboutHomeTabs.BOOKMARKS);
|
||||
if (!mDevice.type.equals("tablet")) {
|
||||
toggleVKB(); // dismiss the keyboard to make sure this works on small screen devices
|
||||
}
|
||||
getInstrumentation().waitForIdleSync();
|
||||
ListView bookmarksTabList = findListViewWithTag("bookmarks");
|
||||
waitForNonEmptyListToLoad(bookmarksTabList);
|
||||
ListAdapter adapter = bookmarksTabList.getAdapter();
|
||||
@ -182,30 +177,59 @@ abstract class AboutHomeTest extends BaseTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param1 a String with the original url
|
||||
* @param2 a String array with the new values for all fields
|
||||
* FIXME: rewrite this to work with fig when rewriting the testBookmarksTab test
|
||||
* This method will edit the bookmark with index = bookmarkIndex from the list of bookmarks
|
||||
* For the field index:
|
||||
* fieldIndex = 1 - the Bookmark name
|
||||
* fieldIndex = 2 - the Bookmark url
|
||||
* fieldIndex = 3 - the Bookmark keyword
|
||||
*/
|
||||
protected void editBookmark(String originalUrl, String[] newValues) {
|
||||
openBookmarkContextMenu(originalUrl);
|
||||
protected void editBookmark(int bookmarkIndex, int fieldIndex, String addedText, ListView list) {
|
||||
|
||||
// Open the Edit Bookmark context menu
|
||||
View child;
|
||||
mSolo.clickOnText("Bookmarks");
|
||||
child = list.getChildAt(bookmarkIndex);
|
||||
mAsserter.ok(child != null, "edit item can be retrieved", child != null ? child.toString() : "null!");
|
||||
waitForText("Switch to tab");
|
||||
mSolo.clickLongOnView(child);
|
||||
waitForText("Share");
|
||||
mSolo.clickOnText("Edit");
|
||||
waitForText("Edit Bookmark");
|
||||
for (String value:newValues) {
|
||||
mSolo.clearEditText(Arrays.asList(newValues).indexOf(value));
|
||||
mSolo.clickOnEditText(Arrays.asList(newValues).indexOf(value));
|
||||
mActions.sendKeys(value);
|
||||
}
|
||||
mSolo.clickOnButton("OK");
|
||||
|
||||
// Clear the Field
|
||||
mSolo.clearEditText(fieldIndex);
|
||||
|
||||
// Enter the new text
|
||||
mSolo.clickOnEditText(fieldIndex);
|
||||
mActions.sendKeys(addedText);
|
||||
mSolo.clickOnText("OK");
|
||||
waitForText("Bookmark updated");
|
||||
}
|
||||
|
||||
protected void checkBookmarkEdit(String bookmarkUrl, String[] values) {
|
||||
openBookmarkContextMenu(bookmarkUrl);
|
||||
// FIXME: rewrite this to work with fig when rewriting the testBookmarksTab test
|
||||
protected boolean checkBookmarkEdit(int bookmarkIndex, String addedText, ListView list) {
|
||||
// Open the Edit Bookmark context menu
|
||||
View child;
|
||||
mSolo.clickOnText("Bookmarks");
|
||||
child = list.getChildAt(bookmarkIndex);
|
||||
mAsserter.ok(child != null, "check item can be retrieved", child != null ? child.toString() : "null!");
|
||||
waitForText("Switch to tab");
|
||||
mSolo.clickLongOnView(child);
|
||||
waitForText("Share");
|
||||
mSolo.clickOnText("Edit");
|
||||
for (String value:values) {
|
||||
mAsserter.ok(mSolo.searchText(value), "Checking that the value is correct", "The value = " + value + " is correct");
|
||||
waitForText("Edit Bookmark");
|
||||
|
||||
// Check if the new text was added
|
||||
if (mSolo.searchText(addedText)) {
|
||||
clickOnButton("Cancel");
|
||||
waitForText("about:home");
|
||||
return true;
|
||||
} else {
|
||||
clickOnButton("Cancel");
|
||||
waitForText("about:home");
|
||||
return false;
|
||||
}
|
||||
clickOnButton("Cancel");
|
||||
waitForText("BOOKMARKS");
|
||||
}
|
||||
|
||||
// A wait in order for the about:home tab to be rendered after drag/tab selection
|
||||
@ -256,12 +280,15 @@ abstract class AboutHomeTest extends BaseTest {
|
||||
protected void openAboutHomeTab(AboutHomeTabs tab) {
|
||||
focusUrlBar();
|
||||
ViewPager pager = (ViewPager)mSolo.getView(ViewPager.class, 0);
|
||||
final int currentTabIndex = pager.getCurrentItem();
|
||||
int tabOffset;
|
||||
|
||||
// Handle tablets by just clicking the visible tab title.
|
||||
if (mDevice.type.equals("tablet")) {
|
||||
// Just click for tablets, since all the titles are visible.
|
||||
if (AboutHomeTabs.MOST_RECENT == tab || AboutHomeTabs.TABS_FROM_LAST_TIME == tab) {
|
||||
mSolo.clickOnText(AboutHomeTabs.HISTORY.toString());
|
||||
tabOffset = aboutHomeTabs.indexOf(AboutHomeTabs.HISTORY.toString()) - currentTabIndex;
|
||||
swipeAboutHome(tabOffset);
|
||||
waitForAboutHomeTab(aboutHomeTabs.indexOf(StringHelper.HISTORY_LABEL));
|
||||
TabWidget tabwidget = (TabWidget)mSolo.getView(TabWidget.class, 0);
|
||||
|
||||
switch (tab) {
|
||||
@ -284,8 +311,7 @@ abstract class AboutHomeTest extends BaseTest {
|
||||
}
|
||||
|
||||
// Handle phones (non-tablets).
|
||||
final int currentTabIndex = pager.getCurrentItem();
|
||||
int tabOffset = aboutHomeTabs.indexOf(tab.toString()) - currentTabIndex;
|
||||
tabOffset = aboutHomeTabs.indexOf(tab.toString()) - currentTabIndex;
|
||||
switch (tab) {
|
||||
case TOP_SITES : {
|
||||
swipeAboutHome(tabOffset);
|
||||
|
@ -45,8 +45,6 @@ class StringHelper {
|
||||
"Add to Home Screen"
|
||||
};
|
||||
|
||||
public static final String[] BOOKMARK_CONTEXT_MENU_ITEMS = {"Open in New Tab", "Open in Private Tab", "Share", "Edit", "Remove", "Add to Home Screen"};
|
||||
|
||||
// Robocop page urls
|
||||
// Note: please use getAbsoluteUrl(String url) on each robocop url to get the correct url
|
||||
public static final String ROBOCOP_BIG_LINK_URL = "/robocop/robocop_big_link.html";
|
||||
|
@ -1,7 +1,6 @@
|
||||
[testAwesomebar]
|
||||
# [testAwesomebarSwipes] # disabled on fig - bug 880060
|
||||
[testBookmark]
|
||||
[testBookmarksPage]
|
||||
# [testBookmarklets] # see bug 915350
|
||||
# [testBookmarkKeyword] # see bug 915350
|
||||
[testBrowserSearchVisibility]
|
||||
@ -46,6 +45,7 @@
|
||||
[testMasterPassword]
|
||||
[testDeviceSearchEngine]
|
||||
[testPrivateBrowsing]
|
||||
[testReaderMode]
|
||||
|
||||
# Used for Talos, please don't use in mochitest
|
||||
#[testPan]
|
||||
|
@ -1,223 +0,0 @@
|
||||
#filter substitution
|
||||
package @ANDROID_PACKAGE_NAME@.tests;
|
||||
|
||||
import @ANDROID_PACKAGE_NAME@.*;
|
||||
|
||||
import com.jayway.android.robotium.solo.Condition;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.ContentUris;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.view.View;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class testBookmarksPage extends AboutHomeTest {
|
||||
private static String BOOKMARK_URL;
|
||||
private static String DESKTOP_BOOKMARK_URL;
|
||||
|
||||
@Override
|
||||
protected int getTestType() {
|
||||
return TEST_MOCHITEST;
|
||||
}
|
||||
|
||||
public void testBookmarksPage() {
|
||||
BOOKMARK_URL = getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
|
||||
DESKTOP_BOOKMARK_URL = getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_02_URL);
|
||||
|
||||
setUpDesktopBookmarks();
|
||||
checkBookmarkList();
|
||||
checkBookmarkContextMenu();
|
||||
}
|
||||
|
||||
private void checkBookmarkList() {
|
||||
// Check that the default bookmarks are displayed
|
||||
for (String url:StringHelper.DEFAULT_BOOKMARKS_URLS) {
|
||||
mAsserter.ok(isBookmarkDisplayed(url), "Checking that default bookmark: " + url + " is displayed in the bookmarks list", url + " is displayed as a bookmark");
|
||||
}
|
||||
mAsserter.ok(isBookmarkDisplayed(BOOKMARK_URL), "Checking that added bookmark: " + BOOKMARK_URL + " is displayed in the bookmarks list", BOOKMARK_URL + " is displayed as a bookmark");
|
||||
|
||||
waitForText(StringHelper.DESKTOP_FOLDER_LABEL);
|
||||
clickOnBookmarkFolder(StringHelper.DESKTOP_FOLDER_LABEL);
|
||||
waitForText(StringHelper.TOOLBAR_FOLDER_LABEL);
|
||||
|
||||
// Verify the number of folders displayed in the Desktop Bookmarks folder is correct
|
||||
ListView desktopFolderContent = findListViewWithTag("bookmarks");
|
||||
ListAdapter adapter = desktopFolderContent.getAdapter();
|
||||
if (mDevice.type.equals("tablet")) { // On tablets it's 4 folders and 1 view for top padding
|
||||
mAsserter.is(adapter.getCount(), 5, "Checking that the correct number of folders is displayed in the Desktop Bookmarks folder");
|
||||
} else { // On phones it's just the 4 folders
|
||||
mAsserter.is(adapter.getCount(), 4, "Checking that the correct number of folders is displayed in the Desktop Bookmarks folder");
|
||||
}
|
||||
|
||||
clickOnBookmarkFolder(StringHelper.TOOLBAR_FOLDER_LABEL);
|
||||
|
||||
// Go up in the bookmark folder hierarchy
|
||||
clickOnBookmarkFolder(StringHelper.TOOLBAR_FOLDER_LABEL);
|
||||
mAsserter.ok(waitForText(StringHelper.BOOKMARKS_MENU_FOLDER_LABEL), "Going up in the folder hierarchy", "We are back in the Desktop Bookmarks folder");
|
||||
|
||||
clickOnBookmarkFolder(StringHelper.DESKTOP_FOLDER_LABEL);
|
||||
mAsserter.ok(waitForText(StringHelper.DESKTOP_FOLDER_LABEL), "Going up in the folder hierarchy", "We are back in the main Bookmarks List View");
|
||||
|
||||
clickOnBookmarkFolder(StringHelper.DESKTOP_FOLDER_LABEL);
|
||||
clickOnBookmarkFolder(StringHelper.TOOLBAR_FOLDER_LABEL);
|
||||
mAsserter.ok(isBookmarkDisplayed(DESKTOP_BOOKMARK_URL), "Checking that added bookmark: " + DESKTOP_BOOKMARK_URL + " is displayed in the bookmarks list", DESKTOP_BOOKMARK_URL + " is displayed as a bookmark");
|
||||
|
||||
// Open the bookmark from a bookmark folder hierarchy
|
||||
loadBookmark(DESKTOP_BOOKMARK_URL);
|
||||
waitForText(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE);
|
||||
verifyPageTitle(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE);
|
||||
openAboutHomeTab(AboutHomeTabs.BOOKMARKS);
|
||||
|
||||
// Check that folders don't have a context menu
|
||||
boolean success = waitForCondition(new Condition() {
|
||||
@Override
|
||||
public boolean isSatisfied() {
|
||||
View desktopFolder = getBookmarkFolderView(StringHelper.DESKTOP_FOLDER_LABEL);
|
||||
if (desktopFolder != null) {
|
||||
mSolo.clickLongOnView(desktopFolder);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}, MAX_WAIT_MS);
|
||||
mAsserter.ok(success, "Trying to long click on the Desktop Bookmarks","Desktop Bookmarks folder could not be long clicked");
|
||||
mAsserter.ok(!waitForText("Share"), "Folders do not have context menus", "The context menu was not opened");
|
||||
|
||||
// Even if no context menu is opened long clicking a folder still opens it. We need to close it.
|
||||
clickOnBookmarkFolder(StringHelper.DESKTOP_FOLDER_LABEL);
|
||||
}
|
||||
|
||||
private void checkBookmarkContextMenu() {
|
||||
// Open default bookmarks in a new tab and a new private tab since the url is substituted with "Switch to tab" after opening the link
|
||||
openBookmarkContextMenu(StringHelper.DEFAULT_BOOKMARKS_URLS[1]);
|
||||
|
||||
// Test that the options are all displayed
|
||||
for (String contextMenuOption:StringHelper.BOOKMARK_CONTEXT_MENU_ITEMS) {
|
||||
mAsserter.ok(mSolo.searchText(contextMenuOption), "Checking that the context menu option is present", contextMenuOption + " is present");
|
||||
}
|
||||
|
||||
// Test that "Open in New Tab" works
|
||||
final Element tabCount = mDriver.findElement(getActivity(), "tabs_counter");
|
||||
final int tabCountInt = Integer.parseInt(tabCount.getText());
|
||||
Actions.EventExpecter tabEventExpecter = mActions.expectGeckoEvent("Tab:Added");
|
||||
mSolo.clickOnText(StringHelper.BOOKMARK_CONTEXT_MENU_ITEMS[0]);
|
||||
tabEventExpecter.blockForEvent();
|
||||
tabEventExpecter.unregisterListener();
|
||||
|
||||
// Test that "Open in Private Tab" works
|
||||
openBookmarkContextMenu(StringHelper.DEFAULT_BOOKMARKS_URLS[2]);
|
||||
tabEventExpecter = mActions.expectGeckoEvent("Tab:Added");
|
||||
mSolo.clickOnText(StringHelper.BOOKMARK_CONTEXT_MENU_ITEMS[1]);
|
||||
tabEventExpecter.blockForEvent();
|
||||
tabEventExpecter.unregisterListener();
|
||||
|
||||
// Test that "Share" works
|
||||
openBookmarkContextMenu(BOOKMARK_URL);
|
||||
mSolo.clickOnText(StringHelper.BOOKMARK_CONTEXT_MENU_ITEMS[2]);
|
||||
mAsserter.ok(waitForText("Share via"), "Checking to see if the share menu has been opened","The share menu has been opened");
|
||||
mActions.sendSpecialKey(Actions.SpecialKey.BACK);
|
||||
waitForText(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
|
||||
|
||||
// Test that "Edit" works
|
||||
String[] editedBookmarkValues = {"New bookmark title", "www.NewBookmark.url", "newBookmarkKeyword"};
|
||||
editBookmark(BOOKMARK_URL,editedBookmarkValues);
|
||||
checkBookmarkEdit(editedBookmarkValues[1],editedBookmarkValues);
|
||||
|
||||
// Test that "Remove" works
|
||||
openBookmarkContextMenu(editedBookmarkValues[1]);
|
||||
mSolo.clickOnText(StringHelper.BOOKMARK_CONTEXT_MENU_ITEMS[4]);
|
||||
waitForText("Bookmark removed");
|
||||
mAsserter.ok(!mDatabaseHelper.isBookmark(editedBookmarkValues[1]), "Checking that the bookmark was removed", "The bookmark was removed");
|
||||
}
|
||||
|
||||
private void clickOnBookmarkFolder(final String folderName) {
|
||||
boolean success = waitForCondition(new Condition() {
|
||||
@Override
|
||||
public boolean isSatisfied() {
|
||||
View bookmarksFolder = getBookmarkFolderView(folderName);
|
||||
if (bookmarksFolder != null) {
|
||||
mSolo.clickOnView(bookmarksFolder);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}, MAX_WAIT_MS);
|
||||
mAsserter.ok(success, "Trying to click on the " + folderName + " folder","The " + folderName + " folder was clicked");
|
||||
}
|
||||
|
||||
private View getBookmarkFolderView(String folderName) {
|
||||
ListView bookmarksTabList = findListViewWithTag("bookmarks");
|
||||
ListAdapter adapter = bookmarksTabList.getAdapter();
|
||||
if (adapter != null) {
|
||||
for (int i = 0; i < adapter.getCount(); i++ ) {
|
||||
View bookmarkView = bookmarksTabList.getChildAt(i);
|
||||
if (bookmarkView instanceof TextView) {
|
||||
TextView folderTextView = (TextView) bookmarkView;
|
||||
if (folderTextView.getText().equals(folderName)) {
|
||||
return bookmarkView;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Add a bookmark in the Desktop folder so we can check the folder navigation in the bookmarks page
|
||||
private void setUpDesktopBookmarks() {
|
||||
// Get the folder id of the StringHelper.DESKTOP_FOLDER_LABEL folder
|
||||
Long desktopFolderId = mDatabaseHelper.getFolderIdFromGuid("toolbar");
|
||||
|
||||
// Generate a Guid for the bookmark
|
||||
String generatedGuid = null;
|
||||
try {
|
||||
ClassLoader classLoader = getActivity().getClassLoader();
|
||||
Class syncUtilityClass = classLoader.loadClass("org.mozilla.gecko.sync.Utils");
|
||||
Method generateGuid = syncUtilityClass.getMethod("generateGuid", (Class[]) null);
|
||||
generatedGuid = (String)generateGuid.invoke(null);
|
||||
} catch (Exception e) {
|
||||
mAsserter.dumpLog("Exception in setUpDesktopBookmarks" + e);
|
||||
}
|
||||
mAsserter.ok((generatedGuid != null), "Generating a random Guid for the bookmark", "We could not generate a Guid for the bookmark");
|
||||
|
||||
// Insert the bookmark
|
||||
ContentResolver resolver = getActivity().getContentResolver();
|
||||
Uri bookmarksUri = mDatabaseHelper.buildUri(DatabaseHelper.BrowserDataType.BOOKMARKS);
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("title", StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE);
|
||||
values.put("url", DESKTOP_BOOKMARK_URL);
|
||||
values.put("parent", desktopFolderId);
|
||||
long now = System.currentTimeMillis();
|
||||
values.put("modified", now);
|
||||
values.put("type", 1);
|
||||
values.put("guid", generatedGuid);
|
||||
values.put("position", 10);
|
||||
values.put("created", now);
|
||||
int updated = resolver.update(bookmarksUri,
|
||||
values,
|
||||
"url = ?",
|
||||
new String[] { DESKTOP_BOOKMARK_URL });
|
||||
if (updated == 0) {
|
||||
Uri uri = resolver.insert(bookmarksUri, values);
|
||||
mAsserter.ok(true, "Inserted at: ", uri.toString());
|
||||
} else {
|
||||
mAsserter.ok(false, "Failed to insert the Desktop bookmark", "Something went wrong");
|
||||
}
|
||||
|
||||
// Add a mobile bookmark
|
||||
mDatabaseHelper.addOrUpdateMobileBookmark(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE, BOOKMARK_URL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown() throws Exception {
|
||||
mDatabaseHelper.deleteBookmark(DESKTOP_BOOKMARK_URL);
|
||||
super.tearDown();
|
||||
}
|
||||
}
|
170
mobile/android/base/tests/testReaderMode.java.in
Normal file
170
mobile/android/base/tests/testReaderMode.java.in
Normal file
@ -0,0 +1,170 @@
|
||||
#filter substitution
|
||||
package @ANDROID_PACKAGE_NAME@.tests;
|
||||
|
||||
import @ANDROID_PACKAGE_NAME@.*;
|
||||
import com.jayway.android.robotium.solo.Solo;
|
||||
import android.widget.ListView;
|
||||
import android.view.View;
|
||||
import java.util.ArrayList;
|
||||
import android.view.ViewGroup;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* This patch tests the Reader Mode feature by adding and removing items in reading list
|
||||
* checks the reader toolbar functionality(share, add/remove to reading list, go to reading list)
|
||||
* accessing a page from reading list menu, checks that the reader icon is associated in History tab
|
||||
* and that the reading list is properly populated after adding or removing reader items
|
||||
*/
|
||||
public class testReaderMode extends AboutHomeTest {
|
||||
int height,width;
|
||||
|
||||
@Override
|
||||
protected int getTestType() {
|
||||
return TEST_MOCHITEST;
|
||||
}
|
||||
public void testReaderMode() {
|
||||
blockForGeckoReady();
|
||||
|
||||
Actions.EventExpecter contentEventExpecter;
|
||||
Actions.EventExpecter contentReaderAddedExpecter;
|
||||
Actions.EventExpecter faviconExpecter;
|
||||
ListView list;
|
||||
View child;
|
||||
String textUrl = getAbsoluteUrl(StringHelper.ROBOCOP_TEXT_PAGE_URL);
|
||||
String devType = mDevice.type;
|
||||
int childNo;
|
||||
|
||||
contentEventExpecter = mActions.expectGeckoEvent("DOMContentLoaded");
|
||||
loadAndPaint(textUrl);
|
||||
contentEventExpecter.blockForEvent();
|
||||
contentEventExpecter.unregisterListener();
|
||||
View readerIcon = getReaderIcon();
|
||||
|
||||
// Add the page to the Reading List using log click on the reader icon
|
||||
contentReaderAddedExpecter = mActions.expectGeckoEvent("Reader:Added");
|
||||
mSolo.clickLongOnView(readerIcon);
|
||||
String eventData = contentReaderAddedExpecter.blockForEventData();
|
||||
isAdded(eventData);
|
||||
contentReaderAddedExpecter.unregisterListener();
|
||||
|
||||
// Try to add the page to the Reading List using log click on the reader icon a second time
|
||||
contentReaderAddedExpecter = mActions.expectGeckoEvent("Reader:Added");
|
||||
mSolo.clickLongOnView(readerIcon);
|
||||
eventData = contentReaderAddedExpecter.blockForEventData();
|
||||
isAdded(eventData);
|
||||
contentReaderAddedExpecter.unregisterListener();
|
||||
|
||||
// Waiting for the favicon since is the last element loaded usually
|
||||
faviconExpecter = mActions.expectGeckoEvent("Reader:FaviconRequest");
|
||||
mSolo.clickOnView(getReaderIcon());
|
||||
|
||||
// Changing devices orientation to be sure that all devices are in portrait when will access the reader toolbar
|
||||
mSolo.setActivityOrientation(Solo.PORTRAIT);
|
||||
faviconExpecter.blockForEvent();
|
||||
faviconExpecter.unregisterListener();
|
||||
verifyPageTitle("Robocop Text Page");
|
||||
|
||||
// Open the share menu for the reader toolbar
|
||||
height = mDriver.getGeckoTop() + mDriver.getGeckoHeight() - 10;
|
||||
width = mDriver.getGeckoLeft() + mDriver.getGeckoWidth() - 10;
|
||||
mAsserter.dumpLog("Long Clicking at width = " + String.valueOf(width) + " and height = " + String.valueOf(height));
|
||||
mSolo.clickOnScreen(width,height);
|
||||
mAsserter.ok(mSolo.waitForText("Share via"), "Waiting for the share menu", "The share menu is present");
|
||||
mActions.sendSpecialKey(Actions.SpecialKey.BACK); // Close the share menu
|
||||
|
||||
// Remove page from the Reading List using reader toolbar
|
||||
height = mDriver.getGeckoTop() + mDriver.getGeckoHeight() - 10;
|
||||
width = mDriver.getGeckoLeft() + 50;
|
||||
mAsserter.dumpLog("Long Clicking at width = " + String.valueOf(width) + " and height = " + String.valueOf(height));
|
||||
mSolo.clickOnScreen(width,height);
|
||||
mAsserter.ok(mSolo.waitForText("Page removed from your Reading List"), "Waiting for the page to removed from your Reading List", "The page is removed from your Reading List");
|
||||
|
||||
//Add page to the Reading List using reader toolbar
|
||||
mSolo.clickOnScreen(width,height);
|
||||
mAsserter.ok(mSolo.waitForText("Page added to your Reading List"), "Waiting for the page to be added to your Reading List", "The page was added to your Reading List");
|
||||
|
||||
// Open the Reading List menu for the toolbar
|
||||
height = mDriver.getGeckoTop() + mDriver.getGeckoHeight() - 10;
|
||||
width = mDriver.getGeckoLeft() + mDriver.getGeckoWidth()/2 - 10;
|
||||
mAsserter.dumpLog("Long Clicking at width = " + String.valueOf(width) + " and height = " + String.valueOf(height));
|
||||
contentEventExpecter = mActions.expectGeckoEvent("DOMContentLoaded");
|
||||
mSolo.clickOnScreen(width,height);
|
||||
contentEventExpecter.blockForEvent();
|
||||
contentEventExpecter.unregisterListener();
|
||||
|
||||
// Check if the page is present in the Reading List
|
||||
mAsserter.ok(mSolo.waitForText("Robocop Text Page"), "Verify if the page is added to your Reading List", "The page is present in your Reading List");
|
||||
|
||||
// Check if the page is added in History tab like a Reading List item
|
||||
openAboutHomeTab(AboutHomeTabs.MOST_RECENT);
|
||||
list = findListViewWithTag("most_recent");
|
||||
child = list.getChildAt(1);
|
||||
mAsserter.ok(child != null, "item can be retrieved", child != null ? child.toString() : "null!");
|
||||
mSolo.clickLongOnView(child);
|
||||
mAsserter.ok(mSolo.waitForText("Open in Reader"), "Verify if the page is present in history as a Reading List item", "The page is present in history as a Reading List item");
|
||||
mActions.sendSpecialKey(Actions.SpecialKey.BACK); // Dismiss the context menu
|
||||
mSolo.waitForText("Robocop Text Page");
|
||||
|
||||
// Verify separately the Reading List entries for tablets and phone because for tablets there is an extra child in UI design
|
||||
if (devType.equals("phone")) {
|
||||
childNo = 1;
|
||||
}
|
||||
else {
|
||||
childNo = 2;
|
||||
}
|
||||
// Verify if the page is present to your Reading List
|
||||
openAboutHomeTab(AboutHomeTabs.READING_LIST);
|
||||
list = findListViewWithTag("reading_list");
|
||||
child = list.getChildAt(childNo-1);
|
||||
mAsserter.ok(child != null, "Verify if the page is present to your Reading List", "The page is present in your Reading List");
|
||||
contentEventExpecter = mActions.expectGeckoEvent("DOMContentLoaded");
|
||||
mSolo.clickOnView(child);
|
||||
contentEventExpecter.blockForEvent();
|
||||
contentEventExpecter.unregisterListener();
|
||||
verifyPageTitle("Robocop Text Page");
|
||||
|
||||
// Verify that we are in reader mode and remove the page from Reading List
|
||||
height = mDriver.getGeckoTop() + mDriver.getGeckoHeight() - 10;
|
||||
width = mDriver.getGeckoLeft() + 50;
|
||||
mAsserter.dumpLog("Long Clicking at width = " + String.valueOf(width) + " and height = " + String.valueOf(height));
|
||||
mSolo.clickOnScreen(width,height);
|
||||
mAsserter.ok(mSolo.waitForText("Page removed from your Reading List"), "Waiting for the page to removed from your Reading List", "The page is removed from your Reading List");
|
||||
verifyPageTitle("Robocop Text Page");
|
||||
|
||||
//Check if the Reading List is empty
|
||||
openAboutHomeTab(AboutHomeTabs.READING_LIST);
|
||||
list = findListViewWithTag("reading_list");
|
||||
child = list.getChildAt(childNo-1);
|
||||
mAsserter.ok(child == null, "Verify if the Reading List is empty", "The Reading List is empty");
|
||||
}
|
||||
|
||||
// Get the reader icon method
|
||||
protected View getReaderIcon() {
|
||||
View pageActionLayout = mSolo.getView(0x7f070025);
|
||||
ArrayList<String> pageActionLayoutChilds = new ArrayList();
|
||||
View actionLayoutItem = pageActionLayout;
|
||||
ViewGroup actionLayoutEntry = (ViewGroup)actionLayoutItem;
|
||||
View icon = actionLayoutEntry.getChildAt(1);
|
||||
return icon;
|
||||
}
|
||||
|
||||
// This method check to see if a reader item is added to the reader list
|
||||
private boolean isAdded(String eventData) {
|
||||
try {
|
||||
JSONObject data = new JSONObject(eventData);
|
||||
if (data.getInt("result") == 0) {
|
||||
mAsserter.ok(true, "Waiting for the page to be added to your Reading List", "The page was added to your Reading List");
|
||||
}
|
||||
else {
|
||||
if (data.getInt("result") == 2) {
|
||||
mAsserter.ok(true, "Trying to add a second time the page in your Reading List", "The page is already in your Reading List");
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
mAsserter.ok(false, "Error parsing the event data", e.toString());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
modules := \
|
||||
log4moz.js \
|
||||
storageservice.js \
|
||||
stringbundle.js \
|
||||
tokenserverclient.js \
|
||||
|
@ -24,7 +24,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/rest.js");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
|
||||
@ -47,8 +47,8 @@ Object.freeze(BagheeraClientRequestResult.prototype);
|
||||
function BagheeraRequest(uri) {
|
||||
RESTRequest.call(this, uri);
|
||||
|
||||
this._log = Log4Moz.repository.getLogger("Services.BagheeraClient");
|
||||
this._log.level = Log4Moz.Level.Debug;
|
||||
this._log = Log.repository.getLogger("Services.BagheeraClient");
|
||||
this._log.level = Log.Level.Debug;
|
||||
}
|
||||
|
||||
BagheeraRequest.prototype = Object.freeze({
|
||||
@ -69,8 +69,8 @@ this.BagheeraClient = function BagheeraClient(baseURI) {
|
||||
throw new Error("baseURI argument must be defined.");
|
||||
}
|
||||
|
||||
this._log = Log4Moz.repository.getLogger("Services.BagheeraClient");
|
||||
this._log.level = Log4Moz.Level.Debug;
|
||||
this._log = Log.repository.getLogger("Services.BagheeraClient");
|
||||
this._log.level = Log.Level.Debug;
|
||||
|
||||
this.baseURI = baseURI;
|
||||
|
||||
|
@ -8,7 +8,7 @@ const {utils: Cu} = Components;
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["BagheeraServer"];
|
||||
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
|
||||
@ -23,7 +23,7 @@ Cu.import("resource://testing-common/httpd.js");
|
||||
* The Bagheera server is essentially a glorified document store.
|
||||
*/
|
||||
this.BagheeraServer = function BagheeraServer() {
|
||||
this._log = Log4Moz.repository.getLogger("metrics.BagheeraServer");
|
||||
this._log = Log.repository.getLogger("metrics.BagheeraServer");
|
||||
|
||||
this.server = new HttpServer();
|
||||
this.namespaces = {};
|
||||
|
@ -11,7 +11,7 @@ this.EXPORTED_SYMBOLS = [
|
||||
|
||||
const {utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
|
||||
this.initTestLogging = function initTestLogging(level) {
|
||||
function LogStats() {
|
||||
@ -19,7 +19,7 @@ this.initTestLogging = function initTestLogging(level) {
|
||||
}
|
||||
LogStats.prototype = {
|
||||
format: function format(message) {
|
||||
if (message.level == Log4Moz.Level.Error) {
|
||||
if (message.level == Log.Level.Error) {
|
||||
this.errorsLogged += 1;
|
||||
}
|
||||
|
||||
@ -27,20 +27,20 @@ this.initTestLogging = function initTestLogging(level) {
|
||||
message.message + "\n";
|
||||
}
|
||||
};
|
||||
LogStats.prototype.__proto__ = new Log4Moz.Formatter();
|
||||
LogStats.prototype.__proto__ = new Log.Formatter();
|
||||
|
||||
let log = Log4Moz.repository.rootLogger;
|
||||
let log = Log.repository.rootLogger;
|
||||
let logStats = new LogStats();
|
||||
let appender = new Log4Moz.DumpAppender(logStats);
|
||||
let appender = new Log.DumpAppender(logStats);
|
||||
|
||||
if (typeof(level) == "undefined") {
|
||||
level = "Debug";
|
||||
}
|
||||
getTestLogger().level = Log4Moz.Level[level];
|
||||
Log4Moz.repository.getLogger("Services").level = Log4Moz.Level[level];
|
||||
getTestLogger().level = Log.Level[level];
|
||||
Log.repository.getLogger("Services").level = Log.Level[level];
|
||||
|
||||
log.level = Log4Moz.Level.Trace;
|
||||
appender.level = Log4Moz.Level.Trace;
|
||||
log.level = Log.Level.Trace;
|
||||
appender.level = Log.Level.Trace;
|
||||
// Overwrite any other appenders (e.g. from previous incarnations)
|
||||
log.ownAppenders = [appender];
|
||||
log.updateAppenders();
|
||||
@ -49,6 +49,6 @@ this.initTestLogging = function initTestLogging(level) {
|
||||
}
|
||||
|
||||
this.getTestLogger = function getTestLogger(component) {
|
||||
return Log4Moz.repository.getLogger("Testing");
|
||||
return Log.repository.getLogger("Testing");
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ this.EXPORTED_SYMBOLS = [
|
||||
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://services-common/async.js");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
|
||||
const STORAGE_HTTP_LOGGER = "Services.Common.Test.Server";
|
||||
@ -74,7 +74,7 @@ this.ServerBSO = function ServerBSO(id, payload, modified) {
|
||||
throw new Error("BSO ID is invalid: " + id);
|
||||
}
|
||||
|
||||
this._log = Log4Moz.repository.getLogger(STORAGE_HTTP_LOGGER);
|
||||
this._log = Log.repository.getLogger(STORAGE_HTTP_LOGGER);
|
||||
|
||||
this.id = id;
|
||||
if (!payload) {
|
||||
@ -287,7 +287,7 @@ this.StorageServerCollection =
|
||||
CommonUtils.ensureMillisecondsTimestamp(timestamp);
|
||||
this._timestamp = timestamp;
|
||||
|
||||
this._log = Log4Moz.repository.getLogger(STORAGE_HTTP_LOGGER);
|
||||
this._log = Log.repository.getLogger(STORAGE_HTTP_LOGGER);
|
||||
}
|
||||
StorageServerCollection.prototype = {
|
||||
BATCH_MAX_COUNT: 100, // # of records.
|
||||
@ -872,7 +872,7 @@ this.StorageServer = function StorageServer(callback) {
|
||||
this.started = false;
|
||||
this.users = {};
|
||||
this.requestCount = 0;
|
||||
this._log = Log4Moz.repository.getLogger(STORAGE_HTTP_LOGGER);
|
||||
this._log = Log.repository.getLogger(STORAGE_HTTP_LOGGER);
|
||||
|
||||
// Install our own default handler. This allows us to mess around with the
|
||||
// whole URL space.
|
||||
|
@ -17,7 +17,7 @@ this.EXPORTED_SYMBOLS = [
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "CryptoUtils",
|
||||
@ -91,9 +91,9 @@ this.RESTRequest = function RESTRequest(uri) {
|
||||
this.uri = uri;
|
||||
|
||||
this._headers = {};
|
||||
this._log = Log4Moz.repository.getLogger(this._logName);
|
||||
this._log = Log.repository.getLogger(this._logName);
|
||||
this._log.level =
|
||||
Log4Moz.Level[Prefs.get("log.logger.rest.request")];
|
||||
Log.Level[Prefs.get("log.logger.rest.request")];
|
||||
}
|
||||
RESTRequest.prototype = {
|
||||
|
||||
@ -309,7 +309,7 @@ RESTRequest.prototype = {
|
||||
}
|
||||
|
||||
this._log.debug(method + " Length: " + data.length);
|
||||
if (this._log.level <= Log4Moz.Level.Trace) {
|
||||
if (this._log.level <= Log.Level.Trace) {
|
||||
this._log.trace(method + " Body: " + data);
|
||||
}
|
||||
|
||||
@ -444,7 +444,7 @@ RESTRequest.prototype = {
|
||||
this._log.debug(this.method + " " + uri + " " + this.response.status);
|
||||
|
||||
// Additionally give the full response body when Trace logging.
|
||||
if (this._log.level <= Log4Moz.Level.Trace) {
|
||||
if (this._log.level <= Log.Level.Trace) {
|
||||
this._log.trace(this.method + " body: " + this.response.body);
|
||||
}
|
||||
|
||||
@ -593,9 +593,9 @@ RESTRequest.prototype = {
|
||||
* the RESTRequest.
|
||||
*/
|
||||
this.RESTResponse = function RESTResponse() {
|
||||
this._log = Log4Moz.repository.getLogger(this._logName);
|
||||
this._log = Log.repository.getLogger(this._logName);
|
||||
this._log.level =
|
||||
Log4Moz.Level[Prefs.get("log.logger.rest.response")];
|
||||
Log.Level[Prefs.get("log.logger.rest.response")];
|
||||
}
|
||||
RESTResponse.prototype = {
|
||||
|
||||
|
@ -35,7 +35,7 @@ const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://services-common/async.js");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/rest.js");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
|
||||
@ -470,8 +470,8 @@ this.StorageServiceRequestError = function StorageServiceRequestError() {
|
||||
* to implement it transparently.
|
||||
*/
|
||||
function StorageServiceRequest() {
|
||||
this._log = Log4Moz.repository.getLogger("Sync.StorageService.Request");
|
||||
this._log.level = Log4Moz.Level[Prefs.get("log.level")];
|
||||
this._log = Log.repository.getLogger("Sync.StorageService.Request");
|
||||
this._log.level = Log.Level[Prefs.get("log.level")];
|
||||
|
||||
this.notModified = false;
|
||||
|
||||
@ -1521,8 +1521,8 @@ Object.freeze(StorageCollectionBatchedDelete.prototype);
|
||||
* (string) Base URI for all requests.
|
||||
*/
|
||||
this.StorageServiceClient = function StorageServiceClient(baseURI) {
|
||||
this._log = Log4Moz.repository.getLogger("Services.Common.StorageServiceClient");
|
||||
this._log.level = Log4Moz.Level[Prefs.get("log.level")];
|
||||
this._log = Log.repository.getLogger("Services.Common.StorageServiceClient");
|
||||
this._log.level = Log.Level[Prefs.get("log.level")];
|
||||
|
||||
this._baseURI = baseURI;
|
||||
|
||||
|
@ -2,13 +2,13 @@
|
||||
* 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/. */
|
||||
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://testing-common/services-common/logging.js");
|
||||
|
||||
let btoa = Cu.import("resource://services-common/log4moz.js").btoa;
|
||||
let atob = Cu.import("resource://services-common/log4moz.js").atob;
|
||||
let btoa = Cu.import("resource://gre/modules/Log.jsm").btoa;
|
||||
let atob = Cu.import("resource://gre/modules/Log.jsm").atob;
|
||||
|
||||
function do_check_empty(obj) {
|
||||
do_check_attribute_count(obj, 0);
|
||||
|
@ -4,7 +4,6 @@
|
||||
const modules = [
|
||||
"async.js",
|
||||
"bagheeraclient.js",
|
||||
"log4moz.js",
|
||||
"rest.js",
|
||||
"storageservice.js",
|
||||
"stringbundle.js",
|
||||
|
@ -2,15 +2,15 @@
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/rest.js");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
|
||||
//DEBUG = true;
|
||||
|
||||
function run_test() {
|
||||
Log4Moz.repository.getLogger("Services.Common.RESTRequest").level =
|
||||
Log4Moz.Level.Trace;
|
||||
Log.repository.getLogger("Services.Common.RESTRequest").level =
|
||||
Log.Level.Trace;
|
||||
initTestLogging("Trace");
|
||||
|
||||
run_next_test();
|
||||
|
@ -105,8 +105,8 @@ function doDeleteRequest(request) {
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
Log4Moz.repository.getLogger("Services.Common.Test.StorageServer").level =
|
||||
Log4Moz.Level.Trace;
|
||||
Log.repository.getLogger("Services.Common.Test.StorageServer").level =
|
||||
Log.Level.Trace;
|
||||
initTestLogging();
|
||||
|
||||
run_next_test();
|
||||
|
@ -25,7 +25,6 @@ firefox-appdir = browser
|
||||
[test_async_querySpinningly.js]
|
||||
[test_bagheera_server.js]
|
||||
[test_bagheera_client.js]
|
||||
[test_log4moz.js]
|
||||
[test_observers.js]
|
||||
[test_restrequest.js]
|
||||
[test_tokenauthenticatedrequest.js]
|
||||
|
@ -14,7 +14,7 @@ this.EXPORTED_SYMBOLS = [
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/rest.js");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
|
||||
@ -114,8 +114,8 @@ TokenServerClientServerError.prototype.constructor =
|
||||
* at fault (e.g. differentiating a 503 from a 401).
|
||||
*/
|
||||
this.TokenServerClient = function TokenServerClient() {
|
||||
this._log = Log4Moz.repository.getLogger("Common.TokenServerClient");
|
||||
this._log.level = Log4Moz.Level[Prefs.get("logger.level")];
|
||||
this._log = Log.repository.getLogger("Common.TokenServerClient");
|
||||
this._log.level = Log.Level[Prefs.get("logger.level")];
|
||||
}
|
||||
TokenServerClient.prototype = {
|
||||
/**
|
||||
|
@ -10,7 +10,7 @@ Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm")
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
|
||||
this.CommonUtils = {
|
||||
exceptionStr: function exceptionStr(e) {
|
||||
@ -88,7 +88,7 @@ this.CommonUtils = {
|
||||
try {
|
||||
return Services.io.newURI(URIString, null, null);
|
||||
} catch (e) {
|
||||
let log = Log4Moz.repository.getLogger("Common.Utils");
|
||||
let log = Log.repository.getLogger("Common.Utils");
|
||||
log.debug("Could not create URI: " + CommonUtils.exceptionStr(e));
|
||||
return null;
|
||||
}
|
||||
@ -464,7 +464,7 @@ this.CommonUtils = {
|
||||
* @param def
|
||||
* (Number) The default value to use if the preference is not defined.
|
||||
* @param log
|
||||
* (Log4Moz.Logger) Logger to write warnings to.
|
||||
* (Log.Logger) Logger to write warnings to.
|
||||
*/
|
||||
getEpochPref: function getEpochPref(branch, pref, def=0, log=null) {
|
||||
if (!Number.isInteger(def)) {
|
||||
@ -507,7 +507,7 @@ this.CommonUtils = {
|
||||
* (Number) The default value (in milliseconds) if the preference is
|
||||
* not defined or invalid.
|
||||
* @param log
|
||||
* (Log4Moz.Logger) Logger to write warnings to.
|
||||
* (Log.Logger) Logger to write warnings to.
|
||||
* @param oldestYear
|
||||
* (Number) Oldest year to accept in read values.
|
||||
*/
|
||||
|
@ -223,7 +223,7 @@ DataReportingService.prototype = Object.freeze({
|
||||
|
||||
Cu.import("resource://gre/modules/Task.jsm", ns);
|
||||
Cu.import("resource://gre/modules/HealthReport.jsm", ns);
|
||||
Cu.import("resource://services-common/log4moz.js", ns);
|
||||
Cu.import("resource://gre/modules/Log.jsm", ns);
|
||||
|
||||
// How many times will we rewrite this code before rolling it up into a
|
||||
// generic module? See also bug 451283.
|
||||
@ -238,22 +238,22 @@ DataReportingService.prototype = Object.freeze({
|
||||
let loggingPrefs = new Preferences(HEALTHREPORT_LOGGING_BRANCH);
|
||||
if (loggingPrefs.get("consoleEnabled", true)) {
|
||||
let level = loggingPrefs.get("consoleLevel", "Warn");
|
||||
let appender = new ns.Log4Moz.ConsoleAppender();
|
||||
appender.level = ns.Log4Moz.Level[level] || ns.Log4Moz.Level.Warn;
|
||||
let appender = new ns.Log.ConsoleAppender();
|
||||
appender.level = ns.Log.Level[level] || ns.Log.Level.Warn;
|
||||
|
||||
for (let name of LOGGERS) {
|
||||
let logger = ns.Log4Moz.repository.getLogger(name);
|
||||
let logger = ns.Log.repository.getLogger(name);
|
||||
logger.addAppender(appender);
|
||||
}
|
||||
}
|
||||
|
||||
if (loggingPrefs.get("dumpEnabled", false)) {
|
||||
let level = loggingPrefs.get("dumpLevel", "Debug");
|
||||
let appender = new ns.Log4Moz.DumpAppender();
|
||||
appender.level = ns.Log4Moz.Level[level] || ns.Log4Moz.Level.Debug;
|
||||
let appender = new ns.Log.DumpAppender();
|
||||
appender.level = ns.Log.Level[level] || ns.Log.Level.Debug;
|
||||
|
||||
for (let name of LOGGERS) {
|
||||
let logger = ns.Log4Moz.repository.getLogger(name);
|
||||
let logger = ns.Log.repository.getLogger(name);
|
||||
logger.addAppender(appender);
|
||||
}
|
||||
}
|
||||
|
@ -8,12 +8,12 @@ this.EXPORTED_SYMBOLS = ["MockPolicyListener"];
|
||||
|
||||
const {utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
|
||||
|
||||
this.MockPolicyListener = function MockPolicyListener() {
|
||||
this._log = Log4Moz.repository.getLogger("Services.DataReporting.Testing.MockPolicyListener");
|
||||
this._log.level = Log4Moz.Level["Debug"];
|
||||
this._log = Log.repository.getLogger("Services.DataReporting.Testing.MockPolicyListener");
|
||||
this._log.level = Log.Level["Debug"];
|
||||
|
||||
this.requestDataUploadCount = 0;
|
||||
this.lastDataRequest = null;
|
||||
|
@ -27,7 +27,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
#endif
|
||||
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
|
||||
const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
|
||||
@ -263,8 +263,8 @@ this.DataSubmissionRequest.prototype = Object.freeze({
|
||||
* events.
|
||||
*/
|
||||
this.DataReportingPolicy = function (prefs, healthReportPrefs, listener) {
|
||||
this._log = Log4Moz.repository.getLogger("Services.DataReporting.Policy");
|
||||
this._log.level = Log4Moz.Level["Debug"];
|
||||
this._log = Log.repository.getLogger("Services.DataReporting.Policy");
|
||||
this._log.level = Log.Level["Debug"];
|
||||
|
||||
for (let handler of this.REQUIRED_LISTENERS) {
|
||||
if (!listener[handler]) {
|
||||
|
@ -16,7 +16,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
|
||||
|
||||
@ -69,7 +69,7 @@ this.SessionRecorder = function (branch) {
|
||||
throw new Error("branch argument must end with '.': " + branch);
|
||||
}
|
||||
|
||||
this._log = Log4Moz.repository.getLogger("Services.DataReporting.SessionRecorder");
|
||||
this._log = Log.repository.getLogger("Services.DataReporting.SessionRecorder");
|
||||
|
||||
this._prefs = new Preferences(branch);
|
||||
this._lastActivityWasInactive = false;
|
||||
|
@ -18,7 +18,7 @@ Cu.import("resource://services-common/async.js");
|
||||
Cu.import("resource://services-common/bagheeraclient.js");
|
||||
#endif
|
||||
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
@ -260,7 +260,7 @@ function AbstractHealthReporter(branch, policy, sessionRecorder) {
|
||||
throw new Error("Must provide policy to HealthReporter constructor.");
|
||||
}
|
||||
|
||||
this._log = Log4Moz.repository.getLogger("Services.HealthReport.HealthReporter");
|
||||
this._log = Log.repository.getLogger("Services.HealthReport.HealthReporter");
|
||||
this._log.info("Initializing health reporter instance against " + branch);
|
||||
|
||||
this._branch = branch;
|
||||
|
@ -25,7 +25,7 @@ const REQUIRED_UINT32_TYPE = {type: "TYPE_UINT32"};
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm")
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
|
||||
// Profile creation time access.
|
||||
|
@ -20,7 +20,7 @@ const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
|
||||
|
||||
@ -86,7 +86,7 @@ this.Measurement = function () {
|
||||
}
|
||||
}
|
||||
|
||||
this._log = Log4Moz.repository.getLogger("Services.Metrics.Measurement." + this.name);
|
||||
this._log = Log.repository.getLogger("Services.Metrics.Measurement." + this.name);
|
||||
|
||||
this.id = null;
|
||||
this.storage = null;
|
||||
@ -502,7 +502,7 @@ this.Provider = function () {
|
||||
throw new Error("Provider must define measurement types.");
|
||||
}
|
||||
|
||||
this._log = Log4Moz.repository.getLogger("Services.Metrics.Provider." + this.name);
|
||||
this._log = Log.repository.getLogger("Services.Metrics.Provider." + this.name);
|
||||
|
||||
this.measurements = null;
|
||||
this.storage = null;
|
||||
|
@ -14,7 +14,7 @@ Cu.import("resource://gre/modules/services/metrics/dataprovider.jsm");
|
||||
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ Cu.import("resource://services-common/utils.js");
|
||||
* provides APIs for bulk collection of data.
|
||||
*/
|
||||
this.ProviderManager = function (storage) {
|
||||
this._log = Log4Moz.repository.getLogger("Services.Metrics.ProviderManager");
|
||||
this._log = Log.repository.getLogger("Services.Metrics.ProviderManager");
|
||||
|
||||
this._providers = new Map();
|
||||
this._storage = storage;
|
||||
|
@ -22,7 +22,7 @@ const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/Sqlite.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
|
||||
|
||||
@ -698,7 +698,7 @@ this.MetricsStorageBackend = function (path) {
|
||||
* FUTURE enforce 1 read/write connection per database limit.
|
||||
*/
|
||||
function MetricsStorageSqliteBackend(connection) {
|
||||
this._log = Log4Moz.repository.getLogger("Services.Metrics.MetricsStorage");
|
||||
this._log = Log.repository.getLogger("Services.Metrics.MetricsStorage");
|
||||
|
||||
this._connection = connection;
|
||||
this._enabledWALCheckpointPages = null;
|
||||
|
@ -16,7 +16,7 @@ const {utils: Cu} = Components;
|
||||
Cu.import("resource://services-sync/record.js");
|
||||
Cu.import("resource://services-sync/util.js");
|
||||
|
||||
let btoa = Cu.import("resource://services-common/log4moz.js").btoa;
|
||||
let btoa = Cu.import("resource://gre/modules/Log.jsm").btoa;
|
||||
|
||||
this.FakeFilesystemService = function FakeFilesystemService(contents) {
|
||||
this.fakeContents = contents;
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-sync/util.js");
|
||||
Cu.import("resource://gre/modules/AddonManager.jsm");
|
||||
|
||||
@ -113,9 +113,9 @@ this.EXPORTED_SYMBOLS = ["AddonsReconciler", "CHANGE_INSTALLED",
|
||||
* heed them like they were normal. In the end, the state is proper.
|
||||
*/
|
||||
this.AddonsReconciler = function AddonsReconciler() {
|
||||
this._log = Log4Moz.repository.getLogger("Sync.AddonsReconciler");
|
||||
this._log = Log.repository.getLogger("Sync.AddonsReconciler");
|
||||
let level = Svc.Prefs.get("log.logger.addonsreconciler", "Debug");
|
||||
this._log.level = Log4Moz.Level[level];
|
||||
this._log.level = Log.Level[level];
|
||||
|
||||
Svc.Obs.add("xpcom-shutdown", this.stopListening, this);
|
||||
};
|
||||
@ -140,7 +140,7 @@ AddonsReconciler.prototype = {
|
||||
*/
|
||||
_shouldPersist: true,
|
||||
|
||||
/** log4moz logger instance */
|
||||
/** Log logger instance */
|
||||
_log: null,
|
||||
|
||||
/**
|
||||
|
@ -9,7 +9,7 @@ this.EXPORTED_SYMBOLS = ["AddonUtils"];
|
||||
const {interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-sync/util.js");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
|
||||
@ -18,8 +18,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository",
|
||||
"resource://gre/modules/AddonRepository.jsm");
|
||||
|
||||
function AddonUtilsInternal() {
|
||||
this._log = Log4Moz.repository.getLogger("Sync.AddonUtils");
|
||||
this._log.Level = Log4Moz.Level[Svc.Prefs.get("log.logger.addonutils")];
|
||||
this._log = Log.repository.getLogger("Sync.AddonUtils");
|
||||
this._log.Level = Log.Level[Svc.Prefs.get("log.logger.addonutils")];
|
||||
}
|
||||
AddonUtilsInternal.prototype = {
|
||||
/**
|
||||
|
@ -13,7 +13,7 @@ this.EXPORTED_SYMBOLS = [
|
||||
const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://services-common/async.js");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/observers.js");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
Cu.import("resource://services-sync/constants.js");
|
||||
@ -42,9 +42,9 @@ this.Tracker = function Tracker(name, engine) {
|
||||
this.name = this.file = name.toLowerCase();
|
||||
this.engine = engine;
|
||||
|
||||
this._log = Log4Moz.repository.getLogger("Sync.Tracker." + name);
|
||||
this._log = Log.repository.getLogger("Sync.Tracker." + name);
|
||||
let level = Svc.Prefs.get("log.logger.engine." + this.name, "Debug");
|
||||
this._log.level = Log4Moz.Level[level];
|
||||
this._log.level = Log.Level[level];
|
||||
|
||||
this._score = 0;
|
||||
this._ignored = [];
|
||||
@ -197,9 +197,9 @@ this.Store = function Store(name, engine) {
|
||||
this.name = name.toLowerCase();
|
||||
this.engine = engine;
|
||||
|
||||
this._log = Log4Moz.repository.getLogger("Sync.Store." + name);
|
||||
this._log = Log.repository.getLogger("Sync.Store." + name);
|
||||
let level = Svc.Prefs.get("log.logger.engine." + this.name, "Debug");
|
||||
this._log.level = Log4Moz.Level[level];
|
||||
this._log.level = Log.Level[level];
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "_timer", function() {
|
||||
return Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
@ -383,8 +383,8 @@ this.EngineManager = function EngineManager(service) {
|
||||
this.service = service;
|
||||
|
||||
this._engines = {};
|
||||
this._log = Log4Moz.repository.getLogger("Sync.EngineManager");
|
||||
this._log.level = Log4Moz.Level[Svc.Prefs.get(
|
||||
this._log = Log.repository.getLogger("Sync.EngineManager");
|
||||
this._log.level = Log.Level[Svc.Prefs.get(
|
||||
"log.logger.service.engines", "Debug")];
|
||||
}
|
||||
EngineManager.prototype = {
|
||||
@ -476,9 +476,9 @@ this.Engine = function Engine(name, service) {
|
||||
this.service = service;
|
||||
|
||||
this._notify = Utils.notify("weave:engine:");
|
||||
this._log = Log4Moz.repository.getLogger("Sync.Engine." + this.Name);
|
||||
this._log = Log.repository.getLogger("Sync.Engine." + this.Name);
|
||||
let level = Svc.Prefs.get("log.logger.engine." + this.name, "Debug");
|
||||
this._log.level = Log4Moz.Level[level];
|
||||
this._log.level = Log.Level[level];
|
||||
|
||||
this._tracker; // initialize tracker to load previously changed IDs
|
||||
this._log.debug("Engine initialized");
|
||||
@ -1056,7 +1056,7 @@ SyncEngine.prototype = {
|
||||
* Truthy if incoming record should be applied. False if not.
|
||||
*/
|
||||
_reconcile: function _reconcile(item) {
|
||||
if (this._log.level <= Log4Moz.Level.Trace) {
|
||||
if (this._log.level <= Log.Level.Trace) {
|
||||
this._log.trace("Incoming: " + item);
|
||||
}
|
||||
|
||||
@ -1273,7 +1273,7 @@ SyncEngine.prototype = {
|
||||
for each (let id in modifiedIDs) {
|
||||
try {
|
||||
let out = this._createRecord(id);
|
||||
if (this._log.level <= Log4Moz.Level.Trace)
|
||||
if (this._log.level <= Log.Level.Trace)
|
||||
this._log.trace("Outgoing: " + out);
|
||||
|
||||
out.encrypt(this.service.collectionKeys.keyForCollection(this.name));
|
||||
|
@ -14,7 +14,7 @@ Cu.import("resource://services-sync/record.js");
|
||||
Cu.import("resource://services-common/async.js");
|
||||
Cu.import("resource://services-sync/util.js");
|
||||
Cu.import("resource://services-sync/constants.js");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
|
||||
const FORMS_TTL = 5184000; // 60 days
|
||||
|
||||
@ -31,7 +31,7 @@ Utils.deferGetSet(FormRec, "cleartext", ["name", "value"]);
|
||||
|
||||
|
||||
let FormWrapper = {
|
||||
_log: Log4Moz.repository.getLogger("Sync.Engine.Forms"),
|
||||
_log: Log.repository.getLogger("Sync.Engine.Forms"),
|
||||
|
||||
_getEntryCols: ["fieldname", "value"],
|
||||
_guidCols: ["guid"],
|
||||
|
@ -13,7 +13,7 @@ const HISTORY_TTL = 5184000; // 60 days
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://services-common/async.js");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-sync/constants.js");
|
||||
Cu.import("resource://services-sync/engines.js");
|
||||
Cu.import("resource://services-sync/record.js");
|
||||
|
@ -10,7 +10,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://services-sync/constants.js");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-sync/util.js");
|
||||
|
||||
// Lazy import to prevent unnecessary load on startup.
|
||||
@ -57,8 +57,8 @@ for (let symbol of ["BulkKeyBundle", "SyncKeyBundle"]) {
|
||||
* and any other function that involves the built-in functionality.
|
||||
*/
|
||||
this.IdentityManager = function IdentityManager() {
|
||||
this._log = Log4Moz.repository.getLogger("Sync.Identity");
|
||||
this._log.Level = Log4Moz.Level[Svc.Prefs.get("log.logger.identity")];
|
||||
this._log = Log.repository.getLogger("Sync.Identity");
|
||||
this._log.Level = Log.Level[Svc.Prefs.get("log.logger.identity")];
|
||||
|
||||
this._basicPassword = null;
|
||||
this._basicPasswordAllowLookup = true;
|
||||
|
@ -6,7 +6,7 @@ this.EXPORTED_SYMBOLS = ["JPAKEClient", "SendCredentialsController"];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/rest.js");
|
||||
Cu.import("resource://services-sync/constants.js");
|
||||
Cu.import("resource://services-sync/util.js");
|
||||
@ -114,8 +114,8 @@ const JPAKE_VERIFY_VALUE = "0123456789ABCDEF";
|
||||
this.JPAKEClient = function JPAKEClient(controller) {
|
||||
this.controller = controller;
|
||||
|
||||
this._log = Log4Moz.repository.getLogger("Sync.JPAKEClient");
|
||||
this._log.level = Log4Moz.Level[Svc.Prefs.get(
|
||||
this._log = Log.repository.getLogger("Sync.JPAKEClient");
|
||||
this._log.level = Log.Level[Svc.Prefs.get(
|
||||
"log.logger.service.jpakeclient", "Debug")];
|
||||
|
||||
this._serverURL = Svc.Prefs.get("jpake.serverURL");
|
||||
@ -700,8 +700,8 @@ JPAKEClient.prototype = {
|
||||
*/
|
||||
this.SendCredentialsController =
|
||||
function SendCredentialsController(jpakeclient, service) {
|
||||
this._log = Log4Moz.repository.getLogger("Sync.SendCredentialsController");
|
||||
this._log.level = Log4Moz.Level[Svc.Prefs.get("log.logger.service.main")];
|
||||
this._log = Log.repository.getLogger("Sync.SendCredentialsController");
|
||||
this._log.level = Log.Level[Svc.Prefs.get("log.logger.service.main")];
|
||||
|
||||
this._log.trace("Loading.");
|
||||
this.jpakeclient = jpakeclient;
|
||||
|
@ -12,7 +12,7 @@ this.EXPORTED_SYMBOLS = [
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://services-sync/constants.js");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-sync/util.js");
|
||||
|
||||
/**
|
||||
@ -120,7 +120,7 @@ KeyBundle.prototype = {
|
||||
* This is just a KeyBundle with a collection attached.
|
||||
*/
|
||||
this.BulkKeyBundle = function BulkKeyBundle(collection) {
|
||||
let log = Log4Moz.repository.getLogger("Sync.BulkKeyBundle");
|
||||
let log = Log.repository.getLogger("Sync.BulkKeyBundle");
|
||||
log.info("BulkKeyBundle being created for " + collection);
|
||||
KeyBundle.call(this);
|
||||
|
||||
@ -177,7 +177,7 @@ BulkKeyBundle.prototype = {
|
||||
* If the username or Sync Key is invalid, an Error will be thrown.
|
||||
*/
|
||||
this.SyncKeyBundle = function SyncKeyBundle(username, syncKey) {
|
||||
let log = Log4Moz.repository.getLogger("Sync.SyncKeyBundle");
|
||||
let log = Log.repository.getLogger("Sync.SyncKeyBundle");
|
||||
log.info("SyncKeyBundle being created.");
|
||||
KeyBundle.call(this);
|
||||
|
||||
|
@ -10,7 +10,7 @@ const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://services-common/observers.js");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-sync/util.js");
|
||||
|
||||
this.Notifications = {
|
||||
@ -115,7 +115,7 @@ this.NotificationButton =
|
||||
try {
|
||||
callback.apply(this, arguments);
|
||||
} catch (e) {
|
||||
let logger = Log4Moz.repository.getLogger("Sync.Notifications");
|
||||
let logger = Log.repository.getLogger("Sync.Notifications");
|
||||
logger.error("An exception occurred: " + Utils.exceptionStr(e));
|
||||
logger.info(Utils.stackTrace(e));
|
||||
throw e;
|
||||
|
@ -9,7 +9,7 @@ this.EXPORTED_SYMBOLS = [
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-sync/constants.js");
|
||||
Cu.import("resource://services-sync/engines.js");
|
||||
Cu.import("resource://services-sync/status.js");
|
||||
@ -20,7 +20,7 @@ this.SyncScheduler = function SyncScheduler(service) {
|
||||
this.init();
|
||||
}
|
||||
SyncScheduler.prototype = {
|
||||
_log: Log4Moz.repository.getLogger("Sync.SyncScheduler"),
|
||||
_log: Log.repository.getLogger("Sync.SyncScheduler"),
|
||||
|
||||
_fatalLoginStatus: [LOGIN_FAILED_NO_USERNAME,
|
||||
LOGIN_FAILED_NO_PASSWORD,
|
||||
@ -67,7 +67,7 @@ SyncScheduler.prototype = {
|
||||
set numClients(value) Svc.Prefs.set("numClients", value),
|
||||
|
||||
init: function init() {
|
||||
this._log.level = Log4Moz.Level[Svc.Prefs.get("log.logger.service.main")];
|
||||
this._log.level = Log.Level[Svc.Prefs.get("log.logger.service.main")];
|
||||
this.setDefaults();
|
||||
Svc.Obs.add("weave:engine:score:updated", this);
|
||||
Svc.Obs.add("network:offline-status-changed", this);
|
||||
@ -500,24 +500,24 @@ ErrorHandler.prototype = {
|
||||
},
|
||||
|
||||
initLogs: function initLogs() {
|
||||
this._log = Log4Moz.repository.getLogger("Sync.ErrorHandler");
|
||||
this._log.level = Log4Moz.Level[Svc.Prefs.get("log.logger.service.main")];
|
||||
this._log = Log.repository.getLogger("Sync.ErrorHandler");
|
||||
this._log.level = Log.Level[Svc.Prefs.get("log.logger.service.main")];
|
||||
this._cleaningUpFileLogs = false;
|
||||
|
||||
let root = Log4Moz.repository.getLogger("Sync");
|
||||
root.level = Log4Moz.Level[Svc.Prefs.get("log.rootLogger")];
|
||||
let root = Log.repository.getLogger("Sync");
|
||||
root.level = Log.Level[Svc.Prefs.get("log.rootLogger")];
|
||||
|
||||
let formatter = new Log4Moz.BasicFormatter();
|
||||
let capp = new Log4Moz.ConsoleAppender(formatter);
|
||||
capp.level = Log4Moz.Level[Svc.Prefs.get("log.appender.console")];
|
||||
let formatter = new Log.BasicFormatter();
|
||||
let capp = new Log.ConsoleAppender(formatter);
|
||||
capp.level = Log.Level[Svc.Prefs.get("log.appender.console")];
|
||||
root.addAppender(capp);
|
||||
|
||||
let dapp = new Log4Moz.DumpAppender(formatter);
|
||||
dapp.level = Log4Moz.Level[Svc.Prefs.get("log.appender.dump")];
|
||||
let dapp = new Log.DumpAppender(formatter);
|
||||
dapp.level = Log.Level[Svc.Prefs.get("log.appender.dump")];
|
||||
root.addAppender(dapp);
|
||||
|
||||
let fapp = this._logAppender = new Log4Moz.StorageStreamAppender(formatter);
|
||||
fapp.level = Log4Moz.Level[Svc.Prefs.get("log.appender.file.level")];
|
||||
let fapp = this._logAppender = new Log.StorageStreamAppender(formatter);
|
||||
fapp.level = Log.Level[Svc.Prefs.get("log.appender.file.level")];
|
||||
root.addAppender(fapp);
|
||||
},
|
||||
|
||||
|
@ -18,7 +18,7 @@ const Cu = Components.utils;
|
||||
const CRYPTO_COLLECTION = "crypto";
|
||||
const KEYS_WBO = "keys";
|
||||
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-sync/constants.js");
|
||||
Cu.import("resource://services-sync/keys.js");
|
||||
Cu.import("resource://services-sync/resource.js");
|
||||
@ -111,7 +111,7 @@ Utils.deferGetSet(WBORecord, "data", ["id", "modified", "sortindex", "payload"])
|
||||
this.RecordManager = function RecordManager(service) {
|
||||
this.service = service;
|
||||
|
||||
this._log = Log4Moz.repository.getLogger(this._logName);
|
||||
this._log = Log.repository.getLogger(this._logName);
|
||||
this._records = {};
|
||||
}
|
||||
RecordManager.prototype = {
|
||||
@ -281,7 +281,7 @@ this.CollectionKeyManager = function CollectionKeyManager() {
|
||||
this._collections = {};
|
||||
this._default = null;
|
||||
|
||||
this._log = Log4Moz.repository.getLogger("Sync.CollectionKeyManager");
|
||||
this._log = Log.repository.getLogger("Sync.CollectionKeyManager");
|
||||
}
|
||||
|
||||
// TODO: persist this locally as an Identity. Bug 610913.
|
||||
|
@ -14,7 +14,7 @@ const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://services-common/async.js");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/observers.js");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
Cu.import("resource://services-sync/constants.js");
|
||||
@ -50,9 +50,9 @@ const DEFAULT_LOAD_FLAGS =
|
||||
* the status of the HTTP response.
|
||||
*/
|
||||
this.AsyncResource = function AsyncResource(uri) {
|
||||
this._log = Log4Moz.repository.getLogger(this._logName);
|
||||
this._log = Log.repository.getLogger(this._logName);
|
||||
this._log.level =
|
||||
Log4Moz.Level[Svc.Prefs.get("log.logger.network.resources")];
|
||||
Log.Level[Svc.Prefs.get("log.logger.network.resources")];
|
||||
this.uri = uri;
|
||||
this._headers = {};
|
||||
this._onComplete = Utils.bind2(this, this._onComplete);
|
||||
@ -265,7 +265,7 @@ AsyncResource.prototype = {
|
||||
this._log.debug(mesg);
|
||||
|
||||
// Additionally give the full response body when Trace logging.
|
||||
if (this._log.level <= Log4Moz.Level.Trace)
|
||||
if (this._log.level <= Log.Level.Trace)
|
||||
this._log.trace(action + " body: " + data);
|
||||
|
||||
} catch(ex) {
|
||||
@ -588,8 +588,8 @@ ChannelListener.prototype = {
|
||||
function ChannelNotificationListener(headersToCopy) {
|
||||
this._headersToCopy = headersToCopy;
|
||||
|
||||
this._log = Log4Moz.repository.getLogger(this._logName);
|
||||
this._log.level = Log4Moz.Level[Svc.Prefs.get("log.logger.network.resources")];
|
||||
this._log = Log.repository.getLogger(this._logName);
|
||||
this._log.level = Log.Level[Svc.Prefs.get("log.logger.network.resources")];
|
||||
}
|
||||
ChannelNotificationListener.prototype = {
|
||||
_logName: "Sync.Resource",
|
||||
@ -609,7 +609,7 @@ ChannelNotificationListener.prototype = {
|
||||
},
|
||||
|
||||
notifyCertProblem: function certProblem(socketInfo, sslStatus, targetHost) {
|
||||
let log = Log4Moz.repository.getLogger("Sync.CertListener");
|
||||
let log = Log.repository.getLogger("Sync.CertListener");
|
||||
log.warn("Invalid HTTPS certificate encountered!");
|
||||
|
||||
// This suppresses the UI warning only. The request is still cancelled.
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/rest.js");
|
||||
Cu.import("resource://services-sync/util.js");
|
||||
Cu.import("resource://services-sync/constants.js");
|
||||
|
@ -20,7 +20,7 @@ const KEYS_WBO = "keys";
|
||||
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
Cu.import("resource://services-sync/constants.js");
|
||||
Cu.import("resource://services-sync/engines.js");
|
||||
@ -317,9 +317,9 @@ Sync11Service.prototype = {
|
||||
|
||||
this.errorHandler = new ErrorHandler(this);
|
||||
|
||||
this._log = Log4Moz.repository.getLogger("Sync.Service");
|
||||
this._log = Log.repository.getLogger("Sync.Service");
|
||||
this._log.level =
|
||||
Log4Moz.Level[Svc.Prefs.get("log.logger.service.main")];
|
||||
Log.Level[Svc.Prefs.get("log.logger.service.main")];
|
||||
|
||||
this._log.info("Loading Weave " + WEAVE_VERSION);
|
||||
|
||||
|
@ -6,7 +6,7 @@ this.EXPORTED_SYMBOLS = ["ClusterManager"];
|
||||
|
||||
const {utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-sync/constants.js");
|
||||
Cu.import("resource://services-sync/policies.js");
|
||||
Cu.import("resource://services-sync/util.js");
|
||||
@ -15,8 +15,8 @@ Cu.import("resource://services-sync/util.js");
|
||||
* Contains code for managing the Sync cluster we are in.
|
||||
*/
|
||||
this.ClusterManager = function ClusterManager(service) {
|
||||
this._log = Log4Moz.repository.getLogger("Sync.Service");
|
||||
this._log.level = Log4Moz.Level[Svc.Prefs.get("log.logger.service.main")];
|
||||
this._log = Log.repository.getLogger("Sync.Service");
|
||||
this._log.level = Log.Level[Svc.Prefs.get("log.logger.service.main")];
|
||||
|
||||
this.service = service;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ this.EXPORTED_SYMBOLS = ["EngineSynchronizer"];
|
||||
|
||||
const {utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-sync/constants.js");
|
||||
Cu.import("resource://services-sync/engines.js");
|
||||
Cu.import("resource://services-sync/policies.js");
|
||||
@ -22,8 +22,8 @@ Cu.import("resource://services-sync/util.js");
|
||||
* This was originally split out of service.js. The API needs lots of love.
|
||||
*/
|
||||
this.EngineSynchronizer = function EngineSynchronizer(service) {
|
||||
this._log = Log4Moz.repository.getLogger("Sync.Synchronizer");
|
||||
this._log.level = Log4Moz.Level[Svc.Prefs.get("log.logger.synchronizer")];
|
||||
this._log = Log.repository.getLogger("Sync.Synchronizer");
|
||||
this._log.level = Log.Level[Svc.Prefs.get("log.logger.synchronizer")];
|
||||
|
||||
this.service = service;
|
||||
|
||||
|
@ -10,12 +10,12 @@ const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://services-sync/constants.js");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-sync/identity.js");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
this.Status = {
|
||||
_log: Log4Moz.repository.getLogger("Sync.Status"),
|
||||
_log: Log.repository.getLogger("Sync.Status"),
|
||||
_authManager: new IdentityManager(),
|
||||
ready: false,
|
||||
|
||||
@ -114,7 +114,7 @@ this.Status = {
|
||||
} catch (ex) {
|
||||
// Use default.
|
||||
}
|
||||
this._log.level = Log4Moz.Level[logLevel];
|
||||
this._log.level = Log.Level[logLevel];
|
||||
|
||||
this._log.info("Resetting Status.");
|
||||
this.service = STATUS_OK;
|
||||
|
@ -10,7 +10,7 @@ this.EXPORTED_SYMBOLS = [
|
||||
|
||||
const {utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/rest.js");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
Cu.import("resource://services-sync/identity.js");
|
||||
@ -24,8 +24,8 @@ Cu.import("resource://services-sync/util.js");
|
||||
* Instances are constructed with the base URI of the service.
|
||||
*/
|
||||
this.UserAPI10Client = function UserAPI10Client(baseURI) {
|
||||
this._log = Log4Moz.repository.getLogger("Sync.UserAPI");
|
||||
this._log.level = Log4Moz.Level[Svc.Prefs.get("log.logger.userapi")];
|
||||
this._log = Log.repository.getLogger("Sync.UserAPI");
|
||||
this._log.level = Log.Level[Svc.Prefs.get("log.logger.userapi")];
|
||||
|
||||
this.baseURI = baseURI;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ this.EXPORTED_SYMBOLS = ["XPCOMUtils", "Services", "NetUtil", "PlacesUtils",
|
||||
|
||||
const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/observers.js");
|
||||
Cu.import("resource://services-common/stringbundle.js");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
|
@ -1,7 +1,7 @@
|
||||
const Cm = Components.manager;
|
||||
|
||||
// Shared logging for all HTTP server functions.
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
const SYNC_HTTP_LOGGER = "Sync.Test.Server";
|
||||
const SYNC_API_VERSION = "1.1";
|
||||
|
||||
@ -163,7 +163,7 @@ function ServerCollection(wbos, acceptNew, timestamp) {
|
||||
* has a modified time.
|
||||
*/
|
||||
this.timestamp = timestamp || new_timestamp();
|
||||
this._log = Log4Moz.repository.getLogger(SYNC_HTTP_LOGGER);
|
||||
this._log = Log.repository.getLogger(SYNC_HTTP_LOGGER);
|
||||
}
|
||||
ServerCollection.prototype = {
|
||||
|
||||
@ -527,7 +527,7 @@ function SyncServer(callback) {
|
||||
this.server = new HttpServer();
|
||||
this.started = false;
|
||||
this.users = {};
|
||||
this._log = Log4Moz.repository.getLogger(SYNC_HTTP_LOGGER);
|
||||
this._log = Log.repository.getLogger(SYNC_HTTP_LOGGER);
|
||||
|
||||
// Install our own default handler. This allows us to mess around with the
|
||||
// whole URL space.
|
||||
|
@ -240,13 +240,13 @@ add_test(function cleanup() {
|
||||
|
||||
function run_test() {
|
||||
initTestLogging("Trace");
|
||||
Log4Moz.repository.getLogger("Sync.Engine.Addons").level =
|
||||
Log4Moz.Level.Trace;
|
||||
Log4Moz.repository.getLogger("Sync.Store.Addons").level = Log4Moz.Level.Trace;
|
||||
Log4Moz.repository.getLogger("Sync.Tracker.Addons").level =
|
||||
Log4Moz.Level.Trace;
|
||||
Log4Moz.repository.getLogger("Sync.AddonsRepository").level =
|
||||
Log4Moz.Level.Trace;
|
||||
Log.repository.getLogger("Sync.Engine.Addons").level =
|
||||
Log.Level.Trace;
|
||||
Log.repository.getLogger("Sync.Store.Addons").level = Log.Level.Trace;
|
||||
Log.repository.getLogger("Sync.Tracker.Addons").level =
|
||||
Log.Level.Trace;
|
||||
Log.repository.getLogger("Sync.AddonsRepository").level =
|
||||
Log.Level.Trace;
|
||||
|
||||
reconciler.startListening();
|
||||
|
||||
|
@ -14,9 +14,9 @@ startupManager();
|
||||
|
||||
function run_test() {
|
||||
initTestLogging("Trace");
|
||||
Log4Moz.repository.getLogger("Sync.AddonsReconciler").level = Log4Moz.Level.Trace;
|
||||
Log4Moz.repository.getLogger("Sync.AddonsReconciler").level =
|
||||
Log4Moz.Level.Trace;
|
||||
Log.repository.getLogger("Sync.AddonsReconciler").level = Log.Level.Trace;
|
||||
Log.repository.getLogger("Sync.AddonsReconciler").level =
|
||||
Log.Level.Trace;
|
||||
|
||||
Svc.Prefs.set("engine.addons", true);
|
||||
Service.engineManager.register(AddonsEngine);
|
||||
|
@ -67,9 +67,9 @@ function createAndStartHTTPServer(port) {
|
||||
|
||||
function run_test() {
|
||||
initTestLogging("Trace");
|
||||
Log4Moz.repository.getLogger("Sync.Engine.Addons").level = Log4Moz.Level.Trace;
|
||||
Log4Moz.repository.getLogger("Sync.AddonsRepository").level =
|
||||
Log4Moz.Level.Trace;
|
||||
Log.repository.getLogger("Sync.Engine.Addons").level = Log.Level.Trace;
|
||||
Log.repository.getLogger("Sync.AddonsRepository").level =
|
||||
Log.Level.Trace;
|
||||
|
||||
reconciler.startListening();
|
||||
|
||||
|
@ -43,9 +43,9 @@ function cleanup_and_advance() {
|
||||
|
||||
function run_test() {
|
||||
initTestLogging("Trace");
|
||||
Log4Moz.repository.getLogger("Sync.Engine.Addons").level = Log4Moz.Level.Trace;
|
||||
Log4Moz.repository.getLogger("Sync.AddonsReconciler").level =
|
||||
Log4Moz.Level.Trace;
|
||||
Log.repository.getLogger("Sync.Engine.Addons").level = Log.Level.Trace;
|
||||
Log.repository.getLogger("Sync.AddonsReconciler").level =
|
||||
Log.Level.Trace;
|
||||
|
||||
cleanup_and_advance();
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
Cu.import("resource://gre/modules/PlacesUtils.jsm");
|
||||
Cu.import("resource://gre/modules/BookmarkJSONUtils.jsm");
|
||||
Cu.import("resource://services-common/async.js");
|
||||
Cu.import("resource://services-common/log4moz.js");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-sync/engines.js");
|
||||
Cu.import("resource://services-sync/engines/bookmarks.js");
|
||||
Cu.import("resource://services-sync/service.js");
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user