mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge fx-team to m-c. a=merge
This commit is contained in:
commit
5dac9823cd
@ -228,6 +228,8 @@ pref("general.autoScroll", true);
|
||||
pref("browser.shell.checkDefaultBrowser", true);
|
||||
pref("browser.shell.shortcutFavicons",true);
|
||||
pref("browser.shell.mostRecentDateSetAsDefault", "");
|
||||
pref("browser.shell.skipDefaultBrowserCheck", true);
|
||||
pref("browser.shell.defaultBrowserCheckCount", 0);
|
||||
|
||||
// 0 = blank, 1 = home (browser.startup.homepage), 2 = last visited page, 3 = resume previous browser session
|
||||
// The behavior of option 3 is detailed at: http://wiki.mozilla.org/Session_Restore
|
||||
|
@ -24,11 +24,15 @@ LOCAL_INCLUDES += [
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
OS_LIBS += [
|
||||
'esent',
|
||||
'ole32',
|
||||
'shell32',
|
||||
'shlwapi',
|
||||
'version',
|
||||
]
|
||||
DELAYLOAD_DLLS += [
|
||||
'esent.dll',
|
||||
]
|
||||
|
||||
# Mac: Need to link with CoreFoundation for Mac Migrators (PList reading code)
|
||||
# GTK2: Need to link with glib for GNOME shell service
|
||||
|
@ -10,6 +10,12 @@
|
||||
|
||||
#define NS_IEHISTORYENUMERATOR_CONTRACTID \
|
||||
"@mozilla.org/profile/migrator/iehistoryenumerator;1"
|
||||
|
||||
#define NS_EDGEREADINGLISTEXTRACTOR_CID \
|
||||
{ 0xeeff77b1, 0xdb98, 0x4241, { 0x94, 0x36, 0x14, 0xf7, 0xa2, 0x28, 0x84, 0xc1 } }
|
||||
|
||||
#define NS_EDGEREADINGLISTEXTRACTOR_CONTRACTID \
|
||||
"@mozilla.org/profile/migrator/edgereadinglistextractor;1"
|
||||
#endif
|
||||
|
||||
#define NS_SHELLSERVICE_CID \
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#if defined(XP_WIN)
|
||||
#include "nsIEHistoryEnumerator.h"
|
||||
#include "nsEdgeReadingListExtractor.h"
|
||||
#endif
|
||||
|
||||
#include "rdf.h"
|
||||
@ -42,6 +43,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGNOMEShellService, Init)
|
||||
|
||||
#if defined(XP_WIN)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsIEHistoryEnumerator)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsEdgeReadingListExtractor)
|
||||
#endif
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsFeedSniffer)
|
||||
@ -56,6 +58,7 @@ NS_DEFINE_NAMED_CID(NS_FEEDSNIFFER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_BROWSER_ABOUT_REDIRECTOR_CID);
|
||||
#if defined(XP_WIN)
|
||||
NS_DEFINE_NAMED_CID(NS_WINIEHISTORYENUMERATOR_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_EDGEREADINGLISTEXTRACTOR_CID);
|
||||
#elif defined(XP_MACOSX)
|
||||
NS_DEFINE_NAMED_CID(NS_SHELLSERVICE_CID);
|
||||
#endif
|
||||
@ -71,6 +74,7 @@ static const mozilla::Module::CIDEntry kBrowserCIDs[] = {
|
||||
{ &kNS_BROWSER_ABOUT_REDIRECTOR_CID, false, nullptr, AboutRedirector::Create },
|
||||
#if defined(XP_WIN)
|
||||
{ &kNS_WINIEHISTORYENUMERATOR_CID, false, nullptr, nsIEHistoryEnumeratorConstructor },
|
||||
{ &kNS_EDGEREADINGLISTEXTRACTOR_CID, false, nullptr, nsEdgeReadingListExtractorConstructor },
|
||||
#elif defined(XP_MACOSX)
|
||||
{ &kNS_SHELLSERVICE_CID, false, nullptr, nsMacShellServiceConstructor },
|
||||
#endif
|
||||
@ -119,6 +123,7 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "pocket-signup", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
#if defined(XP_WIN)
|
||||
{ NS_IEHISTORYENUMERATOR_CONTRACTID, &kNS_WINIEHISTORYENUMERATOR_CID },
|
||||
{ NS_EDGEREADINGLISTEXTRACTOR_CONTRACTID, &kNS_EDGEREADINGLISTEXTRACTOR_CID },
|
||||
#elif defined(XP_MACOSX)
|
||||
{ NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
|
||||
#endif
|
||||
|
@ -1,30 +1,30 @@
|
||||
/* 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/. */
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource:///modules/MigrationUtils.jsm");
|
||||
Cu.import("resource:///modules/MSMigrationUtils.jsm");
|
||||
|
||||
function EdgeProfileMigrator() {
|
||||
}
|
||||
|
||||
EdgeProfileMigrator.prototype = Object.create(MigratorPrototype);
|
||||
|
||||
EdgeProfileMigrator.prototype.getResources = function() {
|
||||
let resources = [
|
||||
MSMigrationUtils.getBookmarksMigrator(MSMigrationUtils.MIGRATION_TYPE_EDGE),
|
||||
MSMigrationUtils.getCookiesMigrator(MSMigrationUtils.MIGRATION_TYPE_EDGE),
|
||||
];
|
||||
return resources.filter(r => r.exists);
|
||||
};
|
||||
|
||||
EdgeProfileMigrator.prototype.classDescription = "Edge Profile Migrator";
|
||||
EdgeProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=edge";
|
||||
EdgeProfileMigrator.prototype.classID = Components.ID("{62e8834b-2d17-49f5-96ff-56344903a2ae}");
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([EdgeProfileMigrator]);
|
||||
/* 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/. */
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource:///modules/MigrationUtils.jsm");
|
||||
Cu.import("resource:///modules/MSMigrationUtils.jsm");
|
||||
|
||||
function EdgeProfileMigrator() {
|
||||
}
|
||||
|
||||
EdgeProfileMigrator.prototype = Object.create(MigratorPrototype);
|
||||
|
||||
EdgeProfileMigrator.prototype.getResources = function() {
|
||||
let resources = [
|
||||
MSMigrationUtils.getBookmarksMigrator(MSMigrationUtils.MIGRATION_TYPE_EDGE),
|
||||
MSMigrationUtils.getCookiesMigrator(MSMigrationUtils.MIGRATION_TYPE_EDGE),
|
||||
];
|
||||
return resources.filter(r => r.exists);
|
||||
};
|
||||
|
||||
EdgeProfileMigrator.prototype.classDescription = "Edge Profile Migrator";
|
||||
EdgeProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=edge";
|
||||
EdgeProfileMigrator.prototype.classID = Components.ID("{62e8834b-2d17-49f5-96ff-56344903a2ae}");
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([EdgeProfileMigrator]);
|
||||
|
@ -84,7 +84,8 @@ History.prototype = {
|
||||
let transitionType = this._typedURLs[uri.spec] ?
|
||||
Ci.nsINavHistoryService.TRANSITION_TYPED :
|
||||
Ci.nsINavHistoryService.TRANSITION_LINK;
|
||||
let lastVisitTime = entry.get("time");
|
||||
// use the current date if we have no visits for this entry
|
||||
let lastVisitTime = entry.get("time") || Date.now();
|
||||
|
||||
places.push(
|
||||
{ uri: uri,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -10,12 +10,14 @@ JAR_MANIFESTS += ['jar.mn']
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIBrowserProfileMigrator.idl',
|
||||
'nsIEdgeReadingListExtractor.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'migration'
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
SOURCES += [
|
||||
'nsEdgeReadingListExtractor.cpp',
|
||||
'nsIEHistoryEnumerator.cpp',
|
||||
]
|
||||
|
||||
|
203
browser/components/migration/nsEdgeReadingListExtractor.cpp
Normal file
203
browser/components/migration/nsEdgeReadingListExtractor.cpp
Normal file
@ -0,0 +1,203 @@
|
||||
/* 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/. */
|
||||
|
||||
#include "nsEdgeReadingListExtractor.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIConsoleService.h"
|
||||
#include "nsIMutableArray.h"
|
||||
#include "nsIWritablePropertyBag2.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsWindowsMigrationUtils.h"
|
||||
|
||||
#define NS_HANDLE_JET_ERROR(err) { \
|
||||
if (err < JET_errSuccess) { \
|
||||
rv = ConvertJETError(err); \
|
||||
goto CloseDB; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define MAX_URL_LENGTH 4168
|
||||
#define MAX_TITLE_LENGTH 1024
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsEdgeReadingListExtractor, nsIEdgeReadingListExtractor)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEdgeReadingListExtractor::Extract(const nsAString& aDBPath, nsIArray** aItems)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
*aItems = nullptr;
|
||||
|
||||
JET_ERR err;
|
||||
JET_INSTANCE instance;
|
||||
JET_SESID sesid;
|
||||
JET_DBID dbid;
|
||||
JET_TABLEID tableid;
|
||||
JET_COLUMNDEF urlColumnInfo = { 0 };
|
||||
JET_COLUMNDEF titleColumnInfo = { 0 };
|
||||
JET_COLUMNDEF addedDateColumnInfo = { 0 };
|
||||
|
||||
// Need to ensure this happens before we skip ahead to CloseDB,
|
||||
// otherwise the compiler complains.
|
||||
nsCOMPtr<nsIMutableArray> items = do_CreateInstance(NS_ARRAY_CONTRACTID);
|
||||
|
||||
// JET does not throw exceptions, and so error handling and ensuring we close
|
||||
// the DB is a bit finnicky. Keep track of how far we got so we guarantee closing
|
||||
// the right things
|
||||
bool instanceCreated, sessionCreated, dbOpened, tableOpened;
|
||||
|
||||
char16_t* dbPath = ToNewUnicode(aDBPath);
|
||||
|
||||
// Check for the right page size and initialize with that
|
||||
unsigned long pageSize;
|
||||
err = JetGetDatabaseFileInfoW(dbPath, &pageSize, sizeof(pageSize), JET_DbInfoPageSize);
|
||||
NS_HANDLE_JET_ERROR(err)
|
||||
err = JetSetSystemParameter(&instance, NULL, JET_paramDatabasePageSize, pageSize, NULL);
|
||||
NS_HANDLE_JET_ERROR(err)
|
||||
|
||||
// Turn off recovery, because otherwise we will create log files in either the cwd or
|
||||
// overwrite Edge's own logfiles, which is useless at best and at worst might mess with
|
||||
// Edge actually using the DB
|
||||
err = JetSetSystemParameter(&instance, NULL, JET_paramRecovery, NULL, "Off");
|
||||
NS_HANDLE_JET_ERROR(err)
|
||||
|
||||
// Start our session:
|
||||
err = JetCreateInstance(&instance, "edge_readinglist_migration");
|
||||
NS_HANDLE_JET_ERROR(err)
|
||||
instanceCreated = true;
|
||||
|
||||
err = JetInit(&instance);
|
||||
NS_HANDLE_JET_ERROR(err)
|
||||
err = JetBeginSession(instance, &sesid, 0, 0);
|
||||
NS_HANDLE_JET_ERROR(err)
|
||||
sessionCreated = true;
|
||||
|
||||
// Actually open the DB, and make sure to do so readonly:
|
||||
err = JetAttachDatabaseW(sesid, dbPath, JET_bitDbReadOnly);
|
||||
NS_HANDLE_JET_ERROR(err)
|
||||
dbOpened = true;
|
||||
err = JetOpenDatabaseW(sesid, dbPath, NULL, &dbid, JET_bitDbReadOnly);
|
||||
NS_HANDLE_JET_ERROR(err)
|
||||
|
||||
// Open the readinglist table and get information on the columns we are interested in:
|
||||
err = JetOpenTable(sesid, dbid, "ReadingList", NULL, 0, JET_bitTableReadOnly, &tableid);
|
||||
NS_HANDLE_JET_ERROR(err)
|
||||
tableOpened = true;
|
||||
err = JetGetColumnInfo(sesid, dbid, "ReadingList", "URL", &urlColumnInfo,
|
||||
sizeof(urlColumnInfo), JET_ColInfo);
|
||||
NS_HANDLE_JET_ERROR(err)
|
||||
if (urlColumnInfo.cbMax > MAX_URL_LENGTH) {
|
||||
nsCOMPtr<nsIConsoleService> consoleService = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
|
||||
if (consoleService) {
|
||||
consoleService->LogStringMessage(NS_LITERAL_STRING("Edge migration: URL column size increased").get());
|
||||
}
|
||||
}
|
||||
err = JetGetColumnInfo(sesid, dbid, "ReadingList", "Title", &titleColumnInfo,
|
||||
sizeof(titleColumnInfo), JET_ColInfo);
|
||||
NS_HANDLE_JET_ERROR(err)
|
||||
if (titleColumnInfo.cbMax > MAX_TITLE_LENGTH) {
|
||||
nsCOMPtr<nsIConsoleService> consoleService = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
|
||||
if (consoleService) {
|
||||
consoleService->LogStringMessage(NS_LITERAL_STRING("Edge migration: Title column size increased").get());
|
||||
}
|
||||
}
|
||||
err = JetGetColumnInfo(sesid, dbid, "ReadingList", "AddedDate", &addedDateColumnInfo,
|
||||
sizeof(addedDateColumnInfo), JET_ColInfo);
|
||||
NS_HANDLE_JET_ERROR(err)
|
||||
|
||||
// verify the column types are what we expect:
|
||||
if (urlColumnInfo.coltyp != JET_coltypLongText ||
|
||||
titleColumnInfo.coltyp != JET_coltypLongText ||
|
||||
addedDateColumnInfo.coltyp != JET_coltypLongLong) {
|
||||
rv = NS_ERROR_NOT_IMPLEMENTED;
|
||||
goto CloseDB;
|
||||
}
|
||||
|
||||
JET_COLUMNID urlColumnId = urlColumnInfo.columnid;
|
||||
JET_COLUMNID titleColumnId = titleColumnInfo.columnid;
|
||||
JET_COLUMNID addedDateColumnId = addedDateColumnInfo.columnid;
|
||||
|
||||
// If we got here, we've found our table and column information
|
||||
|
||||
err = JetMove(sesid, tableid, JET_MoveFirst, 0);
|
||||
// It's possible there are 0 items in this table, in which case we want to
|
||||
// not fail:
|
||||
if (err == JET_errNoCurrentRecord) {
|
||||
items.forget(aItems);
|
||||
goto CloseDB;
|
||||
}
|
||||
// Check for any other errors
|
||||
NS_HANDLE_JET_ERROR(err)
|
||||
|
||||
FILETIME addedDate;
|
||||
wchar_t urlBuffer[MAX_URL_LENGTH] = { 0 };
|
||||
wchar_t titleBuffer[MAX_TITLE_LENGTH] = { 0 };
|
||||
do {
|
||||
err = JetRetrieveColumn(sesid, tableid, urlColumnId, &urlBuffer,
|
||||
sizeof(urlBuffer), NULL, 0, NULL);
|
||||
NS_HANDLE_JET_ERROR(err)
|
||||
err = JetRetrieveColumn(sesid, tableid, titleColumnId, &titleBuffer,
|
||||
sizeof(titleBuffer), NULL, 0, NULL);
|
||||
NS_HANDLE_JET_ERROR(err)
|
||||
err = JetRetrieveColumn(sesid, tableid, addedDateColumnId, &addedDate,
|
||||
sizeof(addedDate), NULL, 0, NULL);
|
||||
NS_HANDLE_JET_ERROR(err)
|
||||
nsCOMPtr<nsIWritablePropertyBag2> pbag = do_CreateInstance("@mozilla.org/hash-property-bag;1");
|
||||
bool dateIsValid;
|
||||
PRTime prAddedDate = WinMigrationFileTimeToPRTime(&addedDate, &dateIsValid);
|
||||
nsDependentString url(urlBuffer);
|
||||
nsDependentString title(titleBuffer);
|
||||
pbag->SetPropertyAsAString(NS_LITERAL_STRING("uri"), url);
|
||||
pbag->SetPropertyAsAString(NS_LITERAL_STRING("title"), title);
|
||||
if (dateIsValid) {
|
||||
pbag->SetPropertyAsInt64(NS_LITERAL_STRING("time"), prAddedDate);
|
||||
}
|
||||
items->AppendElement(pbag, false);
|
||||
memset(urlBuffer, 0, sizeof(urlBuffer));
|
||||
memset(titleBuffer, 0, sizeof(titleBuffer));
|
||||
} while (JET_errSuccess == JetMove(sesid, tableid, JET_MoveNext, 0));
|
||||
|
||||
items.forget(aItems);
|
||||
|
||||
CloseDB:
|
||||
// Terminate ESENT. This performs a clean shutdown.
|
||||
// Ignore errors while closing:
|
||||
if (tableOpened)
|
||||
JetCloseTable(sesid, tableid);
|
||||
if (dbOpened)
|
||||
JetCloseDatabase(sesid, dbid, 0);
|
||||
if (sessionCreated)
|
||||
JetEndSession(sesid, 0);
|
||||
if (instanceCreated)
|
||||
JetTerm(instance);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEdgeReadingListExtractor::ConvertJETError(const JET_ERR &aError)
|
||||
{
|
||||
switch (aError) {
|
||||
case JET_errPageSizeMismatch:
|
||||
case JET_errInvalidName:
|
||||
case JET_errColumnNotFound:
|
||||
// The DB format has changed and we haven't updated this migration code:
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
case JET_errDatabaseLocked:
|
||||
return NS_ERROR_FILE_IS_LOCKED;
|
||||
case JET_errPermissionDenied:
|
||||
case JET_errAccessDenied:
|
||||
return NS_ERROR_FILE_ACCESS_DENIED;
|
||||
case JET_errInvalidFilename:
|
||||
return NS_ERROR_FILE_INVALID_PATH;
|
||||
case JET_errFileNotFound:
|
||||
return NS_ERROR_FILE_NOT_FOUND;
|
||||
default:
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
31
browser/components/migration/nsEdgeReadingListExtractor.h
Normal file
31
browser/components/migration/nsEdgeReadingListExtractor.h
Normal file
@ -0,0 +1,31 @@
|
||||
/* 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/. */
|
||||
|
||||
#ifndef edgereadinglistextractor__h__
|
||||
#define edgereadinglistextractor__h__
|
||||
|
||||
#include "nsIArray.h"
|
||||
#include "nsIEdgeReadingListExtractor.h"
|
||||
|
||||
// To get access to the long data types, we need to use at least the Vista version of the JET APIs
|
||||
#undef JET_VERSION
|
||||
#define JET_VERSION 0x0600
|
||||
#include <esent.h>
|
||||
|
||||
class nsEdgeReadingListExtractor final : public nsIEdgeReadingListExtractor
|
||||
{
|
||||
public:
|
||||
nsEdgeReadingListExtractor() {}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_DECL_NSIEDGEREADINGLISTEXTRACTOR
|
||||
|
||||
private:
|
||||
~nsEdgeReadingListExtractor() {}
|
||||
|
||||
nsresult ConvertJETError(const JET_ERR &err);
|
||||
};
|
||||
|
||||
#endif
|
@ -7,37 +7,13 @@
|
||||
#include <urlhist.h>
|
||||
#include <shlguid.h>
|
||||
|
||||
#include "nsStringAPI.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "prtime.h"
|
||||
#include "nsIVariant.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsArrayEnumerator.h"
|
||||
|
||||
namespace {
|
||||
|
||||
PRTime FileTimeToPRTime(FILETIME* filetime)
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
::FileTimeToSystemTime(filetime, &st);
|
||||
PRExplodedTime prt;
|
||||
prt.tm_year = st.wYear;
|
||||
// SYSTEMTIME's day-of-month parameter is 1-based,
|
||||
// PRExplodedTime's is 0-based.
|
||||
prt.tm_month = st.wMonth - 1;
|
||||
prt.tm_mday = st.wDay;
|
||||
prt.tm_hour = st.wHour;
|
||||
prt.tm_min = st.wMinute;
|
||||
prt.tm_sec = st.wSecond;
|
||||
prt.tm_usec = st.wMilliseconds * 1000;
|
||||
prt.tm_wday = 0;
|
||||
prt.tm_yday = 0;
|
||||
prt.tm_params.tp_gmt_offset = 0;
|
||||
prt.tm_params.tp_dst_offset = 0;
|
||||
return PR_ImplodeTime(&prt);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsIVariant.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsStringAPI.h"
|
||||
#include "nsWindowsMigrationUtils.h"
|
||||
#include "prtime.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// nsIEHistoryEnumerator
|
||||
@ -106,14 +82,17 @@ nsIEHistoryEnumerator::HasMoreElements(bool* _retval)
|
||||
|
||||
nsDependentString title(statURL.pwcsTitle);
|
||||
|
||||
PRTime lastVisited = FileTimeToPRTime(&(statURL.ftLastVisited));
|
||||
bool lastVisitTimeIsValid;
|
||||
PRTime lastVisited = WinMigrationFileTimeToPRTime(&(statURL.ftLastVisited), &lastVisitTimeIsValid);
|
||||
|
||||
mCachedNextEntry = do_CreateInstance("@mozilla.org/hash-property-bag;1");
|
||||
MOZ_ASSERT(mCachedNextEntry, "Should have instanced a new property bag");
|
||||
if (mCachedNextEntry) {
|
||||
mCachedNextEntry->SetPropertyAsInterface(NS_LITERAL_STRING("uri"), uri);
|
||||
mCachedNextEntry->SetPropertyAsAString(NS_LITERAL_STRING("title"), title);
|
||||
mCachedNextEntry->SetPropertyAsInt64(NS_LITERAL_STRING("time"), lastVisited);
|
||||
if (lastVisitTimeIsValid) {
|
||||
mCachedNextEntry->SetPropertyAsInt64(NS_LITERAL_STRING("time"), lastVisited);
|
||||
}
|
||||
|
||||
*_retval = true;
|
||||
}
|
||||
|
23
browser/components/migration/nsIEdgeReadingListExtractor.idl
Normal file
23
browser/components/migration/nsIEdgeReadingListExtractor.idl
Normal file
@ -0,0 +1,23 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIArray;
|
||||
|
||||
[scriptable, uuid(bfdef4aa-dcd1-4d31-b5d9-188fe8d98623)]
|
||||
interface nsIEdgeReadingListExtractor : nsISupports
|
||||
{
|
||||
/**
|
||||
* Import data from the database indicated by the databasePath
|
||||
* May fail if the path is invalid, unreadable, the database is corrupt,
|
||||
* or the data in the database is not in the format we expect.
|
||||
*
|
||||
* @param databasePath the absolute path to the database we'd like to import
|
||||
* @return an enumerator of nsIPropertyBag2 items that each have a URL, title, and
|
||||
* creation dates.
|
||||
*/
|
||||
nsIArray extract(in DOMString databasePath);
|
||||
};
|
36
browser/components/migration/nsWindowsMigrationUtils.h
Normal file
36
browser/components/migration/nsWindowsMigrationUtils.h
Normal file
@ -0,0 +1,36 @@
|
||||
/* 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/. */
|
||||
|
||||
#ifndef windowsmigrationutils__h__
|
||||
#define windowsmigrationutils__h__
|
||||
|
||||
#include "prtime.h"
|
||||
|
||||
static
|
||||
PRTime WinMigrationFileTimeToPRTime(FILETIME* filetime, bool* isValid)
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
*isValid = ::FileTimeToSystemTime(filetime, &st);
|
||||
if (!*isValid) {
|
||||
return 0;
|
||||
}
|
||||
PRExplodedTime prt;
|
||||
prt.tm_year = st.wYear;
|
||||
// SYSTEMTIME's day-of-month parameter is 1-based,
|
||||
// PRExplodedTime's is 0-based.
|
||||
prt.tm_month = st.wMonth - 1;
|
||||
prt.tm_mday = st.wDay;
|
||||
prt.tm_hour = st.wHour;
|
||||
prt.tm_min = st.wMinute;
|
||||
prt.tm_sec = st.wSecond;
|
||||
prt.tm_usec = st.wMilliseconds * 1000;
|
||||
prt.tm_wday = 0;
|
||||
prt.tm_yday = 0;
|
||||
prt.tm_params.tp_gmt_offset = 0;
|
||||
prt.tm_params.tp_dst_offset = 0;
|
||||
return PR_ImplodeTime(&prt);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -317,11 +317,55 @@ nsGNOMEShellService::SetDefaultBrowser(bool aClaimAllTypes,
|
||||
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
|
||||
if (prefs) {
|
||||
(void) prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, true);
|
||||
// Reset the number of times the dialog should be shown
|
||||
// before it is silenced.
|
||||
(void) prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT, 0);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGNOMEShellService::GetShouldSkipCheckDefaultBrowser(bool* aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = prefs->GetBoolPref(PREF_SKIPDEFAULTBROWSERCHECK, aResult);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (*aResult) {
|
||||
// Only skip the default browser check once. The next attempt in
|
||||
// a new session should proceed.
|
||||
return prefs->SetBoolPref(PREF_SKIPDEFAULTBROWSERCHECK, false);
|
||||
}
|
||||
|
||||
int32_t defaultBrowserCheckCount;
|
||||
rv = prefs->GetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT,
|
||||
&defaultBrowserCheckCount);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (defaultBrowserCheckCount < 3) {
|
||||
*aResult = false;
|
||||
return prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT,
|
||||
defaultBrowserCheckCount + 1);
|
||||
}
|
||||
|
||||
// Disable the default browser check after three attempts.
|
||||
// Don't modify PREF_CHECKDEFAULTBROWSER since that is a
|
||||
// user-initiated action and it shouldn't get re-enabled
|
||||
// if it has been user disabled.
|
||||
*aResult = true;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGNOMEShellService::GetShouldCheckDefaultBrowser(bool* aResult)
|
||||
{
|
||||
@ -333,6 +377,18 @@ nsGNOMEShellService::GetShouldCheckDefaultBrowser(bool* aResult)
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
#ifndef RELEASE_BUILD
|
||||
bool skipDefaultBrowserCheck;
|
||||
rv = GetShouldSkipCheckDefaultBrowser(&skipDefaultBrowserCheck);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (skipDefaultBrowserCheck) {
|
||||
*aResult = false;
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -8,7 +8,7 @@
|
||||
interface nsIDOMElement;
|
||||
interface nsIFile;
|
||||
|
||||
[scriptable, uuid(99d2e9f1-3c86-40f7-81fd-3060c18489f0)]
|
||||
[scriptable, uuid(55cb78a8-2fc4-48f4-9345-ff0e541c5cc4)]
|
||||
interface nsIShellService : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -38,7 +38,7 @@ interface nsIShellService : nsISupports
|
||||
*/
|
||||
void setDefaultBrowser(in boolean aClaimAllTypes, in boolean aForAllUsers);
|
||||
|
||||
/**
|
||||
/**
|
||||
* Used to determine whether or not to show a "Set Default Browser"
|
||||
* query dialog. This attribute is true if the application is starting
|
||||
* up and "browser.shell.checkDefaultBrowser" is true, otherwise it
|
||||
@ -46,6 +46,13 @@ interface nsIShellService : nsISupports
|
||||
*/
|
||||
attribute boolean shouldCheckDefaultBrowser;
|
||||
|
||||
/**
|
||||
* Used to determine whether or not the "Set Default Browser" check
|
||||
* should be skipped during first-run or after the browser has been
|
||||
* run a few times.
|
||||
*/
|
||||
readonly attribute boolean shouldSkipCheckDefaultBrowser;
|
||||
|
||||
/**
|
||||
* Used to determine whether or not to offer "Set as desktop background"
|
||||
* functionality. Even if shell service is available it is not
|
||||
|
@ -95,11 +95,55 @@ nsMacShellService::SetDefaultBrowser(bool aClaimAllTypes, bool aForAllUsers)
|
||||
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
|
||||
if (prefs) {
|
||||
(void) prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, true);
|
||||
// Reset the number of times the dialog should be shown
|
||||
// before it is silenced.
|
||||
(void) prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT, 0);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMacShellService::GetShouldSkipCheckDefaultBrowser(bool* aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = prefs->GetBoolPref(PREF_SKIPDEFAULTBROWSERCHECK, aResult);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (*aResult) {
|
||||
// Only skip the default browser check once. The next attempt in
|
||||
// a new session should proceed.
|
||||
return prefs->SetBoolPref(PREF_SKIPDEFAULTBROWSERCHECK, false);
|
||||
}
|
||||
|
||||
int32_t defaultBrowserCheckCount;
|
||||
rv = prefs->GetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT,
|
||||
&defaultBrowserCheckCount);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (defaultBrowserCheckCount < 3) {
|
||||
*aResult = false;
|
||||
return prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT,
|
||||
defaultBrowserCheckCount + 1);
|
||||
}
|
||||
|
||||
// Disable the default browser check after three attempts.
|
||||
// Don't modify PREF_CHECKDEFAULTBROWSER since that is a
|
||||
// user-initiated action and it shouldn't get re-enabled
|
||||
// if it has been user disabled.
|
||||
*aResult = true;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMacShellService::GetShouldCheckDefaultBrowser(bool* aResult)
|
||||
{
|
||||
@ -111,6 +155,18 @@ nsMacShellService::GetShouldCheckDefaultBrowser(bool* aResult)
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
#ifndef RELEASE_BUILD
|
||||
bool skipDefaultBrowserCheck;
|
||||
rv = GetShouldSkipCheckDefaultBrowser(&skipDefaultBrowserCheck);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (skipDefaultBrowserCheck) {
|
||||
*aResult = false;
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -4,6 +4,8 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#define PREF_CHECKDEFAULTBROWSER "browser.shell.checkDefaultBrowser"
|
||||
#define PREF_SKIPDEFAULTBROWSERCHECK "browser.shell.skipDefaultBrowserCheck"
|
||||
#define PREF_DEFAULTBROWSERCHECKCOUNT "browser.shell.defaultBrowserCheckCount"
|
||||
|
||||
#define SHELLSERVICE_PROPERTIES "chrome://browser/locale/shellservice.properties"
|
||||
#define BRAND_PROPERTIES "chrome://branding/locale/brand.properties"
|
||||
|
@ -976,17 +976,61 @@ nsWindowsShellService::SetDefaultBrowser(bool aClaimAllTypes, bool aForAllUsers)
|
||||
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
|
||||
if (prefs) {
|
||||
(void) prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, true);
|
||||
// Reset the number of times the dialog should be shown
|
||||
// before it is silenced.
|
||||
(void) prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT, 0);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsShellService::GetShouldSkipCheckDefaultBrowser(bool* aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = prefs->GetBoolPref(PREF_SKIPDEFAULTBROWSERCHECK, aResult);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (*aResult) {
|
||||
// Only skip the default browser check once. The next attempt in
|
||||
// a new session should proceed.
|
||||
return prefs->SetBoolPref(PREF_SKIPDEFAULTBROWSERCHECK, false);
|
||||
}
|
||||
|
||||
int32_t defaultBrowserCheckCount;
|
||||
rv = prefs->GetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT,
|
||||
&defaultBrowserCheckCount);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (defaultBrowserCheckCount < 3) {
|
||||
*aResult = false;
|
||||
return prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT,
|
||||
defaultBrowserCheckCount + 1);
|
||||
}
|
||||
|
||||
// Disable the default browser check after three attempts.
|
||||
// Don't modify PREF_CHECKDEFAULTBROWSER since that is a
|
||||
// user-initiated action and it shouldn't get re-enabled
|
||||
// if it has been user disabled.
|
||||
*aResult = true;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsShellService::GetShouldCheckDefaultBrowser(bool* aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
|
||||
// If we've already checked, the browser has been started and this is a
|
||||
// If we've already checked, the browser has been started and this is a
|
||||
// new window open, and we don't want to check again.
|
||||
if (mCheckedThisSession) {
|
||||
*aResult = false;
|
||||
@ -994,6 +1038,18 @@ nsWindowsShellService::GetShouldCheckDefaultBrowser(bool* aResult)
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
#ifndef RELEASE_BUILD
|
||||
bool skipDefaultBrowserCheck;
|
||||
rv = GetShouldSkipCheckDefaultBrowser(&skipDefaultBrowserCheck);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (skipDefaultBrowserCheck) {
|
||||
*aResult = false;
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -108,9 +108,7 @@ browser.jar:
|
||||
content/browser/devtools/performance/views/details-js-flamegraph.js (performance/views/details-js-flamegraph.js)
|
||||
content/browser/devtools/performance/views/details-memory-call-tree.js (performance/views/details-memory-call-tree.js)
|
||||
content/browser/devtools/performance/views/details-memory-flamegraph.js (performance/views/details-memory-flamegraph.js)
|
||||
content/browser/devtools/performance/views/details-optimizations.js (performance/views/details-optimizations.js)
|
||||
content/browser/devtools/performance/views/optimizations-list.js (performance/views/optimizations-list.js)
|
||||
content/browser/devtools/performance/views/frames-list.js (performance/views/frames-list.js)
|
||||
content/browser/devtools/performance/views/recordings.js (performance/views/recordings.js)
|
||||
content/browser/devtools/promisedebugger/promise-debugger.js (promisedebugger/promise-debugger.js)
|
||||
content/browser/devtools/promisedebugger/promise-debugger.xhtml (promisedebugger/promise-debugger.xhtml)
|
||||
|
@ -354,13 +354,16 @@ const Formatters = {
|
||||
return marker.name || L10N.getStr("marker.label.unknown");
|
||||
},
|
||||
|
||||
GCLabel: function (marker={}) {
|
||||
GCLabel: function (marker) {
|
||||
if (!marker) {
|
||||
return L10N.getStr("marker.label.garbageCollection2");
|
||||
}
|
||||
// Only if a `nonincrementalReason` exists, do we want to label
|
||||
// this as a non incremental GC event.
|
||||
if ("nonincrementalReason" in marker) {
|
||||
return L10N.getStr("marker.label.garbageCollection.nonIncremental");
|
||||
}
|
||||
return L10N.getStr("marker.label.garbageCollection");
|
||||
return L10N.getStr("marker.label.garbageCollection.incremental");
|
||||
},
|
||||
|
||||
JSLabel: function (marker={}) {
|
||||
|
@ -13,36 +13,75 @@ const { L10N } = require("devtools/performance/global");
|
||||
const { Heritage } = require("resource:///modules/devtools/ViewHelpers.jsm");
|
||||
const { AbstractTreeItem } = require("resource:///modules/devtools/AbstractTreeItem.jsm");
|
||||
|
||||
const MILLISECOND_UNITS = L10N.getStr("table.ms");
|
||||
const PERCENTAGE_UNITS = L10N.getStr("table.percentage");
|
||||
const URL_LABEL_TOOLTIP = L10N.getStr("table.url.tooltiptext");
|
||||
const VIEW_OPTIMIZATIONS_TOOLTIP = L10N.getStr("table.view-optimizations.tooltiptext");
|
||||
const VIEW_OPTIMIZATIONS_TOOLTIP = L10N.getStr("table.view-optimizations.tooltiptext2");
|
||||
|
||||
const CALL_TREE_INDENTATION = 16; // px
|
||||
|
||||
// Used for rendering values in cells
|
||||
const FORMATTERS = {
|
||||
TIME: (value) => L10N.getFormatStr("table.ms2", L10N.numberWithDecimals(value, 2)),
|
||||
PERCENT: (value) => L10N.getFormatStr("table.percentage2", L10N.numberWithDecimals(value, 2)),
|
||||
NUMBER: (value) => value || 0,
|
||||
BYTESIZE: (value) => L10N.getFormatStr("table.bytes", (value || 0))
|
||||
};
|
||||
|
||||
/**
|
||||
* Definitions for rendering cells. Triads of class name, property name from
|
||||
* `frame.getInfo()`, and a formatter function.
|
||||
*/
|
||||
const CELLS = {
|
||||
duration: ["duration", "totalDuration", FORMATTERS.TIME],
|
||||
percentage: ["percentage", "totalPercentage", FORMATTERS.PERCENT],
|
||||
selfDuration: ["self-duration", "selfDuration", FORMATTERS.TIME],
|
||||
selfPercentage: ["self-percentage", "selfPercentage", FORMATTERS.PERCENT],
|
||||
samples: ["samples", "samples", FORMATTERS.NUMBER],
|
||||
|
||||
selfSize: ["self-size", "selfSize", FORMATTERS.BYTESIZE],
|
||||
selfSizePercentage: ["self-size-percentage", "selfSizePercentage", FORMATTERS.PERCENT],
|
||||
selfCount: ["self-count", "selfCount", FORMATTERS.NUMBER],
|
||||
selfCountPercentage: ["self-count-percentage", "selfCountPercentage", FORMATTERS.PERCENT],
|
||||
size: ["size", "totalSize", FORMATTERS.BYTESIZE],
|
||||
sizePercentage: ["size-percentage", "totalSizePercentage", FORMATTERS.PERCENT],
|
||||
count: ["count", "totalCount", FORMATTERS.NUMBER],
|
||||
countPercentage: ["count-percentage", "totalCountPercentage", FORMATTERS.PERCENT],
|
||||
};
|
||||
const CELL_TYPES = Object.keys(CELLS);
|
||||
|
||||
const DEFAULT_SORTING_PREDICATE = (frameA, frameB) => {
|
||||
let dataA = frameA.getDisplayedData();
|
||||
let dataB = frameB.getDisplayedData();
|
||||
if (this.inverted) {
|
||||
// Invert trees, sort by selfPercentage, and then totalPercentage
|
||||
if (dataA.selfPercentage === dataB.selfPercentage) {
|
||||
return dataA.totalPercentage < dataB.totalPercentage ? 1 : -1;
|
||||
}
|
||||
return dataA.selfPercentage < dataB.selfPercentage ? 1 : - 1;
|
||||
let isAllocations = "totalSize" in dataA;
|
||||
|
||||
if (isAllocations) {
|
||||
return this.inverted && dataA.selfSize !== dataB.selfSize ?
|
||||
(dataA.selfSize < dataB.selfSize ? 1 : - 1) :
|
||||
(dataA.totalSize < dataB.totalSize ? 1 : -1);
|
||||
}
|
||||
return dataA.totalPercentage < dataB.totalPercentage ? 1 : -1;
|
||||
|
||||
return this.inverted && dataA.selfPercentage !== dataB.selfPercentage ?
|
||||
(dataA.selfPercentage < dataB.selfPercentage ? 1 : - 1) :
|
||||
(dataA.totalPercentage < dataB.totalPercentage ? 1 : -1);
|
||||
};
|
||||
|
||||
const DEFAULT_AUTO_EXPAND_DEPTH = 3; // depth
|
||||
const DEFAULT_VISIBLE_CELLS = {
|
||||
duration: true,
|
||||
percentage: true,
|
||||
count: false,
|
||||
selfDuration: true,
|
||||
selfPercentage: true,
|
||||
selfCount: false,
|
||||
samples: true,
|
||||
function: true
|
||||
function: true,
|
||||
|
||||
// allocation columns
|
||||
count: false,
|
||||
selfCount: false,
|
||||
size: false,
|
||||
selfSize: false,
|
||||
countPercentage: false,
|
||||
selfCountPercentage: false,
|
||||
sizePercentage: false,
|
||||
selfSizePercentage: false,
|
||||
};
|
||||
|
||||
const clamp = (val, min, max) => Math.max(min, Math.min(max, val));
|
||||
@ -136,27 +175,14 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||
let frameInfo = this.getDisplayedData();
|
||||
let cells = [];
|
||||
|
||||
if (this.visibleCells.duration) {
|
||||
cells.push(this._createTimeCell(document, frameInfo.totalDuration));
|
||||
}
|
||||
if (this.visibleCells.percentage) {
|
||||
cells.push(this._createExecutionCell(document, frameInfo.totalPercentage));
|
||||
}
|
||||
if (this.visibleCells.count) {
|
||||
cells.push(this._createCountCell(document, frameInfo.totalCount));
|
||||
}
|
||||
if (this.visibleCells.selfDuration) {
|
||||
cells.push(this._createTimeCell(document, frameInfo.selfDuration, true));
|
||||
}
|
||||
if (this.visibleCells.selfPercentage) {
|
||||
cells.push(this._createExecutionCell(document, frameInfo.selfPercentage, true));
|
||||
}
|
||||
if (this.visibleCells.selfCount) {
|
||||
cells.push(this._createCountCell(document, frameInfo.selfCount, true));
|
||||
}
|
||||
if (this.visibleCells.samples) {
|
||||
cells.push(this._createSamplesCell(document, frameInfo.samples));
|
||||
for (let type of CELL_TYPES) {
|
||||
if (this.visibleCells[type]) {
|
||||
// Inline for speed, but pass in the formatted value via
|
||||
// cell definition, as well as the element type.
|
||||
cells.push(this._createCell(document, CELLS[type][2](frameInfo[CELLS[type][1]]), CELLS[type][0]));
|
||||
}
|
||||
}
|
||||
|
||||
if (this.visibleCells.function) {
|
||||
cells.push(this._createFunctionCell(document, arrowNode, frameInfo.name, frameInfo, this.level));
|
||||
}
|
||||
@ -204,38 +230,15 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||
* Functions creating each cell in this call view.
|
||||
* Invoked by `_displaySelf`.
|
||||
*/
|
||||
_createTimeCell: function(doc, duration, isSelf = false) {
|
||||
_createCell: function (doc, value, type) {
|
||||
let cell = doc.createElement("description");
|
||||
cell.className = "plain call-tree-cell";
|
||||
cell.setAttribute("type", isSelf ? "self-duration" : "duration");
|
||||
cell.setAttribute("type", type);
|
||||
cell.setAttribute("crop", "end");
|
||||
cell.setAttribute("value", L10N.numberWithDecimals(duration, 2) + " " + MILLISECOND_UNITS);
|
||||
return cell;
|
||||
},
|
||||
_createExecutionCell: function(doc, percentage, isSelf = false) {
|
||||
let cell = doc.createElement("description");
|
||||
cell.className = "plain call-tree-cell";
|
||||
cell.setAttribute("type", isSelf ? "self-percentage" : "percentage");
|
||||
cell.setAttribute("crop", "end");
|
||||
cell.setAttribute("value", L10N.numberWithDecimals(percentage, 2) + PERCENTAGE_UNITS);
|
||||
return cell;
|
||||
},
|
||||
_createCountCell: function(doc, count, isSelf = false) {
|
||||
let cell = doc.createElement("description");
|
||||
cell.className = "plain call-tree-cell";
|
||||
cell.setAttribute("type", isSelf ? "self-count" : "count");
|
||||
cell.setAttribute("crop", "end");
|
||||
cell.setAttribute("value", count || 0);
|
||||
return cell;
|
||||
},
|
||||
_createSamplesCell: function(doc, count) {
|
||||
let cell = doc.createElement("description");
|
||||
cell.className = "plain call-tree-cell";
|
||||
cell.setAttribute("type", "samples");
|
||||
cell.setAttribute("crop", "end");
|
||||
cell.setAttribute("value", count || 0);
|
||||
cell.setAttribute("value", value);
|
||||
return cell;
|
||||
},
|
||||
|
||||
_createFunctionCell: function(doc, arrowNode, frameName, frameInfo, frameLevel) {
|
||||
let cell = doc.createElement("hbox");
|
||||
cell.className = "call-tree-cell";
|
||||
@ -243,12 +246,10 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||
cell.setAttribute("type", "function");
|
||||
cell.appendChild(arrowNode);
|
||||
|
||||
// Render optimization link to JIT view if the frame
|
||||
// has optimizations
|
||||
// Render optimization hint if this frame has opt data.
|
||||
if (this.root.showOptimizationHint && frameInfo.hasOptimizations && !frameInfo.isMetaCategory) {
|
||||
let icon = doc.createElement("description");
|
||||
icon.setAttribute("tooltiptext", VIEW_OPTIMIZATIONS_TOOLTIP);
|
||||
icon.setAttribute("type", "linkable");
|
||||
icon.className = "opt-icon";
|
||||
cell.appendChild(icon);
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ const EVENTS = {
|
||||
// When the PerformanceView updates the display of the buffer status
|
||||
UI_BUFFER_STATUS_UPDATED: "Performance:UI:BufferUpdated",
|
||||
|
||||
// Emitted by the JITOptimizationsView when it renders new optimization
|
||||
// Emitted by the OptimizationsListView when it renders new optimization
|
||||
// data and clears the optimization data
|
||||
OPTIMIZATIONS_RESET: "Performance:UI:OptimizationsReset",
|
||||
OPTIMIZATIONS_RENDERED: "Performance:UI:OptimizationsRendered",
|
||||
|
@ -24,11 +24,9 @@
|
||||
<script type="application/javascript" src="performance/views/details-js-flamegraph.js"/>
|
||||
<script type="application/javascript" src="performance/views/details-memory-call-tree.js"/>
|
||||
<script type="application/javascript" src="performance/views/details-memory-flamegraph.js"/>
|
||||
<script type="application/javascript" src="performance/views/details-optimizations.js"/>
|
||||
<script type="application/javascript" src="performance/views/details.js"/>
|
||||
<script type="application/javascript" src="performance/views/recordings.js"/>
|
||||
<script type="application/javascript" src="performance/views/optimizations-list.js"/>
|
||||
<script type="application/javascript" src="performance/views/frames-list.js"/>
|
||||
|
||||
<popupset id="performance-options-popupset">
|
||||
<menupopup id="performance-filter-menupopup"/>
|
||||
@ -144,11 +142,6 @@
|
||||
label="&performanceUI.toolbar.memory-flamegraph;"
|
||||
hidden="true"
|
||||
data-view="memory-flamegraph" />
|
||||
<toolbarbutton id="select-optimizations-view"
|
||||
class="devtools-toolbarbutton devtools-button"
|
||||
label="Optimizations"
|
||||
hidden="true"
|
||||
data-view="optimizations" />
|
||||
</hbox>
|
||||
<spacer flex="1"></spacer>
|
||||
<hbox id="performance-toolbar-controls-options"
|
||||
@ -298,6 +291,20 @@
|
||||
</hbox>
|
||||
<vbox class="call-tree-cells-container" flex="1"/>
|
||||
</vbox>
|
||||
<splitter class="devtools-side-splitter"/>
|
||||
<!-- Optimizations Panel -->
|
||||
<vbox id="jit-optimizations-view"
|
||||
class="hidden">
|
||||
<toolbar id="jit-optimizations-toolbar" class="devtools-toolbar">
|
||||
<hbox id="jit-optimizations-header">
|
||||
<span class="jit-optimizations-title">&performanceUI.JITOptimizationsTitle;</span>
|
||||
<span class="header-function-name" />
|
||||
<span class="header-file opt-url debugger-link" />
|
||||
<span class="header-line opt-line" />
|
||||
</hbox>
|
||||
</toolbar>
|
||||
<vbox id="jit-optimizations-raw-view"></vbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
<!-- JS FlameChart -->
|
||||
@ -308,15 +315,45 @@
|
||||
<vbox id="memory-calltree-view" flex="1">
|
||||
<hbox class="call-tree-headers-container">
|
||||
<label class="plain call-tree-header"
|
||||
type="count"
|
||||
type="self-size"
|
||||
crop="end"
|
||||
value="&performanceUI.table.totalAlloc;"
|
||||
value="Self Bytes"
|
||||
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
|
||||
<label class="plain call-tree-header"
|
||||
type="self-size-percentage"
|
||||
crop="end"
|
||||
value="Self Bytes %"
|
||||
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
|
||||
<label class="plain call-tree-header"
|
||||
type="self-count"
|
||||
crop="end"
|
||||
value="&performanceUI.table.selfAlloc;"
|
||||
tooltiptext="&performanceUI.table.selfAlloc.tooltip;"/>
|
||||
value="Self Count"
|
||||
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
|
||||
<label class="plain call-tree-header"
|
||||
type="self-count-percentage"
|
||||
crop="end"
|
||||
value="Self Count %"
|
||||
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
|
||||
<label class="plain call-tree-header"
|
||||
type="size"
|
||||
crop="end"
|
||||
value="Total Size"
|
||||
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
|
||||
<label class="plain call-tree-header"
|
||||
type="size-percentage"
|
||||
crop="end"
|
||||
value="Total Size %"
|
||||
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
|
||||
<label class="plain call-tree-header"
|
||||
type="count"
|
||||
crop="end"
|
||||
value="Total Count"
|
||||
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
|
||||
<label class="plain call-tree-header"
|
||||
type="count-percentage"
|
||||
crop="end"
|
||||
value="Total Count %"
|
||||
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
|
||||
<label class="plain call-tree-header"
|
||||
type="function"
|
||||
crop="end"
|
||||
@ -328,47 +365,6 @@
|
||||
<!-- Memory FlameChart -->
|
||||
<hbox id="memory-flamegraph-view" flex="1">
|
||||
</hbox>
|
||||
|
||||
<!-- JIT View -->
|
||||
<hbox id="optimizations-view" flex="1">
|
||||
<hbox id="graph-placeholder" flex="1">
|
||||
</hbox>
|
||||
<splitter id="optimizations-splitter" class="devtools-side-splitter"/>
|
||||
<tabbox id="optimizations-tabs"
|
||||
class="devtools-sidebar-tabs"
|
||||
handleCtrlTab="false">
|
||||
<tabs>
|
||||
<tab id="optimizations-optimizations-tab"
|
||||
label="Optimizations" />
|
||||
<tab id="optimizations-frames-tab"
|
||||
label="Frames" />
|
||||
</tabs>
|
||||
<tabpanels flex="1">
|
||||
|
||||
<!-- Optimizations Panel -->
|
||||
<tabpanel id="optimizations-tabpanel"
|
||||
class="tabpanel-content">
|
||||
<vbox id="jit-optimizations-view">
|
||||
<toolbar id="jit-optimizations-toolbar" class="devtools-toolbar">
|
||||
<hbox id="jit-optimizations-header">
|
||||
<span class="jit-optimizations-title">&performanceUI.JITOptimizationsTitle;</span>
|
||||
<span class="header-function-name" />
|
||||
<span class="header-file opt-url debugger-link" />
|
||||
<span class="header-line opt-line" />
|
||||
</hbox>
|
||||
</toolbar>
|
||||
<vbox id="jit-optimizations-raw-view"></vbox>
|
||||
</vbox>
|
||||
</tabpanel>
|
||||
|
||||
<!-- Frames Panel -->
|
||||
<tabpanel id="frames-tabpanel"
|
||||
class="tabpanel-content">
|
||||
</tabpanel>
|
||||
</tabpanels>
|
||||
</tabbox>
|
||||
</hbox>
|
||||
<!-- /JIT View -->
|
||||
</deck>
|
||||
</deck>
|
||||
</vbox>
|
||||
|
@ -42,8 +42,8 @@ skip-if = true # Bug 1161817
|
||||
[browser_perf-details-07.js]
|
||||
[browser_perf-events-calltree.js]
|
||||
[browser_perf-highlighted.js]
|
||||
#[browser_perf-jit-view-01.js] bug 1176056
|
||||
#[browser_perf-jit-view-02.js] bug 1176056
|
||||
[browser_perf-jit-view-01.js]
|
||||
[browser_perf-jit-view-02.js]
|
||||
[browser_perf-legacy-front-01.js]
|
||||
[browser_perf-legacy-front-02.js]
|
||||
[browser_perf-legacy-front-03.js]
|
||||
@ -69,7 +69,6 @@ skip-if = os == 'linux' # Bug 1172120
|
||||
[browser_perf-options-show-idle-blocks-02.js]
|
||||
[browser_perf-options-enable-memory-01.js]
|
||||
[browser_perf-options-enable-memory-02.js]
|
||||
[browser_perf-options-enable-optimizations.js]
|
||||
[browser_perf-options-enable-framerate.js]
|
||||
[browser_perf-options-allocations.js]
|
||||
[browser_perf-options-profiler.js]
|
||||
|
@ -24,9 +24,15 @@ function* spawnTest() {
|
||||
"duration": false,
|
||||
"percentage": false,
|
||||
"count": true,
|
||||
"count-percentage": true,
|
||||
"size": true,
|
||||
"size-percentage": true,
|
||||
"self-duration": false,
|
||||
"self-percentage": false,
|
||||
"self-count": true,
|
||||
"self-count-percentage": true,
|
||||
"self-size": true,
|
||||
"self-size-percentage": true,
|
||||
"samples": false,
|
||||
"function": true
|
||||
});
|
||||
|
@ -11,7 +11,7 @@ Services.prefs.setBoolPref(INVERT_PREF, false);
|
||||
function* spawnTest() {
|
||||
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||
let { EVENTS, $, $$, window, PerformanceController } = panel.panelWin;
|
||||
let { OverviewView, DetailsView, JITOptimizationsView, JsCallTreeView, RecordingsView } = panel.panelWin;
|
||||
let { OverviewView, DetailsView, OptimizationsListView, JsCallTreeView, RecordingsView } = panel.panelWin;
|
||||
|
||||
let profilerData = { threads: [gThread] }
|
||||
|
||||
@ -42,7 +42,7 @@ function* spawnTest() {
|
||||
yield checkFrame(3);
|
||||
|
||||
let select = once(PerformanceController, EVENTS.RECORDING_SELECTED);
|
||||
let reset = once(JITOptimizationsView, EVENTS.OPTIMIZATIONS_RESET);
|
||||
let reset = once(OptimizationsListView, EVENTS.OPTIMIZATIONS_RESET);
|
||||
RecordingsView.selectedIndex = 0;
|
||||
yield Promise.all([select, reset]);
|
||||
ok(true, "JITOptimizations view correctly reset when switching recordings.");
|
||||
@ -67,11 +67,12 @@ function* spawnTest() {
|
||||
}
|
||||
|
||||
function *checkFrame (frameIndex, expectedOpts=[]) {
|
||||
info(`Checking frame ${frameIndex}`);
|
||||
// Click the frame
|
||||
let rendered = once(JITOptimizationsView, EVENTS.OPTIMIZATIONS_RENDERED);
|
||||
let rendered = once(OptimizationsListView, EVENTS.OPTIMIZATIONS_RENDERED);
|
||||
mousedown(window, $$(".call-tree-item")[frameIndex]);
|
||||
yield rendered;
|
||||
ok(true, "JITOptimizationsView rendered when enabling with the current frame node selected");
|
||||
ok(true, "OptimizationsListView rendered when enabling with the current frame node selected");
|
||||
|
||||
let isEmpty = $("#jit-optimizations-view").classList.contains("empty");
|
||||
if (expectedOpts.length === 0) {
|
||||
@ -85,7 +86,7 @@ function* spawnTest() {
|
||||
// share the same frame info
|
||||
let frameInfo = expectedOpts[0].opt._testFrameInfo;
|
||||
|
||||
let { $headerName, $headerLine, $headerFile } = JITOptimizationsView;
|
||||
let { $headerName, $headerLine, $headerFile } = OptimizationsListView;
|
||||
ok(!$headerName.hidden, "header function name should be shown");
|
||||
ok(!$headerLine.hidden, "header line should be shown");
|
||||
ok(!$headerFile.hidden, "header file should be shown");
|
||||
|
@ -2,17 +2,18 @@
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that the JIT Optimizations view does not display information
|
||||
* Tests that the OptimizationsListView does not display information
|
||||
* for meta nodes when viewing "content only".
|
||||
*/
|
||||
|
||||
Services.prefs.setBoolPref(INVERT_PREF, false);
|
||||
Services.prefs.setBoolPref(PLATFORM_DATA_PREF, false);
|
||||
let { CATEGORY_MASK } = require("devtools/performance/global");
|
||||
|
||||
function* spawnTest() {
|
||||
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||
let { EVENTS, $, $$, window, PerformanceController } = panel.panelWin;
|
||||
let { OverviewView, DetailsView, JITOptimizationsView, JsCallTreeView, RecordingsView } = panel.panelWin;
|
||||
let { OverviewView, DetailsView, OptimizationsListView, JsCallTreeView, RecordingsView } = panel.panelWin;
|
||||
|
||||
let profilerData = { threads: [gThread] };
|
||||
|
||||
@ -31,14 +32,14 @@ function* spawnTest() {
|
||||
yield injectAndRenderProfilerData();
|
||||
|
||||
// Click the frame
|
||||
let rendered = once(JITOptimizationsView, EVENTS.OPTIMIZATIONS_RENDERED);
|
||||
let rendered = once(OptimizationsListView, EVENTS.OPTIMIZATIONS_RENDERED);
|
||||
mousedown(window, $$(".call-tree-item")[2]);
|
||||
yield rendered;
|
||||
|
||||
ok($("#jit-optimizations-view").classList.contains("empty"),
|
||||
"platform meta frame shows as empty");
|
||||
|
||||
let { $headerName, $headerLine, $headerFile } = JITOptimizationsView;
|
||||
let { $headerName, $headerLine, $headerFile } = OptimizationsListView;
|
||||
ok(!$headerName.hidden, "header function name should be shown");
|
||||
ok($headerLine.hidden, "header line should be hidden");
|
||||
ok($headerFile.hidden, "header file should be hidden");
|
||||
|
@ -1,45 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that `enable-jit-optimizations` sets the recording to subsequently
|
||||
* enable the Optimizations View.
|
||||
*/
|
||||
function* spawnTest() {
|
||||
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||
let { EVENTS, PerformanceController, $, DetailsView, WaterfallView, OptimizationsView } = panel.panelWin;
|
||||
Services.prefs.setBoolPref(JIT_PREF, true);
|
||||
|
||||
|
||||
yield startRecording(panel);
|
||||
let rendered = once(OptimizationsView, EVENTS.OPTIMIZATIONS_RENDERED);
|
||||
yield stopRecording(panel);
|
||||
|
||||
yield DetailsView.selectView("optimizations");
|
||||
ok(DetailsView.isViewSelected(OptimizationsView), "The Optimizations View is now selected.");
|
||||
yield rendered;
|
||||
|
||||
let recording = PerformanceController.getCurrentRecording();
|
||||
is(recording.getConfiguration().withJITOptimizations, true, "recording model has withJITOptimizations as true");
|
||||
|
||||
// Set back to false, should not affect display of first recording
|
||||
info("Disabling enable-jit-optimizations");
|
||||
Services.prefs.setBoolPref(JIT_PREF, false);
|
||||
is($("#select-optimizations-view").hidden, false,
|
||||
"JIT Optimizations selector still available since the recording has it enabled.");
|
||||
|
||||
yield startRecording(panel);
|
||||
rendered = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
|
||||
yield stopRecording(panel);
|
||||
|
||||
ok(DetailsView.isViewSelected(WaterfallView), "The waterfall view is now selected.");
|
||||
yield rendered;
|
||||
|
||||
recording = PerformanceController.getCurrentRecording();
|
||||
is(recording.getConfiguration().withJITOptimizations, false, "recording model has withJITOptimizations as false");
|
||||
is($("#select-optimizations-view").hidden, true,
|
||||
"JIT Optimizations selector is hidden if recording did not enable optimizations.");
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
@ -19,6 +19,8 @@ add_task(function () {
|
||||
"getMarkerLabel() returns a simple label");
|
||||
equal(Utils.getMarkerLabel({ name: "Javascript", causeName: "setTimeout handler" }), "setTimeout",
|
||||
"getMarkerLabel() returns a label defined via function");
|
||||
equal(Utils.getMarkerLabel({ name: "GarbageCollection", causeName: "ALLOC_TRIGGER" }), "Incremental GC",
|
||||
"getMarkerLabel() returns a label for a function that is generalizable");
|
||||
|
||||
ok(Utils.getMarkerFields({ name: "Paint" }).length === 0,
|
||||
"getMarkerFields() returns an empty array when no fields defined");
|
||||
@ -53,7 +55,7 @@ add_task(function () {
|
||||
|
||||
equal(Utils.getMarkerClassName("Javascript"), "Function Call",
|
||||
"getMarkerClassName() returns correct string when defined via function");
|
||||
equal(Utils.getMarkerClassName("GarbageCollection"), "Incremental GC",
|
||||
equal(Utils.getMarkerClassName("GarbageCollection"), "Garbage Collection",
|
||||
"getMarkerClassName() returns correct string when defined via function");
|
||||
equal(Utils.getMarkerClassName("Reflow"), "Layout",
|
||||
"getMarkerClassName() returns correct string when defined via string");
|
||||
|
@ -23,14 +23,18 @@ let JsCallTreeView = Heritage.extend(DetailsSubview, {
|
||||
DetailsSubview.initialize.call(this);
|
||||
|
||||
this._onLink = this._onLink.bind(this);
|
||||
this._onFocus = this._onFocus.bind(this);
|
||||
|
||||
this.container = $("#js-calltree-view .call-tree-cells-container");
|
||||
|
||||
OptimizationsListView.initialize();
|
||||
},
|
||||
|
||||
/**
|
||||
* Unbinds events.
|
||||
*/
|
||||
destroy: function () {
|
||||
OptimizationsListView.destroy();
|
||||
this.container = null;
|
||||
DetailsSubview.destroy.call(this);
|
||||
},
|
||||
@ -44,17 +48,44 @@ let JsCallTreeView = Heritage.extend(DetailsSubview, {
|
||||
render: function (interval={}) {
|
||||
let recording = PerformanceController.getCurrentRecording();
|
||||
let profile = recording.getProfile();
|
||||
let optimizations = recording.getConfiguration().withJITOptimizations;
|
||||
|
||||
let options = {
|
||||
contentOnly: !PerformanceController.getOption("show-platform-data"),
|
||||
invertTree: PerformanceController.getOption("invert-call-tree"),
|
||||
flattenRecursion: PerformanceController.getOption("flatten-tree-recursion"),
|
||||
showOptimizationHint: recording.getConfiguration().withJITOptimizations,
|
||||
showOptimizationHint: optimizations
|
||||
};
|
||||
let threadNode = this._prepareCallTree(profile, interval, options);
|
||||
this._populateCallTree(threadNode, options);
|
||||
|
||||
if (optimizations) {
|
||||
this.showOptimizations();
|
||||
} else {
|
||||
this.hideOptimizations();
|
||||
}
|
||||
OptimizationsListView.reset();
|
||||
|
||||
this.emit(EVENTS.JS_CALL_TREE_RENDERED);
|
||||
},
|
||||
|
||||
showOptimizations: function () {
|
||||
$("#jit-optimizations-view").classList.remove("hidden");
|
||||
},
|
||||
|
||||
hideOptimizations: function () {
|
||||
$("#jit-optimizations-view").classList.add("hidden");
|
||||
},
|
||||
|
||||
_onFocus: function (_, treeItem) {
|
||||
if (PerformanceController.getCurrentRecording().getConfiguration().withJITOptimizations) {
|
||||
OptimizationsListView.setCurrentFrame(treeItem.frame);
|
||||
OptimizationsListView.render();
|
||||
}
|
||||
|
||||
this.emit("focus", treeItem);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fired on the "link" event for the call tree in this container.
|
||||
*/
|
||||
@ -111,12 +142,7 @@ let JsCallTreeView = Heritage.extend(DetailsSubview, {
|
||||
|
||||
// Bind events.
|
||||
root.on("link", this._onLink);
|
||||
|
||||
// Pipe "focus" events to the view, mostly for tests
|
||||
root.on("focus", () => this.emit("focus"));
|
||||
// TODO tests for optimization event and rendering
|
||||
// optimization bubbles in call tree
|
||||
root.on("optimization", (_, node) => this.emit("optimization", node));
|
||||
root.on("focus", this._onFocus);
|
||||
|
||||
// Clear out other call trees.
|
||||
this.container.innerHTML = "";
|
||||
|
@ -88,8 +88,6 @@ let MemoryCallTreeView = Heritage.extend(DetailsSubview, {
|
||||
inverted: inverted,
|
||||
// Root nodes are hidden in inverted call trees.
|
||||
hidden: inverted,
|
||||
// Memory call trees should be sorted by allocations.
|
||||
sortingPredicate: (a, b) => a.frame.allocations < b.frame.allocations ? 1 : -1,
|
||||
// Call trees should only auto-expand when not inverted. Passing undefined
|
||||
// will default to the CALL_TREE_AUTO_EXPAND depth.
|
||||
autoExpandDepth: inverted ? 0 : undefined,
|
||||
@ -98,6 +96,12 @@ let MemoryCallTreeView = Heritage.extend(DetailsSubview, {
|
||||
visibleCells: {
|
||||
selfCount: true,
|
||||
count: true,
|
||||
selfSize: true,
|
||||
size: true,
|
||||
selfCountPercentage: true,
|
||||
countPercentage: true,
|
||||
selfSizePercentage: true,
|
||||
sizePercentage: true,
|
||||
function: true
|
||||
}
|
||||
});
|
||||
|
@ -1,174 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
let OptimizationsView = Heritage.extend(DetailsSubview, {
|
||||
|
||||
rerenderPrefs: [
|
||||
"show-platform-data",
|
||||
"flatten-tree-recursion",
|
||||
],
|
||||
|
||||
rangeChangeDebounceTime: 75, // ms
|
||||
|
||||
/**
|
||||
* Sets up the view with event binding.
|
||||
*/
|
||||
initialize: function () {
|
||||
DetailsSubview.initialize.call(this);
|
||||
this.reset = this.reset.bind(this);
|
||||
this.tabs = $("#optimizations-tabs");
|
||||
this._onFramesListSelect = this._onFramesListSelect.bind(this);
|
||||
|
||||
OptimizationsListView.initialize();
|
||||
FramesListView.initialize({ container: $("#frames-tabpanel") });
|
||||
FramesListView.on("select", this._onFramesListSelect);
|
||||
},
|
||||
|
||||
/**
|
||||
* Unbinds events.
|
||||
*/
|
||||
destroy: function () {
|
||||
DetailsSubview.destroy.call(this);
|
||||
this.tabs = this._threadNode = this._frameNode = null;
|
||||
|
||||
FramesListView.off("select", this._onFramesListSelect);
|
||||
FramesListView.destroy();
|
||||
OptimizationsListView.destroy();
|
||||
},
|
||||
|
||||
/**
|
||||
* Selects a tab by name.
|
||||
*
|
||||
* @param {string} name
|
||||
* Can be "frames" or "optimizations"
|
||||
*/
|
||||
selectTabByName: function (name="frames") {
|
||||
switch(name) {
|
||||
case "optimizations":
|
||||
this.tabs.selectedIndex = 0;
|
||||
break;
|
||||
case "frames":
|
||||
this.tabs.selectedIndex = 1;
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method for handling all the set up for rendering a new call tree.
|
||||
*
|
||||
* @param object interval [optional]
|
||||
* The { startTime, endTime }, in milliseconds.
|
||||
*/
|
||||
render: function (interval={}) {
|
||||
let options = {
|
||||
contentOnly: !PerformanceController.getOption("show-platform-data"),
|
||||
flattenRecursion: PerformanceController.getOption("flatten-tree-recursion"),
|
||||
// Always invert the tree for the optimizations view so we can quickly
|
||||
// get leaves
|
||||
invertTree: true,
|
||||
};
|
||||
let recording = PerformanceController.getCurrentRecording();
|
||||
let profile = recording.getProfile();
|
||||
|
||||
this.reset();
|
||||
// TODO bug 1175662
|
||||
// Share thread nodes between details view
|
||||
this.threadNode = this._prepareThreadNode(profile, interval, options);
|
||||
this.emit(EVENTS.OPTIMIZATIONS_RENDERED);
|
||||
},
|
||||
|
||||
/**
|
||||
* The main thread node used in this recording that contains
|
||||
* all potential frame nodes to select.
|
||||
*/
|
||||
set threadNode(threadNode) {
|
||||
if (threadNode === this._threadNode) {
|
||||
return;
|
||||
}
|
||||
this._threadNode = threadNode;
|
||||
// Also clear out the current frame node as its no
|
||||
// longer relevent
|
||||
this.frameNode = null;
|
||||
this._setAndRenderFramesList();
|
||||
},
|
||||
get threadNode() {
|
||||
return this._threadNode;
|
||||
},
|
||||
|
||||
/**
|
||||
* frameNode is the frame node selected currently to inspect
|
||||
* the optimization tiers over time and strategies.
|
||||
*/
|
||||
set frameNode(frameNode) {
|
||||
if (frameNode === this._frameNode) {
|
||||
return;
|
||||
}
|
||||
this._frameNode = frameNode;
|
||||
|
||||
// If no frame selected, jump to the frame list view. If just selected
|
||||
// a frame, jump to optimizations view.
|
||||
// TODO test for this bug 1176056
|
||||
this.selectTabByName(frameNode ? "optimizations" : "frames");
|
||||
this._setAndRenderTierGraph();
|
||||
this._setAndRenderOptimizationsList();
|
||||
},
|
||||
|
||||
get frameNode() {
|
||||
return this._frameNode;
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears the frameNode so that tier and opts list
|
||||
* views are cleared.
|
||||
*/
|
||||
reset: function () {
|
||||
this.threadNode = this.frameNode = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the recording is stopped and prepares data to
|
||||
* populate the graph.
|
||||
*/
|
||||
_prepareThreadNode: function (profile, { startTime, endTime }, options) {
|
||||
let thread = profile.threads[0];
|
||||
let { contentOnly, invertTree, flattenRecursion } = options;
|
||||
let threadNode = new ThreadNode(thread, { startTime, endTime, contentOnly, invertTree, flattenRecursion });
|
||||
return threadNode;
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders the tier graph.
|
||||
*/
|
||||
_setAndRenderTierGraph: function () {
|
||||
// TODO bug 1150299
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders the frames list.
|
||||
*/
|
||||
_setAndRenderFramesList: function () {
|
||||
FramesListView.setCurrentThread(this.threadNode);
|
||||
FramesListView.render();
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders the optimizations list.
|
||||
*/
|
||||
_setAndRenderOptimizationsList: function () {
|
||||
OptimizationsListView.setCurrentFrame(this.frameNode);
|
||||
OptimizationsListView.render();
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when a frame is selected via the FramesListView
|
||||
*/
|
||||
_onFramesListSelect: function (_, frameNode) {
|
||||
this.frameNode = frameNode;
|
||||
},
|
||||
|
||||
toString: () => "[object OptimizationsView]"
|
||||
});
|
||||
|
||||
EventEmitter.decorate(OptimizationsView);
|
@ -37,11 +37,6 @@ let DetailsView = {
|
||||
features: ["withAllocations"],
|
||||
prefs: ["enable-memory-flame"],
|
||||
},
|
||||
"optimizations": {
|
||||
id: "optimizations-view",
|
||||
view: OptimizationsView,
|
||||
features: ["withJITOptimizations"],
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1,113 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
const PERCENTAGE_UNITS = L10N.getStr("table.percentage");
|
||||
|
||||
/**
|
||||
* View for rendering a list of all youngest-frames in a profiler recording.
|
||||
*/
|
||||
|
||||
let FramesListView = {
|
||||
|
||||
// Current `<li>` element selected.
|
||||
_selectedItem: null,
|
||||
|
||||
/**
|
||||
* Initialization function called when the tool starts up.
|
||||
*/
|
||||
initialize: function ({ container }) {
|
||||
this._onFrameListClick = this._onFrameListClick.bind(this);
|
||||
|
||||
this.container = container;
|
||||
this.list = document.createElementNS(HTML_NS, "ul");
|
||||
this.list.setAttribute("class", "frames-list");
|
||||
this.list.addEventListener("click", this._onFrameListClick, false);
|
||||
|
||||
this.container.appendChild(this.list);
|
||||
},
|
||||
|
||||
/**
|
||||
* Destruction function called when the tool cleans up.
|
||||
*/
|
||||
destroy: function () {
|
||||
this.list.removeEventListener("click", this._onFrameListClick, false);
|
||||
this.container.innerHTML = "";
|
||||
this.container = this.list = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the thread node used for subsequent rendering.
|
||||
*
|
||||
* @param {ThreadNode} threadNode
|
||||
*/
|
||||
setCurrentThread: function (threadNode) {
|
||||
this.threadNode = threadNode;
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders a list of leaf frames with optimizations in
|
||||
* order of hotness from the current ThreadNode.
|
||||
*/
|
||||
render: function () {
|
||||
this.list.innerHTML = "";
|
||||
|
||||
if (!this.threadNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
let totalSamples = this.threadNode.samples;
|
||||
let sortedFrames = this.threadNode.calls.sort((a, b) => a.youngestFrameSamples < b.youngestFrameSamples ? 1 : -1);
|
||||
for (let frame of sortedFrames) {
|
||||
if (!frame.hasOptimizations()) {
|
||||
continue;
|
||||
}
|
||||
let info = frame.getInfo();
|
||||
let el = document.createElementNS(HTML_NS, "li");
|
||||
let percentage = frame.youngestFrameSamples / totalSamples * 100;
|
||||
let percentageText = L10N.numberWithDecimals(percentage, 2) + PERCENTAGE_UNITS;
|
||||
let label = `(${percentageText}) ${info.functionName}`;
|
||||
el.textContent = label;
|
||||
el.setAttribute("tooltip", label);
|
||||
el.setAttribute("data-location", frame.location);
|
||||
this.list.appendChild(el);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Fired when a frame in the list is clicked.
|
||||
*/
|
||||
_onFrameListClick: function (e) {
|
||||
// If no threadNode (no renders), abort;
|
||||
// also only allow left click to trigger this event
|
||||
if (!this.threadNode || e.button !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let target = e.target;
|
||||
let location = target.getAttribute("data-location");
|
||||
if (!location) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let frame of this.threadNode.calls) {
|
||||
if (frame.location === location) {
|
||||
// If found, set the selected class on element, remove it
|
||||
// from previous element, and emit event "select"
|
||||
if (this._selectedItem) {
|
||||
this._selectedItem.classList.remove("selected");
|
||||
}
|
||||
this._selectedItem = target;
|
||||
target.classList.add("selected");
|
||||
this.emit("select", frame);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toString: () => "[object FramesListView]"
|
||||
};
|
||||
|
||||
EventEmitter.decorate(FramesListView);
|
@ -360,7 +360,6 @@ let OptimizationsListView = {
|
||||
},
|
||||
|
||||
toString: () => "[object OptimizationsListView]"
|
||||
|
||||
};
|
||||
|
||||
EventEmitter.decorate(OptimizationsListView);
|
||||
|
@ -1,11 +1,12 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
/* globals focusManager, CSSPropertyList, domUtils */
|
||||
|
||||
/**
|
||||
* 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/.
|
||||
*
|
||||
* Basic use:
|
||||
* let spanToEdit = document.getElementById("somespan");
|
||||
*
|
||||
@ -48,28 +49,28 @@ Cu.import("resource://gre/modules/devtools/event-emitter.js");
|
||||
* Changes will be committed when the InlineEditor's input is blurred
|
||||
* or dropped when the user presses escape.
|
||||
*
|
||||
* @param {object} aOptions
|
||||
* @param {Object} options
|
||||
* Options for the editable field, including:
|
||||
* {Element} element:
|
||||
* (required) The span to be edited on focus.
|
||||
* {function} canEdit:
|
||||
* {Function} canEdit:
|
||||
* Will be called before creating the inplace editor. Editor
|
||||
* won't be created if canEdit returns false.
|
||||
* {function} start:
|
||||
* {Function} start:
|
||||
* Will be called when the inplace editor is initialized.
|
||||
* {function} change:
|
||||
* {Function} change:
|
||||
* Will be called when the text input changes. Will be called
|
||||
* with the current value of the text input.
|
||||
* {function} done:
|
||||
* {Function} done:
|
||||
* Called when input is committed or blurred. Called with
|
||||
* current value, a boolean telling the caller whether to
|
||||
* commit the change, and the direction of the next element to be
|
||||
* selected. Direction may be one of nsIFocusManager.MOVEFOCUS_FORWARD,
|
||||
* nsIFocusManager.MOVEFOCUS_BACKWARD, or null (no movement).
|
||||
* This function is called before the editor has been torn down.
|
||||
* {function} destroy:
|
||||
* {Function} destroy:
|
||||
* Called when the editor is destroyed and has been torn down.
|
||||
* {object} advanceChars:
|
||||
* {Object} advanceChars:
|
||||
* This can be either a string or a function.
|
||||
* If it is a string, then if any characters in it are typed,
|
||||
* focus will advance to the next element.
|
||||
@ -78,27 +79,26 @@ Cu.import("resource://gre/modules/devtools/event-emitter.js");
|
||||
* and the insertion point. If the function returns true,
|
||||
* then the focus advance takes place. If it returns false,
|
||||
* then the character is inserted instead.
|
||||
* {boolean} stopOnReturn:
|
||||
* {Boolean} stopOnReturn:
|
||||
* If true, the return key will not advance the editor to the next
|
||||
* focusable element.
|
||||
* {boolean} stopOnTab:
|
||||
* {Boolean} stopOnTab:
|
||||
* If true, the tab key will not advance the editor to the next
|
||||
* focusable element.
|
||||
* {boolean} stopOnShiftTab:
|
||||
* {Boolean} stopOnShiftTab:
|
||||
* If true, shift tab will not advance the editor to the previous
|
||||
* focusable element.
|
||||
* {string} trigger: The DOM event that should trigger editing,
|
||||
* {String} trigger: The DOM event that should trigger editing,
|
||||
* defaults to "click"
|
||||
* {boolean} multiline: Should the editor be a multiline textarea?
|
||||
* {Boolean} multiline: Should the editor be a multiline textarea?
|
||||
* defaults to false
|
||||
* {boolean} trimOutput: Should the returned string be trimmed?
|
||||
* {Boolean} trimOutput: Should the returned string be trimmed?
|
||||
* defaults to true
|
||||
*/
|
||||
function editableField(aOptions)
|
||||
{
|
||||
return editableItem(aOptions, function(aElement, aEvent) {
|
||||
if (!aOptions.element.inplaceEditor) {
|
||||
new InplaceEditor(aOptions, aEvent);
|
||||
function editableField(options) {
|
||||
return editableItem(options, function(element, event) {
|
||||
if (!options.element.inplaceEditor) {
|
||||
new InplaceEditor(options, event);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -110,25 +110,24 @@ exports.editableField = editableField;
|
||||
* clicks and sit in the editing tab order, and call
|
||||
* a callback when it is activated.
|
||||
*
|
||||
* @param {object} aOptions
|
||||
* @param {Object} options
|
||||
* The options for this editor, including:
|
||||
* {Element} element: The DOM element.
|
||||
* {string} trigger: The DOM event that should trigger editing,
|
||||
* {String} trigger: The DOM event that should trigger editing,
|
||||
* defaults to "click"
|
||||
* @param {function} aCallback
|
||||
* @param {Function} callback
|
||||
* Called when the editor is activated.
|
||||
* @return {function} function which calls aCallback
|
||||
* @return {Function} function which calls callback
|
||||
*/
|
||||
function editableItem(aOptions, aCallback)
|
||||
{
|
||||
let trigger = aOptions.trigger || "click"
|
||||
let element = aOptions.element;
|
||||
function editableItem(options, callback) {
|
||||
let trigger = options.trigger || "click";
|
||||
let element = options.element;
|
||||
element.addEventListener(trigger, function(evt) {
|
||||
if (evt.target.nodeName !== "a") {
|
||||
let win = this.ownerDocument.defaultView;
|
||||
let selection = win.getSelection();
|
||||
if (trigger != "click" || selection.isCollapsed) {
|
||||
aCallback(element, evt);
|
||||
callback(element, evt);
|
||||
}
|
||||
evt.stopPropagation();
|
||||
}
|
||||
@ -139,7 +138,7 @@ function editableItem(aOptions, aCallback)
|
||||
element.addEventListener("keypress", function(evt) {
|
||||
if (evt.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN ||
|
||||
evt.charCode === Ci.nsIDOMKeyEvent.DOM_VK_SPACE) {
|
||||
aCallback(element);
|
||||
callback(element);
|
||||
}
|
||||
}, true);
|
||||
|
||||
@ -168,8 +167,8 @@ function editableItem(aOptions, aCallback)
|
||||
element._trigger = trigger;
|
||||
|
||||
return function turnOnEditMode() {
|
||||
aCallback(element);
|
||||
}
|
||||
callback(element);
|
||||
};
|
||||
}
|
||||
|
||||
exports.editableItem = this.editableItem;
|
||||
@ -181,31 +180,32 @@ exports.editableItem = this.editableItem;
|
||||
* within this JSM. So we provide a little workaround here.
|
||||
*/
|
||||
|
||||
function getInplaceEditorForSpan(aSpan)
|
||||
{
|
||||
return aSpan.inplaceEditor;
|
||||
};
|
||||
function getInplaceEditorForSpan(span) {
|
||||
return span.inplaceEditor;
|
||||
}
|
||||
|
||||
exports.getInplaceEditorForSpan = getInplaceEditorForSpan;
|
||||
|
||||
function InplaceEditor(aOptions, aEvent)
|
||||
{
|
||||
this.elt = aOptions.element;
|
||||
function InplaceEditor(options, event) {
|
||||
this.elt = options.element;
|
||||
let doc = this.elt.ownerDocument;
|
||||
this.doc = doc;
|
||||
this.elt.inplaceEditor = this;
|
||||
|
||||
this.change = aOptions.change;
|
||||
this.done = aOptions.done;
|
||||
this.destroy = aOptions.destroy;
|
||||
this.initial = aOptions.initial ? aOptions.initial : this.elt.textContent;
|
||||
this.multiline = aOptions.multiline || false;
|
||||
this.trimOutput = aOptions.trimOutput === undefined ? true : !!aOptions.trimOutput;
|
||||
this.stopOnShiftTab = !!aOptions.stopOnShiftTab;
|
||||
this.stopOnTab = !!aOptions.stopOnTab;
|
||||
this.stopOnReturn = !!aOptions.stopOnReturn;
|
||||
this.contentType = aOptions.contentType || CONTENT_TYPES.PLAIN_TEXT;
|
||||
this.property = aOptions.property;
|
||||
this.popup = aOptions.popup;
|
||||
this.change = options.change;
|
||||
this.done = options.done;
|
||||
this.destroy = options.destroy;
|
||||
this.initial = options.initial ? options.initial : this.elt.textContent;
|
||||
this.multiline = options.multiline || false;
|
||||
this.trimOutput = options.trimOutput === undefined
|
||||
? true
|
||||
: !!options.trimOutput;
|
||||
this.stopOnShiftTab = !!options.stopOnShiftTab;
|
||||
this.stopOnTab = !!options.stopOnTab;
|
||||
this.stopOnReturn = !!options.stopOnReturn;
|
||||
this.contentType = options.contentType || CONTENT_TYPES.PLAIN_TEXT;
|
||||
this.property = options.property;
|
||||
this.popup = options.popup;
|
||||
|
||||
this._onBlur = this._onBlur.bind(this);
|
||||
this._onKeyPress = this._onKeyPress.bind(this);
|
||||
@ -218,11 +218,11 @@ function InplaceEditor(aOptions, aEvent)
|
||||
|
||||
// Pull out character codes for advanceChars, listing the
|
||||
// characters that should trigger a blur.
|
||||
if (typeof(aOptions.advanceChars) === "function") {
|
||||
this._advanceChars = aOptions.advanceChars;
|
||||
if (typeof options.advanceChars === "function") {
|
||||
this._advanceChars = options.advanceChars;
|
||||
} else {
|
||||
let advanceCharcodes = {};
|
||||
let advanceChars = aOptions.advanceChars || '';
|
||||
let advanceChars = options.advanceChars || "";
|
||||
for (let i = 0; i < advanceChars.length; i++) {
|
||||
advanceCharcodes[advanceChars.charCodeAt(i)] = true;
|
||||
}
|
||||
@ -236,7 +236,7 @@ function InplaceEditor(aOptions, aEvent)
|
||||
|
||||
this.input.focus();
|
||||
|
||||
if (typeof(aOptions.selectAll) == "undefined" || aOptions.selectAll) {
|
||||
if (typeof options.selectAll == "undefined" || options.selectAll) {
|
||||
this.input.select();
|
||||
}
|
||||
|
||||
@ -253,7 +253,7 @@ function InplaceEditor(aOptions, aEvent)
|
||||
this.input.addEventListener("mousedown",
|
||||
(e) => { e.stopPropagation(); }, false);
|
||||
|
||||
this.validate = aOptions.validate;
|
||||
this.validate = options.validate;
|
||||
|
||||
if (this.validate) {
|
||||
this.input.addEventListener("keyup", this._onKeyup, false);
|
||||
@ -261,8 +261,8 @@ function InplaceEditor(aOptions, aEvent)
|
||||
|
||||
this._updateSize();
|
||||
|
||||
if (aOptions.start) {
|
||||
aOptions.start(this, aEvent);
|
||||
if (options.start) {
|
||||
options.start(this, event);
|
||||
}
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
@ -279,8 +279,7 @@ InplaceEditor.prototype = {
|
||||
return val;
|
||||
},
|
||||
|
||||
_createInput: function InplaceEditor_createEditor()
|
||||
{
|
||||
_createInput: function() {
|
||||
this.input =
|
||||
this.doc.createElementNS(HTML_NS, this.multiline ? "textarea" : "input");
|
||||
this.input.inplaceEditor = this;
|
||||
@ -293,8 +292,7 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Get rid of the editor.
|
||||
*/
|
||||
_clear: function InplaceEditor_clear()
|
||||
{
|
||||
_clear: function() {
|
||||
if (!this.input) {
|
||||
// Already cleared.
|
||||
return;
|
||||
@ -327,8 +325,7 @@ InplaceEditor.prototype = {
|
||||
* Keeps the editor close to the size of its input string. This is pretty
|
||||
* crappy, suggestions for improvement welcome.
|
||||
*/
|
||||
_autosize: function InplaceEditor_autosize()
|
||||
{
|
||||
_autosize: function() {
|
||||
// Create a hidden, absolutely-positioned span to measure the text
|
||||
// in the input. Boo.
|
||||
|
||||
@ -352,8 +349,7 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Clean up the mess created by _autosize().
|
||||
*/
|
||||
_stopAutosize: function InplaceEditor_stopAutosize()
|
||||
{
|
||||
_stopAutosize: function() {
|
||||
if (!this._measurement) {
|
||||
return;
|
||||
}
|
||||
@ -364,12 +360,11 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Size the editor to fit its current contents.
|
||||
*/
|
||||
_updateSize: function InplaceEditor_updateSize()
|
||||
{
|
||||
_updateSize: function() {
|
||||
// Replace spaces with non-breaking spaces. Otherwise setting
|
||||
// the span's textContent will collapse spaces and the measurement
|
||||
// will be wrong.
|
||||
this._measurement.textContent = this.input.value.replace(/ /g, '\u00a0');
|
||||
this._measurement.textContent = this.input.value.replace(/ /g, "\u00a0");
|
||||
|
||||
// We add a bit of padding to the end. Should be enough to fit
|
||||
// any letter that could be typed, otherwise we'll scroll before
|
||||
@ -391,8 +386,7 @@ InplaceEditor.prototype = {
|
||||
* Get the width of a single character in the input to properly position the
|
||||
* autocompletion popup.
|
||||
*/
|
||||
_getInputCharWidth: function InplaceEditor_getInputCharWidth()
|
||||
{
|
||||
_getInputCharWidth: function() {
|
||||
// Just make the text content to be 'x' to get the width of any character in
|
||||
// a monospace font.
|
||||
this._measurement.textContent = "x";
|
||||
@ -402,12 +396,11 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Increment property values in rule view.
|
||||
*
|
||||
* @param {number} increment
|
||||
* @param {Number} increment
|
||||
* The amount to increase/decrease the property value.
|
||||
* @return {bool} true if value has been incremented.
|
||||
* @return {Boolean} true if value has been incremented.
|
||||
*/
|
||||
_incrementValue: function InplaceEditor_incrementValue(increment)
|
||||
{
|
||||
_incrementValue: function(increment) {
|
||||
let value = this.input.value;
|
||||
let selectionStart = this.input.selectionStart;
|
||||
let selectionEnd = this.input.selectionEnd;
|
||||
@ -434,19 +427,17 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Increment the property value based on the property type.
|
||||
*
|
||||
* @param {string} value
|
||||
* @param {String} value
|
||||
* Property value.
|
||||
* @param {number} increment
|
||||
* @param {Number} increment
|
||||
* Amount to increase/decrease the property value.
|
||||
* @param {number} selStart
|
||||
* @param {Number} selStart
|
||||
* Starting index of the value.
|
||||
* @param {number} selEnd
|
||||
* @param {Number} selEnd
|
||||
* Ending index of the value.
|
||||
* @return {object} object with properties 'value', 'start', and 'end'.
|
||||
* @return {Object} object with properties 'value', 'start', and 'end'.
|
||||
*/
|
||||
_incrementCSSValue: function InplaceEditor_incrementCSSValue(value, increment,
|
||||
selStart, selEnd)
|
||||
{
|
||||
_incrementCSSValue: function(value, increment, selStart, selEnd) {
|
||||
let range = this._parseCSSValue(value, selStart);
|
||||
let type = (range && range.type) || "";
|
||||
let rawValue = (range ? value.substring(range.start, range.end) : "");
|
||||
@ -489,11 +480,12 @@ InplaceEditor.prototype = {
|
||||
}
|
||||
}
|
||||
}
|
||||
return this._incrementGenericValue(value, increment, selStart, selEnd, info);
|
||||
return this._incrementGenericValue(value, increment, selStart, selEnd,
|
||||
info);
|
||||
}
|
||||
|
||||
if (incrementedValue === null) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
let preRawValue = value.substr(0, range.start);
|
||||
@ -509,14 +501,14 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Parses the property value and type.
|
||||
*
|
||||
* @param {string} value
|
||||
* @param {String} value
|
||||
* Property value.
|
||||
* @param {number} offset
|
||||
* @param {Number} offset
|
||||
* Starting index of value.
|
||||
* @return {object} object with properties 'value', 'start', 'end', and 'type'.
|
||||
* @return {Object} object with properties 'value', 'start', 'end', and
|
||||
* 'type'.
|
||||
*/
|
||||
_parseCSSValue: function InplaceEditor_parseCSSValue(value, offset)
|
||||
{
|
||||
_parseCSSValue: function(value, offset) {
|
||||
const reSplitCSS = /(url\("?[^"\)]+"?\)?)|(rgba?\([^)]*\)?)|(hsla?\([^)]*\)?)|(#[\dA-Fa-f]+)|(-?\d*\.?\d+(%|[a-z]{1,4})?)|"([^"]*)"?|'([^']*)'?|([^,\s\/!\(\)]+)|(!(.*)?)/;
|
||||
let start = 0;
|
||||
let m;
|
||||
@ -530,7 +522,7 @@ InplaceEditor.prototype = {
|
||||
}
|
||||
|
||||
if (!m) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
let type;
|
||||
@ -558,22 +550,19 @@ InplaceEditor.prototype = {
|
||||
* Increment the property value for types other than
|
||||
* number or hex, such as rgb, hsl, and file names.
|
||||
*
|
||||
* @param {string} value
|
||||
* @param {String} value
|
||||
* Property value.
|
||||
* @param {number} increment
|
||||
* @param {Number} increment
|
||||
* Amount to increment/decrement.
|
||||
* @param {number} offset
|
||||
* @param {Number} offset
|
||||
* Starting index of the property value.
|
||||
* @param {number} offsetEnd
|
||||
* @param {Number} offsetEnd
|
||||
* Ending index of the property value.
|
||||
* @param {object} info
|
||||
* @param {Object} info
|
||||
* Object with details about the property value.
|
||||
* @return {object} object with properties 'value', 'start', and 'end'.
|
||||
* @return {Object} object with properties 'value', 'start', and 'end'.
|
||||
*/
|
||||
_incrementGenericValue:
|
||||
function InplaceEditor_incrementGenericValue(value, increment, offset,
|
||||
offsetEnd, info)
|
||||
{
|
||||
_incrementGenericValue: function(value, increment, offset, offsetEnd, info) {
|
||||
// Try to find a number around the cursor to increment.
|
||||
let start, end;
|
||||
// Check if we are incrementing in a non-number context (such as a URL)
|
||||
@ -585,8 +574,8 @@ InplaceEditor.prototype = {
|
||||
start = offset;
|
||||
end = offsetEnd;
|
||||
} else {
|
||||
// Parse periods as belonging to the number only if we are in a known number
|
||||
// context. (This makes incrementing the 1 in 'image1.gif' work.)
|
||||
// Parse periods as belonging to the number only if we are in a known
|
||||
// number context. (This makes incrementing the 1 in 'image1.gif' work.)
|
||||
let pattern = "[" + (info ? "0-9." : "0-9") + "]*";
|
||||
let before = new RegExp(pattern + "$").exec(value.substr(0, offset))[0].length;
|
||||
let after = new RegExp("^" + pattern).exec(value.substr(offset))[0].length;
|
||||
@ -602,8 +591,7 @@ InplaceEditor.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
if (start !== end)
|
||||
{
|
||||
if (start !== end) {
|
||||
// Include percentages as part of the incremented number (they are
|
||||
// common enough).
|
||||
if (value.charAt(end) === "%") {
|
||||
@ -629,17 +617,15 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Increment the property value for numbers.
|
||||
*
|
||||
* @param {string} rawValue
|
||||
* @param {String} rawValue
|
||||
* Raw value to increment.
|
||||
* @param {number} increment
|
||||
* @param {Number} increment
|
||||
* Amount to increase/decrease the raw value.
|
||||
* @param {object} info
|
||||
* @param {Object} info
|
||||
* Object with info about the property value.
|
||||
* @return {string} the incremented value.
|
||||
* @return {String} the incremented value.
|
||||
*/
|
||||
_incrementRawValue:
|
||||
function InplaceEditor_incrementRawValue(rawValue, increment, info)
|
||||
{
|
||||
_incrementRawValue: function(rawValue, increment, info) {
|
||||
let num = parseFloat(rawValue);
|
||||
|
||||
if (isNaN(num)) {
|
||||
@ -667,25 +653,23 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Increment the property value for hex.
|
||||
*
|
||||
* @param {string} value
|
||||
* @param {String} value
|
||||
* Property value.
|
||||
* @param {number} increment
|
||||
* @param {Number} increment
|
||||
* Amount to increase/decrease the property value.
|
||||
* @param {number} offset
|
||||
* @param {Number} offset
|
||||
* Starting index of the property value.
|
||||
* @param {number} offsetEnd
|
||||
* @param {Number} offsetEnd
|
||||
* Ending index of the property value.
|
||||
* @return {object} object with properties 'value' and 'selection'.
|
||||
* @return {Object} object with properties 'value' and 'selection'.
|
||||
*/
|
||||
_incHexColor:
|
||||
function InplaceEditor_incHexColor(rawValue, increment, offset, offsetEnd)
|
||||
{
|
||||
_incHexColor: function(rawValue, increment, offset, offsetEnd) {
|
||||
// Return early if no part of the rawValue is selected.
|
||||
if (offsetEnd > rawValue.length && offset >= rawValue.length) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
if (offset < 1 && offsetEnd <= 1) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
// Ignore the leading #.
|
||||
rawValue = rawValue.substr(1);
|
||||
@ -707,7 +691,7 @@ InplaceEditor.prototype = {
|
||||
}
|
||||
|
||||
if (rawValue.length !== 6) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
// If no selection, increment an adjacent color, preferably one to the left.
|
||||
@ -724,7 +708,7 @@ InplaceEditor.prototype = {
|
||||
offsetEnd += offsetEnd % 2;
|
||||
|
||||
// Remap the increments from [0.1, 1, 10] to [1, 1, 16].
|
||||
if (-1 < increment && increment < 1) {
|
||||
if (increment > -1 && increment < 1) {
|
||||
increment = (increment < 0 ? -1 : 1);
|
||||
}
|
||||
if (Math.abs(increment) === 10) {
|
||||
@ -739,7 +723,7 @@ InplaceEditor.prototype = {
|
||||
let value = parseInt(mid, 16);
|
||||
|
||||
if (isNaN(value)) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
mid = Math.min(Math.max(value + increment, 0), 255).toString(16);
|
||||
@ -763,43 +747,45 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Cycle through the autocompletion suggestions in the popup.
|
||||
*
|
||||
* @param {boolean} aReverse
|
||||
* @param {Boolean} reverse
|
||||
* true to select previous item from the popup.
|
||||
* @param {boolean} aNoSelect
|
||||
* @param {Boolean} noSelect
|
||||
* true to not select the text after selecting the newly selectedItem
|
||||
* from the popup.
|
||||
*/
|
||||
_cycleCSSSuggestion:
|
||||
function InplaceEditor_cycleCSSSuggestion(aReverse, aNoSelect)
|
||||
{
|
||||
_cycleCSSSuggestion: function(reverse, noSelect) {
|
||||
// selectedItem can be null when nothing is selected in an empty editor.
|
||||
let {label, preLabel} = this.popup.selectedItem || {label: "", preLabel: ""};
|
||||
if (aReverse) {
|
||||
let {label, preLabel} = this.popup.selectedItem ||
|
||||
{label: "", preLabel: ""};
|
||||
if (reverse) {
|
||||
this.popup.selectPreviousItem();
|
||||
} else {
|
||||
this.popup.selectNextItem();
|
||||
}
|
||||
|
||||
this._selectedIndex = this.popup.selectedIndex;
|
||||
let input = this.input;
|
||||
let pre = "";
|
||||
|
||||
if (input.selectionStart < input.selectionEnd) {
|
||||
pre = input.value.slice(0, input.selectionStart);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
pre = input.value.slice(0, input.selectionStart - label.length +
|
||||
preLabel.length);
|
||||
preLabel.length);
|
||||
}
|
||||
|
||||
let post = input.value.slice(input.selectionEnd, input.value.length);
|
||||
let item = this.popup.selectedItem;
|
||||
let toComplete = item.label.slice(item.preLabel.length);
|
||||
input.value = pre + toComplete + post;
|
||||
if (!aNoSelect) {
|
||||
|
||||
if (!noSelect) {
|
||||
input.setSelectionRange(pre.length, pre.length + toComplete.length);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
input.setSelectionRange(pre.length + toComplete.length,
|
||||
pre.length + toComplete.length);
|
||||
}
|
||||
|
||||
this._updateSize();
|
||||
// This emit is mainly for the purpose of making the test flow simpler.
|
||||
this.emit("after-suggest");
|
||||
@ -808,10 +794,9 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Call the client's done handler and clear out.
|
||||
*/
|
||||
_apply: function InplaceEditor_apply(aEvent, direction)
|
||||
{
|
||||
_apply: function(event, direction) {
|
||||
if (this._applied) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
this._applied = true;
|
||||
@ -827,25 +812,26 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Handle loss of focus by calling done if it hasn't been called yet.
|
||||
*/
|
||||
_onBlur: function InplaceEditor_onBlur(aEvent, aDoNotClear)
|
||||
{
|
||||
if (aEvent && this.popup && this.popup.isOpen &&
|
||||
_onBlur: function(event, doNotClear) {
|
||||
if (event && this.popup && this.popup.isOpen &&
|
||||
this.popup.selectedIndex >= 0) {
|
||||
let label, preLabel;
|
||||
|
||||
if (this._selectedIndex === undefined) {
|
||||
({label, preLabel} = this.popup.getItemAtIndex(this.popup.selectedIndex));
|
||||
}
|
||||
else {
|
||||
({label, preLabel} =
|
||||
this.popup.getItemAtIndex(this.popup.selectedIndex));
|
||||
} else {
|
||||
({label, preLabel} = this.popup.getItemAtIndex(this._selectedIndex));
|
||||
}
|
||||
|
||||
let input = this.input;
|
||||
let pre = "";
|
||||
|
||||
if (input.selectionStart < input.selectionEnd) {
|
||||
pre = input.value.slice(0, input.selectionStart);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
pre = input.value.slice(0, input.selectionStart - label.length +
|
||||
preLabel.length);
|
||||
preLabel.length);
|
||||
}
|
||||
let post = input.value.slice(input.selectionEnd, input.value.length);
|
||||
let item = this.popup.selectedItem;
|
||||
@ -873,8 +859,10 @@ InplaceEditor.prototype = {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this._apply();
|
||||
if (!aDoNotClear) {
|
||||
|
||||
if (!doNotClear) {
|
||||
this._clear();
|
||||
}
|
||||
},
|
||||
@ -882,8 +870,7 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Handle the input field's keypress event.
|
||||
*/
|
||||
_onKeyPress: function InplaceEditor_onKeyPress(aEvent)
|
||||
{
|
||||
_onKeyPress: function(event) {
|
||||
let prevent = false;
|
||||
|
||||
const largeIncrement = 100;
|
||||
@ -892,35 +879,35 @@ InplaceEditor.prototype = {
|
||||
|
||||
let increment = 0;
|
||||
|
||||
if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_UP
|
||||
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP) {
|
||||
if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_UP ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP) {
|
||||
increment = 1;
|
||||
} else if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_DOWN
|
||||
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN) {
|
||||
} else if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_DOWN ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN) {
|
||||
increment = -1;
|
||||
}
|
||||
|
||||
if (aEvent.shiftKey && !aEvent.altKey) {
|
||||
if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP
|
||||
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN) {
|
||||
if (event.shiftKey && !event.altKey) {
|
||||
if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN) {
|
||||
increment *= largeIncrement;
|
||||
} else {
|
||||
increment *= mediumIncrement;
|
||||
}
|
||||
} else if (aEvent.altKey && !aEvent.shiftKey) {
|
||||
} else if (event.altKey && !event.shiftKey) {
|
||||
increment *= smallIncrement;
|
||||
}
|
||||
|
||||
// Use default cursor movement rather than providing auto-suggestions.
|
||||
if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_HOME
|
||||
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_END
|
||||
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP
|
||||
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN) {
|
||||
if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_HOME ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_END ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN) {
|
||||
this._preventSuggestions = true;
|
||||
}
|
||||
|
||||
let cycling = false;
|
||||
if (increment && this._incrementValue(increment) ) {
|
||||
if (increment && this._incrementValue(increment)) {
|
||||
this._updateSize();
|
||||
prevent = true;
|
||||
cycling = true;
|
||||
@ -931,30 +918,30 @@ InplaceEditor.prototype = {
|
||||
this._doValidation();
|
||||
}
|
||||
|
||||
if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_BACK_SPACE ||
|
||||
aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_DELETE ||
|
||||
aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_LEFT ||
|
||||
aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RIGHT) {
|
||||
if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_BACK_SPACE ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_DELETE ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_LEFT ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RIGHT) {
|
||||
if (this.popup && this.popup.isOpen) {
|
||||
this.popup.hidePopup();
|
||||
}
|
||||
} else if (!cycling && !aEvent.metaKey && !aEvent.altKey && !aEvent.ctrlKey) {
|
||||
} else if (!cycling && !event.metaKey && !event.altKey && !event.ctrlKey) {
|
||||
this._maybeSuggestCompletion();
|
||||
}
|
||||
|
||||
if (this.multiline &&
|
||||
aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN &&
|
||||
aEvent.shiftKey) {
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN &&
|
||||
event.shiftKey) {
|
||||
prevent = false;
|
||||
} else if (this._advanceChars(aEvent.charCode, this.input.value,
|
||||
this.input.selectionStart)
|
||||
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN
|
||||
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB) {
|
||||
} else if (this._advanceChars(event.charCode, this.input.value,
|
||||
this.input.selectionStart) ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB) {
|
||||
prevent = true;
|
||||
|
||||
let direction = FOCUS_FORWARD;
|
||||
if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB &&
|
||||
aEvent.shiftKey) {
|
||||
if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB &&
|
||||
event.shiftKey) {
|
||||
if (this.stopOnShiftTab) {
|
||||
direction = null;
|
||||
} else {
|
||||
@ -962,9 +949,9 @@ InplaceEditor.prototype = {
|
||||
}
|
||||
}
|
||||
if ((this.stopOnReturn &&
|
||||
aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN) ||
|
||||
(this.stopOnTab && aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB &&
|
||||
!aEvent.shiftKey)) {
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN) ||
|
||||
(this.stopOnTab && event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB &&
|
||||
!event.shiftKey)) {
|
||||
direction = null;
|
||||
}
|
||||
|
||||
@ -979,22 +966,21 @@ InplaceEditor.prototype = {
|
||||
|
||||
let input = this.input;
|
||||
|
||||
if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB &&
|
||||
if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB &&
|
||||
this.contentType == CONTENT_TYPES.CSS_MIXED) {
|
||||
if (this.popup && input.selectionStart < input.selectionEnd) {
|
||||
aEvent.preventDefault();
|
||||
event.preventDefault();
|
||||
input.setSelectionRange(input.selectionEnd, input.selectionEnd);
|
||||
this.emit("after-suggest");
|
||||
return;
|
||||
}
|
||||
else if (this.popup && this.popup.isOpen) {
|
||||
aEvent.preventDefault();
|
||||
this._cycleCSSSuggestion(aEvent.shiftKey, true);
|
||||
} else if (this.popup && this.popup.isOpen) {
|
||||
event.preventDefault();
|
||||
this._cycleCSSSuggestion(event.shiftKey, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this._apply(aEvent, direction);
|
||||
this._apply(event, direction);
|
||||
|
||||
// Close the popup if open
|
||||
if (this.popup && this.popup.isOpen) {
|
||||
@ -1009,14 +995,14 @@ InplaceEditor.prototype = {
|
||||
// If the next node to be focused has been tagged as an editable
|
||||
// node, trigger editing using the configured event
|
||||
if (next && next.ownerDocument === this.doc && next._editable) {
|
||||
let e = this.doc.createEvent('Event');
|
||||
let e = this.doc.createEvent("Event");
|
||||
e.initEvent(next._trigger, true, true);
|
||||
next.dispatchEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
this._clear();
|
||||
} else if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE) {
|
||||
} else if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE) {
|
||||
// Cancel and blur ourselves.
|
||||
// Now we don't want to suggest anything as we are moving out.
|
||||
this._preventSuggestions = true;
|
||||
@ -1028,8 +1014,8 @@ InplaceEditor.prototype = {
|
||||
this.cancelled = true;
|
||||
this._apply();
|
||||
this._clear();
|
||||
aEvent.stopPropagation();
|
||||
} else if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_SPACE) {
|
||||
event.stopPropagation();
|
||||
} else if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_SPACE) {
|
||||
// No need for leading spaces here. This is particularly
|
||||
// noticable when adding a property: it's very natural to type
|
||||
// <name>: (which advances to the next property) then spacebar.
|
||||
@ -1037,22 +1023,21 @@ InplaceEditor.prototype = {
|
||||
}
|
||||
|
||||
if (prevent) {
|
||||
aEvent.preventDefault();
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle the input field's keyup event.
|
||||
*/
|
||||
_onKeyup: function(aEvent) {
|
||||
_onKeyup: function() {
|
||||
this._applied = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle changes to the input text.
|
||||
*/
|
||||
_onInput: function InplaceEditor_onInput(aEvent)
|
||||
{
|
||||
_onInput: function() {
|
||||
// Validate the entered value.
|
||||
this._doValidation();
|
||||
|
||||
@ -1070,8 +1055,7 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Fire validation callback with current input
|
||||
*/
|
||||
_doValidation: function()
|
||||
{
|
||||
_doValidation: function() {
|
||||
if (this.validate && this.input) {
|
||||
this.validate(this.input.value);
|
||||
}
|
||||
@ -1080,10 +1064,10 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Handles displaying suggestions based on the current input.
|
||||
*
|
||||
* @param {boolean} aNoAutoInsert
|
||||
* @param {Boolean} noAutoInsert
|
||||
* true if you don't want to automatically insert the first suggestion
|
||||
*/
|
||||
_maybeSuggestCompletion: function(aNoAutoInsert) {
|
||||
_maybeSuggestCompletion: function(noAutoInsert) {
|
||||
// Input can be null in cases when you intantaneously switch out of it.
|
||||
if (!this.input) {
|
||||
return;
|
||||
@ -1135,7 +1119,8 @@ InplaceEditor.prototype = {
|
||||
}
|
||||
|
||||
list =
|
||||
["!important", ...domUtils.getCSSValuesForProperty(this.property.name)];
|
||||
["!important",
|
||||
...domUtils.getCSSValuesForProperty(this.property.name)];
|
||||
|
||||
if (query == "") {
|
||||
// Do not suggest '!important' without any manually typed character.
|
||||
@ -1150,7 +1135,8 @@ InplaceEditor.prototype = {
|
||||
let propertyName =
|
||||
query.match(/[;"'=]\s*([^"';:= ]+)\s*:\s*[^"';:=]*$/)[1];
|
||||
list =
|
||||
["!important;", ...domUtils.getCSSValuesForProperty(propertyName)];
|
||||
["!important;",
|
||||
...domUtils.getCSSValuesForProperty(propertyName)];
|
||||
let matchLastQuery = /([^\s,.\/]+$)/.exec(match[2] || "");
|
||||
if (matchLastQuery) {
|
||||
startCheckQuery = matchLastQuery[0];
|
||||
@ -1172,7 +1158,7 @@ InplaceEditor.prototype = {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!aNoAutoInsert) {
|
||||
if (!noAutoInsert) {
|
||||
list.some(item => {
|
||||
if (startCheckQuery != null && item.startsWith(startCheckQuery)) {
|
||||
input.value = query + item.slice(startCheckQuery.length) +
|
||||
@ -1199,13 +1185,11 @@ InplaceEditor.prototype = {
|
||||
preLabel: startCheckQuery,
|
||||
label: list[i]
|
||||
});
|
||||
}
|
||||
else if (count > 0) {
|
||||
} else if (count > 0) {
|
||||
// Since count was incremented, we had already crossed the entries
|
||||
// which would have started with query, assuming that list is sorted.
|
||||
break;
|
||||
}
|
||||
else if (startCheckQuery != null && list[i][0] > startCheckQuery[0]) {
|
||||
} else if (startCheckQuery != null && list[i][0] > startCheckQuery[0]) {
|
||||
// We have crossed all possible matches alphabetically.
|
||||
break;
|
||||
}
|
||||
@ -1217,7 +1201,7 @@ InplaceEditor.prototype = {
|
||||
this.inputCharWidth;
|
||||
this.popup.setItems(finalList);
|
||||
this.popup.openPopup(this.input, x);
|
||||
if (aNoAutoInsert) {
|
||||
if (noAutoInsert) {
|
||||
this.popup.selectedIndex = -1;
|
||||
}
|
||||
} else {
|
||||
@ -1233,25 +1217,22 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Copy text-related styles from one element to another.
|
||||
*/
|
||||
function copyTextStyles(aFrom, aTo)
|
||||
{
|
||||
let win = aFrom.ownerDocument.defaultView;
|
||||
let style = win.getComputedStyle(aFrom);
|
||||
aTo.style.fontFamily = style.getPropertyCSSValue("font-family").cssText;
|
||||
aTo.style.fontSize = style.getPropertyCSSValue("font-size").cssText;
|
||||
aTo.style.fontWeight = style.getPropertyCSSValue("font-weight").cssText;
|
||||
aTo.style.fontStyle = style.getPropertyCSSValue("font-style").cssText;
|
||||
function copyTextStyles(from, to) {
|
||||
let win = from.ownerDocument.defaultView;
|
||||
let style = win.getComputedStyle(from);
|
||||
to.style.fontFamily = style.getPropertyCSSValue("font-family").cssText;
|
||||
to.style.fontSize = style.getPropertyCSSValue("font-size").cssText;
|
||||
to.style.fontWeight = style.getPropertyCSSValue("font-weight").cssText;
|
||||
to.style.fontStyle = style.getPropertyCSSValue("font-style").cssText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger a focus change similar to pressing tab/shift-tab.
|
||||
*/
|
||||
function moveFocus(aWin, aDirection)
|
||||
{
|
||||
return focusManager.moveFocus(aWin, null, aDirection, 0);
|
||||
function moveFocus(win, direction) {
|
||||
return focusManager.moveFocus(win, null, direction, 0);
|
||||
}
|
||||
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "focusManager", function() {
|
||||
return Services.focus;
|
||||
});
|
||||
|
@ -33,6 +33,10 @@ function* getVariablesView(hud) {
|
||||
}
|
||||
|
||||
let deferred = promise.defer();
|
||||
|
||||
// Filter out other messages to ensure ours stays visible.
|
||||
hud.ui.filterBox.value = "browser_console_hide_jsterm_test";
|
||||
|
||||
hud.jsterm.clearOutput();
|
||||
hud.jsterm.execute("new Object({ browser_console_hide_jsterm_test: true })");
|
||||
|
||||
|
@ -23,7 +23,8 @@ marker.label.parseHTML=Parse HTML
|
||||
marker.label.parseXML=Parse XML
|
||||
marker.label.domevent=DOM Event
|
||||
marker.label.consoleTime=Console
|
||||
marker.label.garbageCollection=Incremental GC
|
||||
marker.label.garbageCollection2=Garbage Collection
|
||||
marker.label.garbageCollection.incremental=Incremental GC
|
||||
marker.label.garbageCollection.nonIncremental=Non-incremental GC
|
||||
marker.label.cycleCollection=Cycle Collection
|
||||
marker.label.cycleCollection.forgetSkippable=CC Graph Reduction
|
||||
|
@ -92,13 +92,20 @@ category.storage=Storage
|
||||
category.events=Input & Events
|
||||
category.tools=Tools
|
||||
|
||||
# LOCALIZATION NOTE (table.ms):
|
||||
# This string is displayed in the call tree after units of time in milliseconds.
|
||||
table.ms=ms
|
||||
# LOCALIZATION NOTE (table.bytes):
|
||||
# This string is displayed in the call tree after bytesize units.
|
||||
# %S represents the value in bytes.
|
||||
table.bytes=%S B
|
||||
|
||||
# LOCALIZATION NOTE (table.percentage):
|
||||
# LOCALIZATION NOTE (table.ms2):
|
||||
# This string is displayed in the call tree after units of time in milliseconds.
|
||||
# %S represents the value in milliseconds.
|
||||
table.ms2=%S ms
|
||||
|
||||
# LOCALIZATION NOTE (table.percentage2):
|
||||
# This string is displayed in the call tree after units representing percentages.
|
||||
table.percentage=%
|
||||
# %S represents the value in percentage with two decimal points, localized.
|
||||
table.percentage2=%S%
|
||||
|
||||
# LOCALIZATION NOTE (table.root):
|
||||
# This string is displayed in the call tree for the root node.
|
||||
@ -113,10 +120,10 @@ table.idle=(idle)
|
||||
# labels which, when clicked, jump to the debugger.
|
||||
table.url.tooltiptext=View source in Debugger
|
||||
|
||||
# LOCALIZATION NOTE (table.view-optimizations.tooltiptext):
|
||||
# LOCALIZATION NOTE (table.view-optimizations.tooltiptext2):
|
||||
# This string is displayed in the icon displayed next to frames that
|
||||
# have optimization data
|
||||
table.view-optimizations.tooltiptext=View optimizations in JIT View
|
||||
table.view-optimizations.tooltiptext2=Frame contains JIT optimization data
|
||||
|
||||
# LOCALIZATION NOTE (recordingsList.importDialogTitle):
|
||||
# This string is displayed as a title for importing a recoring from disk.
|
||||
@ -165,4 +172,4 @@ timeline.records=RECORDS
|
||||
# %S is the percentage of the buffer used -- there are two "%"s after to escape
|
||||
# the % that is actually displayed.
|
||||
# Example: "Buffer 54% full"
|
||||
profiler.bufferFull=Buffer %S%% full
|
||||
profiler.bufferFull=Buffer %S%% full
|
||||
|
@ -17,6 +17,7 @@ sourceName360se=360 Secure Browser
|
||||
importedBookmarksFolder=From %S
|
||||
|
||||
importedSafariReadingList=Reading List (From Safari)
|
||||
importedEdgeReadingList=Reading List (From Edge)
|
||||
|
||||
# Import Sources
|
||||
# Note: When adding an import source for profile reset, add the string name to
|
||||
|
@ -234,8 +234,20 @@
|
||||
.call-tree-header[type="count"],
|
||||
.call-tree-cell[type="count"],
|
||||
.call-tree-header[type="self-count"],
|
||||
.call-tree-cell[type="self-count"] {
|
||||
width: 9vw;
|
||||
.call-tree-cell[type="self-count"],
|
||||
.call-tree-header[type="size"],
|
||||
.call-tree-cell[type="size"],
|
||||
.call-tree-header[type="self-size"],
|
||||
.call-tree-cell[type="self-size"],
|
||||
.call-tree-header[type="count-percentage"],
|
||||
.call-tree-cell[type="count-percentage"],
|
||||
.call-tree-header[type="self-count-percentage"],
|
||||
.call-tree-cell[type="self-count-percentage"],
|
||||
.call-tree-header[type="size-percentage"],
|
||||
.call-tree-cell[type="size-percentage"],
|
||||
.call-tree-header[type="self-size-percentage"],
|
||||
.call-tree-cell[type="self-size-percentage"] {
|
||||
width: 6vw;
|
||||
}
|
||||
|
||||
.call-tree-header[type="function"],
|
||||
@ -685,9 +697,6 @@ description.opt-icon::before {
|
||||
.opt-icon[severity=warning]::before {
|
||||
background-position: -24px -24px;
|
||||
}
|
||||
.opt-icon[type=linkable]::before {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
ul.frames-list {
|
||||
list-style-type: none;
|
||||
|
@ -18,11 +18,16 @@ XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["Langpacks"];
|
||||
|
||||
let debug = Services.prefs.getBoolPref("dom.mozApps.debug")
|
||||
? (aMsg) => {
|
||||
dump("-*-*- Langpacks: " + aMsg + "\n");
|
||||
}
|
||||
: (aMsg) => {};
|
||||
let debug;
|
||||
function debugPrefObserver() {
|
||||
debug = Services.prefs.getBoolPref("dom.mozApps.debug")
|
||||
? (aMsg) => {
|
||||
dump("-*-*- Langpacks: " + aMsg + "\n");
|
||||
}
|
||||
: (aMsg) => {};
|
||||
}
|
||||
debugPrefObserver();
|
||||
Services.prefs.addObserver("dom.mozApps.debug", debugPrefObserver, false);
|
||||
|
||||
/**
|
||||
* Langpack support
|
||||
|
@ -107,10 +107,14 @@ let debug = Cu.import("resource://gre/modules/AndroidLog.jsm", {})
|
||||
.AndroidLog.d.bind(null, "Webapps");
|
||||
#else
|
||||
// Elsewhere, report debug messages only if dom.mozApps.debug is set to true.
|
||||
// The pref is only checked once, on startup, so restart after changing it.
|
||||
let debug = Services.prefs.getBoolPref("dom.mozApps.debug")
|
||||
? (aMsg) => dump("-*- Webapps.jsm : " + aMsg + "\n")
|
||||
: (aMsg) => {};
|
||||
let debug;
|
||||
function debugPrefObserver() {
|
||||
debug = Services.prefs.getBoolPref("dom.mozApps.debug")
|
||||
? (aMsg) => dump("-*- Webapps.jsm : " + aMsg + "\n")
|
||||
: (aMsg) => {};
|
||||
}
|
||||
debugPrefObserver();
|
||||
Services.prefs.addObserver("dom.mozApps.debug", debugPrefObserver, false);
|
||||
#endif
|
||||
|
||||
function getNSPRErrorCode(err) {
|
||||
|
@ -2,6 +2,7 @@
|
||||
skip-if = buildapp == 'b2g' || os == 'android'
|
||||
support-files =
|
||||
asmjs/*
|
||||
common.js
|
||||
file_bug_945152.html
|
||||
file_bug_945152.sjs
|
||||
|
||||
|
3
dom/apps/tests/common.js
Normal file
3
dom/apps/tests/common.js
Normal file
@ -0,0 +1,3 @@
|
||||
function prepareEnv(cb) {
|
||||
SpecialPowers.pushPrefEnv({"set":[["dom.mozApps.debug", true]]}, cb);
|
||||
}
|
@ -8,6 +8,7 @@ support-files =
|
||||
addons/update.webapp^headers^
|
||||
addons/index.html
|
||||
chromeAddCert.js
|
||||
common.js
|
||||
file_app.sjs
|
||||
file_app.template.html
|
||||
file_script.template.js
|
||||
|
@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1042881
|
||||
<title>Test for Bug 923897 - Test apps as addons</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="application/javascript;version=1.7">
|
||||
/**
|
||||
@ -203,7 +204,7 @@ function runTest() {
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="go()">
|
||||
<body onload="prepareEnv(go)">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
|
@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={1XXXXXX}
|
||||
<title>Test for Bug {1072090}</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
@ -121,7 +122,7 @@ function runTest() {
|
||||
is(request.result.length, initialAppsCount, "All apps are uninstalled.");
|
||||
}
|
||||
|
||||
addLoadEvent(go);
|
||||
addLoadEvent(() => prepareEnv(go));
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=826058
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 826058</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
@ -278,7 +279,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=826058
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="go()">
|
||||
<body onload="prepareEnv(go)">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=826058">Mozilla Bug 826058</a>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=863337">Mozilla Bug 863337</a>
|
||||
<p id="display"></p>
|
||||
|
@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1168300
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1168300</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
@ -111,7 +112,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1168300
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
</head>
|
||||
<body onload="go()">
|
||||
<body onload="prepareEnv(go)">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1168300">Mozilla Bug 1168300</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=795164
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 795164</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
@ -96,7 +97,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=795164
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="go()">
|
||||
<body onload="prepareEnv(go)">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=795164">Mozilla Bug 795164</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=945152
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 945152</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
@ -162,7 +163,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=945152
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="go()">
|
||||
<body onload="prepareEnv(go)">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=945152">Mozilla Bug 945152</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={1191516}
|
||||
<title>Test for Bug {1191516}</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
@ -92,7 +93,7 @@ function runTest() {
|
||||
yield undefined;
|
||||
}
|
||||
|
||||
addLoadEvent(go);
|
||||
addLoadEvent(() => prepareEnv(go));
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={982874}
|
||||
<title>Test for Bug {982874}</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="common.js"></script>
|
||||
<script type="text/javascript" src="test_packaged_app_common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
@ -322,7 +323,7 @@ function runTest() {
|
||||
is(request.result.length, initialAppsCount, "All apps are uninstalled.");
|
||||
}
|
||||
|
||||
addLoadEvent(go);
|
||||
addLoadEvent(() => prepareEnv(go));
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={1111961}
|
||||
<title>Test for Bug {1111961}</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
@ -114,7 +115,7 @@ function runTest() {
|
||||
is(request.result.length, initialAppsCount, "All apps are uninstalled.");
|
||||
}
|
||||
|
||||
addLoadEvent(go);
|
||||
addLoadEvent(() => prepareEnv(go));
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={778277}
|
||||
<title>Test for Bug {778277}</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
@ -116,7 +117,7 @@ function runTest() {
|
||||
is(request.result.length, initialAppsCount, "All apps are uninstalled.");
|
||||
}
|
||||
|
||||
addLoadEvent(go);
|
||||
addLoadEvent(() => prepareEnv(go));
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={960837}
|
||||
<title>Test for Bug {960837}</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
@ -206,7 +207,7 @@ function runTest() {
|
||||
yield undefined;
|
||||
}
|
||||
|
||||
addLoadEvent(go);
|
||||
addLoadEvent(() => prepareEnv(go));
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1108096
|
||||
<title>Test for Bug 1108096 - Langpack support</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="application/javascript;version=1.7">
|
||||
/**
|
||||
@ -305,7 +306,7 @@ function runTest() {
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="go()">
|
||||
<body onload="prepareEnv(go)">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
|
@ -9,6 +9,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=989806
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="test_packaged_app_common.js"></script>
|
||||
<script type="text/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
@ -341,7 +342,7 @@ PackagedTestHelper.setSteps([
|
||||
}
|
||||
]);
|
||||
|
||||
addLoadEvent(PackagedTestHelper.start);
|
||||
addLoadEvent(() => prepareEnv(() => PackagedTestHelper.start()));
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -212,6 +212,9 @@ function checkAppState(aApp,
|
||||
}
|
||||
|
||||
var steps = [
|
||||
function() {
|
||||
prepareEnv(next);
|
||||
},
|
||||
function() {
|
||||
setupDataDirs(next);
|
||||
ok(true, "Data directory set up to " + singlevariantDir);
|
||||
|
@ -8,6 +8,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=893800
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="common.js"/>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
|
@ -10,6 +10,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=997886
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
@ -229,7 +230,7 @@ function runTest() {
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="go()">
|
||||
<body onload="prepareEnv(go)">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
|
@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={821589}
|
||||
<title>Test for Bug {821589} Packaged apps installation and update</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="common.js"></script>
|
||||
<script type="text/javascript" src="test_packaged_app_common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
@ -347,7 +348,7 @@ var steps = [
|
||||
|
||||
PackagedTestHelper.setSteps(steps);
|
||||
|
||||
addLoadEvent(PackagedTestHelper.start);
|
||||
addLoadEvent(() => prepareEnv(() => PackagedTestHelper.start()));
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={900533}
|
||||
<title>Test for Bug {900533} Packaged app update tests</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="common.js"></script>
|
||||
<script type="text/javascript" src="test_packaged_app_common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
@ -346,7 +347,7 @@ PackagedTestHelper.setSteps(steps);
|
||||
// install tests
|
||||
miniManifestURL = PackagedTestHelper.gSJS + "?getManifest=true&appToUpdate&testNameChange";
|
||||
|
||||
addLoadEvent(PackagedTestHelper.start);
|
||||
addLoadEvent(() => prepareEnv(() => PackagedTestHelper.start()));
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={757226}
|
||||
<title>Test for Bug {757226} Implement mozApps app.replaceReceipt</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
@ -231,7 +232,7 @@ function runTest() {
|
||||
ok(true, "App uninstalled");
|
||||
}
|
||||
|
||||
addLoadEvent(go);
|
||||
addLoadEvent(() => prepareEnv(go));
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -8,6 +8,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=880043
|
||||
<title>Test for Bug 880043 Packaged apps installation and update</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="common.js"></script>
|
||||
<script type="text/javascript" src="test_packaged_app_common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
@ -269,7 +270,7 @@ var steps = [
|
||||
PackagedTestHelper.setSteps(steps);
|
||||
PackagedTestHelper.gSJSPath = gSJSPath;
|
||||
|
||||
addLoadEvent(PackagedTestHelper.start);
|
||||
addLoadEvent(() => prepareEnv(() => PackagedTestHelper.start()));
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={1011738}
|
||||
<title>Test for Bug {1011738}</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="common.js"></script>
|
||||
<script type="text/javascript" src="test_packaged_app_common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
@ -102,7 +103,7 @@ function runTest() {
|
||||
yield undefined;
|
||||
}
|
||||
|
||||
addLoadEvent(go);
|
||||
addLoadEvent(() => prepareEnv(go));
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={1097468}
|
||||
<title>Test for Bug {1097468}</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
@ -192,7 +193,7 @@ function runTest() {
|
||||
navigator.mozApps.mgmt.onuninstall = null;
|
||||
}
|
||||
|
||||
addLoadEvent(go);
|
||||
addLoadEvent(() => prepareEnv(go));
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -8,6 +8,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=830258
|
||||
<title>Test for Bug 830258</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="text/javascript" src="common.js"></script>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
/** Test for Bug 830258 **/
|
||||
@ -96,7 +97,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=830258
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="go()">
|
||||
<body onload="prepareEnv(go)">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=830258">Mozilla Bug 830258</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={1075716}
|
||||
<title>Install web app from manifest with application/manifest+json MIME type</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
@ -165,7 +166,7 @@ function runTest() {
|
||||
is(request.result.length, initialAppsCount, "Correct number of apps.");
|
||||
}
|
||||
|
||||
addLoadEvent(go);
|
||||
addLoadEvent(() => prepareEnv(go));
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -5,6 +5,7 @@
|
||||
<title>Test for Widget</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="file_test_widget.js"></script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
@ -12,7 +13,7 @@
|
||||
<script type="application/javascript;version=1.7">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
gHasBrowserPermission = false;
|
||||
runTest();
|
||||
prepareEnv(runTest);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -5,6 +5,7 @@
|
||||
<title>Test for DataStore - basic operation on a readonly db</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="file_test_widget.js"></script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
@ -12,7 +13,7 @@
|
||||
<script type="application/javascript;version=1.7">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
gHasBrowserPermission = true;
|
||||
runTest();
|
||||
prepareEnv(runTest);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
4
dom/apps/tests/unit/head.js
Normal file
4
dom/apps/tests/unit/head.js
Normal file
@ -0,0 +1,4 @@
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
Cu.import("resource:///modules/Services.jsm");
|
||||
var dom_mozApps_debug = Services.prefs.getBoolPref("dom.mozApps.debug");
|
||||
Services.prefs.setBoolPref("dom.mozApps.debug", true);
|
1
dom/apps/tests/unit/tail.js
Normal file
1
dom/apps/tests/unit/tail.js
Normal file
@ -0,0 +1 @@
|
||||
Services.prefs.setBoolPref("dom.mozApps.debug", dom_mozApps_debug);
|
@ -1,10 +1,7 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource:///modules/AppsUtils.jsm");
|
||||
Cu.import("resource:///modules/Services.jsm");
|
||||
|
||||
add_test(function test_has_widget_criterion() {
|
||||
|
||||
|
@ -1,9 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/InterAppCommService.jsm");
|
||||
Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const {interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource:///modules/AppsUtils.jsm");
|
||||
|
||||
add_test(() => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
[DEFAULT]
|
||||
head =
|
||||
tail =
|
||||
head = head.js
|
||||
tail = tail.js
|
||||
|
||||
[test_has_widget_criterion.js]
|
||||
[test_inter_app_comm_service.js]
|
||||
|
@ -271,8 +271,6 @@ user_pref("browser.translation.engine", "bing");
|
||||
// Make sure we don't try to load snippets from the network.
|
||||
user_pref("browser.aboutHomeSnippets.updateUrl", "nonexistent://test");
|
||||
|
||||
// Enable debug logging in the mozApps implementation.
|
||||
user_pref("dom.mozApps.debug", true);
|
||||
// Enable apps customizations
|
||||
user_pref("dom.apps.customization.enabled", true);
|
||||
|
||||
|
@ -66,6 +66,13 @@ const standardParams = {
|
||||
description: l10n.lookup("screenshotDelayDesc"),
|
||||
manual: l10n.lookup("screenshotDelayManual")
|
||||
},
|
||||
{
|
||||
name: "dpi",
|
||||
type: { name: "number", min: 0, allowFloat: true },
|
||||
defaultValue: 0,
|
||||
description: l10n.lookup("screenshotDPIDesc"),
|
||||
manual: l10n.lookup("screenshotDPIManual")
|
||||
},
|
||||
{
|
||||
name: "fullpage",
|
||||
type: "boolean",
|
||||
@ -287,7 +294,7 @@ function createScreenshotData(document, args) {
|
||||
|
||||
const canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
const ratio = window.devicePixelRatio;
|
||||
const ratio = args.dpi ? args.dpi : window.devicePixelRatio;
|
||||
canvas.width = width * ratio;
|
||||
canvas.height = height * ratio;
|
||||
ctx.scale(ratio, ratio);
|
||||
|
@ -211,7 +211,12 @@ const PerformanceFront = exports.PerformanceFront = protocol.FrontClass(Performa
|
||||
|
||||
let normalizedCurrent = (totalSize * (currentGeneration - origGeneration)) + currentPosition;
|
||||
let percent = (normalizedCurrent - origPosition) / totalSize;
|
||||
return percent > 1 ? 1 : percent;
|
||||
|
||||
// Clamp between 0 and 1; can get negative percentage values when a new
|
||||
// recording starts and the currentBufferStatus has not yet been updated. Rather
|
||||
// than fetching another status update, just clamp to 0, and this will be updated
|
||||
// on the next profiler-status event.
|
||||
return percent > 1 ? 1 : percent < 0 ? 0 : percent;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1555,3 +1555,104 @@ function getFontPreviewData(font, doc, options) {
|
||||
}
|
||||
|
||||
exports.getFontPreviewData = getFontPreviewData;
|
||||
|
||||
/**
|
||||
* Get the text content of a rule given some CSS text, a line and a column
|
||||
* Consider the following example:
|
||||
* body {
|
||||
* color: red;
|
||||
* }
|
||||
* p {
|
||||
* line-height: 2em;
|
||||
* color: blue;
|
||||
* }
|
||||
* Calling the function with the whole text above and line=4 and column=1 would
|
||||
* return "line-height: 2em; color: blue;"
|
||||
* @param {String} initialText
|
||||
* @param {Number} line (1-indexed)
|
||||
* @param {Number} column (1-indexed)
|
||||
* @return {object} An object of the form {offset: number, text: string}
|
||||
* The offset is the index into the input string where
|
||||
* the rule text started. The text is the content of
|
||||
* the rule.
|
||||
*/
|
||||
function getRuleText(initialText, line, column) {
|
||||
if (typeof line === "undefined" || typeof column === "undefined") {
|
||||
throw new Error("Location information is missing");
|
||||
}
|
||||
|
||||
let {offset: textOffset, text} =
|
||||
getTextAtLineColumn(initialText, line, column);
|
||||
let lexer = DOMUtils.getCSSLexer(text);
|
||||
|
||||
// Search forward for the opening brace.
|
||||
while (true) {
|
||||
let token = lexer.nextToken();
|
||||
if (!token) {
|
||||
throw new Error("couldn't find start of the rule");
|
||||
}
|
||||
if (token.tokenType === "symbol" && token.text === "{") {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Now collect text until we see the matching close brace.
|
||||
let braceDepth = 1;
|
||||
let startOffset, endOffset;
|
||||
while (true) {
|
||||
let token = lexer.nextToken();
|
||||
if (!token) {
|
||||
break;
|
||||
}
|
||||
if (startOffset === undefined) {
|
||||
startOffset = token.startOffset;
|
||||
}
|
||||
if (token.tokenType === "symbol") {
|
||||
if (token.text === "{") {
|
||||
++braceDepth;
|
||||
} else if (token.text === "}") {
|
||||
--braceDepth;
|
||||
if (braceDepth == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
endOffset = token.endOffset;
|
||||
}
|
||||
|
||||
// If the rule was of the form "selector {" with no closing brace
|
||||
// and no properties, just return an empty string.
|
||||
if (startOffset === undefined) {
|
||||
return {offset: 0, text: ""};
|
||||
}
|
||||
// Note that this approach will preserve comments, despite the fact
|
||||
// that cssTokenizer skips them.
|
||||
return {offset: textOffset + startOffset,
|
||||
text: text.substring(startOffset, endOffset)};
|
||||
}
|
||||
|
||||
exports.getRuleText = getRuleText;
|
||||
|
||||
/**
|
||||
* Return the offset and substring of |text| that starts at the given
|
||||
* line and column.
|
||||
* @param {String} text
|
||||
* @param {Number} line (1-indexed)
|
||||
* @param {Number} column (1-indexed)
|
||||
* @return {object} An object of the form {offset: number, text: string},
|
||||
* where the offset is the offset into the input string
|
||||
* where the text starts, and where text is the text.
|
||||
*/
|
||||
function getTextAtLineColumn(text, line, column) {
|
||||
let offset;
|
||||
if (line > 1) {
|
||||
let rx = new RegExp("(?:.*(?:\\r\\n|\\n|\\r|\\f)){" + (line - 1) + "}");
|
||||
offset = rx.exec(text)[0].length;
|
||||
} else {
|
||||
offset = 0;
|
||||
}
|
||||
offset += column - 1;
|
||||
return {offset: offset, text: text.substr(offset) };
|
||||
}
|
||||
|
||||
exports.getTextAtLineColumn = getTextAtLineColumn;
|
||||
|
130
toolkit/devtools/server/tests/unit/test_getRuleText.js
Normal file
130
toolkit/devtools/server/tests/unit/test_getRuleText.js
Normal file
@ -0,0 +1,130 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {getRuleText} = devtools.require("devtools/server/actors/styles");
|
||||
|
||||
const TEST_DATA = [
|
||||
{
|
||||
desc: "Empty input",
|
||||
input: "",
|
||||
line: 1,
|
||||
column: 1,
|
||||
throws: true
|
||||
},
|
||||
{
|
||||
desc: "Simplest test case",
|
||||
input: "#id{color:red;background:yellow;}",
|
||||
line: 1,
|
||||
column: 1,
|
||||
expected: {offset: 4, text: "color:red;background:yellow;"}
|
||||
},
|
||||
{
|
||||
desc: "Multiple rules test case",
|
||||
input: "#id{color:red;background:yellow;}.class-one .class-two { position:absolute; line-height: 45px}",
|
||||
line: 1,
|
||||
column: 34,
|
||||
expected: {offset: 56, text: " position:absolute; line-height: 45px"}
|
||||
},
|
||||
{
|
||||
desc: "Unclosed rule",
|
||||
input: "#id{color:red;background:yellow;",
|
||||
line: 1,
|
||||
column: 1,
|
||||
expected: {offset: 4, text: "color:red;background:yellow;"}
|
||||
},
|
||||
{
|
||||
desc: "Null input",
|
||||
input: null,
|
||||
line: 1,
|
||||
column: 1,
|
||||
throws: true
|
||||
},
|
||||
{
|
||||
desc: "Missing loc",
|
||||
input: "#id{color:red;background:yellow;}",
|
||||
throws: true
|
||||
},
|
||||
{
|
||||
desc: "Multi-lines CSS",
|
||||
input: [
|
||||
"/* this is a multi line css */",
|
||||
"body {",
|
||||
" color: green;",
|
||||
" background-repeat: no-repeat",
|
||||
"}",
|
||||
" /*something else here */",
|
||||
"* {",
|
||||
" color: purple;",
|
||||
"}"
|
||||
].join("\n"),
|
||||
line: 7,
|
||||
column: 1,
|
||||
expected: {offset: 116, text: "\n color: purple;\n"}
|
||||
},
|
||||
{
|
||||
desc: "Multi-lines CSS and multi-line rule",
|
||||
input: [
|
||||
"/* ",
|
||||
"* some comments",
|
||||
"*/",
|
||||
"",
|
||||
"body {",
|
||||
" margin: 0;",
|
||||
" padding: 15px 15px 2px 15px;",
|
||||
" color: red;",
|
||||
"}",
|
||||
"",
|
||||
"#header .btn, #header .txt {",
|
||||
" font-size: 100%;",
|
||||
"}",
|
||||
"",
|
||||
"#header #information {",
|
||||
" color: #dddddd;",
|
||||
" font-size: small;",
|
||||
"}",
|
||||
].join("\n"),
|
||||
line: 5,
|
||||
column: 1,
|
||||
expected: {
|
||||
offset: 30,
|
||||
text: "\n margin: 0;\n padding: 15px 15px 2px 15px;\n color: red;\n"}
|
||||
},
|
||||
{
|
||||
desc: "Content string containing a } character",
|
||||
input: " #id{border:1px solid red;content: '}';color:red;}",
|
||||
line: 1,
|
||||
column: 4,
|
||||
expected: {offset: 7, text: "border:1px solid red;content: '}';color:red;"}
|
||||
},
|
||||
];
|
||||
|
||||
function run_test() {
|
||||
for (let test of TEST_DATA) {
|
||||
do_print("Starting test: " + test.desc);
|
||||
do_print("Input string " + test.input);
|
||||
let output;
|
||||
try {
|
||||
output = getRuleText(test.input, test.line, test.column);
|
||||
if (test.throws) {
|
||||
do_print("Test should have thrown");
|
||||
do_check_true(false);
|
||||
}
|
||||
} catch (e) {
|
||||
do_print("getRuleText threw an exception with the given input string");
|
||||
if (test.throws) {
|
||||
do_print("Exception expected");
|
||||
do_check_true(true);
|
||||
} else {
|
||||
do_print("Exception unexpected\n" + e);
|
||||
do_check_true(false);
|
||||
}
|
||||
}
|
||||
if (output) {
|
||||
deepEqual(output, test.expected);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {getTextAtLineColumn} = devtools.require("devtools/server/actors/styles");
|
||||
|
||||
const TEST_DATA = [
|
||||
{
|
||||
desc: "simplest",
|
||||
input: "#id{color:red;background:yellow;}",
|
||||
line: 1,
|
||||
column: 5,
|
||||
expected: {offset: 4, text: "color:red;background:yellow;}"}
|
||||
},
|
||||
{
|
||||
desc: "multiple lines",
|
||||
input: "one\n two\n three",
|
||||
line: 3,
|
||||
column: 3,
|
||||
expected: {offset: 11, text: "three"}
|
||||
},
|
||||
];
|
||||
|
||||
function run_test() {
|
||||
for (let test of TEST_DATA) {
|
||||
do_print("Starting test: " + test.desc);
|
||||
do_print("Input string " + test.input);
|
||||
|
||||
let output = getTextAtLineColumn(test.input, test.line, test.column);
|
||||
deepEqual(output, test.expected);
|
||||
}
|
||||
}
|
@ -78,6 +78,8 @@ skip-if = os == 'linux' # Bug 1176173
|
||||
[test_frameactor-04.js]
|
||||
[test_frameactor-05.js]
|
||||
[test_framearguments-01.js]
|
||||
[test_getRuleText.js]
|
||||
[test_getTextAtLineColumn.js]
|
||||
[test_pauselifetime-01.js]
|
||||
[test_pauselifetime-02.js]
|
||||
[test_pauselifetime-03.js]
|
||||
|
@ -96,6 +96,16 @@ screenshotDelayDesc=Delay (seconds)
|
||||
# asks for help on what it does.
|
||||
screenshotDelayManual=The time to wait (in seconds) before the screenshot is taken
|
||||
|
||||
# LOCALIZATION NOTE (screenshotDPIDesc) A very short string to describe
|
||||
# the 'dpi' parameter to the 'screenshot' command, which is displayed in
|
||||
# a dialog when the user is using this command.
|
||||
screenshotDPIDesc=Dots per inch
|
||||
|
||||
# LOCALIZATION NOTE (screenshotDPIManual) A fuller description of the
|
||||
# 'dpi' parameter to the 'screenshot' command, displayed when the user
|
||||
# asks for help on what it does.
|
||||
screenshotDPIManual=The number of dots per inch in the screenshot
|
||||
|
||||
# LOCALIZATION NOTE (screenshotFullscreenDesc) A very short string to describe
|
||||
# the 'fullscreen' parameter to the 'screenshot' command, which is displayed in
|
||||
# a dialog when the user is using this command.
|
||||
|
@ -4,6 +4,9 @@
|
||||
# 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/.
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('Firefox', 'Web Apps')
|
||||
|
||||
EXTRA_PP_JS_MODULES += [
|
||||
'NativeApp.jsm',
|
||||
'WebappOSUtils.jsm',
|
||||
|
@ -586,3 +586,7 @@ AlertsService.init();
|
||||
SimpleTest.registerCleanupFunction(() => {
|
||||
AlertsService.restore();
|
||||
});
|
||||
|
||||
function prepareEnv(cb) {
|
||||
SpecialPowers.pushPrefEnv({"set":[["dom.mozApps.debug", true]]}, cb);
|
||||
}
|
||||
|
@ -125,10 +125,10 @@ let runTest = Task.async(function*() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
runTest().catch((e) => {
|
||||
prepareEnv(() => runTest().catch((e) => {
|
||||
ok(false, "Error during test: " + e);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}));
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
@ -161,10 +161,10 @@ let runTest = Task.async(function*() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
runTest().catch((e) => {
|
||||
prepareEnv(() => runTest().catch((e) => {
|
||||
ok(false, "Error during test: " + e);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}));
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
@ -147,10 +147,10 @@ let runTest = Task.async(function*() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
runTest().catch((e) => {
|
||||
prepareEnv(() => runTest().catch((e) => {
|
||||
ok(false, "Error during test: " + e);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}));
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
@ -106,10 +106,10 @@ let runTest = Task.async(function*() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
runTest().catch((e) => {
|
||||
prepareEnv(() => runTest().catch((e) => {
|
||||
ok(false, "Error during test: " + e);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}));
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
@ -147,10 +147,10 @@ let runTest = Task.async(function*() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
runTest().catch((e) => {
|
||||
prepareEnv(() => runTest().catch((e) => {
|
||||
ok(false, "Error during test: " + e);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}));
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
@ -93,10 +93,10 @@ let runTest = Task.async(function*() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
runTest().catch((e) => {
|
||||
prepareEnv(() => runTest().catch((e) => {
|
||||
ok(false, "Error during test: " + e);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}));
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
@ -93,10 +93,10 @@ let runTest = Task.async(function*() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
runTest().catch((e) => {
|
||||
prepareEnv(() => runTest().catch((e) => {
|
||||
ok(false, "Error during test: " + e);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}));
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
@ -135,10 +135,10 @@ let runTest = Task.async(function*() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
runTest().catch((e) => {
|
||||
prepareEnv(() => runTest().catch((e) => {
|
||||
ok(false, "Error during test: " + e);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}));
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
@ -110,10 +110,10 @@ let runTest = Task.async(function*() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
runTest().catch((e) => {
|
||||
prepareEnv(() => runTest().catch((e) => {
|
||||
ok(false, "Error during test: " + e);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}));
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
@ -116,10 +116,10 @@ let runTest = Task.async(function*() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
runTest().catch((e) => {
|
||||
prepareEnv(() => runTest().catch((e) => {
|
||||
ok(false, "Error during test: " + e);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}));
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
@ -148,10 +148,10 @@ let runTest = Task.async(function*() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
runTest().catch((e) => {
|
||||
prepareEnv(() => runTest().catch((e) => {
|
||||
ok(false, "Error during test: " + e);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}));
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
@ -164,10 +164,10 @@ let runTest = Task.async(function*() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
runTest().catch((e) => {
|
||||
prepareEnv(() => runTest().catch((e) => {
|
||||
ok(false, "Error during test: " + e);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}));
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user