mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Merge mozilla-central into services-central
This commit is contained in:
commit
fadf7fd538
@ -997,18 +997,19 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
|
||||
}
|
||||
|
||||
nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aNode);
|
||||
|
||||
// If the element is focusable or global ARIA attribute is applied to it or
|
||||
// it is referenced by ARIA relationship then treat role="presentation" on
|
||||
// the element as the role is not there.
|
||||
if (roleMapEntry && roleMapEntry->Is(nsGkAtoms::presentation)) {
|
||||
// Ignore presentation role if element is focusable (focus event shouldn't
|
||||
// be ever lost and should be sensible).
|
||||
if (content->IsFocusable())
|
||||
roleMapEntry = nullptr;
|
||||
else
|
||||
if (!content->IsFocusable() && !HasUniversalAriaProperty(content) &&
|
||||
!HasRelatedContent(content))
|
||||
return nullptr;
|
||||
|
||||
roleMapEntry = nullptr;
|
||||
}
|
||||
|
||||
if (weakFrame.IsAlive() && !newAcc && isHTML) { // HTML accessibles
|
||||
bool tryTagNameOrFrame = true;
|
||||
|
||||
nsIAtom *frameType = weakFrame.GetFrame()->GetType();
|
||||
|
||||
bool partOfHTMLTable =
|
||||
@ -1016,6 +1017,7 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
|
||||
frameType == nsGkAtoms::tableCellFrame ||
|
||||
frameType == nsGkAtoms::tableRowGroupFrame ||
|
||||
frameType == nsGkAtoms::tableRowFrame;
|
||||
bool legalPartOfHTMLTable = partOfHTMLTable;
|
||||
|
||||
if (partOfHTMLTable) {
|
||||
// Table-related frames don't get table-related roles
|
||||
@ -1057,26 +1059,26 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
|
||||
}
|
||||
|
||||
// otherwise create ARIA based accessible.
|
||||
tryTagNameOrFrame = false;
|
||||
legalPartOfHTMLTable = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tableContent->Tag() == nsGkAtoms::table) {
|
||||
// Stop before we are fooled by any additional table ancestors
|
||||
// This table cell frameis part of a separate ancestor table.
|
||||
tryTagNameOrFrame = false;
|
||||
legalPartOfHTMLTable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tableContent)
|
||||
tryTagNameOrFrame = false;
|
||||
legalPartOfHTMLTable = false;
|
||||
}
|
||||
|
||||
if (roleMapEntry) {
|
||||
// Create ARIA grid/treegrid accessibles if node is not of a child or
|
||||
// valid child of HTML table and is not a HTML table.
|
||||
if ((!partOfHTMLTable || !tryTagNameOrFrame) &&
|
||||
// Create ARIA grid/treegrid accessibles if node is not a child or legal
|
||||
// child of HTML table and is not a HTML table.
|
||||
if ((!partOfHTMLTable || !legalPartOfHTMLTable) &&
|
||||
frameType != nsGkAtoms::tableOuterFrame) {
|
||||
|
||||
if (roleMapEntry->role == roles::TABLE ||
|
||||
@ -1091,16 +1093,16 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
|
||||
}
|
||||
}
|
||||
|
||||
if (!newAcc && tryTagNameOrFrame) {
|
||||
if (!newAcc) {
|
||||
// Prefer to use markup (mostly tag name, perhaps attributes) to
|
||||
// decide if and what kind of accessible to create.
|
||||
// The method creates accessibles for table related content too therefore
|
||||
// we do not call it if accessibles for table related content are
|
||||
// prevented above.
|
||||
newAcc = CreateHTMLAccessibleByMarkup(weakFrame.GetFrame(), content,
|
||||
docAcc);
|
||||
docAcc, legalPartOfHTMLTable);
|
||||
|
||||
if (!newAcc) {
|
||||
if (!newAcc && (!partOfHTMLTable || legalPartOfHTMLTable)) {
|
||||
// Do not create accessible object subtrees for non-rendered table
|
||||
// captions. This could not be done in
|
||||
// nsTableCaptionFrame::GetAccessible() because the descendants of
|
||||
@ -1553,8 +1555,20 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
|
||||
already_AddRefed<Accessible>
|
||||
nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame* aFrame,
|
||||
nsIContent* aContent,
|
||||
DocAccessible* aDoc)
|
||||
DocAccessible* aDoc,
|
||||
bool aIsLegalPartOfHTMLTable)
|
||||
{
|
||||
if (aIsLegalPartOfHTMLTable) {
|
||||
if (nsCoreUtils::IsHTMLTableHeader(aContent)) {
|
||||
Accessible* accessible =
|
||||
new HTMLTableHeaderCellAccessibleWrap(aContent, aDoc);
|
||||
NS_IF_ADDREF(accessible);
|
||||
return accessible;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// This method assumes we're in an HTML namespace.
|
||||
nsIAtom* tag = aContent->Tag();
|
||||
if (tag == nsGkAtoms::figcaption) {
|
||||
@ -1635,12 +1649,6 @@ nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame* aFrame,
|
||||
return accessible;
|
||||
}
|
||||
|
||||
if (nsCoreUtils::IsHTMLTableHeader(aContent)) {
|
||||
Accessible* accessible = new HTMLTableHeaderCellAccessibleWrap(aContent, aDoc);
|
||||
NS_IF_ADDREF(accessible);
|
||||
return accessible;
|
||||
}
|
||||
|
||||
if (tag == nsGkAtoms::output) {
|
||||
Accessible* accessible = new HTMLOutputAccessible(aContent, aDoc);
|
||||
NS_IF_ADDREF(accessible);
|
||||
|
@ -229,7 +229,8 @@ private:
|
||||
*/
|
||||
already_AddRefed<Accessible>
|
||||
CreateHTMLAccessibleByMarkup(nsIFrame* aFrame, nsIContent* aContent,
|
||||
DocAccessible* aDoc);
|
||||
DocAccessible* aDoc,
|
||||
bool aIsLegalPartOfHTMLTable);
|
||||
|
||||
/**
|
||||
* Create accessible if parent is a deck frame.
|
||||
|
@ -18,7 +18,7 @@ nsEventShell::FireEvent(AccEvent* aEvent)
|
||||
return;
|
||||
|
||||
Accessible* accessible = aEvent->GetAccessible();
|
||||
NS_ENSURE_TRUE(accessible,);
|
||||
NS_ENSURE_TRUE_VOID(accessible);
|
||||
|
||||
nsINode* node = aEvent->GetNode();
|
||||
if (node) {
|
||||
@ -35,7 +35,7 @@ void
|
||||
nsEventShell::FireEvent(uint32_t aEventType, Accessible* aAccessible,
|
||||
EIsFromUserInput aIsFromUserInput)
|
||||
{
|
||||
NS_ENSURE_TRUE(aAccessible,);
|
||||
NS_ENSURE_TRUE_VOID(aAccessible);
|
||||
|
||||
nsRefPtr<AccEvent> event = new AccEvent(aEventType, aAccessible,
|
||||
aIsFromUserInput);
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "nsIForm.h"
|
||||
#include "nsIFormControl.h"
|
||||
|
||||
#include "nsDeckFrame.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsIStringBundle.h"
|
||||
@ -606,26 +607,35 @@ Accessible::TranslateString(const nsString& aKey, nsAString& aStringOut)
|
||||
uint64_t
|
||||
Accessible::VisibilityState()
|
||||
{
|
||||
uint64_t vstates = states::INVISIBLE | states::OFFSCREEN;
|
||||
|
||||
nsIFrame* frame = GetFrame();
|
||||
if (!frame)
|
||||
return vstates;
|
||||
return states::INVISIBLE;
|
||||
|
||||
nsIPresShell* shell(mDoc->PresShell());
|
||||
if (!shell)
|
||||
return vstates;
|
||||
// Walk the parent frame chain to see if there's invisible parent or the frame
|
||||
// is in background tab.
|
||||
if (!frame->GetStyleVisibility()->IsVisible())
|
||||
return states::INVISIBLE;
|
||||
|
||||
// We need to know if at least a kMinPixels around the object is visible,
|
||||
// otherwise it will be marked states::OFFSCREEN.
|
||||
const uint16_t kMinPixels = 12;
|
||||
const nsSize frameSize = frame->GetSize();
|
||||
const nsRectVisibility rectVisibility =
|
||||
shell->GetRectVisibility(frame, nsRect(nsPoint(0,0), frameSize),
|
||||
nsPresContext::CSSPixelsToAppUnits(kMinPixels));
|
||||
nsIFrame* curFrame = frame;
|
||||
do {
|
||||
nsIView* view = curFrame->GetView();
|
||||
if (view && view->GetVisibility() == nsViewVisibility_kHide)
|
||||
return states::INVISIBLE;
|
||||
|
||||
if (rectVisibility == nsRectVisibility_kVisible)
|
||||
vstates &= ~states::OFFSCREEN;
|
||||
// Offscreen state for background tab content.
|
||||
nsIFrame* parentFrame = curFrame->GetParent();
|
||||
nsDeckFrame* deckFrame = do_QueryFrame(parentFrame);
|
||||
if (deckFrame && deckFrame->GetSelectedBox() != curFrame)
|
||||
return states::OFFSCREEN;
|
||||
|
||||
if (!parentFrame) {
|
||||
parentFrame = nsLayoutUtils::GetCrossDocParentFrame(curFrame);
|
||||
if (parentFrame && !parentFrame->GetStyleVisibility()->IsVisible())
|
||||
return states::INVISIBLE;
|
||||
}
|
||||
|
||||
curFrame = parentFrame;
|
||||
} while (curFrame);
|
||||
|
||||
// Zero area rects can occur in the first frame of a multi-frame text flow,
|
||||
// in which case the rendered text is not empty and the frame should not be
|
||||
@ -638,16 +648,21 @@ Accessible::VisibilityState()
|
||||
nsAutoString renderedText;
|
||||
frame->GetRenderedText(&renderedText, nullptr, nullptr, 0, 1);
|
||||
if (renderedText.IsEmpty())
|
||||
return vstates;
|
||||
|
||||
return states::INVISIBLE;
|
||||
}
|
||||
|
||||
// XXX Do we really need to cross from content to chrome ancestor?
|
||||
if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY))
|
||||
return vstates;
|
||||
// We need to know if at least a kMinPixels around the object is visible,
|
||||
// otherwise it will be marked states::OFFSCREEN.
|
||||
const uint16_t kMinPixels = 12;
|
||||
const nsSize frameSize = frame->GetSize();
|
||||
const nsRectVisibility rectVisibility =
|
||||
mDoc->PresShell()->GetRectVisibility(frame, nsRect(nsPoint(0,0), frameSize),
|
||||
nsPresContext::CSSPixelsToAppUnits(kMinPixels));
|
||||
|
||||
// Assume we are visible enough.
|
||||
return vstates &= ~states::INVISIBLE;
|
||||
if (rectVisibility != nsRectVisibility_kVisible)
|
||||
return states::OFFSCREEN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
@ -2929,7 +2944,7 @@ void
|
||||
Accessible::CacheChildren()
|
||||
{
|
||||
DocAccessible* doc = Document();
|
||||
NS_ENSURE_TRUE(doc,);
|
||||
NS_ENSURE_TRUE_VOID(doc);
|
||||
|
||||
nsAccTreeWalker walker(doc, mContent, CanHaveAnonChildren());
|
||||
|
||||
|
@ -1705,7 +1705,7 @@ HyperTextAccessible::GetSelectionDOMRanges(int16_t aType,
|
||||
uint32_t childCount = startNode->GetChildCount();
|
||||
nsresult rv = domSel->
|
||||
GetRangesForIntervalArray(startNode, 0, startNode, childCount, true, aRanges);
|
||||
NS_ENSURE_SUCCESS(rv,);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
// Remove collapsed ranges
|
||||
uint32_t numRanges = aRanges->Length();
|
||||
|
@ -159,7 +159,7 @@ HTMLRadioButtonAccessible::GetPositionAndSizeInternal(int32_t* aPosInSet,
|
||||
inputElms = NS_GetContentList(formElm, namespaceId, tagName);
|
||||
else
|
||||
inputElms = NS_GetContentList(mContent->OwnerDoc(), namespaceId, tagName);
|
||||
NS_ENSURE_TRUE(inputElms, );
|
||||
NS_ENSURE_TRUE_VOID(inputElms);
|
||||
|
||||
uint32_t inputCount = inputElms->Length(false);
|
||||
|
||||
|
@ -139,7 +139,7 @@ XULColorPickerAccessible::AreItemsOperable() const
|
||||
void
|
||||
XULColorPickerAccessible::CacheChildren()
|
||||
{
|
||||
NS_ENSURE_TRUE(mDoc,);
|
||||
NS_ENSURE_TRUE_VOID(mDoc);
|
||||
|
||||
nsAccTreeWalker walker(mDoc, mContent, true);
|
||||
|
||||
|
@ -181,7 +181,7 @@ XULButtonAccessible::CacheChildren()
|
||||
mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
||||
nsGkAtoms::menuButton, eCaseMatters);
|
||||
|
||||
NS_ENSURE_TRUE(mDoc,);
|
||||
NS_ENSURE_TRUE_VOID(mDoc);
|
||||
if (!isMenu && !isMenuButton)
|
||||
return;
|
||||
|
||||
@ -823,7 +823,7 @@ XULTextFieldAccessible::GetEditor() const
|
||||
void
|
||||
XULTextFieldAccessible::CacheChildren()
|
||||
{
|
||||
NS_ENSURE_TRUE(mDoc,);
|
||||
NS_ENSURE_TRUE_VOID(mDoc);
|
||||
// Create child accessibles for native anonymous content of underlying HTML
|
||||
// input element.
|
||||
nsCOMPtr<nsIContent> inputContent(GetInputField());
|
||||
|
@ -16,27 +16,56 @@
|
||||
src="../role.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../states.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../events.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../browser.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
function doTest()
|
||||
function addTab(aURL)
|
||||
{
|
||||
testStates("div", 0, 0, STATE_INVISIBLE);
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, tabDocumentAt, 1)
|
||||
];
|
||||
|
||||
this.invoke = function addTab_invoke()
|
||||
{
|
||||
tabBrowser().loadOneTab(aURL, null, "", null, false);
|
||||
}
|
||||
|
||||
this.finalCheck = function addTab_finalCheck()
|
||||
{
|
||||
var tabDoc = tabDocumentAt(0);
|
||||
var input = getAccessible(tabDoc.getElementById("input"));
|
||||
testStates(input, STATE_OFFSCREEN, 0, STATE_INVISIBLE);
|
||||
}
|
||||
|
||||
this.getID = function addTab_getID()
|
||||
{
|
||||
return "add tab: " + aURL;
|
||||
}
|
||||
}
|
||||
|
||||
var gInputDocURI = "data:text/html,<html><input id='input'></html>";
|
||||
|
||||
function doTests()
|
||||
{
|
||||
testStates("div", 0, 0, STATE_INVISIBLE | STATE_OFFSCREEN);
|
||||
testStates("div_off", STATE_OFFSCREEN, 0, STATE_INVISIBLE);
|
||||
testStates("div_abschild", 0, 0, STATE_INVISIBLE);
|
||||
testStates("div_abschild", 0, 0, STATE_INVISIBLE | STATE_OFFSCREEN);
|
||||
|
||||
// Confirm destruction of accessibles.
|
||||
document.getElementById("div").style.visibility = "hidden";
|
||||
document.getElementById("div_off").style.visibility="hidden";
|
||||
document.getElementById("div_abschild").style.visibility="hidden";
|
||||
document.body.clientWidth; // flush layout
|
||||
testAccessibleTree("outer_div", {children:[]});
|
||||
gQueue = new eventQueue();
|
||||
|
||||
// Accessibles in background tab should have offscreen state and no
|
||||
// invisible state.
|
||||
gQueue.push(new addTab("about:blank"));
|
||||
|
||||
SimpleTest.finish();
|
||||
gQueue.onFinish = function() { closeBrowserWindow(); }
|
||||
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
openBrowserWindow(doTests, gInputDocURI);
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
@ -17,6 +17,7 @@ MOCHITEST_A11Y_FILES =\
|
||||
test_aria_globals.html \
|
||||
test_aria_imgmap.html \
|
||||
test_aria_presentation.html \
|
||||
test_brokencontext.html \
|
||||
test_button.xul \
|
||||
test_canvas.html \
|
||||
test_combobox.xul \
|
||||
|
@ -54,6 +54,19 @@
|
||||
] };
|
||||
testAccessibleTree("tblfocusable_cnt", tree);
|
||||
|
||||
// Has ARIA globals or referred by ARIA relationship.
|
||||
tree =
|
||||
{ SECTION: [ // container
|
||||
{ LABEL: [ // label, has aria-owns
|
||||
{ TEXT_LEAF: [ ] }
|
||||
] },
|
||||
{ TEXT_LEAF: [ ] },
|
||||
{ LABEL: [ // label, referenced by aria-owns
|
||||
{ TEXT_LEAF: [ ] }
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree("airaglobalprop_cnt", tree);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
@ -98,5 +111,10 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="airaglobalprop_cnt">
|
||||
<label role="presentation" aria-owns="ariaowned">has aria-owns</label>
|
||||
<label role="presentation" id="ariaowned">referred by aria-owns</label>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
106
accessible/tests/mochitest/tree/test_brokencontext.html
Normal file
106
accessible/tests/mochitest/tree/test_brokencontext.html
Normal file
@ -0,0 +1,106 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Broken context hierarchy</title>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../role.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../states.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
function doTest()
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// HTML table elements outside table context.
|
||||
|
||||
ok(!isAccessible("tr_in_presentation_table"), "tr shouldn't be accessible");
|
||||
ok(!isAccessible("th_in_presentation_table"), "th shouldn't be accessible");
|
||||
ok(!isAccessible("td_in_presentation_table"), "td shouldn't be accessible");
|
||||
|
||||
var tree =
|
||||
{ PUSHBUTTON: [ // table
|
||||
{ NOTHING: [ // tbody
|
||||
{ NOTHING: [ // tr
|
||||
{ NOTHING: [ // th
|
||||
{ TEXT_LEAF: [ ] }
|
||||
] },
|
||||
{ NOTHING: [ // td
|
||||
{ TEXT_LEAF: [ ] }
|
||||
] }
|
||||
] },
|
||||
] },
|
||||
] };
|
||||
testAccessibleTree("button_table", tree);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Styled as HTML table elements, accessible is created by tag name
|
||||
|
||||
tree =
|
||||
{ LINK: [ // a
|
||||
{ TEXT_LEAF: [ ] }
|
||||
] };
|
||||
testAccessibleTree("a_as_td", tree);
|
||||
|
||||
tree =
|
||||
{ HEADING: [
|
||||
{ TEXT_LEAF: [ ] }
|
||||
] };
|
||||
testAccessibleTree("h1_as_td", tree);
|
||||
testAccessibleTree("h2_as_td", tree);
|
||||
testAccessibleTree("h3_as_td", tree);
|
||||
testAccessibleTree("h4_as_td", tree);
|
||||
testAccessibleTree("h5_as_td", tree);
|
||||
testAccessibleTree("h6_as_td", tree);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=706849"
|
||||
title="Create accessible by tag name as fallback if table descendant style is used out of table context">
|
||||
Mozilla Bug 706849
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<!-- HTML table elements out of table -->
|
||||
<table role="presentation">
|
||||
<tr id="tr_in_presentation_table">
|
||||
<th id="th_in_presentation_table">not a header</th>
|
||||
<td id="td_in_presentation_table">not a cell</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table role="button" id="button_table">
|
||||
<tr id="tr_in_button_table">
|
||||
<th id="th_in_button_table">not a header</th>
|
||||
<td id="td_in_button_table">not a cell</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- styled as HTML table elements -->
|
||||
<a id="a_as_td" style="display:table-cell;" href="http://www.google.com">Google</a>
|
||||
<h1 id="h1_as_td" style="display: table-cell;">h1</h1>
|
||||
<h2 id="h2_as_td" style="display: table-cell;">h2</h2>
|
||||
<h3 id="h3_as_td" style="display: table-cell;">h3</h3>
|
||||
<h4 id="h4_as_td" style="display: table-cell;">h4</h4>
|
||||
<h5 id="h5_as_td" style="display: table-cell;">h5</h5>
|
||||
<h6 id="h6_as_td" style="display: table-cell;">h6</h6>
|
||||
</body>
|
||||
</html>
|
@ -139,6 +139,7 @@
|
||||
] } ]
|
||||
};
|
||||
testAccessibleTree("table4", accTree);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
2
aclocal.m4
vendored
2
aclocal.m4
vendored
@ -17,6 +17,8 @@ builtin(include, build/autoconf/mozcommonheader.m4)dnl
|
||||
builtin(include, build/autoconf/acwinpaths.m4)dnl
|
||||
builtin(include, build/autoconf/lto.m4)dnl
|
||||
builtin(include, build/autoconf/gcc-pr49911.m4)dnl
|
||||
builtin(include, build/autoconf/gcc-pr39608.m4)dnl
|
||||
builtin(include, build/autoconf/llvm-pr8927.m4)dnl
|
||||
builtin(include, build/autoconf/frameptr.m4)dnl
|
||||
builtin(include, build/autoconf/compiler-opts.m4)dnl
|
||||
builtin(include, build/autoconf/expandlibs.m4)dnl
|
||||
|
@ -435,22 +435,30 @@ pref("marionette.defaultPrefs.port", 2828);
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_UPDATER
|
||||
// Timeout before the update prompt automatically installs the update
|
||||
pref("b2g.update.apply-prompt-timeout", 60000); // milliseconds
|
||||
// Optional timeout the user can wait before getting another update prompt
|
||||
pref("b2g.update.apply-wait-timeout", 1800000); // milliseconds
|
||||
// Amount of time the updater waits for the process to exit cleanly before
|
||||
// forcefully exiting the process
|
||||
pref("b2g.update.self-destruct-timeout", 5000); // milliseconds
|
||||
|
||||
pref("app.update.enabled", true);
|
||||
pref("app.update.auto", true);
|
||||
pref("app.update.silent", true);
|
||||
pref("app.update.auto", false);
|
||||
pref("app.update.silent", false);
|
||||
pref("app.update.mode", 0);
|
||||
pref("app.update.incompatible.mode", 0);
|
||||
pref("app.update.staging.enabled", true);
|
||||
pref("app.update.service.enabled", true);
|
||||
|
||||
// The URL hosting the update manifest.
|
||||
pref("app.update.url", "http://update.boot2gecko.org/m2.5/updates.xml");
|
||||
pref("app.update.url", "http://update.boot2gecko.org/nightly/update.xml");
|
||||
// Interval at which update manifest is fetched. In units of seconds.
|
||||
pref("app.update.interval", 3600); // 1 hour
|
||||
pref("app.update.interval", 86400); // 1 day
|
||||
// First interval to elapse before checking for update. In units of
|
||||
// milliseconds. Capped at 10 seconds.
|
||||
pref("app.update.timerFirstInterval", 30000);
|
||||
pref("app.update.timerMinimumDelay", 30); // seconds
|
||||
pref("app.update.timerFirstInterval", 3600000); // 1 hour
|
||||
pref("app.update.timerMinimumDelay", 3600); // 1 hour in seconds
|
||||
// Don't throttle background updates.
|
||||
pref("app.update.download.backgroundInterval", 0);
|
||||
|
||||
@ -484,7 +492,7 @@ pref("dom.experimental_forms", true);
|
||||
// Turns on gralloc-based direct texturing for Gonk
|
||||
pref("gfx.gralloc.enabled", false);
|
||||
|
||||
// XXXX REMOVE FOR PRODUCTION. Turns on GC and CC logging
|
||||
// XXXX REMOVE FOR PRODUCTION. Turns on GC and CC logging
|
||||
pref("javascript.options.mem.log", true);
|
||||
|
||||
// Increase mark slice time from 10ms to 30ms
|
||||
@ -505,9 +513,9 @@ pref("ui.showHideScrollbars", 1);
|
||||
// background.
|
||||
pref("dom.ipc.processPriorityManager.enabled", true);
|
||||
pref("dom.ipc.processPriorityManager.gracePeriodMS", 1000);
|
||||
pref("hal.processPriorityManager.gonk.masterOomAdjust", 0);
|
||||
pref("hal.processPriorityManager.gonk.foregroundOomAdjust", 1);
|
||||
pref("hal.processPriorityManager.gonk.backgroundOomAdjust", 6);
|
||||
pref("hal.processPriorityManager.gonk.masterOomScoreAdjust", 0);
|
||||
pref("hal.processPriorityManager.gonk.foregroundOomScoreAdjust", 67);
|
||||
pref("hal.processPriorityManager.gonk.backgroundOomScoreAdjust", 400);
|
||||
pref("hal.processPriorityManager.gonk.masterNice", -1);
|
||||
pref("hal.processPriorityManager.gonk.foregroundNice", 0);
|
||||
pref("hal.processPriorityManager.gonk.backgroundNice", 10);
|
||||
|
@ -185,7 +185,7 @@ select > button {
|
||||
background-color: transparent;
|
||||
background-position: -15px center, 4px center !important;
|
||||
background-repeat: no-repeat, no-repeat !important;
|
||||
background-size: 100% 90%, normal normal;
|
||||
background-size: 100% 90%, auto auto;
|
||||
|
||||
-moz-binding: none !important;
|
||||
position: relative !important;
|
||||
|
@ -106,3 +106,8 @@ SettingsListener.observe('debug.log-animations.enabled', false, function(value)
|
||||
SettingsListener.observe('debug.dev-mode', false, function(value) {
|
||||
Services.prefs.setBoolPref('dom.mozApps.dev_mode', value);
|
||||
});
|
||||
|
||||
// =================== Privacy ====================
|
||||
SettingsListener.observe('privacy.donottrackheader.enabled', false, function(value) {
|
||||
Services.prefs.setBoolPref('privacy.donottrackheader.enabled', value);
|
||||
});
|
@ -1,11 +1,6 @@
|
||||
# Scrollbars
|
||||
category agent-style-sheets browser-content-stylesheet chrome://browser/content/content.css
|
||||
|
||||
# CameraContent.js
|
||||
component {eff4231b-abce-4f7f-a40a-d646e8fde3ce} CameraContent.js
|
||||
contract @mozilla.org/b2g-camera-content;1 {eff4231b-abce-4f7f-a40a-d646e8fde3ce}
|
||||
category JavaScript-navigator-property mozCamera @mozilla.org/b2g-camera-content;1
|
||||
|
||||
# AlertsService.js
|
||||
component {fe33c107-82a4-41d6-8c64-5353267e04c9} AlertsService.js
|
||||
contract @mozilla.org/system-alerts-service;1 {fe33c107-82a4-41d6-8c64-5353267e04c9}
|
||||
@ -46,3 +41,7 @@ contract @mozilla.org/uriloader/content-handler;1?type=application/pdf {d18d0216
|
||||
# PaymentGlue.js
|
||||
component {8b83eabc-7929-47f4-8b48-4dea8d887e4b} PaymentGlue.js
|
||||
contract @mozilla.org/payment/ui-glue;1 {8b83eabc-7929-47f4-8b48-4dea8d887e4b}
|
||||
|
||||
# YoutubeProtocolHandler.js
|
||||
component {c3f1b945-7e71-49c8-95c7-5ae9cc9e2bad} YoutubeProtocolHandler.js
|
||||
contract @mozilla.org/network/protocol;1?name=vnd.youtube {c3f1b945-7e71-49c8-95c7-5ae9cc9e2bad}
|
||||
|
@ -1,83 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const kProtocolName = "b2g-camera:";
|
||||
|
||||
let CameraContent = function() {
|
||||
this.hasPrivileges = false;
|
||||
this.mapping = [];
|
||||
}
|
||||
|
||||
CameraContent.prototype = {
|
||||
getCameraURI: function(aOptions) {
|
||||
if (!this.hasPrivileges)
|
||||
return null;
|
||||
|
||||
let options = aOptions || { };
|
||||
if (!options.camera)
|
||||
options.camera = 0;
|
||||
if (!options.width)
|
||||
options.width = 320;
|
||||
if (!options.height)
|
||||
options.height = 240;
|
||||
|
||||
let uuid = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID().toString();
|
||||
uuid = uuid.substring(1, uuid.length - 2); // remove the brackets
|
||||
this.mapping.push(uuid);
|
||||
let uri = kProtocolName + "?camera=" + options.camera +
|
||||
"&width=" + options.width +
|
||||
"&height=" + options.height +
|
||||
"&type=video/x-raw-yuv";
|
||||
// XXX that's no e10s ready, but the camera inputstream itself is not...
|
||||
Services.prefs.setCharPref("b2g.camera." + kProtocolName + "?" + uuid, uri);
|
||||
return kProtocolName + "?" + uuid;
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
if (aTopic == "inner-window-destroyed") {
|
||||
let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
|
||||
if (wId == this.innerWindowID) {
|
||||
Services.obs.removeObserver(this, "inner-window-destroyed");
|
||||
for (let aId in this.mapping)
|
||||
Services.prefs.clearUserPref("b2g.camera." + kProtocolName + "?" + aId);
|
||||
this.mapping = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
init: function(aWindow) {
|
||||
let principal = aWindow.document.nodePrincipal;
|
||||
let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
|
||||
|
||||
let perm = Services.perms.testExactPermissionFromPrincipal(principal, "content-camera");
|
||||
|
||||
//only pages with perm set and chrome pages can use the camera in content
|
||||
this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
|
||||
|
||||
Services.obs.addObserver(this, "inner-window-destroyed", false);
|
||||
let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||
this.innerWindowID = util.currentInnerWindowID;
|
||||
},
|
||||
|
||||
classID: Components.ID("{eff4231b-abce-4f7f-a40a-d646e8fde3ce}"),
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIB2GCameraContent, Ci.nsIDOMGlobalPropertyInitializer, Ci.nsIObserver]),
|
||||
|
||||
classInfo: XPCOMUtils.generateCI({classID: Components.ID("{eff4231b-abce-4f7f-a40a-d646e8fde3ce}"),
|
||||
contractID: "@mozilla.org/b2g-camera-content;1",
|
||||
interfaces: [Ci.nsIB2GCameraContent],
|
||||
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
||||
classDescription: "B2G Camera Content Helper"})
|
||||
}
|
||||
|
||||
const NSGetFactory = XPCOMUtils.generateNSGetFactory([CameraContent]);
|
@ -9,6 +9,7 @@ const Cc = Components.classes;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Webapps.jsm");
|
||||
|
||||
function ContentPermissionPrompt() {}
|
||||
|
||||
@ -52,13 +53,29 @@ ContentPermissionPrompt.prototype = {
|
||||
request.cancel();
|
||||
});
|
||||
|
||||
let principal = request.principal;
|
||||
let isApp = principal.appStatus != Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED;
|
||||
|
||||
let details = {
|
||||
"type": "permission-prompt",
|
||||
"permission": request.type,
|
||||
"id": requestId,
|
||||
"url": request.principal.URI.spec
|
||||
type: "permission-prompt",
|
||||
permission: request.type,
|
||||
id: requestId,
|
||||
origin: principal.origin,
|
||||
isApp: isApp
|
||||
};
|
||||
browser.shell.sendChromeEvent(details);
|
||||
|
||||
if (!isApp) {
|
||||
browser.shell.sendChromeEvent(details);
|
||||
return;
|
||||
}
|
||||
|
||||
// When it's an app, get the manifest to add the l10n application name.
|
||||
let app = DOMApplicationRegistry.getAppByLocalId(principal.appId);
|
||||
DOMApplicationRegistry.getManifestFor(app.origin, function getManifest(aManifest) {
|
||||
let helper = new DOMApplicationManifest(aManifest, app.origin);
|
||||
details.appName = helper.name;
|
||||
browser.shell.sendChromeEvent(details);
|
||||
});
|
||||
},
|
||||
|
||||
classID: Components.ID("{8c719f03-afe0-4aac-91ff-6c215895d467}"),
|
||||
|
@ -20,13 +20,13 @@ EXTRA_PP_COMPONENTS = \
|
||||
ActivitiesGlue.js \
|
||||
AlertsService.js \
|
||||
B2GComponents.manifest \
|
||||
CameraContent.js \
|
||||
ContentHandler.js \
|
||||
ContentPermissionPrompt.js \
|
||||
DirectoryProvider.js \
|
||||
MozKeyboard.js \
|
||||
ProcessGlobal.js \
|
||||
PaymentGlue.js \
|
||||
YoutubeProtocolHandler.js \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_UPDATER
|
||||
|
@ -18,12 +18,28 @@ let log =
|
||||
function log_dump(msg) { dump("UpdatePrompt: "+ msg +"\n"); } :
|
||||
function log_noop(msg) { };
|
||||
|
||||
const APPLY_PROMPT_TIMEOUT =
|
||||
Services.prefs.getIntPref("b2g.update.apply-prompt-timeout");
|
||||
const APPLY_WAIT_TIMEOUT =
|
||||
Services.prefs.getIntPref("b2g.update.apply-wait-timeout");
|
||||
const SELF_DESTRUCT_TIMEOUT =
|
||||
Services.prefs.getIntPref("b2g.update.self-destruct-timeout");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(Services, "aus",
|
||||
"@mozilla.org/updates/update-service;1",
|
||||
"nsIApplicationUpdateService");
|
||||
|
||||
function UpdatePrompt() { }
|
||||
|
||||
UpdatePrompt.prototype = {
|
||||
classID: Components.ID("{88b3eb21-d072-4e3b-886d-f89d8c49fe59}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdatePrompt]),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdatePrompt,
|
||||
Ci.nsIRequestObserver,
|
||||
Ci.nsIProgressEventSink]),
|
||||
|
||||
_update: null,
|
||||
_applyPromptTimer: null,
|
||||
_applyWaitTimer: null,
|
||||
_selfDestructTimer: null,
|
||||
|
||||
// nsIUpdatePrompt
|
||||
@ -32,20 +48,146 @@ UpdatePrompt.prototype = {
|
||||
// updates when on a billed pipe. Initially, opt-in for 3g, but
|
||||
// that doesn't cover all cases.
|
||||
checkForUpdates: function UP_checkForUpdates() { },
|
||||
showUpdateAvailable: function UP_showUpdateAvailable(aUpdate) { },
|
||||
|
||||
showUpdateAvailable: function UP_showUpdateAvailable(aUpdate) {
|
||||
if (!this.sendUpdateEvent("update-available", aUpdate,
|
||||
this.handleAvailableResult)) {
|
||||
|
||||
log("Unable to prompt for available update, forcing download");
|
||||
this.downloadUpdate(aUpdate);
|
||||
}
|
||||
},
|
||||
|
||||
showUpdateDownloaded: function UP_showUpdateDownloaded(aUpdate, aBackground) {
|
||||
// FIXME/bug 737598: we should let the user request that the
|
||||
// update be applied later, e.g. if they're in the middle of a
|
||||
// phone call ;).
|
||||
if (!this.sendUpdateEvent("update-downloaded", aUpdate,
|
||||
this.handleDownloadedResult)) {
|
||||
log("Unable to prompt, forcing restart");
|
||||
this.restartProcess();
|
||||
return;
|
||||
}
|
||||
|
||||
// Schedule a fallback timeout in case the UI is unable to respond or show
|
||||
// a prompt for some reason
|
||||
this._applyPromptTimer = this.createTimer(APPLY_PROMPT_TIMEOUT);
|
||||
},
|
||||
|
||||
showUpdateError: function UP_showUpdateError(aUpdate) {
|
||||
if (aUpdate.state == "failed") {
|
||||
log("Failed to download update, errorCode: " + aUpdate.errorCode);
|
||||
}
|
||||
},
|
||||
|
||||
showUpdateHistory: function UP_showUpdateHistory(aParent) { },
|
||||
showUpdateInstalled: function UP_showUpdateInstalled() { },
|
||||
|
||||
sendUpdateEvent: function UP_sendUpdateEvent(aType, aUpdate, aCallback) {
|
||||
let detail = {
|
||||
displayVersion: aUpdate.displayVersion,
|
||||
detailsURL: aUpdate.detailsURL
|
||||
};
|
||||
|
||||
let patch = aUpdate.selectedPatch;
|
||||
if (!patch) {
|
||||
// For now we just check the first patch to get size information if a
|
||||
// patch hasn't been selected yet.
|
||||
if (aUpdate.patchCount == 0) {
|
||||
log("Warning: no patches available in update");
|
||||
return false;
|
||||
}
|
||||
patch = aUpdate.getPatchAt(0);
|
||||
}
|
||||
|
||||
detail.size = patch.size;
|
||||
detail.updateType = patch.type;
|
||||
|
||||
this._update = aUpdate;
|
||||
return this.sendChromeEvent(aType, detail, aCallback);
|
||||
},
|
||||
|
||||
sendChromeEvent: function UP_sendChromeEvent(aType, aDetail, aCallback) {
|
||||
let browser = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
if (!browser) {
|
||||
log("Warning: Couldn't send update event " + aType +
|
||||
": no content browser");
|
||||
return false;
|
||||
}
|
||||
|
||||
let content = browser.getContentWindow();
|
||||
if (!content) {
|
||||
log("Warning: Couldn't send update event " + aType +
|
||||
": no content window");
|
||||
return false;
|
||||
}
|
||||
|
||||
let detail = aDetail || {};
|
||||
detail.type = aType;
|
||||
|
||||
if (!aCallback) {
|
||||
browser.shell.sendChromeEvent(detail);
|
||||
return true;
|
||||
}
|
||||
|
||||
let resultType = aType + "-result";
|
||||
let handleContentEvent = (function(e) {
|
||||
if (!e.detail) {
|
||||
return;
|
||||
}
|
||||
|
||||
let detail = e.detail;
|
||||
if (detail.type == resultType) {
|
||||
aCallback.call(this, detail);
|
||||
content.removeEventListener("mozContentEvent", handleContentEvent);
|
||||
this._update = null;
|
||||
}
|
||||
}).bind(this);
|
||||
|
||||
content.addEventListener("mozContentEvent", handleContentEvent);
|
||||
browser.shell.sendChromeEvent(detail);
|
||||
return true;
|
||||
},
|
||||
|
||||
handleAvailableResult: function UP_handleAvailableResult(aDetail) {
|
||||
// If the user doesn't choose "download", the updater will implicitly call
|
||||
// showUpdateAvailable again after a certain period of time
|
||||
switch (aDetail.result) {
|
||||
case "download":
|
||||
this.downloadUpdate(this._update);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
handleDownloadedResult: function UP_handleDownloadedResult(aDetail) {
|
||||
if (this._applyPromptTimer) {
|
||||
this._applyPromptTimer.cancel();
|
||||
this._applyPromptTimer = null;
|
||||
}
|
||||
|
||||
switch (aDetail.result) {
|
||||
case "wait":
|
||||
// Wait for a fixed period of time, allowing the user to temporarily
|
||||
// postpone applying an update
|
||||
this._applyWaitTimer = this.createTimer(APPLY_WAIT_TIMEOUT);
|
||||
break;
|
||||
case "restart":
|
||||
this.restartProcess();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
downloadUpdate: function UP_downloadUpdate(aUpdate) {
|
||||
Services.aus.downloadUpdate(aUpdate, true);
|
||||
Services.aus.addDownloadListener(this);
|
||||
},
|
||||
|
||||
restartProcess: function UP_restartProcess() {
|
||||
log("Update downloaded, restarting to apply it");
|
||||
|
||||
// If not cleanly shut down within 5 seconds, this process will
|
||||
// explode.
|
||||
this._setSelfDestructTimer(5000);
|
||||
this._selfDestructTimer = this.createTimer(SELF_DESTRUCT_TIMEOUT);
|
||||
|
||||
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
|
||||
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"]
|
||||
.getService(Ci.nsIAppStartup);
|
||||
// NB: on Gonk, we rely on the system process manager to restart
|
||||
// us. Trying to restart here would conflict with the process
|
||||
// manager. We should be using a runtime check to detect Gonk
|
||||
@ -57,33 +199,60 @@ UpdatePrompt.prototype = {
|
||||
);
|
||||
},
|
||||
|
||||
_setSelfDestructTimer: function UP__setSelfDestructTimer(timeoutMs) {
|
||||
notify: function UP_notify(aTimer) {
|
||||
if (aTimer == this._selfDestructTimer) {
|
||||
this._selfDestructTimer = null;
|
||||
this.selfDestruct();
|
||||
} else if (aTimer == this._applyPromptTimer) {
|
||||
log("Timed out waiting for result, restarting");
|
||||
this._applyPromptTimer = null;
|
||||
this.restartProcess();
|
||||
} else if (aTimer == this._applyWaitTimer) {
|
||||
this._applyWaitTimer = null;
|
||||
this.showUpdatePrompt();
|
||||
}
|
||||
},
|
||||
|
||||
selfDestruct: function UP_selfDestruct() {
|
||||
#ifdef ANDROID
|
||||
Cu.import("resource://gre/modules/ctypes.jsm");
|
||||
let libc = ctypes.open("libc.so");
|
||||
let _exit = libc.declare("_exit", ctypes.default_abi,
|
||||
let _exit = libc.declare("_exit", ctypes.default_abi,
|
||||
ctypes.void_t, // [return]
|
||||
ctypes.int); // status
|
||||
this.notify = function UP_notify(_) {
|
||||
log("Self-destruct timer fired; didn't cleanly shut down. BOOM");
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback(this, timeoutMs, timer.TYPE_ONE_SHOT);
|
||||
this._selfDestructTimer = timer;
|
||||
log("Self-destruct timer fired; didn't cleanly shut down. BOOM");
|
||||
_exit(0);
|
||||
#endif
|
||||
},
|
||||
|
||||
showUpdateInstalled: function UP_showUpdateInstalled() { },
|
||||
|
||||
showUpdateError: function UP_showUpdateError(aUpdate) {
|
||||
if (aUpdate.state == "failed") {
|
||||
log("Failed to download update, errorCode: " + aUpdate.errorCode);
|
||||
}
|
||||
createTimer: function UP_createTimer(aTimeoutMs) {
|
||||
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback(this, aTimeoutMs, timer.TYPE_ONE_SHOT);
|
||||
return timer;
|
||||
},
|
||||
|
||||
showUpdateHistory: function UP_showUpdateHistory(aParent) { },
|
||||
// nsIRequestObserver
|
||||
|
||||
onStartRequest: function UP_onStartRequest(aRequest, aContext) {
|
||||
this.sendChromeEvent("update-downloading");
|
||||
},
|
||||
|
||||
onStopRequest: function UP_onStopRequest(aRequest, aContext, aStatusCode) {
|
||||
Services.aus.removeDownloadListener(this);
|
||||
},
|
||||
|
||||
// nsIProgressEventSink
|
||||
|
||||
onProgress: function UP_onProgress(aRequest, aContext, aProgress,
|
||||
aProgressMax) {
|
||||
this.sendChromeEvent("update-progress", {
|
||||
progress: aProgress,
|
||||
total: aProgressMax
|
||||
});
|
||||
},
|
||||
|
||||
onStatus: function UP_onStatus(aRequest, aUpdate, aStatus, aStatusArg) { }
|
||||
};
|
||||
|
||||
const NSGetFactory = XPCOMUtils.generateNSGetFactory([UpdatePrompt]);
|
||||
|
117
b2g/components/YoutubeProtocolHandler.js
Normal file
117
b2g/components/YoutubeProtocolHandler.js
Normal file
@ -0,0 +1,117 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "cpmm", function() {
|
||||
return Cc["@mozilla.org/childprocessmessagemanager;1"]
|
||||
.getService(Ci.nsIMessageSender);
|
||||
});
|
||||
|
||||
// Splits parameters in a query string.
|
||||
function extractParameters(aQuery) {
|
||||
let params = aQuery.split("&");
|
||||
let res = {};
|
||||
params.forEach(function(aParam) {
|
||||
let obj = aParam.split("=");
|
||||
res[obj[0]] = decodeURIComponent(obj[1]);
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
function YoutubeProtocolHandler() {
|
||||
}
|
||||
|
||||
YoutubeProtocolHandler.prototype = {
|
||||
classID: Components.ID("{c3f1b945-7e71-49c8-95c7-5ae9cc9e2bad}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIProtocolHandler]),
|
||||
|
||||
scheme: "vnd.youtube",
|
||||
defaultPort: -1,
|
||||
protocolFlags: Ci.nsIProtocolHandler.URI_NORELATIVE |
|
||||
Ci.nsIProtocolHandler.URI_NOAUTH |
|
||||
Ci.nsIProtocolHandler.URI_LOADABLE_BY_ANYONE,
|
||||
|
||||
// Sample URL:
|
||||
// vnd.youtube:iNuKL2Gy_QM?vndapp=youtube_mobile&vndclient=mv-google&vndel=watch&vnddnc=1
|
||||
newURI: function yt_phNewURI(aSpec, aOriginCharset, aBaseURI) {
|
||||
let uri = Cc["@mozilla.org/network/standard-url;1"]
|
||||
.createInstance(Ci.nsIStandardURL);
|
||||
let id = aSpec.substring(this.scheme.length + 1);
|
||||
id = id.substring(0, id.indexOf('?'));
|
||||
uri.init(Ci.nsIStandardURL.URLTYPE_STANDARD, -1, this.scheme + "://dummy_host/" + id, aOriginCharset,
|
||||
aBaseURI);
|
||||
return uri.QueryInterface(Ci.nsIURI);
|
||||
},
|
||||
|
||||
newChannel: function yt_phNewChannel(aURI) {
|
||||
// Get a list of streams for this video id.
|
||||
let infoURI = "http://www.youtube.com/get_video_info?&video_id=" +
|
||||
aURI.path.substring(1);
|
||||
|
||||
let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance(Ci.nsIXMLHttpRequest);
|
||||
xhr.open("GET", infoURI, true);
|
||||
xhr.addEventListener("load", function() {
|
||||
// Youtube sends the response as a double wrapped url answer:
|
||||
// we first extract the url_encoded_fmt_stream_map parameter,
|
||||
// and from each comma-separated entry in this value, we extract
|
||||
// other parameters (url and type).
|
||||
let key = "url_encoded_fmt_stream_map=";
|
||||
let pos = xhr.responseText.indexOf(key);
|
||||
if (pos == -1) {
|
||||
return;
|
||||
}
|
||||
let streams = decodeURIComponent(xhr.responseText
|
||||
.substring(pos + key.length)).split(",");
|
||||
let uri;
|
||||
let mimeType;
|
||||
|
||||
// Recognized mime types, ordered from the less usable to the most usable.
|
||||
let recognizedTypes = ["video/webm"];
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
recognizedTypes.push("video/mp4");
|
||||
#endif
|
||||
|
||||
let bestType = -1;
|
||||
|
||||
streams.forEach(function(aStream) {
|
||||
let params = extractParameters(aStream);
|
||||
let url = params["url"];
|
||||
let type = params["type"] ? params["type"].split(";")[0] : null;
|
||||
|
||||
let index;
|
||||
if (url && type && ((index = recognizedTypes.indexOf(type)) != -1) &&
|
||||
index > bestType) {
|
||||
uri = url;
|
||||
mimeType = type;
|
||||
bestType = index;
|
||||
}
|
||||
});
|
||||
|
||||
if (uri && mimeType) {
|
||||
cpmm.sendAsyncMessage("content-handler", {
|
||||
url: uri,
|
||||
type: mimeType
|
||||
});
|
||||
}
|
||||
});
|
||||
xhr.send(null);
|
||||
|
||||
throw Components.results.NS_ERROR_ILLEGAL_VALUE;
|
||||
},
|
||||
|
||||
allowPort: function yt_phAllowPort(aPort, aScheme) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const NSGetFactory = XPCOMUtils.generateNSGetFactory([YoutubeProtocolHandler]);
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0"?>
|
||||
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1346451771000">
|
||||
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1347572992000">
|
||||
<emItems>
|
||||
<emItem blockID="i58" id="webmaster@buzzzzvideos.info">
|
||||
<versionRange minVersion="0" maxVersion="*">
|
||||
@ -96,6 +96,10 @@
|
||||
<versionRange minVersion="0" maxVersion="15.0.5" severity="1">
|
||||
</versionRange>
|
||||
</emItem>
|
||||
<emItem blockID="i136" id="Adobe@flash.com">
|
||||
<versionRange minVersion="0" maxVersion="*" severity="1">
|
||||
</versionRange>
|
||||
</emItem>
|
||||
<emItem blockID="i38" id="{B7082FAA-CB62-4872-9106-E42DD88EDE45}">
|
||||
<versionRange minVersion="0.1" maxVersion="3.3.0.*">
|
||||
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
|
||||
@ -448,6 +452,9 @@
|
||||
<pluginItem blockID="p129">
|
||||
<match name="filename" exp="Silverlight\.plugin" /> <versionRange minVersion="0" maxVersion="5.0.99999" severity="1"></versionRange>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="p138">
|
||||
<match name="filename" exp="JavaAppletPlugin\.plugin" /> <versionRange minVersion="Java 7 Update 01" maxVersion="Java 7 Update 06" severity="0"></versionRange>
|
||||
</pluginItem>
|
||||
</pluginItems>
|
||||
|
||||
<gfxItems>
|
||||
@ -460,26 +467,6 @@
|
||||
</devices>
|
||||
<feature>DIRECT3D_9_LAYERS</feature> <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus> <driverVersion>8.17.12.5896</driverVersion> <driverVersionComparator>LESS_THAN_OR_EQUAL</driverVersionComparator> </gfxBlacklistEntry>
|
||||
<gfxBlacklistEntry blockID="g37"> <os>WINNT 5.1</os> <vendor>0x10de</vendor> <feature>DIRECT3D_9_LAYERS</feature> <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus> <driverVersion>7.0.0.0</driverVersion> <driverVersionComparator>GREATER_THAN_OR_EQUAL</driverVersionComparator> </gfxBlacklistEntry>
|
||||
<gfxBlacklistEntry blockID="g81"> <os>WINNT 6.1</os> <vendor>0x1002</vendor> <devices>
|
||||
<device>0x9802</device>
|
||||
<device>0x9803</device>
|
||||
<device>0x9803</device>
|
||||
<device>0x9804</device>
|
||||
<device>0x9805</device>
|
||||
<device>0x9806</device>
|
||||
<device>0x9807</device>
|
||||
</devices>
|
||||
<feature>DIRECT2D</feature> <featureStatus>BLOCKED_DEVICE</featureStatus> <driverVersion>1.0.0.0</driverVersion> <driverVersionComparator>GREATER_THAN_OR_EQUAL</driverVersionComparator> </gfxBlacklistEntry>
|
||||
<gfxBlacklistEntry blockID="g95"> <os>WINNT 6.1</os> <vendor>0x1002</vendor> <devices>
|
||||
<device>0x9802</device>
|
||||
<device>0x9803</device>
|
||||
<device>0x9803</device>
|
||||
<device>0x9804</device>
|
||||
<device>0x9805</device>
|
||||
<device>0x9806</device>
|
||||
<device>0x9807</device>
|
||||
</devices>
|
||||
<feature>DIRECT3D_9_LAYERS</feature> <featureStatus>BLOCKED_DEVICE</featureStatus> <driverVersion>1.0.0.0</driverVersion> <driverVersionComparator>GREATER_THAN_OR_EQUAL</driverVersionComparator> </gfxBlacklistEntry>
|
||||
</gfxItems>
|
||||
|
||||
|
||||
|
@ -194,7 +194,6 @@ pref("extensions.update.background.url", "https://versioncheck-bg.addons.mozilla
|
||||
pref("extensions.update.interval", 86400); // Check for updates to Extensions and
|
||||
// Themes every day
|
||||
// Non-symmetric (not shared by extensions) extension-specific [update] preferences
|
||||
pref("extensions.getMoreThemesURL", "https://addons.mozilla.org/%LOCALE%/firefox/getpersonas");
|
||||
pref("extensions.dss.enabled", false); // Dynamic Skin Switching
|
||||
pref("extensions.dss.switchPending", false); // Non-dynamic switch pending after next
|
||||
// restart.
|
||||
|
@ -112,28 +112,38 @@ const DEFAULT_SNIPPETS_URLS = [
|
||||
|
||||
const SNIPPETS_UPDATE_INTERVAL_MS = 86400000; // 1 Day.
|
||||
|
||||
let gSearchEngine;
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function init() {
|
||||
setupSearchEngine();
|
||||
loadSnippets();
|
||||
let gObserver = new MutationObserver(function (mutations) {
|
||||
for (let mutation of mutations) {
|
||||
if (mutation.attributeName == "searchEngineURL") {
|
||||
gObserver.disconnect();
|
||||
setupSearchEngine();
|
||||
loadSnippets();
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("load", function () {
|
||||
// Delay search engine setup, cause browser.js::BrowserOnAboutPageLoad runs
|
||||
// later and may use asynchronous getters.
|
||||
window.gObserver.observe(document.documentElement, { attributes: true });
|
||||
fitToWidth();
|
||||
});
|
||||
window.addEventListener("load", fitToWidth);
|
||||
window.addEventListener("resize", fitToWidth);
|
||||
|
||||
|
||||
function onSearchSubmit(aEvent)
|
||||
{
|
||||
let searchTerms = document.getElementById("searchText").value;
|
||||
if (gSearchEngine && searchTerms.length > 0) {
|
||||
let searchURL = document.documentElement.getAttribute("searchEngineURL");
|
||||
if (searchURL && searchTerms.length > 0) {
|
||||
const SEARCH_TOKENS = {
|
||||
"_searchTerms_": encodeURIComponent(searchTerms)
|
||||
}
|
||||
let url = gSearchEngine.searchUrl;
|
||||
for (let key in SEARCH_TOKENS) {
|
||||
url = url.replace(key, SEARCH_TOKENS[key]);
|
||||
searchURL = searchURL.replace(key, SEARCH_TOKENS[key]);
|
||||
}
|
||||
window.location.href = url;
|
||||
window.location.href = searchURL;
|
||||
}
|
||||
|
||||
aEvent.preventDefault();
|
||||
@ -142,27 +152,24 @@ function onSearchSubmit(aEvent)
|
||||
|
||||
function setupSearchEngine()
|
||||
{
|
||||
gSearchEngine = JSON.parse(localStorage["search-engine"]);
|
||||
|
||||
if (!gSearchEngine)
|
||||
let searchEngineName = document.documentElement.getAttribute("searchEngineName");
|
||||
let searchEngineInfo = SEARCH_ENGINES[searchEngineName];
|
||||
if (!searchEngineInfo) {
|
||||
return;
|
||||
|
||||
// Look for extended information, like logo and links.
|
||||
let searchEngineInfo = SEARCH_ENGINES[gSearchEngine.name];
|
||||
if (searchEngineInfo) {
|
||||
for (let prop in searchEngineInfo)
|
||||
gSearchEngine[prop] = searchEngineInfo[prop];
|
||||
}
|
||||
|
||||
// Enqueue additional params if required by the engine definition.
|
||||
if (gSearchEngine.params)
|
||||
gSearchEngine.searchUrl += "&" + gSearchEngine.params;
|
||||
if (searchEngineInfo.params) {
|
||||
let searchEngineURL = document.documentElement.getAttribute("searchEngineURL");
|
||||
searchEngineURL += "&" + searchEngineInfo.params;
|
||||
document.documentElement.setAttribute("searchEngineURL", searchEngineURL);
|
||||
}
|
||||
|
||||
// Add search engine logo.
|
||||
if (gSearchEngine.image) {
|
||||
if (searchEngineInfo.image) {
|
||||
let logoElt = document.getElementById("searchEngineLogo");
|
||||
logoElt.src = gSearchEngine.image;
|
||||
logoElt.alt = gSearchEngine.name;
|
||||
logoElt.src = searchEngineInfo.image;
|
||||
logoElt.alt = searchEngineInfo.name;
|
||||
}
|
||||
|
||||
// The "autofocus" attribute doesn't focus the form element
|
||||
@ -180,7 +187,7 @@ function loadSnippets()
|
||||
{
|
||||
// Check last snippets update.
|
||||
let lastUpdate = localStorage["snippets-last-update"];
|
||||
let updateURL = localStorage["snippets-update-url"];
|
||||
let updateURL = document.documentElement.getAttribute("snippetsURL");
|
||||
if (updateURL && (!lastUpdate ||
|
||||
Date.now() - lastUpdate > SNIPPETS_UPDATE_INTERVAL_MS)) {
|
||||
// Try to update from network.
|
||||
|
@ -326,7 +326,7 @@ let SocialShareButton = {
|
||||
// whenever we notice the provider has changed - but the concept of
|
||||
// "provider changed" will only exist once bug 774520 lands.
|
||||
// get the recommend-prompt info.
|
||||
let port = Social.provider._getWorkerPort();
|
||||
let port = Social.provider.getWorkerPort();
|
||||
if (port) {
|
||||
port.onmessage = function(evt) {
|
||||
if (evt.data.topic == "social.user-recommend-prompt-response") {
|
||||
|
@ -90,6 +90,9 @@ __defineSetter__("PluralForm", function (val) {
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
|
||||
"resource://gre/modules/TelemetryStopwatch.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AboutHomeUtils",
|
||||
"resource:///modules/AboutHomeUtils.jsm");
|
||||
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
XPCOMUtils.defineLazyGetter(this, "Weave", function() {
|
||||
let tmp = {};
|
||||
@ -2495,10 +2498,19 @@ function BrowserOnAboutPageLoad(document) {
|
||||
// the hidden attribute set on the apps button in aboutHome.xhtml
|
||||
if (getBoolPref("browser.aboutHome.apps", false))
|
||||
document.getElementById("apps").removeAttribute("hidden");
|
||||
|
||||
let ss = Components.classes["@mozilla.org/browser/sessionstore;1"].
|
||||
getService(Components.interfaces.nsISessionStore);
|
||||
if (!ss.canRestoreLastSession)
|
||||
document.getElementById("launcher").removeAttribute("session");
|
||||
|
||||
// Inject search engine and snippets URL.
|
||||
let docElt = document.documentElement;
|
||||
docElt.setAttribute("snippetsURL", AboutHomeUtils.snippetsURL);
|
||||
docElt.setAttribute("searchEngineName",
|
||||
AboutHomeUtils.defaultSearchEngine.name);
|
||||
docElt.setAttribute("searchEngineURL",
|
||||
AboutHomeUtils.defaultSearchEngine.searchURL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5675,13 +5687,11 @@ var OfflineApps = {
|
||||
// OfflineApps Public Methods
|
||||
init: function ()
|
||||
{
|
||||
Services.obs.addObserver(this, "dom-storage-warn-quota-exceeded", false);
|
||||
Services.obs.addObserver(this, "offline-cache-update-completed", false);
|
||||
},
|
||||
|
||||
uninit: function ()
|
||||
{
|
||||
Services.obs.removeObserver(this, "dom-storage-warn-quota-exceeded");
|
||||
Services.obs.removeObserver(this, "offline-cache-update-completed");
|
||||
},
|
||||
|
||||
@ -5800,10 +5810,6 @@ var OfflineApps = {
|
||||
}
|
||||
}
|
||||
|
||||
var storageManager = Cc["@mozilla.org/dom/storagemanager;1"].
|
||||
getService(Ci.nsIDOMStorageManager);
|
||||
usage += storageManager.getUsage(host);
|
||||
|
||||
return usage;
|
||||
},
|
||||
|
||||
@ -5923,19 +5929,7 @@ var OfflineApps = {
|
||||
// nsIObserver
|
||||
observe: function (aSubject, aTopic, aState)
|
||||
{
|
||||
if (aTopic == "dom-storage-warn-quota-exceeded") {
|
||||
if (aSubject) {
|
||||
var uri = makeURI(aSubject.location.href);
|
||||
|
||||
if (OfflineApps._checkUsage(uri)) {
|
||||
var browserWindow =
|
||||
this._getBrowserWindowForContentWindow(aSubject);
|
||||
var browser = this._getBrowserForContentWindow(browserWindow,
|
||||
aSubject);
|
||||
OfflineApps._warnUsage(browser, uri);
|
||||
}
|
||||
}
|
||||
} else if (aTopic == "offline-cache-update-completed") {
|
||||
if (aTopic == "offline-cache-update-completed") {
|
||||
var cacheUpdate = aSubject.QueryInterface(Ci.nsIOfflineCacheUpdate);
|
||||
|
||||
var uri = cacheUpdate.manifestURI;
|
||||
|
@ -268,8 +268,12 @@
|
||||
</hbox>
|
||||
</panel>
|
||||
|
||||
<panel id="social-notification-panel" class="social-panel"
|
||||
type="arrow" hidden="true" noautofocus="true">
|
||||
<panel id="social-notification-panel"
|
||||
class="social-panel"
|
||||
type="arrow"
|
||||
hidden="true"
|
||||
consumeoutsideclicks="true"
|
||||
noautofocus="true">
|
||||
<box id="social-notification-box" flex="1"></box>
|
||||
</panel>
|
||||
<panel id="social-flyout-panel"
|
||||
|
@ -171,10 +171,10 @@ let gUpdater = {
|
||||
// Set the site's initial opacity to zero.
|
||||
site.node.style.opacity = 0;
|
||||
|
||||
// Without the setTimeout() the node would just appear instead of fade in.
|
||||
setTimeout(function () {
|
||||
gTransformation.showSite(site, function () batch.pop());
|
||||
}, 0);
|
||||
// Flush all style changes for the dynamically inserted site to make
|
||||
// the fade-in transition work.
|
||||
window.getComputedStyle(site.node).opacity;
|
||||
gTransformation.showSite(site, function () batch.pop());
|
||||
});
|
||||
|
||||
batch.close();
|
||||
|
@ -820,7 +820,7 @@ nsContextMenu.prototype = {
|
||||
canvas.height = video.videoHeight;
|
||||
var ctxDraw = canvas.getContext("2d");
|
||||
ctxDraw.drawImage(video, 0, 0);
|
||||
saveImageURL(canvas.toDataURL("image/jpeg", ""), name, "SaveImageTitle", true, false, document.documentURIObject);
|
||||
saveImageURL(canvas.toDataURL("image/jpeg", ""), name, "SaveImageTitle", true, false, document.documentURIObject, this.target.ownerDocument);
|
||||
},
|
||||
|
||||
fullScreenVideo: function () {
|
||||
@ -1061,12 +1061,12 @@ nsContextMenu.prototype = {
|
||||
if (this.onCanvas) {
|
||||
// Bypass cache, since it's a data: URL.
|
||||
saveImageURL(this.target.toDataURL(), "canvas.png", "SaveImageTitle",
|
||||
true, false, doc.documentURIObject);
|
||||
true, false, doc.documentURIObject, doc);
|
||||
}
|
||||
else if (this.onImage) {
|
||||
urlSecurityCheck(this.mediaURL, doc.nodePrincipal);
|
||||
saveImageURL(this.mediaURL, null, "SaveImageTitle", false,
|
||||
false, doc.documentURIObject);
|
||||
false, doc.documentURIObject, doc);
|
||||
}
|
||||
else if (this.onVideo || this.onAudio) {
|
||||
urlSecurityCheck(this.mediaURL, doc.nodePrincipal);
|
||||
|
@ -85,8 +85,8 @@ Sanitizer.prototype = {
|
||||
cacheService.evictEntries(Ci.nsICache.STORE_ANYWHERE);
|
||||
} catch(er) {}
|
||||
|
||||
var imageCache = Cc["@mozilla.org/image/cache;1"].
|
||||
getService(Ci.imgICache);
|
||||
var imageCache = Cc["@mozilla.org/image/tools;1"].
|
||||
getService(Ci.imgITools).getImgCacheForDocument(null);
|
||||
try {
|
||||
imageCache.clearCache(false); // true=chrome, false=content
|
||||
} catch(er) {}
|
||||
|
@ -685,7 +685,10 @@
|
||||
if (!(aURI instanceof Ci.nsIURI))
|
||||
aURI = makeURI(aURI);
|
||||
this.mFaviconService.setAndFetchFaviconForPage(browser.currentURI,
|
||||
aURI, false);
|
||||
aURI, false,
|
||||
gPrivateBrowsingUI.privateWindow ?
|
||||
this.mFaviconService.FAVICON_LOAD_PRIVATE :
|
||||
this.mFaviconService.FAVICON_LOAD_NON_PRIVATE);
|
||||
}
|
||||
|
||||
if ((browser.mIconURL || "") != aTab.getAttribute("image")) {
|
||||
|
@ -15,64 +15,17 @@ registerCleanupFunction(function() {
|
||||
let gTests = [
|
||||
|
||||
{
|
||||
desc: "Check that rejecting cookies does not prevent page from working",
|
||||
desc: "Check that clearing cookies does not clear storage",
|
||||
setup: function ()
|
||||
{
|
||||
Services.prefs.setIntPref("network.cookies.cookieBehavior", 2);
|
||||
Cc["@mozilla.org/dom/storagemanager;1"]
|
||||
.getService(Ci.nsIObserver)
|
||||
.observe(null, "cookie-changed", "cleared");
|
||||
},
|
||||
run: function ()
|
||||
{
|
||||
let storage = getStorage();
|
||||
isnot(storage.getItem("search-engine"), null);
|
||||
try {
|
||||
Services.prefs.clearUserPref("network.cookies.cookieBehavior");
|
||||
} catch (ex) {}
|
||||
executeSoon(runNextTest);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Check that asking for cookies does not prevent page from working",
|
||||
setup: function ()
|
||||
{
|
||||
Services.prefs.setIntPref("network.cookie.lifetimePolicy", 1);
|
||||
},
|
||||
run: function ()
|
||||
{
|
||||
let storage = getStorage();
|
||||
isnot(storage.getItem("search-engine"), null);
|
||||
try {
|
||||
Services.prefs.clearUserPref("network.cookie.lifetimePolicy");
|
||||
} catch (ex) {}
|
||||
executeSoon(runNextTest);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Check that clearing cookies does not prevent page from working",
|
||||
setup: function ()
|
||||
{
|
||||
Components.classes["@mozilla.org/dom/storagemanager;1"].
|
||||
getService(Components.interfaces.nsIObserver).
|
||||
observe(null, "cookie-changed", "cleared");
|
||||
},
|
||||
run: function ()
|
||||
{
|
||||
let storage = getStorage();
|
||||
isnot(storage.getItem("search-engine"), null);
|
||||
executeSoon(runNextTest);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Check normal status is working",
|
||||
setup: function ()
|
||||
{
|
||||
},
|
||||
run: function ()
|
||||
{
|
||||
let storage = getStorage();
|
||||
isnot(storage.getItem("search-engine"), null);
|
||||
isnot(storage.getItem("snippets-last-update"), null);
|
||||
executeSoon(runNextTest);
|
||||
}
|
||||
},
|
||||
@ -120,14 +73,6 @@ function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
|
||||
// browser-chrome test harness inits browser specifying an hardcoded page
|
||||
// and this causes nsIBrowserHandler.defaultArgs to not be evaluated since
|
||||
// there is a predefined argument.
|
||||
// About:home localStorage is populated with overridden homepage, that is
|
||||
// setup in the defaultArgs getter.
|
||||
// Thus to populate about:home we need to get defaultArgs manually.
|
||||
Cc["@mozilla.org/browser/clh;1"].getService(Ci.nsIBrowserHandler).defaultArgs;
|
||||
|
||||
// Ensure that by default we don't try to check for remote snippets since that
|
||||
// could be tricky due to network bustages or slowness.
|
||||
let storage = getStorage();
|
||||
@ -148,10 +93,20 @@ function runNextTest()
|
||||
info(test.desc);
|
||||
test.setup();
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab("about:home");
|
||||
tab.linkedBrowser.addEventListener("load", function (event) {
|
||||
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
// Some part of the page is populated on load, so enqueue on it.
|
||||
executeSoon(test.run);
|
||||
tab.linkedBrowser.addEventListener("load", function load(event) {
|
||||
tab.linkedBrowser.removeEventListener("load", load, true);
|
||||
|
||||
let observer = new MutationObserver(function (mutations) {
|
||||
for (let mutation of mutations) {
|
||||
if (mutation.attributeName == "searchEngineURL") {
|
||||
observer.disconnect();
|
||||
executeSoon(test.run);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
let docElt = tab.linkedBrowser.contentDocument.documentElement;
|
||||
observer.observe(docElt, { attributes: true });
|
||||
}, true);
|
||||
}
|
||||
else {
|
||||
|
@ -435,7 +435,7 @@ var gAllTests = [
|
||||
wh.open();
|
||||
},
|
||||
function () {
|
||||
// Test for offline apps data and cache deletion
|
||||
// Test for offline cache deletion
|
||||
|
||||
// Prepare stuff, we will work with www.example.com
|
||||
var URL = "http://www.example.com";
|
||||
@ -454,12 +454,6 @@ var gAllTests = [
|
||||
pm.addFromPrincipal(principal, "offline-app", Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
pm.addFromPrincipal(principal, "offline-app", Ci.nsIOfflineCacheUpdateService.ALLOW_NO_WARN);
|
||||
|
||||
// Store some user data to localStorage
|
||||
var dsm = Cc["@mozilla.org/dom/storagemanager;1"]
|
||||
.getService(Ci.nsIDOMStorageManager);
|
||||
var localStorage = dsm.getLocalStorageForPrincipal(principal, URL);
|
||||
localStorage.setItem("test", "value");
|
||||
|
||||
// Store something to the offline cache
|
||||
const nsICache = Components.interfaces.nsICache;
|
||||
var cs = Components.classes["@mozilla.org/network/cache-service;1"]
|
||||
@ -477,9 +471,7 @@ var gAllTests = [
|
||||
this.checkPrefCheckbox("offlineApps", true);
|
||||
this.acceptDialog();
|
||||
|
||||
// Check all has been deleted (data, cache)
|
||||
is(localStorage.length, 0, "DOM storage cleared");
|
||||
|
||||
// Check if the cache has been deleted
|
||||
var size = -1;
|
||||
var visitor = {
|
||||
visitDevice: function (deviceID, deviceInfo)
|
||||
|
@ -24,7 +24,7 @@ function test() {
|
||||
var tests = {
|
||||
testOpenCloseChat: function(next) {
|
||||
let chats = document.getElementById("pinnedchats");
|
||||
let port = Social.provider.port;
|
||||
let port = Social.provider.getWorkerPort();
|
||||
ok(port, "provider has a port");
|
||||
port.onmessage = function (e) {
|
||||
let topic = e.data.topic;
|
||||
@ -43,6 +43,7 @@ var tests = {
|
||||
iframe.addEventListener("unload", function chatUnload() {
|
||||
iframe.removeEventListener("unload", chatUnload, true);
|
||||
ok(true, "got chatbox unload on close");
|
||||
port.close();
|
||||
next();
|
||||
}, true);
|
||||
chats.selectedChat.close();
|
||||
@ -60,8 +61,9 @@ var tests = {
|
||||
testManyChats: function(next) {
|
||||
// open enough chats to overflow the window, then check
|
||||
// if the menupopup is visible
|
||||
let port = Social.provider.port;
|
||||
let port = Social.provider.getWorkerPort();
|
||||
ok(port, "provider has a port");
|
||||
port.postMessage({topic: "test-init"});
|
||||
let width = document.documentElement.boxObject.width;
|
||||
let numToOpen = (width / 200) + 1;
|
||||
port.onmessage = function (e) {
|
||||
@ -81,6 +83,7 @@ var tests = {
|
||||
chats.selectedChat.close();
|
||||
}
|
||||
ok(!chats.selectedChat, "chats are all closed");
|
||||
port.close();
|
||||
next();
|
||||
break;
|
||||
}
|
||||
@ -92,8 +95,9 @@ var tests = {
|
||||
},
|
||||
testWorkerChatWindow: function(next) {
|
||||
const chatUrl = "https://example.com/browser/browser/base/content/test/social_chat.html";
|
||||
let port = Social.provider.port;
|
||||
let port = Social.provider.getWorkerPort();
|
||||
ok(port, "provider has a port");
|
||||
port.postMessage({topic: "test-init"});
|
||||
port.onmessage = function (e) {
|
||||
let topic = e.data.topic;
|
||||
switch (topic) {
|
||||
@ -104,6 +108,7 @@ var tests = {
|
||||
chats.selectedChat.close();
|
||||
}
|
||||
ok(!chats.selectedChat, "chats are all closed");
|
||||
port.close();
|
||||
ensureSocialUrlNotRemembered(chatUrl);
|
||||
next();
|
||||
break;
|
||||
|
@ -20,7 +20,7 @@ function test() {
|
||||
var tests = {
|
||||
testOpenCloseFlyout: function(next) {
|
||||
let panel = document.getElementById("social-flyout-panel");
|
||||
let port = Social.provider.port;
|
||||
let port = Social.provider.getWorkerPort();
|
||||
ok(port, "provider has a port");
|
||||
port.onmessage = function (e) {
|
||||
let topic = e.data.topic;
|
||||
@ -31,6 +31,7 @@ var tests = {
|
||||
case "got-flyout-visibility":
|
||||
if (e.data.result == "hidden") {
|
||||
ok(true, "flyout visibility is 'hidden'");
|
||||
port.close();
|
||||
next();
|
||||
} else if (e.data.result == "shown") {
|
||||
ok(true, "flyout visibility is 'shown");
|
||||
|
@ -19,41 +19,46 @@ function test() {
|
||||
|
||||
var tests = {
|
||||
testSidebarMessage: function(next) {
|
||||
let port = Social.provider.port;
|
||||
let port = Social.provider.getWorkerPort();
|
||||
ok(port, "provider has a port");
|
||||
port.postMessage({topic: "test-init"});
|
||||
Social.provider.port.onmessage = function (e) {
|
||||
port.onmessage = function (e) {
|
||||
let topic = e.data.topic;
|
||||
switch (topic) {
|
||||
case "got-sidebar-message":
|
||||
// The sidebar message will always come first, since it loads by default
|
||||
ok(true, "got sidebar message");
|
||||
port.close();
|
||||
next();
|
||||
break;
|
||||
}
|
||||
};
|
||||
},
|
||||
testIsVisible: function(next) {
|
||||
let port = Social.provider.port;
|
||||
let port = Social.provider.getWorkerPort();
|
||||
port.postMessage({topic: "test-init"});
|
||||
port.onmessage = function (e) {
|
||||
let topic = e.data.topic;
|
||||
switch (topic) {
|
||||
case "got-isVisible-response":
|
||||
is(e.data.result, true, "Sidebar should be visible by default");
|
||||
Social.toggleSidebar();
|
||||
port.close();
|
||||
next();
|
||||
}
|
||||
};
|
||||
port.postMessage({topic: "test-isVisible"});
|
||||
},
|
||||
testIsNotVisible: function(next) {
|
||||
let port = Social.provider.port;
|
||||
let port = Social.provider.getWorkerPort();
|
||||
port.postMessage({topic: "test-init"});
|
||||
port.onmessage = function (e) {
|
||||
let topic = e.data.topic;
|
||||
switch (topic) {
|
||||
case "got-isVisible-response":
|
||||
is(e.data.result, false, "Sidebar should be hidden");
|
||||
Services.prefs.clearUserPref("social.sidebar.open");
|
||||
port.close();
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
@ -29,17 +29,23 @@ var tests = {
|
||||
|
||||
function triggerIconPanel() {
|
||||
let statusIcons = document.getElementById("social-status-iconbox");
|
||||
ok(!statusIcons.firstChild.hidden, "status icon is visible");
|
||||
// Click the button to trigger its contentPanel
|
||||
let panel = document.getElementById("social-notification-panel");
|
||||
EventUtils.synthesizeMouseAtCenter(statusIcons.firstChild, {});
|
||||
waitForCondition(function() statusIcons.firstChild && !statusIcons.firstChild.hidden,
|
||||
function() {
|
||||
// Click the button to trigger its contentPanel
|
||||
let panel = document.getElementById("social-notification-panel");
|
||||
EventUtils.synthesizeMouseAtCenter(statusIcons.firstChild, {});
|
||||
}, "Status icon didn't become non-hidden");
|
||||
}
|
||||
|
||||
let port = Social.provider.port;
|
||||
let port = Social.provider.getWorkerPort();
|
||||
ok(port, "provider has a port");
|
||||
port.onmessage = function (e) {
|
||||
let topic = e.data.topic;
|
||||
switch (topic) {
|
||||
case "test-init-done":
|
||||
iconsReady = true;
|
||||
checkNext();
|
||||
break;
|
||||
case "got-panel-message":
|
||||
ok(true, "got panel message");
|
||||
// Check the panel isn't in our history.
|
||||
@ -52,6 +58,7 @@ var tests = {
|
||||
panel.hidePopup();
|
||||
} else if (e.data.result == "hidden") {
|
||||
ok(true, "panel hidden");
|
||||
port.close();
|
||||
next();
|
||||
}
|
||||
break;
|
||||
@ -66,24 +73,5 @@ var tests = {
|
||||
}
|
||||
}
|
||||
port.postMessage({topic: "test-init"});
|
||||
|
||||
// Our worker sets up ambient notification at the same time as it responds to
|
||||
// the workerAPI initialization. If it's already initialized, we can
|
||||
// immediately check the icons, otherwise wait for initialization by
|
||||
// observing the topic sent out by the social service.
|
||||
if (Social.provider.workerAPI.initialized) {
|
||||
iconsReady = true;
|
||||
checkNext();
|
||||
} else {
|
||||
Services.obs.addObserver(function obs() {
|
||||
Services.obs.removeObserver(obs, "social:ambient-notification-changed");
|
||||
// Let the other observers (like the one that updates the UI) run before
|
||||
// checking the icons.
|
||||
executeSoon(function () {
|
||||
iconsReady = true;
|
||||
checkNext();
|
||||
});
|
||||
}, "social:ambient-notification-changed", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,9 @@ function tabLoaded() {
|
||||
function testInitial(finishcb) {
|
||||
ok(Social.provider, "Social provider is active");
|
||||
ok(Social.provider.enabled, "Social provider is enabled");
|
||||
ok(Social.provider.port, "Social provider has a port to its FrameWorker");
|
||||
let port = Social.provider.getWorkerPort();
|
||||
ok(port, "Social provider has a port to its FrameWorker");
|
||||
port.close();
|
||||
|
||||
let {shareButton, sharePopup} = SocialShareButton;
|
||||
ok(shareButton, "share button exists");
|
||||
@ -186,11 +188,74 @@ function testCloseBySpace() {
|
||||
sharePopup.addEventListener("popuphidden", function listener() {
|
||||
sharePopup.removeEventListener("popuphidden", listener);
|
||||
ok(true, "space closed the share popup");
|
||||
executeSoon(testDisable);
|
||||
executeSoon(testStillSharedIn2Tabs);
|
||||
});
|
||||
EventUtils.synthesizeKey("VK_SPACE", {});
|
||||
}
|
||||
|
||||
function testStillSharedIn2Tabs() {
|
||||
let toShare = "http://example.com";
|
||||
let {shareButton} = SocialShareButton;
|
||||
let initialTab = gBrowser.selectedTab;
|
||||
if (shareButton.hasAttribute("shared")) {
|
||||
SocialShareButton.unsharePage();
|
||||
}
|
||||
is(shareButton.hasAttribute("shared"), false, "Share button should not have 'shared' for the initial tab");
|
||||
let tab1 = gBrowser.selectedTab = gBrowser.addTab(toShare);
|
||||
let tab1b = gBrowser.getBrowserForTab(tab1);
|
||||
|
||||
tab1b.addEventListener("load", function tabLoad(event) {
|
||||
tab1b.removeEventListener("load", tabLoad, true);
|
||||
let tab2 = gBrowser.selectedTab = gBrowser.addTab(toShare);
|
||||
let tab2b = gBrowser.getBrowserForTab(tab2);
|
||||
tab2b.addEventListener("load", function tabLoad(event) {
|
||||
tab2b.removeEventListener("load", tabLoad, true);
|
||||
// should start without either page being shared.
|
||||
is(shareButton.hasAttribute("shared"), false, "Share button should not have 'shared' before we've done anything");
|
||||
EventUtils.synthesizeMouseAtCenter(shareButton, {});
|
||||
is(shareButton.hasAttribute("shared"), true, "Share button should reflect the share");
|
||||
// and switching to the first tab (with the same URL) should still reflect shared.
|
||||
gBrowser.selectedTab = tab1;
|
||||
is(shareButton.hasAttribute("shared"), true, "Share button should reflect the share");
|
||||
// but switching back the initial one should reflect not shared.
|
||||
gBrowser.selectedTab = initialTab;
|
||||
is(shareButton.hasAttribute("shared"), false, "Initial tab should not reflect shared");
|
||||
|
||||
gBrowser.selectedTab = tab1;
|
||||
SocialShareButton.unsharePage();
|
||||
gBrowser.removeTab(tab1);
|
||||
gBrowser.removeTab(tab2);
|
||||
executeSoon(testStillSharedAfterReopen);
|
||||
}, true);
|
||||
}, true);
|
||||
}
|
||||
|
||||
function testStillSharedAfterReopen() {
|
||||
let toShare = "http://example.com";
|
||||
let {shareButton} = SocialShareButton;
|
||||
|
||||
is(shareButton.hasAttribute("shared"), false, "Reopen: Share button should not have 'shared' for the initial tab");
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab(toShare);
|
||||
let tabb = gBrowser.getBrowserForTab(tab);
|
||||
tabb.addEventListener("load", function tabLoad(event) {
|
||||
tabb.removeEventListener("load", tabLoad, true);
|
||||
SocialShareButton.sharePage();
|
||||
is(shareButton.hasAttribute("shared"), true, "Share button should reflect the share");
|
||||
gBrowser.removeTab(tab);
|
||||
// should be on the initial unshared tab now.
|
||||
is(shareButton.hasAttribute("shared"), false, "Initial tab should be selected and be unshared.");
|
||||
// now open the same URL - should be back to shared.
|
||||
tab = gBrowser.selectedTab = gBrowser.addTab(toShare, {skipAnimation: true});
|
||||
tab.linkedBrowser.addEventListener("load", function tabLoad(event) {
|
||||
tab.linkedBrowser.removeEventListener("load", tabLoad, true);
|
||||
is(shareButton.hasAttribute("shared"), true, "New tab to previously shared URL should reflect shared");
|
||||
SocialShareButton.unsharePage();
|
||||
gBrowser.removeTab(tab);
|
||||
executeSoon(testDisable);
|
||||
}, true);
|
||||
}, true);
|
||||
}
|
||||
|
||||
function testDisable() {
|
||||
let shareButton = SocialShareButton.shareButton;
|
||||
Services.prefs.setBoolPref(prefName, false);
|
||||
|
@ -11,6 +11,7 @@ onconnect = function(e) {
|
||||
switch (topic) {
|
||||
case "test-init":
|
||||
testPort = port;
|
||||
port.postMessage({topic: "test-init-done"});
|
||||
break;
|
||||
case "sidebar-message":
|
||||
sidebarPort = port;
|
||||
@ -69,7 +70,6 @@ onconnect = function(e) {
|
||||
case "social.initialize":
|
||||
// This is the workerAPI port, respond and set up a notification icon.
|
||||
apiPort = port;
|
||||
port.postMessage({topic: "social.initialize-response"});
|
||||
let profile = {
|
||||
portrait: "https://example.com/portrait.jpg",
|
||||
userName: "trickster",
|
||||
|
@ -1615,6 +1615,12 @@
|
||||
return "passwords";
|
||||
if (type == "editBookmarkPanel")
|
||||
return "bookmarks";
|
||||
if (type == "addon-install-complete") {
|
||||
if (!Services.prefs.prefHasUserValue("services.sync.username"))
|
||||
return "addons";
|
||||
if (!Services.prefs.getBoolPref("services.sync.engine.addons"))
|
||||
return "addons-sync-disabled";
|
||||
}
|
||||
return null;
|
||||
]]></getter>
|
||||
</property>
|
||||
@ -1626,6 +1632,14 @@
|
||||
);
|
||||
]]></getter>
|
||||
</property>
|
||||
<property name="_notificationLink">
|
||||
<getter><![CDATA[
|
||||
if (this._notificationType == "addons-sync-disabled") {
|
||||
return "https://support.mozilla.org/kb/how-do-i-enable-add-sync";
|
||||
}
|
||||
return "https://services.mozilla.com/sync/";
|
||||
]]></getter>
|
||||
</property>
|
||||
<method name="onCloseButtonCommand">
|
||||
<body><![CDATA[
|
||||
this._viewsLeft = 0;
|
||||
@ -1656,7 +1670,8 @@
|
||||
|
||||
let viewsLeft = this._viewsLeft;
|
||||
if (viewsLeft) {
|
||||
if (Services.prefs.prefHasUserValue("services.sync.username")) {
|
||||
if (Services.prefs.prefHasUserValue("services.sync.username") &&
|
||||
this._notificationType != "addons-sync-disabled") {
|
||||
// If the user has already setup Sync, don't show the notification.
|
||||
this._viewsLeft = 0;
|
||||
// Be sure to hide the panel, in case it was visible and the user
|
||||
@ -1669,7 +1684,7 @@
|
||||
this._viewsLeft = viewsLeft - 1;
|
||||
}
|
||||
|
||||
this._promolink.setAttribute("href", "https://services.mozilla.com/sync/");
|
||||
this._promolink.setAttribute("href", this._notificationLink);
|
||||
this._promolink.value = gNavigatorBundle.getString("syncPromoNotification.learnMoreLinkText");
|
||||
|
||||
this.hidden = false;
|
||||
|
@ -1328,7 +1328,14 @@ FeedWriter.prototype = {
|
||||
}
|
||||
var faviconURI = makeURI(readerURI.prePath + "/favicon.ico");
|
||||
var self = this;
|
||||
var usePrivateBrowsing = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell)
|
||||
.QueryInterface(Ci.nsILoadContext)
|
||||
.usePrivateBrowsing;
|
||||
this._faviconService.setAndFetchFaviconForPage(readerURI, faviconURI, false,
|
||||
usePrivateBrowsing ? this._faviconService.FAVICON_LOAD_PRIVATE
|
||||
: this._faviconService.FAVICON_LOAD_NON_PRIVATE,
|
||||
function (aURI, aDataLen, aData, aMimeType) {
|
||||
if (aDataLen > 0) {
|
||||
var dataURL = "data:" + aMimeType + ";base64," +
|
||||
|
@ -577,10 +577,6 @@ nsBrowserContentHandler.prototype = {
|
||||
} catch (ex) {}
|
||||
let override = needHomepageOverride(prefb);
|
||||
if (override != OVERRIDE_NONE) {
|
||||
// Setup the default search engine to about:home page.
|
||||
AboutHomeUtils.loadDefaultSearchEngine();
|
||||
AboutHomeUtils.loadSnippetsURL();
|
||||
|
||||
switch (override) {
|
||||
case OVERRIDE_NEW_PROFILE:
|
||||
// New profile.
|
||||
@ -603,13 +599,6 @@ nsBrowserContentHandler.prototype = {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// No need to override homepage, but update snippets url if the pref has
|
||||
// been manually changed.
|
||||
if (Services.prefs.prefHasUserValue(AboutHomeUtils.SNIPPETS_URL_PREF)) {
|
||||
AboutHomeUtils.loadSnippetsURL();
|
||||
}
|
||||
}
|
||||
} catch (ex) {}
|
||||
|
||||
// formatURLPref might return "about:blank" if getting the pref fails
|
||||
@ -835,41 +824,5 @@ nsDefaultCommandLineHandler.prototype = {
|
||||
helpInfo : "",
|
||||
};
|
||||
|
||||
let AboutHomeUtils = {
|
||||
SNIPPETS_URL_PREF: "browser.aboutHomeSnippets.updateUrl",
|
||||
get _storage() {
|
||||
let aboutHomeURI = Services.io.newURI("moz-safe-about:home", null, null);
|
||||
let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"].
|
||||
getService(Components.interfaces.nsIScriptSecurityManager).
|
||||
getNoAppCodebasePrincipal(aboutHomeURI);
|
||||
let dsm = Components.classes["@mozilla.org/dom/storagemanager;1"].
|
||||
getService(Components.interfaces.nsIDOMStorageManager);
|
||||
return dsm.getLocalStorageForPrincipal(principal, "");
|
||||
},
|
||||
|
||||
loadDefaultSearchEngine: function AHU_loadDefaultSearchEngine()
|
||||
{
|
||||
let defaultEngine = Services.search.originalDefaultEngine;
|
||||
let submission = defaultEngine.getSubmission("_searchTerms_");
|
||||
if (submission.postData)
|
||||
throw new Error("Home page does not support POST search engines.");
|
||||
let engine = {
|
||||
name: defaultEngine.name
|
||||
, searchUrl: submission.uri.spec
|
||||
}
|
||||
this._storage.setItem("search-engine", JSON.stringify(engine));
|
||||
},
|
||||
|
||||
loadSnippetsURL: function AHU_loadSnippetsURL()
|
||||
{
|
||||
const STARTPAGE_VERSION = 3;
|
||||
let updateURL = Services.prefs
|
||||
.getCharPref(this.SNIPPETS_URL_PREF)
|
||||
.replace("%STARTPAGE_VERSION%", STARTPAGE_VERSION);
|
||||
updateURL = Services.urlFormatter.formatURL(updateURL);
|
||||
this._storage.setItem("snippets-update-url", updateURL);
|
||||
},
|
||||
};
|
||||
|
||||
var components = [nsBrowserContentHandler, nsDefaultCommandLineHandler];
|
||||
var NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
|
||||
|
@ -316,10 +316,6 @@ var gAdvancedPane = {
|
||||
}
|
||||
}
|
||||
|
||||
var storageManager = Components.classes["@mozilla.org/dom/storagemanager;1"].
|
||||
getService(Components.interfaces.nsIDOMStorageManager);
|
||||
usage += storageManager.getUsage(host);
|
||||
|
||||
return usage;
|
||||
},
|
||||
|
||||
@ -407,12 +403,6 @@ var gAdvancedPane = {
|
||||
}
|
||||
}
|
||||
|
||||
// send out an offline-app-removed signal. The nsDOMStorage
|
||||
// service will clear DOM storage for this host.
|
||||
var obs = Components.classes["@mozilla.org/observer-service;1"]
|
||||
.getService(Components.interfaces.nsIObserverService);
|
||||
obs.notifyObservers(null, "offline-app-removed", host);
|
||||
|
||||
// remove the permission
|
||||
var pm = Components.classes["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Components.interfaces.nsIPermissionManager);
|
||||
|
@ -308,10 +308,6 @@ var gAdvancedPane = {
|
||||
}
|
||||
}
|
||||
|
||||
var storageManager = Components.classes["@mozilla.org/dom/storagemanager;1"].
|
||||
getService(Components.interfaces.nsIDOMStorageManager);
|
||||
usage += storageManager.getUsage(host);
|
||||
|
||||
return usage;
|
||||
},
|
||||
|
||||
@ -399,12 +395,6 @@ var gAdvancedPane = {
|
||||
}
|
||||
}
|
||||
|
||||
// send out an offline-app-removed signal. The nsDOMStorage
|
||||
// service will clear DOM storage for this host.
|
||||
var obs = Components.classes["@mozilla.org/observer-service;1"]
|
||||
.getService(Components.interfaces.nsIObserverService);
|
||||
obs.notifyObservers(null, "offline-app-removed", host);
|
||||
|
||||
// remove the permission
|
||||
var pm = Components.classes["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Components.interfaces.nsIPermissionManager);
|
||||
|
@ -651,8 +651,8 @@ PrivateBrowsingService.prototype = {
|
||||
}
|
||||
|
||||
// Image Cache
|
||||
let (imageCache = Cc["@mozilla.org/image/cache;1"].
|
||||
getService(Ci.imgICache)) {
|
||||
let (imageCache = Cc["@mozilla.org/image/tools;1"].
|
||||
getService(Ci.imgITools).getImgCacheForDocument(null)) {
|
||||
try {
|
||||
imageCache.clearCache(false); // true=chrome, false=content
|
||||
} catch (ex) {
|
||||
|
@ -3,15 +3,13 @@
|
||||
<!DOCTYPE html>
|
||||
<title>Test for bug 463205</title>
|
||||
|
||||
<body>
|
||||
<body onload="onLoad()">
|
||||
<iframe src="data:text/html,<input%20id='original'>"></iframe>
|
||||
<iframe src="browser_463205_helper.html"></iframe>
|
||||
<iframe src="data:text/html,mark1"></iframe>
|
||||
|
||||
<script type="application/javascript">
|
||||
frames[2].addEventListener("DOMContentLoaded", function() {
|
||||
frames[2].removeEventListener("DOMContentLoaded", arguments.callee, false);
|
||||
|
||||
function onLoad() {
|
||||
if (frames[2].document.location.href == "data:text/html,mark1") {
|
||||
frames[2].document.location = "data:text/html,mark2";
|
||||
}
|
||||
@ -20,6 +18,6 @@
|
||||
frames[0].document.location = "http://mochi.test:8888/browser/" +
|
||||
"browser/components/sessionstore/test/browser_463205_helper.html";
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
@ -224,7 +224,7 @@ let PageThumbs = {
|
||||
let sh = aWindow.innerHeight;
|
||||
|
||||
let {width: thumbnailWidth, height: thumbnailHeight} = aCanvas;
|
||||
let scale = Math.max(thumbnailWidth / sw, thumbnailHeight / sh);
|
||||
let scale = Math.min(Math.max(thumbnailWidth / sw, thumbnailHeight / sh), 1);
|
||||
let scaledWidth = sw * scale;
|
||||
let scaledHeight = sh * scale;
|
||||
|
||||
|
@ -9,7 +9,11 @@ ENABLE_MARIONETTE=1
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
mk_add_options MOZ_MAKE_FLAGS=-j1
|
||||
if test -n "${_PYMAKE}"; then
|
||||
mk_add_options MOZ_MAKE_FLAGS=-j4
|
||||
else
|
||||
mk_add_options MOZ_MAKE_FLAGS=-j1
|
||||
fi
|
||||
|
||||
# Package js shell.
|
||||
export MOZ_PACKAGE_JSSHELL=1
|
||||
|
@ -18,7 +18,11 @@ export MOZILLA_OFFICIAL=1
|
||||
|
||||
export MOZ_TELEMETRY_REPORTING=1
|
||||
|
||||
mk_add_options MOZ_MAKE_FLAGS=-j1
|
||||
if test -n "${_PYMAKE}"; then
|
||||
mk_add_options MOZ_MAKE_FLAGS=-j4
|
||||
else
|
||||
mk_add_options MOZ_MAKE_FLAGS=-j1
|
||||
fi
|
||||
|
||||
# Package js shell.
|
||||
export MOZ_PACKAGE_JSSHELL=1
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
let EXPORTED_SYMBOLS = [ ];
|
||||
let EXPORTED_SYMBOLS = [ "Flags" ];
|
||||
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
@ -13,6 +13,12 @@ Cu.import("resource://gre/modules/Services.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
|
||||
"resource://gre/modules/AddonManager.jsm");
|
||||
|
||||
// We need to use an object in which to store any flags because a primitive
|
||||
// would remain undefined.
|
||||
let Flags = {
|
||||
addonsLoaded: false
|
||||
};
|
||||
|
||||
/**
|
||||
* 'addon' command.
|
||||
*/
|
||||
@ -286,5 +292,6 @@ AddonManager.getAllAddons(function addonAsync(aAddons) {
|
||||
return promise;
|
||||
}
|
||||
});
|
||||
Flags.addonsLoaded = true;
|
||||
Services.obs.notifyObservers(null, "gcli_addon_commands_ready", null);
|
||||
});
|
||||
|
@ -12,6 +12,10 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LayoutHelpers",
|
||||
"resource:///modules/devtools/LayoutHelpers.jsm");
|
||||
|
||||
// String used as an indication to generate default file name in the following
|
||||
// format: "Screen Shot yyyy-mm-dd at HH.MM.SS.png"
|
||||
const FILENAME_DEFAULT_VALUE = " ";
|
||||
|
||||
/**
|
||||
* 'screenshot' command
|
||||
*/
|
||||
@ -19,57 +23,86 @@ gcli.addCommand({
|
||||
name: "screenshot",
|
||||
description: gcli.lookup("screenshotDesc"),
|
||||
manual: gcli.lookup("screenshotManual"),
|
||||
returnType: "string",
|
||||
returnType: "html",
|
||||
params: [
|
||||
{
|
||||
name: "filename",
|
||||
type: "string",
|
||||
defaultValue: FILENAME_DEFAULT_VALUE,
|
||||
description: gcli.lookup("screenshotFilenameDesc"),
|
||||
manual: gcli.lookup("screenshotFilenameManual")
|
||||
},
|
||||
{
|
||||
name: "delay",
|
||||
type: { name: "number", min: 0 },
|
||||
defaultValue: 0,
|
||||
description: gcli.lookup("screenshotDelayDesc"),
|
||||
manual: gcli.lookup("screenshotDelayManual")
|
||||
},
|
||||
{
|
||||
name: "fullpage",
|
||||
type: "boolean",
|
||||
description: gcli.lookup("screenshotFullPageDesc"),
|
||||
manual: gcli.lookup("screenshotFullPageManual")
|
||||
},
|
||||
{
|
||||
name: "selector",
|
||||
type: "node",
|
||||
defaultValue: null,
|
||||
description: gcli.lookup("inspectNodeDesc"),
|
||||
manual: gcli.lookup("inspectNodeManual")
|
||||
group: gcli.lookup("screenshotGroupOptions"),
|
||||
params: [
|
||||
{
|
||||
name: "clipboard",
|
||||
type: "boolean",
|
||||
description: gcli.lookup("screenshotClipboardDesc"),
|
||||
manual: gcli.lookup("screenshotClipboardManual")
|
||||
},
|
||||
{
|
||||
name: "chrome",
|
||||
type: "boolean",
|
||||
description: gcli.lookup("screenshotChromeDesc"),
|
||||
manual: gcli.lookup("screenshotChromeManual")
|
||||
},
|
||||
{
|
||||
name: "delay",
|
||||
type: { name: "number", min: 0 },
|
||||
defaultValue: 0,
|
||||
description: gcli.lookup("screenshotDelayDesc"),
|
||||
manual: gcli.lookup("screenshotDelayManual")
|
||||
},
|
||||
{
|
||||
name: "fullpage",
|
||||
type: "boolean",
|
||||
description: gcli.lookup("screenshotFullPageDesc"),
|
||||
manual: gcli.lookup("screenshotFullPageManual")
|
||||
},
|
||||
{
|
||||
name: "selector",
|
||||
type: "node",
|
||||
defaultValue: null,
|
||||
description: gcli.lookup("inspectNodeDesc"),
|
||||
manual: gcli.lookup("inspectNodeManual")
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
exec: function Command_screenshot(args, context) {
|
||||
var document = context.environment.contentDocument;
|
||||
if (args.chrome && args.selector) {
|
||||
// Node screenshot with chrome option does not work as inteded
|
||||
// Refer https://bugzilla.mozilla.org/show_bug.cgi?id=659268#c7
|
||||
// throwing for now.
|
||||
throw new Error(gcli.lookup("screenshotSelectorChromeConflict"));
|
||||
}
|
||||
var document = args.chrome? context.environment.chromeDocument
|
||||
: context.environment.contentDocument;
|
||||
if (args.delay > 0) {
|
||||
var promise = context.createPromise();
|
||||
document.defaultView.setTimeout(function Command_screenshotDelay() {
|
||||
let reply = this.grabScreen(document, args.filename);
|
||||
let reply = this.grabScreen(document, args.filename, args.clipboard,
|
||||
args.fullpage);
|
||||
promise.resolve(reply);
|
||||
}.bind(this), args.delay * 1000);
|
||||
return promise;
|
||||
}
|
||||
else {
|
||||
return this.grabScreen(document, args.filename, args.fullpage, args.selector);
|
||||
return this.grabScreen(document, args.filename, args.clipboard,
|
||||
args.fullpage, args.selector);
|
||||
}
|
||||
},
|
||||
grabScreen:
|
||||
function Command_screenshotGrabScreen(document, filename, fullpage, node) {
|
||||
function Command_screenshotGrabScreen(document, filename, clipboard,
|
||||
fullpage, node) {
|
||||
let window = document.defaultView;
|
||||
let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
||||
let left = 0;
|
||||
let top = 0;
|
||||
let width;
|
||||
let height;
|
||||
let div = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
|
||||
|
||||
if (!fullpage) {
|
||||
if (!node) {
|
||||
@ -93,19 +126,70 @@ gcli.addCommand({
|
||||
|
||||
let ctx = canvas.getContext("2d");
|
||||
ctx.drawWindow(window, left, top, width, height, "#fff");
|
||||
|
||||
let data = canvas.toDataURL("image/png", "");
|
||||
|
||||
try {
|
||||
if (clipboard) {
|
||||
let io = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
let channel = io.newChannel(data, null, null);
|
||||
let input = channel.open();
|
||||
let imgTools = Cc["@mozilla.org/image/tools;1"]
|
||||
.getService(Ci.imgITools);
|
||||
|
||||
let container = {};
|
||||
imgTools.decodeImageData(input, channel.contentType, container);
|
||||
|
||||
let wrapped = Cc["@mozilla.org/supports-interface-pointer;1"]
|
||||
.createInstance(Ci.nsISupportsInterfacePointer);
|
||||
wrapped.data = container.value;
|
||||
|
||||
let trans = Cc["@mozilla.org/widget/transferable;1"]
|
||||
.createInstance(Ci.nsITransferable);
|
||||
if ("init" in trans) {
|
||||
trans.init(null);
|
||||
}
|
||||
trans.addDataFlavor(channel.contentType);
|
||||
trans.setTransferData(channel.contentType, wrapped, -1);
|
||||
|
||||
let clipid = Ci.nsIClipboard;
|
||||
let clip = Cc["@mozilla.org/widget/clipboard;1"].getService(clipid);
|
||||
clip.setData(trans, null, clipid.kGlobalClipboard);
|
||||
div.textContent = gcli.lookup("screenshotCopied");
|
||||
return div;
|
||||
}
|
||||
}
|
||||
catch (ex) {
|
||||
div.textContent = gcli.lookup("screenshotErrorCopying");
|
||||
return div;
|
||||
}
|
||||
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
|
||||
// Create a name for the file if not present
|
||||
if (filename == FILENAME_DEFAULT_VALUE) {
|
||||
let date = new Date();
|
||||
let dateString = date.getFullYear() + "-" + (date.getMonth() + 1) +
|
||||
"-" + date.getDate();
|
||||
dateString = dateString.split("-").map(function(part) {
|
||||
if (part.length == 1) {
|
||||
part = "0" + part;
|
||||
}
|
||||
return part;
|
||||
}).join("-");
|
||||
let timeString = date.toTimeString().replace(/:/g, ".").split(" ")[0];
|
||||
filename = gcli.lookupFormat("screenshotGeneratedFilename",
|
||||
[dateString, timeString]) + ".png";
|
||||
}
|
||||
// Check there is a .png extension to filename
|
||||
if (!filename.match(/.png$/i)) {
|
||||
else if (!filename.match(/.png$/i)) {
|
||||
filename += ".png";
|
||||
}
|
||||
|
||||
// If the filename is relative, tack it onto the download directory
|
||||
if (!filename.match(/[\\\/]/)) {
|
||||
let downloadMgr = Cc["@mozilla.org/download-manager;1"]
|
||||
.getService(Ci.nsIDownloadManager);
|
||||
.getService(Ci.nsIDownloadManager);
|
||||
let tempfile = downloadMgr.userDownloadsDirectory;
|
||||
tempfile.append(filename);
|
||||
filename = tempfile.path;
|
||||
@ -114,21 +198,36 @@ gcli.addCommand({
|
||||
try {
|
||||
file.initWithPath(filename);
|
||||
} catch (ex) {
|
||||
return "Error saving to " + filename;
|
||||
div.textContent = gcli.lookup("screenshotErrorSavingToFile") + " " + filename;
|
||||
return div;
|
||||
}
|
||||
|
||||
let ioService = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
.getService(Ci.nsIIOService);
|
||||
|
||||
let Persist = Ci.nsIWebBrowserPersist;
|
||||
let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
|
||||
.createInstance(Persist);
|
||||
.createInstance(Persist);
|
||||
persist.persistFlags = Persist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
|
||||
Persist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
|
||||
|
||||
let source = ioService.newURI(data, "UTF8", null);
|
||||
persist.saveURI(source, null, null, null, null, file);
|
||||
|
||||
return "Saved to " + filename;
|
||||
div.textContent = gcli.lookup("screenshotSavedToFile") + " " + filename;
|
||||
div.addEventListener("click", function openFile() {
|
||||
div.removeEventListener("click", openFile);
|
||||
file.reveal();
|
||||
});
|
||||
div.style.cursor = "pointer";
|
||||
let image = document.createElement("div");
|
||||
let previewHeight = parseInt(256*height/width);
|
||||
image.setAttribute("style",
|
||||
"width:256px; height:" + previewHeight + "px;" +
|
||||
"background-image: url('" + data + "');" +
|
||||
"background-size: 256px " + previewHeight + "px;" +
|
||||
"margin: 4px; display: block");
|
||||
div.appendChild(image);
|
||||
return div;
|
||||
}
|
||||
});
|
||||
});
|
@ -24,6 +24,7 @@ MOCHITEST_BROWSER_FILES = \
|
||||
browser_cmd_pagemod_export.js \
|
||||
browser_cmd_pref.js \
|
||||
browser_cmd_restart.js \
|
||||
browser_cmd_screenshot.js \
|
||||
browser_cmd_settings.js \
|
||||
browser_gcli_web.js \
|
||||
head.js \
|
||||
@ -33,6 +34,7 @@ MOCHITEST_BROWSER_FILES = \
|
||||
MOCHITEST_BROWSER_FILES += \
|
||||
browser_dbg_cmd_break.html \
|
||||
browser_dbg_cmd.html \
|
||||
browser_cmd_screenshot.html \
|
||||
browser_cmd_pagemod_export.html \
|
||||
browser_cmd_jsb_script.jsi \
|
||||
$(NULL)
|
||||
|
@ -3,6 +3,9 @@
|
||||
|
||||
// Tests that the addon commands works as they should
|
||||
|
||||
let imported = {};
|
||||
Components.utils.import("resource:///modules/devtools/CmdAddon.jsm", imported);
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test("about:blank", [ GAT_test ]);
|
||||
}
|
||||
@ -10,6 +13,7 @@ function test() {
|
||||
function GAT_test() {
|
||||
var GAT_ready = DeveloperToolbarTest.checkCalled(function() {
|
||||
Services.obs.removeObserver(GAT_ready, "gcli_addon_commands_ready", false);
|
||||
info("gcli_addon_commands_ready notification received, running tests");
|
||||
|
||||
helpers.setInput('addon list dictionary');
|
||||
helpers.check({
|
||||
@ -91,4 +95,14 @@ function GAT_test() {
|
||||
});
|
||||
|
||||
Services.obs.addObserver(GAT_ready, "gcli_addon_commands_ready", false);
|
||||
|
||||
if (imported.Flags.addonsLoaded) {
|
||||
info("The getAllAddons command has already completed and we have missed ");
|
||||
info("the notification. Let's send the gcli_addon_commands_ready ");
|
||||
info("notification ourselves.");
|
||||
|
||||
Services.obs.notifyObservers(null, "gcli_addon_commands_ready", null);
|
||||
} else {
|
||||
info("gcli_addon_commands_ready notification has not yet been received.");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<img id="testImage" ></img>
|
||||
</body>
|
||||
</html>
|
148
browser/devtools/commandline/test/browser_cmd_screenshot.js
Normal file
148
browser/devtools/commandline/test/browser_cmd_screenshot.js
Normal file
@ -0,0 +1,148 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that screenshot command works properly
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" +
|
||||
"test/browser_cmd_screenshot.html";
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
let tempScope = {};
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm", tempScope);
|
||||
let FileUtils = tempScope.FileUtils;
|
||||
|
||||
function test() {
|
||||
DeveloperToolbarTest.test(TEST_URI, [ testInput, testCapture ]);
|
||||
}
|
||||
|
||||
function testInput() {
|
||||
helpers.setInput('screenshot');
|
||||
helpers.check({
|
||||
input: 'screenshot',
|
||||
markup: 'VVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
}
|
||||
});
|
||||
|
||||
helpers.setInput('screenshot abc.png');
|
||||
helpers.check({
|
||||
input: 'screenshot abc.png',
|
||||
markup: 'VVVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
filename: { value: "abc.png"},
|
||||
}
|
||||
});
|
||||
|
||||
helpers.setInput('screenshot --fullpage');
|
||||
helpers.check({
|
||||
input: 'screenshot --fullpage',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
fullpage: { value: true},
|
||||
}
|
||||
});
|
||||
|
||||
helpers.setInput('screenshot abc --delay 5');
|
||||
helpers.check({
|
||||
input: 'screenshot abc --delay 5',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
filename: { value: "abc"},
|
||||
delay: { value: "5"},
|
||||
}
|
||||
});
|
||||
|
||||
helpers.setInput('screenshot --selector img#testImage');
|
||||
helpers.check({
|
||||
input: 'screenshot --selector img#testImage',
|
||||
markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
|
||||
status: 'VALID',
|
||||
args: {
|
||||
selector: { value: content.document.getElementById("testImage")},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testCapture() {
|
||||
function checkTemporaryFile() {
|
||||
// Create a temporary file.
|
||||
let gFile = FileUtils.getFile("TmpD", ["TestScreenshotFile.png"]);
|
||||
if (gFile.exists()) {
|
||||
gFile.remove(false);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function clearClipboard() {
|
||||
let clipid = Ci.nsIClipboard;
|
||||
let clip = Cc["@mozilla.org/widget/clipboard;1"].getService(clipid);
|
||||
clip.emptyClipboard(clipid.kGlobalClipboard);
|
||||
}
|
||||
|
||||
function checkClipboard() {
|
||||
try {
|
||||
let clipid = Ci.nsIClipboard;
|
||||
let clip = Cc["@mozilla.org/widget/clipboard;1"].getService(clipid);
|
||||
let trans = Cc["@mozilla.org/widget/transferable;1"]
|
||||
.createInstance(Ci.nsITransferable);
|
||||
if ("init" in trans) {
|
||||
trans.init(null);
|
||||
}
|
||||
let io = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
let contentType = io.newChannel("", null, null).contentType;
|
||||
trans.addDataFlavor(contentType);
|
||||
clip.getData(trans, clipid.kGlobalClipboard);
|
||||
let str = new Object();
|
||||
let strLength = new Object();
|
||||
trans.getTransferData(contentType, str, strLength);
|
||||
if (str && strLength > 0) {
|
||||
clip.emptyClipboard(clipid.kGlobalClipboard);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (ex) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
let path = FileUtils.getFile("TmpD", ["TestScreenshotFile.png"]).path;
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "screenshot " + path,
|
||||
args: {
|
||||
delay: 0,
|
||||
filename: "" + path,
|
||||
fullpage: false,
|
||||
clipboard: false,
|
||||
node: null,
|
||||
chrome: false,
|
||||
},
|
||||
outputMatch: new RegExp("^Saved to "),
|
||||
});
|
||||
|
||||
ok(checkTemporaryFile, "Screenshot got created");
|
||||
|
||||
clearClipboard();
|
||||
|
||||
DeveloperToolbarTest.exec({
|
||||
typed: "screenshot --fullpage --clipboard",
|
||||
args: {
|
||||
delay: 0,
|
||||
filename: " ",
|
||||
fullpage: true,
|
||||
clipboard: true,
|
||||
node: null,
|
||||
chrome: false,
|
||||
},
|
||||
outputMatch: new RegExp("^Copied to clipboard.$"),
|
||||
});
|
||||
|
||||
ok(checkClipboard, "Screenshot got created and copied");
|
||||
}
|
||||
|
@ -46,8 +46,8 @@ DebuggerUI.prototype = {
|
||||
tabs.addEventListener("TabSelect", bound_refreshCommand, true);
|
||||
|
||||
win.addEventListener("unload", function onClose(aEvent) {
|
||||
tabs.removeEventListener("TabSelect", bound_refreshCommand, true);
|
||||
win.removeEventListener("unload", onClose, false);
|
||||
tabs.removeEventListener("TabSelect", bound_refreshCommand, true);
|
||||
}, false);
|
||||
},
|
||||
|
||||
@ -245,7 +245,7 @@ DebuggerPane.prototype = {
|
||||
_initServer: function DP__initServer() {
|
||||
if (!DebuggerServer.initialized) {
|
||||
// Always allow connections from nsIPipe transports.
|
||||
DebuggerServer.init(function () { return true; });
|
||||
DebuggerServer.init(function() true);
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
},
|
||||
|
@ -20,6 +20,7 @@ Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
|
||||
|
||||
/**
|
||||
* Controls the debugger view by handling the source scripts, the current
|
||||
@ -51,6 +52,7 @@ let DebuggerController = {
|
||||
window.removeEventListener("DOMContentLoaded", this._startupDebugger, true);
|
||||
|
||||
DebuggerView.cacheView();
|
||||
DebuggerView.initializeKeys();
|
||||
DebuggerView.initializePanes();
|
||||
DebuggerView.initializeEditor(function() {
|
||||
DebuggerView.GlobalSearch.initialize();
|
||||
@ -246,23 +248,6 @@ let DebuggerController = {
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if this is a remote debugger instance.
|
||||
* @return boolean
|
||||
*/
|
||||
get _isRemoteDebugger() {
|
||||
return window._remoteFlag;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if this is a chrome debugger instance.
|
||||
* @return boolean
|
||||
*/
|
||||
get _isChromeDebugger() {
|
||||
// Directly accessing window.parent.content may throw in some cases.
|
||||
return !("content" in window.parent) && !this._isRemoteDebugger;
|
||||
},
|
||||
|
||||
/**
|
||||
* Attempts to quit the current process if allowed.
|
||||
*/
|
||||
@ -295,6 +280,26 @@ let DebuggerController = {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if this is a remote debugger instance.
|
||||
* @return boolean
|
||||
*/
|
||||
XPCOMUtils.defineLazyGetter(DebuggerController, "_isRemoteDebugger", function() {
|
||||
// We're inside a single top level XUL window, not an iframe container.
|
||||
return !(window.frameElement instanceof XULElement) &&
|
||||
!!window._remoteFlag;
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns true if this is a chrome debugger instance.
|
||||
* @return boolean
|
||||
*/
|
||||
XPCOMUtils.defineLazyGetter(DebuggerController, "_isChromeDebugger", function() {
|
||||
// We're inside a single top level XUL window, but not a remote debugger.
|
||||
return !(window.frameElement instanceof XULElement) &&
|
||||
!window._remoteFlag;
|
||||
});
|
||||
|
||||
/**
|
||||
* ThreadState keeps the UI up to date with the state of the
|
||||
* thread (paused/attached/etc.).
|
||||
@ -1272,6 +1277,7 @@ SourceScripts.prototype = {
|
||||
return self._logError(url, aStatus);
|
||||
}
|
||||
let source = NetUtil.readInputStreamToString(aStream, aStream.available());
|
||||
source = self._convertToUnicode(source);
|
||||
self._onLoadSourceFinished(url, source, null, options);
|
||||
aStream.close();
|
||||
});
|
||||
@ -1296,8 +1302,8 @@ SourceScripts.prototype = {
|
||||
if (!Components.isSuccessCode(aStatusCode)) {
|
||||
return self._logError(url, aStatusCode);
|
||||
}
|
||||
self._onLoadSourceFinished(
|
||||
url, chunks.join(""), channel.contentType, options);
|
||||
let source = self._convertToUnicode(chunks.join(""), channel.contentCharset);
|
||||
self._onLoadSourceFinished(url, source, channel.contentType, options);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1307,6 +1313,28 @@ SourceScripts.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert a given string, encoded in a given character set, to unicode.
|
||||
* @param string aString
|
||||
* A string.
|
||||
* @param string aCharset
|
||||
* A character set.
|
||||
* @return string
|
||||
* A unicode string.
|
||||
*/
|
||||
_convertToUnicode: function SS__convertToUnicode(aString, aCharset) {
|
||||
// Decoding primitives.
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
|
||||
try {
|
||||
converter.charset = aCharset || "UTF-8";
|
||||
return converter.ConvertToUnicode(aString);
|
||||
} catch(e) {
|
||||
return aString;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when a script's source has been loaded.
|
||||
*
|
||||
|
@ -33,12 +33,65 @@ let DebuggerView = {
|
||||
cacheView: function DV_cacheView() {
|
||||
this._onTogglePanesButtonPressed = this._onTogglePanesButtonPressed.bind(this);
|
||||
|
||||
// Panes and view containers
|
||||
this._togglePanesButton = document.getElementById("toggle-panes");
|
||||
this._stackframesAndBreakpoints = document.getElementById("stackframes+breakpoints");
|
||||
this._stackframes = document.getElementById("stackframes");
|
||||
this._breakpoints = document.getElementById("breakpoints");
|
||||
this._variables = document.getElementById("variables");
|
||||
this._scripts = document.getElementById("scripts");
|
||||
this._globalSearch = document.getElementById("globalsearch");
|
||||
this._globalSearchSplitter = document.getElementById("globalsearch-splitter");
|
||||
|
||||
// Keys
|
||||
this._fileSearchKey = document.getElementById("fileSearchKey");
|
||||
this._lineSearchKey = document.getElementById("lineSearchKey");
|
||||
this._tokenSearchKey = document.getElementById("tokenSearchKey");
|
||||
this._globalSearchKey = document.getElementById("globalSearchKey");
|
||||
this._resumeKey = document.getElementById("resumeKey");
|
||||
this._stepOverKey = document.getElementById("stepOverKey");
|
||||
this._stepInKey = document.getElementById("stepInKey");
|
||||
this._stepOutKey = document.getElementById("stepOutKey");
|
||||
|
||||
// Buttons, textboxes etc.
|
||||
this._resumeButton = document.getElementById("resume");
|
||||
this._stepOverButton = document.getElementById("step-over");
|
||||
this._stepInButton = document.getElementById("step-in");
|
||||
this._stepOutButton = document.getElementById("step-out");
|
||||
this._scriptsSearchbox = document.getElementById("scripts-search");
|
||||
this._globalOperatorLabel = document.getElementById("global-operator-label");
|
||||
this._globalOperatorButton = document.getElementById("global-operator-button");
|
||||
this._tokenOperatorLabel = document.getElementById("token-operator-label");
|
||||
this._tokenOperatorButton = document.getElementById("token-operator-button");
|
||||
this._lineOperatorLabel = document.getElementById("line-operator-label");
|
||||
this._lineOperatorButton = document.getElementById("line-operator-button");
|
||||
},
|
||||
|
||||
/**
|
||||
* Applies the correct key labels and tooltips across global view elements.
|
||||
*/
|
||||
initializeKeys: function DV_initializeKeys() {
|
||||
this._resumeButton.setAttribute("tooltiptext",
|
||||
L10N.getFormatStr("pauseButtonTooltip", [LayoutHelpers.prettyKey(this._resumeKey)]));
|
||||
this._stepOverButton.setAttribute("tooltiptext",
|
||||
L10N.getFormatStr("stepOverTooltip", [LayoutHelpers.prettyKey(this._stepOverKey)]));
|
||||
this._stepInButton.setAttribute("tooltiptext",
|
||||
L10N.getFormatStr("stepInTooltip", [LayoutHelpers.prettyKey(this._stepInKey)]));
|
||||
this._stepOutButton.setAttribute("tooltiptext",
|
||||
L10N.getFormatStr("stepOutTooltip", [LayoutHelpers.prettyKey(this._stepOutKey)]));
|
||||
|
||||
this._scriptsSearchbox.setAttribute("placeholder",
|
||||
L10N.getFormatStr("emptyFilterText", [LayoutHelpers.prettyKey(this._fileSearchKey)]));
|
||||
this._globalOperatorLabel.setAttribute("value",
|
||||
L10N.getFormatStr("searchPanelGlobal", [LayoutHelpers.prettyKey(this._globalSearchKey)]));
|
||||
this._tokenOperatorLabel.setAttribute("value",
|
||||
L10N.getFormatStr("searchPanelToken", [LayoutHelpers.prettyKey(this._tokenSearchKey)]));
|
||||
this._lineOperatorLabel.setAttribute("value",
|
||||
L10N.getFormatStr("searchPanelLine", [LayoutHelpers.prettyKey(this._lineSearchKey)]));
|
||||
|
||||
this._globalOperatorButton.setAttribute("label", SEARCH_GLOBAL_FLAG);
|
||||
this._tokenOperatorButton.setAttribute("label", SEARCH_TOKEN_FLAG);
|
||||
this._lineOperatorButton.setAttribute("label", SEARCH_LINE_FLAG);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -92,6 +145,11 @@ let DebuggerView = {
|
||||
this._stackframesAndBreakpoints.parentNode.removeChild(this._stackframesAndBreakpoints);
|
||||
this._variables.parentNode.removeChild(this._variables);
|
||||
this._globalSearch.parentNode.removeChild(this._globalSearch);
|
||||
|
||||
// Delete all the cached global view elements.
|
||||
for (let i in this) {
|
||||
if (!(this[i] instanceof Function)) delete this[i];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -145,10 +203,12 @@ let DebuggerView = {
|
||||
if (aVisibleFlag) {
|
||||
this._stackframesAndBreakpoints.style.marginLeft = "0";
|
||||
this._togglePanesButton.removeAttribute("stackframesAndBreakpointsHidden");
|
||||
this._togglePanesButton.setAttribute("tooltiptext", L10N.getStr("collapsePanes"));
|
||||
} else {
|
||||
let margin = parseInt(this._stackframesAndBreakpoints.getAttribute("width")) + 1;
|
||||
this._stackframesAndBreakpoints.style.marginLeft = -margin + "px";
|
||||
this._togglePanesButton.setAttribute("stackframesAndBreakpointsHidden", "true");
|
||||
this._togglePanesButton.setAttribute("tooltiptext", L10N.getStr("expandPanes"));
|
||||
}
|
||||
Prefs.stackframesPaneVisible = aVisibleFlag;
|
||||
},
|
||||
@ -168,10 +228,12 @@ let DebuggerView = {
|
||||
if (aVisibleFlag) {
|
||||
this._variables.style.marginRight = "0";
|
||||
this._togglePanesButton.removeAttribute("variablesHidden");
|
||||
this._togglePanesButton.setAttribute("tooltiptext", L10N.getStr("collapsePanes"));
|
||||
} else {
|
||||
let margin = parseInt(this._variables.getAttribute("width")) + 1;
|
||||
this._variables.style.marginRight = -margin + "px";
|
||||
this._togglePanesButton.setAttribute("variablesHidden", "true");
|
||||
this._togglePanesButton.setAttribute("tooltiptext", L10N.getStr("expandPanes"));
|
||||
}
|
||||
Prefs.variablesPaneVisible = aVisibleFlag;
|
||||
},
|
||||
@ -184,7 +246,28 @@ let DebuggerView = {
|
||||
_stackframes: null,
|
||||
_breakpoints: null,
|
||||
_variables: null,
|
||||
_globalSearch: null
|
||||
_scripts: null,
|
||||
_globalSearch: null,
|
||||
_globalSearchSplitter: null,
|
||||
_fileSearchKey: null,
|
||||
_lineSearchKey: null,
|
||||
_tokenSearchKey: null,
|
||||
_globalSearchKey: null,
|
||||
_resumeKey: null,
|
||||
_stepOverKey: null,
|
||||
_stepInKey: null,
|
||||
_stepOutKey: null,
|
||||
_resumeButton: null,
|
||||
_stepOverButton: null,
|
||||
_stepInButton: null,
|
||||
_stepOutButton: null,
|
||||
_scriptsSearchbox: null,
|
||||
_globalOperatorLabel: null,
|
||||
_globalOperatorButton: null,
|
||||
_tokenOperatorLabel: null,
|
||||
_tokenOperatorButton: null,
|
||||
_lineOperatorLabel: null,
|
||||
_lineOperatorButton: null
|
||||
};
|
||||
|
||||
/**
|
||||
@ -245,6 +328,7 @@ function GlobalSearchView() {
|
||||
this._onLineClick = this._onLineClick.bind(this);
|
||||
this._onMatchClick = this._onMatchClick.bind(this);
|
||||
this._onResultsScroll = this._onResultsScroll.bind(this);
|
||||
this._onFocusLost = this._onFocusLost.bind(this);
|
||||
this._startSearch = this._startSearch.bind(this);
|
||||
}
|
||||
|
||||
@ -259,6 +343,12 @@ GlobalSearchView.prototype = {
|
||||
this._splitter.hidden = value;
|
||||
},
|
||||
|
||||
/**
|
||||
* True if the search results container is hidden.
|
||||
* @return boolean
|
||||
*/
|
||||
get hidden() this._pane.hidden,
|
||||
|
||||
/**
|
||||
* Removes all elements from the search results container, leaving it empty.
|
||||
*/
|
||||
@ -381,7 +471,7 @@ GlobalSearchView.prototype = {
|
||||
|
||||
for (let [url, text] of this._scriptSources) {
|
||||
// Check if the search token is not found anywhere in the script source.
|
||||
if (text.toLowerCase().indexOf(lowerCaseToken) === -1) {
|
||||
if (!text.toLowerCase().contains(lowerCaseToken)) {
|
||||
continue;
|
||||
}
|
||||
let lines = text.split("\n");
|
||||
@ -395,7 +485,7 @@ GlobalSearchView.prototype = {
|
||||
let lowerCaseLine = line.toLowerCase();
|
||||
|
||||
// Search is not case sensitive, and is tied to each line in the source.
|
||||
if (lowerCaseLine.indexOf(lowerCaseToken) === -1) {
|
||||
if (!lowerCaseLine.contains(lowerCaseToken)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -675,6 +765,20 @@ GlobalSearchView.prototype = {
|
||||
this._onMatchClick({ target: matches[this._currentlyFocusedMatch] });
|
||||
},
|
||||
|
||||
/**
|
||||
* Focuses the previously found match in the source editor.
|
||||
*/
|
||||
focusPrevMatch: function DVGS_focusPrevMatch() {
|
||||
let matches = this._pane.querySelectorAll(".string[match=true]");
|
||||
if (!matches.length) {
|
||||
return;
|
||||
}
|
||||
if (--this._currentlyFocusedMatch < 0) {
|
||||
this._currentlyFocusedMatch = matches.length - 1;
|
||||
}
|
||||
this._onMatchClick({ target: matches[this._currentlyFocusedMatch] });
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when a line in the search results container is clicked.
|
||||
*/
|
||||
@ -708,6 +812,13 @@ GlobalSearchView.prototype = {
|
||||
editor.setSelection(offset + range.start, offset + range.start + range.length);
|
||||
},
|
||||
|
||||
/**
|
||||
* Listener handling the searchbox blur event.
|
||||
*/
|
||||
_onFocusLost: function DVGS__onFocusLost(e) {
|
||||
this.hideAndEmpty();
|
||||
},
|
||||
|
||||
/**
|
||||
* Listener handling the global search container scroll event.
|
||||
*/
|
||||
@ -790,15 +901,18 @@ GlobalSearchView.prototype = {
|
||||
*/
|
||||
_pane: null,
|
||||
_splitter: null,
|
||||
_searchbox: null,
|
||||
|
||||
/**
|
||||
* Initialization function, called when the debugger is initialized.
|
||||
*/
|
||||
initialize: function DVS_initialize() {
|
||||
this._pane = document.getElementById("globalsearch");
|
||||
this._splitter = document.getElementById("globalsearch-splitter");
|
||||
initialize: function DVGS_initialize() {
|
||||
this._pane = DebuggerView._globalSearch;
|
||||
this._splitter = DebuggerView._globalSearchSplitter;
|
||||
this._searchbox = DebuggerView._scriptsSearchbox;
|
||||
|
||||
this._pane.addEventListener("scroll", this._onResultsScroll, false);
|
||||
this._searchbox.addEventListener("blur", this._onFocusLost, false);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -806,10 +920,12 @@ GlobalSearchView.prototype = {
|
||||
*/
|
||||
destroy: function DVS_destroy() {
|
||||
this._pane.removeEventListener("scroll", this._onResultsScroll, false);
|
||||
this._searchbox.removeEventListener("blur", this._onFocusLost, false);
|
||||
|
||||
this.hideAndEmpty();
|
||||
this._pane = null;
|
||||
this._splitter = null;
|
||||
this._searchbox = null;
|
||||
this._scriptSources = null;
|
||||
}
|
||||
};
|
||||
@ -819,8 +935,10 @@ GlobalSearchView.prototype = {
|
||||
*/
|
||||
function ScriptsView() {
|
||||
this._onScriptsChange = this._onScriptsChange.bind(this);
|
||||
this._onScriptsSearchClick = this._onScriptsSearchClick.bind(this);
|
||||
this._onScriptsSearchBlur = this._onScriptsSearchBlur.bind(this);
|
||||
this._onScriptsSearch = this._onScriptsSearch.bind(this);
|
||||
this._onScriptsKeyUp = this._onScriptsKeyUp.bind(this);
|
||||
this._onScriptsKeyPress = this._onScriptsKeyPress.bind(this);
|
||||
}
|
||||
|
||||
ScriptsView.prototype = {
|
||||
@ -1168,6 +1286,10 @@ ScriptsView.prototype = {
|
||||
DebuggerController.SourceScripts.showScript(selectedItem.getUserData("sourceScript"));
|
||||
},
|
||||
|
||||
_prevSearchedFile: "",
|
||||
_prevSearchedLine: 0,
|
||||
_prevSearchedToken: "",
|
||||
|
||||
/**
|
||||
* Performs a file search if necessary.
|
||||
*
|
||||
@ -1254,6 +1376,20 @@ ScriptsView.prototype = {
|
||||
this._prevSearchedToken = aToken;
|
||||
},
|
||||
|
||||
/**
|
||||
* The focus listener for the scripts search box.
|
||||
*/
|
||||
_onScriptsSearchClick: function DVS__onScriptsSearchClick() {
|
||||
this._searchboxPanel.openPopup(this._searchbox);
|
||||
},
|
||||
|
||||
/**
|
||||
* The blur listener for the scripts search box.
|
||||
*/
|
||||
_onScriptsSearchBlur: function DVS__onScriptsSearchBlur() {
|
||||
this._searchboxPanel.hidePopup();
|
||||
},
|
||||
|
||||
/**
|
||||
* The search listener for the scripts search box.
|
||||
*/
|
||||
@ -1262,6 +1398,8 @@ ScriptsView.prototype = {
|
||||
if (!this._scripts.itemCount) {
|
||||
return;
|
||||
}
|
||||
this._searchboxPanel.hidePopup();
|
||||
|
||||
let [file, line, token, isGlobal] = this.searchboxInfo;
|
||||
|
||||
// If this is a global script search, schedule a search in all the sources,
|
||||
@ -1277,28 +1415,45 @@ ScriptsView.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* The keyup listener for the scripts search box.
|
||||
* The keypress listener for the scripts search box.
|
||||
*/
|
||||
_onScriptsKeyUp: function DVS__onScriptsKeyUp(e) {
|
||||
_onScriptsKeyPress: function DVS__onScriptsKeyPress(e) {
|
||||
if (e.keyCode === e.DOM_VK_ESCAPE) {
|
||||
DebuggerView.editor.focus();
|
||||
return;
|
||||
}
|
||||
var action;
|
||||
|
||||
if (e.keyCode === e.DOM_VK_RETURN || e.keyCode === e.DOM_VK_ENTER) {
|
||||
let token = this.searchboxInfo[2];
|
||||
let isGlobal = this.searchboxInfo[3];
|
||||
if (e.keyCode === e.DOM_VK_DOWN ||
|
||||
e.keyCode === e.DOM_VK_RETURN ||
|
||||
e.keyCode === e.DOM_VK_ENTER) {
|
||||
action = 1;
|
||||
} else if (e.keyCode === e.DOM_VK_UP) {
|
||||
action = 2;
|
||||
}
|
||||
|
||||
if (!token.length) {
|
||||
if (action) {
|
||||
let [file, line, token, isGlobal] = this.searchboxInfo;
|
||||
|
||||
if (token.length) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if (isGlobal) {
|
||||
DebuggerView.GlobalSearch.focusNextMatch();
|
||||
if (DebuggerView.GlobalSearch.hidden) {
|
||||
DebuggerView.GlobalSearch.scheduleSearch();
|
||||
} else {
|
||||
DebuggerView.GlobalSearch[action === 1
|
||||
? "focusNextMatch"
|
||||
: "focusPrevMatch"]();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let editor = DebuggerView.editor;
|
||||
let offset = editor.findNext(true);
|
||||
let offset = editor[action === 1 ? "findNext" : "findPrevious"](true);
|
||||
if (offset > -1) {
|
||||
editor.setSelection(offset, offset + token.length)
|
||||
}
|
||||
@ -1314,11 +1469,20 @@ ScriptsView.prototype = {
|
||||
DebuggerView.GlobalSearch.hideAndEmpty();
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the scripts path filter key sequence was pressed.
|
||||
*/
|
||||
_onFileSearch: function DVS__onFileSearch() {
|
||||
this._onSearch();
|
||||
this._searchboxPanel.openPopup(this._searchbox);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the scripts token filter key sequence was pressed.
|
||||
*/
|
||||
_onLineSearch: function DVS__onLineSearch() {
|
||||
this._onSearch(SEARCH_LINE_FLAG);
|
||||
this._searchboxPanel.hidePopup();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1326,6 +1490,7 @@ ScriptsView.prototype = {
|
||||
*/
|
||||
_onTokenSearch: function DVS__onTokenSearch() {
|
||||
this._onSearch(SEARCH_TOKEN_FLAG);
|
||||
this._searchboxPanel.hidePopup();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1333,6 +1498,7 @@ ScriptsView.prototype = {
|
||||
*/
|
||||
_onGlobalSearch: function DVS__onGlobalSearch() {
|
||||
this._onSearch(SEARCH_GLOBAL_FLAG);
|
||||
this._searchboxPanel.hidePopup();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1340,17 +1506,22 @@ ScriptsView.prototype = {
|
||||
*/
|
||||
_scripts: null,
|
||||
_searchbox: null,
|
||||
_searchboxPanel: null,
|
||||
|
||||
/**
|
||||
* Initialization function, called when the debugger is initialized.
|
||||
*/
|
||||
initialize: function DVS_initialize() {
|
||||
this._scripts = document.getElementById("scripts");
|
||||
this._scripts = DebuggerView._scripts;
|
||||
this._searchbox = document.getElementById("scripts-search");
|
||||
this._searchboxPanel = document.getElementById("scripts-search-panel");
|
||||
|
||||
this._scripts.addEventListener("select", this._onScriptsChange, false);
|
||||
this._searchbox.addEventListener("click", this._onScriptsSearchClick, false);
|
||||
this._searchbox.addEventListener("blur", this._onScriptsSearchBlur, false);
|
||||
this._searchbox.addEventListener("select", this._onScriptsSearch, false);
|
||||
this._searchbox.addEventListener("input", this._onScriptsSearch, false);
|
||||
this._searchbox.addEventListener("keyup", this._onScriptsKeyUp, false);
|
||||
this._searchbox.addEventListener("keypress", this._onScriptsKeyPress, false);
|
||||
this.commitScripts();
|
||||
},
|
||||
|
||||
@ -1359,13 +1530,16 @@ ScriptsView.prototype = {
|
||||
*/
|
||||
destroy: function DVS_destroy() {
|
||||
this._scripts.removeEventListener("select", this._onScriptsChange, false);
|
||||
this._searchbox.removeEventListener("click", this._onScriptsSearchClick, false);
|
||||
this._searchbox.removeEventListener("blur", this._onScriptsSearchBlur, false);
|
||||
this._searchbox.removeEventListener("select", this._onScriptsSearch, false);
|
||||
this._searchbox.removeEventListener("input", this._onScriptsSearch, false);
|
||||
this._searchbox.removeEventListener("keyup", this._onScriptsKeyUp, false);
|
||||
this._searchbox.removeEventListener("keypress", this._onScriptsKeyPress, false);
|
||||
|
||||
this.empty();
|
||||
this._scripts = null;
|
||||
this._searchbox = null;
|
||||
this._searchboxPanel = null;
|
||||
}
|
||||
};
|
||||
|
||||
@ -1384,26 +1558,27 @@ function StackFramesView() {
|
||||
|
||||
StackFramesView.prototype = {
|
||||
|
||||
/**
|
||||
* Sets the current frames state based on the debugger active thread state.
|
||||
*
|
||||
* @param string aState
|
||||
* Either "paused" or "attached".
|
||||
*/
|
||||
updateState: function DVF_updateState(aState) {
|
||||
let resume = document.getElementById("resume");
|
||||
/**
|
||||
* Sets the current frames state based on the debugger active thread state.
|
||||
*
|
||||
* @param string aState
|
||||
* Either "paused" or "attached".
|
||||
*/
|
||||
updateState: function DVF_updateState(aState) {
|
||||
let resume = DebuggerView._resumeButton;
|
||||
let resumeKey = LayoutHelpers.prettyKey(DebuggerView._resumeKey);
|
||||
|
||||
// If we're paused, show a pause label and a resume label on the button.
|
||||
if (aState == "paused") {
|
||||
resume.setAttribute("tooltiptext", L10N.getStr("resumeTooltip"));
|
||||
resume.setAttribute("checked", true);
|
||||
}
|
||||
// If we're attached, do the opposite.
|
||||
else if (aState == "attached") {
|
||||
resume.setAttribute("tooltiptext", L10N.getStr("pauseTooltip"));
|
||||
resume.removeAttribute("checked");
|
||||
}
|
||||
},
|
||||
// If we're paused, show a pause label and a resume label on the button.
|
||||
if (aState == "paused") {
|
||||
resume.setAttribute("tooltiptext", L10N.getFormatStr("resumeButtonTooltip", [resumeKey]));
|
||||
resume.setAttribute("checked", true);
|
||||
}
|
||||
// If we're attached, do the opposite.
|
||||
else if (aState == "attached") {
|
||||
resume.setAttribute("tooltiptext", L10N.getFormatStr("pauseButtonTooltip", [resumeKey]));
|
||||
resume.removeAttribute("checked");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes all elements from the stackframes container, leaving it empty.
|
||||
@ -1638,11 +1813,11 @@ StackFramesView.prototype = {
|
||||
initialize: function DVF_initialize() {
|
||||
let close = document.getElementById("close");
|
||||
let pauseOnExceptions = document.getElementById("pause-exceptions");
|
||||
let resume = document.getElementById("resume");
|
||||
let stepOver = document.getElementById("step-over");
|
||||
let stepIn = document.getElementById("step-in");
|
||||
let stepOut = document.getElementById("step-out");
|
||||
let frames = document.getElementById("stackframes");
|
||||
let resume = DebuggerView._resumeButton;
|
||||
let stepOver = DebuggerView._stepOverButton;
|
||||
let stepIn = DebuggerView._stepInButton;
|
||||
let stepOut = DebuggerView._stepOutButton;
|
||||
let frames = DebuggerView._stackframes;
|
||||
|
||||
close.addEventListener("click", this._onCloseButtonClick, false);
|
||||
pauseOnExceptions.checked = DebuggerController.StackFrames.pauseOnExceptions;
|
||||
@ -1665,11 +1840,11 @@ StackFramesView.prototype = {
|
||||
destroy: function DVF_destroy() {
|
||||
let close = document.getElementById("close");
|
||||
let pauseOnExceptions = document.getElementById("pause-exceptions");
|
||||
let resume = document.getElementById("resume");
|
||||
let stepOver = document.getElementById("step-over");
|
||||
let stepIn = document.getElementById("step-in");
|
||||
let stepOut = document.getElementById("step-out");
|
||||
let frames = this._frames;
|
||||
let resume = DebuggerView._resumeButton;
|
||||
let stepOver = DebuggerView._stepOverButton;
|
||||
let stepIn = DebuggerView._stepInButton;
|
||||
let stepOut = DebuggerView._stepOutButton;
|
||||
let frames = DebuggerView._stackframes;
|
||||
|
||||
close.removeEventListener("click", this._onCloseButtonClick, false);
|
||||
pauseOnExceptions.removeEventListener("click", this._onPauseExceptionsClick, false);
|
||||
@ -2208,7 +2383,7 @@ BreakpointsView.prototype = {
|
||||
* Initialization function, called when the debugger is initialized.
|
||||
*/
|
||||
initialize: function DVB_initialize() {
|
||||
let breakpoints = document.getElementById("breakpoints");
|
||||
let breakpoints = DebuggerView._breakpoints;
|
||||
breakpoints.addEventListener("click", this._onBreakpointClick, false);
|
||||
|
||||
this._breakpoints = breakpoints;
|
||||
@ -3314,7 +3489,7 @@ PropertiesView.prototype = {
|
||||
* Initialization function, called when the debugger is initialized.
|
||||
*/
|
||||
initialize: function DVP_initialize() {
|
||||
this._vars = document.getElementById("variables");
|
||||
this._vars = DebuggerView._variables;
|
||||
|
||||
this.emptyText();
|
||||
this.createHierarchyStore();
|
||||
|
@ -37,23 +37,23 @@
|
||||
<commandset id="sourceEditorCommands"/>
|
||||
<keyset id="sourceEditorKeys"/>
|
||||
<keyset id="scriptSearchKeys">
|
||||
<key key="P" modifiers="access shift"
|
||||
oncommand="DebuggerView.Scripts._onSearch()"/>
|
||||
<key key="G" modifiers="access shift"
|
||||
<key id="fileSearchKey" key="P" modifiers="access shift"
|
||||
oncommand="DebuggerView.Scripts._onFileSearch()"/>
|
||||
<key id="lineSearchKey" key="G" modifiers="access shift"
|
||||
oncommand="DebuggerView.Scripts._onLineSearch()"/>
|
||||
<key key="T" modifiers="access shift"
|
||||
<key id="tokenSearchKey" key="T" modifiers="access shift"
|
||||
oncommand="DebuggerView.Scripts._onTokenSearch()"/>
|
||||
<key key="F" modifiers="access shift"
|
||||
<key id="globalSearchKey" key="F" modifiers="access shift"
|
||||
oncommand="DebuggerView.Scripts._onGlobalSearch()"/>
|
||||
</keyset>
|
||||
<keyset id="threadStateKeys">
|
||||
<key keycode="VK_F6"
|
||||
<key id="resumeKey" keycode="VK_F6"
|
||||
oncommand="DebuggerView.StackFrames._onResume()"/>
|
||||
<key keycode="VK_F7"
|
||||
<key id="stepOverKey" keycode="VK_F7"
|
||||
oncommand="DebuggerView.StackFrames._onStepOver()"/>
|
||||
<key keycode="VK_F8"
|
||||
<key id="stepInKey" keycode="VK_F8"
|
||||
oncommand="DebuggerView.StackFrames._onStepIn()"/>
|
||||
<key keycode="VK_F8" modifiers="shift"
|
||||
<key id="stepOutKey" keycode="VK_F8" modifiers="shift"
|
||||
oncommand="DebuggerView.StackFrames._onStepOut()"/>
|
||||
</keyset>
|
||||
|
||||
@ -74,23 +74,19 @@
|
||||
tabindex="0"/>
|
||||
<toolbarbutton id="step-over"
|
||||
class="devtools-toolbarbutton"
|
||||
tooltiptext="&debuggerUI.stepOverButton.tooltip;"
|
||||
tabindex="0"/>
|
||||
<toolbarbutton id="step-in"
|
||||
class="devtools-toolbarbutton"
|
||||
tooltiptext="&debuggerUI.stepInButton.tooltip;"
|
||||
tabindex="0"/>
|
||||
<toolbarbutton id="step-out"
|
||||
class="devtools-toolbarbutton"
|
||||
tooltiptext="&debuggerUI.stepOutButton.tooltip;"
|
||||
tabindex="0"/>
|
||||
</hbox>
|
||||
<menulist id="scripts" class="devtools-menulist"
|
||||
sizetopopup="always"
|
||||
label="&debuggerUI.emptyScriptText;"/>
|
||||
<textbox id="scripts-search" type="search"
|
||||
class="devtools-searchinput"
|
||||
emptytext="&debuggerUI.emptyFilterText;"/>
|
||||
class="devtools-searchinput"/>
|
||||
<checkbox id="pause-exceptions"
|
||||
type="checkbox"
|
||||
tabindex="0"
|
||||
@ -102,8 +98,31 @@
|
||||
class="devtools-closebutton"/>
|
||||
#endif
|
||||
</toolbar>
|
||||
<panel id="scripts-search-panel"
|
||||
type="arrow"
|
||||
noautofocus="true"
|
||||
position="before_start">
|
||||
<vbox>
|
||||
<label class="description" value="&debuggerUI.searchPanelTitle;"/>
|
||||
<hbox align="center">
|
||||
<button id="global-operator-button" class="operator"
|
||||
onclick="DebuggerView.Scripts._onGlobalSearch()"/>
|
||||
<label id="global-operator-label" class="plain operator"/>
|
||||
</hbox>
|
||||
<hbox align="center">
|
||||
<button id="token-operator-button" class="operator"
|
||||
onclick="DebuggerView.Scripts._onTokenSearch()"/>
|
||||
<label id="token-operator-label" class="plain operator"/>
|
||||
</hbox>
|
||||
<hbox align="center">
|
||||
<button id="line-operator-button" class="operator"
|
||||
onclick="DebuggerView.Scripts._onLineSearch()"/>
|
||||
<label id="line-operator-label" class="plain operator"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</panel>
|
||||
<vbox id="dbg-content" flex="1">
|
||||
<vbox id="globalsearch" hidden="true" flex="1"/>
|
||||
<vbox id="globalsearch" hidden="true"/>
|
||||
<splitter id="globalsearch-splitter"
|
||||
class="devtools-horizontal-splitter" hidden="true"/>
|
||||
<hbox flex="1">
|
||||
|
@ -56,6 +56,8 @@ MOCHITEST_BROWSER_TESTS = \
|
||||
browser_dbg_scripts-searching-05.js \
|
||||
browser_dbg_scripts-searching-06.js \
|
||||
browser_dbg_scripts-searching-07.js \
|
||||
browser_dbg_scripts-searching-08.js \
|
||||
browser_dbg_scripts-searching-popup.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) \
|
||||
|
@ -70,6 +70,8 @@ function test()
|
||||
|
||||
isnot(editor.getText().indexOf("debugger"), -1,
|
||||
"The correct script was loaded initially.");
|
||||
isnot(editor.getText().indexOf("\u263a"), -1,
|
||||
"Unicode characters are converted correctly.");
|
||||
|
||||
contextMenu = gDebugger.document.getElementById("sourceEditorContextMenu");
|
||||
ok(contextMenu, "source editor context menupopup");
|
||||
|
@ -16,9 +16,7 @@ function test() {
|
||||
ok(pane, "toggleDebugger() should return a pane.");
|
||||
let frame = pane._frame;
|
||||
|
||||
frame.addEventListener("Debugger:Loaded", function dbgLoaded() {
|
||||
frame.removeEventListener("Debugger:Loaded", dbgLoaded, true);
|
||||
|
||||
wait_for_connect_and_resume(function() {
|
||||
let cmd = document.getElementById("Tools:Debugger");
|
||||
is(cmd.getAttribute("checked"), "true", "<command Tools:Debugger> is checked.");
|
||||
|
||||
@ -33,10 +31,10 @@ function test() {
|
||||
let pane = DebuggerUI.toggleDebugger();
|
||||
|
||||
is(cmd.getAttribute("checked"), "false", "<command Tools:Debugger> is unchecked once closed.");
|
||||
}, true);
|
||||
});
|
||||
|
||||
frame.addEventListener("Debugger:Unloaded", function dbgUnloaded() {
|
||||
frame.removeEventListener("Debugger:Unloaded", dbgUnloaded, true);
|
||||
window.addEventListener("Debugger:Shutdown", function dbgShutdown() {
|
||||
window.removeEventListener("Debugger:Shutdown", dbgShutdown, true);
|
||||
removeTab(tab1);
|
||||
removeTab(tab2);
|
||||
|
||||
@ -45,4 +43,3 @@ function test() {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -20,14 +20,11 @@ function test() {
|
||||
is(DebuggerUI.getDebugger(), pane,
|
||||
"getDebugger() should return the same pane as toggleDebugger().");
|
||||
|
||||
let frame = pane._frame;
|
||||
let content = pane.contentWindow;
|
||||
let stackframes;
|
||||
let variables;
|
||||
|
||||
frame.addEventListener("Debugger:Loaded", function dbgLoaded() {
|
||||
frame.removeEventListener("Debugger:Loaded", dbgLoaded, true);
|
||||
|
||||
wait_for_connect_and_resume(function() {
|
||||
ok(content.Prefs.stackframesWidth,
|
||||
"The debugger preferences should have a saved stackframesWidth value.");
|
||||
ok(content.Prefs.variablesWidth,
|
||||
@ -45,11 +42,10 @@ function test() {
|
||||
variables.setAttribute("width", someWidth2);
|
||||
|
||||
removeTab(tab1);
|
||||
});
|
||||
|
||||
}, true);
|
||||
|
||||
frame.addEventListener("Debugger:Unloaded", function dbgUnloaded() {
|
||||
frame.removeEventListener("Debugger:Unloaded", dbgUnloaded, true);
|
||||
window.addEventListener("Debugger:Shutdown", function dbgShutdown() {
|
||||
window.removeEventListener("Debugger:Shutdown", dbgShutdown, true);
|
||||
|
||||
is(content.Prefs.stackframesWidth, stackframes.getAttribute("width"),
|
||||
"The stackframes pane width should have been saved by now.");
|
||||
|
@ -7,12 +7,18 @@
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebugger = null;
|
||||
var gView = null;
|
||||
var gLH = null;
|
||||
var gL10N = null;
|
||||
|
||||
function test() {
|
||||
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.contentWindow;
|
||||
gView = gDebugger.DebuggerView;
|
||||
gLH = gDebugger.LayoutHelpers;
|
||||
gL10N = gDebugger.L10N;
|
||||
|
||||
testPause();
|
||||
});
|
||||
@ -23,7 +29,8 @@ function testPause() {
|
||||
"Should be running after debug_tab_pane.");
|
||||
|
||||
let button = gDebugger.document.getElementById("resume");
|
||||
is(button.getAttribute("tooltiptext"), gDebugger.L10N.getStr("pauseTooltip"),
|
||||
is(button.getAttribute("tooltiptext"),
|
||||
gL10N.getFormatStr("pauseButtonTooltip", [gLH.prettyKey(gView._resumeKey)]),
|
||||
"Button tooltip should be pause when running.");
|
||||
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("paused", function() {
|
||||
@ -35,7 +42,8 @@ function testPause() {
|
||||
is(gDebugger.DebuggerController.activeThread.paused, true,
|
||||
"Should be paused after an interrupt request.");
|
||||
|
||||
is(button.getAttribute("tooltiptext"), gDebugger.L10N.getStr("resumeTooltip"),
|
||||
is(button.getAttribute("tooltiptext"),
|
||||
gL10N.getFormatStr("resumeButtonTooltip", [gLH.prettyKey(gView._resumeKey)]),
|
||||
"Button tooltip should be resume when paused.");
|
||||
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
|
||||
@ -58,7 +66,8 @@ function testResume() {
|
||||
"Should be paused after an interrupt request.");
|
||||
|
||||
let button = gDebugger.document.getElementById("resume");
|
||||
is(button.getAttribute("tooltiptext"), gDebugger.L10N.getStr("pauseTooltip"),
|
||||
is(button.getAttribute("tooltiptext"),
|
||||
gL10N.getFormatStr("pauseButtonTooltip", [gLH.prettyKey(gView._resumeKey)]),
|
||||
"Button tooltip should be pause when running.");
|
||||
|
||||
closeDebuggerAndFinish();
|
||||
@ -74,4 +83,8 @@ registerCleanupFunction(function() {
|
||||
removeTab(gTab);
|
||||
gPane = null;
|
||||
gTab = null;
|
||||
gDebugger = null;
|
||||
gView = null;
|
||||
gLH = null;
|
||||
gL10N = null;
|
||||
});
|
||||
|
@ -11,6 +11,10 @@ var gScripts = null;
|
||||
var gSearchBox = null;
|
||||
var gMenulist = null;
|
||||
|
||||
/**
|
||||
* Tests basic functionality of scripts filtering (token search and line jump).
|
||||
*/
|
||||
|
||||
function test()
|
||||
{
|
||||
let scriptShown = false;
|
||||
@ -64,26 +68,31 @@ function testScriptSearching() {
|
||||
gEditor.getCaretPosition().col == 44 + token.length,
|
||||
"The editor didn't jump to the correct token. (1)");
|
||||
|
||||
EventUtils.sendKey("RETURN");
|
||||
EventUtils.sendKey("DOWN");
|
||||
ok(gEditor.getCaretPosition().line == 8 &&
|
||||
gEditor.getCaretPosition().col == 2 + token.length,
|
||||
"The editor didn't jump to the correct token. (2)");
|
||||
|
||||
EventUtils.sendKey("ENTER");
|
||||
EventUtils.sendKey("DOWN");
|
||||
ok(gEditor.getCaretPosition().line == 12 &&
|
||||
gEditor.getCaretPosition().col == 8 + token.length,
|
||||
"The editor didn't jump to the correct token. (3)");
|
||||
|
||||
EventUtils.sendKey("ENTER");
|
||||
EventUtils.sendKey("RETURN");
|
||||
ok(gEditor.getCaretPosition().line == 19 &&
|
||||
gEditor.getCaretPosition().col == 4 + token.length,
|
||||
"The editor didn't jump to the correct token. (4)");
|
||||
|
||||
EventUtils.sendKey("RETURN");
|
||||
EventUtils.sendKey("ENTER");
|
||||
ok(gEditor.getCaretPosition().line == 2 &&
|
||||
gEditor.getCaretPosition().col == 44 + token.length,
|
||||
"The editor didn't jump to the correct token. (5)");
|
||||
|
||||
EventUtils.sendKey("UP");
|
||||
ok(gEditor.getCaretPosition().line == 19 &&
|
||||
gEditor.getCaretPosition().col == 4 + token.length,
|
||||
"The editor didn't jump to the correct token. (5.1)");
|
||||
|
||||
|
||||
token = "debugger;";
|
||||
write(":bogus#" + token);
|
||||
@ -152,12 +161,12 @@ function testScriptSearching() {
|
||||
"The editor didn't jump to the correct token. (14)");
|
||||
|
||||
|
||||
EventUtils.sendKey("RETURN");
|
||||
EventUtils.sendKey("DOWN");
|
||||
ok(gEditor.getCaretPosition().line == 8 &&
|
||||
gEditor.getCaretPosition().col == 2 + token.length,
|
||||
"The editor didn't jump to the correct token. (15)");
|
||||
|
||||
EventUtils.sendKey("ENTER");
|
||||
EventUtils.sendKey("DOWN");
|
||||
ok(gEditor.getCaretPosition().line == 12 &&
|
||||
gEditor.getCaretPosition().col == 8 + token.length,
|
||||
"The editor didn't jump to the correct token. (16)");
|
||||
@ -172,10 +181,15 @@ function testScriptSearching() {
|
||||
gEditor.getCaretPosition().col == 44 + token.length,
|
||||
"The editor didn't jump to the correct token. (18)");
|
||||
|
||||
EventUtils.sendKey("UP");
|
||||
ok(gEditor.getCaretPosition().line == 19 &&
|
||||
gEditor.getCaretPosition().col == 4 + token.length,
|
||||
"The editor didn't jump to the correct token. (18.1)");
|
||||
|
||||
|
||||
clear();
|
||||
ok(gEditor.getCaretPosition().line == 2 &&
|
||||
gEditor.getCaretPosition().col == 44 + token.length,
|
||||
ok(gEditor.getCaretPosition().line == 19 &&
|
||||
gEditor.getCaretPosition().col == 4 + token.length,
|
||||
"The editor didn't remain at the correct token. (19)");
|
||||
is(gScripts.visibleItemsCount, 1,
|
||||
"Not all the scripts are shown after the search. (20)");
|
||||
|
@ -4,6 +4,10 @@
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
|
||||
|
||||
/**
|
||||
* Tests basic functionality of scripts filtering (file search).
|
||||
*/
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
|
@ -4,6 +4,11 @@
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
|
||||
|
||||
/**
|
||||
* Tests basic functionality of global search (lowercase + upper case, expected
|
||||
* UI behavior, number of results found etc.)
|
||||
*/
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
@ -322,5 +327,6 @@ registerCleanupFunction(function() {
|
||||
gDebugger = null;
|
||||
gEditor = null;
|
||||
gScripts = null;
|
||||
gSearchView = null;
|
||||
gSearchBox = null;
|
||||
});
|
||||
|
@ -4,6 +4,11 @@
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
|
||||
|
||||
/**
|
||||
* Tests if the global search results switch back and forth, and wrap around
|
||||
* when switching between them.
|
||||
*/
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
@ -124,7 +129,7 @@ function doFirstJump() {
|
||||
}
|
||||
});
|
||||
executeSoon(function() {
|
||||
EventUtils.sendKey("ENTER");
|
||||
EventUtils.sendKey("DOWN");
|
||||
});
|
||||
}
|
||||
|
||||
@ -151,7 +156,7 @@ function doSecondJump() {
|
||||
}
|
||||
});
|
||||
executeSoon(function() {
|
||||
EventUtils.sendKey("ENTER");
|
||||
EventUtils.sendKey("RETURN");
|
||||
});
|
||||
}
|
||||
|
||||
@ -171,7 +176,7 @@ function doWrapAroundJump() {
|
||||
is(gScripts.visibleItemsCount, 2,
|
||||
"Not all the correct scripts are shown after the search. (3)");
|
||||
|
||||
testSearchTokenEmpty();
|
||||
doBackwardsWrapAroundJump();
|
||||
});
|
||||
} else {
|
||||
ok(false, "We jumped in a bowl of hot lava (aka WRONG MATCH). That was bad for us.");
|
||||
@ -182,6 +187,33 @@ function doWrapAroundJump() {
|
||||
});
|
||||
}
|
||||
|
||||
function doBackwardsWrapAroundJump() {
|
||||
window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) {
|
||||
window.removeEventListener(aEvent.type, _onEvent);
|
||||
info("Current script url:\n" + aEvent.detail.url + "\n");
|
||||
info("Debugger editor text:\n" + gEditor.getText() + "\n");
|
||||
|
||||
let url = aEvent.detail.url;
|
||||
if (url.indexOf("-02.js") != -1) {
|
||||
executeSoon(function() {
|
||||
info("Editor caret position: " + gEditor.getCaretPosition().toSource() + "\n");
|
||||
ok(gEditor.getCaretPosition().line == 5 &&
|
||||
gEditor.getCaretPosition().col == 6,
|
||||
"The editor didn't jump to the correct line. (4)");
|
||||
is(gScripts.visibleItemsCount, 2,
|
||||
"Not all the correct scripts are shown after the search. (4)");
|
||||
|
||||
testSearchTokenEmpty();
|
||||
});
|
||||
} else {
|
||||
ok(false, "We jumped in a bowl of hot lava (aka WRONG MATCH). That was bad for us.");
|
||||
}
|
||||
});
|
||||
executeSoon(function() {
|
||||
EventUtils.sendKey("UP");
|
||||
});
|
||||
}
|
||||
|
||||
function testSearchTokenEmpty() {
|
||||
window.addEventListener("Debugger:GlobalSearch:TokenEmpty", function _onEvent(aEvent) {
|
||||
window.removeEventListener(aEvent.type, _onEvent);
|
||||
@ -189,14 +221,14 @@ function testSearchTokenEmpty() {
|
||||
info("Debugger editor text:\n" + gEditor.getText() + "\n");
|
||||
|
||||
let url = gScripts.selected;
|
||||
if (url.indexOf("-01.js") != -1) {
|
||||
if (url.indexOf("-02.js") != -1) {
|
||||
executeSoon(function() {
|
||||
info("Editor caret position: " + gEditor.getCaretPosition().toSource() + "\n");
|
||||
ok(gEditor.getCaretPosition().line == 4 &&
|
||||
ok(gEditor.getCaretPosition().line == 5 &&
|
||||
gEditor.getCaretPosition().col == 6,
|
||||
"The editor didn't remain at the correct line. (4)");
|
||||
"The editor didn't remain at the correct line. (5)");
|
||||
is(gScripts.visibleItemsCount, 2,
|
||||
"Not all the correct scripts are shown after the search. (4)");
|
||||
"Not all the correct scripts are shown after the search. (5)");
|
||||
|
||||
is(gSearchView._pane.childNodes.length, 0,
|
||||
"The global search pane shouldn't have any child nodes after clear().");
|
||||
@ -247,5 +279,6 @@ registerCleanupFunction(function() {
|
||||
gDebugger = null;
|
||||
gEditor = null;
|
||||
gScripts = null;
|
||||
gSearchView = null;
|
||||
gSearchBox = null;
|
||||
});
|
||||
|
@ -4,6 +4,11 @@
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
|
||||
|
||||
/**
|
||||
* Tests if the global search results are cleared on location changes, and
|
||||
* the expected UI behaviors are triggered.
|
||||
*/
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
@ -166,5 +171,6 @@ registerCleanupFunction(function() {
|
||||
gDebugger = null;
|
||||
gEditor = null;
|
||||
gScripts = null;
|
||||
gSearchView = null;
|
||||
gSearchBox = null;
|
||||
});
|
||||
|
@ -4,6 +4,11 @@
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
|
||||
|
||||
/**
|
||||
* Tests if the global search results trigger MatchFound and NoMatchFound events
|
||||
* properly, and triggers the expected UI behavior.
|
||||
*/
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
@ -139,5 +144,6 @@ registerCleanupFunction(function() {
|
||||
gDebugger = null;
|
||||
gEditor = null;
|
||||
gScripts = null;
|
||||
gSearchView = null;
|
||||
gSearchBox = null;
|
||||
});
|
||||
|
@ -4,6 +4,12 @@
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
|
||||
|
||||
/**
|
||||
* Tests if the global search results are expanded on scroll or click, and
|
||||
* clicking matches makes the source editor shows the correct script and
|
||||
* makes a selection based on the match.
|
||||
*/
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
@ -243,5 +249,6 @@ registerCleanupFunction(function() {
|
||||
gDebugger = null;
|
||||
gEditor = null;
|
||||
gScripts = null;
|
||||
gSearchView = null;
|
||||
gSearchBox = null;
|
||||
});
|
||||
|
@ -0,0 +1,209 @@
|
||||
/* 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";
|
||||
|
||||
/**
|
||||
* Tests if the global search results are hidden when they're supposed to
|
||||
* (after a focus lost, or when ESCAPE is pressed).
|
||||
*/
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
var gEditor = null;
|
||||
var gScripts = null;
|
||||
var gSearchView = null;
|
||||
var gSearchBox = 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.contentWindow;
|
||||
|
||||
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;
|
||||
gSearchView = gDebugger.DebuggerView.GlobalSearch;
|
||||
gSearchBox = gScripts._searchbox;
|
||||
|
||||
doSearch();
|
||||
});
|
||||
}
|
||||
|
||||
function doSearch() {
|
||||
is(gSearchView._pane.hidden, true,
|
||||
"The global search pane shouldn't be visible yet.");
|
||||
|
||||
window.addEventListener("Debugger:GlobalSearch:MatchFound", function _onEvent(aEvent) {
|
||||
window.removeEventListener(aEvent.type, _onEvent);
|
||||
info("Current script url:\n" + gScripts.selected + "\n");
|
||||
info("Debugger editor text:\n" + gEditor.getText() + "\n");
|
||||
|
||||
let url = gScripts.selected;
|
||||
if (url.indexOf("-02.js") != -1) {
|
||||
executeSoon(function() {
|
||||
testFocusLost();
|
||||
});
|
||||
} else {
|
||||
ok(false, "The current script shouldn't have changed after a global search.");
|
||||
}
|
||||
});
|
||||
executeSoon(function() {
|
||||
write("!a");
|
||||
});
|
||||
}
|
||||
|
||||
function testFocusLost()
|
||||
{
|
||||
is(gSearchView._pane.hidden, false,
|
||||
"The global search pane should be visible after a search.");
|
||||
|
||||
window.addEventListener("Debugger:GlobalSearch:ViewCleared", function _onEvent(aEvent) {
|
||||
window.removeEventListener(aEvent.type, _onEvent);
|
||||
info("Current script url:\n" + gScripts.selected + "\n");
|
||||
info("Debugger editor text:\n" + gEditor.getText() + "\n");
|
||||
|
||||
let url = gScripts.selected;
|
||||
if (url.indexOf("-02.js") != -1) {
|
||||
executeSoon(function() {
|
||||
reshowSearch();
|
||||
});
|
||||
} else {
|
||||
ok(false, "The current script shouldn't have changed after the global search stopped.");
|
||||
}
|
||||
});
|
||||
executeSoon(function() {
|
||||
gDebugger.DebuggerView.editor.focus();
|
||||
});
|
||||
}
|
||||
|
||||
function reshowSearch() {
|
||||
is(gSearchView._pane.hidden, true,
|
||||
"The global search pane shouldn't be visible after the search was stopped.");
|
||||
|
||||
window.addEventListener("Debugger:GlobalSearch:MatchFound", function _onEvent(aEvent) {
|
||||
window.removeEventListener(aEvent.type, _onEvent);
|
||||
info("Current script url:\n" + gScripts.selected + "\n");
|
||||
info("Debugger editor text:\n" + gEditor.getText() + "\n");
|
||||
|
||||
let url = gScripts.selected;
|
||||
if (url.indexOf("-02.js") != -1) {
|
||||
executeSoon(function() {
|
||||
testEscape();
|
||||
});
|
||||
} else {
|
||||
ok(false, "The current script shouldn't have changed after a global re-search.");
|
||||
}
|
||||
});
|
||||
executeSoon(function() {
|
||||
sendEnter();
|
||||
});
|
||||
}
|
||||
|
||||
function testEscape()
|
||||
{
|
||||
is(gSearchView._pane.hidden, false,
|
||||
"The global search pane should be visible after a re-search.");
|
||||
|
||||
window.addEventListener("Debugger:GlobalSearch:ViewCleared", function _onEvent(aEvent) {
|
||||
window.removeEventListener(aEvent.type, _onEvent);
|
||||
info("Current script url:\n" + gScripts.selected + "\n");
|
||||
info("Debugger editor text:\n" + gEditor.getText() + "\n");
|
||||
|
||||
let url = gScripts.selected;
|
||||
if (url.indexOf("-02.js") != -1) {
|
||||
executeSoon(function() {
|
||||
finalCheck();
|
||||
});
|
||||
} else {
|
||||
ok(false, "The current script shouldn't have changed after the global search escaped.");
|
||||
}
|
||||
});
|
||||
executeSoon(function() {
|
||||
sendEscape();
|
||||
});
|
||||
}
|
||||
|
||||
function finalCheck()
|
||||
{
|
||||
is(gSearchView._pane.hidden, true,
|
||||
"The global search pane shouldn't be visible after the search was escaped.");
|
||||
|
||||
closeDebuggerAndFinish();
|
||||
}
|
||||
|
||||
function clear() {
|
||||
gSearchBox.focus();
|
||||
gSearchBox.value = "";
|
||||
}
|
||||
|
||||
function write(text) {
|
||||
clear();
|
||||
append(text);
|
||||
}
|
||||
|
||||
function sendEnter() {
|
||||
gSearchBox.focus();
|
||||
EventUtils.sendKey("ENTER");
|
||||
}
|
||||
|
||||
function sendEscape() {
|
||||
gSearchBox.focus();
|
||||
EventUtils.sendKey("ESCAPE");
|
||||
}
|
||||
|
||||
function append(text) {
|
||||
gSearchBox.focus();
|
||||
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
EventUtils.sendChar(text[i]);
|
||||
}
|
||||
info("Editor caret position: " + gEditor.getCaretPosition().toSource() + "\n");
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
removeTab(gTab);
|
||||
gPane = null;
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gDebugger = null;
|
||||
gEditor = null;
|
||||
gScripts = null;
|
||||
gSearchView = null;
|
||||
gSearchBox = null;
|
||||
});
|
@ -0,0 +1,62 @@
|
||||
/* 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 gScripts = null;
|
||||
var gSearchBox = null;
|
||||
var gSearchBoxPanel = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.contentWindow;
|
||||
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
runTest();
|
||||
});
|
||||
|
||||
gDebuggee.firstCall();
|
||||
});
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
gScripts = gDebugger.DebuggerView.Scripts;
|
||||
gSearchBox = gScripts._searchbox;
|
||||
gSearchBoxPanel = gScripts._searchboxPanel;
|
||||
|
||||
focusSearchbox();
|
||||
}
|
||||
|
||||
function focusSearchbox() {
|
||||
is(gSearchBoxPanel.state, "closed",
|
||||
"The search box panel shouldn't be visible yet.");
|
||||
|
||||
gSearchBoxPanel.addEventListener("popupshown", function _onEvent(aEvent) {
|
||||
gSearchBoxPanel.removeEventListener(aEvent.type, _onEvent);
|
||||
is(gSearchBoxPanel.state, "open",
|
||||
"The search box panel should be visible after searching started.");
|
||||
|
||||
closeDebuggerAndFinish();
|
||||
});
|
||||
EventUtils.sendMouseEvent({ type: "click" }, gSearchBox);
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
removeTab(gTab);
|
||||
gPane = null;
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gDebugger = null;
|
||||
gScripts = null;
|
||||
gSearchBox = null;
|
||||
gSearchBoxPanel = null;
|
||||
});
|
@ -2,6 +2,6 @@
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function secondCall() {
|
||||
// This comment is useful for browser_dbg_select-line.js.
|
||||
// This comment is useful for browser_dbg_select-line.js. ☺
|
||||
eval("debugger;");
|
||||
}
|
||||
|
@ -220,10 +220,6 @@ Highlighter.prototype = {
|
||||
|
||||
this.invalidateSize(!!aScroll);
|
||||
|
||||
if (this._highlighting) {
|
||||
this.showOutline();
|
||||
}
|
||||
|
||||
if (oldNode !== this.node) {
|
||||
this.emitEvent("nodeselected");
|
||||
}
|
||||
@ -263,6 +259,7 @@ Highlighter.prototype = {
|
||||
this.moveInfobar();
|
||||
|
||||
if (this._highlighting) {
|
||||
this.showOutline();
|
||||
this.emitEvent("highlighting");
|
||||
}
|
||||
},
|
||||
|
@ -18,6 +18,7 @@ Cu.import("resource:///modules/devtools/MarkupView.jsm");
|
||||
Cu.import("resource:///modules/highlighter.jsm");
|
||||
Cu.import("resource:///modules/devtools/LayoutView.jsm");
|
||||
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
|
||||
Cu.import("resource:///modules/devtools/EventEmitter.jsm");
|
||||
|
||||
// Inspector notifications dispatched through the nsIObserverService.
|
||||
const INSPECTOR_NOTIFICATIONS = {
|
||||
@ -67,7 +68,7 @@ function Inspector(aIUI)
|
||||
this._IUI = aIUI;
|
||||
this._winID = aIUI.winID;
|
||||
this._browser = aIUI.browser;
|
||||
this._listeners = {};
|
||||
this._eventEmitter = new EventEmitter();
|
||||
|
||||
this._browser.addEventListener("resize", this, true);
|
||||
|
||||
@ -147,7 +148,7 @@ Inspector.prototype = {
|
||||
this._destroyMarkup();
|
||||
this._browser.removeEventListener("resize", this, true);
|
||||
delete this._IUI;
|
||||
delete this._listeners;
|
||||
delete this._eventEmitter;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -284,7 +285,7 @@ Inspector.prototype = {
|
||||
this._markupBox.removeAttribute("hidden");
|
||||
|
||||
this.markup = new MarkupView(this, this._markupFrame);
|
||||
this._emit("markuploaded");
|
||||
this.emit("markuploaded");
|
||||
},
|
||||
|
||||
_destroyMarkup: function Inspector__destroyMarkup()
|
||||
@ -348,8 +349,7 @@ Inspector.prototype = {
|
||||
delete this._frozen;
|
||||
},
|
||||
|
||||
/// Event stuff. Would like to refactor this eventually.
|
||||
/// Emulates the jetpack event source, which has a nice API.
|
||||
/// Forward the events related calls to the event emitter.
|
||||
|
||||
/**
|
||||
* Connect a listener to this object.
|
||||
@ -361,10 +361,7 @@ Inspector.prototype = {
|
||||
*/
|
||||
on: function Inspector_on(aEvent, aListener)
|
||||
{
|
||||
if (!(aEvent in this._listeners)) {
|
||||
this._listeners[aEvent] = [];
|
||||
}
|
||||
this._listeners[aEvent].push(aListener);
|
||||
this._eventEmitter.on(aEvent, aListener);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -377,11 +374,7 @@ Inspector.prototype = {
|
||||
*/
|
||||
once: function Inspector_once(aEvent, aListener)
|
||||
{
|
||||
let handler = function() {
|
||||
this.removeListener(aEvent, handler);
|
||||
aListener();
|
||||
}.bind(this);
|
||||
this.on(aEvent, handler);
|
||||
this._eventEmitter.once(aEvent, aListener);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -393,35 +386,18 @@ Inspector.prototype = {
|
||||
* @param function aListener
|
||||
* The listener to remove.
|
||||
*/
|
||||
removeListener: function Inspector_removeListener(aEvent, aListener)
|
||||
off: function Inspector_removeListener(aEvent, aListener)
|
||||
{
|
||||
this._listeners[aEvent] = this._listeners[aEvent].filter(function(l) aListener != l);
|
||||
this._eventEmitter.off(aEvent, aListener);
|
||||
},
|
||||
|
||||
/**
|
||||
* Emit an event on the inspector. All arguments to this method will
|
||||
* be sent to listner functions.
|
||||
*/
|
||||
_emit: function Inspector__emit(aEvent)
|
||||
emit: function Inspector_emit()
|
||||
{
|
||||
if (!(aEvent in this._listeners))
|
||||
return;
|
||||
|
||||
let originalListeners = this._listeners[aEvent];
|
||||
for (let listener of this._listeners[aEvent]) {
|
||||
// If the inspector was destroyed during event emission, stop
|
||||
// emitting.
|
||||
if (!this._listeners) {
|
||||
break;
|
||||
}
|
||||
|
||||
// If listeners were removed during emission, make sure the
|
||||
// event handler we're going to fire wasn't removed.
|
||||
if (originalListeners === this._listeners[aEvent] ||
|
||||
this._listeners[aEvent].some(function(l) l === listener)) {
|
||||
listener.apply(null, arguments);
|
||||
}
|
||||
}
|
||||
this._eventEmitter.emit.apply(this._eventEmitter, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
@ -872,13 +848,13 @@ InspectorUI.prototype = {
|
||||
this.inspecting = true;
|
||||
this.highlighter.unlock();
|
||||
this._notifySelected();
|
||||
this._currentInspector._emit("unlocked");
|
||||
this._currentInspector.emit("unlocked");
|
||||
},
|
||||
|
||||
_notifySelected: function IUI__notifySelected(aFrom)
|
||||
{
|
||||
this._currentInspector._cancelLayoutChange();
|
||||
this._currentInspector._emit("select", aFrom);
|
||||
this._currentInspector.emit("select", aFrom);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -908,7 +884,7 @@ InspectorUI.prototype = {
|
||||
|
||||
this.highlighter.lock();
|
||||
this._notifySelected();
|
||||
this._currentInspector._emit("locked");
|
||||
this._currentInspector.emit("locked");
|
||||
},
|
||||
|
||||
/**
|
||||
@ -993,7 +969,7 @@ InspectorUI.prototype = {
|
||||
this.highlighter.updateInfobar();
|
||||
this.highlighter.invalidateSize();
|
||||
this.breadcrumbs.updateSelectors();
|
||||
this._currentInspector._emit("change", aUpdater);
|
||||
this._currentInspector.emit("change", aUpdater);
|
||||
},
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
@ -1821,8 +1797,8 @@ InspectorStyleSidebar.prototype = {
|
||||
// If the current tool is already loaded, notify that we're
|
||||
// showing this sidebar.
|
||||
if (aTool.loaded) {
|
||||
this._inspector._emit("sidebaractivated", aTool.id);
|
||||
this._inspector._emit("sidebaractivated-" + aTool.id);
|
||||
this._inspector.emit("sidebaractivated", aTool.id);
|
||||
this._inspector.emit("sidebaractivated-" + aTool.id);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1841,14 +1817,14 @@ InspectorStyleSidebar.prototype = {
|
||||
aTool.loaded = true;
|
||||
aTool.context = aTool.registration.load(this._inspector, aTool.frame);
|
||||
|
||||
this._inspector._emit("sidebaractivated", aTool.id);
|
||||
this._inspector.emit("sidebaractivated", aTool.id);
|
||||
|
||||
// Send an event specific to the activation of this panel. For
|
||||
// this initial event, include a "createpanel" argument
|
||||
// to let panels watch sidebaractivated to refresh themselves
|
||||
// but ignore the one immediately after their load.
|
||||
// I don't really like this, we should find a better solution.
|
||||
this._inspector._emit("sidebaractivated-" + aTool.id, "createpanel");
|
||||
this._inspector.emit("sidebaractivated-" + aTool.id, "createpanel");
|
||||
}.bind(this);
|
||||
aTool.frame.addEventListener("load", aTool.onLoad, true);
|
||||
aTool.frame.setAttribute("src", aTool.registration.contentURL);
|
||||
|
@ -123,8 +123,8 @@ LayoutView.prototype = {
|
||||
* Destroy the nodes. Remove listeners.
|
||||
*/
|
||||
destroy: function LV_destroy() {
|
||||
this.inspector.removeListener("select", this.onSelect);
|
||||
this.inspector.removeListener("unlocked", this.onUnlock);
|
||||
this.inspector.off("select", this.onSelect);
|
||||
this.inspector.off("unlocked", this.onUnlock);
|
||||
this.browser.removeEventListener("MozAfterPaint", this.update, true);
|
||||
this.iframe.removeEventListener("keypress", this.bound_handleKeypress, true);
|
||||
this.inspector.chromeWindow.removeEventListener("message", this.onMessage, true);
|
||||
|
@ -331,7 +331,7 @@ MarkupView.prototype = {
|
||||
this._updateChildren(container);
|
||||
}
|
||||
}
|
||||
this._inspector._emit("markupmutation");
|
||||
this._inspector.emit("markupmutation");
|
||||
},
|
||||
|
||||
/**
|
||||
@ -479,7 +479,7 @@ MarkupView.prototype = {
|
||||
this._frame.removeEventListener("keydown", this._boundKeyDown, true);
|
||||
delete this._boundKeyDown;
|
||||
|
||||
this._inspector.removeListener("select", this._boundSelect);
|
||||
this._inspector.off("select", this._boundSelect);
|
||||
delete this._boundSelect;
|
||||
|
||||
delete this._elt;
|
||||
|
@ -23,10 +23,10 @@ Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource:///modules/PropertyPanel.jsm");
|
||||
Cu.import("resource:///modules/source-editor.jsm");
|
||||
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
|
||||
Cu.import("resource:///modules/devtools/scratchpad-manager.jsm");
|
||||
Cu.import("resource://gre/modules/jsdebugger.jsm");
|
||||
|
||||
|
||||
const SCRATCHPAD_CONTEXT_CONTENT = 1;
|
||||
const SCRATCHPAD_CONTEXT_BROWSER = 2;
|
||||
const SCRATCHPAD_L10N = "chrome://browser/locale/devtools/scratchpad.properties";
|
||||
@ -37,47 +37,6 @@ const BUTTON_POSITION_CANCEL = 1;
|
||||
const BUTTON_POSITION_DONT_SAVE = 2;
|
||||
const BUTTON_POSITION_REVERT=0;
|
||||
|
||||
let keysbundle = Services.strings.createBundle("chrome://global-platform/locale/platformKeys.properties");
|
||||
|
||||
|
||||
function SP_Pretty_Key(aElemKey) {
|
||||
|
||||
let elemString = "";
|
||||
let elemMod = aElemKey.getAttribute("modifiers");
|
||||
|
||||
if (elemMod.match("accel")) {
|
||||
if (navigator.platform.indexOf("Mac") !== -1) {
|
||||
// XXX bug 779642 Use "Cmd-" literal vs cloverleaf meta-key until
|
||||
// Orion adds variable height lines
|
||||
// elemString += keysbundle.GetStringFromName("VK_META_CMD") +
|
||||
// keysbundle.GetStringFromName("MODIFIER_SEPARATOR");
|
||||
elemString += "Cmd-";
|
||||
} else {
|
||||
elemString += keysbundle.GetStringFromName("VK_CONTROL") +
|
||||
keysbundle.GetStringFromName("MODIFIER_SEPARATOR");
|
||||
}
|
||||
}
|
||||
|
||||
if (elemMod.match("shift")) {
|
||||
elemString += keysbundle.GetStringFromName("VK_SHIFT") +
|
||||
keysbundle.GetStringFromName("MODIFIER_SEPARATOR");
|
||||
}
|
||||
if (elemMod.match("alt")) {
|
||||
elemString += keysbundle.GetStringFromName("VK_ALT") +
|
||||
keysbundle.GetStringFromName("MODIFIER_SEPARATOR");
|
||||
}
|
||||
if (elemMod.match("ctrl")) {
|
||||
elemString += keysbundle.GetStringFromName("VK_CONTROL") +
|
||||
keysbundle.GetStringFromName("MODIFIER_SEPARATOR");
|
||||
}
|
||||
if (elemMod.match("meta")) {
|
||||
elemString += keysbundle.GetStringFromName("VK_META") +
|
||||
keysbundle.GetStringFromName("MODIFIER_SEPARATOR");
|
||||
}
|
||||
|
||||
return elemString + aElemKey.getAttribute("key").toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* The scratchpad object handles the Scratchpad window functionality.
|
||||
*/
|
||||
@ -268,6 +227,7 @@ var Scratchpad = {
|
||||
this._contentSandbox = new Cu.Sandbox(contentWindow,
|
||||
{ sandboxPrototype: contentWindow, wantXrays: false,
|
||||
sandboxName: 'scratchpad-content'});
|
||||
this._contentSandbox.__SCRATCHPAD__ = this;
|
||||
|
||||
this._previousBrowserWindow = this.browserWindow;
|
||||
this._previousBrowser = this.gBrowser.selectedBrowser;
|
||||
@ -302,6 +262,7 @@ var Scratchpad = {
|
||||
this._chromeSandbox = new Cu.Sandbox(this.browserWindow,
|
||||
{ sandboxPrototype: this.browserWindow, wantXrays: false,
|
||||
sandboxName: 'scratchpad-chrome'});
|
||||
this._chromeSandbox.__SCRATCHPAD__ = this;
|
||||
addDebuggerToGlobal(this._chromeSandbox);
|
||||
|
||||
this._previousBrowserWindow = this.browserWindow;
|
||||
@ -450,6 +411,34 @@ var Scratchpad = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Reload the current page and execute the entire editor content when
|
||||
* the page finishes loading. Note that this operation should be available
|
||||
* only in the content context.
|
||||
*/
|
||||
reloadAndRun: function SP_reloadAndRun()
|
||||
{
|
||||
if (this.executionContext !== SCRATCHPAD_CONTEXT_CONTENT) {
|
||||
Cu.reportError(this.strings.
|
||||
GetStringFromName("scratchpadContext.invalid"));
|
||||
return;
|
||||
}
|
||||
|
||||
let browser = this.gBrowser.selectedBrowser;
|
||||
|
||||
this._reloadAndRunEvent = function onLoad(evt) {
|
||||
if (evt.target !== browser.contentDocument) {
|
||||
return;
|
||||
}
|
||||
|
||||
browser.removeEventListener("load", this._reloadAndRunEvent, true);
|
||||
this.run();
|
||||
}.bind(this);
|
||||
|
||||
browser.addEventListener("load", this._reloadAndRunEvent, true);
|
||||
browser.contentWindow.location.reload();
|
||||
},
|
||||
|
||||
/**
|
||||
* Execute the selected text (if any) or the entire editor content in the
|
||||
* current context. The evaluation result is inserted into the editor after
|
||||
@ -479,9 +468,9 @@ var Scratchpad = {
|
||||
let insertionPoint = selection.start != selection.end ?
|
||||
selection.end : // after selected text
|
||||
this.editor.getCharCount(); // after text end
|
||||
|
||||
|
||||
let newComment = "\n/*\n" + aValue + "\n*/";
|
||||
|
||||
|
||||
this.setText(newComment, insertionPoint, insertionPoint);
|
||||
|
||||
// Select the new comment.
|
||||
@ -510,7 +499,7 @@ var Scratchpad = {
|
||||
else if (aError.lineNumber) {
|
||||
stack = "@" + aError.lineNumber;
|
||||
}
|
||||
|
||||
|
||||
let newComment = "Exception: " + ( aError.message || aError) + ( stack == "" ? stack : "\n" + stack.replace(/\n$/, "") );
|
||||
|
||||
this.writeAsComment(newComment);
|
||||
@ -931,7 +920,6 @@ var Scratchpad = {
|
||||
*/
|
||||
revertFile: function SP_revertFile(aCallback)
|
||||
{
|
||||
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
file.initWithPath(this.filename);
|
||||
|
||||
@ -1019,6 +1007,7 @@ var Scratchpad = {
|
||||
|
||||
let content = document.getElementById("sp-menu-content");
|
||||
document.getElementById("sp-menu-browser").removeAttribute("checked");
|
||||
document.getElementById("sp-cmd-reloadAndRun").removeAttribute("disabled");
|
||||
content.setAttribute("checked", true);
|
||||
this.executionContext = SCRATCHPAD_CONTEXT_CONTENT;
|
||||
this.notificationBox.removeAllNotifications(false);
|
||||
@ -1035,8 +1024,12 @@ var Scratchpad = {
|
||||
}
|
||||
|
||||
let browser = document.getElementById("sp-menu-browser");
|
||||
let reloadAndRun = document.getElementById("sp-cmd-reloadAndRun");
|
||||
|
||||
document.getElementById("sp-menu-content").removeAttribute("checked");
|
||||
reloadAndRun.setAttribute("disabled", true);
|
||||
browser.setAttribute("checked", true);
|
||||
|
||||
this.executionContext = SCRATCHPAD_CONTEXT_BROWSER;
|
||||
this.notificationBox.appendNotification(
|
||||
this.strings.GetStringFromName("browserContext.notification"),
|
||||
@ -1097,9 +1090,9 @@ var Scratchpad = {
|
||||
|
||||
let initialText = this.strings.formatStringFromName(
|
||||
"scratchpadIntro1",
|
||||
[SP_Pretty_Key(document.getElementById("sp-key-run")),
|
||||
SP_Pretty_Key(document.getElementById("sp-key-inspect")),
|
||||
SP_Pretty_Key(document.getElementById("sp-key-display"))],
|
||||
[LayoutHelpers.prettyKey(document.getElementById("sp-key-run")),
|
||||
LayoutHelpers.prettyKey(document.getElementById("sp-key-inspect")),
|
||||
LayoutHelpers.prettyKey(document.getElementById("sp-key-display"))],
|
||||
3);
|
||||
|
||||
if ("arguments" in window &&
|
||||
@ -1213,6 +1206,8 @@ var Scratchpad = {
|
||||
}
|
||||
|
||||
this.resetContext();
|
||||
this.gBrowser.selectedBrowser.removeEventListener("load",
|
||||
this._reloadAndRunEvent, true);
|
||||
this.editor.removeEventListener(SourceEditor.EVENTS.DIRTY_CHANGED,
|
||||
this._onDirtyChanged);
|
||||
PreferenceObserver.uninit();
|
||||
|
@ -45,6 +45,7 @@
|
||||
<command id="sp-cmd-display" oncommand="Scratchpad.display();"/>
|
||||
<command id="sp-cmd-contentContext" oncommand="Scratchpad.setContentContext();"/>
|
||||
<command id="sp-cmd-browserContext" oncommand="Scratchpad.setBrowserContext();" disabled="true"/>
|
||||
<command id="sp-cmd-reloadAndRun" oncommand="Scratchpad.reloadAndRun();"/>
|
||||
<command id="sp-cmd-resetContext" oncommand="Scratchpad.resetContext();"/>
|
||||
<command id="sp-cmd-errorConsole" oncommand="Scratchpad.openErrorConsole();" disabled="true"/>
|
||||
<command id="sp-cmd-webConsole" oncommand="Scratchpad.openWebConsole();"/>
|
||||
@ -90,6 +91,10 @@
|
||||
key="&display.key;"
|
||||
command="sp-cmd-display"
|
||||
modifiers="accel"/>
|
||||
<key id="sp-key-reloadAndRun"
|
||||
key="&reloadAndRun.key;"
|
||||
command="sp-cmd-reloadAndRun"
|
||||
modifiers="accel,shift"/>
|
||||
<key id="sp-key-errorConsole"
|
||||
key="&errorConsoleCmd.commandkey;"
|
||||
command="sp-cmd-errorConsole"
|
||||
@ -194,6 +199,11 @@
|
||||
key="sp-key-display"
|
||||
command="sp-cmd-display"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="sp-text-reloadAndRun"
|
||||
label="&reloadAndRun.label;"
|
||||
key="sp-key-reloadAndRun"
|
||||
accesskey="&reloadAndRun.accesskey;"
|
||||
command="sp-cmd-reloadAndRun"/>
|
||||
<menuitem id="sp-text-resetContext"
|
||||
label="&resetContext2.label;"
|
||||
accesskey="&resetContext2.accesskey;"
|
||||
|
@ -34,6 +34,7 @@ MOCHITEST_BROWSER_FILES = \
|
||||
browser_scratchpad_bug_651942_recent_files.js \
|
||||
browser_scratchpad_bug756681_display_non_error_exceptions.js \
|
||||
browser_scratchpad_bug_751744_revert_to_saved.js \
|
||||
browser_scratchpad_bug740948_reload_and_run.js \
|
||||
head.js \
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -0,0 +1,73 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let DEVTOOLS_CHROME_ENABLED = "devtools.chrome.enabled";
|
||||
let EDITOR_TEXT = [
|
||||
"var evt = new CustomEvent('foo', { bubbles: true });",
|
||||
"document.body.innerHTML = 'Modified text';",
|
||||
"window.dispatchEvent(evt);"
|
||||
].join("\n");
|
||||
|
||||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
Services.prefs.setBoolPref(DEVTOOLS_CHROME_ENABLED, true);
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
|
||||
openScratchpad(runTests);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,Scratchpad test for bug 740948";
|
||||
}
|
||||
|
||||
function runTests()
|
||||
{
|
||||
let sp = gScratchpadWindow.Scratchpad;
|
||||
ok(sp, "Scratchpad object exists in new window");
|
||||
|
||||
// Test that Reload And Run command is enabled in the content
|
||||
// context and disabled in the browser context.
|
||||
|
||||
let reloadAndRun = gScratchpadWindow.document.
|
||||
getElementById("sp-cmd-reloadAndRun");
|
||||
ok(reloadAndRun, "Reload And Run command exists");
|
||||
ok(!reloadAndRun.hasAttribute("disabled"),
|
||||
"Reload And Run command is enabled");
|
||||
|
||||
sp.setBrowserContext();
|
||||
ok(reloadAndRun.hasAttribute("disabled"),
|
||||
"Reload And Run command is disabled in the browser context.");
|
||||
|
||||
// Switch back to the content context and run our predefined
|
||||
// code. This code modifies the body of our document and dispatches
|
||||
// a custom event 'foo'. We listen to that event and check the
|
||||
// body to make sure that the page has been reloaded and Scratchpad
|
||||
// code has been executed.
|
||||
|
||||
sp.setContentContext();
|
||||
sp.setText(EDITOR_TEXT);
|
||||
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
|
||||
browser.addEventListener("DOMWindowCreated", function onWindowCreated() {
|
||||
browser.removeEventListener("DOMWindowCreated", onWindowCreated, true);
|
||||
|
||||
browser.contentWindow.addEventListener("foo", function onFoo() {
|
||||
browser.contentWindow.removeEventListener("foo", onFoo, true);
|
||||
|
||||
is(browser.contentWindow.document.body.innerHTML, "Modified text",
|
||||
"After reloading, HTML is different.");
|
||||
|
||||
Services.prefs.clearUserPref(DEVTOOLS_CHROME_ENABLED);
|
||||
finish();
|
||||
}, true);
|
||||
}, true);
|
||||
|
||||
ok(browser.contentWindow.document.body.innerHTML !== "Modified text",
|
||||
"Before reloading, HTML is intact.");
|
||||
sp.reloadAndRun();
|
||||
}
|
||||
|
@ -41,6 +41,14 @@ function runTests()
|
||||
ok(!notificationBox.currentNotification,
|
||||
"there is no notification in content context");
|
||||
|
||||
let dsp = sp.contentSandbox.__SCRATCHPAD__;
|
||||
|
||||
ok(sp.contentSandbox.__SCRATCHPAD__,
|
||||
"there is a variable named __SCRATCHPAD__");
|
||||
|
||||
ok(sp.contentSandbox.__SCRATCHPAD__.editor,
|
||||
"scratchpad is actually an instance of Scratchpad");
|
||||
|
||||
sp.setText("window.foobarBug636725 = 'aloha';");
|
||||
|
||||
ok(!content.wrappedJSObject.foobarBug636725,
|
||||
@ -62,6 +70,12 @@ function runTests()
|
||||
isnot(contentMenu.getAttribute("checked"), "true",
|
||||
"content menuitem is not checked");
|
||||
|
||||
ok(sp.chromeSandbox.__SCRATCHPAD__,
|
||||
"there is a variable named __SCRATCHPAD__");
|
||||
|
||||
ok(sp.chromeSandbox.__SCRATCHPAD__.editor,
|
||||
"scratchpad is actually an instance of Scratchpad");
|
||||
|
||||
ok(notificationBox.currentNotification,
|
||||
"there is a notification in browser context");
|
||||
|
||||
|
80
browser/devtools/shared/EventEmitter.jsm
Normal file
80
browser/devtools/shared/EventEmitter.jsm
Normal file
@ -0,0 +1,80 @@
|
||||
var EXPORTED_SYMBOLS = ["EventEmitter"];
|
||||
|
||||
function EventEmitter() {
|
||||
}
|
||||
|
||||
EventEmitter.prototype = {
|
||||
/**
|
||||
* Connect a listener.
|
||||
*
|
||||
* @param string aEvent
|
||||
* The event name to which we're connecting.
|
||||
* @param function aListener
|
||||
* Called when the event is fired.
|
||||
*/
|
||||
on: function EventEmitter_on(aEvent, aListener) {
|
||||
if (!this._eventEmitterListeners)
|
||||
this._eventEmitterListeners = new Map();
|
||||
if (!this._eventEmitterListeners.has(aEvent)) {
|
||||
this._eventEmitterListeners.set(aEvent, []);
|
||||
}
|
||||
this._eventEmitterListeners.get(aEvent).push(aListener);
|
||||
},
|
||||
|
||||
/**
|
||||
* Listen for the next time an event is fired.
|
||||
*
|
||||
* @param string aEvent
|
||||
* The event name to which we're connecting.
|
||||
* @param function aListener
|
||||
* Called when the event is fired. Will be called at most one time.
|
||||
*/
|
||||
once: function EventEmitter_once(aEvent, aListener) {
|
||||
let handler = function() {
|
||||
this.off(aEvent, handler);
|
||||
aListener();
|
||||
}.bind(this);
|
||||
this.on(aEvent, handler);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a previously-registered event listener. Works for events
|
||||
* registered with either on or once.
|
||||
*
|
||||
* @param string aEvent
|
||||
* The event name whose listener we're disconnecting.
|
||||
* @param function aListener
|
||||
* The listener to remove.
|
||||
*/
|
||||
off: function EventEmitter_off(aEvent, aListener) {
|
||||
if (!this._eventEmitterListeners)
|
||||
return;
|
||||
let listeners = this._eventEmitterListeners.get(aEvent);
|
||||
this._eventEmitterListeners.set(aEvent, listeners.filter(function(l) aListener != l));
|
||||
},
|
||||
|
||||
/**
|
||||
* Emit an event. All arguments to this method will
|
||||
* be sent to listner functions.
|
||||
*/
|
||||
emit: function EventEmitter_emit(aEvent) {
|
||||
if (!this._eventEmitterListeners || !this._eventEmitterListeners.has(aEvent))
|
||||
return;
|
||||
|
||||
let originalListeners = this._eventEmitterListeners.get(aEvent);
|
||||
for (let listener of this._eventEmitterListeners.get(aEvent)) {
|
||||
// If the object was destroyed during event emission, stop
|
||||
// emitting.
|
||||
if (!this._eventEmitterListeners) {
|
||||
break;
|
||||
}
|
||||
|
||||
// If listeners were removed during emission, make sure the
|
||||
// event handler we're going to fire wasn't removed.
|
||||
if (originalListeners === this._eventEmitterListeners.get(aEvent) ||
|
||||
this._eventEmitterListeners.get(aEvent).some(function(l) l === listener)) {
|
||||
listener.apply(null, arguments);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
@ -8,6 +8,16 @@ const Cu = Components.utils;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "PlatformKeys", function() {
|
||||
return Services.strings.createBundle(
|
||||
"chrome://global-platform/locale/platformKeys.properties");
|
||||
});
|
||||
|
||||
var EXPORTED_SYMBOLS = ["LayoutHelpers"];
|
||||
|
||||
LayoutHelpers = {
|
||||
@ -310,4 +320,60 @@ LayoutHelpers = {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Prettifies the modifier keys for an element.
|
||||
*
|
||||
* @param Node aElemKey
|
||||
* The key element to get the modifiers from.
|
||||
* @return string
|
||||
* A prettified and properly separated modifier keys string.
|
||||
*/
|
||||
prettyKey: function LH_prettyKey(aElemKey)
|
||||
{
|
||||
let elemString = "";
|
||||
let elemMod = aElemKey.getAttribute("modifiers");
|
||||
|
||||
if (elemMod.match("accel")) {
|
||||
if (Services.appinfo.OS == "Darwin") {
|
||||
// XXX bug 779642 Use "Cmd-" literal vs. cloverleaf meta-key until
|
||||
// Orion adds variable height lines.
|
||||
// elemString += PlatformKeys.GetStringFromName("VK_META") +
|
||||
// PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
|
||||
elemString += "Cmd-";
|
||||
} else {
|
||||
elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
|
||||
PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
|
||||
}
|
||||
}
|
||||
if (elemMod.match("access")) {
|
||||
if (Services.appinfo.OS == "Darwin") {
|
||||
elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
|
||||
PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
|
||||
} else {
|
||||
elemString += PlatformKeys.GetStringFromName("VK_ALT") +
|
||||
PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
|
||||
}
|
||||
}
|
||||
if (elemMod.match("shift")) {
|
||||
elemString += PlatformKeys.GetStringFromName("VK_SHIFT") +
|
||||
PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
|
||||
}
|
||||
if (elemMod.match("alt")) {
|
||||
elemString += PlatformKeys.GetStringFromName("VK_ALT") +
|
||||
PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
|
||||
}
|
||||
if (elemMod.match("ctrl")) {
|
||||
elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
|
||||
PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
|
||||
}
|
||||
if (elemMod.match("meta")) {
|
||||
elemString += PlatformKeys.GetStringFromName("VK_META") +
|
||||
PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
|
||||
}
|
||||
|
||||
return elemString +
|
||||
(aElemKey.getAttribute("keycode").replace(/^.*VK_/, "") ||
|
||||
aElemKey.getAttribute("key")).toUpperCase();
|
||||
}
|
||||
};
|
||||
|
@ -22,6 +22,7 @@ MOCHITEST_BROWSER_FILES = \
|
||||
browser_toolbar_tooltip.js \
|
||||
browser_toolbar_webconsole_errors_count.js \
|
||||
browser_layoutHelpers.js \
|
||||
browser_eventemitter_basic.js \
|
||||
head.js \
|
||||
helpers.js \
|
||||
leakhunt.js \
|
||||
|
66
browser/devtools/shared/test/browser_eventemitter_basic.js
Normal file
66
browser/devtools/shared/test/browser_eventemitter_basic.js
Normal file
@ -0,0 +1,66 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
|
||||
function test() {
|
||||
Cu.import("resource:///modules/devtools/EventEmitter.jsm", this);
|
||||
let emitter = new EventEmitter();
|
||||
ok(emitter, "We have an event emitter");
|
||||
|
||||
emitter.on("next", next);
|
||||
emitter.emit("next", "abc", "def");
|
||||
|
||||
let beenHere1 = false;
|
||||
function next(eventName, str1, str2) {
|
||||
is(eventName, "next", "Got event");
|
||||
is(str1, "abc", "Argument 1 is correct");
|
||||
is(str2, "def", "Argument 2 is correct");
|
||||
|
||||
ok(!beenHere1, "first time in next callback");
|
||||
beenHere1 = true;
|
||||
|
||||
emitter.off("next", next);
|
||||
|
||||
emitter.emit("next");
|
||||
|
||||
emitter.once("onlyonce", onlyOnce);
|
||||
|
||||
emitter.emit("onlyonce");
|
||||
emitter.emit("onlyonce");
|
||||
}
|
||||
|
||||
let beenHere2 = false;
|
||||
function onlyOnce() {
|
||||
ok(!beenHere2, "\"once\" listner has been called once");
|
||||
beenHere2 = true;
|
||||
emitter.emit("onlyonce");
|
||||
|
||||
killItWhileEmitting();
|
||||
}
|
||||
|
||||
function killItWhileEmitting() {
|
||||
function c1() {
|
||||
ok(true, "c1 called");
|
||||
}
|
||||
function c2() {
|
||||
ok(true, "c2 called");
|
||||
emitter.off("tick", c3);
|
||||
}
|
||||
function c3() {
|
||||
ok(false, "c3 should not be called");
|
||||
}
|
||||
function c4() {
|
||||
ok(true, "c4 called");
|
||||
}
|
||||
|
||||
emitter.on("tick", c1);
|
||||
emitter.on("tick", c2);
|
||||
emitter.on("tick", c3);
|
||||
emitter.on("tick", c4);
|
||||
|
||||
emitter.emit("tick");
|
||||
|
||||
delete emitter;
|
||||
finish();
|
||||
}
|
||||
}
|
@ -146,9 +146,9 @@ RuleViewTool.prototype = {
|
||||
},
|
||||
|
||||
destroy: function RVT_destroy() {
|
||||
this.inspector.removeListener("select", this._onSelect);
|
||||
this.inspector.removeListener("change", this._onChange);
|
||||
this.inspector.removeListener("sidebaractivated-ruleview", this._onChange);
|
||||
this.inspector.off("select", this._onSelect);
|
||||
this.inspector.off("change", this._onChange);
|
||||
this.inspector.off("sidebaractivated-ruleview", this._onChange);
|
||||
this.view.element.removeEventListener("CssRuleViewChanged",
|
||||
this._changeHandler);
|
||||
this.view.element.removeEventListener("CssRuleViewCSSLinkClicked",
|
||||
@ -214,9 +214,9 @@ ComputedViewTool.prototype = {
|
||||
|
||||
destroy: function CVT_destroy(aContext)
|
||||
{
|
||||
this.inspector.removeListener("select", this._onSelect);
|
||||
this.inspector.removeListener("change", this._onChange);
|
||||
this.inspector.removeListener("sidebaractivated-computedview", this._onChange);
|
||||
this.inspector.off("select", this._onSelect);
|
||||
this.inspector.off("change", this._onChange);
|
||||
this.inspector.off("sidebaractivated-computedview", this._onChange);
|
||||
this.view.destroy();
|
||||
delete this.view;
|
||||
|
||||
|
@ -647,8 +647,8 @@ function JSTermHelper(aJSTerm)
|
||||
{
|
||||
aJSTerm.helperEvaluated = true;
|
||||
aJSTerm.window.open(
|
||||
"https://developer.mozilla.org/AppLinks/WebConsoleHelp?locale=" +
|
||||
aJSTerm.window.navigator.language, "help", "");
|
||||
"https://developer.mozilla.org/docs/Tools/Web_Console/Helpers",
|
||||
"help", "");
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1,34 +1,178 @@
|
||||
|
||||
Copyright (c) 2011 Mozilla Foundation
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
Contributors: Andreas Gal <gal@mozilla.com>
|
||||
Chris G Jones <cjones@mozilla.com>
|
||||
Shaon Barman <shaon.barman@gmail.com>
|
||||
Vivien Nicolas <21@vingtetun.org>
|
||||
Justin D'Arcangelo <justindarc@gmail.com>
|
||||
Yury Delendik
|
||||
Kalervo Kujala
|
||||
Adil Allawi <@ironymark>
|
||||
Jakob Miland <saebekassebil@gmail.com>
|
||||
Artur Adib <aadib@mozilla.com>
|
||||
Brendan Dahl <bdahl@mozilla.com>
|
||||
David Quintana <gigaherz@gmail.com>
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
1. Definitions.
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
This is the pdf.js project output, https://github.com/mozilla/pdf.js
|
||||
|
||||
Current extension version is: 0.4.11
|
||||
Current extension version is: 0.5.22
|
||||
|
||||
|
@ -1,5 +1,19 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
@ -18,6 +32,7 @@ const PDF_VIEWER_WEB_PAGE = 'resource://pdf.js/web/viewer.html';
|
||||
const MAX_DATABASE_LENGTH = 4096;
|
||||
const FIREFOX_ID = '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}';
|
||||
const SEAMONKEY_ID = '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}';
|
||||
const METRO_ID = '{99bceaaa-e3c6-48c1-b981-ef9b46b67d60}';
|
||||
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
@ -36,7 +51,8 @@ if (appInfo.ID === FIREFOX_ID) {
|
||||
privateBrowsing = Cc['@mozilla.org/privatebrowsing;1']
|
||||
.getService(Ci.nsIPrivateBrowsingService);
|
||||
inPrivateBrowsing = privateBrowsing.privateBrowsingEnabled;
|
||||
} else if (appInfo.ID === SEAMONKEY_ID) {
|
||||
} else if (appInfo.ID === SEAMONKEY_ID ||
|
||||
appInfo.ID === METRO_ID) {
|
||||
privateBrowsing = null;
|
||||
inPrivateBrowsing = false;
|
||||
}
|
||||
|
@ -1,3 +1,18 @@
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var EXPORTED_SYMBOLS = ["PdfJs"];
|
||||
|
||||
const Cc = Components.classes;
|
||||
|
@ -1,5 +1,19 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
|
@ -1,3 +1,18 @@
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
@ -29,29 +44,17 @@ select {
|
||||
|
||||
#viewerContainer:-webkit-full-screen {
|
||||
top: 0px;
|
||||
padding-top: 6px;
|
||||
padding-bottom: 24px;
|
||||
border-top: 5px solid transparent;
|
||||
background-color: #404040;
|
||||
background-image: url(images/texture.png);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:-webkit-full-screen #viewer {
|
||||
margin: 0pt;
|
||||
padding: 0pt;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:-webkit-full-screen .page {
|
||||
margin: 0px auto;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#viewerContainer:-moz-full-screen {
|
||||
top: 0px;
|
||||
border-top: 5px solid transparent;
|
||||
background-color: #404040;
|
||||
background-image: url(images/texture.png);
|
||||
width: 100%;
|
||||
@ -59,6 +62,10 @@ select {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:-webkit-full-screen .page:last-child {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
:-moz-full-screen .page:last-child {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
@ -760,9 +767,9 @@ html[dir='rtl'] .toolbarButton.pageDown::before {
|
||||
}
|
||||
|
||||
#thumbnailView {
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
width: 120px;
|
||||
top: 33px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
padding: 10px 40px 0;
|
||||
overflow: auto;
|
||||
@ -771,8 +778,6 @@ html[dir='rtl'] .toolbarButton.pageDown::before {
|
||||
.thumbnail {
|
||||
margin-bottom: 15px;
|
||||
float: left;
|
||||
width: 114px;
|
||||
height: 142px;
|
||||
}
|
||||
|
||||
.thumbnail:not([data-loaded]) {
|
||||
@ -825,9 +830,9 @@ a:focus > .thumbnail > .thumbnailSelectionRing,
|
||||
}
|
||||
|
||||
#outlineView {
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
width: 192px;
|
||||
top: 33px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
padding: 4px 4px 0;
|
||||
overflow: auto;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,19 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
@ -21,6 +35,7 @@ var RenderingStates = {
|
||||
FINISHED: 3
|
||||
};
|
||||
|
||||
PDFJS.workerSrc = '../build/pdf.js';
|
||||
|
||||
var mozL10n = document.mozL10n || document.webL10n;
|
||||
|
||||
@ -33,6 +48,19 @@ function getFileName(url) {
|
||||
return url.substring(url.lastIndexOf('/', end) + 1, end);
|
||||
}
|
||||
|
||||
function scrollIntoView(element, spot) {
|
||||
var parent = element.offsetParent, offsetY = element.offsetTop;
|
||||
while (parent.clientHeight == parent.scrollHeight) {
|
||||
offsetY += parent.offsetTop;
|
||||
parent = parent.offsetParent;
|
||||
if (!parent)
|
||||
return; // no need to scroll
|
||||
}
|
||||
if (spot)
|
||||
offsetY += spot.top;
|
||||
parent.scrollTop = offsetY;
|
||||
}
|
||||
|
||||
var Cache = function cacheCache(size) {
|
||||
var data = [];
|
||||
this.push = function cachePush(view) {
|
||||
@ -98,6 +126,21 @@ var ProgressBar = (function ProgressBarClosure() {
|
||||
return ProgressBar;
|
||||
})();
|
||||
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var FirefoxCom = (function FirefoxComClosure() {
|
||||
return {
|
||||
/**
|
||||
@ -242,6 +285,7 @@ var PDFView = {
|
||||
thumbnailViewScroll: null,
|
||||
isFullscreen: false,
|
||||
previousScale: null,
|
||||
pageRotation: 0,
|
||||
|
||||
// called once when the document is loaded
|
||||
initialize: function pdfViewInitialize() {
|
||||
@ -431,7 +475,13 @@ var PDFView = {
|
||||
|
||||
setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) {
|
||||
this.url = url;
|
||||
document.title = decodeURIComponent(getFileName(url)) || url;
|
||||
try {
|
||||
document.title = decodeURIComponent(getFileName(url)) || url;
|
||||
} catch (e) {
|
||||
// decodeURIComponent may throw URIError,
|
||||
// fall back to using the unprocessed url in that case
|
||||
document.title = url;
|
||||
}
|
||||
},
|
||||
|
||||
open: function pdfViewOpen(url, scale, password) {
|
||||
@ -674,6 +724,8 @@ var PDFView = {
|
||||
storedHash = 'page=' + page + '&zoom=' + zoom + ',' + left + ',' + top;
|
||||
}
|
||||
|
||||
this.pageRotation = 0;
|
||||
|
||||
var pages = this.pages = [];
|
||||
this.pageText = [];
|
||||
this.startedTextExtraction = false;
|
||||
@ -1147,6 +1199,34 @@ var PDFView = {
|
||||
this.isFullscreen = false;
|
||||
this.parseScale(this.previousScale);
|
||||
this.page = this.page;
|
||||
},
|
||||
|
||||
rotatePages: function pdfViewPageRotation(delta) {
|
||||
|
||||
this.pageRotation = (this.pageRotation + 360 + delta) % 360;
|
||||
|
||||
for (var i = 0, l = this.pages.length; i < l; i++) {
|
||||
var page = this.pages[i];
|
||||
page.update(page.scale, this.pageRotation);
|
||||
}
|
||||
|
||||
for (var i = 0, l = this.thumbnails.length; i < l; i++) {
|
||||
var thumb = this.thumbnails[i];
|
||||
thumb.updateRotation(this.pageRotation);
|
||||
}
|
||||
|
||||
var currentPage = this.pages[this.page - 1];
|
||||
|
||||
if (this.isFullscreen) {
|
||||
this.parseScale('page-fit', true);
|
||||
}
|
||||
|
||||
this.renderHighestPriority();
|
||||
|
||||
// Wait for fullscreen to take effect
|
||||
setTimeout(function() {
|
||||
currentPage.scrollIntoView();
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1155,8 +1235,9 @@ var PageView = function pageView(container, pdfPage, id, scale,
|
||||
this.id = id;
|
||||
this.pdfPage = pdfPage;
|
||||
|
||||
this.rotation = 0;
|
||||
this.scale = scale || 1.0;
|
||||
this.viewport = this.pdfPage.getViewport(this.scale);
|
||||
this.viewport = this.pdfPage.getViewport(this.scale, this.pdfPage.rotate);
|
||||
|
||||
this.renderingState = RenderingStates.INITIAL;
|
||||
this.resume = null;
|
||||
@ -1167,6 +1248,8 @@ var PageView = function pageView(container, pdfPage, id, scale,
|
||||
var div = this.el = document.createElement('div');
|
||||
div.id = 'pageContainer' + this.id;
|
||||
div.className = 'page';
|
||||
div.style.width = this.viewport.width + 'px';
|
||||
div.style.height = this.viewport.height + 'px';
|
||||
|
||||
container.appendChild(anchor);
|
||||
container.appendChild(div);
|
||||
@ -1176,12 +1259,18 @@ var PageView = function pageView(container, pdfPage, id, scale,
|
||||
this.pdfPage.destroy();
|
||||
};
|
||||
|
||||
this.update = function pageViewUpdate(scale) {
|
||||
this.update = function pageViewUpdate(scale, rotation) {
|
||||
this.renderingState = RenderingStates.INITIAL;
|
||||
this.resume = null;
|
||||
|
||||
if (typeof rotation !== 'undefined') {
|
||||
this.rotation = rotation;
|
||||
}
|
||||
|
||||
this.scale = scale || this.scale;
|
||||
var viewport = this.pdfPage.getViewport(this.scale);
|
||||
|
||||
var totalRotation = (this.rotation + this.pdfPage.rotate) % 360;
|
||||
var viewport = this.pdfPage.getViewport(this.scale, totalRotation);
|
||||
|
||||
this.viewport = viewport;
|
||||
div.style.width = viewport.width + 'px';
|
||||
@ -1310,7 +1399,7 @@ var PageView = function pageView(container, pdfPage, id, scale,
|
||||
|
||||
this.scrollIntoView = function pageViewScrollIntoView(dest) {
|
||||
if (!dest) {
|
||||
div.scrollIntoView(true);
|
||||
scrollIntoView(div);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1369,16 +1458,7 @@ var PageView = function pageView(container, pdfPage, id, scale,
|
||||
var width = Math.abs(boundingRect[0][0] - boundingRect[1][0]);
|
||||
var height = Math.abs(boundingRect[0][1] - boundingRect[1][1]);
|
||||
|
||||
// using temporary div to scroll it into view
|
||||
var tempDiv = document.createElement('div');
|
||||
tempDiv.style.position = 'absolute';
|
||||
tempDiv.style.left = Math.floor(x) + 'px';
|
||||
tempDiv.style.top = Math.floor(y) + 'px';
|
||||
tempDiv.style.width = Math.ceil(width) + 'px';
|
||||
tempDiv.style.height = Math.ceil(height) + 'px';
|
||||
div.appendChild(tempDiv);
|
||||
tempDiv.scrollIntoView(true);
|
||||
div.removeChild(tempDiv);
|
||||
scrollIntoView(div, {left: x, top: y, width: width, height: height});
|
||||
}, 0);
|
||||
};
|
||||
|
||||
@ -1521,7 +1601,9 @@ var ThumbnailView = function thumbnailView(container, pdfPage, id) {
|
||||
return false;
|
||||
};
|
||||
|
||||
var viewport = pdfPage.getViewport(1);
|
||||
var rotation = 0;
|
||||
var totalRotation = (rotation + pdfPage.rotate) % 360;
|
||||
var viewport = pdfPage.getViewport(1, totalRotation);
|
||||
var pageWidth = this.width = viewport.width;
|
||||
var pageHeight = this.height = viewport.height;
|
||||
var pageRatio = pageWidth / pageHeight;
|
||||
@ -1536,12 +1618,41 @@ var ThumbnailView = function thumbnailView(container, pdfPage, id) {
|
||||
div.id = 'thumbnailContainer' + id;
|
||||
div.className = 'thumbnail';
|
||||
|
||||
var ring = document.createElement('div');
|
||||
ring.className = 'thumbnailSelectionRing';
|
||||
ring.style.width = canvasWidth + 'px';
|
||||
ring.style.height = canvasHeight + 'px';
|
||||
|
||||
div.appendChild(ring);
|
||||
anchor.appendChild(div);
|
||||
container.appendChild(anchor);
|
||||
|
||||
this.hasImage = false;
|
||||
this.renderingState = RenderingStates.INITIAL;
|
||||
|
||||
this.updateRotation = function(rot) {
|
||||
|
||||
rotation = rot;
|
||||
totalRotation = (rotation + pdfPage.rotate) % 360;
|
||||
viewport = pdfPage.getViewport(1, totalRotation);
|
||||
pageWidth = this.width = viewport.width;
|
||||
pageHeight = this.height = viewport.height;
|
||||
pageRatio = pageWidth / pageHeight;
|
||||
|
||||
canvasHeight = canvasWidth / this.width * this.height;
|
||||
scaleX = this.scaleX = (canvasWidth / pageWidth);
|
||||
scaleY = this.scaleY = (canvasHeight / pageHeight);
|
||||
|
||||
div.removeAttribute('data-loaded');
|
||||
ring.textContent = '';
|
||||
ring.style.width = canvasWidth + 'px';
|
||||
ring.style.height = canvasHeight + 'px';
|
||||
|
||||
this.hasImage = false;
|
||||
this.renderingState = RenderingStates.INITIAL;
|
||||
this.resume = null;
|
||||
}
|
||||
|
||||
function getPageDrawContext() {
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.id = 'thumbnail' + id;
|
||||
@ -1555,10 +1666,7 @@ var ThumbnailView = function thumbnailView(container, pdfPage, id) {
|
||||
|
||||
div.setAttribute('data-loaded', true);
|
||||
|
||||
var ring = document.createElement('div');
|
||||
ring.className = 'thumbnailSelectionRing';
|
||||
ring.appendChild(canvas);
|
||||
div.appendChild(ring);
|
||||
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.save();
|
||||
@ -1584,7 +1692,7 @@ var ThumbnailView = function thumbnailView(container, pdfPage, id) {
|
||||
|
||||
var self = this;
|
||||
var ctx = getPageDrawContext();
|
||||
var drawViewport = pdfPage.getViewport(scaleX);
|
||||
var drawViewport = pdfPage.getViewport(scaleX, totalRotation);
|
||||
var renderContext = {
|
||||
canvasContext: ctx,
|
||||
viewport: drawViewport,
|
||||
@ -1890,6 +1998,93 @@ document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) {
|
||||
PDFView.renderHighestPriority();
|
||||
});
|
||||
|
||||
document.getElementById('viewThumbnail').addEventListener('click',
|
||||
function() {
|
||||
PDFView.switchSidebarView('thumbs');
|
||||
});
|
||||
|
||||
document.getElementById('viewOutline').addEventListener('click',
|
||||
function() {
|
||||
PDFView.switchSidebarView('outline');
|
||||
});
|
||||
|
||||
document.getElementById('viewSearch').addEventListener('click',
|
||||
function() {
|
||||
PDFView.switchSidebarView('search');
|
||||
});
|
||||
|
||||
document.getElementById('searchButton').addEventListener('click',
|
||||
function() {
|
||||
PDFView.search();
|
||||
});
|
||||
|
||||
document.getElementById('previous').addEventListener('click',
|
||||
function() {
|
||||
PDFView.page--;
|
||||
});
|
||||
|
||||
document.getElementById('next').addEventListener('click',
|
||||
function() {
|
||||
PDFView.page++;
|
||||
});
|
||||
|
||||
document.querySelector('.zoomIn').addEventListener('click',
|
||||
function() {
|
||||
PDFView.zoomIn();
|
||||
});
|
||||
|
||||
document.querySelector('.zoomOut').addEventListener('click',
|
||||
function() {
|
||||
PDFView.zoomOut();
|
||||
});
|
||||
|
||||
document.getElementById('fullscreen').addEventListener('click',
|
||||
function() {
|
||||
PDFView.fullscreen();
|
||||
});
|
||||
|
||||
document.getElementById('openFile').addEventListener('click',
|
||||
function() {
|
||||
document.getElementById('fileInput').click();
|
||||
});
|
||||
|
||||
document.getElementById('print').addEventListener('click',
|
||||
function() {
|
||||
window.print();
|
||||
});
|
||||
|
||||
document.getElementById('download').addEventListener('click',
|
||||
function() {
|
||||
PDFView.download();
|
||||
});
|
||||
|
||||
document.getElementById('searchTermsInput').addEventListener('keydown',
|
||||
function() {
|
||||
if (event.keyCode == 13) {
|
||||
PDFView.search();
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('pageNumber').addEventListener('change',
|
||||
function() {
|
||||
PDFView.page = this.value;
|
||||
});
|
||||
|
||||
document.getElementById('scaleSelect').addEventListener('change',
|
||||
function() {
|
||||
PDFView.parseScale(this.value);
|
||||
});
|
||||
|
||||
document.getElementById('page_rotate_ccw').addEventListener('click',
|
||||
function() {
|
||||
PDFView.rotatePages(-90);
|
||||
});
|
||||
|
||||
document.getElementById('page_rotate_cw').addEventListener('click',
|
||||
function() {
|
||||
PDFView.rotatePages(90);
|
||||
});
|
||||
|
||||
if (FirefoxCom.requestSync('getLoadingType') == 'passive') {
|
||||
PDFView.setTitleUsingUrl(file);
|
||||
PDFView.initPassiveLoading();
|
||||
@ -2050,7 +2245,7 @@ window.addEventListener('pagechange', function pagechange(evt) {
|
||||
var last = numVisibleThumbs > 1 ?
|
||||
visibleThumbs.last.id : first;
|
||||
if (page <= first || page >= last)
|
||||
thumbnail.scrollIntoView();
|
||||
scrollIntoView(thumbnail);
|
||||
}
|
||||
|
||||
}
|
||||
@ -2137,6 +2332,18 @@ window.addEventListener('keydown', function keydown(evt) {
|
||||
handled = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 82: // 'r'
|
||||
PDFView.rotatePages(90);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd == 4) { // shift-key
|
||||
switch (evt.keyCode) {
|
||||
case 82: // 'r'
|
||||
PDFView.rotatePages(-90);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user