mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
Merge from mozilla-central.
This commit is contained in:
commit
d1f7c1b50b
@ -690,14 +690,15 @@ ApplicationAccessibleWrap::Unload()
|
||||
// }
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ApplicationAccessibleWrap::GetName(nsAString& aName)
|
||||
ENameValueFlag
|
||||
ApplicationAccessibleWrap::Name(nsString& aName)
|
||||
{
|
||||
// ATK doesn't provide a way to obtain an application name (for example,
|
||||
// Firefox or Thunderbird) like IA2 does. Thus let's return an application
|
||||
// name as accessible name that was used to get a branding name (for example,
|
||||
// Minefield aka nightly Firefox or Daily aka nightly Thunderbird).
|
||||
return GetAppName(aName);
|
||||
GetAppName(aName);
|
||||
return eNameOK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -57,8 +57,7 @@ public:
|
||||
virtual bool Init();
|
||||
|
||||
// nsAccessible
|
||||
NS_IMETHOD GetName(nsAString &aName);
|
||||
|
||||
virtual mozilla::a11y::ENameValueFlag Name(nsString& aName);
|
||||
virtual bool AppendChild(nsAccessible* aChild);
|
||||
virtual bool RemoveChild(nsAccessible* aChild);
|
||||
|
||||
|
@ -678,25 +678,21 @@ finalizeCB(GObject *aObj)
|
||||
G_OBJECT_CLASS (parent_class)->finalize(aObj);
|
||||
}
|
||||
|
||||
const gchar *
|
||||
getNameCB(AtkObject *aAtkObj)
|
||||
const gchar*
|
||||
getNameCB(AtkObject* aAtkObj)
|
||||
{
|
||||
nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
|
||||
if (!accWrap) {
|
||||
return nsnull;
|
||||
}
|
||||
nsAccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
|
||||
if (!accWrap)
|
||||
return nsnull;
|
||||
|
||||
/* nsIAccessible is responsible for the non-NULL name */
|
||||
nsAutoString uniName;
|
||||
nsresult rv = accWrap->GetName(uniName);
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
nsAutoString uniName;
|
||||
accWrap->Name(uniName);
|
||||
|
||||
NS_ConvertUTF8toUTF16 objName(aAtkObj->name);
|
||||
if (!uniName.Equals(objName)) {
|
||||
atk_object_set_name(aAtkObj,
|
||||
NS_ConvertUTF16toUTF8(uniName).get());
|
||||
}
|
||||
return aAtkObj->name;
|
||||
NS_ConvertUTF8toUTF16 objName(aAtkObj->name);
|
||||
if (!uniName.Equals(objName))
|
||||
atk_object_set_name(aAtkObj, NS_ConvertUTF16toUTF8(uniName).get());
|
||||
|
||||
return aAtkObj->name;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
@ -1043,8 +1039,8 @@ nsAccessibleWrap::FirePlatformEvent(AccEvent* aEvent)
|
||||
|
||||
case nsIAccessibleEvent::EVENT_NAME_CHANGE:
|
||||
{
|
||||
nsString newName;
|
||||
accessible->GetName(newName);
|
||||
nsAutoString newName;
|
||||
accessible->Name(newName);
|
||||
NS_ConvertUTF16toUTF8 utf8Name(newName);
|
||||
if (!atkObj->name || !utf8Name.Equals(atkObj->name))
|
||||
atk_object_set_name(atkObj, utf8Name.get());
|
||||
|
@ -211,7 +211,7 @@ private:
|
||||
nsAutoString role; \
|
||||
GetAccService()->GetStringRole(aAccessible->Role(), role); \
|
||||
nsAutoString name; \
|
||||
aAccessible->GetName(name); \
|
||||
aAccessible->Name(name); \
|
||||
printf(" role: %s, name: %s; ", NS_ConvertUTF16toUTF8(role).get(), \
|
||||
NS_ConvertUTF16toUTF8(name).get()); \
|
||||
A11YDEBUG_FOCUS_LOG_DOMNODE(aAccessible->GetNode()) \
|
||||
|
@ -114,4 +114,20 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
|
||||
LOCAL_INCLUDES += \
|
||||
-I$(srcdir)/../atk \
|
||||
$(NULL)
|
||||
else
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
|
||||
LOCAL_INCLUDES += \
|
||||
-I$(srcdir)/../msaa \
|
||||
$(NULL)
|
||||
else
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
|
||||
LOCAL_INCLUDES += \
|
||||
-I$(srcdir)/../mac \
|
||||
$(NULL)
|
||||
else
|
||||
LOCAL_INCLUDES += \
|
||||
-I$(srcdir)/../other \
|
||||
$(NULL)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
@ -209,9 +209,8 @@ nsAccessible::nsAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
|
||||
NS_ConvertUTF16toUTF8(content->NodeInfo()->QualifiedName()).get(),
|
||||
(void *)content.get());
|
||||
nsAutoString buf;
|
||||
if (NS_SUCCEEDED(GetName(buf))) {
|
||||
printf(" Name:[%s]", NS_ConvertUTF16toUTF8(buf).get());
|
||||
}
|
||||
Name(buf);
|
||||
printf(" Name:[%s]", NS_ConvertUTF16toUTF8(buf).get());
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
@ -278,45 +277,52 @@ nsAccessible::GetName(nsAString& aName)
|
||||
if (IsDefunct())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsAutoString name;
|
||||
Name(name);
|
||||
aName.Assign(name);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ENameValueFlag
|
||||
nsAccessible::Name(nsString& aName)
|
||||
{
|
||||
aName.Truncate();
|
||||
|
||||
GetARIAName(aName);
|
||||
if (!aName.IsEmpty())
|
||||
return NS_OK;
|
||||
return eNameOK;
|
||||
|
||||
nsCOMPtr<nsIXBLAccessible> xblAccessible(do_QueryInterface(mContent));
|
||||
if (xblAccessible) {
|
||||
xblAccessible->GetAccessibleName(aName);
|
||||
if (!aName.IsEmpty())
|
||||
return NS_OK;
|
||||
return eNameOK;
|
||||
}
|
||||
|
||||
nsresult rv = GetNameInternal(aName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!aName.IsEmpty())
|
||||
return NS_OK;
|
||||
return eNameOK;
|
||||
|
||||
// In the end get the name from tooltip.
|
||||
nsIAtom *tooltipAttr = nsnull;
|
||||
|
||||
if (mContent->IsHTML())
|
||||
tooltipAttr = nsGkAtoms::title;
|
||||
else if (mContent->IsXUL())
|
||||
tooltipAttr = nsGkAtoms::tooltiptext;
|
||||
else
|
||||
return NS_OK;
|
||||
|
||||
// XXX: if CompressWhiteSpace worked on nsAString we could avoid a copy.
|
||||
nsAutoString name;
|
||||
if (mContent->GetAttr(kNameSpaceID_None, tooltipAttr, name)) {
|
||||
name.CompressWhitespace();
|
||||
aName = name;
|
||||
return NS_OK_NAME_FROM_TOOLTIP;
|
||||
if (mContent->IsHTML()) {
|
||||
if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName)) {
|
||||
aName.CompressWhitespace();
|
||||
return eNameFromTooltip;
|
||||
}
|
||||
} else if (mContent->IsXUL()) {
|
||||
if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, aName)) {
|
||||
aName.CompressWhitespace();
|
||||
return eNameFromTooltip;
|
||||
}
|
||||
} else {
|
||||
return eNameOK;
|
||||
}
|
||||
|
||||
if (rv != NS_OK_EMPTY_NAME)
|
||||
aName.SetIsVoid(true);
|
||||
|
||||
return NS_OK;
|
||||
return eNameOK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -364,7 +370,7 @@ nsAccessible::Description(nsString& aDescription)
|
||||
nsGkAtoms::title;
|
||||
if (mContent->GetAttr(kNameSpaceID_None, descAtom, aDescription)) {
|
||||
nsAutoString name;
|
||||
GetName(name);
|
||||
Name(name);
|
||||
if (name.IsEmpty() || aDescription == name)
|
||||
// Don't use tooltip for a description if this object
|
||||
// has no name or the tooltip is the same as the name
|
||||
|
@ -65,9 +65,25 @@ class nsHTMLImageMapAccessible;
|
||||
class nsHTMLLIAccessible;
|
||||
struct nsRoleMapEntry;
|
||||
class Relation;
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
class TableAccessible;
|
||||
|
||||
/**
|
||||
* Name type flags.
|
||||
*/
|
||||
enum ENameValueFlag {
|
||||
/**
|
||||
* Name either
|
||||
* a) present (not empty): !name.IsEmpty()
|
||||
* b) no name (was missed): name.IsVoid()
|
||||
* c) was left empty by the author on demand: name.IsEmpty() && !name.IsVoid()
|
||||
*/
|
||||
eNameOK,
|
||||
eNameFromTooltip // Tooltip was used as a name
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
class nsTextAccessible;
|
||||
@ -140,6 +156,11 @@ public:
|
||||
*/
|
||||
virtual void Value(nsString& aValue);
|
||||
|
||||
/**
|
||||
* Get the name of this accessible.
|
||||
*/
|
||||
virtual mozilla::a11y::ENameValueFlag Name(nsString& aName);
|
||||
|
||||
/**
|
||||
* Return DOM node associated with this accessible.
|
||||
*/
|
||||
|
@ -213,26 +213,26 @@ NS_IMPL_RELEASE_INHERITED(nsDocAccessible, nsHyperTextAccessible)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIAccessible
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocAccessible::GetName(nsAString& aName)
|
||||
ENameValueFlag
|
||||
nsDocAccessible::Name(nsString& aName)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
aName.Truncate();
|
||||
|
||||
if (mParent) {
|
||||
rv = mParent->GetName(aName); // Allow owning iframe to override the name
|
||||
mParent->Name(aName); // Allow owning iframe to override the name
|
||||
}
|
||||
if (aName.IsEmpty()) {
|
||||
// Allow name via aria-labelledby or title attribute
|
||||
rv = nsAccessible::GetName(aName);
|
||||
nsAccessible::Name(aName);
|
||||
}
|
||||
if (aName.IsEmpty()) {
|
||||
rv = GetTitle(aName); // Try title element
|
||||
GetTitle(aName); // Try title element
|
||||
}
|
||||
if (aName.IsEmpty()) { // Last resort: use URL
|
||||
rv = GetURL(aName);
|
||||
GetURL(aName);
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
||||
return eNameOK;
|
||||
}
|
||||
|
||||
// nsAccessible public method
|
||||
|
@ -92,7 +92,6 @@ public:
|
||||
virtual ~nsDocAccessible();
|
||||
|
||||
// nsIAccessible
|
||||
NS_IMETHOD GetName(nsAString& aName);
|
||||
NS_IMETHOD GetAttributes(nsIPersistentProperties **aAttributes);
|
||||
NS_IMETHOD TakeFocus(void);
|
||||
|
||||
@ -111,6 +110,7 @@ public:
|
||||
virtual nsIDocument* GetDocumentNode() const { return mDocument; }
|
||||
|
||||
// nsAccessible
|
||||
virtual mozilla::a11y::ENameValueFlag Name(nsString& aName);
|
||||
virtual void Description(nsString& aDescription);
|
||||
virtual nsAccessible* FocusedChild();
|
||||
virtual mozilla::a11y::role NativeRole();
|
||||
|
@ -110,27 +110,22 @@ nsRootAccessible::~nsRootAccessible()
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIAccessible
|
||||
// nsAccessible
|
||||
|
||||
/* readonly attribute AString name; */
|
||||
NS_IMETHODIMP
|
||||
nsRootAccessible::GetName(nsAString& aName)
|
||||
ENameValueFlag
|
||||
nsRootAccessible::Name(nsString& aName)
|
||||
{
|
||||
aName.Truncate();
|
||||
|
||||
if (!mDocument) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (mRoleMapEntry) {
|
||||
nsAccessible::GetName(aName);
|
||||
if (!aName.IsEmpty()) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsAccessible::Name(aName);
|
||||
if (!aName.IsEmpty())
|
||||
return eNameOK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(mDocument);
|
||||
return document->GetTitle(aName);
|
||||
document->GetTitle(aName);
|
||||
return eNameOK;
|
||||
}
|
||||
|
||||
role
|
||||
|
@ -62,9 +62,6 @@ public:
|
||||
nsIPresShell* aPresShell);
|
||||
virtual ~nsRootAccessible();
|
||||
|
||||
// nsIAccessible
|
||||
NS_IMETHOD GetName(nsAString& aName);
|
||||
|
||||
// nsIDOMEventListener
|
||||
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
|
||||
|
||||
@ -72,6 +69,7 @@ public:
|
||||
virtual void Shutdown();
|
||||
|
||||
// nsAccessible
|
||||
virtual mozilla::a11y::ENameValueFlag Name(nsString& aName);
|
||||
virtual Relation RelationByType(PRUint32 aType);
|
||||
virtual mozilla::a11y::role NativeRole();
|
||||
virtual PRUint64 NativeState();
|
||||
|
@ -48,6 +48,8 @@
|
||||
|
||||
#include "nsArrayUtils.h"
|
||||
|
||||
using namespace mozilla::a11y;
|
||||
|
||||
#define NS_OK_NO_NAME_CLAUSE_HANDLED \
|
||||
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_GENERAL, 0x24)
|
||||
|
||||
@ -227,19 +229,16 @@ nsTextEquivUtils::AppendFromAccessible(nsAccessible *aAccessible,
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsAutoString text;
|
||||
nsresult rv = aAccessible->GetName(text);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool isEmptyTextEquiv = true;
|
||||
|
||||
// If the name is from tooltip then append it to result string in the end
|
||||
// (see h. step of name computation guide).
|
||||
if (rv != NS_OK_NAME_FROM_TOOLTIP)
|
||||
nsAutoString text;
|
||||
if (aAccessible->Name(text) != eNameFromTooltip)
|
||||
isEmptyTextEquiv = !AppendString(aString, text);
|
||||
|
||||
// Implementation of f. step.
|
||||
rv = AppendFromValue(aAccessible, aString);
|
||||
nsresult rv = AppendFromValue(aAccessible, aString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (rv != NS_OK_NO_NAME_CLAUSE_HANDLED)
|
||||
|
@ -96,8 +96,8 @@ ApplicationAccessible::GetPreviousSibling(nsIAccessible** aPreviousSibling)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ApplicationAccessible::GetName(nsAString& aName)
|
||||
ENameValueFlag
|
||||
ApplicationAccessible::Name(nsString& aName)
|
||||
{
|
||||
aName.Truncate();
|
||||
|
||||
@ -105,12 +105,14 @@ ApplicationAccessible::GetName(nsAString& aName)
|
||||
mozilla::services::GetStringBundleService();
|
||||
|
||||
NS_ASSERTION(bundleService, "String bundle service must be present!");
|
||||
NS_ENSURE_STATE(bundleService);
|
||||
if (!bundleService)
|
||||
return eNameOK;
|
||||
|
||||
nsCOMPtr<nsIStringBundle> bundle;
|
||||
nsresult rv = bundleService->CreateBundle("chrome://branding/locale/brand.properties",
|
||||
getter_AddRefs(bundle));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_FAILED(rv))
|
||||
return eNameOK;
|
||||
|
||||
nsXPIDLString appName;
|
||||
rv = bundle->GetStringFromName(NS_LITERAL_STRING("brandShortName").get(),
|
||||
@ -121,7 +123,7 @@ ApplicationAccessible::GetName(nsAString& aName)
|
||||
}
|
||||
|
||||
aName.Assign(appName);
|
||||
return NS_OK;
|
||||
return eNameOK;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -79,7 +79,6 @@ public:
|
||||
NS_IMETHOD GetParent(nsIAccessible **aParent);
|
||||
NS_IMETHOD GetNextSibling(nsIAccessible **aNextSibling);
|
||||
NS_IMETHOD GetPreviousSibling(nsIAccessible **aPreviousSibling);
|
||||
NS_IMETHOD GetName(nsAString &aName);
|
||||
NS_IMETHOD GetAttributes(nsIPersistentProperties **aAttributes);
|
||||
NS_IMETHOD GroupPosition(PRInt32 *aGroupLevel, PRInt32 *aSimilarItemsInGroup,
|
||||
PRInt32 *aPositionInGroup);
|
||||
@ -101,6 +100,7 @@ public:
|
||||
virtual bool IsPrimaryForNode() const;
|
||||
|
||||
// nsAccessible
|
||||
virtual mozilla::a11y::ENameValueFlag Name(nsString& aName);
|
||||
virtual void ApplyARIAState(PRUint64* aState);
|
||||
virtual void Description(nsString& aDescription);
|
||||
virtual void Value(nsString& aValue);
|
||||
|
@ -594,7 +594,7 @@ nsHTMLComboboxAccessible::Value(nsString& aValue)
|
||||
// Use accessible name of selected option.
|
||||
nsAccessible* option = SelectedOption();
|
||||
if (option)
|
||||
option->GetName(aValue);
|
||||
option->Name(aValue);
|
||||
}
|
||||
|
||||
PRUint8
|
||||
|
@ -68,12 +68,12 @@ nsHTMLTextAccessible::
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLTextAccessible, nsTextAccessible)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLTextAccessible::GetName(nsAString& aName)
|
||||
ENameValueFlag
|
||||
nsHTMLTextAccessible::Name(nsString& aName)
|
||||
{
|
||||
// Text node, ARIA can't be used.
|
||||
aName = mText;
|
||||
return NS_OK;
|
||||
return eNameOK;
|
||||
}
|
||||
|
||||
role
|
||||
@ -348,14 +348,11 @@ nsHTMLListBulletAccessible::IsPrimaryForNode() const
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsHTMLListBulletAccessible: nsAccessible
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLListBulletAccessible::GetName(nsAString &aName)
|
||||
ENameValueFlag
|
||||
nsHTMLListBulletAccessible::Name(nsString &aName)
|
||||
{
|
||||
aName.Truncate();
|
||||
|
||||
if (IsDefunct())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Native anonymous content, ARIA can't be used. Get list bullet text.
|
||||
nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame());
|
||||
NS_ASSERTION(blockFrame, "No frame for list item!");
|
||||
@ -366,7 +363,7 @@ nsHTMLListBulletAccessible::GetName(nsAString &aName)
|
||||
aName.Append(' ');
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return eNameOK;
|
||||
}
|
||||
|
||||
role
|
||||
|
@ -55,10 +55,8 @@ public:
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIAccessible
|
||||
NS_IMETHOD GetName(nsAString& aName);
|
||||
|
||||
// nsAccessible
|
||||
virtual mozilla::a11y::ENameValueFlag Name(nsString& aName);
|
||||
virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
|
||||
virtual mozilla::a11y::role NativeRole();
|
||||
virtual PRUint64 NativeState();
|
||||
@ -129,13 +127,11 @@ class nsHTMLListBulletAccessible : public nsLeafAccessible
|
||||
public:
|
||||
nsHTMLListBulletAccessible(nsIContent* aContent, nsDocAccessible* aDoc);
|
||||
|
||||
// nsIAccessible
|
||||
NS_IMETHOD GetName(nsAString& aName);
|
||||
|
||||
// nsAccessNode
|
||||
virtual bool IsPrimaryForNode() const;
|
||||
|
||||
// nsAccessible
|
||||
virtual mozilla::a11y::ENameValueFlag Name(nsString& aName);
|
||||
virtual mozilla::a11y::role NativeRole();
|
||||
virtual PRUint64 NativeState();
|
||||
virtual void AppendTextTo(nsAString& aText, PRUint32 aStartOffset = 0,
|
||||
|
@ -62,7 +62,6 @@ CMMSRCS = nsAccessNodeWrap.mm \
|
||||
|
||||
|
||||
EXPORTS = \
|
||||
ApplicationAccessibleWrap.h \
|
||||
ARIAGridAccessibleWrap.h \
|
||||
nsAccessNodeWrap.h \
|
||||
nsTextAccessibleWrap.h \
|
||||
|
@ -514,7 +514,7 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
nsAutoString title;
|
||||
mGeckoAccessible->GetName (title);
|
||||
mGeckoAccessible->Name(title);
|
||||
return title.IsEmpty() ? nil : [NSString stringWithCharacters:title.BeginReading() length:title.Length()];
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
|
@ -78,7 +78,6 @@ CPPSRCS = \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = \
|
||||
ApplicationAccessibleWrap.h \
|
||||
ARIAGridAccessibleWrap.h \
|
||||
nsAccessNodeWrap.h \
|
||||
nsAccessibleWrap.h \
|
||||
|
@ -285,9 +285,7 @@ __try {
|
||||
return CO_E_OBJNOTCONNECTED;
|
||||
|
||||
nsAutoString name;
|
||||
nsresult rv = xpAccessible->GetName(name);
|
||||
if (NS_FAILED(rv))
|
||||
return GetHRESULT(rv);
|
||||
xpAccessible->Name(name);
|
||||
|
||||
// The name was not provided, e.g. no alt attribute for an image. A screen
|
||||
// reader may choose to invent its own accessible name, e.g. from an image src
|
||||
|
@ -38,6 +38,8 @@
|
||||
#include "nsXULMenuAccessibleWrap.h"
|
||||
#include "nsINameSpaceManager.h"
|
||||
|
||||
using namespace mozilla::a11y;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsXULMenuAccessibleWrap
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -48,21 +50,19 @@ nsXULMenuitemAccessibleWrap::
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULMenuitemAccessibleWrap::GetName(nsAString& aName)
|
||||
ENameValueFlag
|
||||
nsXULMenuitemAccessibleWrap::Name(nsString& aName)
|
||||
{
|
||||
// XXX This should be done in get_accName() so that nsIAccessible::GetName()]
|
||||
// provides the same results on all platforms
|
||||
nsresult rv = nsXULMenuitemAccessible::GetName(aName);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
nsXULMenuitemAccessible::Name(aName);
|
||||
if (aName.IsEmpty())
|
||||
return eNameOK;
|
||||
|
||||
nsAutoString accel;
|
||||
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::acceltext, accel);
|
||||
if (!accel.IsEmpty()) {
|
||||
if (!accel.IsEmpty())
|
||||
aName += NS_LITERAL_STRING("\t") + accel;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return eNameOK;
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ public:
|
||||
virtual ~nsXULMenuitemAccessibleWrap() {}
|
||||
|
||||
// nsIAccessible
|
||||
NS_IMETHOD GetName(nsAString& aName);
|
||||
virtual mozilla::a11y::ENameValueFlag Name(nsString& aName);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -54,7 +54,6 @@ CPPSRCS = \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = \
|
||||
ApplicationAccessibleWrap.h \
|
||||
ARIAGridAccessibleWrap.h \
|
||||
nsAccessNodeWrap.h \
|
||||
nsTextAccessibleWrap.h \
|
||||
|
@ -66,13 +66,13 @@ nsXULAlertAccessible::NativeState()
|
||||
return nsAccessible::NativeState() | states::ALERT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULAlertAccessible::GetName(nsAString& aName)
|
||||
ENameValueFlag
|
||||
nsXULAlertAccessible::Name(nsString& aName)
|
||||
{
|
||||
// Screen readers need to read contents of alert, not the accessible name.
|
||||
// If we have both some screen readers will read the alert twice.
|
||||
aName.Truncate();
|
||||
return NS_OK;
|
||||
return eNameOK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -51,10 +51,8 @@ public:
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIAccessible
|
||||
NS_IMETHOD GetName(nsAString& aName);
|
||||
|
||||
// nsAccessible
|
||||
virtual mozilla::a11y::ENameValueFlag Name(nsString& aName);
|
||||
virtual mozilla::a11y::role NativeRole();
|
||||
virtual PRUint64 NativeState();
|
||||
|
||||
|
@ -1176,16 +1176,13 @@ NS_IMPL_RELEASE_INHERITED(nsXULTreeItemAccessible, nsXULTreeItemAccessibleBase)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsXULTreeItemAccessible: nsIAccessible implementation
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTreeItemAccessible::GetName(nsAString& aName)
|
||||
ENameValueFlag
|
||||
nsXULTreeItemAccessible::Name(nsString& aName)
|
||||
{
|
||||
aName.Truncate();
|
||||
|
||||
if (IsDefunct())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
GetCellName(mColumn, aName);
|
||||
return NS_OK;
|
||||
return eNameOK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -1197,7 +1194,7 @@ nsXULTreeItemAccessible::Init()
|
||||
if (!nsXULTreeItemAccessibleBase::Init())
|
||||
return false;
|
||||
|
||||
GetName(mCachedName);
|
||||
Name(mCachedName);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1235,7 +1232,7 @@ nsXULTreeItemAccessible::RowInvalidated(PRInt32 aStartColIdx,
|
||||
PRInt32 aEndColIdx)
|
||||
{
|
||||
nsAutoString name;
|
||||
GetName(name);
|
||||
Name(name);
|
||||
|
||||
if (name != mCachedName) {
|
||||
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
|
||||
|
@ -267,13 +267,12 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULTreeItemAccessible,
|
||||
nsXULTreeItemAccessibleBase)
|
||||
|
||||
NS_IMETHOD GetName(nsAString& aName);
|
||||
|
||||
// nsAccessNode
|
||||
virtual bool Init();
|
||||
virtual void Shutdown();
|
||||
|
||||
// nsAccessible
|
||||
virtual mozilla::a11y::ENameValueFlag Name(nsString& aName);
|
||||
virtual mozilla::a11y::role NativeRole();
|
||||
|
||||
// nsXULTreeItemAccessibleBase
|
||||
|
@ -657,14 +657,11 @@ nsXULTreeGridRowAccessible::NativeRole()
|
||||
return roles::ROW;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTreeGridRowAccessible::GetName(nsAString& aName)
|
||||
ENameValueFlag
|
||||
nsXULTreeGridRowAccessible::Name(nsString& aName)
|
||||
{
|
||||
aName.Truncate();
|
||||
|
||||
if (IsDefunct())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// XXX: the row name sholdn't be a concatenation of cell names (bug 664384).
|
||||
nsCOMPtr<nsITreeColumn> column = nsCoreUtils::GetFirstSensibleColumn(mTree);
|
||||
while (column) {
|
||||
@ -678,7 +675,7 @@ nsXULTreeGridRowAccessible::GetName(nsAString& aName)
|
||||
column = nsCoreUtils::GetNextSensibleColumn(column);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return eNameOK;
|
||||
}
|
||||
|
||||
nsAccessible*
|
||||
@ -844,13 +841,13 @@ nsXULTreeGridCellAccessible::FocusedChild()
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTreeGridCellAccessible::GetName(nsAString& aName)
|
||||
ENameValueFlag
|
||||
nsXULTreeGridCellAccessible::Name(nsString& aName)
|
||||
{
|
||||
aName.Truncate();
|
||||
|
||||
if (IsDefunct() || !mTreeView)
|
||||
return NS_ERROR_FAILURE;
|
||||
if (!mTreeView)
|
||||
return eNameOK;
|
||||
|
||||
mTreeView->GetCellText(mRow, mColumn, aName);
|
||||
|
||||
@ -862,7 +859,7 @@ nsXULTreeGridCellAccessible::GetName(nsAString& aName)
|
||||
if (aName.IsEmpty())
|
||||
mTreeView->GetCellValue(mRow, mColumn, aName);
|
||||
|
||||
return NS_OK;
|
||||
return eNameOK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -103,7 +103,7 @@ public:
|
||||
|
||||
// nsAccessible
|
||||
virtual mozilla::a11y::role NativeRole();
|
||||
NS_IMETHOD GetName(nsAString& aName);
|
||||
virtual mozilla::a11y::ENameValueFlag Name(nsString& aName);
|
||||
virtual nsAccessible* ChildAtPoint(PRInt32 aX, PRInt32 aY,
|
||||
EWhichChildAtPoint aWhichChild);
|
||||
|
||||
@ -155,7 +155,6 @@ public:
|
||||
|
||||
// nsIAccessible
|
||||
|
||||
NS_IMETHOD GetName(nsAString& aName);
|
||||
NS_IMETHOD GetBounds(PRInt32 *aX, PRInt32 *aY,
|
||||
PRInt32 *aWidth, PRInt32 *aHeight);
|
||||
|
||||
@ -170,6 +169,7 @@ public:
|
||||
virtual bool IsPrimaryForNode() const;
|
||||
|
||||
// nsAccessible
|
||||
virtual mozilla::a11y::ENameValueFlag Name(nsString& aName);
|
||||
virtual nsAccessible* FocusedChild();
|
||||
virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
|
||||
virtual PRInt32 IndexInParent() const;
|
||||
|
@ -73,7 +73,7 @@
|
||||
// show popup again for the next test
|
||||
gQueue.push(new synthClick("popupbutton", new nofocusChecker()));
|
||||
|
||||
if (MAC) {
|
||||
if (!MAC) {
|
||||
// click menubutton of the 'menubutton' button while popup of button open.
|
||||
gQueue.push(new synthClick("mbb", new focusChecker("mbb"), { where: "right" }));
|
||||
// close popup, focus stays on menubutton, fire focus event
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
is(root.parentDocument, null,
|
||||
"Wrong parent document of root accessible");
|
||||
is(root.childDocumentCount, SEAMONKEY ? 1 : 3,
|
||||
is(root.childDocumentCount, 1,
|
||||
"Wrong child document count of root accessible");
|
||||
is(root.getChildDocumentAt(0), tabDoc,
|
||||
"Wrong child document at index 0 of root accessible");
|
||||
|
@ -435,7 +435,7 @@ pref("dom.sms.enabled", true);
|
||||
pref("dom.sms.whitelist", "file://,http://homescreen.gaiamobile.org,http://sms.gaiamobile.org");
|
||||
|
||||
// Temporary permission hack for WebMobileConnection
|
||||
pref("dom.mobileconnection.whitelist", "http://homescreen.gaiamobile.org");
|
||||
pref("dom.mobileconnection.whitelist", "http://system.gaiamobile.org,http://homescreen.gaiamobile.org,http://dialer.gaiamobile.org");
|
||||
|
||||
// Temporary permission hack for WebContacts
|
||||
pref("dom.mozContacts.enabled", true);
|
||||
|
@ -1045,9 +1045,6 @@ pref("services.sync.prefs.sync.xpinstall.whitelist.required", true);
|
||||
// Disable the error console
|
||||
pref("devtools.errorconsole.enabled", false);
|
||||
|
||||
// Enable the developer toolbar
|
||||
pref("devtools.toolbar.enabled", false);
|
||||
|
||||
// Enable the Inspector
|
||||
pref("devtools.inspector.enabled", true);
|
||||
pref("devtools.inspector.htmlHeight", 112);
|
||||
@ -1061,14 +1058,9 @@ pref("devtools.layoutview.open", false);
|
||||
|
||||
// Enable the Debugger
|
||||
pref("devtools.debugger.enabled", false);
|
||||
pref("devtools.debugger.remote-enabled", false);
|
||||
pref("devtools.debugger.remote-host", "localhost");
|
||||
pref("devtools.debugger.remote-port", 6000);
|
||||
|
||||
// The default Debugger UI height
|
||||
pref("devtools.debugger.ui.height", 250);
|
||||
pref("devtools.debugger.ui.remote-win.width", 900);
|
||||
pref("devtools.debugger.ui.remote-win.height", 400);
|
||||
|
||||
// Enable the style inspector
|
||||
pref("devtools.styleinspector.enabled", true);
|
||||
@ -1091,14 +1083,8 @@ pref("devtools.styleeditor.transitions", true);
|
||||
// Enable tools for Chrome development.
|
||||
pref("devtools.chrome.enabled", false);
|
||||
|
||||
// Display the introductory text
|
||||
pref("devtools.gcli.hideIntro", false);
|
||||
|
||||
// How eager are we to show help: never=1, sometimes=2, always=3
|
||||
pref("devtools.gcli.eagerHelper", 2);
|
||||
|
||||
// Do we allow the 'pref set' command
|
||||
pref("devtools.gcli.allowSet", false);
|
||||
// Disable the GCLI enhanced command line.
|
||||
pref("devtools.gcli.enable", false);
|
||||
|
||||
// The last Web Console height. This is initially 0 which means that the Web
|
||||
// Console will use the default height next time it shows.
|
||||
|
@ -176,14 +176,8 @@
|
||||
<menuseparator class="appmenu-menuseparator"/>
|
||||
<menu id="appmenu_webDeveloper"
|
||||
label="&appMenuWebDeveloper.label;">
|
||||
<menupopup id="appmenu_webDeveloper_popup">
|
||||
<menuitem id="appmenu_devToolbar"
|
||||
type="checkbox"
|
||||
autocheck="false"
|
||||
hidden="true"
|
||||
label="&devToolbarMenu.label;"
|
||||
command="Tools:DevToolbar"
|
||||
key="key_devToolbar"/>
|
||||
<menupopup id="appmenu_webDeveloper_popup"
|
||||
onpopupshowing="onWebDeveloperMenuShowing();">
|
||||
<menuitem id="appmenu_webConsole"
|
||||
label="&webConsoleCmd.label;"
|
||||
type="checkbox"
|
||||
@ -197,14 +191,9 @@
|
||||
key="key_inspect"/>
|
||||
<menuitem id="appmenu_debugger"
|
||||
hidden="true"
|
||||
type="checkbox"
|
||||
label="&debuggerMenu.label;"
|
||||
key="key_debugger"
|
||||
command="Tools:Debugger"/>
|
||||
<menuitem id="appmenu_remoteDebugger"
|
||||
hidden="true"
|
||||
label="&remoteDebuggerMenu.label;"
|
||||
command="Tools:RemoteDebugger"/>
|
||||
<menuitem id="appmenu_scratchpad"
|
||||
hidden="true"
|
||||
label="&scratchpad.label;"
|
||||
|
@ -225,7 +225,7 @@ var FullZoom = {
|
||||
return;
|
||||
|
||||
// Avoid the cps roundtrip and apply the default/global pref.
|
||||
if (aURI.spec == "about:blank") {
|
||||
if (isBlankPageURL(aURI.spec)) {
|
||||
this._applyPrefToSetting(undefined, aBrowser);
|
||||
return;
|
||||
}
|
||||
|
@ -531,15 +531,8 @@
|
||||
<menu id="webDeveloperMenu"
|
||||
label="&webDeveloperMenu.label;"
|
||||
accesskey="&webDeveloperMenu.accesskey;">
|
||||
<menupopup id="menuWebDeveloperPopup">
|
||||
<menuitem id="menu_devToolbar"
|
||||
type="checkbox"
|
||||
autocheck="false"
|
||||
hidden="true"
|
||||
label="&devToolbarMenu.label;"
|
||||
accesskey="&devToolbarMenu.accesskey;"
|
||||
key="key_devToolbar"
|
||||
command="Tools:DevToolbar"/>
|
||||
<menupopup id="menuWebDeveloperPopup"
|
||||
onpopupshowing="onWebDeveloperMenuShowing();">
|
||||
<menuitem id="webConsole"
|
||||
type="checkbox"
|
||||
label="&webConsoleCmd.label;"
|
||||
@ -555,14 +548,9 @@
|
||||
command="Tools:Inspect"/>
|
||||
<menuitem id="menu_debugger"
|
||||
hidden="true"
|
||||
type="checkbox"
|
||||
label="&debuggerMenu.label;"
|
||||
key="key_debugger"
|
||||
command="Tools:Debugger"/>
|
||||
<menuitem id="menu_remoteDebugger"
|
||||
hidden="true"
|
||||
label="&remoteDebuggerMenu.label;"
|
||||
command="Tools:RemoteDebugger"/>
|
||||
<menuitem id="menu_scratchpad"
|
||||
hidden="true"
|
||||
label="&scratchpad.label;"
|
||||
|
@ -126,11 +126,9 @@
|
||||
|
||||
<command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/>
|
||||
<command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/>
|
||||
<command id="Tools:DevToolbar" oncommand="DeveloperToolbar.toggle();" disabled="true"/>
|
||||
<command id="Tools:WebConsole" oncommand="HUDConsoleUI.toggleHUD();"/>
|
||||
<command id="Tools:Inspect" oncommand="InspectorUI.toggleInspectorUI();" disabled="true"/>
|
||||
<command id="Tools:Debugger" oncommand="DebuggerUI.toggleDebugger();" disabled="true"/>
|
||||
<command id="Tools:RemoteDebugger" oncommand="DebuggerUI.toggleRemoteDebugger();" disabled="true"/>
|
||||
<command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();" disabled="true"/>
|
||||
<command id="Tools:StyleEditor" oncommand="StyleEditor.openChrome();" disabled="true"/>
|
||||
<command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
|
||||
@ -257,13 +255,6 @@
|
||||
#endif
|
||||
<key id="key_openAddons" key="&addons.commandkey;" command="Tools:Addons" modifiers="accel,shift"/>
|
||||
<key id="key_errorConsole" key="&errorConsoleCmd.commandkey;" oncommand="toJavaScriptConsole();" modifiers="accel,shift" disabled="true"/>
|
||||
<key id="key_devToolbar" key="&devToolbar.commandkey;" command="Tools:DevToolbar"
|
||||
#ifdef XP_MACOSX
|
||||
modifiers="accel,alt"
|
||||
#else
|
||||
modifiers="accel,shift"
|
||||
#endif
|
||||
/>
|
||||
<key id="key_webConsole" key="&webConsoleCmd.commandkey;" oncommand="HUDConsoleUI.toggleHUD();"
|
||||
#ifdef XP_MACOSX
|
||||
modifiers="accel,alt"
|
||||
|
@ -214,6 +214,8 @@ let TabView = {
|
||||
|
||||
this._isFrameLoading = true;
|
||||
|
||||
TelemetryStopwatch.start("PANORAMA_INITIALIZATION_TIME_MS");
|
||||
|
||||
// ___ find the deck
|
||||
this._deck = document.getElementById("tab-view-deck");
|
||||
|
||||
@ -229,6 +231,8 @@ let TabView = {
|
||||
window.addEventListener("tabviewframeinitialized", function onInit() {
|
||||
window.removeEventListener("tabviewframeinitialized", onInit, false);
|
||||
|
||||
TelemetryStopwatch.finish("PANORAMA_INITIALIZATION_TIME_MS");
|
||||
|
||||
self._isFrameLoading = false;
|
||||
self._window = self._iframe.contentWindow;
|
||||
self._setBrowserKeyHandlers();
|
||||
|
@ -179,12 +179,6 @@ XPCOMUtils.defineLazyGetter(this, "PopupNotifications", function () {
|
||||
}
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "DeveloperToolbar", function() {
|
||||
let tmp = {};
|
||||
Cu.import("resource:///modules/devtools/DeveloperToolbar.jsm", tmp);
|
||||
return new tmp.DeveloperToolbar(window, document.getElementById("developer-toolbar"));
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "InspectorUI", function() {
|
||||
let tmp = {};
|
||||
Cu.import("resource:///modules/inspector.jsm", tmp);
|
||||
@ -1702,16 +1696,6 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
||||
setUrlAndSearchBarWidthForConditionalForwardButton();
|
||||
});
|
||||
|
||||
// Enable developer toolbar?
|
||||
let devToolbarEnabled = gPrefService.getBoolPref("devtools.toolbar.enabled");
|
||||
if (devToolbarEnabled) {
|
||||
document.getElementById("menu_devToolbar").hidden = false;
|
||||
document.getElementById("Tools:DevToolbar").removeAttribute("disabled");
|
||||
#ifdef MENUBAR_CAN_AUTOHIDE
|
||||
document.getElementById("appmenu_devToolbar").hidden = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Enable Inspector?
|
||||
let enabled = gPrefService.getBoolPref("devtools.inspector.enabled");
|
||||
if (enabled) {
|
||||
@ -1720,7 +1704,6 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
||||
#ifdef MENUBAR_CAN_AUTOHIDE
|
||||
document.getElementById("appmenu_pageInspect").hidden = false;
|
||||
#endif
|
||||
document.getElementById("developer-toolbar-inspector").hidden = false;
|
||||
}
|
||||
|
||||
// Enable Debugger?
|
||||
@ -1730,17 +1713,6 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
||||
document.getElementById("Tools:Debugger").removeAttribute("disabled");
|
||||
#ifdef MENUBAR_CAN_AUTOHIDE
|
||||
document.getElementById("appmenu_debugger").hidden = false;
|
||||
#endif
|
||||
document.getElementById("developer-toolbar-debugger").hidden = false;
|
||||
}
|
||||
|
||||
// Enable Remote Debugger?
|
||||
let enabled = gPrefService.getBoolPref("devtools.debugger.remote-enabled");
|
||||
if (enabled) {
|
||||
document.getElementById("menu_remoteDebugger").hidden = false;
|
||||
document.getElementById("Tools:RemoteDebugger").removeAttribute("disabled");
|
||||
#ifdef MENUBAR_CAN_AUTOHIDE
|
||||
document.getElementById("appmenu_remoteDebugger").hidden = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -9309,6 +9281,10 @@ var StyleEditor = {
|
||||
}
|
||||
};
|
||||
|
||||
function onWebDeveloperMenuShowing() {
|
||||
document.getElementById("Tools:WebConsole").setAttribute("checked", HUDConsoleUI.getOpenHUD() != null);
|
||||
}
|
||||
|
||||
|
||||
XPCOMUtils.defineLazyGetter(window, "gShowPageResizers", function () {
|
||||
#ifdef XP_WIN
|
||||
|
@ -1039,60 +1039,6 @@
|
||||
tooltiptext="&inspectCloseButton.tooltiptext;"/>
|
||||
#endif
|
||||
</toolbar>
|
||||
|
||||
<panel id="gcli-tooltip"
|
||||
type="arrow"
|
||||
noautofocus="true"
|
||||
noautohide="true"
|
||||
class="gcli-panel">
|
||||
<iframe id="gcli-tooltip-frame"
|
||||
src="chrome://browser/content/devtools/gcliblank.xhtml"
|
||||
flex="1"/>
|
||||
</panel>
|
||||
<panel id="gcli-output"
|
||||
type="arrow"
|
||||
noautofocus="true"
|
||||
noautohide="true"
|
||||
class="gcli-panel">
|
||||
<iframe id="gcli-output-frame"
|
||||
src="chrome://browser/content/devtools/gcliblank.xhtml"
|
||||
flex="1"/>
|
||||
</panel>
|
||||
|
||||
<toolbar id="developer-toolbar"
|
||||
class="devtools-toolbar"
|
||||
hidden="true">
|
||||
#ifdef XP_MACOSX
|
||||
<toolbarbutton id="developer-toolbar-closebutton"
|
||||
oncommand="DeveloperToolbar.hide();"
|
||||
tooltiptext="&devToolbarCloseButton.tooltiptext;"/>
|
||||
#endif
|
||||
<stack class="gclitoolbar-stack-node" flex="1">
|
||||
<description class="gclitoolbar-prompt">»</description>
|
||||
<description class="gclitoolbar-complete-node"/>
|
||||
<textbox class="gclitoolbar-input-node" rows="1"/>
|
||||
</stack>
|
||||
<toolbarbutton id="developer-toolbar-webconsole"
|
||||
label="&webConsoleButton.label;"
|
||||
class="devtools-toolbarbutton"
|
||||
command="Tools:WebConsole"/>
|
||||
<toolbarbutton id="developer-toolbar-inspector"
|
||||
label="&inspectorButton.label;"
|
||||
class="devtools-toolbarbutton"
|
||||
hidden="true"
|
||||
command="Tools:Inspect"/>
|
||||
<toolbarbutton id="developer-toolbar-debugger"
|
||||
label="&scriptsButton.label;"
|
||||
class="devtools-toolbarbutton"
|
||||
hidden="true"
|
||||
command="Tools:Debugger"/>
|
||||
#ifndef XP_MACOSX
|
||||
<toolbarbutton id="developer-toolbar-closebutton"
|
||||
oncommand="DeveloperToolbar.hide();"
|
||||
tooltiptext="&devToolbarCloseButton.tooltiptext;"/>
|
||||
#endif
|
||||
</toolbar>
|
||||
|
||||
<toolbar id="addon-bar"
|
||||
toolbarname="&addonBarCmd.label;" accesskey="&addonBarCmd.accesskey;"
|
||||
collapsed="true"
|
||||
|
@ -92,13 +92,17 @@
|
||||
<field name="tabs" readonly="true">
|
||||
this.tabContainer.childNodes;
|
||||
</field>
|
||||
|
||||
<property name="visibleTabs" readonly="true">
|
||||
<getter><![CDATA[
|
||||
return Array.filter(this.tabs, function(tab) {
|
||||
return !tab.hidden && !tab.closing;
|
||||
});
|
||||
if (!this._visibleTabs)
|
||||
this._visibleTabs = Array.filter(this.tabs,
|
||||
function (tab) !tab.hidden && !tab.closing);
|
||||
return this._visibleTabs;
|
||||
]]></getter>
|
||||
</property>
|
||||
<field name="_visibleTabs">null</field>
|
||||
|
||||
<field name="mURIFixup" readonly="true">
|
||||
Components.classes["@mozilla.org/docshell/urifixup;1"]
|
||||
.getService(Components.interfaces.nsIURIFixup);
|
||||
@ -151,9 +155,6 @@
|
||||
false
|
||||
#endif
|
||||
</field>
|
||||
<field name="_browsers">
|
||||
null
|
||||
</field>
|
||||
|
||||
<field name="_autoScrollPopup">
|
||||
null
|
||||
@ -1240,8 +1241,6 @@
|
||||
aIsUTF8 = params.isUTF8;
|
||||
}
|
||||
|
||||
this._browsers = null; // invalidate cache
|
||||
|
||||
// if we're adding tabs, we're past interrupt mode, ditch the owner
|
||||
if (this.mCurrentTab.owner)
|
||||
this.mCurrentTab.owner = null;
|
||||
@ -1291,10 +1290,11 @@
|
||||
}, 0, this.tabContainer);
|
||||
}
|
||||
|
||||
this.tabContainer.appendChild(t);
|
||||
|
||||
// invalidate cache, because tabContainer is about to change
|
||||
// invalidate caches
|
||||
this._browsers = null;
|
||||
this._visibleTabs = null;
|
||||
|
||||
this.tabContainer.appendChild(t);
|
||||
|
||||
// If this new tab is owned by another, assert that relationship
|
||||
if (aOwner)
|
||||
@ -1625,6 +1625,7 @@
|
||||
|
||||
aTab.closing = true;
|
||||
this._removingTabs.push(aTab);
|
||||
this._visibleTabs = null; // invalidate cache
|
||||
if (newTab)
|
||||
this.addTab(BROWSER_NEW_TAB_URL, {skipAnimation: true});
|
||||
else
|
||||
@ -2009,7 +2010,10 @@
|
||||
<![CDATA[
|
||||
if (aTab.hidden) {
|
||||
aTab.removeAttribute("hidden");
|
||||
this._visibleTabs = null; // invalidate cache
|
||||
|
||||
this.tabContainer.adjustTabstrip();
|
||||
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("TabShow", true, false);
|
||||
aTab.dispatchEvent(event);
|
||||
@ -2025,7 +2029,10 @@
|
||||
if (!aTab.hidden && !aTab.pinned && !aTab.selected &&
|
||||
!aTab.closing) {
|
||||
aTab.setAttribute("hidden", "true");
|
||||
this._visibleTabs = null; // invalidate cache
|
||||
|
||||
this.tabContainer.adjustTabstrip();
|
||||
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("TabHide", true, false);
|
||||
aTab.dispatchEvent(event);
|
||||
@ -2081,6 +2088,7 @@
|
||||
]]>
|
||||
</getter>
|
||||
</property>
|
||||
<field name="_browsers">null</field>
|
||||
|
||||
<!-- Moves a tab to a new browser window, unless it's already the only tab
|
||||
in the current window, in which case this will do nothing. -->
|
||||
@ -2126,11 +2134,14 @@
|
||||
|
||||
aIndex = aIndex < aTab._tPos ? aIndex: aIndex+1;
|
||||
this.mCurrentTab._selected = false;
|
||||
|
||||
// invalidate caches
|
||||
this._browsers = null;
|
||||
this._visibleTabs = null;
|
||||
|
||||
// use .item() instead of [] because dragging to the end of the strip goes out of
|
||||
// bounds: .item() returns null (so it acts like appendChild), but [] throws
|
||||
this.tabContainer.insertBefore(aTab, this.tabs.item(aIndex));
|
||||
// invalidate cache, because tabContainer is about to change
|
||||
this._browsers = null;
|
||||
|
||||
for (let i = 0; i < this.tabs.length; i++) {
|
||||
this.tabs[i]._tPos = i;
|
||||
|
@ -131,7 +131,6 @@ function startTest2() {
|
||||
"onStateChange",
|
||||
"onLocationChange",
|
||||
"onSecurityChange",
|
||||
"onSecurityChange",
|
||||
"onStateChange"
|
||||
];
|
||||
gFrontNotifications = gAllNotifications;
|
||||
@ -156,7 +155,6 @@ function startTest4() {
|
||||
"onStateChange",
|
||||
"onLocationChange",
|
||||
"onSecurityChange",
|
||||
"onSecurityChange",
|
||||
"onStateChange"
|
||||
];
|
||||
gFrontNotifications = [];
|
||||
|
@ -68,6 +68,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "BookmarkHTMLUtils",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "webappsUI",
|
||||
"resource:///modules/webappsUI.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
|
||||
"resource:///modules/PageThumbs.jsm");
|
||||
|
||||
const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser";
|
||||
const PREF_PLUGINS_UPDATEURL = "plugins.update.url";
|
||||
|
||||
@ -358,6 +361,8 @@ BrowserGlue.prototype = {
|
||||
// Initialize webapps UI
|
||||
webappsUI.init();
|
||||
|
||||
PageThumbs.init();
|
||||
|
||||
Services.obs.notifyObservers(null, "browser-ui-startup-complete", "");
|
||||
},
|
||||
|
||||
@ -379,6 +384,7 @@ BrowserGlue.prototype = {
|
||||
_onProfileShutdown: function BG__onProfileShutdown() {
|
||||
this._shutdownPlaces();
|
||||
this._sanitizer.onShutdown();
|
||||
PageThumbs.uninit();
|
||||
},
|
||||
|
||||
// All initial windows have opened.
|
||||
|
@ -35,36 +35,6 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
function provideWindow(aCallback, aURL, aFeatures) {
|
||||
function callback() {
|
||||
executeSoon(function () {
|
||||
aCallback(win);
|
||||
});
|
||||
}
|
||||
|
||||
let win = openDialog(getBrowserURL(), "", aFeatures || "chrome,all,dialog=no", aURL);
|
||||
|
||||
whenWindowLoaded(win, function () {
|
||||
if (!aURL) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
win.gBrowser.selectedBrowser.addEventListener("load", function() {
|
||||
win.gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
callback();
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
||||
function whenWindowLoaded(aWin, aCallback) {
|
||||
aWin.addEventListener("load", function () {
|
||||
aWin.removeEventListener("load", arguments.callee, false);
|
||||
executeSoon(function () {
|
||||
aCallback(aWin);
|
||||
});
|
||||
}, false);
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
|
@ -35,43 +35,13 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
function provideWindow(aCallback, aURL, aFeatures) {
|
||||
function callback() {
|
||||
executeSoon(function () {
|
||||
aCallback(win);
|
||||
});
|
||||
}
|
||||
|
||||
let win = openDialog(getBrowserURL(), "", aFeatures || "chrome,all,dialog=no", aURL);
|
||||
|
||||
whenWindowLoaded(win, function () {
|
||||
if (!aURL) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
win.gBrowser.selectedBrowser.addEventListener("load", function() {
|
||||
win.gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
callback();
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
||||
function whenWindowLoaded(aWin, aCallback) {
|
||||
aWin.addEventListener("load", function () {
|
||||
aWin.removeEventListener("load", arguments.callee, false);
|
||||
executeSoon(function () {
|
||||
aCallback(aWin);
|
||||
});
|
||||
}, false);
|
||||
}
|
||||
|
||||
function test() {
|
||||
// This test takes quite some time, and timeouts frequently, so we require
|
||||
// more time to run.
|
||||
// See Bug 518970.
|
||||
requestLongerTimeout(2);
|
||||
|
||||
waitForExplicitFinish();
|
||||
waitForExplicitFinish();
|
||||
|
||||
// helper function that does the actual testing
|
||||
function openWindowRec(windowsToOpen, expectedResults, recCallback) {
|
||||
@ -94,13 +64,14 @@ function test() {
|
||||
executeSoon(recCallback);
|
||||
return;
|
||||
}
|
||||
|
||||
// hack to force window to be considered a popup (toolbar=no didn't work)
|
||||
let winData = windowsToOpen.shift();
|
||||
let settings = "chrome,dialog=no," +
|
||||
(winData.isPopup ? "all=no" : "all");
|
||||
let url = "http://example.com/?window=" + windowsToOpen.length;
|
||||
|
||||
provideWindow(function (win) {
|
||||
provideWindow(function onTestURLLoaded(win) {
|
||||
win.close();
|
||||
openWindowRec(windowsToOpen, expectedResults, recCallback);
|
||||
}, url, settings);
|
||||
|
@ -93,14 +93,6 @@ let TabsProgressListener = {
|
||||
}
|
||||
}
|
||||
|
||||
// ----------
|
||||
function whenWindowLoaded(win, callback) {
|
||||
win.addEventListener("load", function onLoad() {
|
||||
win.removeEventListener("load", onLoad, false);
|
||||
executeSoon(callback);
|
||||
}, false);
|
||||
}
|
||||
|
||||
// ----------
|
||||
function newWindowWithState(state, callback) {
|
||||
let opts = "chrome,all,dialog=no,height=800,width=800";
|
||||
@ -108,10 +100,10 @@ function newWindowWithState(state, callback) {
|
||||
|
||||
registerCleanupFunction(function () win.close());
|
||||
|
||||
whenWindowLoaded(win, function () {
|
||||
TabsProgressListener.init(win);
|
||||
whenWindowLoaded(win, function onWindowLoaded(aWin) {
|
||||
TabsProgressListener.init(aWin);
|
||||
TabsProgressListener.setCallback(callback);
|
||||
|
||||
ss.setWindowState(win, JSON.stringify(state), true);
|
||||
ss.setWindowState(aWin, JSON.stringify(state), true);
|
||||
});
|
||||
}
|
||||
|
@ -27,14 +27,6 @@ function test() {
|
||||
});
|
||||
}
|
||||
|
||||
// ----------
|
||||
function whenWindowLoaded(aWindow, aCallback) {
|
||||
aWindow.addEventListener("load", function onLoad() {
|
||||
aWindow.removeEventListener("load", onLoad, false);
|
||||
executeSoon(aCallback);
|
||||
}, false);
|
||||
}
|
||||
|
||||
// ----------
|
||||
function newWindowWithState(aState, aCallback) {
|
||||
let opts = "chrome,all,dialog=no,height=800,width=800";
|
||||
@ -42,8 +34,8 @@ function newWindowWithState(aState, aCallback) {
|
||||
|
||||
registerCleanupFunction(function () win.close());
|
||||
|
||||
whenWindowLoaded(win, function () {
|
||||
ss.setWindowState(win, JSON.stringify(aState), true);
|
||||
executeSoon(function () aCallback(win));
|
||||
whenWindowLoaded(win, function onWindowLoaded(aWin) {
|
||||
ss.setWindowState(aWin, JSON.stringify(aState), true);
|
||||
executeSoon(function () aCallback(aWin));
|
||||
});
|
||||
}
|
||||
|
@ -49,6 +49,28 @@ registerCleanupFunction(function () {
|
||||
// session restore tests to be run standalone without triggering errors.
|
||||
Cc["@mozilla.org/browser/clh;1"].getService(Ci.nsIBrowserHandler).defaultArgs;
|
||||
|
||||
function provideWindow(aCallback, aURL, aFeatures) {
|
||||
function callbackSoon(aWindow) {
|
||||
executeSoon(function executeCallbackSoon() {
|
||||
aCallback(aWindow);
|
||||
});
|
||||
}
|
||||
|
||||
let win = openDialog(getBrowserURL(), "", aFeatures || "chrome,all,dialog=no", aURL);
|
||||
whenWindowLoaded(win, function onWindowLoaded(aWin) {
|
||||
if (!aURL) {
|
||||
info("Loaded a blank window.");
|
||||
callbackSoon(aWin);
|
||||
return;
|
||||
}
|
||||
|
||||
aWin.gBrowser.selectedBrowser.addEventListener("load", function selectedBrowserLoadListener() {
|
||||
aWin.gBrowser.selectedBrowser.removeEventListener("load", selectedBrowserLoadListener, true);
|
||||
callbackSoon(aWin);
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
||||
// This assumes that tests will at least have some state/entries
|
||||
function waitForBrowserState(aState, aSetStateCallback) {
|
||||
let windows = [window];
|
||||
@ -198,6 +220,15 @@ function whenBrowserLoaded(aBrowser, aCallback) {
|
||||
}, true);
|
||||
}
|
||||
|
||||
function whenWindowLoaded(aWindow, aCallback) {
|
||||
aWindow.addEventListener("load", function windowLoadListener() {
|
||||
aWindow.removeEventListener("load", windowLoadListener, false);
|
||||
executeSoon(function executeWhenWindowLoaded() {
|
||||
aCallback(aWindow);
|
||||
});
|
||||
}, false);
|
||||
}
|
||||
|
||||
var gUniqueCounter = 0;
|
||||
function r() {
|
||||
return Date.now() + "-" + (++gUniqueCounter);
|
||||
|
@ -73,4 +73,5 @@ let AllTabs = {
|
||||
#include drag.js
|
||||
#include trench.js
|
||||
#include search.js
|
||||
#include telemetry.js
|
||||
#include ui.js
|
||||
|
63
browser/components/tabview/telemetry.js
Normal file
63
browser/components/tabview/telemetry.js
Normal file
@ -0,0 +1,63 @@
|
||||
/* 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/. */
|
||||
|
||||
/**
|
||||
* Collects telemetry data for Tabview.
|
||||
*/
|
||||
let Telemetry = {
|
||||
TOPIC_GATHER_TELEMETRY: "gather-telemetry",
|
||||
|
||||
/**
|
||||
* Initializes the object.
|
||||
*/
|
||||
init: function Telemetry_init() {
|
||||
Services.obs.addObserver(this, this.TOPIC_GATHER_TELEMETRY, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Uninitializes the object.
|
||||
*/
|
||||
uninit: function Telemetry_uninit() {
|
||||
Services.obs.removeObserver(this, this.TOPIC_GATHER_TELEMETRY);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds telemetry values to gather usage statistics.
|
||||
*/
|
||||
_collect: function Telemetry_collect() {
|
||||
let stackedGroupsCount = 0;
|
||||
let childCounts = [];
|
||||
|
||||
GroupItems.groupItems.forEach(function (groupItem) {
|
||||
if (!groupItem.isEmpty()) {
|
||||
childCounts.push(groupItem.getChildren().length);
|
||||
|
||||
if (groupItem.isStacked())
|
||||
stackedGroupsCount++;
|
||||
}
|
||||
});
|
||||
|
||||
function addTelemetryValue(aId, aValue) {
|
||||
Services.telemetry.getHistogramById("PANORAMA_" + aId).add(aValue);
|
||||
}
|
||||
function median(aChildCounts) {
|
||||
aChildCounts.sort(function(x, y) { return x - y; });
|
||||
let middle = Math.floor(aChildCounts.length / 2);
|
||||
return aChildCounts[middle];
|
||||
}
|
||||
|
||||
addTelemetryValue("GROUPS_COUNT", GroupItems.groupItems.length);
|
||||
addTelemetryValue("STACKED_GROUPS_COUNT", stackedGroupsCount);
|
||||
addTelemetryValue("MEDIAN_TABS_IN_GROUPS_COUNT", median(childCounts));
|
||||
},
|
||||
|
||||
/**
|
||||
* Observes for gather telemetry topic.
|
||||
*/
|
||||
observe: function Telemetry_observe(aSubject, aTopic, aData) {
|
||||
if (!gPrivateBrowsing.privateBrowsingEnabled)
|
||||
this._collect();
|
||||
}
|
||||
}
|
||||
|
@ -173,6 +173,7 @@ _BROWSER_FILES = \
|
||||
browser_tabview_bug716880.js \
|
||||
browser_tabview_bug728887.js \
|
||||
browser_tabview_bug733115.js \
|
||||
browser_tabview_bug749658.js \
|
||||
browser_tabview_click_group.js \
|
||||
browser_tabview_dragdrop.js \
|
||||
browser_tabview_exit_button.js \
|
||||
|
26
browser/components/tabview/test/browser_tabview_bug749658.js
Normal file
26
browser/components/tabview/test/browser_tabview_bug749658.js
Normal file
@ -0,0 +1,26 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
let win;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
newWindowWithTabView(function(newWin) {
|
||||
win = newWin;
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
win.close();
|
||||
});
|
||||
|
||||
is(win.gBrowser.tabContainer.getAttribute("overflow"), "",
|
||||
"The tabstrip should not be overflowing");
|
||||
|
||||
finish();
|
||||
}, function(newWin) {
|
||||
/* add a tab with a ridiculously long title to trigger bug 749658 */
|
||||
var longTitle = "this is a very long title for the new tab ";
|
||||
longTitle = longTitle + longTitle + longTitle + longTitle + longTitle;
|
||||
longTitle = longTitle + longTitle + longTitle + longTitle + longTitle;
|
||||
newWin.gBrowser.addTab("data:text/html,<head><title>" + longTitle);
|
||||
});
|
||||
}
|
@ -171,6 +171,8 @@ let UI = {
|
||||
// ___ search
|
||||
Search.init();
|
||||
|
||||
Telemetry.init();
|
||||
|
||||
// ___ currentTab
|
||||
this._currentTab = gBrowser.selectedTab;
|
||||
|
||||
@ -312,6 +314,7 @@ let UI = {
|
||||
GroupItems.uninit();
|
||||
FavIcons.uninit();
|
||||
Storage.uninit();
|
||||
Telemetry.uninit();
|
||||
|
||||
this._removeTabActionHandlers();
|
||||
this._currentTab = null;
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
let EXPORTED_SYMBOLS = ["PageThumbs", "PageThumbsCache"];
|
||||
let EXPORTED_SYMBOLS = ["PageThumbs", "PageThumbsStorage", "PageThumbsCache"];
|
||||
|
||||
const Cu = Components.utils;
|
||||
const Cc = Components.classes;
|
||||
@ -12,6 +12,11 @@ const Ci = Components.interfaces;
|
||||
|
||||
const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
|
||||
|
||||
/**
|
||||
* Name of the directory in the profile that contains the thumbnails.
|
||||
*/
|
||||
const THUMBNAIL_DIRECTORY = "thumbnails";
|
||||
|
||||
/**
|
||||
* The default background color for page thumbnails.
|
||||
*/
|
||||
@ -25,11 +30,29 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gCryptoHash", function () {
|
||||
return Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gUnicodeConverter", function () {
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
converter.charset = 'utf8';
|
||||
return converter;
|
||||
});
|
||||
|
||||
/**
|
||||
* Singleton providing functionality for capturing web page thumbnails and for
|
||||
* accessing them if already cached.
|
||||
*/
|
||||
let PageThumbs = {
|
||||
_initialized: false,
|
||||
|
||||
/**
|
||||
* The calculated width and height of the thumbnails.
|
||||
@ -52,6 +75,20 @@ let PageThumbs = {
|
||||
*/
|
||||
get contentType() "image/png",
|
||||
|
||||
init: function PageThumbs_init() {
|
||||
if (!this._initialized) {
|
||||
this._initialized = true;
|
||||
PlacesUtils.history.addObserver(PageThumbsHistoryObserver, false);
|
||||
}
|
||||
},
|
||||
|
||||
uninit: function PageThumbs_uninit() {
|
||||
if (this._initialized) {
|
||||
this._initialized = false;
|
||||
PlacesUtils.history.removeObserver(PageThumbsHistoryObserver);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the thumbnail image's url for a given web page's url.
|
||||
* @param aUrl The web page's url that is depicted in the thumbnail.
|
||||
@ -124,32 +161,14 @@ let PageThumbs = {
|
||||
// Sync and therefore also redirect sources appear on the newtab
|
||||
// page. We also want thumbnails for those.
|
||||
if (url != originalURL)
|
||||
PageThumbsCache._copy(url, originalURL);
|
||||
PageThumbsStorage.copy(url, originalURL);
|
||||
}
|
||||
|
||||
if (aCallback)
|
||||
aCallback(aSuccessful);
|
||||
}
|
||||
|
||||
// Get a writeable cache entry.
|
||||
PageThumbsCache.getWriteEntry(url, function (aEntry) {
|
||||
if (!aEntry) {
|
||||
finish(false);
|
||||
return;
|
||||
}
|
||||
|
||||
let outputStream = aEntry.openOutputStream(0);
|
||||
|
||||
// Write the image data to the cache entry.
|
||||
NetUtil.asyncCopy(aInputStream, outputStream, function (aResult) {
|
||||
let success = Components.isSuccessCode(aResult);
|
||||
if (success)
|
||||
aEntry.markValid();
|
||||
|
||||
aEntry.close();
|
||||
finish(success);
|
||||
});
|
||||
});
|
||||
PageThumbsStorage.write(url, aInputStream, finish);
|
||||
});
|
||||
},
|
||||
|
||||
@ -197,7 +216,7 @@ let PageThumbs = {
|
||||
*/
|
||||
_getThumbnailSize: function PageThumbs_getThumbnailSize() {
|
||||
if (!this._thumbnailWidth || !this._thumbnailHeight) {
|
||||
let screenManager = Cc["@mozilla.org/gfx/screenmanager;1"]
|
||||
let screenManager = Cc["@mozilla.org/gfx/screenmanager;1"]
|
||||
.getService(Ci.nsIScreenManager);
|
||||
let left = {}, top = {}, width = {}, height = {};
|
||||
screenManager.primaryScreen.GetRect(left, top, width, height);
|
||||
@ -208,6 +227,88 @@ let PageThumbs = {
|
||||
}
|
||||
};
|
||||
|
||||
let PageThumbsStorage = {
|
||||
getFileForURL: function Storage_getFileForURL(aURL) {
|
||||
let hash = this._calculateMD5Hash(aURL);
|
||||
let parts = [THUMBNAIL_DIRECTORY, hash[0], hash[1], hash.slice(2) + ".png"];
|
||||
return FileUtils.getFile("ProfD", parts);
|
||||
},
|
||||
|
||||
write: function Storage_write(aURL, aDataStream, aCallback) {
|
||||
let file = this.getFileForURL(aURL);
|
||||
let fos = FileUtils.openSafeFileOutputStream(file);
|
||||
|
||||
NetUtil.asyncCopy(aDataStream, fos, function (aResult) {
|
||||
FileUtils.closeSafeFileOutputStream(fos);
|
||||
aCallback(Components.isSuccessCode(aResult));
|
||||
});
|
||||
},
|
||||
|
||||
copy: function Storage_copy(aSourceURL, aTargetURL) {
|
||||
let sourceFile = this.getFileForURL(aSourceURL);
|
||||
let targetFile = this.getFileForURL(aTargetURL);
|
||||
|
||||
try {
|
||||
sourceFile.copyTo(targetFile.parent, targetFile.leafName);
|
||||
} catch (e) {
|
||||
/* We might not be permitted to write to the file. */
|
||||
}
|
||||
},
|
||||
|
||||
remove: function Storage_remove(aURL) {
|
||||
try {
|
||||
this.getFileForURL(aURL).remove(false);
|
||||
} catch (e) {
|
||||
/* The file might not exist or we're not permitted to remove it. */
|
||||
}
|
||||
},
|
||||
|
||||
wipe: function Storage_wipe() {
|
||||
try {
|
||||
FileUtils.getDir("ProfD", [THUMBNAIL_DIRECTORY]).remove(true);
|
||||
} catch (e) {
|
||||
/* The file might not exist or we're not permitted to remove it. */
|
||||
}
|
||||
},
|
||||
|
||||
_calculateMD5Hash: function Storage_calculateMD5Hash(aValue) {
|
||||
let hash = gCryptoHash;
|
||||
let value = gUnicodeConverter.convertToByteArray(aValue);
|
||||
|
||||
hash.init(hash.MD5);
|
||||
hash.update(value, value.length);
|
||||
return this._convertToHexString(hash.finish(false));
|
||||
},
|
||||
|
||||
_convertToHexString: function Storage_convertToHexString(aData) {
|
||||
let hex = "";
|
||||
for (let i = 0; i < aData.length; i++)
|
||||
hex += ("0" + aData.charCodeAt(i).toString(16)).slice(-2);
|
||||
return hex;
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
let PageThumbsHistoryObserver = {
|
||||
onDeleteURI: function Thumbnails_onDeleteURI(aURI, aGUID) {
|
||||
PageThumbsStorage.remove(aURI.spec);
|
||||
},
|
||||
|
||||
onClearHistory: function Thumbnails_onClearHistory() {
|
||||
PageThumbsStorage.wipe();
|
||||
},
|
||||
|
||||
onTitleChanged: function () {},
|
||||
onBeginUpdateBatch: function () {},
|
||||
onEndUpdateBatch: function () {},
|
||||
onVisit: function () {},
|
||||
onBeforeDeleteURI: function () {},
|
||||
onPageChanged: function () {},
|
||||
onDeleteVisits: function () {},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver])
|
||||
};
|
||||
|
||||
/**
|
||||
* A singleton handling the storage of page thumbnails.
|
||||
*/
|
||||
@ -222,64 +323,6 @@ let PageThumbsCache = {
|
||||
this._openCacheEntry(aKey, Ci.nsICache.ACCESS_READ, aCallback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Calls the given callback with a cache entry opened for writing.
|
||||
* @param aKey The key identifying the desired cache entry.
|
||||
* @param aCallback The callback that is called when the cache entry is ready.
|
||||
*/
|
||||
getWriteEntry: function Cache_getWriteEntry(aKey, aCallback) {
|
||||
// Try to open the desired cache entry.
|
||||
this._openCacheEntry(aKey, Ci.nsICache.ACCESS_WRITE, aCallback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Copies an existing cache entry's data to a new cache entry.
|
||||
* @param aSourceKey The key that contains the data to copy.
|
||||
* @param aTargetKey The key that will be the copy of aSourceKey's data.
|
||||
*/
|
||||
_copy: function Cache_copy(aSourceKey, aTargetKey) {
|
||||
let sourceEntry, targetEntry, waitingCount = 2;
|
||||
|
||||
function finish() {
|
||||
if (sourceEntry)
|
||||
sourceEntry.close();
|
||||
|
||||
if (targetEntry)
|
||||
targetEntry.close();
|
||||
}
|
||||
|
||||
function copyDataWhenReady() {
|
||||
if (--waitingCount > 0)
|
||||
return;
|
||||
|
||||
if (!sourceEntry || !targetEntry) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
let inputStream = sourceEntry.openInputStream(0);
|
||||
let outputStream = targetEntry.openOutputStream(0);
|
||||
|
||||
// Copy the image data to a new entry.
|
||||
NetUtil.asyncCopy(inputStream, outputStream, function (aResult) {
|
||||
if (Components.isSuccessCode(aResult))
|
||||
targetEntry.markValid();
|
||||
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
this.getReadEntry(aSourceKey, function (aSourceEntry) {
|
||||
sourceEntry = aSourceEntry;
|
||||
copyDataWhenReady();
|
||||
});
|
||||
|
||||
this.getWriteEntry(aTargetKey, function (aTargetEntry) {
|
||||
targetEntry = aTargetEntry;
|
||||
copyDataWhenReady();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Opens the cache entry identified by the given key.
|
||||
* @param aKey The key identifying the desired cache entry.
|
||||
|
@ -72,6 +72,14 @@ Protocol.prototype = {
|
||||
* @return The newly created channel.
|
||||
*/
|
||||
newChannel: function Proto_newChannel(aURI) {
|
||||
let {url} = parseURI(aURI);
|
||||
let file = PageThumbsStorage.getFileForURL(url);
|
||||
|
||||
if (file.exists()) {
|
||||
let fileuri = Services.io.newFileURI(file);
|
||||
return Services.io.newChannelFromURI(fileuri);
|
||||
}
|
||||
|
||||
return new Channel(aURI);
|
||||
},
|
||||
|
||||
|
@ -14,6 +14,7 @@ include $(topsrcdir)/config/rules.mk
|
||||
_BROWSER_FILES = \
|
||||
browser_thumbnails_capture.js \
|
||||
browser_thumbnails_redirect.js \
|
||||
browser_thumbnails_storage.js \
|
||||
browser_thumbnails_bug726727.js \
|
||||
head.js \
|
||||
background_red.html \
|
||||
|
@ -4,9 +4,6 @@
|
||||
const URL = "http://mochi.test:8888/browser/browser/components/thumbnails/" +
|
||||
"test/background_red_redirect.sjs";
|
||||
|
||||
let cacheService = Cc["@mozilla.org/network/cache-service;1"]
|
||||
.getService(Ci.nsICacheService);
|
||||
|
||||
/**
|
||||
* These tests ensure that we save and provide thumbnails for redirecting sites.
|
||||
*/
|
||||
@ -19,33 +16,17 @@ function runTests() {
|
||||
yield addTab(URL);
|
||||
yield captureAndCheckColor(255, 0, 0, "we have a red thumbnail");
|
||||
|
||||
// Wait until the referrer's thumbnail's cache entry has been written.
|
||||
yield whenCacheEntryExists(URL);
|
||||
// Wait until the referrer's thumbnail's file has been written.
|
||||
yield whenFileExists(URL);
|
||||
yield checkThumbnailColor(URL, 255, 0, 0, "referrer has a red thumbnail");
|
||||
}
|
||||
|
||||
function whenCacheEntryExists(aKey) {
|
||||
function whenFileExists(aURL) {
|
||||
let callback = next;
|
||||
|
||||
checkCacheEntryExists(aKey, function (aExists) {
|
||||
if (!aExists)
|
||||
callback = function () whenCacheEntryExists(aKey);
|
||||
let file = PageThumbsStorage.getFileForURL(aURL);
|
||||
if (!file.exists())
|
||||
callback = function () whenFileExists(aURL);
|
||||
|
||||
executeSoon(callback);
|
||||
});
|
||||
}
|
||||
|
||||
function checkCacheEntryExists(aKey, aCallback) {
|
||||
PageThumbsCache.getReadEntry(aKey, function (aEntry) {
|
||||
let inputStream = aEntry && aEntry.openInputStream(0);
|
||||
let exists = inputStream && inputStream.available();
|
||||
|
||||
if (inputStream)
|
||||
inputStream.close();
|
||||
|
||||
if (aEntry)
|
||||
aEntry.close();
|
||||
|
||||
aCallback(exists);
|
||||
});
|
||||
executeSoon(callback);
|
||||
}
|
||||
|
@ -0,0 +1,89 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const URL = "http://mochi.test:8888/";
|
||||
const URL_COPY = URL + "#copy";
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "Sanitizer", function () {
|
||||
let tmp = {};
|
||||
Cc["@mozilla.org/moz/jssubscript-loader;1"]
|
||||
.getService(Ci.mozIJSSubScriptLoader)
|
||||
.loadSubScript("chrome://browser/content/sanitize.js", tmp);
|
||||
return tmp.Sanitizer;
|
||||
});
|
||||
|
||||
/**
|
||||
* These tests ensure that the thumbnail storage is working as intended.
|
||||
* Newly captured thumbnails should be saved as files and they should as well
|
||||
* be removed when the user sanitizes their history.
|
||||
*/
|
||||
function runTests() {
|
||||
clearHistory();
|
||||
|
||||
// create a thumbnail
|
||||
yield addTab(URL);
|
||||
yield whenFileExists();
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
|
||||
// clear all browser history
|
||||
yield clearHistory();
|
||||
|
||||
// create a thumbnail
|
||||
yield addTab(URL);
|
||||
yield whenFileExists();
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
|
||||
// make sure copy() updates an existing file
|
||||
PageThumbsStorage.copy(URL, URL_COPY);
|
||||
let copy = PageThumbsStorage.getFileForURL(URL_COPY);
|
||||
let mtime = copy.lastModifiedTime -= 60;
|
||||
|
||||
PageThumbsStorage.copy(URL, URL_COPY);
|
||||
isnot(PageThumbsStorage.getFileForURL(URL_COPY).lastModifiedTime, mtime,
|
||||
"thumbnail file was updated");
|
||||
|
||||
// clear last 10 mins of history
|
||||
yield clearHistory(true);
|
||||
ok(!copy.exists(), "copy of thumbnail has been removed");
|
||||
}
|
||||
|
||||
function clearHistory(aUseRange) {
|
||||
let s = new Sanitizer();
|
||||
s.prefDomain = "privacy.cpd.";
|
||||
|
||||
let prefs = gPrefService.getBranch(s.prefDomain);
|
||||
prefs.setBoolPref("history", true);
|
||||
prefs.setBoolPref("downloads", false);
|
||||
prefs.setBoolPref("cache", false);
|
||||
prefs.setBoolPref("cookies", false);
|
||||
prefs.setBoolPref("formdata", false);
|
||||
prefs.setBoolPref("offlineApps", false);
|
||||
prefs.setBoolPref("passwords", false);
|
||||
prefs.setBoolPref("sessions", false);
|
||||
prefs.setBoolPref("siteSettings", false);
|
||||
|
||||
if (aUseRange) {
|
||||
let usec = Date.now() * 1000;
|
||||
s.range = [usec - 10 * 60 * 1000 * 1000, usec];
|
||||
}
|
||||
|
||||
s.sanitize();
|
||||
s.range = null;
|
||||
|
||||
executeSoon(function () {
|
||||
if (PageThumbsStorage.getFileForURL(URL).exists())
|
||||
clearHistory(aFile, aUseRange);
|
||||
else
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
function whenFileExists() {
|
||||
let callback = whenFileExists;
|
||||
|
||||
let file = PageThumbsStorage.getFileForURL(URL);
|
||||
if (file.exists() && file.fileSize)
|
||||
callback = next;
|
||||
|
||||
executeSoon(callback);
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
let tmp = {};
|
||||
Cu.import("resource:///modules/PageThumbs.jsm", tmp);
|
||||
let PageThumbs = tmp.PageThumbs;
|
||||
let PageThumbsCache = tmp.PageThumbsCache;
|
||||
let PageThumbsStorage = tmp.PageThumbsStorage;
|
||||
|
||||
registerCleanupFunction(function () {
|
||||
while (gBrowser.tabs.length > 1)
|
||||
|
@ -45,13 +45,7 @@ const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
const DBG_XUL = "chrome://browser/content/debugger.xul";
|
||||
const REMOTE_PROFILE_NAME = "_remote-debug";
|
||||
|
||||
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
let EXPORTED_SYMBOLS = ["DebuggerUI"];
|
||||
|
||||
@ -66,20 +60,6 @@ function DebuggerUI(aWindow) {
|
||||
}
|
||||
|
||||
DebuggerUI.prototype = {
|
||||
/**
|
||||
* Called by the DebuggerPane to update the Debugger toggle switches with the
|
||||
* debugger state.
|
||||
*/
|
||||
refreshCommand: function DUI_refreshCommand() {
|
||||
let selectedTab = this.chromeWindow.getBrowser().selectedTab;
|
||||
let command = this.chromeWindow.document.getElementById("Tools:Debugger");
|
||||
|
||||
if (this.getDebugger(selectedTab) != null) {
|
||||
command.setAttribute("checked", "true");
|
||||
} else {
|
||||
command.removeAttribute("checked");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts a debugger for the current tab, or stops it if already started.
|
||||
@ -92,22 +72,7 @@ DebuggerUI.prototype = {
|
||||
tab._scriptDebugger.close();
|
||||
return null;
|
||||
}
|
||||
return new DebuggerPane(this, tab);
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts a remote debugger in a new process, or stops it if already started.
|
||||
* @see DebuggerProcess.constructor
|
||||
* @return DebuggerProcess if the debugger is started, null if it's stopped.
|
||||
*/
|
||||
toggleRemoteDebugger: function DUI_toggleRemoteDebugger(aOnClose, aOnRun) {
|
||||
let win = this.chromeWindow;
|
||||
|
||||
if (win._remoteDebugger) {
|
||||
win._remoteDebugger.close();
|
||||
return null;
|
||||
}
|
||||
return new DebuggerProcess(win, aOnClose, aOnRun);
|
||||
return new DebuggerPane(tab);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -115,7 +80,7 @@ DebuggerUI.prototype = {
|
||||
* @return DebuggerPane if a debugger exists for the tab, null otherwise
|
||||
*/
|
||||
getDebugger: function DUI_getDebugger(aTab) {
|
||||
return '_scriptDebugger' in aTab ? aTab._scriptDebugger : null;
|
||||
return aTab._scriptDebugger;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -123,7 +88,7 @@ DebuggerUI.prototype = {
|
||||
* @return object
|
||||
*/
|
||||
get preferences() {
|
||||
return DebuggerPreferences;
|
||||
return DebuggerUIPreferences;
|
||||
}
|
||||
};
|
||||
|
||||
@ -133,25 +98,13 @@ DebuggerUI.prototype = {
|
||||
* @param XULElement aTab
|
||||
* The tab in which to create the debugger.
|
||||
*/
|
||||
function DebuggerPane(aDebuggerUI, aTab) {
|
||||
this._globalUI = aDebuggerUI;
|
||||
function DebuggerPane(aTab) {
|
||||
this._tab = aTab;
|
||||
this._initServer();
|
||||
this._create();
|
||||
}
|
||||
|
||||
DebuggerPane.prototype = {
|
||||
|
||||
/**
|
||||
* Initializes the debugger server.
|
||||
*/
|
||||
_initServer: function DP__initServer() {
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates and initializes the widgets containing the debugger UI.
|
||||
*/
|
||||
@ -165,7 +118,7 @@ DebuggerPane.prototype = {
|
||||
this._splitter.setAttribute("class", "hud-splitter");
|
||||
|
||||
this._frame = ownerDocument.createElement("iframe");
|
||||
this._frame.height = DebuggerPreferences.height;
|
||||
this._frame.height = DebuggerUIPreferences.height;
|
||||
|
||||
this._nbox = gBrowser.getNotificationBox(this._tab.linkedBrowser);
|
||||
this._nbox.appendChild(this._splitter);
|
||||
@ -186,9 +139,7 @@ DebuggerPane.prototype = {
|
||||
self.getBreakpoint = bkp.getBreakpoint;
|
||||
}, true);
|
||||
|
||||
this._frame.setAttribute("src", DBG_XUL);
|
||||
|
||||
this._globalUI.refreshCommand();
|
||||
this._frame.setAttribute("src", "chrome://browser/content/debugger.xul");
|
||||
},
|
||||
|
||||
/**
|
||||
@ -198,10 +149,10 @@ DebuggerPane.prototype = {
|
||||
if (!this._tab) {
|
||||
return;
|
||||
}
|
||||
delete this._tab._scriptDebugger;
|
||||
this._tab._scriptDebugger = null;
|
||||
this._tab = null;
|
||||
|
||||
DebuggerPreferences.height = this._frame.height;
|
||||
DebuggerUIPreferences.height = this._frame.height;
|
||||
this._frame.removeEventListener("Debugger:Close", this.close, true);
|
||||
this._frame.removeEventListener("unload", this.close, true);
|
||||
|
||||
@ -211,8 +162,6 @@ DebuggerPane.prototype = {
|
||||
this._splitter = null;
|
||||
this._frame = null;
|
||||
this._nbox = null;
|
||||
|
||||
this._globalUI.refreshCommand();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -237,112 +186,9 @@ DebuggerPane.prototype = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a process that will hold the remote debugger.
|
||||
*
|
||||
* @param function aOnClose
|
||||
* Optional, a function called when the process exits.
|
||||
* @param function aOnRun
|
||||
* Optional, a function called when the process starts running.
|
||||
* @param nsIDOMWindow aWindow
|
||||
* The chrome window for which the remote debugger instance is created.
|
||||
* Various debugger UI preferences (currently just the pane height).
|
||||
*/
|
||||
function DebuggerProcess(aWindow, aOnClose, aOnRun) {
|
||||
this._win = aWindow;
|
||||
this._closeCallback = aOnClose;
|
||||
this._runCallback = aOnRun;
|
||||
this._initProfile();
|
||||
this._create();
|
||||
}
|
||||
|
||||
DebuggerProcess.prototype = {
|
||||
|
||||
/**
|
||||
* Initializes the debugger server.
|
||||
*/
|
||||
_initServer: function RDP__initServer() {
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
DebuggerServer.closeListener();
|
||||
DebuggerServer.openListener(DebuggerPreferences.remotePort, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes a profile for the remote debugger process.
|
||||
*/
|
||||
_initProfile: function RDP__initProfile() {
|
||||
let profileService = Cc["@mozilla.org/toolkit/profile-service;1"]
|
||||
.createInstance(Ci.nsIToolkitProfileService);
|
||||
|
||||
let dbgProfileName;
|
||||
try {
|
||||
dbgProfileName = profileService.selectedProfile.name + REMOTE_PROFILE_NAME;
|
||||
} catch(e) {
|
||||
dbgProfileName = REMOTE_PROFILE_NAME;
|
||||
Cu.reportError(e);
|
||||
}
|
||||
|
||||
this._dbgProfile = profileService.createProfile(null, null, dbgProfileName);
|
||||
profileService.flush();
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates and initializes the profile & process for the remote debugger.
|
||||
*/
|
||||
_create: function RDP__create() {
|
||||
this._win._remoteDebugger = this;
|
||||
|
||||
let file = FileUtils.getFile("CurProcD",
|
||||
[Services.appinfo.OS == "WINNT" ? "firefox.exe"
|
||||
: "firefox-bin"]);
|
||||
|
||||
let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
|
||||
process.init(file);
|
||||
|
||||
let args = [
|
||||
"-no-remote", "-P", this._dbgProfile.name,
|
||||
"-chrome", DBG_XUL,
|
||||
"-width", DebuggerPreferences.remoteWinWidth,
|
||||
"-height", DebuggerPreferences.remoteWinHeight];
|
||||
|
||||
process.runwAsync(args, args.length, { observe: this.close.bind(this) });
|
||||
this._dbgProcess = process;
|
||||
|
||||
if (typeof this._runCallback === "function") {
|
||||
this._runCallback.call({}, this);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Closes the remote debugger, removing the profile and killing the process.
|
||||
*/
|
||||
close: function RDP_close() {
|
||||
if (!this._win) {
|
||||
return;
|
||||
}
|
||||
delete this._win._remoteDebugger;
|
||||
this._win = null;
|
||||
|
||||
if (this._dbgProcess.isRunning) {
|
||||
this._dbgProcess.kill();
|
||||
}
|
||||
if (this._dbgProfile) {
|
||||
this._dbgProfile.remove(false);
|
||||
}
|
||||
if (typeof this._closeCallback === "function") {
|
||||
this._closeCallback.call({}, this);
|
||||
}
|
||||
|
||||
this._dbgProcess = null;
|
||||
this._dbgProfile = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Various debugger preferences.
|
||||
*/
|
||||
let DebuggerPreferences = {
|
||||
let DebuggerUIPreferences = {
|
||||
|
||||
/**
|
||||
* Gets the preferred height of the debugger pane.
|
||||
@ -364,35 +210,3 @@ let DebuggerPreferences = {
|
||||
this._height = value;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the preferred width of the remote debugger window.
|
||||
* @return number
|
||||
*/
|
||||
XPCOMUtils.defineLazyGetter(DebuggerPreferences, "remoteWinWidth", function() {
|
||||
return Services.prefs.getIntPref("devtools.debugger.ui.remote-win.width");
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets the preferred height of the remote debugger window.
|
||||
* @return number
|
||||
*/
|
||||
XPCOMUtils.defineLazyGetter(DebuggerPreferences, "remoteWinHeight", function() {
|
||||
return Services.prefs.getIntPref("devtools.debugger.ui.remote-win.height");
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets the preferred default remote debugging host.
|
||||
* @return string
|
||||
*/
|
||||
XPCOMUtils.defineLazyGetter(DebuggerPreferences, "remoteHost", function() {
|
||||
return Services.prefs.getCharPref("devtools.debugger.remote-host");
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets the preferred default remote debugging port.
|
||||
* @return number
|
||||
*/
|
||||
XPCOMUtils.defineLazyGetter(DebuggerPreferences, "remotePort", function() {
|
||||
return Services.prefs.getIntPref("devtools.debugger.remote-port");
|
||||
});
|
||||
|
@ -114,7 +114,6 @@ let DebuggerController = {
|
||||
|
||||
this.dispatchEvent("Debugger:Unloaded");
|
||||
this._disconnect();
|
||||
this._isRemote && this._quitApp();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -122,10 +121,12 @@ let DebuggerController = {
|
||||
* wiring event handlers as necessary.
|
||||
*/
|
||||
_connect: function DC__connect() {
|
||||
let transport =
|
||||
this._isRemote ? debuggerSocketConnect(Prefs.remoteHost, Prefs.remotePort)
|
||||
: DebuggerServer.connectPipe();
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
let client = this.client = new DebuggerClient(transport);
|
||||
|
||||
client.addListener("tabNavigated", this._onTabNavigated);
|
||||
@ -219,31 +220,6 @@ let DebuggerController = {
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if this is a remote debugger instance.
|
||||
* @return boolean
|
||||
*/
|
||||
get _isRemote() {
|
||||
return !window.parent.content;
|
||||
},
|
||||
|
||||
/**
|
||||
* Attempts to quit the current process if allowed.
|
||||
*/
|
||||
_quitApp: function DC__quitApp() {
|
||||
let canceled = Cc["@mozilla.org/supports-PRBool;1"]
|
||||
.createInstance(Ci.nsISupportsPRBool);
|
||||
|
||||
Services.obs.notifyObservers(canceled, "quit-application-requested", null);
|
||||
|
||||
// Somebody canceled our quit request.
|
||||
if (canceled.data) {
|
||||
return;
|
||||
}
|
||||
|
||||
Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit);
|
||||
},
|
||||
|
||||
/**
|
||||
* Convenience method, dispatching a custom event.
|
||||
*
|
||||
@ -494,38 +470,6 @@ StackFrames.prototype = {
|
||||
this._addExpander(thisVar, frame.this);
|
||||
}
|
||||
|
||||
if (frame.environment) {
|
||||
// Add nodes for every argument.
|
||||
let variables = frame.environment.bindings.arguments;
|
||||
for each (let variable in variables) {
|
||||
let name = Object.getOwnPropertyNames(variable)[0];
|
||||
let paramVar = localScope.addVar(name);
|
||||
let paramVal = variable[name].value;
|
||||
paramVar.setGrip(paramVal);
|
||||
this._addExpander(paramVar, paramVal);
|
||||
}
|
||||
|
||||
// Add nodes for every other variable in scope.
|
||||
variables = frame.environment.bindings.variables;
|
||||
for (let variable in variables) {
|
||||
let paramVar = localScope.addVar(variable);
|
||||
let paramVal = variables[variable].value;
|
||||
paramVar.setGrip(paramVal);
|
||||
this._addExpander(paramVar, paramVal);
|
||||
}
|
||||
|
||||
// If we already found 'arguments', we are done here.
|
||||
if ("arguments" in frame.environment.bindings.variables) {
|
||||
// Signal that variables have been fetched.
|
||||
DebuggerController.dispatchEvent("Debugger:FetchedVariables");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Sometimes in call frames with arguments we don't get 'arguments' in the
|
||||
// environment (bug 746601) and we have to construct it manually. Note, that
|
||||
// in this case arguments.callee will be absent, even in the cases where it
|
||||
// shouldn't be.
|
||||
if (frame.arguments && frame.arguments.length > 0) {
|
||||
// Add "arguments".
|
||||
let argsVar = localScope.addVar("arguments");
|
||||
@ -535,20 +479,33 @@ StackFrames.prototype = {
|
||||
});
|
||||
this._addExpander(argsVar, frame.arguments);
|
||||
|
||||
// Signal that variables have been fetched.
|
||||
DebuggerController.dispatchEvent("Debugger:FetchedVariables");
|
||||
}
|
||||
// Add variables for every argument.
|
||||
let objClient = this.activeThread.pauseGrip(frame.callee);
|
||||
objClient.getSignature(function SF_getSignature(aResponse) {
|
||||
for (let i = 0, l = aResponse.parameters.length; i < l; i++) {
|
||||
let param = aResponse.parameters[i];
|
||||
let paramVar = localScope.addVar(param);
|
||||
let paramVal = frame.arguments[i];
|
||||
|
||||
paramVar.setGrip(paramVal);
|
||||
this._addExpander(paramVar, paramVal);
|
||||
}
|
||||
|
||||
// Signal that call parameters have been fetched.
|
||||
DebuggerController.dispatchEvent("Debugger:FetchedParameters");
|
||||
|
||||
}.bind(this));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds an 'onexpand' callback for a variable, lazily handling the addition of
|
||||
* Adds a onexpand callback for a variable, lazily handling the addition of
|
||||
* new properties.
|
||||
*/
|
||||
_addExpander: function SF__addExpander(aVar, aObject) {
|
||||
// No need for expansion for null and undefined values, but we do need them
|
||||
// for frame.arguments which is a regular array.
|
||||
if (!aVar || !aObject || typeof aObject !== "object" ||
|
||||
if (!aObject || typeof aObject !== "object" ||
|
||||
(aObject.type !== "object" && !Array.isArray(aObject))) {
|
||||
return;
|
||||
}
|
||||
@ -729,7 +686,7 @@ SourceScripts.prototype = {
|
||||
* Handler for the debugger client's unsolicited newScript notification.
|
||||
*/
|
||||
_onNewScript: function SS__onNewScript(aNotification, aPacket) {
|
||||
this._addScript({ url: aPacket.url, startLine: aPacket.startLine }, true);
|
||||
this._addScript({ url: aPacket.url, startLine: aPacket.startLine });
|
||||
},
|
||||
|
||||
/**
|
||||
@ -737,9 +694,8 @@ SourceScripts.prototype = {
|
||||
*/
|
||||
_onScriptsAdded: function SS__onScriptsAdded() {
|
||||
for each (let script in this.activeThread.cachedScripts) {
|
||||
this._addScript(script, false);
|
||||
this._addScript(script);
|
||||
}
|
||||
DebuggerView.Scripts.commitScripts();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -791,22 +747,6 @@ SourceScripts.prototype = {
|
||||
return aUrl;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the prePath for a script URL.
|
||||
*
|
||||
* @param string aUrl
|
||||
* The script url.
|
||||
* @return string
|
||||
* The script prePath if the url is valid, null otherwise.
|
||||
*/
|
||||
_getScriptPrePath: function SS__getScriptDomain(aUrl) {
|
||||
try {
|
||||
return Services.io.newURI(aUrl, null, null).prePath + "/";
|
||||
} catch (e) {
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets a unique, simplified label from a script url.
|
||||
* ex: a). ici://some.address.com/random/subrandom/
|
||||
@ -823,7 +763,7 @@ SourceScripts.prototype = {
|
||||
* The script url.
|
||||
* @param string aHref
|
||||
* The content location href to be used. If unspecified, it will
|
||||
* default to the script url prepath.
|
||||
* defalult to debugged panrent window location.
|
||||
* @return string
|
||||
* The simplified label.
|
||||
*/
|
||||
@ -834,18 +774,15 @@ SourceScripts.prototype = {
|
||||
return this._labelsCache[url];
|
||||
}
|
||||
|
||||
let content = window.parent.content;
|
||||
let domain = content ? content.location.href : this._getScriptPrePath(aUrl);
|
||||
|
||||
let href = aHref || domain;
|
||||
let href = aHref || window.parent.content.location.href;
|
||||
let pathElements = url.split("/");
|
||||
let label = pathElements.pop() || (pathElements.pop() + "/");
|
||||
|
||||
// If the label as a leaf name is already present in the scripts list.
|
||||
// if the label as a leaf name is alreay present in the scripts list
|
||||
if (DebuggerView.Scripts.containsLabel(label)) {
|
||||
label = url.replace(href.substring(0, href.lastIndexOf("/") + 1), "");
|
||||
|
||||
// If the path/to/script is exactly the same, we're in different domains.
|
||||
// if the path/to/script is exactly the same, we're in different domains
|
||||
if (DebuggerView.Scripts.containsLabel(label)) {
|
||||
label = url;
|
||||
}
|
||||
@ -863,16 +800,15 @@ SourceScripts.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the specified script to the list.
|
||||
*
|
||||
* @param object aScript
|
||||
* The script object coming from the active thread.
|
||||
* @param boolean aForceFlag
|
||||
* True to force the script to be immediately added.
|
||||
* Add the specified script to the list and display it in the editor if the
|
||||
* editor is empty.
|
||||
*/
|
||||
_addScript: function SS__addScript(aScript, aForceFlag) {
|
||||
DebuggerView.Scripts.addScript(
|
||||
this._getScriptLabel(aScript.url), aScript, aForceFlag);
|
||||
_addScript: function SS__addScript(aScript) {
|
||||
DebuggerView.Scripts.addScript(this._getScriptLabel(aScript.url), aScript);
|
||||
|
||||
if (DebuggerView.editor.getCharCount() == 0) {
|
||||
this.showScript(aScript);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -940,7 +876,7 @@ SourceScripts.prototype = {
|
||||
* Handles notifications to load a source script from the cache or from a
|
||||
* local file.
|
||||
*
|
||||
* XXX: It may be better to use nsITraceableChannel to get to the sources
|
||||
* XXX: Tt may be better to use nsITraceableChannel to get to the sources
|
||||
* without relying on caching when we can (not for eval, etc.):
|
||||
* http://www.softwareishard.com/blog/firebug/nsitraceablechannel-intercept-http-traffic/
|
||||
*/
|
||||
@ -1031,7 +967,7 @@ SourceScripts.prototype = {
|
||||
* The failure status code.
|
||||
*/
|
||||
_logError: function SS__logError(aUrl, aStatus) {
|
||||
Cu.reportError(L10N.getFormatStr("loadingError", [aUrl, aStatus]));
|
||||
Components.utils.reportError(L10N.getFormatStr("loadingError", [aUrl, aStatus]));
|
||||
},
|
||||
};
|
||||
|
||||
@ -1322,27 +1258,6 @@ XPCOMUtils.defineLazyGetter(L10N, "stringBundle", function() {
|
||||
return Services.strings.createBundle(DBG_STRINGS_URI);
|
||||
});
|
||||
|
||||
/**
|
||||
* Shortcuts for accessing various debugger preferences.
|
||||
*/
|
||||
let Prefs = {};
|
||||
|
||||
/**
|
||||
* Gets the preferred default remote debugging host.
|
||||
* @return string
|
||||
*/
|
||||
XPCOMUtils.defineLazyGetter(Prefs, "remoteHost", function() {
|
||||
return Services.prefs.getCharPref("devtools.debugger.remote-host");
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets the preferred default remote debugging port.
|
||||
* @return number
|
||||
*/
|
||||
XPCOMUtils.defineLazyGetter(Prefs, "remotePort", function() {
|
||||
return Services.prefs.getIntPref("devtools.debugger.remote-port");
|
||||
});
|
||||
|
||||
/**
|
||||
* Preliminary setup for the DebuggerController object.
|
||||
*/
|
||||
|
@ -90,7 +90,6 @@ let DebuggerView = {
|
||||
*/
|
||||
function ScriptsView() {
|
||||
this._onScriptsChange = this._onScriptsChange.bind(this);
|
||||
this._onScriptsSearch = this._onScriptsSearch.bind(this);
|
||||
}
|
||||
|
||||
ScriptsView.prototype = {
|
||||
@ -104,14 +103,6 @@ ScriptsView.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes the input in the searchbox and unhides all the scripts.
|
||||
*/
|
||||
clearSearch: function DVS_clearSearch() {
|
||||
this._searchbox.value = "";
|
||||
this._onScriptsSearch({});
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks whether the script with the specified URL is among the scripts
|
||||
* known to the debugger and shown in the list.
|
||||
@ -121,11 +112,6 @@ ScriptsView.prototype = {
|
||||
* @return boolean
|
||||
*/
|
||||
contains: function DVS_contains(aUrl) {
|
||||
if (this._tmpScripts.some(function(element) {
|
||||
return element.script.url == aUrl;
|
||||
})) {
|
||||
return true;
|
||||
}
|
||||
if (this._scripts.getElementsByAttribute("value", aUrl).length > 0) {
|
||||
return true;
|
||||
}
|
||||
@ -141,11 +127,6 @@ ScriptsView.prototype = {
|
||||
* @return boolean
|
||||
*/
|
||||
containsLabel: function DVS_containsLabel(aLabel) {
|
||||
if (this._tmpScripts.some(function(element) {
|
||||
return element.label == aLabel;
|
||||
})) {
|
||||
return true;
|
||||
}
|
||||
if (this._scripts.getElementsByAttribute("label", aLabel).length > 0) {
|
||||
return true;
|
||||
}
|
||||
@ -190,18 +171,6 @@ ScriptsView.prototype = {
|
||||
this._scripts.selectedItem.value : null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the list of labels in the scripts container.
|
||||
* @return array
|
||||
*/
|
||||
get scriptLabels() {
|
||||
let labels = [];
|
||||
for (let i = 0, l = this._scripts.itemCount; i < l; i++) {
|
||||
labels.push(this._scripts.getItemAtIndex(i).label);
|
||||
}
|
||||
return labels;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the list of URIs for scripts in the page.
|
||||
* @return array
|
||||
@ -215,212 +184,50 @@ ScriptsView.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the number of visible (hidden=false) scripts in the container.
|
||||
* @return number
|
||||
*/
|
||||
get visibleItemsCount() {
|
||||
let count = 0;
|
||||
for (let i = 0, l = this._scripts.itemCount; i < l; i++) {
|
||||
count += this._scripts.getItemAtIndex(i).hidden ? 0 : 1;
|
||||
}
|
||||
return count;
|
||||
},
|
||||
|
||||
/**
|
||||
* Prepares a script to be added to the scripts container. This allows
|
||||
* for a large number of scripts to be batched up before being
|
||||
* alphabetically sorted and added in the container.
|
||||
* @see ScriptsView.commitScripts
|
||||
*
|
||||
* If aForceFlag is true, the script will be immediately inserted at the
|
||||
* necessary position in the container so that all the scripts remain sorted.
|
||||
* This can be much slower than batching up multiple scripts.
|
||||
* Adds a script to the scripts container.
|
||||
* If the script already exists (was previously added), null is returned.
|
||||
* Otherwise, the newly created element is returned.
|
||||
*
|
||||
* @param string aLabel
|
||||
* The simplified script location to be shown.
|
||||
* @param string aScript
|
||||
* The source script.
|
||||
* @param boolean aForceFlag
|
||||
* True to force the script to be immediately added.
|
||||
* @return object
|
||||
* The newly created html node representing the added script.
|
||||
*/
|
||||
addScript: function DVS_addScript(aLabel, aScript, aForceFlag) {
|
||||
// Batch the script to be added later.
|
||||
if (!aForceFlag) {
|
||||
this._tmpScripts.push({ label: aLabel, script: aScript });
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the target position in the menulist and insert the script there.
|
||||
for (let i = 0, l = this._scripts.itemCount; i < l; i++) {
|
||||
if (this._scripts.getItemAtIndex(i).label > aLabel) {
|
||||
this._createScriptElement(aLabel, aScript, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// The script is alphabetically the last one.
|
||||
this._createScriptElement(aLabel, aScript, -1, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds all the prepared scripts to the scripts container.
|
||||
* If a script already exists (was previously added), nothing happens.
|
||||
*/
|
||||
commitScripts: function DVS_commitScripts() {
|
||||
let newScripts = this._tmpScripts;
|
||||
this._tmpScripts = [];
|
||||
|
||||
if (!newScripts || !newScripts.length) {
|
||||
return;
|
||||
}
|
||||
newScripts.sort(function(a, b) {
|
||||
return a.label.toLowerCase() > b.label.toLowerCase();
|
||||
});
|
||||
|
||||
for (let i = 0, l = newScripts.length; i < l; i++) {
|
||||
let item = newScripts[i];
|
||||
this._createScriptElement(item.label, item.script, -1, true);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a custom script element and adds it to the scripts container.
|
||||
* If the script with the specified label already exists, nothing happens.
|
||||
*
|
||||
* @param string aLabel
|
||||
* The simplified script location to be shown.
|
||||
* @param string aScript
|
||||
* The source script.
|
||||
* @param number aIndex
|
||||
* The index where to insert to new script in the container.
|
||||
* Pass -1 to append the script at the end.
|
||||
* @param boolean aSelectIfEmptyFlag
|
||||
* True to set the newly created script as the currently selected item
|
||||
* if there are no other existing scripts in the container.
|
||||
*/
|
||||
_createScriptElement: function DVS__createScriptElement(
|
||||
aLabel, aScript, aIndex, aSelectIfEmptyFlag)
|
||||
{
|
||||
addScript: function DVS_addScript(aLabel, aScript) {
|
||||
// Make sure we don't duplicate anything.
|
||||
if (aLabel == "null" || this.containsLabel(aLabel)) {
|
||||
return;
|
||||
if (this.containsLabel(aLabel)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let scriptItem =
|
||||
aIndex == -1 ? this._scripts.appendItem(aLabel, aScript.url)
|
||||
: this._scripts.insertItemAt(aIndex, aLabel, aScript.url);
|
||||
let script = this._scripts.appendItem(aLabel, aScript.url);
|
||||
script.setAttribute("tooltiptext", aScript.url);
|
||||
script.setUserData("sourceScript", aScript, null);
|
||||
|
||||
scriptItem.setAttribute("tooltiptext", aScript.url);
|
||||
scriptItem.setUserData("sourceScript", aScript, null);
|
||||
|
||||
if (this._scripts.itemCount == 1 && aSelectIfEmptyFlag) {
|
||||
this._scripts.selectedItem = scriptItem;
|
||||
}
|
||||
this._scripts.selectedItem = script;
|
||||
return script;
|
||||
},
|
||||
|
||||
/**
|
||||
* The click listener for the scripts container.
|
||||
* The cached click listener for the scripts container.
|
||||
*/
|
||||
_onScriptsChange: function DVS__onScriptsChange() {
|
||||
let script = this._scripts.selectedItem.getUserData("sourceScript");
|
||||
this._preferredScript = script;
|
||||
DebuggerController.SourceScripts.showScript(script);
|
||||
},
|
||||
|
||||
/**
|
||||
* The search listener for the scripts search box.
|
||||
*/
|
||||
_onScriptsSearch: function DVS__onScriptsSearch(e) {
|
||||
let editor = DebuggerView.editor;
|
||||
let scripts = this._scripts;
|
||||
let rawValue = this._searchbox.value.toLowerCase();
|
||||
|
||||
let rawLength = rawValue.length;
|
||||
let lastColon = rawValue.lastIndexOf(":");
|
||||
let lastAt = rawValue.lastIndexOf("@");
|
||||
|
||||
let fileEnd = lastColon != -1 ? lastColon : lastAt != -1 ? lastAt : rawLength;
|
||||
let lineEnd = lastAt != -1 ? lastAt : rawLength;
|
||||
|
||||
let file = rawValue.slice(0, fileEnd);
|
||||
let line = window.parseInt(rawValue.slice(fileEnd + 1, lineEnd)) || -1;
|
||||
let token = rawValue.slice(lineEnd + 1);
|
||||
|
||||
// Presume we won't find anything.
|
||||
scripts.selectedItem = this._preferredScript;
|
||||
|
||||
// If we're not searching for a file anymore, unhide all the scripts.
|
||||
if (!file) {
|
||||
for (let i = 0, l = scripts.itemCount; i < l; i++) {
|
||||
scripts.getItemAtIndex(i).hidden = false;
|
||||
}
|
||||
} else {
|
||||
for (let i = 0, l = scripts.itemCount, found = false; i < l; i++) {
|
||||
let item = scripts.getItemAtIndex(i);
|
||||
let target = item.value.toLowerCase();
|
||||
|
||||
// Search is not case sensitive, and is tied to the url not the label.
|
||||
if (target.match(file)) {
|
||||
item.hidden = false;
|
||||
|
||||
if (!found) {
|
||||
found = true;
|
||||
scripts.selectedItem = item;
|
||||
}
|
||||
}
|
||||
// Hide what doesn't match our search.
|
||||
else {
|
||||
item.hidden = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (line > -1) {
|
||||
editor.setCaretPosition(line - 1);
|
||||
}
|
||||
if (token) {
|
||||
let offset = editor.find(token, { ignoreCase: true });
|
||||
if (offset > -1) {
|
||||
editor.setCaretPosition(0);
|
||||
editor.setCaretOffset(offset);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The keyup listener for the scripts search box.
|
||||
*/
|
||||
_onScriptsKeyUp: function DVS__onScriptsKeyUp(e) {
|
||||
if (e.keyCode === e.DOM_VK_ESCAPE) {
|
||||
DebuggerView.editor.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.keyCode === e.DOM_VK_RETURN || e.keyCode === e.DOM_VK_ENTER) {
|
||||
let editor = DebuggerView.editor;
|
||||
let offset = editor.findNext(true);
|
||||
if (offset > -1) {
|
||||
editor.setCaretPosition(0);
|
||||
editor.setCaretOffset(offset);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The cached scripts container and search box.
|
||||
* The cached scripts container.
|
||||
*/
|
||||
_scripts: null,
|
||||
_searchbox: null,
|
||||
|
||||
/**
|
||||
* Initialization function, called when the debugger is initialized.
|
||||
*/
|
||||
initialize: function DVS_initialize() {
|
||||
this._scripts = document.getElementById("scripts");
|
||||
this._searchbox = document.getElementById("scripts-search");
|
||||
this._scripts.addEventListener("select", this._onScriptsChange, false);
|
||||
this._searchbox.addEventListener("select", this._onScriptsSearch, false);
|
||||
this._searchbox.addEventListener("input", this._onScriptsSearch, false);
|
||||
this._searchbox.addEventListener("keyup", this._onScriptsKeyUp, false);
|
||||
this.commitScripts();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -428,11 +235,7 @@ ScriptsView.prototype = {
|
||||
*/
|
||||
destroy: function DVS_destroy() {
|
||||
this._scripts.removeEventListener("select", this._onScriptsChange, false);
|
||||
this._searchbox.removeEventListener("select", this._onScriptsSearch, false);
|
||||
this._searchbox.removeEventListener("input", this._onScriptsSearch, false);
|
||||
this._searchbox.removeEventListener("keyup", this._onScriptsKeyUp, false);
|
||||
this._scripts = null;
|
||||
this._searchbox = null;
|
||||
}
|
||||
};
|
||||
|
||||
@ -474,8 +277,6 @@ StackFramesView.prototype = {
|
||||
else {
|
||||
status.textContent = "";
|
||||
}
|
||||
|
||||
DebuggerView.Scripts.clearSearch();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -499,7 +300,7 @@ StackFramesView.prototype = {
|
||||
|
||||
// The empty node should look grayed out to avoid confusion.
|
||||
item.className = "empty list-item";
|
||||
item.appendChild(document.createTextNode(L10N.getStr("emptyStackText")));
|
||||
item.appendChild(document.createTextNode(L10N.getStr("emptyText")));
|
||||
|
||||
this._frames.appendChild(item);
|
||||
},
|
||||
@ -580,7 +381,7 @@ StackFramesView.prototype = {
|
||||
* The frame depth specified by the debugger.
|
||||
*/
|
||||
unhighlightFrame: function DVF_unhighlightFrame(aDepth) {
|
||||
this.highlightFrame(aDepth, true);
|
||||
this.highlightFrame(aDepth, true)
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -81,8 +81,6 @@
|
||||
<xul:button id="step-in">&debuggerUI.stepInButton;</xul:button>
|
||||
<xul:button id="step-out">&debuggerUI.stepOutButton;</xul:button>
|
||||
<xul:menulist id="scripts"/>
|
||||
<xul:textbox id="scripts-search" type="search"
|
||||
emptytext="&debuggerUI.emptyFilterText;"/>
|
||||
</xul:toolbar>
|
||||
<div id="dbg-content" class="hbox flex">
|
||||
<div id="stack" class="vbox">
|
||||
|
@ -46,7 +46,6 @@ include $(DEPTH)/config/autoconf.mk
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_BROWSER_TEST_FILES = \
|
||||
browser_dbg_createRemote.js \
|
||||
browser_dbg_debuggerstatement.js \
|
||||
browser_dbg_listtabs.js \
|
||||
browser_dbg_tabactor-01.js \
|
||||
@ -71,9 +70,6 @@ _BROWSER_TEST_FILES = \
|
||||
browser_dbg_stack-05.js \
|
||||
browser_dbg_location-changes.js \
|
||||
browser_dbg_script-switching.js \
|
||||
browser_dbg_scripts-sorting.js \
|
||||
browser_dbg_scripts-searching-01.js \
|
||||
browser_dbg_scripts-searching-02.js \
|
||||
browser_dbg_pause-resume.js \
|
||||
browser_dbg_update-editor-mode.js \
|
||||
$(warning browser_dbg_select-line.js temporarily disabled due to oranges, see bug 726609) \
|
||||
|
@ -23,44 +23,37 @@ function test()
|
||||
let SourceEditor = tempScope.SourceEditor;
|
||||
let scriptShown = false;
|
||||
let framesAdded = false;
|
||||
let resumed = false;
|
||||
let testStarted = false;
|
||||
|
||||
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
resumed = true;
|
||||
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
framesAdded = true;
|
||||
executeSoon(startTest);
|
||||
runTest();
|
||||
});
|
||||
|
||||
executeSoon(function() {
|
||||
gDebuggee.firstCall();
|
||||
});
|
||||
gDebuggee.firstCall();
|
||||
});
|
||||
|
||||
function onScriptShown(aEvent)
|
||||
{
|
||||
scriptShown = aEvent.detail.url.indexOf("-02.js") != -1;
|
||||
executeSoon(startTest);
|
||||
}
|
||||
window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) {
|
||||
let url = aEvent.detail.url;
|
||||
if (url.indexOf("-02.js") != -1) {
|
||||
scriptShown = true;
|
||||
window.removeEventListener(aEvent.type, _onEvent);
|
||||
runTest();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("Debugger:ScriptShown", onScriptShown);
|
||||
|
||||
function startTest()
|
||||
function runTest()
|
||||
{
|
||||
if (scriptShown && framesAdded && resumed && !testStarted) {
|
||||
window.removeEventListener("Debugger:ScriptShown", onScriptShown);
|
||||
testStarted = true;
|
||||
Services.tm.currentThread.dispatch({ run: performTest }, 0);
|
||||
if (scriptShown && framesAdded) {
|
||||
Services.tm.currentThread.dispatch({ run: onScriptShown }, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function performTest()
|
||||
function onScriptShown()
|
||||
{
|
||||
gScripts = gDebugger.DebuggerView.Scripts;
|
||||
|
||||
|
@ -21,43 +21,37 @@ function test()
|
||||
let contextMenu = null;
|
||||
let scriptShown = false;
|
||||
let framesAdded = false;
|
||||
let resumed = false;
|
||||
let testStarted = false;
|
||||
|
||||
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
resumed = true;
|
||||
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
framesAdded = true;
|
||||
executeSoon(startTest);
|
||||
});
|
||||
|
||||
executeSoon(function() {
|
||||
gDebuggee.firstCall();
|
||||
runTest();
|
||||
});
|
||||
gDebuggee.firstCall();
|
||||
});
|
||||
|
||||
function onScriptShown(aEvent) {
|
||||
scriptShown = aEvent.detail.url.indexOf("-02.js") != -1;
|
||||
executeSoon(startTest);
|
||||
}
|
||||
window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) {
|
||||
let url = aEvent.detail.url;
|
||||
if (url.indexOf("-02.js") != -1) {
|
||||
scriptShown = true;
|
||||
window.removeEventListener(aEvent.type, _onEvent);
|
||||
runTest();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("Debugger:ScriptShown", onScriptShown);
|
||||
|
||||
function startTest()
|
||||
function runTest()
|
||||
{
|
||||
if (scriptShown && framesAdded && resumed && !testStarted) {
|
||||
testStarted = true;
|
||||
window.removeEventListener("Debugger:ScriptShown", onScriptShown);
|
||||
Services.tm.currentThread.dispatch({ run: performTest }, 0);
|
||||
if (scriptShown && framesAdded) {
|
||||
Services.tm.currentThread.dispatch({ run: onScriptShown }, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function performTest()
|
||||
function onScriptShown()
|
||||
{
|
||||
let scripts = gDebugger.DebuggerView.Scripts._scripts;
|
||||
|
||||
|
@ -1,86 +0,0 @@
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
var gProcess = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
|
||||
function test() {
|
||||
remote_debug_tab_pane(STACK_URL, aOnClosing, function(aTab, aDebuggee, aProcess) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gProcess = aProcess;
|
||||
|
||||
testSimpleCall();
|
||||
});
|
||||
}
|
||||
|
||||
function testSimpleCall() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
ok(gProcess._dbgProcess,
|
||||
"The remote debugger process wasn't created properly!");
|
||||
ok(gProcess._dbgProcess.isRunning,
|
||||
"The remote debugger process isn't running!");
|
||||
is(typeof gProcess._dbgProcess.pid, "number",
|
||||
"The remote debugger process doesn't have a pid (?!)");
|
||||
|
||||
info("process location: " + gProcess._dbgProcess.location);
|
||||
info("process pid: " + gProcess._dbgProcess.pid);
|
||||
info("process name: " + gProcess._dbgProcess.processName);
|
||||
info("process sig: " + gProcess._dbgProcess.processSignature);
|
||||
|
||||
ok(gProcess._dbgProfile,
|
||||
"The remote debugger profile wasn't created properly!");
|
||||
ok(gProcess._dbgProfile.localDir,
|
||||
"The remote debugger profile doesn't have a localDir...");
|
||||
ok(gProcess._dbgProfile.rootDir,
|
||||
"The remote debugger profile doesn't have a rootDir...");
|
||||
ok(gProcess._dbgProfile.name,
|
||||
"The remote debugger profile doesn't have a name...");
|
||||
|
||||
info("profile localDir: " + gProcess._dbgProfile.localDir);
|
||||
info("profile rootDir: " + gProcess._dbgProfile.rootDir);
|
||||
info("profile name: " + gProcess._dbgProfile.name);
|
||||
|
||||
let profileService = Cc["@mozilla.org/toolkit/profile-service;1"]
|
||||
.createInstance(Ci.nsIToolkitProfileService);
|
||||
|
||||
let profile = profileService.getProfileByName(gProcess._dbgProfile.name);
|
||||
|
||||
ok(profile,
|
||||
"The remote debugger profile wasn't *actually* created properly!");
|
||||
is(profile.localDir.path, gProcess._dbgProfile.localDir.path,
|
||||
"The remote debugger profile doesn't have the correct localDir!");
|
||||
is(profile.rootDir.path, gProcess._dbgProfile.rootDir.path,
|
||||
"The remote debugger profile doesn't have the correct rootDir!");
|
||||
|
||||
DebuggerUI.toggleRemoteDebugger();
|
||||
}}, 0);
|
||||
}
|
||||
|
||||
function aOnClosing() {
|
||||
ok(!gProcess._dbgProcess.isRunning,
|
||||
"The remote debugger process isn't closed as it should be!");
|
||||
is(gProcess._dbgProcess.exitValue, (Services.appinfo.OS == "WINNT" ? 0 : 256),
|
||||
"The remote debugger process didn't die cleanly.");
|
||||
|
||||
info("process exit value: " + gProcess._dbgProcess.exitValue);
|
||||
|
||||
info("profile localDir: " + gProcess._dbgProfile.localDir.path);
|
||||
info("profile rootDir: " + gProcess._dbgProfile.rootDir.path);
|
||||
info("profile name: " + gProcess._dbgProfile.name);
|
||||
|
||||
executeSoon(function() {
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
removeTab(gTab);
|
||||
gProcess = null;
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
});
|
@ -85,8 +85,7 @@ function resumeAndFinish() {
|
||||
gDebugger.DebuggerController.activeThread.resume(function() {
|
||||
let vs = gDebugger.DebuggerView.Scripts;
|
||||
let ss = gDebugger.DebuggerController.SourceScripts;
|
||||
vs.empty();
|
||||
vs._scripts.removeEventListener("select", vs._onScriptsChange, false);
|
||||
ss._onScriptsCleared();
|
||||
|
||||
is(ss._trimUrlQuery("a/b/c.d?test=1&random=4"), "a/b/c.d",
|
||||
"Trimming the url query isn't done properly.");
|
||||
@ -102,11 +101,12 @@ function resumeAndFinish() {
|
||||
{ href: "si://interesting.address.moc/random/x/y/", leaf: "script.js?a=1&b=2&c=3" }
|
||||
];
|
||||
|
||||
vs._scripts.removeEventListener("select", vs._onScriptsChange, false);
|
||||
|
||||
urls.forEach(function(url) {
|
||||
executeSoon(function() {
|
||||
let loc = url.href + url.leaf;
|
||||
vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc });
|
||||
vs.commitScripts();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -27,10 +27,10 @@ function testFrameParameters()
|
||||
{
|
||||
dump("Started testFrameParameters!\n");
|
||||
|
||||
gDebugger.addEventListener("Debugger:FetchedVariables", function test() {
|
||||
dump("Entered Debugger:FetchedVariables!\n");
|
||||
gDebugger.addEventListener("Debugger:FetchedParameters", function test() {
|
||||
dump("Entered Debugger:FetchedParameters!\n");
|
||||
|
||||
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
|
||||
gDebugger.removeEventListener("Debugger:FetchedParameters", test, false);
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
dump("After currentThread.dispatch!\n");
|
||||
@ -52,42 +52,33 @@ function testFrameParameters()
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 3,
|
||||
"Should have three frames.");
|
||||
|
||||
is(localNodes.length, 11,
|
||||
is(localNodes.length, 8,
|
||||
"The localScope should contain all the created variable elements.");
|
||||
|
||||
is(localNodes[0].querySelector(".info").textContent, "[object Proxy]",
|
||||
"Should have the right property value for 'this'.");
|
||||
|
||||
is(localNodes[1].querySelector(".info").textContent, "[object Object]",
|
||||
is(localNodes[1].querySelector(".info").textContent, "[object Arguments]",
|
||||
"Should have the right property value for 'arguments'.");
|
||||
|
||||
is(localNodes[2].querySelector(".info").textContent, "[object Object]",
|
||||
"Should have the right property value for 'aArg'.");
|
||||
|
||||
is(localNodes[2].querySelector(".info").textContent, '"beta"',
|
||||
is(localNodes[3].querySelector(".info").textContent, '"beta"',
|
||||
"Should have the right property value for 'bArg'.");
|
||||
|
||||
is(localNodes[3].querySelector(".info").textContent, "3",
|
||||
is(localNodes[4].querySelector(".info").textContent, "3",
|
||||
"Should have the right property value for 'cArg'.");
|
||||
|
||||
is(localNodes[4].querySelector(".info").textContent, "false",
|
||||
is(localNodes[5].querySelector(".info").textContent, "false",
|
||||
"Should have the right property value for 'dArg'.");
|
||||
|
||||
is(localNodes[5].querySelector(".info").textContent, "null",
|
||||
is(localNodes[6].querySelector(".info").textContent, "null",
|
||||
"Should have the right property value for 'eArg'.");
|
||||
|
||||
is(localNodes[6].querySelector(".info").textContent, "undefined",
|
||||
is(localNodes[7].querySelector(".info").textContent, "undefined",
|
||||
"Should have the right property value for 'fArg'.");
|
||||
|
||||
is(localNodes[7].querySelector(".info").textContent, "1",
|
||||
"Should have the right property value for 'a'.");
|
||||
|
||||
is(localNodes[8].querySelector(".info").textContent, "[object Object]",
|
||||
"Should have the right property value for 'b'.");
|
||||
|
||||
is(localNodes[9].querySelector(".info").textContent, "[object Object]",
|
||||
"Should have the right property value for 'c'.");
|
||||
|
||||
is(localNodes[10].querySelector(".info").textContent, "[object Arguments]",
|
||||
"Should have the right property value for 'arguments'.");
|
||||
|
||||
resumeAndFinish();
|
||||
}}, 0);
|
||||
}, false);
|
||||
|
@ -27,10 +27,10 @@ function testFrameParameters()
|
||||
{
|
||||
dump("Started testFrameParameters!\n");
|
||||
|
||||
gDebugger.addEventListener("Debugger:FetchedVariables", function test() {
|
||||
dump("Entered Debugger:FetchedVariables!\n");
|
||||
gDebugger.addEventListener("Debugger:FetchedParameters", function test() {
|
||||
dump("Entered Debugger:FetchedParameters!\n");
|
||||
|
||||
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
|
||||
gDebugger.removeEventListener("Debugger:FetchedParameters", test, false);
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
dump("After currentThread.dispatch!\n");
|
||||
@ -50,17 +50,16 @@ function testFrameParameters()
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 3,
|
||||
"Should have three frames.");
|
||||
|
||||
is(localNodes.length, 11,
|
||||
is(localNodes.length, 8,
|
||||
"The localScope should contain all the created variable elements.");
|
||||
|
||||
is(localNodes[0].querySelector(".info").textContent, "[object Proxy]",
|
||||
"Should have the right property value for 'this'.");
|
||||
|
||||
// Expand the '__proto__', 'arguments' and 'a' tree nodes. This causes
|
||||
// their properties to be retrieved and displayed.
|
||||
// Expand the __proto__ and arguments tree nodes. This causes their
|
||||
// properties to be retrieved and displayed.
|
||||
localNodes[0].expand();
|
||||
localNodes[9].expand();
|
||||
localNodes[10].expand();
|
||||
localNodes[1].expand();
|
||||
|
||||
// Poll every few milliseconds until the properties are retrieved.
|
||||
// It's important to set the timer in the chrome window, because the
|
||||
@ -71,9 +70,7 @@ function testFrameParameters()
|
||||
ok(false, "Timed out while polling for the properties.");
|
||||
resumeAndFinish();
|
||||
}
|
||||
if (!localNodes[0].fetched ||
|
||||
!localNodes[9].fetched ||
|
||||
!localNodes[10].fetched) {
|
||||
if (!localNodes[0].fetched || !localNodes[1].fetched) {
|
||||
return;
|
||||
}
|
||||
window.clearInterval(intervalID);
|
||||
@ -85,26 +82,14 @@ function testFrameParameters()
|
||||
.textContent.search(/object/) != -1,
|
||||
"__proto__ should be an object.");
|
||||
|
||||
is(localNodes[9].querySelector(".info").textContent, "[object Object]",
|
||||
"Should have the right property value for 'c'.");
|
||||
|
||||
is(localNodes[9].querySelectorAll(".property > .title > .key")[1]
|
||||
.textContent, "a",
|
||||
"Should have the right property name for 'a'.");
|
||||
|
||||
is(localNodes[9].querySelectorAll(".property > .title > .value")[1]
|
||||
.textContent, 1,
|
||||
"Should have the right value for 'c.a'.");
|
||||
|
||||
is(localNodes[10].querySelector(".info").textContent,
|
||||
"[object Arguments]",
|
||||
is(localNodes[1].querySelector(".info").textContent, "[object Arguments]",
|
||||
"Should have the right property value for 'arguments'.");
|
||||
|
||||
is(localNodes[10].querySelector(".property > .title > .key")
|
||||
is(localNodes[1].querySelector(".property > .title > .key")
|
||||
.textContent, "length",
|
||||
"Should have the right property name for 'length'.");
|
||||
"Should have the right property name for length.");
|
||||
|
||||
is(localNodes[10].querySelector(".property > .title > .value")
|
||||
is(localNodes[1].querySelector(".property > .title > .value")
|
||||
.textContent, 5,
|
||||
"Should have the right argument length.");
|
||||
|
||||
@ -119,8 +104,7 @@ function testFrameParameters()
|
||||
}
|
||||
|
||||
function resumeAndFinish() {
|
||||
let thread = gDebugger.DebuggerController.activeThread;
|
||||
thread.addOneTimeListener("framescleared", function() {
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framescleared", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
var frames = gDebugger.DebuggerView.StackFrames._frames;
|
||||
|
||||
@ -131,7 +115,7 @@ function resumeAndFinish() {
|
||||
}}, 0);
|
||||
});
|
||||
|
||||
thread.resume();
|
||||
gDebugger.DebuggerController.activeThread.resume();
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
|
@ -8,6 +8,10 @@
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
|
||||
|
||||
let tempScope = {};
|
||||
Cu.import("resource:///modules/source-editor.jsm", tempScope);
|
||||
let SourceEditor = tempScope.SourceEditor;
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
@ -18,39 +22,33 @@ function test()
|
||||
{
|
||||
let scriptShown = false;
|
||||
let framesAdded = false;
|
||||
let resumed = false;
|
||||
let testStarted = false;
|
||||
|
||||
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
resumed = true;
|
||||
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
framesAdded = true;
|
||||
executeSoon(startTest);
|
||||
runTest();
|
||||
});
|
||||
|
||||
executeSoon(function() {
|
||||
gDebuggee.firstCall();
|
||||
});
|
||||
gDebuggee.firstCall();
|
||||
});
|
||||
|
||||
function onScriptShown(aEvent)
|
||||
{
|
||||
scriptShown = aEvent.detail.url.indexOf("-02.js") != -1;
|
||||
executeSoon(startTest);
|
||||
}
|
||||
window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) {
|
||||
let url = aEvent.detail.url;
|
||||
if (url.indexOf("-02.js") != -1) {
|
||||
scriptShown = true;
|
||||
window.removeEventListener(aEvent.type, _onEvent);
|
||||
runTest();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("Debugger:ScriptShown", onScriptShown);
|
||||
|
||||
function startTest()
|
||||
function runTest()
|
||||
{
|
||||
if (scriptShown && framesAdded && resumed && !testStarted) {
|
||||
window.removeEventListener("Debugger:ScriptShown", onScriptShown);
|
||||
testStarted = true;
|
||||
if (scriptShown && framesAdded) {
|
||||
Services.tm.currentThread.dispatch({ run: testScriptsDisplay }, 0);
|
||||
}
|
||||
}
|
||||
@ -81,6 +79,8 @@ function testScriptsDisplay() {
|
||||
ok(gDebugger.DebuggerView.Scripts.containsLabel(
|
||||
label2), "Second script label is incorrect.");
|
||||
|
||||
dump("Debugger editor text:\n" + gDebugger.editor.getText() + "\n");
|
||||
|
||||
ok(gDebugger.editor.getText().search(/debugger/) != -1,
|
||||
"The correct script was loaded initially.");
|
||||
|
||||
@ -100,6 +100,8 @@ function testScriptsDisplay() {
|
||||
|
||||
function testSwitchPaused()
|
||||
{
|
||||
dump("Debugger editor text:\n" + gDebugger.editor.getText() + "\n");
|
||||
|
||||
ok(gDebugger.editor.getText().search(/debugger/) == -1,
|
||||
"The second script is no longer displayed.");
|
||||
|
||||
@ -125,8 +127,6 @@ function testSwitchPaused()
|
||||
|
||||
function testSwitchRunning()
|
||||
{
|
||||
dump("Debugger editor text:\n" + gDebugger.editor.getText() + "\n");
|
||||
|
||||
ok(gDebugger.editor.getText().search(/debugger/) != -1,
|
||||
"The second script is displayed again.");
|
||||
|
||||
|
@ -1,188 +0,0 @@
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
var gEditor = null;
|
||||
var gScripts = null;
|
||||
var gSearchBox = null;
|
||||
var gMenulist = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
let scriptShown = false;
|
||||
let framesAdded = false;
|
||||
|
||||
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
framesAdded = true;
|
||||
runTest();
|
||||
});
|
||||
|
||||
gDebuggee.simpleCall();
|
||||
});
|
||||
|
||||
window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) {
|
||||
window.removeEventListener(aEvent.type, _onEvent);
|
||||
scriptShown = true;
|
||||
runTest();
|
||||
});
|
||||
|
||||
function runTest()
|
||||
{
|
||||
if (scriptShown && framesAdded) {
|
||||
Services.tm.currentThread.dispatch({ run: testScriptSearching }, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testScriptSearching() {
|
||||
gDebugger.DebuggerController.activeThread.resume(function() {
|
||||
gEditor = gDebugger.DebuggerView.editor;
|
||||
gScripts = gDebugger.DebuggerView.Scripts;
|
||||
gSearchBox = gScripts._searchbox;
|
||||
gMenulist = gScripts._scripts;
|
||||
|
||||
write(":12");
|
||||
ok(gEditor.getCaretPosition().line == 11 &&
|
||||
gEditor.getCaretPosition().col == 0,
|
||||
"The editor didn't jump to the correct line.");
|
||||
|
||||
write("@debugger");
|
||||
ok(gEditor.getCaretPosition().line == 2 &&
|
||||
gEditor.getCaretPosition().col == 44,
|
||||
"The editor didn't jump to the correct token. (1)");
|
||||
|
||||
EventUtils.sendKey("RETURN");
|
||||
ok(gEditor.getCaretPosition().line == 8 &&
|
||||
gEditor.getCaretPosition().col == 2,
|
||||
"The editor didn't jump to the correct token. (2)");
|
||||
|
||||
EventUtils.sendKey("ENTER");
|
||||
ok(gEditor.getCaretPosition().line == 12 &&
|
||||
gEditor.getCaretPosition().col == 8,
|
||||
"The editor didn't jump to the correct token. (3)");
|
||||
|
||||
EventUtils.sendKey("ENTER");
|
||||
ok(gEditor.getCaretPosition().line == 19 &&
|
||||
gEditor.getCaretPosition().col == 4,
|
||||
"The editor didn't jump to the correct token. (4)");
|
||||
|
||||
EventUtils.sendKey("RETURN");
|
||||
ok(gEditor.getCaretPosition().line == 2 &&
|
||||
gEditor.getCaretPosition().col == 44,
|
||||
"The editor didn't jump to the correct token. (5)");
|
||||
|
||||
|
||||
write(":bogus@debugger;");
|
||||
ok(gEditor.getCaretPosition().line == 8 &&
|
||||
gEditor.getCaretPosition().col == 2,
|
||||
"The editor didn't jump to the correct token. (7)");
|
||||
|
||||
write(":13@debugger;");
|
||||
ok(gEditor.getCaretPosition().line == 8 &&
|
||||
gEditor.getCaretPosition().col == 2,
|
||||
"The editor didn't jump to the correct token. (7)");
|
||||
|
||||
write(":@debugger;");
|
||||
ok(gEditor.getCaretPosition().line == 8 &&
|
||||
gEditor.getCaretPosition().col == 2,
|
||||
"The editor didn't jump to the correct token. (8)");
|
||||
|
||||
write("::@debugger;");
|
||||
ok(gEditor.getCaretPosition().line == 8 &&
|
||||
gEditor.getCaretPosition().col == 2,
|
||||
"The editor didn't jump to the correct token. (9)");
|
||||
|
||||
write(":::@debugger;");
|
||||
ok(gEditor.getCaretPosition().line == 8 &&
|
||||
gEditor.getCaretPosition().col == 2,
|
||||
"The editor didn't jump to the correct token. (10)");
|
||||
|
||||
|
||||
write(":i am not a number");
|
||||
ok(gEditor.getCaretPosition().line == 8 &&
|
||||
gEditor.getCaretPosition().col == 2,
|
||||
"The editor didn't remain at the correct token. (11)");
|
||||
|
||||
write("@__i do not exist__");
|
||||
ok(gEditor.getCaretPosition().line == 8 &&
|
||||
gEditor.getCaretPosition().col == 2,
|
||||
"The editor didn't remain at the correct token. (12)");
|
||||
|
||||
|
||||
write(":1:2:3:a:b:c:::12");
|
||||
ok(gEditor.getCaretPosition().line == 11 &&
|
||||
gEditor.getCaretPosition().col == 0,
|
||||
"The editor didn't jump to the correct line. (13)");
|
||||
|
||||
write("@don't@find@me@instead@find@debugger");
|
||||
ok(gEditor.getCaretPosition().line == 2 &&
|
||||
gEditor.getCaretPosition().col == 44,
|
||||
"The editor didn't jump to the correct token. (14)");
|
||||
|
||||
EventUtils.sendKey("RETURN");
|
||||
ok(gEditor.getCaretPosition().line == 8 &&
|
||||
gEditor.getCaretPosition().col == 2,
|
||||
"The editor didn't jump to the correct token. (15)");
|
||||
|
||||
EventUtils.sendKey("ENTER");
|
||||
ok(gEditor.getCaretPosition().line == 12 &&
|
||||
gEditor.getCaretPosition().col == 8,
|
||||
"The editor didn't jump to the correct token. (16)");
|
||||
|
||||
EventUtils.sendKey("RETURN");
|
||||
ok(gEditor.getCaretPosition().line == 19 &&
|
||||
gEditor.getCaretPosition().col == 4,
|
||||
"The editor didn't jump to the correct token. (17)");
|
||||
|
||||
EventUtils.sendKey("ENTER");
|
||||
ok(gEditor.getCaretPosition().line == 2 &&
|
||||
gEditor.getCaretPosition().col == 44,
|
||||
"The editor didn't jump to the correct token. (18)");
|
||||
|
||||
|
||||
clear();
|
||||
ok(gEditor.getCaretPosition().line == 2 &&
|
||||
gEditor.getCaretPosition().col == 44,
|
||||
"The editor didn't remain at the correct token. (19)");
|
||||
is(gScripts.visibleItemsCount, 1,
|
||||
"Not all the scripts are shown after the search. (20)");
|
||||
|
||||
closeDebuggerAndFinish(gTab);
|
||||
});
|
||||
}
|
||||
|
||||
function clear() {
|
||||
gSearchBox.focus();
|
||||
gSearchBox.value = "";
|
||||
}
|
||||
|
||||
function write(text) {
|
||||
clear();
|
||||
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
EventUtils.sendChar(text[i]);
|
||||
}
|
||||
dump("editor caret position: " + gEditor.getCaretPosition().toSource() + "\n");
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
removeTab(gTab);
|
||||
gPane = null;
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gDebugger = null;
|
||||
gEditor = null;
|
||||
gScripts = null;
|
||||
gSearchBox = null;
|
||||
gMenulist = null;
|
||||
});
|
@ -1,146 +0,0 @@
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
var gEditor = null;
|
||||
var gScripts = null;
|
||||
var gSearchBox = null;
|
||||
var gMenulist = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
let scriptShown = false;
|
||||
let framesAdded = false;
|
||||
|
||||
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
framesAdded = true;
|
||||
runTest();
|
||||
});
|
||||
|
||||
gDebuggee.firstCall();
|
||||
});
|
||||
|
||||
window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) {
|
||||
let url = aEvent.detail.url;
|
||||
if (url.indexOf("-02.js") != -1) {
|
||||
scriptShown = true;
|
||||
window.removeEventListener(aEvent.type, _onEvent);
|
||||
runTest();
|
||||
}
|
||||
});
|
||||
|
||||
function runTest()
|
||||
{
|
||||
if (scriptShown && framesAdded) {
|
||||
Services.tm.currentThread.dispatch({ run: testScriptSearching }, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testScriptSearching() {
|
||||
gDebugger.DebuggerController.activeThread.resume(function() {
|
||||
gEditor = gDebugger.DebuggerView.editor;
|
||||
gScripts = gDebugger.DebuggerView.Scripts;
|
||||
gSearchBox = gScripts._searchbox;
|
||||
gMenulist = gScripts._scripts;
|
||||
|
||||
firstSearch();
|
||||
});
|
||||
}
|
||||
|
||||
function firstSearch() {
|
||||
window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) {
|
||||
dump("Current script url:\n" + aEvent.detail.url + "\n");
|
||||
dump("Debugger editor text:\n" + gEditor.getText() + "\n");
|
||||
|
||||
let url = aEvent.detail.url;
|
||||
if (url.indexOf("-01.js") != -1) {
|
||||
window.removeEventListener(aEvent.type, _onEvent);
|
||||
|
||||
executeSoon(function() {
|
||||
dump("Editor caret position: " + gEditor.getCaretPosition().toSource() + "\n");
|
||||
ok(gEditor.getCaretPosition().line == 4 &&
|
||||
gEditor.getCaretPosition().col == 0,
|
||||
"The editor didn't jump to the correct line. (1)");
|
||||
is(gScripts.visibleItemsCount, 1,
|
||||
"Not all the correct scripts are shown after the search. (1)");
|
||||
|
||||
secondSearch();
|
||||
});
|
||||
}
|
||||
});
|
||||
write(".*-01\.js:5");
|
||||
}
|
||||
|
||||
function secondSearch() {
|
||||
window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) {
|
||||
dump("Current script url:\n" + aEvent.detail.url + "\n");
|
||||
dump("Debugger editor text:\n" + gEditor.getText() + "\n");
|
||||
|
||||
let url = aEvent.detail.url;
|
||||
if (url.indexOf("-02.js") != -1) {
|
||||
window.removeEventListener(aEvent.type, _onEvent);
|
||||
|
||||
executeSoon(function() {
|
||||
dump("Editor caret position: " + gEditor.getCaretPosition().toSource() + "\n");
|
||||
ok(gEditor.getCaretPosition().line == 5 &&
|
||||
gEditor.getCaretPosition().col == 8,
|
||||
"The editor didn't jump to the correct line. (2)");
|
||||
is(gScripts.visibleItemsCount, 1,
|
||||
"Not all the correct scripts are shown after the search. (2)");
|
||||
|
||||
finalCheck();
|
||||
});
|
||||
}
|
||||
});
|
||||
write(".*-02\.js@debugger;");
|
||||
}
|
||||
|
||||
function finalCheck() {
|
||||
clear();
|
||||
ok(gEditor.getCaretPosition().line == 5 &&
|
||||
gEditor.getCaretPosition().col == 8,
|
||||
"The editor didn't remain at the correct token. (3)");
|
||||
is(gScripts.visibleItemsCount, 2,
|
||||
"Not all the scripts are shown after the search. (3)");
|
||||
|
||||
closeDebuggerAndFinish(gTab);
|
||||
}
|
||||
|
||||
function clear() {
|
||||
gSearchBox.focus();
|
||||
gSearchBox.value = "";
|
||||
}
|
||||
|
||||
function write(text) {
|
||||
clear();
|
||||
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
EventUtils.sendChar(text[i]);
|
||||
}
|
||||
dump("editor caret position: " + gEditor.getCaretPosition().toSource() + "\n");
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
removeTab(gTab);
|
||||
gPane = null;
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gDebugger = null;
|
||||
gEditor = null;
|
||||
gScripts = null;
|
||||
gSearchBox = null;
|
||||
gMenulist = null;
|
||||
});
|
@ -1,124 +0,0 @@
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
|
||||
function test() {
|
||||
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
|
||||
testSimpleCall();
|
||||
});
|
||||
}
|
||||
|
||||
function testSimpleCall() {
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
resumeAndFinish();
|
||||
}}, 0);
|
||||
});
|
||||
|
||||
gDebuggee.simpleCall();
|
||||
}
|
||||
|
||||
function resumeAndFinish() {
|
||||
gDebugger.DebuggerController.activeThread.resume(function() {
|
||||
checkScriptsOrder();
|
||||
addScriptsAndCheckOrder(1, function() {
|
||||
addScriptsAndCheckOrder(2, function() {
|
||||
addScriptsAndCheckOrder(3, function() {
|
||||
closeDebuggerAndFinish(gTab);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addScriptsAndCheckOrder(method, callback) {
|
||||
let vs = gDebugger.DebuggerView.Scripts;
|
||||
let ss = gDebugger.DebuggerController.SourceScripts;
|
||||
vs.empty();
|
||||
vs._scripts.removeEventListener("select", vs._onScriptsChange, false);
|
||||
|
||||
let urls = [
|
||||
{ href: "ici://some.address.com/random/", leaf: "subrandom/" },
|
||||
{ href: "ni://another.address.org/random/subrandom/", leaf: "page.html" },
|
||||
{ href: "san://interesting.address.gro/random/", leaf: "script.js" },
|
||||
{ href: "si://interesting.address.moc/random/", leaf: "script.js" },
|
||||
{ href: "si://interesting.address.moc/random/", leaf: "x/script.js" },
|
||||
{ href: "si://interesting.address.moc/random/", leaf: "x/y/script.js?a=1" },
|
||||
{ href: "si://interesting.address.moc/random/x/", leaf: "y/script.js?a=1&b=2" },
|
||||
{ href: "si://interesting.address.moc/random/x/y/", leaf: "script.js?a=1&b=2&c=3" }
|
||||
];
|
||||
|
||||
urls.sort(function(a, b) {
|
||||
return Math.random() - 0.5;
|
||||
});
|
||||
|
||||
switch (method) {
|
||||
case 1:
|
||||
urls.forEach(function(url) {
|
||||
let loc = url.href + url.leaf;
|
||||
vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc });
|
||||
});
|
||||
vs.commitScripts();
|
||||
break;
|
||||
|
||||
case 2:
|
||||
urls.forEach(function(url) {
|
||||
let loc = url.href + url.leaf;
|
||||
vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc }, true);
|
||||
});
|
||||
break;
|
||||
|
||||
case 3:
|
||||
let i = 0
|
||||
for (; i < urls.length / 2; i++) {
|
||||
let url = urls[i];
|
||||
let loc = url.href + url.leaf;
|
||||
vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc });
|
||||
}
|
||||
vs.commitScripts();
|
||||
|
||||
for (; i < urls.length; i++) {
|
||||
let url = urls[i];
|
||||
let loc = url.href + url.leaf;
|
||||
vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc }, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
executeSoon(function() {
|
||||
checkScriptsOrder(method);
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
function checkScriptsOrder(method) {
|
||||
let labels = gDebugger.DebuggerView.Scripts.scriptLabels;
|
||||
let sorted = labels.reduce(function(prev, curr, index, array) {
|
||||
return array[index - 1] < array[index];
|
||||
});
|
||||
|
||||
ok(sorted,
|
||||
"Using method " + method + ", " +
|
||||
"the scripts weren't in the correct order: " + labels.toSource());
|
||||
|
||||
return sorted;
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
removeTab(gTab);
|
||||
gPane = null;
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gDebugger = null;
|
||||
});
|
@ -22,38 +22,32 @@ function test()
|
||||
{
|
||||
let scriptShown = false;
|
||||
let framesAdded = false;
|
||||
let testStarted = false;
|
||||
let resumed = false;
|
||||
|
||||
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
resumed = true;
|
||||
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
framesAdded = true;
|
||||
executeSoon(startTest);
|
||||
});
|
||||
|
||||
executeSoon(function() {
|
||||
gDebuggee.firstCall();
|
||||
runTest();
|
||||
});
|
||||
gDebuggee.firstCall();
|
||||
});
|
||||
|
||||
function onScriptShown(aEvent) {
|
||||
scriptShown = aEvent.detail.url.indexOf("test-editor-mode") != -1;
|
||||
executeSoon(startTest);
|
||||
}
|
||||
window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) {
|
||||
let url = aEvent.detail.url;
|
||||
if (url.indexOf("editor-mode") != -1) {
|
||||
scriptShown = true;
|
||||
window.removeEventListener(aEvent.type, _onEvent);
|
||||
runTest();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("Debugger:ScriptShown", onScriptShown);
|
||||
|
||||
function startTest()
|
||||
function runTest()
|
||||
{
|
||||
if (scriptShown && framesAdded && resumed && !testStarted) {
|
||||
window.removeEventListener("Debugger:ScriptShown", onScriptShown);
|
||||
testStarted = true;
|
||||
if (scriptShown && framesAdded) {
|
||||
Services.tm.currentThread.dispatch({ run: testScriptsDisplay }, 0);
|
||||
}
|
||||
}
|
||||
|
@ -92,6 +92,7 @@ function debug_tab_pane(aURL, aOnDebugging)
|
||||
{
|
||||
let tab = addTab(aURL, function() {
|
||||
gBrowser.selectedTab = gTab;
|
||||
|
||||
let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject;
|
||||
|
||||
let pane = DebuggerUI.toggleDebugger();
|
||||
@ -105,17 +106,3 @@ function debug_tab_pane(aURL, aOnDebugging)
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
||||
function remote_debug_tab_pane(aURL, aOnClosing, aOnDebugging)
|
||||
{
|
||||
let tab = addTab(aURL, function() {
|
||||
gBrowser.selectedTab = gTab;
|
||||
let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject;
|
||||
|
||||
DebuggerUI.toggleRemoteDebugger(aOnClosing, function dbgRan(process) {
|
||||
|
||||
// Wait for the remote debugging process to start...
|
||||
aOnDebugging(tab, debuggee, process);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -398,7 +398,7 @@ InspectorUI.prototype = {
|
||||
*/
|
||||
get isInspectorOpen()
|
||||
{
|
||||
return !!(this.toolbar && !this.toolbar.hidden && this.highlighter);
|
||||
return this.toolbar && !this.toolbar.hidden && this.highlighter;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -647,7 +647,7 @@ InspectorUI.prototype = {
|
||||
if (!aKeepInspector)
|
||||
this.store.deleteInspector(this.winID);
|
||||
|
||||
this.inspectMenuitem.removeAttribute("checked");
|
||||
this.inspectMenuitem.setAttribute("checked", false);
|
||||
this.browser = this.win = null; // null out references to browser and window
|
||||
this.winID = null;
|
||||
this.selection = null;
|
||||
|
@ -17,5 +17,3 @@ browser.jar:
|
||||
content/browser/debugger.css (debugger/debugger.css)
|
||||
content/browser/debugger-controller.js (debugger/debugger-controller.js)
|
||||
content/browser/debugger-view.js (debugger/debugger-view.js)
|
||||
content/browser/devtools/gcli.css (webconsole/gcli.css)
|
||||
content/browser/devtools/gcliblank.xhtml (webconsole/gcliblank.xhtml)
|
||||
|
@ -1,476 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the Firefox Developer Toolbar.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2012
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Camp <dcamp@mozilla.com> (Original Author)
|
||||
* Joe Walker <jwalker@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
let EXPORTED_SYMBOLS = [ "DeveloperToolbar", "loadCommands" ];
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gcli", function () {
|
||||
let obj = {};
|
||||
Components.utils.import("resource:///modules/gcli.jsm", obj);
|
||||
return obj.gcli;
|
||||
});
|
||||
|
||||
let console = gcli._internal.console;
|
||||
|
||||
/**
|
||||
* Load the various Command JSMs.
|
||||
* Should be called when the developer toolbar first opens.
|
||||
*/
|
||||
function loadCommands()
|
||||
{
|
||||
Components.utils.import("resource:///modules/GcliCommands.jsm", {});
|
||||
Components.utils.import("resource:///modules/GcliTiltCommands.jsm", {});
|
||||
}
|
||||
|
||||
|
||||
|
||||
let commandsLoaded = false;
|
||||
|
||||
/**
|
||||
* A component to manage the global developer toolbar, which contains a GCLI
|
||||
* and buttons for various developer tools.
|
||||
* @param aChromeWindow The browser window to which this toolbar is attached
|
||||
* @param aToolbarElement See browser.xul:<toolbar id="developer-toolbar">
|
||||
*/
|
||||
function DeveloperToolbar(aChromeWindow, aToolbarElement)
|
||||
{
|
||||
if (!commandsLoaded) {
|
||||
loadCommands();
|
||||
commandsLoaded = true;
|
||||
}
|
||||
|
||||
this._chromeWindow = aChromeWindow;
|
||||
|
||||
this._element = aToolbarElement;
|
||||
this._element.hidden = true;
|
||||
this._doc = this._element.ownerDocument;
|
||||
|
||||
this._command = this._doc.getElementById("Tools:DevToolbar");
|
||||
|
||||
aChromeWindow.getBrowser().tabContainer.addEventListener("TabSelect", this, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspector notifications dispatched through the nsIObserverService
|
||||
*/
|
||||
const NOTIFICATIONS = {
|
||||
/** DeveloperToolbar.show() has been called */
|
||||
SHOW: "developer-toolbar-show",
|
||||
|
||||
/** DeveloperToolbar.hide() has been called */
|
||||
HIDE: "developer-toolbar-hide"
|
||||
};
|
||||
|
||||
/**
|
||||
* Attach notification constants to the object prototype so tests etc can
|
||||
* use them without needing to import anything
|
||||
*/
|
||||
DeveloperToolbar.prototype.NOTIFICATIONS = NOTIFICATIONS;
|
||||
|
||||
/**
|
||||
* Is the toolbar open?
|
||||
*/
|
||||
Object.defineProperty(DeveloperToolbar.prototype, 'visible', {
|
||||
get: function DT_visible() {
|
||||
return !this._element.hidden;
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
/**
|
||||
* Called from browser.xul in response to menu-click or keyboard shortcut to
|
||||
* toggle the toolbar
|
||||
*/
|
||||
DeveloperToolbar.prototype.toggle = function DT_toggle()
|
||||
{
|
||||
if (this.visible) {
|
||||
this.hide();
|
||||
} else {
|
||||
this.show();
|
||||
this._input.focus();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Even if the user has not clicked on 'Got it' in the intro, we only show it
|
||||
* once per session.
|
||||
* Warning this is slightly messed up because this.DeveloperToolbar is not the
|
||||
* same as this.DeveloperToolbar when in browser.js context.
|
||||
*/
|
||||
DeveloperToolbar.introShownThisSession = false;
|
||||
|
||||
/**
|
||||
* Show the developer toolbar
|
||||
*/
|
||||
DeveloperToolbar.prototype.show = function DT_show()
|
||||
{
|
||||
this._command.setAttribute("checked", "true");
|
||||
|
||||
this._input = this._doc.querySelector(".gclitoolbar-input-node");
|
||||
|
||||
this.tooltipPanel = new TooltipPanel(this._doc, this._input);
|
||||
this.outputPanel = new OutputPanel(this._doc, this._input);
|
||||
|
||||
let contentDocument = this._chromeWindow.getBrowser().contentDocument;
|
||||
|
||||
this.display = gcli._internal.createDisplay({
|
||||
contentDocument: contentDocument,
|
||||
chromeDocument: this._doc,
|
||||
chromeWindow: this._chromeWindow,
|
||||
|
||||
hintElement: this.tooltipPanel.hintElement,
|
||||
inputElement: this._input,
|
||||
completeElement: this._doc.querySelector(".gclitoolbar-complete-node"),
|
||||
backgroundElement: this._doc.querySelector(".gclitoolbar-stack-node"),
|
||||
outputDocument: this.outputPanel.document,
|
||||
|
||||
environment: {
|
||||
chromeDocument: this._doc,
|
||||
contentDocument: contentDocument
|
||||
},
|
||||
|
||||
tooltipClass: 'gcliterm-tooltip',
|
||||
eval: null,
|
||||
scratchpad: null
|
||||
});
|
||||
|
||||
this.display.onVisibilityChange.add(this.outputPanel._visibilityChanged, this.outputPanel);
|
||||
this.display.onVisibilityChange.add(this.tooltipPanel._visibilityChanged, this.tooltipPanel);
|
||||
this.display.onOutput.add(this.outputPanel._outputChanged, this.outputPanel);
|
||||
|
||||
this._element.hidden = false;
|
||||
this._notify(NOTIFICATIONS.SHOW);
|
||||
|
||||
if (!DeveloperToolbar.introShownThisSession) {
|
||||
this.display.maybeShowIntro();
|
||||
DeveloperToolbar.introShownThisSession = true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide the developer toolbar
|
||||
*/
|
||||
DeveloperToolbar.prototype.hide = function DT_hide()
|
||||
{
|
||||
this._command.setAttribute("checked", "false");
|
||||
|
||||
this.display.onVisibilityChange.remove(this.outputPanel._visibilityChanged, this.outputPanel);
|
||||
this.display.onVisibilityChange.remove(this.tooltipPanel._visibilityChanged, this.tooltipPanel);
|
||||
this.display.onOutput.remove(this.outputPanel._outputChanged, this.outputPanel);
|
||||
this.display.destroy();
|
||||
|
||||
// We could "delete this.display" etc if we have hard-to-track-down memory
|
||||
// leaks as a belt-and-braces approach, however this prevents our DOM node
|
||||
// hunter from looking in all the nooks and crannies, so it's better if we
|
||||
// can be leak-free without
|
||||
|
||||
this.outputPanel.remove();
|
||||
delete this.outputPanel;
|
||||
|
||||
this.tooltipPanel.remove();
|
||||
delete this.tooltipPanel;
|
||||
|
||||
this._element.hidden = true;
|
||||
this._notify(NOTIFICATIONS.HIDE);
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility for sending notifications
|
||||
* @param aTopic a NOTIFICATION constant
|
||||
*/
|
||||
DeveloperToolbar.prototype._notify = function DT_notify(aTopic)
|
||||
{
|
||||
let data = { toolbar: this };
|
||||
data.wrappedJSObject = data;
|
||||
Services.obs.notifyObservers(data, aTopic, null);
|
||||
};
|
||||
|
||||
/**
|
||||
* Update various parts of the UI when the current tab changes
|
||||
* @param aEvent
|
||||
*/
|
||||
DeveloperToolbar.prototype.handleEvent = function DT_handleEvent(aEvent)
|
||||
{
|
||||
if (aEvent.type == "TabSelect") {
|
||||
this._chromeWindow.HUDConsoleUI.refreshCommand();
|
||||
this._chromeWindow.DebuggerUI.refreshCommand();
|
||||
|
||||
if (this.visible) {
|
||||
let contentDocument = this._chromeWindow.getBrowser().contentDocument;
|
||||
|
||||
this.display.reattach({
|
||||
contentDocument: contentDocument,
|
||||
chromeWindow: this._chromeWindow,
|
||||
environment: {
|
||||
chromeDocument: this._doc,
|
||||
contentDocument: contentDocument
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add class="gcli-panel-inner-arrowcontent" to a panel's
|
||||
* |<xul:box class="panel-inner-arrowcontent">| so we can alter the styling
|
||||
* without complex CSS expressions.
|
||||
* @param aPanel The panel to affect
|
||||
*/
|
||||
function getContentBox(aPanel)
|
||||
{
|
||||
let container = aPanel.ownerDocument.getAnonymousElementByAttribute(
|
||||
aPanel, "anonid", "container");
|
||||
return container.querySelector(".panel-inner-arrowcontent");
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to calculate the sum of the vertical padding and margins
|
||||
* between a nested node |aNode| and an ancestor |aRoot|. Iff all of the
|
||||
* children of aRoot are 'only-childs' until you get to aNode then to avoid
|
||||
* scroll-bars, the 'correct' height of aRoot is verticalSpacing + aNode.height.
|
||||
* @param aNode The child node whose height is known.
|
||||
* @param aRoot The parent height whose height we can affect.
|
||||
* @return The sum of the vertical padding/margins in between aNode and aRoot.
|
||||
*/
|
||||
function getVerticalSpacing(aNode, aRoot)
|
||||
{
|
||||
let win = aNode.ownerDocument.defaultView;
|
||||
|
||||
function pxToNum(styles, property) {
|
||||
return parseInt(styles.getPropertyValue(property).replace(/px$/, ''), 10);
|
||||
}
|
||||
|
||||
let vertSpacing = 0;
|
||||
do {
|
||||
let styles = win.getComputedStyle(aNode);
|
||||
vertSpacing += pxToNum(styles, "padding-top");
|
||||
vertSpacing += pxToNum(styles, "padding-bottom");
|
||||
vertSpacing += pxToNum(styles, "margin-top");
|
||||
vertSpacing += pxToNum(styles, "margin-bottom");
|
||||
vertSpacing += pxToNum(styles, "border-top-width");
|
||||
vertSpacing += pxToNum(styles, "border-bottom-width");
|
||||
|
||||
let prev = aNode.previousSibling;
|
||||
while (prev != null) {
|
||||
vertSpacing += prev.clientHeight;
|
||||
prev = prev.previousSibling;
|
||||
}
|
||||
|
||||
let next = aNode.nextSibling;
|
||||
while (next != null) {
|
||||
vertSpacing += next.clientHeight;
|
||||
next = next.nextSibling;
|
||||
}
|
||||
|
||||
aNode = aNode.parentNode;
|
||||
} while (aNode !== aRoot);
|
||||
|
||||
return vertSpacing + 9;
|
||||
}
|
||||
|
||||
/**
|
||||
* Panel to handle command line output.
|
||||
* @param aChromeDoc document from which we can pull the parts we need.
|
||||
* @param aInput the input element that should get focus.
|
||||
*/
|
||||
function OutputPanel(aChromeDoc, aInput)
|
||||
{
|
||||
this._input = aInput;
|
||||
this._panel = aChromeDoc.getElementById("gcli-output");
|
||||
this._frame = aChromeDoc.getElementById("gcli-output-frame");
|
||||
this._anchor = aChromeDoc.getElementById("developer-toolbar");
|
||||
|
||||
this._content = getContentBox(this._panel);
|
||||
this._content.classList.add("gcli-panel-inner-arrowcontent");
|
||||
|
||||
this.document = this._frame.contentDocument;
|
||||
this.document.body.classList.add("gclichrome-output");
|
||||
|
||||
this._div = this.document.querySelector("div");
|
||||
this._div.classList.add('gcli-row-out');
|
||||
this._div.setAttribute('aria-live', 'assertive');
|
||||
|
||||
this.displayedOutput = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the OutputPanel.
|
||||
*/
|
||||
OutputPanel.prototype.show = function OP_show()
|
||||
{
|
||||
this._panel.ownerDocument.defaultView.setTimeout(function() {
|
||||
this._resize();
|
||||
}.bind(this), 0);
|
||||
|
||||
this._resize();
|
||||
this._panel.openPopup(this._anchor, "before_end", -300, 0, false, false, null);
|
||||
|
||||
this._input.focus();
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal helper to set the height of the output panel to fit the available
|
||||
* content;
|
||||
*/
|
||||
OutputPanel.prototype._resize = function CLP_resize()
|
||||
{
|
||||
let vertSpacing = getVerticalSpacing(this._content, this._panel);
|
||||
let idealHeight = this.document.body.scrollHeight + vertSpacing;
|
||||
this._panel.sizeTo(400, Math.min(idealHeight, 500));
|
||||
};
|
||||
|
||||
/**
|
||||
* Called by GCLI when a command is executed.
|
||||
*/
|
||||
OutputPanel.prototype._outputChanged = function OP_outputChanged(aEvent)
|
||||
{
|
||||
if (aEvent.output.hidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.remove();
|
||||
|
||||
this.displayedOutput = aEvent.output;
|
||||
this.update();
|
||||
|
||||
this.displayedOutput.onChange.add(this.update, this);
|
||||
this.displayedOutput.onClose.add(this.remove, this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when displayed Output says it's changed or from outputChanged, which
|
||||
* happens when there is a new displayed Output.
|
||||
*/
|
||||
OutputPanel.prototype.update = function OP_update()
|
||||
{
|
||||
if (this.displayedOutput.data == null) {
|
||||
while (this._div.hasChildNodes()) {
|
||||
this._div.removeChild(this._div.firstChild);
|
||||
}
|
||||
} else {
|
||||
this.displayedOutput.toDom(this._div);
|
||||
this.show();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Detach listeners from the currently displayed Output.
|
||||
*/
|
||||
OutputPanel.prototype.remove = function OP_remove()
|
||||
{
|
||||
this._panel.hidePopup();
|
||||
|
||||
if (this.displayedOutput) {
|
||||
this.displayedOutput.onChange.remove(this.update, this);
|
||||
this.displayedOutput.onClose.remove(this.remove, this);
|
||||
delete this.displayedOutput;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Called by GCLI to indicate that we should show or hide one either the
|
||||
* tooltip panel or the output panel.
|
||||
*/
|
||||
OutputPanel.prototype._visibilityChanged = function OP_visibilityChanged(aEvent)
|
||||
{
|
||||
if (aEvent.outputVisible === true) {
|
||||
// this.show is called by _outputChanged
|
||||
} else {
|
||||
this._panel.hidePopup();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Panel to handle tooltips.
|
||||
* @param aChromeDoc document from which we can pull the parts we need.
|
||||
* @param aInput the input element that should get focus.
|
||||
*/
|
||||
function TooltipPanel(aChromeDoc, aInput)
|
||||
{
|
||||
this._input = aInput;
|
||||
this._panel = aChromeDoc.getElementById("gcli-tooltip");
|
||||
this._frame = aChromeDoc.getElementById("gcli-tooltip-frame");
|
||||
this._anchor = aChromeDoc.getElementById("developer-toolbar");
|
||||
|
||||
this._content = getContentBox(this._panel);
|
||||
this._content.classList.add("gcli-panel-inner-arrowcontent");
|
||||
|
||||
this.document = this._frame.contentDocument;
|
||||
this.document.body.classList.add("gclichrome-tooltip");
|
||||
|
||||
this.hintElement = this.document.querySelector("div");
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the TooltipPanel.
|
||||
*/
|
||||
TooltipPanel.prototype.show = function TP_show()
|
||||
{
|
||||
let vertSpacing = getVerticalSpacing(this._content, this._panel);
|
||||
let idealHeight = this.document.body.scrollHeight + vertSpacing;
|
||||
this._panel.sizeTo(350, Math.min(idealHeight, 500));
|
||||
this._panel.openPopup(this._anchor, "before_start", 0, 0, false, false, null);
|
||||
|
||||
this._input.focus();
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide the TooltipPanel.
|
||||
*/
|
||||
TooltipPanel.prototype.remove = function TP_remove()
|
||||
{
|
||||
this._panel.hidePopup();
|
||||
};
|
||||
|
||||
/**
|
||||
* Called by GCLI to indicate that we should show or hide one either the
|
||||
* tooltip panel or the output panel.
|
||||
*/
|
||||
TooltipPanel.prototype._visibilityChanged = function TP_visibilityChanged(aEvent)
|
||||
{
|
||||
if (aEvent.tooltipVisible === true) {
|
||||
this.show();
|
||||
} else {
|
||||
this._panel.hidePopup();
|
||||
}
|
||||
};
|
@ -42,11 +42,6 @@ var EXPORTED_SYMBOLS = [ "Templater", "template" ];
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
const Node = Components.interfaces.nsIDOMNode;
|
||||
|
||||
/**
|
||||
* For full documentation, see:
|
||||
* https://github.com/mozilla/domtemplate/blob/master/README.md
|
||||
*/
|
||||
|
||||
// WARNING: do not 'use_strict' without reading the notes in _envEval();
|
||||
|
||||
/**
|
||||
@ -55,16 +50,8 @@ const Node = Components.interfaces.nsIDOMNode;
|
||||
* @param data Data to use in filling out the template
|
||||
* @param options Options to customize the template processing. One of:
|
||||
* - allowEval: boolean (default false) Basic template interpolations are
|
||||
* either property paths (e.g. ${a.b.c.d}), or if allowEval=true then we
|
||||
* allow arbitrary JavaScript
|
||||
* - stack: string or array of strings (default empty array) The template
|
||||
* engine maintains a stack of tasks to help debug where it is. This allows
|
||||
* this stack to be prefixed with a template name
|
||||
* - blankNullUndefined: By default DOMTemplate exports null and undefined
|
||||
* values using the strings 'null' and 'undefined', which can be helpful for
|
||||
* debugging, but can introduce unnecessary extra logic in a template to
|
||||
* convert null/undefined to ''. By setting blankNullUndefined:true, this
|
||||
* conversion is handled by DOMTemplate
|
||||
* either property paths (e.g. ${a.b.c.d}), however if allowEval=true then we
|
||||
* allow arbitrary JavaScript
|
||||
*/
|
||||
function template(node, data, options) {
|
||||
var template = new Templater(options || {});
|
||||
@ -81,15 +68,7 @@ function Templater(options) {
|
||||
options = { allowEval: true };
|
||||
}
|
||||
this.options = options;
|
||||
if (options.stack && Array.isArray(options.stack)) {
|
||||
this.stack = options.stack;
|
||||
}
|
||||
else if (typeof options.stack === 'string') {
|
||||
this.stack = [ options.stack ];
|
||||
}
|
||||
else {
|
||||
this.stack = [];
|
||||
}
|
||||
this.stack = [];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -111,7 +90,7 @@ Templater.prototype._splitSpecial = /\uF001|\uF002/;
|
||||
* Cached regex used to detect if a script is capable of being interpreted
|
||||
* using Template._property() or if we need to use Template._envEval()
|
||||
*/
|
||||
Templater.prototype._isPropertyScript = /^[_a-zA-Z0-9.]*$/;
|
||||
Templater.prototype._isPropertyScript = /^[a-zA-Z0-9.]*$/;
|
||||
|
||||
/**
|
||||
* Recursive function to walk the tree processing the attributes as it goes.
|
||||
@ -174,11 +153,7 @@ Templater.prototype.processNode = function(node, data) {
|
||||
} else {
|
||||
// Replace references in all other attributes
|
||||
var newValue = value.replace(this._templateRegion, function(path) {
|
||||
var insert = this._envEval(path.slice(2, -1), data, value);
|
||||
if (this.options.blankNullUndefined && insert == null) {
|
||||
insert = '';
|
||||
}
|
||||
return insert;
|
||||
return this._envEval(path.slice(2, -1), data, value);
|
||||
}.bind(this));
|
||||
// Remove '_' prefix of attribute names so the DOM won't try
|
||||
// to use them before we've processed the template
|
||||
@ -202,7 +177,7 @@ Templater.prototype.processNode = function(node, data) {
|
||||
this.processNode(childNodes[j], data);
|
||||
}
|
||||
|
||||
if (node.nodeType === 3 /*Node.TEXT_NODE*/) {
|
||||
if (node.nodeType === Node.TEXT_NODE) {
|
||||
this._processTextNode(node, data);
|
||||
}
|
||||
} finally {
|
||||
@ -372,27 +347,8 @@ Templater.prototype._processTextNode = function(node, data) {
|
||||
part = this._envEval(part.slice(1), data, node.data);
|
||||
}
|
||||
this._handleAsync(part, node, function(reply, siblingNode) {
|
||||
var doc = siblingNode.ownerDocument;
|
||||
if (reply == null) {
|
||||
reply = this.options.blankNullUndefined ? '' : '' + reply;
|
||||
}
|
||||
if (typeof reply.cloneNode === 'function') {
|
||||
// i.e. if (reply instanceof Element) { ...
|
||||
reply = this._maybeImportNode(reply, doc);
|
||||
siblingNode.parentNode.insertBefore(reply, siblingNode);
|
||||
} else if (typeof reply.item === 'function' && reply.length) {
|
||||
// if thing is a NodeList, then import the children
|
||||
for (var i = 0; i < reply.length; i++) {
|
||||
var child = this._maybeImportNode(reply.item(i), doc);
|
||||
siblingNode.parentNode.insertBefore(child, siblingNode);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// if thing isn't a DOM element then wrap its string value in one
|
||||
reply = doc.createTextNode(reply.toString());
|
||||
siblingNode.parentNode.insertBefore(reply, siblingNode);
|
||||
}
|
||||
|
||||
reply = this._toNode(reply, siblingNode.ownerDocument);
|
||||
siblingNode.parentNode.insertBefore(reply, siblingNode);
|
||||
}.bind(this));
|
||||
}, this);
|
||||
node.parentNode.removeChild(node);
|
||||
@ -400,13 +356,21 @@ Templater.prototype._processTextNode = function(node, data) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Return node or a import of node, if it's not in the given document
|
||||
* @param node The node that we want to be properly owned
|
||||
* @param doc The document that the given node should belong to
|
||||
* @return A node that belongs to the given document
|
||||
* Helper to convert a 'thing' to a DOM Node.
|
||||
* This is (obviously) a no-op for DOM Elements (which are detected using
|
||||
* 'typeof thing.cloneNode !== "function"' (is there a better way that will
|
||||
* work in all environments, including a .jsm?)
|
||||
* Non DOM elements are converted to a string and wrapped in a TextNode.
|
||||
*/
|
||||
Templater.prototype._maybeImportNode = function(node, doc) {
|
||||
return node.ownerDocument === doc ? node : doc.importNode(node, true);
|
||||
Templater.prototype._toNode = function(thing, document) {
|
||||
if (thing == null) {
|
||||
thing = '' + thing;
|
||||
}
|
||||
// if thing isn't a DOM element then wrap its string value in one
|
||||
if (typeof thing.cloneNode !== 'function') {
|
||||
thing = document.createTextNode(thing.toString());
|
||||
}
|
||||
return thing;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -465,6 +429,7 @@ Templater.prototype._stripBraces = function(str) {
|
||||
* <tt>newValue</tt> is applied.
|
||||
*/
|
||||
Templater.prototype._property = function(path, data, newValue) {
|
||||
this.stack.push(path);
|
||||
try {
|
||||
if (typeof path === 'string') {
|
||||
path = path.split('.');
|
||||
@ -480,13 +445,12 @@ Templater.prototype._property = function(path, data, newValue) {
|
||||
return value;
|
||||
}
|
||||
if (!value) {
|
||||
this._handleError('"' + path[0] + '" is undefined');
|
||||
this._handleError('Can\'t find path=' + path);
|
||||
return null;
|
||||
}
|
||||
return this._property(path.slice(1), value, newValue);
|
||||
} catch (ex) {
|
||||
this._handleError('Path error with \'' + path + '\'', ex);
|
||||
return '${' + path + '}';
|
||||
} finally {
|
||||
this.stack.pop();
|
||||
}
|
||||
};
|
||||
|
||||
@ -505,7 +469,7 @@ Templater.prototype._property = function(path, data, newValue) {
|
||||
*/
|
||||
Templater.prototype._envEval = function(script, data, frame) {
|
||||
try {
|
||||
this.stack.push(frame.replace(/\s+/g, ' '));
|
||||
this.stack.push(frame);
|
||||
if (this._isPropertyScript.test(script)) {
|
||||
return this._property(script, data);
|
||||
} else {
|
||||
@ -519,7 +483,8 @@ Templater.prototype._envEval = function(script, data, frame) {
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
this._handleError('Template error evaluating \'' + script + '\'', ex);
|
||||
this._handleError('Template error evaluating \'' + script + '\'' +
|
||||
' environment=' + Object.keys(data).join(', '), ex);
|
||||
return '${' + script + '}';
|
||||
} finally {
|
||||
this.stack.pop();
|
||||
@ -533,7 +498,8 @@ Templater.prototype._envEval = function(script, data, frame) {
|
||||
* @param ex optional associated exception.
|
||||
*/
|
||||
Templater.prototype._handleError = function(message, ex) {
|
||||
this._logError(message + ' (In: ' + this.stack.join(' > ') + ')');
|
||||
this._logError(message);
|
||||
this._logError('In: ' + this.stack.join(' > '));
|
||||
if (ex) {
|
||||
this._logError(ex);
|
||||
}
|
||||
|
@ -49,21 +49,11 @@ include $(topsrcdir)/config/rules.mk
|
||||
_BROWSER_TEST_FILES = \
|
||||
browser_promise_basic.js \
|
||||
browser_templater_basic.js \
|
||||
browser_toolbar_basic.js \
|
||||
browser_gcli_commands.js \
|
||||
browser_gcli_inspect.js \
|
||||
browser_gcli_integrate.js \
|
||||
browser_gcli_require.js \
|
||||
browser_gcli_web.js \
|
||||
browser_gcli_break.js \
|
||||
head.js \
|
||||
$(NULL)
|
||||
|
||||
_BROWSER_TEST_PAGES = \
|
||||
browser_templater_basic.html \
|
||||
browser_toolbar_basic.html \
|
||||
browser_gcli_inspect.html \
|
||||
browser_gcli_break.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_BROWSER_TEST_FILES)
|
||||
|
@ -1,82 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that the break command works as it should
|
||||
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/shared/test/browser_gcli_break.html";
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
|
||||
testBreakCommands();
|
||||
});
|
||||
}
|
||||
|
||||
function testBreakCommands() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "brea",
|
||||
directTabText: "k",
|
||||
status: "ERROR"
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "break",
|
||||
status: "ERROR"
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "break add",
|
||||
status: "ERROR"
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "break add line",
|
||||
emptyParameters: [ " <file>", " <line>" ],
|
||||
status: "ERROR"
|
||||
});
|
||||
|
||||
let pane = DebuggerUI.toggleDebugger();
|
||||
pane._frame.addEventListener("Debugger:Connecting", function dbgConnected() {
|
||||
pane._frame.removeEventListener("Debugger:Connecting", dbgConnected, true);
|
||||
|
||||
// Wait for the initial resume.
|
||||
let client = pane.debuggerWindow.gClient;
|
||||
client.addOneTimeListener("resumed", function() {
|
||||
client.activeThread.addOneTimeListener("framesadded", function() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "break add line " + TEST_URI + " " + content.wrappedJSObject.line0,
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.exec({
|
||||
args: {
|
||||
type: 'line',
|
||||
file: TEST_URI,
|
||||
line: content.wrappedJSObject.line0
|
||||
},
|
||||
completed: false
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "break list",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.exec();
|
||||
|
||||
client.activeThread.resume(function() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "break del 0",
|
||||
status: "VALID"
|
||||
});
|
||||
DeveloperToolbarTest.exec({
|
||||
args: { breakid: 0 },
|
||||
completed: false
|
||||
});
|
||||
|
||||
finish();
|
||||
});
|
||||
});
|
||||
|
||||
// Trigger newScript notifications using eval.
|
||||
content.wrappedJSObject.firstCall();
|
||||
});
|
||||
}, true);
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test various GCLI commands
|
||||
|
||||
let imported = {};
|
||||
Components.utils.import("resource:///modules/HUDService.jsm", imported);
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,gcli-commands";
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
|
||||
testEcho();
|
||||
testConsoleClear();
|
||||
testConsoleOpenClose(tab);
|
||||
|
||||
imported = undefined;
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
function testEcho() {
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "echo message",
|
||||
args: { message: "message" },
|
||||
outputMatch: /^message$/,
|
||||
});
|
||||
}
|
||||
|
||||
function testConsoleClear() {
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "console clear",
|
||||
args: {},
|
||||
blankOutput: true,
|
||||
});
|
||||
}
|
||||
|
||||
function testConsoleOpenClose(tab) {
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "console open",
|
||||
args: {},
|
||||
blankOutput: true,
|
||||
});
|
||||
|
||||
let hud = imported.HUDService.getHudByWindow(content);
|
||||
ok(hud.hudId in imported.HUDService.hudReferences, "console open");
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "console close",
|
||||
args: {},
|
||||
blankOutput: true,
|
||||
});
|
||||
|
||||
ok(!(hud.hudId in imported.HUDService.hudReferences), "console closed");
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that the inspect command works as it should
|
||||
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/shared/test/browser_gcli_inspect.html";
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
|
||||
testInspect();
|
||||
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
function testInspect() {
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "inspec",
|
||||
directTabText: "t",
|
||||
status: "ERROR"
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "inspect",
|
||||
emptyParameters: [ " <node>" ],
|
||||
status: "ERROR"
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "inspect h1",
|
||||
status: "ERROR"
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "inspect span",
|
||||
status: "ERROR"
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "inspect div",
|
||||
status: "VALID"
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "inspect .someclass",
|
||||
status: "VALID"
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "inspect #someid",
|
||||
status: "VALID"
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "inspect button[disabled]",
|
||||
status: "VALID"
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "inspect p>strong",
|
||||
status: "VALID"
|
||||
});
|
||||
|
||||
DeveloperToolbarTest.checkInputStatus({
|
||||
typed: "inspect :root",
|
||||
status: "VALID"
|
||||
});
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that source URLs in the Web Console can be clicked to display the
|
||||
// standard View Source window.
|
||||
|
||||
function test() {
|
||||
testCreateCommands();
|
||||
testRemoveCommands();
|
||||
}
|
||||
|
||||
let tselarr = {
|
||||
name: 'tselarr',
|
||||
params: [
|
||||
{ name: 'num', type: { name: 'selection', data: [ '1', '2', '3' ] } },
|
||||
{ name: 'arr', type: { name: 'array', subtype: 'string' } },
|
||||
],
|
||||
exec: function(args, env) {
|
||||
return "flu " + args.num + "-" + args.arr.join("_");
|
||||
}
|
||||
};
|
||||
|
||||
function testCreateCommands() {
|
||||
let gcliIndex = require("gcli/index");
|
||||
gcliIndex.addCommand(tselarr);
|
||||
|
||||
let canon = require("gcli/canon");
|
||||
let tselcmd = canon.getCommand("tselarr");
|
||||
ok(tselcmd != null, "tselarr exists in the canon");
|
||||
ok(tselcmd instanceof canon.Command, "canon storing commands");
|
||||
}
|
||||
|
||||
function testRemoveCommands() {
|
||||
let gcliIndex = require("gcli/index");
|
||||
gcliIndex.removeCommand(tselarr);
|
||||
|
||||
let canon = require("gcli/canon");
|
||||
let tselcmd = canon.getCommand("tselarr");
|
||||
ok(tselcmd == null, "tselcmd removed from the canon");
|
||||
}
|
@ -3,15 +3,11 @@
|
||||
|
||||
// Tests that the DOM Template engine works properly
|
||||
|
||||
/*
|
||||
* These tests run both in Mozilla/Mochitest and plain browsers (as does
|
||||
* domtemplate)
|
||||
* We should endevour to keep the source in sync.
|
||||
*/
|
||||
|
||||
var imports = {};
|
||||
Cu.import("resource:///modules/devtools/Templater.jsm", imports);
|
||||
Cu.import("resource:///modules/devtools/Promise.jsm", imports);
|
||||
let tempScope = {};
|
||||
Cu.import("resource:///modules/devtools/Templater.jsm", tempScope);
|
||||
Cu.import("resource:///modules/devtools/Promise.jsm", tempScope);
|
||||
let template = tempScope.template;
|
||||
let Promise = tempScope.Promise;
|
||||
|
||||
function test() {
|
||||
addTab("http://example.com/browser/browser/devtools/shared/test/browser_templater_basic.html", function() {
|
||||
@ -29,7 +25,7 @@ function runTest(index) {
|
||||
holder.innerHTML = options.template;
|
||||
|
||||
info('Running ' + options.name);
|
||||
imports.template(holder, options.data, options.options);
|
||||
template(holder, options.data, options.options);
|
||||
|
||||
if (typeof options.result == 'string') {
|
||||
is(holder.innerHTML, options.result, options.name);
|
||||
@ -242,43 +238,11 @@ var tests = [
|
||||
name: 'propertyFail',
|
||||
template: '<p>${Math.max(1, 2)}</p>',
|
||||
result: '<p>${Math.max(1, 2)}</p>'
|
||||
};},
|
||||
|
||||
// Bug 723431: DOMTemplate should allow customisation of display of
|
||||
// null/undefined values
|
||||
function() { return {
|
||||
name: 'propertyUndefAttrFull',
|
||||
template: '<p>${nullvar}|${undefinedvar1}|${undefinedvar2}</p>',
|
||||
data: { nullvar: null, undefinedvar1: undefined },
|
||||
result: '<p>null|undefined|undefined</p>'
|
||||
};},
|
||||
|
||||
function() { return {
|
||||
name: 'propertyUndefAttrBlank',
|
||||
template: '<p>${nullvar}|${undefinedvar1}|${undefinedvar2}</p>',
|
||||
data: { nullvar: null, undefinedvar1: undefined },
|
||||
options: { blankNullUndefined: true },
|
||||
result: '<p>||</p>'
|
||||
};},
|
||||
|
||||
function() { return {
|
||||
name: 'propertyUndefAttrFull',
|
||||
template: '<div><p value="${nullvar}"></p><p value="${undefinedvar1}"></p><p value="${undefinedvar2}"></p></div>',
|
||||
data: { nullvar: null, undefinedvar1: undefined },
|
||||
result: '<div><p value="null"></p><p value="undefined"></p><p value="undefined"></p></div>'
|
||||
};},
|
||||
|
||||
function() { return {
|
||||
name: 'propertyUndefAttrBlank',
|
||||
template: '<div><p value="${nullvar}"></p><p value="${undefinedvar1}"></p><p value="${undefinedvar2}"></p></div>',
|
||||
data: { nullvar: null, undefinedvar1: undefined },
|
||||
options: { blankNullUndefined: true },
|
||||
result: '<div><p value=""></p><p value=""></p><p value=""></p></div>'
|
||||
};}
|
||||
];
|
||||
|
||||
function delayReply(data) {
|
||||
var p = new imports.Promise();
|
||||
var p = new Promise();
|
||||
executeSoon(function() {
|
||||
p.resolve(data);
|
||||
});
|
||||
|
@ -1,35 +0,0 @@
|
||||
<!doctype html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Developer Toolbar Tests</title>
|
||||
<style type="text/css">
|
||||
#single { color: red; }
|
||||
</style>
|
||||
<script type="text/javascript">var a=1;</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p id=single>
|
||||
1
|
||||
</p>
|
||||
|
||||
<p class=twin>
|
||||
2a
|
||||
</p>
|
||||
|
||||
<p class=twin>
|
||||
2b
|
||||
</p>
|
||||
|
||||
<style>
|
||||
.twin { color: blue; }
|
||||
</style>
|
||||
<script>var b=2;</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,36 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that the developer toolbar works properly
|
||||
|
||||
const URL = "http://example.com/browser/browser/devtools/shared/test/browser_toolbar_basic.html";
|
||||
|
||||
function test() {
|
||||
addTab(URL, function(browser, tab) {
|
||||
info("Starting browser_toolbar_basic.js");
|
||||
runTest();
|
||||
});
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
Services.obs.addObserver(checkOpen, DeveloperToolbar.NOTIFICATIONS.SHOW, false);
|
||||
// TODO: reopen the window so the pref has a chance to take effect
|
||||
// EventUtils.synthesizeKey("v", { ctrlKey: true, shiftKey: true });
|
||||
DeveloperToolbarTest.show();
|
||||
}
|
||||
|
||||
function checkOpen() {
|
||||
Services.obs.removeObserver(checkOpen, DeveloperToolbar.NOTIFICATIONS.SHOW, false);
|
||||
ok(DeveloperToolbar.visible, "DeveloperToolbar is visible");
|
||||
|
||||
Services.obs.addObserver(checkClosed, DeveloperToolbar.NOTIFICATIONS.HIDE, false);
|
||||
// EventUtils.synthesizeKey("v", { ctrlKey: true, shiftKey: true });
|
||||
DeveloperToolbarTest.hide();
|
||||
}
|
||||
|
||||
function checkClosed() {
|
||||
Services.obs.removeObserver(checkClosed, DeveloperToolbar.NOTIFICATIONS.HIDE, false);
|
||||
ok(!DeveloperToolbar.visible, "DeveloperToolbar is not visible");
|
||||
|
||||
finish();
|
||||
}
|
@ -36,38 +36,23 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
let gcli;
|
||||
let console;
|
||||
let require;
|
||||
let define;
|
||||
let tab;
|
||||
let browser;
|
||||
|
||||
(function() {
|
||||
let tempScope = {};
|
||||
Components.utils.import("resource:///modules/gcli.jsm", tempScope);
|
||||
|
||||
gcli = tempScope.gcli;
|
||||
console = gcli._internal.console;
|
||||
define = gcli._internal.define;
|
||||
require = gcli._internal.require;
|
||||
})();
|
||||
|
||||
/**
|
||||
* Open a new tab at a URL and call a callback on load
|
||||
*/
|
||||
function addTab(aURL, aCallback)
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
|
||||
function onTabLoad() {
|
||||
browser.removeEventListener("load", onTabLoad, true);
|
||||
aCallback();
|
||||
}
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
content.location = aURL;
|
||||
|
||||
let tab = gBrowser.selectedTab;
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
|
||||
function onTabLoad() {
|
||||
browser.removeEventListener("load", onTabLoad, true);
|
||||
aCallback(browser, tab);
|
||||
}
|
||||
tab = gBrowser.selectedTab;
|
||||
browser = gBrowser.getBrowserForTab(tab);
|
||||
|
||||
browser.addEventListener("load", onTabLoad, true);
|
||||
}
|
||||
@ -77,236 +62,6 @@ registerCleanupFunction(function tearDown() {
|
||||
gBrowser.removeCurrentTab();
|
||||
}
|
||||
|
||||
console = undefined;
|
||||
define = undefined;
|
||||
require = undefined;
|
||||
gcli = undefined;
|
||||
tab = undefined;
|
||||
browser = undefined;
|
||||
});
|
||||
|
||||
/**
|
||||
* Various functions for testing DeveloperToolbar
|
||||
*/
|
||||
let DeveloperToolbarTest = {
|
||||
/**
|
||||
* Paranoid DeveloperToolbar.show();
|
||||
*/
|
||||
show: function DTT_show() {
|
||||
if (DeveloperToolbar.visible) {
|
||||
ok(false, "DeveloperToolbar.visible at start of openDeveloperToolbar");
|
||||
}
|
||||
else {
|
||||
DeveloperToolbar.show();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Paranoid DeveloperToolbar.hide();
|
||||
*/
|
||||
hide: function DTT_hide() {
|
||||
if (!DeveloperToolbar.visible) {
|
||||
ok(false, "!DeveloperToolbar.visible at start of closeDeveloperToolbar");
|
||||
}
|
||||
else {
|
||||
DeveloperToolbar.display.inputter.setInput("");
|
||||
DeveloperToolbar.hide();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check that we can parse command input.
|
||||
* Doesn't execute the command, just checks that we grok the input properly:
|
||||
*
|
||||
* DeveloperToolbarTest.checkInputStatus({
|
||||
* // Test inputs
|
||||
* typed: "ech", // Required
|
||||
* cursor: 3, // Optional cursor position
|
||||
*
|
||||
* // Thing to check
|
||||
* status: "INCOMPLETE", // One of "VALID", "ERROR", "INCOMPLETE"
|
||||
* emptyParameters: [ "<message>" ], // Still to type
|
||||
* directTabText: "o", // Simple completion text
|
||||
* arrowTabText: "", // When the completion is not an extension
|
||||
* });
|
||||
*/
|
||||
checkInputStatus: function DTT_checkInputStatus(test) {
|
||||
if (test.typed) {
|
||||
DeveloperToolbar.display.inputter.setInput(test.typed);
|
||||
}
|
||||
else {
|
||||
ok(false, "Missing typed for " + JSON.stringify(test));
|
||||
return;
|
||||
}
|
||||
|
||||
if (test.cursor) {
|
||||
DeveloperToolbar.display.inputter.setCursor(test.cursor)
|
||||
}
|
||||
|
||||
if (test.status) {
|
||||
is(DeveloperToolbar.display.requisition.getStatus().toString(),
|
||||
test.status,
|
||||
"status for " + test.typed);
|
||||
}
|
||||
|
||||
if (test.emptyParameters == null) {
|
||||
test.emptyParameters = [];
|
||||
}
|
||||
|
||||
let completer = DeveloperToolbar.display.completer;
|
||||
let realParams = completer.emptyParameters;
|
||||
is(realParams.length, test.emptyParameters.length,
|
||||
'emptyParameters.length for \'' + test.typed + '\'');
|
||||
|
||||
if (realParams.length === test.emptyParameters.length) {
|
||||
for (let i = 0; i < realParams.length; i++) {
|
||||
is(realParams[i].replace(/\u00a0/g, ' '), test.emptyParameters[i],
|
||||
'emptyParameters[' + i + '] for \'' + test.typed + '\'');
|
||||
}
|
||||
}
|
||||
|
||||
if (test.directTabText) {
|
||||
is(completer.directTabText, test.directTabText,
|
||||
'directTabText for \'' + test.typed + '\'');
|
||||
}
|
||||
else {
|
||||
is(completer.directTabText, '', 'directTabText for \'' + test.typed + '\'');
|
||||
}
|
||||
|
||||
if (test.arrowTabText) {
|
||||
is(completer.arrowTabText, ' \u00a0\u21E5 ' + test.arrowTabText,
|
||||
'arrowTabText for \'' + test.typed + '\'');
|
||||
}
|
||||
else {
|
||||
is(completer.arrowTabText, '', 'arrowTabText for \'' + test.typed + '\'');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Execute a command:
|
||||
*
|
||||
* DeveloperToolbarTest.exec({
|
||||
* // Test inputs
|
||||
* typed: "echo hi", // Optional, uses existing if undefined
|
||||
*
|
||||
* // Thing to check
|
||||
* args: { message: "hi" }, // Check that the args were understood properly
|
||||
* outputMatch: /^hi$/, // Regex to test against textContent of output
|
||||
* blankOutput: true, // Special checks when there is no output
|
||||
* });
|
||||
*/
|
||||
exec: function DTT_exec(test) {
|
||||
test = test || {};
|
||||
|
||||
if (test.typed) {
|
||||
DeveloperToolbar.display.inputter.setInput(test.typed);
|
||||
}
|
||||
|
||||
let typed = DeveloperToolbar.display.inputter.getInputState().typed;
|
||||
let output = DeveloperToolbar.display.requisition.exec();
|
||||
|
||||
is(typed, output.typed, 'output.command for: ' + typed);
|
||||
|
||||
if (test.completed !== false) {
|
||||
ok(output.completed, 'output.completed false for: ' + typed);
|
||||
}
|
||||
else {
|
||||
// It is actually an error if we say something is async and it turns
|
||||
// out not to be? For now we're saying 'no'
|
||||
// ok(!output.completed, 'output.completed true for: ' + typed);
|
||||
}
|
||||
|
||||
if (test.args != null) {
|
||||
is(Object.keys(test.args).length, Object.keys(output.args).length,
|
||||
'arg count for ' + typed);
|
||||
|
||||
Object.keys(output.args).forEach(function(arg) {
|
||||
let expectedArg = test.args[arg];
|
||||
let actualArg = output.args[arg];
|
||||
|
||||
if (Array.isArray(expectedArg)) {
|
||||
if (!Array.isArray(actualArg)) {
|
||||
ok(false, 'actual is not an array. ' + typed + '/' + arg);
|
||||
return;
|
||||
}
|
||||
|
||||
is(expectedArg.length, actualArg.length,
|
||||
'array length: ' + typed + '/' + arg);
|
||||
for (let i = 0; i < expectedArg.length; i++) {
|
||||
is(expectedArg[i], actualArg[i],
|
||||
'member: "' + typed + '/' + arg + '/' + i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let displayed = DeveloperToolbar.outputPanel._div.textContent;
|
||||
|
||||
if (test.outputMatch) {
|
||||
if (!test.outputMatch.test(displayed)) {
|
||||
ok(false, "html output for " + typed + " (textContent sent to info)");
|
||||
info("Actual textContent");
|
||||
info(displayed);
|
||||
}
|
||||
}
|
||||
|
||||
if (test.blankOutput != null) {
|
||||
if (!/^$/.test(displayed)) {
|
||||
ok(false, "html output for " + typed + " (textContent sent to info)");
|
||||
info("Actual textContent");
|
||||
info(displayed);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Quick wrapper around the things you need to do to run DeveloperToolbar
|
||||
* command tests:
|
||||
* - Set the pref 'devtools.toolbar.enabled' to true
|
||||
* - Add a tab pointing at |uri|
|
||||
* - Open the DeveloperToolbar
|
||||
* - Register a cleanup function to undo the above
|
||||
* - Run the tests
|
||||
*
|
||||
* @param uri The uri of a page to load. Can be 'about:blank' or 'data:...'
|
||||
* @param testFunc A function containing the tests to run. This should
|
||||
* arrange for 'finish()' to be called on completion.
|
||||
*/
|
||||
test: function DTT_test(uri, testFunc) {
|
||||
let menuItem = document.getElementById("menu_devToolbar");
|
||||
let command = document.getElementById("Tools:DevToolbar");
|
||||
let appMenuItem = document.getElementById("appmenu_devToolbar");
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
DeveloperToolbarTest.hide();
|
||||
|
||||
// a.k.a Services.prefs.clearUserPref("devtools.toolbar.enabled");
|
||||
if (menuItem) {
|
||||
menuItem.hidden = true;
|
||||
}
|
||||
if (command) {
|
||||
command.setAttribute("disabled", "true");
|
||||
}
|
||||
if (appMenuItem) {
|
||||
appMenuItem.hidden = true;
|
||||
}
|
||||
});
|
||||
|
||||
// a.k.a: Services.prefs.setBoolPref("devtools.toolbar.enabled", true);
|
||||
if (menuItem) {
|
||||
menuItem.hidden = false;
|
||||
}
|
||||
if (command) {
|
||||
command.removeAttribute("disabled");
|
||||
}
|
||||
if (appMenuItem) {
|
||||
appMenuItem.hidden = false;
|
||||
}
|
||||
|
||||
addTab(uri, function(browser, tab) {
|
||||
DeveloperToolbarTest.show();
|
||||
testFunc(browser, tab);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
@ -101,23 +101,11 @@ gcli.addCommand({
|
||||
name: "console close",
|
||||
description: gcli.lookup("consolecloseDesc"),
|
||||
exec: function Command_consoleClose(args, context) {
|
||||
let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab
|
||||
let tab = HUDService.getHudReferenceById(context.environment.hudId).tab;
|
||||
HUDService.deactivateHUDForContext(tab);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 'console open' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "console open",
|
||||
description: gcli.lookup("consoleopenDesc"),
|
||||
exec: function Command_consoleOpen(args, context) {
|
||||
let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab
|
||||
HUDService.activateHUDForContext(tab);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 'inspect' command
|
||||
*/
|
||||
|
@ -151,6 +151,24 @@ function LogFactory(aMessagePrefix)
|
||||
return log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the various Command JSMs.
|
||||
* Should be called when the console first opens.
|
||||
*
|
||||
* @return an object containing the EXPORTED_SYMBOLS from all the command
|
||||
* modules. In general there is no reason when JSMs need to export symbols
|
||||
* except when they need the host environment to inform them of things like the
|
||||
* current window/document/etc.
|
||||
*/
|
||||
function loadCommands() {
|
||||
let commandExports = {};
|
||||
|
||||
Cu.import("resource:///modules/GcliCommands.jsm", commandExports);
|
||||
Cu.import("resource:///modules/GcliTiltCommands.jsm", commandExports);
|
||||
|
||||
return commandExports;
|
||||
}
|
||||
|
||||
let log = LogFactory("*** HUDService:");
|
||||
|
||||
const HUD_STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
|
||||
@ -1552,7 +1570,6 @@ HUD_SERVICE.prototype =
|
||||
if (procInstr.contexts.indexOf(hudId) == -1) {
|
||||
procInstr.contexts.push(hudId);
|
||||
}
|
||||
HeadsUpDisplayUICommands.refreshCommand();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1583,7 +1600,6 @@ HUD_SERVICE.prototype =
|
||||
this.unregisterDisplay(hudId);
|
||||
|
||||
window.focus();
|
||||
HeadsUpDisplayUICommands.refreshCommand();
|
||||
}
|
||||
|
||||
// Remove this context from the list of contexts that need the GCLI CSS
|
||||
@ -3598,7 +3614,7 @@ HeadsUpDisplay.prototype = {
|
||||
{
|
||||
let usegcli = false;
|
||||
try {
|
||||
// usegcli = Services.prefs.getBoolPref("devtools.gcli.enable");
|
||||
usegcli = Services.prefs.getBoolPref("devtools.gcli.enable");
|
||||
}
|
||||
catch (ex) {}
|
||||
|
||||
@ -6319,16 +6335,6 @@ ConsoleUtils = {
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HeadsUpDisplayUICommands = {
|
||||
refreshCommand: function UIC_refreshCommand() {
|
||||
var window = HUDService.currentContext();
|
||||
let command = window.document.getElementById("Tools:WebConsole");
|
||||
if (this.getOpenHUD() != null) {
|
||||
command.setAttribute("checked", true);
|
||||
} else {
|
||||
command.removeAttribute("checked");
|
||||
}
|
||||
},
|
||||
|
||||
toggleHUD: function UIC_toggleHUD() {
|
||||
var window = HUDService.currentContext();
|
||||
var gBrowser = window.gBrowser;
|
||||
@ -6829,76 +6835,93 @@ function GcliTerm(aContentWindow, aHudId, aDocument, aConsole, aHintNode, aConso
|
||||
this.createUI();
|
||||
this.createSandbox();
|
||||
|
||||
this.gcliConsole = gcli._internal.createDisplay({
|
||||
contentDocument: aContentWindow.document,
|
||||
chromeDocument: this.document,
|
||||
outputDocument: this.document,
|
||||
chromeWindow: this.document.defaultView,
|
||||
this.show = this.show.bind(this);
|
||||
this.hide = this.hide.bind(this);
|
||||
|
||||
hintElement: this.hintNode,
|
||||
inputElement: this.inputNode,
|
||||
completeElement: this.completeNode,
|
||||
backgroundElement: this.inputStack,
|
||||
consoleWrap: aConsoleWrap,
|
||||
|
||||
eval: this.evalInSandbox.bind(this),
|
||||
// Allow GCLI:Inputter to decide how and when to open a scratchpad window
|
||||
let scratchpad = {
|
||||
shouldActivate: function Scratchpad_shouldActivate(aEvent) {
|
||||
return aEvent.shiftKey &&
|
||||
aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN;
|
||||
},
|
||||
activate: function Scratchpad_activate(aValue) {
|
||||
aValue = aValue.replace(/^\s*{\s*/, '');
|
||||
ScratchpadManager.openScratchpad({ text: aValue });
|
||||
return true;
|
||||
},
|
||||
linkText: stringBundle.GetStringFromName('scratchpad.linkText')
|
||||
};
|
||||
|
||||
this.opts = {
|
||||
environment: {
|
||||
hudId: this.hudId,
|
||||
chromeDocument: this.document,
|
||||
contentDocument: aContentWindow.document
|
||||
},
|
||||
|
||||
tooltipClass: 'gcliterm-tooltip',
|
||||
|
||||
// Allow GCLI:Inputter to decide how and when to open a scratchpad window
|
||||
scratchpad: {
|
||||
shouldActivate: function Scratchpad_shouldActivate(aEvent) {
|
||||
return aEvent.shiftKey &&
|
||||
aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN;
|
||||
},
|
||||
activate: function Scratchpad_activate(aValue) {
|
||||
aValue = aValue.replace(/^\s*{\s*/, '');
|
||||
ScratchpadManager.openScratchpad({ text: aValue });
|
||||
return true;
|
||||
},
|
||||
linkText: stringBundle.GetStringFromName('scratchpad.linkText')
|
||||
chromeDocument: this.document,
|
||||
contentDocument: aContentWindow.document,
|
||||
jsEnvironment: {
|
||||
globalObject: unwrap(aContentWindow),
|
||||
evalFunction: this.evalInSandbox.bind(this)
|
||||
},
|
||||
});
|
||||
inputElement: this.inputNode,
|
||||
completeElement: this.completeNode,
|
||||
inputBackgroundElement: this.inputStack,
|
||||
hintElement: this.hintNode,
|
||||
consoleWrap: aConsoleWrap,
|
||||
scratchpad: scratchpad,
|
||||
gcliTerm: this
|
||||
};
|
||||
|
||||
this.gcliConsole.onVisibilityChange.add(this.onVisibilityChange, this);
|
||||
this.gcliConsole.onOutput.add(this.onOutput, this);
|
||||
gcli._internal.commandOutputManager.addListener(this.onCommandOutput, this);
|
||||
gcli._internal.createView(this.opts);
|
||||
|
||||
if (!commandExports) {
|
||||
commandExports = loadCommands();
|
||||
}
|
||||
}
|
||||
|
||||
GcliTerm.prototype = {
|
||||
/**
|
||||
* Show or remove the hint column from the display.
|
||||
* Remove the hint column from the display.
|
||||
*/
|
||||
onVisibilityChange: function GcliTerm_onVisibilityChange(ev)
|
||||
hide: function GcliTerm_hide()
|
||||
{
|
||||
if (ev.visible) {
|
||||
this.hintNode.parentNode.hidden = false;
|
||||
let permaHint = false;
|
||||
try {
|
||||
permaHint = Services.prefs.getBoolPref("devtools.gcli.permaHint");
|
||||
}
|
||||
else {
|
||||
let permaHint = false;
|
||||
try {
|
||||
permaHint = Services.prefs.getBoolPref("devtools.gcli.permaHint");
|
||||
}
|
||||
catch (ex) {}
|
||||
catch (ex) {}
|
||||
|
||||
if (!permaHint) {
|
||||
this.hintNode.parentNode.hidden = true;
|
||||
}
|
||||
if (!permaHint) {
|
||||
this.hintNode.parentNode.hidden = true;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Undo the effects of calling hide().
|
||||
*/
|
||||
show: function GcliTerm_show()
|
||||
{
|
||||
this.hintNode.parentNode.hidden = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroy the GcliTerm object. Call this method to avoid memory leaks.
|
||||
*/
|
||||
destroy: function Gcli_destroy()
|
||||
{
|
||||
this.gcliConsole.onVisibilityChange.remove(this.onVisibilityChange, this);
|
||||
this.gcliConsole.onOutput.remove(this.onOutput, this);
|
||||
this.gcliConsole.destroy();
|
||||
gcli._internal.removeView(this.opts);
|
||||
gcli._internal.commandOutputManager.removeListener(this.onCommandOutput, this);
|
||||
|
||||
delete this.opts.chromeDocument;
|
||||
delete this.opts.inputElement;
|
||||
delete this.opts.completeElement;
|
||||
delete this.opts.inputBackgroundElement;
|
||||
delete this.opts.hintElement;
|
||||
delete this.opts.contentDocument;
|
||||
delete this.opts.jsEnvironment;
|
||||
delete this.opts.gcliTerm;
|
||||
|
||||
delete this.context;
|
||||
delete this.document;
|
||||
@ -6907,10 +6930,10 @@ GcliTerm.prototype = {
|
||||
delete this._window;
|
||||
|
||||
delete this.sandbox;
|
||||
delete this.element;
|
||||
delete this.inputStack;
|
||||
delete this.completeNode;
|
||||
delete this.inputNode;
|
||||
delete this.element
|
||||
delete this.inputStack
|
||||
delete this.completeNode
|
||||
delete this.inputNode
|
||||
},
|
||||
|
||||
/**
|
||||
@ -6927,13 +6950,11 @@ GcliTerm.prototype = {
|
||||
this.console = aConsole;
|
||||
this.createSandbox();
|
||||
|
||||
this.gcliConsole.reattach({
|
||||
contentDocument: aContentWindow.document,
|
||||
environment: {
|
||||
chromeDocument: this.document,
|
||||
contentDocument: aContentWindow.document
|
||||
},
|
||||
});
|
||||
this.opts.environment.contentDocument = aContentWindow.document;
|
||||
this.opts.contentDocument = aContentWindow.document;
|
||||
this.opts.jsEnvironment.globalObject = unwrap(aContentWindow);
|
||||
|
||||
gcli._internal.reattachConsole(this.opts);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -6964,7 +6985,7 @@ GcliTerm.prototype = {
|
||||
/**
|
||||
* Called by GCLI/canon when command line output changes.
|
||||
*/
|
||||
onOutput: function Gcli_onOutput(aEvent)
|
||||
onCommandOutput: function Gcli_onCommandOutput(aEvent)
|
||||
{
|
||||
// When we can update the history of the console, then we should stop
|
||||
// filtering incomplete reports.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,59 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
||||
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
|
||||
[
|
||||
<!ENTITY % webConsoleDTD SYSTEM "chrome://browser/locale/devtools/webConsole.dtd">
|
||||
%webConsoleDTD;
|
||||
]
|
||||
>
|
||||
|
||||
<!-- ***** BEGIN LICENSE BLOCK *****
|
||||
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
-
|
||||
- The contents of this file are subject to the Mozilla Public License Version
|
||||
- 1.1 (the "License"); you may not use this file except in compliance with
|
||||
- the License. You may obtain a copy of the License at
|
||||
- http://www.mozilla.org/MPL/
|
||||
-
|
||||
- Software distributed under the License is distributed on an "AS IS" basis,
|
||||
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
- for the specific language governing rights and limitations under the
|
||||
- License.
|
||||
-
|
||||
- The Original Code is GCLI.
|
||||
-
|
||||
- The Initial Developer of the Original Code is
|
||||
- Mozilla Foundation.
|
||||
- Portions created by the Initial Developer are Copyright (C) 2010
|
||||
- the Initial Developer. All Rights Reserved.
|
||||
-
|
||||
- Contributor(s):
|
||||
- Joe Walker <jwalker@mozilla.com>
|
||||
-
|
||||
- Alternatively, the contents of this file may be used under the terms of
|
||||
- either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
- in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
- of those above. If you wish to allow use of your version of this file only
|
||||
- under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
- use your version of this file under the terms of the MPL, indicate your
|
||||
- decision by deleting the provisions above and replace them with the notice
|
||||
- and other provisions required by the LGPL or the GPL. If you do not delete
|
||||
- the provisions above, a recipient may use your version of this file under
|
||||
- the terms of any one of the MPL, the GPL or the LGPL.
|
||||
-
|
||||
- ***** END LICENSE BLOCK ***** -->
|
||||
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<link rel="stylesheet" href="chrome://global/skin/global.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://browser/content/devtools/gcli.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://browser/skin/devtools/gcli.css" type="text/css"/>
|
||||
</head>
|
||||
<body id="gclichrome-body">
|
||||
<div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -144,10 +144,17 @@ _BROWSER_TEST_FILES = \
|
||||
browser_webconsole_bug_678816.js \
|
||||
browser_webconsole_bug_664131_console_group.js \
|
||||
browser_webconsole_bug_704295.js \
|
||||
browser_gcli_commands.js \
|
||||
browser_gcli_helpers.js \
|
||||
browser_gcli_inspect.js \
|
||||
browser_gcli_integrate.js \
|
||||
browser_gcli_require.js \
|
||||
browser_gcli_web.js \
|
||||
browser_webconsole_bug_658368_time_methods.js \
|
||||
browser_webconsole_bug_622303_persistent_filters.js \
|
||||
browser_webconsole_window_zombie.js \
|
||||
browser_cached_messages.js \
|
||||
browser_gcli_break.js \
|
||||
head.js \
|
||||
$(NULL)
|
||||
|
||||
@ -218,9 +225,11 @@ _BROWSER_TEST_PAGES = \
|
||||
test-bug-646025-console-file-location.html \
|
||||
test-bug-678816-content.js \
|
||||
test-file-location.js \
|
||||
browser_gcli_inspect.html \
|
||||
test-bug-658368-time-methods.html \
|
||||
test-webconsole-error-observer.html \
|
||||
test-for-of.html \
|
||||
browser_gcli_break.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_BROWSER_TEST_FILES)
|
||||
|
@ -1,8 +1,8 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Browser GCLI break command test</title>
|
||||
<title>Browser GCLI break command test</title>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<script type="text/javascript">
|
||||
@ -13,7 +13,7 @@
|
||||
eval("debugger;");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
105
browser/devtools/webconsole/test/browser_gcli_break.js
Normal file
105
browser/devtools/webconsole/test/browser_gcli_break.js
Normal file
@ -0,0 +1,105 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// For more information on GCLI see:
|
||||
// - https://github.com/mozilla/gcli/blob/master/docs/index.md
|
||||
// - https://wiki.mozilla.org/DevTools/Features/GCLI
|
||||
|
||||
// Tests that the break command works as it should
|
||||
|
||||
let tempScope = {};
|
||||
Components.utils.import("resource:///modules/gcli.jsm", tempScope);
|
||||
let gcli = tempScope.gcli;
|
||||
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/browser_gcli_break.html";
|
||||
registerCleanupFunction(function() {
|
||||
gcliterm = undefined;
|
||||
requisition = undefined;
|
||||
|
||||
Services.prefs.clearUserPref("devtools.gcli.enable");
|
||||
});
|
||||
|
||||
function test() {
|
||||
Services.prefs.setBoolPref("devtools.gcli.enable", true);
|
||||
addTab(TEST_URI);
|
||||
browser.addEventListener("DOMContentLoaded", onLoad, false);
|
||||
}
|
||||
|
||||
let gcliterm;
|
||||
let requisition;
|
||||
|
||||
function onLoad() {
|
||||
browser.removeEventListener("DOMContentLoaded", onLoad, false);
|
||||
|
||||
try {
|
||||
openConsole();
|
||||
|
||||
let hud = HUDService.getHudByWindow(content);
|
||||
gcliterm = hud.gcliterm;
|
||||
requisition = gcliterm.opts.requisition;
|
||||
|
||||
testSetup();
|
||||
testCreateCommands();
|
||||
}
|
||||
catch (ex) {
|
||||
ok(false, "Caught exception: " + ex)
|
||||
gcli._internal.console.error("Test Failure", ex);
|
||||
closeConsole();
|
||||
finishTest();
|
||||
}
|
||||
}
|
||||
|
||||
function testSetup() {
|
||||
ok(gcliterm, "We have a GCLI term");
|
||||
ok(requisition, "We have a Requisition");
|
||||
}
|
||||
|
||||
function testCreateCommands() {
|
||||
type("brea");
|
||||
is(gcliterm.completeNode.textContent, " break", "Completion for 'brea'");
|
||||
is(requisition.getStatus().toString(), "ERROR", "brea is ERROR");
|
||||
|
||||
type("break");
|
||||
is(requisition.getStatus().toString(), "ERROR", "break is ERROR");
|
||||
|
||||
type("break add");
|
||||
is(requisition.getStatus().toString(), "ERROR", "break add is ERROR");
|
||||
|
||||
type("break add line");
|
||||
is(requisition.getStatus().toString(), "ERROR", "break add line is ERROR");
|
||||
|
||||
let pane = DebuggerUI.toggleDebugger();
|
||||
pane._frame.addEventListener("Debugger:Connecting", function dbgConnected() {
|
||||
pane._frame.removeEventListener("Debugger:Connecting", dbgConnected, true);
|
||||
|
||||
// Wait for the initial resume.
|
||||
pane.debuggerWindow.gClient.addOneTimeListener("resumed", function() {
|
||||
pane.debuggerWindow.gClient.activeThread.addOneTimeListener("framesadded", function() {
|
||||
type("break add line " + TEST_URI + " " + content.wrappedJSObject.line0);
|
||||
is(requisition.getStatus().toString(), "VALID", "break add line is VALID");
|
||||
requisition.exec();
|
||||
|
||||
type("break list");
|
||||
is(requisition.getStatus().toString(), "VALID", "break list is VALID");
|
||||
requisition.exec();
|
||||
|
||||
pane.debuggerWindow.gClient.activeThread.resume(function() {
|
||||
type("break del 0");
|
||||
is(requisition.getStatus().toString(), "VALID", "break del 0 is VALID");
|
||||
requisition.exec();
|
||||
|
||||
closeConsole();
|
||||
finishTest();
|
||||
});
|
||||
});
|
||||
// Trigger newScript notifications using eval.
|
||||
content.wrappedJSObject.firstCall();
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
|
||||
function type(command) {
|
||||
gcliterm.inputNode.value = command.slice(0, -1);
|
||||
gcliterm.inputNode.focus();
|
||||
EventUtils.synthesizeKey(command.slice(-1), {});
|
||||
}
|
80
browser/devtools/webconsole/test/browser_gcli_commands.js
Normal file
80
browser/devtools/webconsole/test/browser_gcli_commands.js
Normal file
@ -0,0 +1,80 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// For more information on GCLI see:
|
||||
// - https://github.com/mozilla/gcli/blob/master/docs/index.md
|
||||
// - https://wiki.mozilla.org/DevTools/Features/GCLI
|
||||
|
||||
let tmp = {};
|
||||
Components.utils.import("resource:///modules/gcli.jsm", tmp);
|
||||
let gcli = tmp.gcli;
|
||||
|
||||
let hud;
|
||||
let gcliterm;
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gcliterm = undefined;
|
||||
hud = undefined;
|
||||
Services.prefs.clearUserPref("devtools.gcli.enable");
|
||||
});
|
||||
|
||||
function test() {
|
||||
Services.prefs.setBoolPref("devtools.gcli.enable", true);
|
||||
addTab("http://example.com/browser/browser/devtools/webconsole/test/browser_gcli_inspect.html");
|
||||
browser.addEventListener("DOMContentLoaded", onLoad, false);
|
||||
}
|
||||
|
||||
function onLoad() {
|
||||
browser.removeEventListener("DOMContentLoaded", onLoad, false);
|
||||
|
||||
openConsole();
|
||||
|
||||
hud = HUDService.getHudByWindow(content);
|
||||
gcliterm = hud.gcliterm;
|
||||
|
||||
testEcho();
|
||||
|
||||
// gcli._internal.console.error("Command Tests Completed");
|
||||
}
|
||||
|
||||
function testEcho() {
|
||||
let nodes = exec("echo message");
|
||||
is(nodes.length, 2, "after echo");
|
||||
is(nodes[0].textContent, "echo message", "output 0");
|
||||
is(nodes[1].textContent.trim(), "message", "output 1");
|
||||
|
||||
testConsoleClear();
|
||||
}
|
||||
|
||||
function testConsoleClear() {
|
||||
let nodes = exec("console clear");
|
||||
is(nodes.length, 1, "after console clear 1");
|
||||
|
||||
executeSoon(function() {
|
||||
let nodes = hud.outputNode.querySelectorAll("richlistitem");
|
||||
is(nodes.length, 0, "after console clear 2");
|
||||
|
||||
testConsoleClose();
|
||||
});
|
||||
}
|
||||
|
||||
function testConsoleClose() {
|
||||
ok(hud.hudId in HUDService.hudReferences, "console open");
|
||||
|
||||
exec("console close");
|
||||
|
||||
ok(!(hud.hudId in HUDService.hudReferences), "console closed");
|
||||
|
||||
finishTest();
|
||||
}
|
||||
|
||||
function exec(command) {
|
||||
gcliterm.clearOutput();
|
||||
let nodes = hud.outputNode.querySelectorAll("richlistitem");
|
||||
is(nodes.length, 0, "setup - " + command);
|
||||
|
||||
gcliterm.opts.console.inputter.setInput(command);
|
||||
gcliterm.opts.requisition.exec();
|
||||
|
||||
return hud.outputNode.querySelectorAll("richlistitem");
|
||||
}
|
124
browser/devtools/webconsole/test/browser_gcli_helpers.js
Normal file
124
browser/devtools/webconsole/test/browser_gcli_helpers.js
Normal file
@ -0,0 +1,124 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// For more information on GCLI see:
|
||||
// - https://github.com/mozilla/gcli/blob/master/docs/index.md
|
||||
// - https://wiki.mozilla.org/DevTools/Features/GCLI
|
||||
|
||||
let tmp = {};
|
||||
Components.utils.import("resource:///modules/gcli.jsm", tmp);
|
||||
let gcli = tmp.gcli;
|
||||
|
||||
let hud;
|
||||
let gcliterm;
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gcliterm = undefined;
|
||||
hud = undefined;
|
||||
Services.prefs.clearUserPref("devtools.gcli.enable");
|
||||
});
|
||||
|
||||
function test() {
|
||||
Services.prefs.setBoolPref("devtools.gcli.enable", true);
|
||||
addTab("http://example.com/browser/browser/devtools/webconsole/test/test-console.html");
|
||||
browser.addEventListener("DOMContentLoaded", onLoad, false);
|
||||
}
|
||||
|
||||
function onLoad() {
|
||||
browser.removeEventListener("DOMContentLoaded", onLoad, false);
|
||||
|
||||
openConsole();
|
||||
hud = HUDService.getHudByWindow(content);
|
||||
gcliterm = hud.gcliterm;
|
||||
|
||||
testHelpers();
|
||||
testScripts();
|
||||
|
||||
closeConsole();
|
||||
finishTest();
|
||||
|
||||
// gcli._internal.console.error("Command Tests Completed");
|
||||
}
|
||||
|
||||
function testScripts() {
|
||||
check("{ 'id=' + $('header').getAttribute('id')", '"id=header"');
|
||||
check("{ headerQuery = $$('h1')", "Instance of NodeList");
|
||||
check("{ 'length=' + headerQuery.length", '"length=1"');
|
||||
|
||||
check("{ xpathQuery = $x('.//*', document.body);", 'Instance of Array');
|
||||
check("{ 'headerFound=' + (xpathQuery[0] == headerQuery[0])", '"headerFound=true"');
|
||||
|
||||
check("{ 'keysResult=' + (keys({b:1})[0] == 'b')", '"keysResult=true"');
|
||||
check("{ 'valuesResult=' + (values({b:1})[0] == 1)", '"valuesResult=true"');
|
||||
|
||||
check("{ [] instanceof Array", "true");
|
||||
check("{ ({}) instanceof Object", "true");
|
||||
check("{ document", "Instance of HTMLDocument");
|
||||
check("{ null", "null");
|
||||
check("{ undefined", undefined);
|
||||
|
||||
check("{ for (var x=0; x<9; x++) x;", "8");
|
||||
}
|
||||
|
||||
function check(command, reply) {
|
||||
gcliterm.clearOutput();
|
||||
gcliterm.opts.console.inputter.setInput(command);
|
||||
gcliterm.opts.requisition.exec();
|
||||
|
||||
let labels = hud.outputNode.querySelectorAll(".webconsole-msg-output");
|
||||
if (reply === undefined) {
|
||||
is(labels.length, 0, "results count for: " + command);
|
||||
}
|
||||
else {
|
||||
is(labels.length, 1, "results count for: " + command);
|
||||
is(labels[0].textContent.trim(), reply, "message for: " + command);
|
||||
}
|
||||
|
||||
gcliterm.opts.console.inputter.setInput("");
|
||||
}
|
||||
|
||||
function testHelpers() {
|
||||
gcliterm.clearOutput();
|
||||
gcliterm.opts.console.inputter.setInput("{ pprint({b:2, a:1})");
|
||||
gcliterm.opts.requisition.exec();
|
||||
// Doesn't conform to check() format
|
||||
let label = hud.outputNode.querySelector(".webconsole-msg-output");
|
||||
is(label.textContent.trim(), "a: 1\n b: 2", "pprint() worked");
|
||||
|
||||
// no gcliterm.clearOutput() here as we clear the output using the clear() fn.
|
||||
gcliterm.opts.console.inputter.setInput("{ clear()");
|
||||
gcliterm.opts.requisition.exec();
|
||||
ok(!hud.outputNode.querySelector(".hud-group"), "clear() worked");
|
||||
|
||||
// check that pprint(window) and keys(window) don't throw, bug 608358
|
||||
gcliterm.clearOutput();
|
||||
gcliterm.opts.console.inputter.setInput("{ pprint(window)");
|
||||
gcliterm.opts.requisition.exec();
|
||||
let labels = hud.outputNode.querySelectorAll(".webconsole-msg-output");
|
||||
is(labels.length, 1, "one line of output for pprint(window)");
|
||||
|
||||
gcliterm.clearOutput();
|
||||
gcliterm.opts.console.inputter.setInput("{ keys(window)");
|
||||
gcliterm.opts.requisition.exec();
|
||||
labels = hud.outputNode.querySelectorAll(".webconsole-msg-output");
|
||||
is(labels.length, 1, "one line of output for keys(window)");
|
||||
|
||||
gcliterm.clearOutput();
|
||||
gcliterm.opts.console.inputter.setInput("{ pprint('hi')");
|
||||
gcliterm.opts.requisition.exec();
|
||||
// Doesn't conform to check() format, bug 614561
|
||||
label = hud.outputNode.querySelector(".webconsole-msg-output");
|
||||
is(label.textContent.trim(), '0: "h"\n 1: "i"', 'pprint("hi") worked');
|
||||
|
||||
// Causes a memory leak. FIXME Bug 717892
|
||||
/*
|
||||
// check that pprint(function) shows function source, bug 618344
|
||||
gcliterm.clearOutput();
|
||||
gcliterm.opts.console.inputter.setInput("{ pprint(print)");
|
||||
gcliterm.opts.requisition.exec();
|
||||
label = hud.outputNode.querySelector(".webconsole-msg-output");
|
||||
isnot(label.textContent.indexOf("SEVERITY_LOG"), -1, "pprint(function) shows function source");
|
||||
*/
|
||||
|
||||
gcliterm.clearOutput();
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user