mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 12:37:37 +00:00
Merge MC -> JM
This commit is contained in:
commit
227285ac43
@ -324,6 +324,16 @@ private:
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Accessible widget selection change event.
|
||||
*/
|
||||
class AccSelectionChangeEvent : public AccEvent
|
||||
{
|
||||
public:
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Accessible table change event.
|
||||
*/
|
||||
|
@ -180,13 +180,16 @@ HTMLLabelIterator::Next()
|
||||
nsAccessible* walkUp = mAcc->Parent();
|
||||
while (walkUp && !walkUp->IsDoc()) {
|
||||
nsIContent* walkUpElm = walkUp->GetContent();
|
||||
if (walkUpElm->Tag() == nsGkAtoms::label) {
|
||||
mLabelFilter = eSkipAncestorLabel; // prevent infinite loop
|
||||
return walkUp;
|
||||
}
|
||||
if (walkUpElm->IsHTML()) {
|
||||
if (walkUpElm->Tag() == nsGkAtoms::label &&
|
||||
!walkUpElm->HasAttr(kNameSpaceID_None, nsGkAtoms::_for)) {
|
||||
mLabelFilter = eSkipAncestorLabel; // prevent infinite loop
|
||||
return walkUp;
|
||||
}
|
||||
|
||||
if (walkUpElm->Tag() == nsGkAtoms::form)
|
||||
break;
|
||||
if (walkUpElm->Tag() == nsGkAtoms::form)
|
||||
break;
|
||||
}
|
||||
|
||||
walkUp = walkUp->Parent();
|
||||
}
|
||||
|
@ -49,6 +49,18 @@ namespace statistics {
|
||||
inline void A11yInitialized()
|
||||
{ Telemetry::Accumulate(Telemetry::A11Y_INSTANTIATED, true); }
|
||||
|
||||
/**
|
||||
* Report that ISimpleDOM* has been used.
|
||||
*/
|
||||
inline void ISimpleDOMUsed()
|
||||
{ Telemetry::Accumulate(Telemetry::ISIMPLE_DOM_USAGE, 1); }
|
||||
|
||||
/**
|
||||
* Report that IAccessibleTable has been used.
|
||||
*/
|
||||
inline void IAccessibleTableUsed()
|
||||
{ Telemetry::Accumulate(Telemetry::IACCESSIBLE_TABLE_USAGE, 1); }
|
||||
|
||||
} // namespace statistics
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
@ -961,10 +961,23 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
|
||||
// elements return the image frame as their primary frame. The main content
|
||||
// for the image frame is the image content. If the frame is not an image
|
||||
// frame or the node is not an area element then null is returned.
|
||||
// This setup will change when bug 135040 is fixed.
|
||||
return GetAreaAccessible(weakFrame.GetFrame(), aNode, aWeakShell);
|
||||
// This setup will change when bug 135040 is fixed. Make sure we don't
|
||||
// create area accessible here. Hopefully assertion below will handle that.
|
||||
|
||||
#ifdef DEBUG
|
||||
nsImageFrame* imageFrame = do_QueryFrame(weakFrame.GetFrame());
|
||||
NS_ASSERTION(imageFrame && content->IsHTML() && content->Tag() == nsGkAtoms::area,
|
||||
"Unknown case of not main content for the frame!");
|
||||
#endif
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
nsImageFrame* imageFrame = do_QueryFrame(weakFrame.GetFrame());
|
||||
NS_ASSERTION(!imageFrame || !content->IsHTML() || content->Tag() != nsGkAtoms::area,
|
||||
"Image map manages the area accessible creation!");
|
||||
#endif
|
||||
|
||||
nsDocAccessible* docAcc =
|
||||
GetAccService()->GetDocAccessible(aNode->GetOwnerDoc());
|
||||
if (!docAcc) {
|
||||
@ -1278,50 +1291,6 @@ nsAccessibilityService::HasUniversalAriaProperty(nsIContent *aContent)
|
||||
nsAccUtils::HasDefinedARIAToken(aContent, nsGkAtoms::aria_relevant);
|
||||
}
|
||||
|
||||
nsAccessible*
|
||||
nsAccessibilityService::GetAreaAccessible(nsIFrame* aImageFrame,
|
||||
nsINode* aAreaNode,
|
||||
nsIWeakReference* aWeakShell,
|
||||
nsAccessible** aImageAccessible)
|
||||
{
|
||||
// Check if frame is an image frame, and content is <area>.
|
||||
nsImageFrame *imageFrame = do_QueryFrame(aImageFrame);
|
||||
if (!imageFrame)
|
||||
return nsnull;
|
||||
|
||||
nsCOMPtr<nsIDOMHTMLAreaElement> areaElmt = do_QueryInterface(aAreaNode);
|
||||
if (!areaElmt)
|
||||
return nsnull;
|
||||
|
||||
// Try to get image map accessible from the global cache or create it
|
||||
// if failed.
|
||||
nsRefPtr<nsAccessible> image =
|
||||
GetAccessibleInWeakShell(aImageFrame->GetContent(), aWeakShell);
|
||||
if (!image) {
|
||||
image = CreateHTMLImageAccessible(aImageFrame->GetContent(),
|
||||
aImageFrame->PresContext()->PresShell());
|
||||
|
||||
nsDocAccessible* document =
|
||||
GetAccService()->GetDocAccessible(aAreaNode->GetOwnerDoc());
|
||||
if (!document) {
|
||||
NS_NOTREACHED("No document for accessible being created!");
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
if (!document->BindToDocument(image, nsnull))
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
if (aImageAccessible)
|
||||
*aImageAccessible = image;
|
||||
|
||||
// Make sure <area> accessible children of the image map are cached so
|
||||
// that they should be available in global cache.
|
||||
image->EnsureChildren();
|
||||
|
||||
return GetAccessibleInWeakShell(aAreaNode, aWeakShell);
|
||||
}
|
||||
|
||||
already_AddRefed<nsAccessible>
|
||||
nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
|
||||
nsIWeakReference* aWeakShell)
|
||||
|
@ -229,18 +229,6 @@ private:
|
||||
*/
|
||||
void Shutdown();
|
||||
|
||||
/**
|
||||
* Return accessible for HTML area element associated with an image map.
|
||||
*
|
||||
* @param aImageFrame [in] image frame
|
||||
* @param aAreaNode [in] area node
|
||||
* @param aWeakShell [in] presshell of image frame
|
||||
* @param aImageAccessible [out, optional] image accessible, isn't addrefed
|
||||
*/
|
||||
nsAccessible* GetAreaAccessible(nsIFrame* aImageFrame, nsINode* aAreaNode,
|
||||
nsIWeakReference* aWeakShell,
|
||||
nsAccessible** aImageAccessible = nsnull);
|
||||
|
||||
/**
|
||||
* Create accessible for the element implementing nsIAccessibleProvider
|
||||
* interface.
|
||||
|
@ -387,15 +387,10 @@ nsRootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent)
|
||||
NS_ASSERTION(targetDocument, "No document while accessible is in document?!");
|
||||
|
||||
nsINode* targetNode = accessible->GetNode();
|
||||
nsIContent* targetContent = targetNode->IsElement() ?
|
||||
targetNode->AsElement() : nsnull;
|
||||
nsIContent* origTargetContent = origTargetNode->IsElement() ?
|
||||
origTargetNode->AsElement() : nsnull;
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
bool isTree = targetContent ?
|
||||
targetContent->NodeInfo()->Equals(nsGkAtoms::tree, kNameSpaceID_XUL) :
|
||||
PR_FALSE;
|
||||
bool isTree = targetNode->IsElement() &&
|
||||
targetNode->AsElement()->NodeInfo()->Equals(nsGkAtoms::tree, kNameSpaceID_XUL);
|
||||
|
||||
if (isTree) {
|
||||
nsRefPtr<nsXULTreeAccessible> treeAcc = do_QueryObject(accessible);
|
||||
|
@ -278,8 +278,8 @@ nsHTMLButtonAccessible::NativeState()
|
||||
{
|
||||
PRUint64 state = nsHyperTextAccessibleWrap::NativeState();
|
||||
|
||||
if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
||||
nsGkAtoms::submit, eIgnoreCase))
|
||||
nsEventStates elmState = mContent->AsElement()->State();
|
||||
if (elmState.HasState(NS_EVENT_STATE_DEFAULT))
|
||||
state |= states::DEFAULT;
|
||||
|
||||
return state;
|
||||
@ -382,8 +382,8 @@ nsHTML4ButtonAccessible::NativeState()
|
||||
|
||||
state |= states::FOCUSABLE;
|
||||
|
||||
if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
||||
nsGkAtoms::submit, eIgnoreCase))
|
||||
nsEventStates elmState = mContent->AsElement()->State();
|
||||
if (elmState.HasState(NS_EVENT_STATE_DEFAULT))
|
||||
state |= states::DEFAULT;
|
||||
|
||||
return state;
|
||||
|
@ -1360,7 +1360,7 @@ nsHTMLTableAccessible::IsProbablyForLayout(bool *aIsProbablyForLayout)
|
||||
#define RETURN_LAYOUT_ANSWER(isLayout, heuristic) { *aIsProbablyForLayout = isLayout; return NS_OK; }
|
||||
#endif
|
||||
|
||||
*aIsProbablyForLayout = PR_FALSE;
|
||||
*aIsProbablyForLayout = false;
|
||||
|
||||
if (IsDefunct())
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -1369,7 +1369,7 @@ nsHTMLTableAccessible::IsProbablyForLayout(bool *aIsProbablyForLayout)
|
||||
if (docAccessible) {
|
||||
PRUint64 docState = docAccessible->State();
|
||||
if (docState & states::EDITABLE) { // Need to see all elements while document is being edited
|
||||
RETURN_LAYOUT_ANSWER(PR_FALSE, "In editable document");
|
||||
RETURN_LAYOUT_ANSWER(false, "In editable document");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1377,45 +1377,77 @@ nsHTMLTableAccessible::IsProbablyForLayout(bool *aIsProbablyForLayout)
|
||||
// but for which we still expose table semantics (treegrid, for example).
|
||||
bool hasNonTableRole = (Role() != nsIAccessibleRole::ROLE_TABLE);
|
||||
if (hasNonTableRole) {
|
||||
RETURN_LAYOUT_ANSWER(PR_FALSE, "Has role attribute");
|
||||
RETURN_LAYOUT_ANSWER(false, "Has role attribute");
|
||||
}
|
||||
|
||||
if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::role)) {
|
||||
// Role attribute is present, but overridden roles have already been dealt with.
|
||||
// Only landmarks and other roles that don't override the role from native
|
||||
// markup are left to deal with here.
|
||||
RETURN_LAYOUT_ANSWER(PR_FALSE, "Has role attribute, weak role, and role is table");
|
||||
RETURN_LAYOUT_ANSWER(false, "Has role attribute, weak role, and role is table");
|
||||
}
|
||||
|
||||
// Check for legitimate data table elements or attributes
|
||||
|
||||
// Check for legitimate data table attributes.
|
||||
nsAutoString summary;
|
||||
if ((mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::summary, summary) &&
|
||||
!summary.IsEmpty()) ||
|
||||
HasDescendant(NS_LITERAL_STRING("caption"), PR_FALSE) ||
|
||||
HasDescendant(NS_LITERAL_STRING("th")) ||
|
||||
HasDescendant(NS_LITERAL_STRING("thead")) ||
|
||||
HasDescendant(NS_LITERAL_STRING("tfoot")) ||
|
||||
HasDescendant(NS_LITERAL_STRING("colgroup"))) {
|
||||
RETURN_LAYOUT_ANSWER(PR_FALSE, "Has caption, summary, th, thead, tfoot or colgroup -- legitimate table structures");
|
||||
if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::summary, summary) &&
|
||||
!summary.IsEmpty())
|
||||
RETURN_LAYOUT_ANSWER(false, "Has summary -- legitimate table structures");
|
||||
|
||||
// Check for legitimate data table elements.
|
||||
nsAccessible* caption = FirstChild();
|
||||
if (caption && caption->Role() == nsIAccessibleRole::ROLE_CAPTION &&
|
||||
caption->HasChildren()) {
|
||||
RETURN_LAYOUT_ANSWER(false,
|
||||
"Not empty caption -- legitimate table structures");
|
||||
}
|
||||
|
||||
for (nsIContent* childElm = mContent->GetFirstChild(); childElm;
|
||||
childElm = childElm->GetNextSibling()) {
|
||||
if (!childElm->IsHTML())
|
||||
continue;
|
||||
|
||||
if (childElm->Tag() == nsGkAtoms::col ||
|
||||
childElm->Tag() == nsGkAtoms::colgroup ||
|
||||
childElm->Tag() == nsGkAtoms::tfoot ||
|
||||
childElm->Tag() == nsGkAtoms::thead) {
|
||||
RETURN_LAYOUT_ANSWER(false,
|
||||
"Has col, colgroup, tfoot or thead -- legitimate table structures");
|
||||
}
|
||||
|
||||
if (childElm->Tag() == nsGkAtoms::tbody) {
|
||||
for (nsIContent* rowElm = childElm->GetFirstChild(); rowElm;
|
||||
rowElm = rowElm->GetNextSibling()) {
|
||||
if (rowElm->IsHTML() && rowElm->Tag() == nsGkAtoms::tr) {
|
||||
for (nsIContent* cellElm = rowElm->GetFirstChild(); cellElm;
|
||||
cellElm = cellElm->GetNextSibling()) {
|
||||
if (cellElm->IsHTML() && cellElm->Tag() == nsGkAtoms::th) {
|
||||
RETURN_LAYOUT_ANSWER(false,
|
||||
"Has th -- legitimate table structures");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (HasDescendant(NS_LITERAL_STRING("table"))) {
|
||||
RETURN_LAYOUT_ANSWER(PR_TRUE, "Has a nested table within it");
|
||||
RETURN_LAYOUT_ANSWER(true, "Has a nested table within it");
|
||||
}
|
||||
|
||||
// If only 1 column or only 1 row, it's for layout
|
||||
PRInt32 columns, rows;
|
||||
GetColumnCount(&columns);
|
||||
if (columns <=1) {
|
||||
RETURN_LAYOUT_ANSWER(PR_TRUE, "Has only 1 column");
|
||||
RETURN_LAYOUT_ANSWER(true, "Has only 1 column");
|
||||
}
|
||||
GetRowCount(&rows);
|
||||
if (rows <=1) {
|
||||
RETURN_LAYOUT_ANSWER(PR_TRUE, "Has only 1 row");
|
||||
RETURN_LAYOUT_ANSWER(true, "Has only 1 row");
|
||||
}
|
||||
|
||||
// Check for many columns
|
||||
if (columns >= 5) {
|
||||
RETURN_LAYOUT_ANSWER(PR_FALSE, ">=5 columns");
|
||||
RETURN_LAYOUT_ANSWER(false, ">=5 columns");
|
||||
}
|
||||
|
||||
// Now we know there are 2-4 columns and 2 or more rows
|
||||
@ -1434,7 +1466,7 @@ nsHTMLTableAccessible::IsProbablyForLayout(bool *aIsProbablyForLayout)
|
||||
nsMargin border;
|
||||
cellFrame->GetBorder(border);
|
||||
if (border.top && border.bottom && border.left && border.right) {
|
||||
RETURN_LAYOUT_ANSWER(PR_FALSE, "Has nonzero border-width on table cell");
|
||||
RETURN_LAYOUT_ANSWER(false, "Has nonzero border-width on table cell");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1462,21 +1494,21 @@ nsHTMLTableAccessible::IsProbablyForLayout(bool *aIsProbablyForLayout)
|
||||
lastRowColor = color;
|
||||
styleDecl->GetPropertyValue(NS_LITERAL_STRING("background-color"), color);
|
||||
if (rowCount > 0 && PR_FALSE == lastRowColor.Equals(color)) {
|
||||
RETURN_LAYOUT_ANSWER(PR_FALSE, "2 styles of row background color, non-bordered");
|
||||
RETURN_LAYOUT_ANSWER(false, "2 styles of row background color, non-bordered");
|
||||
}
|
||||
}
|
||||
|
||||
// Check for many rows
|
||||
const PRInt32 kMaxLayoutRows = 20;
|
||||
if (rows > kMaxLayoutRows) { // A ton of rows, this is probably for data
|
||||
RETURN_LAYOUT_ANSWER(PR_FALSE, ">= kMaxLayoutRows (20) and non-bordered");
|
||||
RETURN_LAYOUT_ANSWER(false, ">= kMaxLayoutRows (20) and non-bordered");
|
||||
}
|
||||
|
||||
// Check for very wide table
|
||||
nsAutoString styledWidth;
|
||||
GetComputedStyleValue(EmptyString(), NS_LITERAL_STRING("width"), styledWidth);
|
||||
if (styledWidth.EqualsLiteral("100%")) {
|
||||
RETURN_LAYOUT_ANSWER(PR_TRUE, "<=4 columns and 100% width");
|
||||
RETURN_LAYOUT_ANSWER(true, "<=4 columns and 100% width");
|
||||
}
|
||||
if (styledWidth.Find(NS_LITERAL_STRING("px"))) { // Hardcoded in pixels
|
||||
nsIFrame *tableFrame = GetFrame();
|
||||
@ -1494,24 +1526,24 @@ nsHTMLTableAccessible::IsProbablyForLayout(bool *aIsProbablyForLayout)
|
||||
if (percentageOfDocWidth > 95) {
|
||||
// 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width
|
||||
// Probably for layout
|
||||
RETURN_LAYOUT_ANSWER(PR_TRUE, "<=4 columns, width hardcoded in pixels and 95% of document width");
|
||||
RETURN_LAYOUT_ANSWER(true, "<=4 columns, width hardcoded in pixels and 95% of document width");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Two column rules
|
||||
if (rows * columns <= 10) {
|
||||
RETURN_LAYOUT_ANSWER(PR_TRUE, "2-4 columns, 10 cells or less, non-bordered");
|
||||
RETURN_LAYOUT_ANSWER(true, "2-4 columns, 10 cells or less, non-bordered");
|
||||
}
|
||||
|
||||
if (HasDescendant(NS_LITERAL_STRING("embed")) ||
|
||||
HasDescendant(NS_LITERAL_STRING("object")) ||
|
||||
HasDescendant(NS_LITERAL_STRING("applet")) ||
|
||||
HasDescendant(NS_LITERAL_STRING("iframe"))) {
|
||||
RETURN_LAYOUT_ANSWER(PR_TRUE, "Has no borders, and has iframe, object, applet or iframe, typical of advertisements");
|
||||
RETURN_LAYOUT_ANSWER(true, "Has no borders, and has iframe, object, applet or iframe, typical of advertisements");
|
||||
}
|
||||
|
||||
RETURN_LAYOUT_ANSWER(PR_FALSE, "no layout factor strong enough, so will guess data");
|
||||
RETURN_LAYOUT_ANSWER(false, "no layout factor strong enough, so will guess data");
|
||||
}
|
||||
|
||||
|
||||
|
@ -49,10 +49,13 @@
|
||||
#include "nsIWinAccessNode.h"
|
||||
#include "nsAccessNodeWrap.h"
|
||||
#include "nsWinUtils.h"
|
||||
#include "Statistics.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
|
||||
using namespace mozilla::a11y;
|
||||
|
||||
#define CANT_QUERY_ASSERTION_MSG \
|
||||
"Subclass of CAccessibleTable doesn't implement nsIAccessibleTable"\
|
||||
|
||||
@ -64,6 +67,7 @@ CAccessibleTable::QueryInterface(REFIID iid, void** ppv)
|
||||
*ppv = NULL;
|
||||
|
||||
if (IID_IAccessibleTable == iid) {
|
||||
statistics::IAccessibleTableUsed();
|
||||
*ppv = static_cast<IAccessibleTable*>(this);
|
||||
(reinterpret_cast<IUnknown*>(*ppv))->AddRef();
|
||||
return S_OK;
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "nsCoreUtils.h"
|
||||
#include "nsRootAccessible.h"
|
||||
#include "nsWinUtils.h"
|
||||
#include "Statistics.h"
|
||||
|
||||
#include "nsAttrName.h"
|
||||
#include "nsIDocument.h"
|
||||
@ -59,6 +60,7 @@
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::a11y;
|
||||
|
||||
/// the accessible library and cached methods
|
||||
HINSTANCE nsAccessNodeWrap::gmAccLib = nsnull;
|
||||
@ -120,11 +122,14 @@ STDMETHODIMP nsAccessNodeWrap::QueryInterface(REFIID iid, void** ppv)
|
||||
{
|
||||
*ppv = nsnull;
|
||||
|
||||
if (IID_IUnknown == iid || IID_ISimpleDOMNode == iid)
|
||||
if (IID_IUnknown == iid) {
|
||||
*ppv = static_cast<ISimpleDOMNode*>(this);
|
||||
|
||||
if (nsnull == *ppv)
|
||||
} else if (IID_ISimpleDOMNode == iid) {
|
||||
statistics::ISimpleDOMUsed();
|
||||
*ppv = static_cast<ISimpleDOMNode*>(this);
|
||||
} else {
|
||||
return E_NOINTERFACE; //iid not supported.
|
||||
}
|
||||
|
||||
(reinterpret_cast<IUnknown*>(*ppv))->AddRef();
|
||||
return S_OK;
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "nsIAccessibilityService.h"
|
||||
#include "nsRootAccessible.h"
|
||||
#include "nsWinUtils.h"
|
||||
#include "Statistics.h"
|
||||
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDocShellTreeNode.h"
|
||||
@ -54,6 +55,8 @@
|
||||
#include "nsIViewManager.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
|
||||
using namespace mozilla::a11y;
|
||||
|
||||
/* For documentation of the accessibility architecture,
|
||||
* see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
|
||||
*/
|
||||
@ -91,12 +94,11 @@ STDMETHODIMP nsDocAccessibleWrap::QueryInterface(REFIID iid, void** ppv)
|
||||
{
|
||||
*ppv = NULL;
|
||||
|
||||
if (IID_ISimpleDOMDocument == iid)
|
||||
*ppv = static_cast<ISimpleDOMDocument*>(this);
|
||||
|
||||
if (NULL == *ppv)
|
||||
if (IID_ISimpleDOMDocument != iid)
|
||||
return nsHyperTextAccessibleWrap::QueryInterface(iid, ppv);
|
||||
|
||||
|
||||
statistics::ISimpleDOMUsed();
|
||||
*ppv = static_cast<ISimpleDOMDocument*>(this);
|
||||
(reinterpret_cast<IUnknown*>(*ppv))->AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -41,6 +41,7 @@
|
||||
|
||||
#include "nsCoreUtils.h"
|
||||
#include "nsDocAccessible.h"
|
||||
#include "Statistics.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsFontMetrics.h"
|
||||
#include "nsPresContext.h"
|
||||
@ -48,6 +49,8 @@
|
||||
|
||||
#include "gfxFont.h"
|
||||
|
||||
using namespace mozilla::a11y;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsTextAccessibleWrap Accessible
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -72,11 +75,14 @@ STDMETHODIMP nsTextAccessibleWrap::QueryInterface(REFIID iid, void** ppv)
|
||||
{
|
||||
*ppv = nsnull;
|
||||
|
||||
if (IID_IUnknown == iid || IID_ISimpleDOMText == iid)
|
||||
if (IID_IUnknown == iid) {
|
||||
*ppv = static_cast<ISimpleDOMText*>(this);
|
||||
|
||||
if (nsnull == *ppv)
|
||||
} else if (IID_ISimpleDOMText == iid) {
|
||||
statistics::ISimpleDOMUsed();
|
||||
*ppv = static_cast<ISimpleDOMText*>(this);
|
||||
} else {
|
||||
return nsAccessibleWrap::QueryInterface(iid, ppv);
|
||||
}
|
||||
|
||||
(reinterpret_cast<IUnknown*>(*ppv))->AddRef();
|
||||
return S_OK;
|
||||
|
@ -817,22 +817,17 @@ Relation
|
||||
nsXULTreeItemAccessibleBase::RelationByType(PRUint32 aType)
|
||||
{
|
||||
if (aType != nsIAccessibleRelation::RELATION_NODE_CHILD_OF)
|
||||
return nsAccessible::RelationByType(aType);
|
||||
return Relation();
|
||||
|
||||
Relation rel;
|
||||
PRInt32 parentIndex;
|
||||
if (!NS_SUCCEEDED(mTreeView->GetParentIndex(mRow, &parentIndex)))
|
||||
return rel;
|
||||
return Relation();
|
||||
|
||||
if (parentIndex == -1) {
|
||||
rel.AppendTarget(mParent);
|
||||
return rel;
|
||||
}
|
||||
if (parentIndex == -1)
|
||||
return Relation(mParent);
|
||||
|
||||
nsRefPtr<nsXULTreeAccessible> treeAcc = do_QueryObject(mParent);
|
||||
|
||||
rel.AppendTarget(treeAcc->GetTreeItemAccessible(parentIndex));
|
||||
return rel;
|
||||
return Relation(treeAcc->GetTreeItemAccessible(parentIndex));
|
||||
}
|
||||
|
||||
PRUint8
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "nsAccUtils.h"
|
||||
#include "nsDocAccessible.h"
|
||||
#include "nsEventShell.h"
|
||||
#include "Relation.h"
|
||||
#include "States.h"
|
||||
|
||||
#include "nsITreeSelection.h"
|
||||
@ -1237,6 +1238,12 @@ nsXULTreeGridCellAccessible::IndexInParent() const
|
||||
return GetColumnIndex();
|
||||
}
|
||||
|
||||
Relation
|
||||
nsXULTreeGridCellAccessible::RelationByType(PRUint32 aType)
|
||||
{
|
||||
return Relation();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsXULTreeGridCellAccessible: public implementation
|
||||
|
||||
|
@ -163,6 +163,7 @@ public:
|
||||
virtual nsAccessible* FocusedChild();
|
||||
virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
|
||||
virtual PRInt32 IndexInParent() const;
|
||||
virtual Relation RelationByType(PRUint32 aType);
|
||||
virtual PRUint32 NativeRole();
|
||||
virtual PRUint64 NativeState();
|
||||
|
||||
|
@ -76,6 +76,7 @@ _TEST_FILES =\
|
||||
test_focus_menu.xul \
|
||||
test_focus_name.html \
|
||||
test_focus_selects.html \
|
||||
test_focus_tabbox.xul \
|
||||
test_focus_tree.xul \
|
||||
test_menu.xul \
|
||||
test_mutation.html \
|
||||
|
@ -106,9 +106,10 @@
|
||||
gQueue.push(new synthContextMenu(editableDoc, new contextMenuChecker()));
|
||||
gQueue.push(new synthDownKey(editableDoc, new focusContextMenuItemChecker()));
|
||||
gQueue.push(new synthEscapeKey(editableDoc, new focusChecker(editableDoc)));
|
||||
|
||||
todo(false, "shift+tab doesn't issue the focus, see bug 684818");
|
||||
//gQuee.push(new synthShiftTab("link", new focusChecker("link")));
|
||||
if (LINUX)
|
||||
todo(false, "shift tab from editable document Fails on linux!");
|
||||
else
|
||||
gQueue.push(new synthShiftTab("link", new focusChecker("link")));
|
||||
|
||||
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||
}
|
||||
|
94
accessible/tests/mochitest/events/test_focus_tabbox.xul
Normal file
94
accessible/tests/mochitest/events/test_focus_tabbox.xul
Normal file
@ -0,0 +1,94 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="Tabbox focus testing">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../common.js" />
|
||||
<script type="application/javascript"
|
||||
src="../states.js" />
|
||||
<script type="application/javascript"
|
||||
src="../events.js" />
|
||||
|
||||
<script type="application/javascript">
|
||||
//gA11yEventDumpID = "eventdump"; // debug stuff
|
||||
//gA11yEventDumpToConsole = true; // debug stuff
|
||||
|
||||
var gQueue = null;
|
||||
function doTests()
|
||||
{
|
||||
// Test focus events.
|
||||
gQueue = new eventQueue();
|
||||
|
||||
gQueue.push(new synthClick("tab1", new focusChecker("tab1")));
|
||||
gQueue.push(new synthTab("tab1", new focusChecker("checkbox1")));
|
||||
gQueue.push(new synthKey("tab1", "VK_TAB", { ctrlKey: true },
|
||||
new focusChecker("textbox")));
|
||||
gQueue.push(new synthKey("tab2", "VK_TAB", { ctrlKey: true },
|
||||
new focusChecker("tab3")));
|
||||
gQueue.push(new synthKey("tab3", "VK_TAB", { ctrlKey: true },
|
||||
new focusChecker("tab1")));
|
||||
|
||||
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTests);
|
||||
</script>
|
||||
|
||||
<hbox flex="1" style="overflow: auto;">
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=370396"
|
||||
title="Control+Tab to an empty tab panel in a tabbox causes focus to leave the tabbox">
|
||||
Mozilla Bug 370396
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
<vbox flex="1">
|
||||
<tabbox>
|
||||
<tabs>
|
||||
<tab id="tab1" label="Tab1" selected="true"/>
|
||||
<tab id="tab2" label="Tab2" />
|
||||
<tab id="tab3" label="Tab3" />
|
||||
</tabs>
|
||||
<tabpanels>
|
||||
<tabpanel orient="vertical">
|
||||
<groupbox orient="vertical">
|
||||
<checkbox id="checkbox1" label="Monday" width="75"/>
|
||||
<checkbox label="Tuesday" width="75"/>
|
||||
<checkbox label="Wednesday" width="75"/>
|
||||
<checkbox label="Thursday" width="75"/>
|
||||
<checkbox label="Friday" width="75"/>
|
||||
<checkbox label="Saturday" width="75"/>
|
||||
<checkbox label="Sunday" width="75"/>
|
||||
</groupbox>
|
||||
|
||||
<spacer style="height: 10px" />
|
||||
<label value="Label After checkboxes" />
|
||||
</tabpanel>
|
||||
<tabpanel orient="vertical">
|
||||
<textbox id="textbox" />
|
||||
</tabpanel>
|
||||
<tabpanel orient="vertical">
|
||||
<description>Tab 3 content</description>
|
||||
</tabpanel>
|
||||
</tabpanels>
|
||||
</tabbox>
|
||||
|
||||
<vbox id="eventdump"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</window>
|
@ -170,11 +170,13 @@
|
||||
testName("combo4", "Subscribe to ATOM feed.");
|
||||
|
||||
testName("comboinmiddle2", "Play the Haliluya sound when new mail arrives");
|
||||
testName("combo5", "Play the Haliluya sound when new mail arrives");
|
||||
testName("combo5", null); // label isn't used as a name for control
|
||||
testName("checkbox", "Play the Haliluya sound when new mail arrives");
|
||||
testName("comboinmiddle3", "Play the Haliluya sound when new mail arrives");
|
||||
testName("combo6", "Play the Haliluya sound when new mail arrives");
|
||||
|
||||
testName("comboinend", "This day was sunny");
|
||||
testName("combo6", "This day was");
|
||||
testName("combo7", "This day was");
|
||||
|
||||
testName("textboxinend", "This day was sunny");
|
||||
testName("textbox2", "This day was");
|
||||
@ -213,6 +215,11 @@
|
||||
title="Use placeholder as name if name is otherwise empty">
|
||||
Mozilla Bug 604391
|
||||
</a>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=669312"
|
||||
title="Accessible name is duplicated when input has a label associated uisng for/id and is wrapped around the input">
|
||||
Mozilla Bug 669312
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
@ -437,10 +444,18 @@
|
||||
</label>
|
||||
<input id="checkbox" type="checkbox" />
|
||||
|
||||
<label id="comboinmiddle3" for="combo6">Play the
|
||||
<select id="combo6">
|
||||
<option>Haliluya</option>
|
||||
<option>Hurra</option>
|
||||
</select>
|
||||
sound when new mail arrives
|
||||
</label>
|
||||
|
||||
<!-- at the end (without and with whitespaces) -->
|
||||
<label id="comboinend">
|
||||
This day was
|
||||
<select id="combo6" name="occupation">
|
||||
<select id="combo7" name="occupation">
|
||||
<option>sunny</option>
|
||||
<option>rainy</option>
|
||||
</select></label>
|
||||
|
@ -41,6 +41,10 @@
|
||||
testRelation("control1_11", RELATION_LABELLED_BY, "label1_11");
|
||||
testRelation("control1_12", RELATION_LABELLED_BY, "label1_12");
|
||||
|
||||
testRelation("label1_13", RELATION_LABEL_FOR, null);
|
||||
testRelation("control1_13", RELATION_LABELLED_BY, null);
|
||||
testRelation("control1_14", RELATION_LABELLED_BY, "label1_14");
|
||||
|
||||
// aria-labelledby
|
||||
testRelation("label2", RELATION_LABEL_FOR, "checkbox2");
|
||||
testRelation("checkbox2", RELATION_LABELLED_BY, "label2");
|
||||
@ -157,6 +161,11 @@
|
||||
title="make HTML <output> accessible">
|
||||
Mozilla Bug 558036
|
||||
</a>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=682790"
|
||||
title="Ignore implicit label association when it's associated explicitly">
|
||||
Mozilla Bug 682790
|
||||
</a>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=687393"
|
||||
title="HTML select options gets relation from containing label">
|
||||
@ -204,6 +213,13 @@
|
||||
<progress id="control1_12"></progress>
|
||||
</label>
|
||||
|
||||
<label id="label1_13" for="">Label
|
||||
<input id="control1_13">
|
||||
</label>
|
||||
<label id="label1_14" for="control1_14">Label
|
||||
<input id="control1_14">
|
||||
</label>
|
||||
|
||||
<span id="label2">label</span>
|
||||
<span role="checkbox" id="checkbox2" aria-labelledby="label2"></span>
|
||||
|
||||
|
@ -47,6 +47,10 @@
|
||||
var treeitem6 = treeitem5.nextSibling;
|
||||
testRelation(treeitem6, RELATION_NODE_CHILD_OF, [tree]);
|
||||
|
||||
// treeitems and treecells shouldn't pick up relations from tree
|
||||
testRelation(treeitem1, RELATION_LABELLED_BY, null);
|
||||
testRelation(treeitem1.firstChild, RELATION_LABELLED_BY, null);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
@ -68,7 +72,12 @@
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=503727"
|
||||
title="Reorganize implementation of XUL tree accessibility">
|
||||
Mozilla Bug 503727
|
||||
</a><br/>
|
||||
</a>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=691248"
|
||||
title="XUL tree items shouldn't pick up relations from XUL tree">
|
||||
Mozilla Bug 691248
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
@ -77,9 +86,11 @@
|
||||
</body>
|
||||
|
||||
<vbox flex="1">
|
||||
<label control="tree" value="It's a tree"/>
|
||||
<tree id="tree" flex="1">
|
||||
<treecols>
|
||||
<treecol id="col" flex="1" primary="true" label="column"/>
|
||||
<treecol id="col2" flex="1" label="column2"/>
|
||||
</treecols>
|
||||
<treechildren/>
|
||||
</tree>
|
||||
|
@ -13,6 +13,7 @@
|
||||
const STATE_CHECKED = nsIAccessibleStates.STATE_CHECKED;
|
||||
const STATE_CHECKABLE = nsIAccessibleStates.STATE_CHECKABLE;
|
||||
const STATE_COLLAPSED = nsIAccessibleStates.STATE_COLLAPSED;
|
||||
const STATE_DEFAULT = nsIAccessibleStates.STATE_DEFAULT;
|
||||
const STATE_EXPANDED = nsIAccessibleStates.STATE_EXPANDED;
|
||||
const STATE_EXTSELECTABLE = nsIAccessibleStates.STATE_EXTSELECTABLE;
|
||||
const STATE_FOCUSABLE = nsIAccessibleStates.STATE_FOCUSABLE;
|
||||
|
@ -49,6 +49,7 @@ _TEST_FILES =\
|
||||
test_aria.html \
|
||||
test_aria_imgmap.html \
|
||||
test_aria_tabs.html \
|
||||
test_buttons.html \
|
||||
test_doc.html \
|
||||
test_docarticle.html \
|
||||
test_editablebody.html \
|
||||
|
79
accessible/tests/mochitest/states/test_buttons.html
Normal file
79
accessible/tests/mochitest/states/test_buttons.html
Normal file
@ -0,0 +1,79 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>HTML button accessible states</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="../states.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
function doTest()
|
||||
{
|
||||
// Default state.
|
||||
testStates("f1_image", STATE_DEFAULT);
|
||||
testStates("f2_submit", STATE_DEFAULT);
|
||||
testStates("f3_submitbutton", STATE_DEFAULT);
|
||||
testStates("f4_button", 0, 0, STATE_DEFAULT);
|
||||
testStates("f4_image1", STATE_DEFAULT);
|
||||
testStates("f4_image2", 0, 0, STATE_DEFAULT);
|
||||
testStates("f4_submit", 0, 0, STATE_DEFAULT);
|
||||
testStates("f4_submitbutton", 0, 0, STATE_DEFAULT);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=664142"
|
||||
title="DEFAULT state exposed incorrectly for HTML">
|
||||
Mozilla Bug 664142
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<p>A form with an image button</p>
|
||||
<form name="form1" method="get">
|
||||
<input type="text" name="hi">
|
||||
|
||||
<input id="f1_image" type="image" value="image-button">
|
||||
</form>
|
||||
|
||||
<p>A form with a submit button:</p>
|
||||
<form name="form2" method="get">
|
||||
<input type="text" name="hi">
|
||||
<input id="f2_submit" type="submit">
|
||||
</form>
|
||||
|
||||
<p>A form with a HTML4 submit button:</p>
|
||||
<form name="form3" method="get">
|
||||
<input type="text" name="hi">
|
||||
<button id="f3_submitbutton" type="submit">submit</button>
|
||||
</form>
|
||||
|
||||
<p>A form with normal button, two image buttons, submit button,
|
||||
HTML4 submit button:</p>
|
||||
<form name="form4" method="get">
|
||||
<input type="text" name="hi">
|
||||
<input id="f4_button" type="button" value="normal" name="normal-button">
|
||||
<input id="f4_image1" type="image" value="image-button1" name="image-button1">
|
||||
<input id="f4_image2" type="image" value="image-button2" name="image-button2">
|
||||
<input id="f4_submit" type="submit" value="real-submit" name="real-submit">
|
||||
<button id="f4_submitbutton" type="submit">submit</button>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -36,9 +36,6 @@
|
||||
// table with empty caption
|
||||
testAttrs("table4.2", attr, true);
|
||||
|
||||
// table with two captions
|
||||
testAbsentAttrs("table4.3", attr);
|
||||
|
||||
// table with th element
|
||||
testAbsentAttrs("table5", attr);
|
||||
|
||||
@ -48,8 +45,9 @@
|
||||
// table with tfoot element
|
||||
testAbsentAttrs("table7", attr);
|
||||
|
||||
// table with colgroup element
|
||||
// table with colgroup or col elements
|
||||
testAbsentAttrs("table8", attr);
|
||||
testAbsentAttrs("table8.2", attr);
|
||||
|
||||
// layout table with nested table
|
||||
testAttrs("table9", attr, true);
|
||||
@ -87,6 +85,14 @@
|
||||
// tree grid, no layout table
|
||||
testAbsentAttrs("table20", attr);
|
||||
|
||||
// layout table containing nested data table (having data structures)
|
||||
testAttrs("table21", attr, true);
|
||||
testAttrs("table21.2", attr, true);
|
||||
testAttrs("table21.3", attr, true);
|
||||
testAttrs("table21.4", attr, true);
|
||||
testAttrs("table21.5", attr, true);
|
||||
testAttrs("table21.6", attr, true);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
@ -101,6 +107,11 @@
|
||||
title="Don't treat tables that have a landmark role as layout table">
|
||||
Mozilla Bug 495388
|
||||
</a>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=690222"
|
||||
title="Data table elements used to determine layout-guess attribute shouldn't be picked from nested tables">
|
||||
Mozilla Bug 690222
|
||||
</a>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
@ -178,15 +189,6 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- table with two captions -->
|
||||
<table id="table4.3">
|
||||
<caption> </caption>
|
||||
<tr>
|
||||
<td>Cell1</td><td>cell2</td>
|
||||
</tr>
|
||||
<caption>a caption</caption>
|
||||
</table>
|
||||
|
||||
<!-- table with th element -->
|
||||
<table id="table5">
|
||||
<tr>
|
||||
@ -212,10 +214,17 @@
|
||||
</tfoot>
|
||||
</table>
|
||||
|
||||
<!-- table with colgroup element -->
|
||||
<!-- table with colgroup and col elements -->
|
||||
<table id="table8">
|
||||
<colgroup width="20"></colgroup>
|
||||
<tr>
|
||||
<colgroup><td>Cell1</td><td>cell2</td></colgroup>
|
||||
<td>Cell1</td><td>cell2</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table id="table8.2">
|
||||
<col width="20">
|
||||
<tr>
|
||||
<td>Cell1</td><td>cell2</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@ -339,5 +348,68 @@
|
||||
<table id="table20" role="treegrid">
|
||||
<tr role="treeitem"><td>Cell1</td><td>Cell2</td></tr>
|
||||
</table>
|
||||
|
||||
<!-- layout table with nested data table containing data table elements -->
|
||||
<table id="table21">
|
||||
<tr>
|
||||
<td>
|
||||
<table>
|
||||
<caption>table</caption>
|
||||
<tr><td>Cell</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table id="table21.2">
|
||||
<tr>
|
||||
<td>
|
||||
<table>
|
||||
<colgroup width="20"></colgroup>
|
||||
<tr><th>Cell</th></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table id="table21.3">
|
||||
<tr>
|
||||
<td>
|
||||
<table>
|
||||
<col width="20"></col>
|
||||
<tr><th>Cell</th></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table id="table21.4">
|
||||
<tr>
|
||||
<td>
|
||||
<table>
|
||||
<tr><th>Cell</th></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table id="table21.5">
|
||||
<tr>
|
||||
<td>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><td>Cell</td></tr>
|
||||
</thead>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table id="table21.6">
|
||||
<tr>
|
||||
<td>
|
||||
<table>
|
||||
<tfoot>
|
||||
<tr><td>Cell</td></tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -105,6 +105,14 @@
|
||||
label="&mediaHideControls.label;"
|
||||
accesskey="&mediaHideControls.accesskey;"
|
||||
oncommand="gContextMenu.mediaCommand('hidecontrols');"/>
|
||||
<menuitem id="context-video-showstats"
|
||||
accesskey="&videoShowStats.accesskey;"
|
||||
label="&videoShowStats.label;"
|
||||
oncommand="gContextMenu.mediaCommand('showstats');"/>
|
||||
<menuitem id="context-video-hidestats"
|
||||
accesskey="&videoHideStats.accesskey;"
|
||||
label="&videoHideStats.label;"
|
||||
oncommand="gContextMenu.mediaCommand('hidestats');"/>
|
||||
<menuitem id="context-video-fullscreen"
|
||||
accesskey="&videoFullScreen.accesskey;"
|
||||
label="&videoFullScreen.label;"
|
||||
@ -167,6 +175,10 @@
|
||||
label="&saveAudioCmd.label;"
|
||||
accesskey="&saveAudioCmd.accesskey;"
|
||||
oncommand="gContextMenu.saveMedia();"/>
|
||||
<menuitem id="context-video-saveimage"
|
||||
accesskey="&videoSaveImage.accesskey;"
|
||||
label="&videoSaveImage.label;"
|
||||
oncommand="gContextMenu.saveVideoFrameAsImage();"/>
|
||||
<menuitem id="context-sendvideo"
|
||||
label="&sendVideoCmd.label;"
|
||||
accesskey="&sendVideoCmd.accesskey;"
|
||||
|
@ -224,6 +224,7 @@ nsContextMenu.prototype = {
|
||||
this.showItem("context-saveimage", this.onLoadedImage || this.onCanvas);
|
||||
this.showItem("context-savevideo", this.onVideo);
|
||||
this.showItem("context-saveaudio", this.onAudio);
|
||||
this.showItem("context-video-saveimage", this.onVideo);
|
||||
this.setItemAttr("context-savevideo", "disabled", !this.mediaURL);
|
||||
this.setItemAttr("context-saveaudio", "disabled", !this.mediaURL);
|
||||
// Send media URL (but not for canvas, since it's a big data: URL)
|
||||
@ -417,6 +418,10 @@ nsContextMenu.prototype = {
|
||||
this.showItem("context-media-showcontrols", onMedia && !this.target.controls);
|
||||
this.showItem("context-media-hidecontrols", onMedia && this.target.controls);
|
||||
this.showItem("context-video-fullscreen", this.onVideo);
|
||||
var statsShowing = this.onVideo && this.target.wrappedJSObject.mozMediaStatisticsShowing;
|
||||
this.showItem("context-video-showstats", this.onVideo && this.target.controls && !statsShowing);
|
||||
this.showItem("context-video-hidestats", this.onVideo && this.target.controls && statsShowing);
|
||||
|
||||
// Disable them when there isn't a valid media source loaded.
|
||||
if (onMedia) {
|
||||
var hasError = this.target.error != null ||
|
||||
@ -427,8 +432,13 @@ nsContextMenu.prototype = {
|
||||
this.setItemAttr("context-media-unmute", "disabled", hasError);
|
||||
this.setItemAttr("context-media-showcontrols", "disabled", hasError);
|
||||
this.setItemAttr("context-media-hidecontrols", "disabled", hasError);
|
||||
if (this.onVideo)
|
||||
this.setItemAttr("context-video-fullscreen", "disabled", hasError);
|
||||
if (this.onVideo) {
|
||||
let canSaveSnapshot = this.target.readyState >= this.target.HAVE_CURRENT_DATA;
|
||||
this.setItemAttr("context-video-saveimage", "disabled", !canSaveSnapshot);
|
||||
this.setItemAttr("context-video-fullscreen", "disabled", hasError);
|
||||
this.setItemAttr("context-video-showstats", "disabled", hasError);
|
||||
this.setItemAttr("context-video-hidestats", "disabled", hasError);
|
||||
}
|
||||
}
|
||||
this.showItem("context-media-sep-commands", onMedia);
|
||||
},
|
||||
@ -826,6 +836,27 @@ nsContextMenu.prototype = {
|
||||
openUILink(viewURL, e, null, null, null, null, doc.documentURIObject );
|
||||
},
|
||||
|
||||
saveVideoFrameAsImage: function () {
|
||||
urlSecurityCheck(this.mediaURL, this.browser.contentPrincipal,
|
||||
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
|
||||
let name = "";
|
||||
try {
|
||||
let uri = makeURI(this.mediaURL);
|
||||
let url = uri.QueryInterface(Ci.nsIURL);
|
||||
if (url.fileBaseName)
|
||||
name = url.fileBaseName + ".jpg";
|
||||
} catch (e) { }
|
||||
if (!name)
|
||||
name = "snapshot.jpg";
|
||||
var video = this.target;
|
||||
var canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
||||
canvas.width = video.videoWidth;
|
||||
canvas.height = video.videoHeight;
|
||||
var ctxDraw = canvas.getContext("2d");
|
||||
ctxDraw.drawImage(video, 0, 0);
|
||||
saveImageURL(canvas.toDataURL("image/jpg", ""), name, "SaveImageTitle", true, false, document.documentURIObject);
|
||||
},
|
||||
|
||||
fullScreenVideo: function () {
|
||||
this.target.pause();
|
||||
|
||||
@ -1411,6 +1442,16 @@ nsContextMenu.prototype = {
|
||||
case "showcontrols":
|
||||
media.setAttribute("controls", "true");
|
||||
break;
|
||||
case "showstats":
|
||||
var event = document.createEvent("CustomEvent");
|
||||
event.initCustomEvent("media-showStatistics", false, true, true);
|
||||
media.dispatchEvent(event);
|
||||
break;
|
||||
case "hidestats":
|
||||
var event = document.createEvent("CustomEvent");
|
||||
event.initCustomEvent("media-showStatistics", false, true, false);
|
||||
media.dispatchEvent(event);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -59,7 +59,7 @@ let gSyncAddDevice = {
|
||||
pin2: this.pin3,
|
||||
pin3: this.wizard.getButton("next")};
|
||||
|
||||
this.throbber = document.getElementById("add-device-throbber");
|
||||
this.throbber = document.getElementById("pairDeviceThrobber");
|
||||
this.errorRow = document.getElementById("errorRow");
|
||||
|
||||
// Kick off a sync. That way the server will have the most recent data from
|
||||
@ -107,18 +107,33 @@ let gSyncAddDevice = {
|
||||
|
||||
startTransfer: function startTransfer() {
|
||||
this.errorRow.hidden = true;
|
||||
// When onAbort is called, Weave may already be gone.
|
||||
const JPAKE_ERROR_USERABORT = Weave.JPAKE_ERROR_USERABORT;
|
||||
|
||||
let self = this;
|
||||
this._jpakeclient = new Weave.JPAKEClient({
|
||||
let jpakeclient = this._jpakeclient = new Weave.JPAKEClient({
|
||||
onPaired: function onPaired() {
|
||||
let credentials = {account: Weave.Service.account,
|
||||
password: Weave.Service.password,
|
||||
synckey: Weave.Service.passphrase,
|
||||
serverURL: Weave.Service.serverURL};
|
||||
jpakeclient.sendAndComplete(credentials);
|
||||
},
|
||||
onComplete: function onComplete() {
|
||||
delete self._jpakeclient;
|
||||
self.wizard.pageIndex = DEVICE_CONNECTED_PAGE;
|
||||
|
||||
// Schedule a Sync for soonish to fetch the data uploaded by the
|
||||
// device with which we just paired.
|
||||
Weave.SyncScheduler.scheduleNextSync(Weave.SyncScheduler.activeInterval);
|
||||
},
|
||||
onAbort: function onAbort(error) {
|
||||
delete self._jpakeclient;
|
||||
|
||||
// Aborted by user, ignore.
|
||||
if (!error)
|
||||
if (error == JPAKE_ERROR_USERABORT) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.errorRow.hidden = false;
|
||||
self.throbber.hidden = true;
|
||||
@ -132,11 +147,8 @@ let gSyncAddDevice = {
|
||||
this.wizard.canAdvance = false;
|
||||
|
||||
let pin = this.pin1.value + this.pin2.value + this.pin3.value;
|
||||
let credentials = {account: Weave.Service.account,
|
||||
password: Weave.Service.password,
|
||||
synckey: Weave.Service.passphrase,
|
||||
serverURL: Weave.Service.serverURL};
|
||||
this._jpakeclient.sendWithPIN(pin, credentials);
|
||||
let expectDelay = false;
|
||||
jpakeclient.pairWithPIN(pin, expectDelay);
|
||||
},
|
||||
|
||||
onWizardBack: function onWizardBack() {
|
||||
|
@ -52,7 +52,7 @@
|
||||
<wizard xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
id="wizard"
|
||||
title="&addDevice.title.label;"
|
||||
title="&pairDevice.title.label;"
|
||||
windowtype="Sync:AddDevice"
|
||||
persist="screenX screenY"
|
||||
onwizardnext="return gSyncAddDevice.onWizardAdvance();"
|
||||
@ -70,10 +70,10 @@
|
||||
src="chrome://global/content/printUtils.js"/>
|
||||
|
||||
<wizardpage id="addDevicePage"
|
||||
label="&addDevice.title.label;"
|
||||
label="&pairDevice.title.label;"
|
||||
onpageshow="gSyncAddDevice.onPageShow();">
|
||||
<description>
|
||||
&addDevice.dialog.description.label;
|
||||
&pairDevice.dialog.description.label;
|
||||
<label class="text-link"
|
||||
value="&addDevice.showMeHow.label;"
|
||||
href="https://services.mozilla.com/sync/help/add-device"/>
|
||||
@ -101,7 +101,7 @@
|
||||
/>
|
||||
</vbox>
|
||||
<separator class="groove-thin"/>
|
||||
<vbox id="add-device-throbber" align="center" hidden="true">
|
||||
<vbox id="pairDeviceThrobber" align="center" hidden="true">
|
||||
<image/>
|
||||
</vbox>
|
||||
<hbox id="errorRow" pack="center" hidden="true">
|
||||
|
@ -56,19 +56,20 @@
|
||||
|
||||
<implementation>
|
||||
<constructor><![CDATA[
|
||||
Cu.import("resource://services-sync/ext/Observers.js");
|
||||
Cu.import("resource://services-sync/notifications.js");
|
||||
let temp = {};
|
||||
Cu.import("resource://services-sync/ext/Observers.js", temp);
|
||||
temp.Observers.add("weave:notification:added", this.onNotificationAdded, this);
|
||||
temp.Observers.add("weave:notification:removed", this.onNotificationRemoved, this);
|
||||
|
||||
Observers.add("weave:notification:added", this.onNotificationAdded, this);
|
||||
Observers.add("weave:notification:removed", this.onNotificationRemoved, this);
|
||||
|
||||
for each (var notification in Notifications.notifications)
|
||||
for each (var notification in Weave.Notifications.notifications)
|
||||
this._appendNotification(notification);
|
||||
]]></constructor>
|
||||
|
||||
<destructor><![CDATA[
|
||||
Observers.remove("weave:notification:added", this.onNotificationAdded, this);
|
||||
Observers.remove("weave:notification:removed", this.onNotificationRemoved, this);
|
||||
let temp = {};
|
||||
Cu.import("resource://services-sync/ext/Observers.js", temp);
|
||||
temp.Observers.remove("weave:notification:added", this.onNotificationAdded, this);
|
||||
temp.Observers.remove("weave:notification:removed", this.onNotificationRemoved, this);
|
||||
]]></destructor>
|
||||
|
||||
<method name="onNotificationAdded">
|
||||
@ -140,7 +141,7 @@
|
||||
onset="this._notification = val; return val;"/>
|
||||
<method name="close">
|
||||
<body><![CDATA[
|
||||
Notifications.remove(this.notification);
|
||||
Weave.Notifications.remove(this.notification);
|
||||
|
||||
// We should be able to call the base class's close method here
|
||||
// to remove the notification element from the notification box,
|
||||
|
@ -46,33 +46,38 @@ const Cu = Components.utils;
|
||||
|
||||
// page consts
|
||||
|
||||
const INTRO_PAGE = 0;
|
||||
const NEW_ACCOUNT_START_PAGE = 1;
|
||||
const NEW_ACCOUNT_PP_PAGE = 2;
|
||||
const NEW_ACCOUNT_CAPTCHA_PAGE = 3;
|
||||
const EXISTING_ACCOUNT_CONNECT_PAGE = 4;
|
||||
const EXISTING_ACCOUNT_LOGIN_PAGE = 5;
|
||||
const OPTIONS_PAGE = 6;
|
||||
const OPTIONS_CONFIRM_PAGE = 7;
|
||||
const SETUP_SUCCESS_PAGE = 8;
|
||||
const PAIR_PAGE = 0;
|
||||
const INTRO_PAGE = 1;
|
||||
const NEW_ACCOUNT_START_PAGE = 2;
|
||||
const EXISTING_ACCOUNT_CONNECT_PAGE = 3;
|
||||
const EXISTING_ACCOUNT_LOGIN_PAGE = 4;
|
||||
const OPTIONS_PAGE = 5;
|
||||
const OPTIONS_CONFIRM_PAGE = 6;
|
||||
const SETUP_SUCCESS_PAGE = 7;
|
||||
|
||||
// Broader than we'd like, but after this changed from api-secure.recaptcha.net
|
||||
// we had no choice. At least we only do this for the duration of setup.
|
||||
// See discussion in Bugs 508112 and 653307.
|
||||
const RECAPTCHA_DOMAIN = "https://www.google.com";
|
||||
|
||||
const PIN_PART_LENGTH = 4;
|
||||
|
||||
Cu.import("resource://services-sync/main.js");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/PlacesUtils.jsm");
|
||||
Cu.import("resource://gre/modules/PluralForm.jsm");
|
||||
|
||||
|
||||
function setVisibility(element, visible) {
|
||||
element.style.visibility = visible ? "visible" : "hidden";
|
||||
}
|
||||
|
||||
var gSyncSetup = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
|
||||
Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
|
||||
haveCaptcha: true,
|
||||
captchaBrowser: null,
|
||||
wizard: null,
|
||||
_disabledSites: [],
|
||||
@ -120,17 +125,23 @@ var gSyncSetup = {
|
||||
}, 0);
|
||||
|
||||
this.captchaBrowser = document.getElementById("captcha");
|
||||
this.wizard = document.getElementById("accountSetup");
|
||||
|
||||
if (window.arguments && window.arguments[0] == true) {
|
||||
// we're resetting sync
|
||||
this._resettingSync = true;
|
||||
this.wizard.pageIndex = OPTIONS_PAGE;
|
||||
this.wizardType = null;
|
||||
if (window.arguments && window.arguments[0]) {
|
||||
this.wizardType = window.arguments[0];
|
||||
}
|
||||
else {
|
||||
this.wizard.canAdvance = false;
|
||||
this.captchaBrowser.addProgressListener(this);
|
||||
Weave.Svc.Prefs.set("firstSync", "notReady");
|
||||
switch (this.wizardType) {
|
||||
case null:
|
||||
this.wizard.pageIndex = INTRO_PAGE;
|
||||
// Fall through!
|
||||
case "pair":
|
||||
this.captchaBrowser.addProgressListener(this);
|
||||
Weave.Svc.Prefs.set("firstSync", "notReady");
|
||||
break;
|
||||
case "reset":
|
||||
this._resettingSync = true;
|
||||
this.wizard.pageIndex = OPTIONS_PAGE;
|
||||
break;
|
||||
}
|
||||
|
||||
this.wizard.getButton("extra1").label =
|
||||
@ -150,14 +161,19 @@ var gSyncSetup = {
|
||||
return false;
|
||||
this._settingUpNew = true;
|
||||
this.wizard.pageIndex = NEW_ACCOUNT_START_PAGE;
|
||||
this.loadCaptcha();
|
||||
},
|
||||
|
||||
useExistingAccount: function () {
|
||||
if (!Weave.Utils.ensureMPUnlocked())
|
||||
return false;
|
||||
this._settingUpNew = false;
|
||||
this.wizard.pageIndex = EXISTING_ACCOUNT_CONNECT_PAGE;
|
||||
if (this.wizardType == "pair") {
|
||||
// We're already pairing, so there's no point in pairing again.
|
||||
// Go straight to the manual login page.
|
||||
this.wizard.pageIndex = EXISTING_ACCOUNT_LOGIN_PAGE;
|
||||
} else {
|
||||
this.wizard.pageIndex = EXISTING_ACCOUNT_CONNECT_PAGE;
|
||||
}
|
||||
},
|
||||
|
||||
resetPassphrase: function resetPassphrase() {
|
||||
@ -207,6 +223,20 @@ var gSyncSetup = {
|
||||
this.toggleLoginFeedback(true);
|
||||
},
|
||||
|
||||
sendCredentialsAfterSync: function () {
|
||||
let send = function() {
|
||||
Services.obs.removeObserver("weave:service:sync:finish", send);
|
||||
Services.obs.removeObserver("weave:service:sync:error", send);
|
||||
let credentials = {account: Weave.Service.account,
|
||||
password: Weave.Service.password,
|
||||
synckey: Weave.Service.passphrase,
|
||||
serverURL: Weave.Service.serverURL};
|
||||
this._jpakeclient.sendAndComplete(credentials);
|
||||
}.bind(this);
|
||||
Services.obs.addObserver("weave:service:sync:finish", send, false);
|
||||
Services.obs.addObserver("weave:service:sync:error", send, false);
|
||||
},
|
||||
|
||||
toggleLoginFeedback: function (stop) {
|
||||
document.getElementById("login-throbber").hidden = stop;
|
||||
let password = document.getElementById("existingPasswordFeedbackRow");
|
||||
@ -289,6 +319,15 @@ var gSyncSetup = {
|
||||
return true;
|
||||
},
|
||||
|
||||
onPINInput: function onPINInput(textbox) {
|
||||
if (textbox && textbox.value.length == PIN_PART_LENGTH) {
|
||||
this.nextFocusEl[textbox.id].focus();
|
||||
}
|
||||
this.wizard.canAdvance = (this.pin1.value.length == PIN_PART_LENGTH &&
|
||||
this.pin2.value.length == PIN_PART_LENGTH &&
|
||||
this.pin3.value.length == PIN_PART_LENGTH);
|
||||
},
|
||||
|
||||
onEmailInput: function () {
|
||||
// Check account validity when the user stops typing for 1 second.
|
||||
if (this._checkAccountTimer)
|
||||
@ -335,16 +374,8 @@ var gSyncSetup = {
|
||||
|
||||
onPasswordChange: function () {
|
||||
let password = document.getElementById("weavePassword");
|
||||
let valid, str;
|
||||
if (password.value == document.getElementById("weavePassphrase").value) {
|
||||
// xxxmpc - hack, sigh
|
||||
valid = false;
|
||||
errorString = Weave.Utils.getErrorString("change.password.pwSameAsRecoveryKey");
|
||||
}
|
||||
else {
|
||||
let pwconfirm = document.getElementById("weavePasswordConfirm");
|
||||
[valid, errorString] = gSyncUtils.validatePassword(password, pwconfirm);
|
||||
}
|
||||
let pwconfirm = document.getElementById("weavePasswordConfirm");
|
||||
let [valid, errorString] = gSyncUtils.validatePassword(password, pwconfirm);
|
||||
|
||||
let feedback = document.getElementById("passwordFeedbackRow");
|
||||
this._setFeedback(feedback, valid, errorString);
|
||||
@ -353,32 +384,24 @@ var gSyncSetup = {
|
||||
this.checkFields();
|
||||
},
|
||||
|
||||
onPassphraseGenerate: function () {
|
||||
let passphrase = Weave.Utils.generatePassphrase();
|
||||
Weave.Service.passphrase = passphrase;
|
||||
let el = document.getElementById("weavePassphrase");
|
||||
el.value = Weave.Utils.hyphenatePassphrase(passphrase);
|
||||
},
|
||||
|
||||
onPageShow: function() {
|
||||
switch (this.wizard.pageIndex) {
|
||||
case PAIR_PAGE:
|
||||
this.wizard.getButton("back").hidden = true;
|
||||
this.wizard.getButton("extra1").hidden = true;
|
||||
this.onPINInput();
|
||||
this.pin1.focus();
|
||||
break;
|
||||
case INTRO_PAGE:
|
||||
// We may not need the captcha in the Existing Account branch of the
|
||||
// wizard. However, we want to preload it to avoid any flickering while
|
||||
// the Create Account page is shown.
|
||||
this.loadCaptcha();
|
||||
this.wizard.getButton("next").hidden = true;
|
||||
this.wizard.getButton("back").hidden = true;
|
||||
this.wizard.getButton("extra1").hidden = true;
|
||||
break;
|
||||
case NEW_ACCOUNT_PP_PAGE:
|
||||
document.getElementById("saveSyncKeyButton").focus();
|
||||
let el = document.getElementById("weavePassphrase");
|
||||
if (!el.value)
|
||||
this.onPassphraseGenerate();
|
||||
this.checkFields();
|
||||
break;
|
||||
case NEW_ACCOUNT_CAPTCHA_PAGE:
|
||||
if (!this.haveCaptcha) {
|
||||
gSyncSetup.wizard.advance();
|
||||
}
|
||||
break;
|
||||
case NEW_ACCOUNT_START_PAGE:
|
||||
this.wizard.getButton("extra1").hidden = false;
|
||||
this.wizard.getButton("next").hidden = false;
|
||||
@ -396,6 +419,9 @@ var gSyncSetup = {
|
||||
this.startEasySetup();
|
||||
break;
|
||||
case EXISTING_ACCOUNT_LOGIN_PAGE:
|
||||
this.wizard.getButton("next").hidden = false;
|
||||
this.wizard.getButton("back").hidden = false;
|
||||
this.wizard.getButton("extra1").hidden = false;
|
||||
this.wizard.canRewind = true;
|
||||
this.checkFields();
|
||||
break;
|
||||
@ -407,6 +433,9 @@ var gSyncSetup = {
|
||||
this.wizard.getButton("cancel").hidden = true;
|
||||
this.wizard.getButton("finish").hidden = false;
|
||||
this._handleSuccess();
|
||||
if (this.wizardType == "pair") {
|
||||
this.completePairing();
|
||||
}
|
||||
break;
|
||||
case OPTIONS_PAGE:
|
||||
this.wizard.canRewind = false;
|
||||
@ -445,19 +474,23 @@ var gSyncSetup = {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.wizard.pageIndex)
|
||||
return true;
|
||||
|
||||
switch (this.wizard.pageIndex) {
|
||||
case PAIR_PAGE:
|
||||
this.startPairing();
|
||||
return false;
|
||||
case NEW_ACCOUNT_START_PAGE:
|
||||
// If the user selects Next (e.g. by hitting enter) when we haven't
|
||||
// executed the delayed checks yet, execute them immediately.
|
||||
if (this._checkAccountTimer)
|
||||
if (this._checkAccountTimer) {
|
||||
this.checkAccount();
|
||||
if (this._checkServerTimer)
|
||||
}
|
||||
if (this._checkServerTimer) {
|
||||
this.checkServer();
|
||||
return this.wizard.canAdvance;
|
||||
case NEW_ACCOUNT_CAPTCHA_PAGE:
|
||||
}
|
||||
if (!this.wizard.canAdvance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let doc = this.captchaBrowser.contentDocument;
|
||||
let getField = function getField(field) {
|
||||
let node = doc.getElementById("recaptcha_" + field + "_field");
|
||||
@ -470,7 +503,7 @@ var gSyncSetup = {
|
||||
let label = image.nextSibling;
|
||||
image.setAttribute("status", "active");
|
||||
label.value = this._stringBundle.GetStringFromName("verifying.label");
|
||||
feedback.hidden = false;
|
||||
setVisibility(feedback, true);
|
||||
|
||||
let password = document.getElementById("weavePassword").value;
|
||||
let email = Weave.Utils.normalizeAccount(
|
||||
@ -484,6 +517,7 @@ var gSyncSetup = {
|
||||
if (error == null) {
|
||||
Weave.Service.account = email;
|
||||
Weave.Service.password = password;
|
||||
Weave.Service.passphrase = Weave.Utils.generatePassphrase();
|
||||
this._handleNoScript(false);
|
||||
this.wizard.pageIndex = SETUP_SUCCESS_PAGE;
|
||||
return false;
|
||||
@ -529,6 +563,15 @@ var gSyncSetup = {
|
||||
this.abortEasySetup();
|
||||
this.wizard.pageIndex = INTRO_PAGE;
|
||||
return false;
|
||||
case EXISTING_ACCOUNT_LOGIN_PAGE:
|
||||
// If we were already pairing on entry, we went straight to the manual
|
||||
// login page. If subsequently we go back, return to the page that lets
|
||||
// us choose whether we already have an account.
|
||||
if (this.wizardType == "pair") {
|
||||
this.wizard.pageIndex = INTRO_PAGE;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
case OPTIONS_CONFIRM_PAGE:
|
||||
// Backing up from the confirmation page = resetting first sync to merge.
|
||||
document.getElementById("mergeChoiceRadio").selectedIndex = 0;
|
||||
@ -594,6 +637,59 @@ var gSyncSetup = {
|
||||
return false;
|
||||
},
|
||||
|
||||
startPairing: function startPairing() {
|
||||
this.pairDeviceErrorRow.hidden = true;
|
||||
// When onAbort is called, Weave may already be gone.
|
||||
const JPAKE_ERROR_USERABORT = Weave.JPAKE_ERROR_USERABORT;
|
||||
|
||||
let self = this;
|
||||
let jpakeclient = this._jpakeclient = new Weave.JPAKEClient({
|
||||
onPaired: function onPaired() {
|
||||
self.wizard.pageIndex = INTRO_PAGE;
|
||||
},
|
||||
onComplete: function onComplete() {
|
||||
// This method will never be called since SendCredentialsController
|
||||
// will take over after the wizard completes.
|
||||
},
|
||||
onAbort: function onAbort(error) {
|
||||
delete self._jpakeclient;
|
||||
|
||||
// Aborted by user, ignore. The window is almost certainly going to close
|
||||
// or is already closed.
|
||||
if (error == JPAKE_ERROR_USERABORT) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.pairDeviceErrorRow.hidden = false;
|
||||
self.pairDeviceThrobber.hidden = true;
|
||||
self.pin1.value = self.pin2.value = self.pin3.value = "";
|
||||
self.pin1.disabled = self.pin2.disabled = self.pin3.disabled = false;
|
||||
if (self.wizard.pageIndex == PAIR_PAGE) {
|
||||
self.pin1.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
this.pairDeviceThrobber.hidden = false;
|
||||
this.pin1.disabled = this.pin2.disabled = this.pin3.disabled = true;
|
||||
this.wizard.canAdvance = false;
|
||||
|
||||
let pin = this.pin1.value + this.pin2.value + this.pin3.value;
|
||||
let expectDelay = true;
|
||||
jpakeclient.pairWithPIN(pin, expectDelay);
|
||||
},
|
||||
|
||||
completePairing: function completePairing() {
|
||||
if (!this._jpakeclient) {
|
||||
// The channel was aborted while we were setting up the account
|
||||
// locally. XXX TODO should we do anything here, e.g. tell
|
||||
// the user on the last wizard page that it's ok, they just
|
||||
// have to pair again?
|
||||
return;
|
||||
}
|
||||
let controller = new Weave.SendCredentialsController(this._jpakeclient);
|
||||
this._jpakeclient.controller = controller;
|
||||
},
|
||||
|
||||
startEasySetup: function () {
|
||||
// Don't do anything if we have a client already (e.g. we went to
|
||||
// Sync Options and just came back).
|
||||
@ -611,6 +707,8 @@ var gSyncSetup = {
|
||||
document.getElementById("easySetupPIN3").value = pin.slice(8);
|
||||
},
|
||||
|
||||
onPairingStart: function onPairingStart() {},
|
||||
|
||||
onComplete: function onComplete(credentials) {
|
||||
Weave.Service.account = credentials.account;
|
||||
Weave.Service.password = credentials.password;
|
||||
@ -708,7 +806,7 @@ var gSyncSetup = {
|
||||
},
|
||||
|
||||
onServerCommand: function () {
|
||||
document.getElementById("TOSRow").hidden = !this._usingMainServers;
|
||||
setVisibility(document.getElementById("TOSRow"), this._usingMainServers);
|
||||
let control = document.getElementById("server");
|
||||
if (!this._usingMainServers) {
|
||||
control.setAttribute("editable", "true");
|
||||
@ -962,9 +1060,12 @@ var gSyncSetup = {
|
||||
},
|
||||
|
||||
loadCaptcha: function loadCaptcha() {
|
||||
let captchaURI = Weave.Service.miscAPI + "captcha_html";
|
||||
// First check for NoScript and whitelist the right sites.
|
||||
this._handleNoScript(true);
|
||||
this.captchaBrowser.loadURI(Weave.Service.miscAPI + "captcha_html");
|
||||
if (this.captchaBrowser.currentURI.spec != captchaURI) {
|
||||
this.captchaBrowser.loadURI(captchaURI);
|
||||
}
|
||||
},
|
||||
|
||||
onStateChange: function(webProgress, request, stateFlags, status) {
|
||||
@ -976,30 +1077,36 @@ var gSyncSetup = {
|
||||
if ((stateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) == 0)
|
||||
return;
|
||||
|
||||
// If we didn't find the captcha, assume it's not needed and move on
|
||||
if (request.QueryInterface(Ci.nsIHttpChannel).responseStatus == 404) {
|
||||
this.haveCaptcha = false;
|
||||
// Hide the browser just in case we end up displaying the captcha page
|
||||
// due to a sign up error.
|
||||
this.captchaBrowser.hidden = true;
|
||||
if (this.wizard.pageIndex == NEW_ACCOUNT_CAPTCHA_PAGE) {
|
||||
this.onWizardAdvance();
|
||||
}
|
||||
} else {
|
||||
this.haveCaptcha = true;
|
||||
this.captchaBrowser.hidden = false;
|
||||
}
|
||||
// If we didn't find a captcha, assume it's not needed and don't show it.
|
||||
let responseStatus = request.QueryInterface(Ci.nsIHttpChannel).responseStatus;
|
||||
setVisibility(this.captchaBrowser, responseStatus != 404);
|
||||
//XXX TODO we should really log any responseStatus other than 200
|
||||
},
|
||||
onProgressChange: function() {},
|
||||
onStatusChange: function() {},
|
||||
onSecurityChange: function() {},
|
||||
onLocationChange: function () {}
|
||||
}
|
||||
};
|
||||
|
||||
// onWizardAdvance() and onPageShow() are run before init(), so we'll set
|
||||
// wizard & _stringBundle up as lazy getters.
|
||||
XPCOMUtils.defineLazyGetter(gSyncSetup, "wizard", function() {
|
||||
return document.getElementById("accountSetup");
|
||||
// Define lazy getters for various XUL elements.
|
||||
//
|
||||
// onWizardAdvance() and onPageShow() are run before init(), so we'll even
|
||||
// define things that will almost certainly be used (like 'wizard') as a lazy
|
||||
// getter here.
|
||||
["wizard",
|
||||
"pin1",
|
||||
"pin2",
|
||||
"pin3",
|
||||
"pairDeviceErrorRow",
|
||||
"pairDeviceThrobber"].forEach(function (id) {
|
||||
XPCOMUtils.defineLazyGetter(gSyncSetup, id, function() {
|
||||
return document.getElementById(id);
|
||||
});
|
||||
});
|
||||
XPCOMUtils.defineLazyGetter(gSyncSetup, "nextFocusEl", function () {
|
||||
return {pin1: this.pin2,
|
||||
pin2: this.pin3,
|
||||
pin3: this.wizard.getButton("next")};
|
||||
});
|
||||
XPCOMUtils.defineLazyGetter(gSyncSetup, "_stringBundle", function() {
|
||||
return Services.strings.createBundle("chrome://browser/locale/syncSetup.properties");
|
||||
|
@ -52,7 +52,8 @@
|
||||
%syncBrandDTD;
|
||||
%syncSetupDTD;
|
||||
]>
|
||||
<wizard id="accountSetup" title="&accountSetupTitle.label;"
|
||||
<wizard id="wizard"
|
||||
title="&accountSetupTitle.label;"
|
||||
windowtype="Weave:AccountSetup"
|
||||
persist="screenX screenY"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
@ -72,6 +73,48 @@
|
||||
<script type="application/javascript"
|
||||
src="chrome://global/content/printUtils.js"/>
|
||||
|
||||
<wizardpage id="addDevicePage"
|
||||
label="&pairDevice.title.label;"
|
||||
onpageshow="gSyncSetup.onPageShow()">
|
||||
<description>
|
||||
&pairDevice.dialog.description.label;
|
||||
<label class="text-link"
|
||||
value="&addDevice.showMeHow.label;"
|
||||
href="https://services.mozilla.com/sync/help/add-device"/>
|
||||
</description>
|
||||
<separator class="groove-thin"/>
|
||||
<description>
|
||||
&addDevice.dialog.enterCode.label;
|
||||
</description>
|
||||
<separator class="groove-thin"/>
|
||||
<vbox align="center">
|
||||
<textbox id="pin1"
|
||||
class="pin"
|
||||
oninput="gSyncSetup.onPINInput(this);"
|
||||
onfocus="this.select();"
|
||||
/>
|
||||
<textbox id="pin2"
|
||||
class="pin"
|
||||
oninput="gSyncSetup.onPINInput(this);"
|
||||
onfocus="this.select();"
|
||||
/>
|
||||
<textbox id="pin3"
|
||||
class="pin"
|
||||
oninput="gSyncSetup.onPINInput(this);"
|
||||
onfocus="this.select();"
|
||||
/>
|
||||
</vbox>
|
||||
<separator class="groove-thin"/>
|
||||
<vbox id="pairDeviceThrobber" align="center" hidden="true">
|
||||
<image/>
|
||||
</vbox>
|
||||
<hbox id="pairDeviceErrorRow" pack="center" hidden="true">
|
||||
<image class="statusIcon" status="error"/>
|
||||
<label class="status"
|
||||
value="&addDevice.dialog.tryAgain.label;"/>
|
||||
</hbox>
|
||||
</wizardpage>
|
||||
|
||||
<wizardpage id="pickSetupType"
|
||||
label="&syncBrand.fullName.label;"
|
||||
onpageshow="gSyncSetup.onPageShow()">
|
||||
@ -79,22 +122,20 @@
|
||||
<description style="padding: 0 7em;">
|
||||
&setup.pickSetupType.description;
|
||||
</description>
|
||||
<spacer flex="1"/>
|
||||
<spacer flex="3"/>
|
||||
<button id="newAccount"
|
||||
class="accountChoiceButton"
|
||||
label="&button.createNewAccount.label;"
|
||||
oncommand="gSyncSetup.startNewAccountSetup()"
|
||||
align="center"/>
|
||||
<spacer flex="3"/>
|
||||
<spacer flex="1"/>
|
||||
</vbox>
|
||||
<separator class="groove"/>
|
||||
<vbox align="center" flex="1">
|
||||
<spacer flex="3"/>
|
||||
<label value="&setup.haveAccount.label;" />
|
||||
<spacer flex="1"/>
|
||||
<button id="existingAccount"
|
||||
class="accountChoiceButton"
|
||||
label="&button.connect.label;"
|
||||
label="&button.haveAccount.label;"
|
||||
oncommand="gSyncSetup.useExistingAccount()"/>
|
||||
<spacer flex="3"/>
|
||||
</vbox>
|
||||
@ -194,64 +235,27 @@
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</wizardpage>
|
||||
|
||||
<wizardpage label="&setup.newRecoveryKeyPage.title.label;"
|
||||
onextra1="gSyncSetup.onSyncOptions()"
|
||||
onpageshow="gSyncSetup.onPageShow();">
|
||||
<description>
|
||||
&setup.newRecoveryKeyPage.description.label;
|
||||
</description>
|
||||
<spacer/>
|
||||
|
||||
<groupbox>
|
||||
<label value="&recoveryKeyEntry.label;"
|
||||
accesskey="&recoveryKeyEntry.accesskey;"
|
||||
control="weavePassphrase"/>
|
||||
<textbox id="weavePassphrase"
|
||||
readonly="true"
|
||||
onfocus="this.select();"/>
|
||||
</groupbox>
|
||||
|
||||
<groupbox align="center">
|
||||
<description>&recoveryKeyBackup.description;</description>
|
||||
<hbox>
|
||||
<button id="printSyncKeyButton"
|
||||
label="&button.syncKeyBackup.print.label;"
|
||||
accesskey="&button.syncKeyBackup.print.accesskey;"
|
||||
oncommand="gSyncUtils.passphrasePrint('weavePassphrase');"/>
|
||||
<button id="saveSyncKeyButton"
|
||||
label="&button.syncKeyBackup.save.label;"
|
||||
accesskey="&button.syncKeyBackup.save.accesskey;"
|
||||
oncommand="gSyncUtils.passphraseSave('weavePassphrase');"/>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
</wizardpage>
|
||||
|
||||
<wizardpage label="&setup.captchaPage2.title.label;"
|
||||
onextra1="gSyncSetup.onSyncOptions()"
|
||||
onpageshow="gSyncSetup.onPageShow();">
|
||||
<spacer flex="1"/>
|
||||
<vbox flex="1" align="center">
|
||||
<browser height="150"
|
||||
width="450"
|
||||
width="500"
|
||||
id="captcha"
|
||||
type="content"
|
||||
disablehistory="true"/>
|
||||
<spacer flex="1"/>
|
||||
<hbox id="captchaFeedback" hidden="true">
|
||||
<hbox id="captchaFeedback">
|
||||
<image class="statusIcon"/>
|
||||
<label class="status" value=" "/>
|
||||
</hbox>
|
||||
<spacer flex="3"/>
|
||||
</vbox>
|
||||
</wizardpage>
|
||||
|
||||
<wizardpage id="addDevice"
|
||||
label="&addDevice.title.label;"
|
||||
label="&pairDevice.title.label;"
|
||||
onextra1="gSyncSetup.onSyncOptions()"
|
||||
onpageshow="gSyncSetup.onPageShow()">
|
||||
<description>
|
||||
&addDevice.setup.description.label;
|
||||
&pairDevice.setup.description.label;
|
||||
<label class="text-link"
|
||||
value="&addDevice.showMeHow.label;"
|
||||
href="https://services.mozilla.com/sync/help/easy-setup"/>
|
||||
|
@ -1297,9 +1297,6 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||
// Returns true if the groupItem, given "count", should stack (instead of
|
||||
// grid).
|
||||
shouldStack: function GroupItem_shouldStack(count) {
|
||||
if (count <= 1)
|
||||
return false;
|
||||
|
||||
let bb = this.getContentBounds();
|
||||
let options = {
|
||||
return: 'widthAndColumns',
|
||||
@ -2380,15 +2377,13 @@ let GroupItems = {
|
||||
}
|
||||
|
||||
let targetGroupItem;
|
||||
// find first visible non-app tab in the tabbar.
|
||||
// find first non-app visible tab belongs a group, and add the new tabItem
|
||||
// to that group
|
||||
gBrowser.visibleTabs.some(function(tab) {
|
||||
if (!tab.pinned && tab != tabItem.tab) {
|
||||
if (tab._tabViewTabItem) {
|
||||
if (!tab._tabViewTabItem.parent && !tab._tabViewTabItem.parent.hidden) {
|
||||
// the first visible tab belongs to a group, add the new tabItem to
|
||||
// that group
|
||||
targetGroupItem = tab._tabViewTabItem.parent;
|
||||
}
|
||||
if (tab._tabViewTabItem && tab._tabViewTabItem.parent &&
|
||||
!tab._tabViewTabItem.parent.hidden) {
|
||||
targetGroupItem = tab._tabViewTabItem.parent;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -53,80 +53,23 @@
|
||||
// Title: search.js
|
||||
// Implementation for the search functionality of Firefox Panorama.
|
||||
|
||||
// ----------
|
||||
// Function: scorePatternMatch
|
||||
// Given a pattern string, returns a score between 0 and 1 of how well
|
||||
// that pattern matches the original string. It mimics the heuristics
|
||||
// of the Mac application launcher Quicksilver.
|
||||
function scorePatternMatch(pattern, matched, offset) {
|
||||
offset = offset || 0;
|
||||
pattern = pattern.toLowerCase();
|
||||
matched = matched.toLowerCase();
|
||||
|
||||
if (pattern.length == 0) return 0.9;
|
||||
if (pattern.length > matched.length) return 0.0;
|
||||
|
||||
for (var i = pattern.length; i > 0; i--) {
|
||||
var sub_pattern = pattern.substring(0,i);
|
||||
var index = matched.indexOf(sub_pattern);
|
||||
|
||||
if (index < 0) continue;
|
||||
if (index + pattern.length > matched.length + offset) continue;
|
||||
|
||||
var next_string = matched.substring(index+sub_pattern.length);
|
||||
var next_pattern = null;
|
||||
|
||||
if (i >= pattern.length)
|
||||
next_pattern = '';
|
||||
else
|
||||
next_pattern = pattern.substring(i);
|
||||
|
||||
var remaining_score =
|
||||
scorePatternMatch(next_pattern, next_string, offset + index);
|
||||
|
||||
if (remaining_score > 0) {
|
||||
var score = matched.length-next_string.length;
|
||||
|
||||
if (index != 0) {
|
||||
var j = 0;
|
||||
|
||||
var c = matched.charCodeAt(index-1);
|
||||
if (c == 32 || c == 9) {
|
||||
for (var j = (index - 2); j >= 0; j--) {
|
||||
c = matched.charCodeAt(j);
|
||||
score -= ((c == 32 || c == 9) ? 1 : 0.15);
|
||||
}
|
||||
} else {
|
||||
score -= index;
|
||||
}
|
||||
}
|
||||
|
||||
score += remaining_score * next_string.length;
|
||||
score /= matched.length;
|
||||
return score;
|
||||
}
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// ##########
|
||||
// Class: TabUtils
|
||||
//
|
||||
// A collection of helper functions for dealing with both
|
||||
// <TabItem>s and <xul:tab>s without having to worry which
|
||||
// one is which.
|
||||
var TabUtils = {
|
||||
//
|
||||
// A collection of helper functions for dealing with both <TabItem>s and
|
||||
// <xul:tab>s without having to worry which one is which.
|
||||
let TabUtils = {
|
||||
// ----------
|
||||
// Function: toString
|
||||
// Prints [TabUtils] for debug use
|
||||
// Prints [TabUtils] for debug use.
|
||||
toString: function TabUtils_toString() {
|
||||
return "[TabUtils]";
|
||||
},
|
||||
|
||||
// ---------
|
||||
// Function: _nameOfTab
|
||||
// Function: nameOfTab
|
||||
// Given a <TabItem> or a <xul:tab> returns the tab's name.
|
||||
nameOf: function TabUtils_nameOfTab(tab) {
|
||||
nameOf: function TabUtils_nameOf(tab) {
|
||||
// We can have two types of tabs: A <TabItem> or a <xul:tab>
|
||||
// because we have to deal with both tabs represented inside
|
||||
// of active Panoramas as well as for windows in which
|
||||
@ -134,88 +77,88 @@ var TabUtils = {
|
||||
// determine the type of tab and then returns its name.
|
||||
return tab.label != undefined ? tab.label : tab.$tabTitle[0].textContent;
|
||||
},
|
||||
|
||||
|
||||
// ---------
|
||||
// Function: URLOf
|
||||
// Given a <TabItem> or a <xul:tab> returns the URL of tab
|
||||
// Given a <TabItem> or a <xul:tab> returns the URL of tab.
|
||||
URLOf: function TabUtils_URLOf(tab) {
|
||||
// Convert a <TabItem> to <xul:tab>
|
||||
if(tab.tab != undefined)
|
||||
if ("tab" in tab)
|
||||
tab = tab.tab;
|
||||
return tab.linkedBrowser.currentURI.spec;
|
||||
},
|
||||
|
||||
// ---------
|
||||
// Function: favURLOf
|
||||
// Function: faviconURLOf
|
||||
// Given a <TabItem> or a <xul:tab> returns the URL of tab's favicon.
|
||||
faviconURLOf: function TabUtils_faviconURLOf(tab) {
|
||||
return tab.image != undefined ? tab.image : tab.$favImage[0].src;
|
||||
},
|
||||
|
||||
|
||||
// ---------
|
||||
// Function: focus
|
||||
// Given a <TabItem> or a <xul:tab>, focuses it and it's window.
|
||||
focus: function TabUtils_focus(tab) {
|
||||
// Convert a <TabItem> to a <xul:tab>
|
||||
if (tab.tab != undefined) tab = tab.tab;
|
||||
if ("tab" in tab)
|
||||
tab = tab.tab;
|
||||
tab.ownerDocument.defaultView.gBrowser.selectedTab = tab;
|
||||
tab.ownerDocument.defaultView.focus();
|
||||
tab.ownerDocument.defaultView.focus();
|
||||
}
|
||||
};
|
||||
|
||||
// ##########
|
||||
// Class: TabMatcher
|
||||
//
|
||||
// A singleton class that allows you to iterate over
|
||||
// matching and not-matching tabs, given a case-insensitive
|
||||
// search term.
|
||||
function TabMatcher(term) {
|
||||
this.term = term;
|
||||
//
|
||||
// A class that allows you to iterate over matching and not-matching tabs,
|
||||
// given a case-insensitive search term.
|
||||
function TabMatcher(term) {
|
||||
this.term = term;
|
||||
}
|
||||
|
||||
TabMatcher.prototype = {
|
||||
// ----------
|
||||
// Function: toString
|
||||
// Prints [TabMatcher (term)] for debug use
|
||||
// Prints [TabMatcher (term)] for debug use.
|
||||
toString: function TabMatcher_toString() {
|
||||
return "[TabMatcher (" + this.term + ")]";
|
||||
},
|
||||
|
||||
// ---------
|
||||
// Function: _filterAndSortMatches
|
||||
// Function: _filterAndSortForMatches
|
||||
// Given an array of <TabItem>s and <xul:tab>s returns a new array
|
||||
// of tabs whose name matched the search term, sorted by lexical
|
||||
// closeness.
|
||||
// closeness.
|
||||
_filterAndSortForMatches: function TabMatcher__filterAndSortForMatches(tabs) {
|
||||
var self = this;
|
||||
tabs = tabs.filter(function(tab){
|
||||
let self = this;
|
||||
tabs = tabs.filter(function TabMatcher__filterAndSortForMatches_filter(tab) {
|
||||
let name = TabUtils.nameOf(tab);
|
||||
let url = TabUtils.URLOf(tab);
|
||||
return name.match(self.term, "i") || url.match(self.term, "i");
|
||||
});
|
||||
|
||||
tabs.sort(function sorter(x, y){
|
||||
var yScore = scorePatternMatch(self.term, TabUtils.nameOf(y));
|
||||
var xScore = scorePatternMatch(self.term, TabUtils.nameOf(x));
|
||||
return yScore - xScore;
|
||||
tabs.sort(function TabMatcher__filterAndSortForMatches_sort(x, y) {
|
||||
let yScore = self._scorePatternMatch(self.term, TabUtils.nameOf(y));
|
||||
let xScore = self._scorePatternMatch(self.term, TabUtils.nameOf(x));
|
||||
return yScore - xScore;
|
||||
});
|
||||
|
||||
|
||||
return tabs;
|
||||
},
|
||||
|
||||
|
||||
// ---------
|
||||
// Function: _filterForUnmatches
|
||||
// Given an array of <TabItem>s returns an unsorted array of tabs whose name
|
||||
// does not match the the search term.
|
||||
_filterForUnmatches: function TabMatcher__filterForUnmatches(tabs) {
|
||||
var self = this;
|
||||
return tabs.filter(function(tab) {
|
||||
let self = this;
|
||||
return tabs.filter(function TabMatcher__filterForUnmatches_filter(tab) {
|
||||
let name = tab.$tabTitle[0].textContent;
|
||||
let url = TabUtils.URLOf(tab);
|
||||
return !name.match(self.term, "i") && !url.match(self.term, "i");
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
// ---------
|
||||
// Function: _getTabsForOtherWindows
|
||||
// Returns an array of <TabItem>s and <xul:tabs>s representing tabs
|
||||
@ -224,18 +167,18 @@ TabMatcher.prototype = {
|
||||
// <xul:tab>s will be returned for windows in which Panorama has never
|
||||
// been activated.
|
||||
_getTabsForOtherWindows: function TabMatcher__getTabsForOtherWindows() {
|
||||
var enumerator = Services.wm.getEnumerator("navigator:browser");
|
||||
var allTabs = [];
|
||||
let enumerator = Services.wm.getEnumerator("navigator:browser");
|
||||
let allTabs = [];
|
||||
|
||||
while (enumerator.hasMoreElements()) {
|
||||
var win = enumerator.getNext();
|
||||
let win = enumerator.getNext();
|
||||
// This function gets tabs from other windows, not from the current window
|
||||
if (win != gWindow)
|
||||
allTabs.push.apply(allTabs, win.gBrowser.tabs);
|
||||
}
|
||||
return allTabs;
|
||||
},
|
||||
|
||||
|
||||
// ----------
|
||||
// Function: matchedTabsFromOtherWindows
|
||||
// Returns an array of <TabItem>s and <xul:tab>s that match the search term
|
||||
@ -244,37 +187,34 @@ TabMatcher.prototype = {
|
||||
// <xul:tab>s will be returned for windows in which Panorama has never
|
||||
// been activated.
|
||||
// (new TabMatcher("app")).matchedTabsFromOtherWindows();
|
||||
matchedTabsFromOtherWindows: function TabMatcher_matchedTabsFromOtherWindows(){
|
||||
matchedTabsFromOtherWindows: function TabMatcher_matchedTabsFromOtherWindows() {
|
||||
if (this.term.length < 2)
|
||||
return [];
|
||||
|
||||
var tabs = this._getTabsForOtherWindows();
|
||||
tabs = this._filterAndSortForMatches(tabs);
|
||||
return tabs;
|
||||
|
||||
let tabs = this._getTabsForOtherWindows();
|
||||
return this._filterAndSortForMatches(tabs);
|
||||
},
|
||||
|
||||
|
||||
// ----------
|
||||
// Function: matched
|
||||
// Returns an array of <TabItem>s which match the current search term.
|
||||
// If the term is less than 2 characters in length, it returns
|
||||
// nothing.
|
||||
// If the term is less than 2 characters in length, it returns nothing.
|
||||
matched: function TabMatcher_matched() {
|
||||
if (this.term.length < 2)
|
||||
return [];
|
||||
|
||||
var tabs = TabItems.getItems();
|
||||
tabs = this._filterAndSortForMatches(tabs);
|
||||
return tabs;
|
||||
|
||||
let tabs = TabItems.getItems();
|
||||
return this._filterAndSortForMatches(tabs);
|
||||
},
|
||||
|
||||
|
||||
// ----------
|
||||
// Function: unmatched
|
||||
// Returns all of <TabItem>s that .matched() doesn't return.
|
||||
unmatched: function TabMatcher_unmatched() {
|
||||
var tabs = TabItems.getItems();
|
||||
let tabs = TabItems.getItems();
|
||||
if (this.term.length < 2)
|
||||
return tabs;
|
||||
|
||||
|
||||
return this._filterForUnmatches(tabs);
|
||||
},
|
||||
|
||||
@ -289,73 +229,222 @@ TabMatcher.prototype = {
|
||||
// passed both <TabItem>s and <xul:tab>s and the index is offset by the
|
||||
// number of matched tabs inside the window.
|
||||
doSearch: function TabMatcher_doSearch(matchFunc, unmatchFunc, otherFunc) {
|
||||
var matches = this.matched();
|
||||
var unmatched = this.unmatched();
|
||||
var otherMatches = this.matchedTabsFromOtherWindows();
|
||||
let matches = this.matched();
|
||||
let unmatched = this.unmatched();
|
||||
let otherMatches = this.matchedTabsFromOtherWindows();
|
||||
|
||||
matches.forEach(function(tab, i) {
|
||||
matchFunc(tab, i);
|
||||
});
|
||||
|
||||
otherMatches.forEach(function(tab,i) {
|
||||
otherFunc(tab, i+matches.length);
|
||||
otherFunc(tab, i+matches.length);
|
||||
});
|
||||
|
||||
|
||||
unmatched.forEach(function(tab, i) {
|
||||
unmatchFunc(tab, i);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: _scorePatternMatch
|
||||
// Given a pattern string, returns a score between 0 and 1 of how well
|
||||
// that pattern matches the original string. It mimics the heuristics
|
||||
// of the Mac application launcher Quicksilver.
|
||||
_scorePatternMatch: function TabMatcher__scorePatternMatch(pattern, matched, offset) {
|
||||
offset = offset || 0;
|
||||
pattern = pattern.toLowerCase();
|
||||
matched = matched.toLowerCase();
|
||||
|
||||
if (pattern.length == 0)
|
||||
return 0.9;
|
||||
if (pattern.length > matched.length)
|
||||
return 0.0;
|
||||
|
||||
for (let i = pattern.length; i > 0; i--) {
|
||||
let sub_pattern = pattern.substring(0,i);
|
||||
let index = matched.indexOf(sub_pattern);
|
||||
|
||||
if (index < 0)
|
||||
continue;
|
||||
if (index + pattern.length > matched.length + offset)
|
||||
continue;
|
||||
|
||||
let next_string = matched.substring(index+sub_pattern.length);
|
||||
let next_pattern = null;
|
||||
|
||||
if (i >= pattern.length)
|
||||
next_pattern = '';
|
||||
else
|
||||
next_pattern = pattern.substring(i);
|
||||
|
||||
let remaining_score = this._scorePatternMatch(next_pattern, next_string, offset + index);
|
||||
|
||||
if (remaining_score > 0) {
|
||||
let score = matched.length-next_string.length;
|
||||
|
||||
if (index != 0) {
|
||||
let c = matched.charCodeAt(index-1);
|
||||
if (c == 32 || c == 9) {
|
||||
for (let j = (index - 2); j >= 0; j--) {
|
||||
c = matched.charCodeAt(j);
|
||||
score -= ((c == 32 || c == 9) ? 1 : 0.15);
|
||||
}
|
||||
} else {
|
||||
score -= index;
|
||||
}
|
||||
}
|
||||
|
||||
score += remaining_score * next_string.length;
|
||||
score /= matched.length;
|
||||
return score;
|
||||
}
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
};
|
||||
|
||||
// ##########
|
||||
// Class: SearchEventHandlerClass
|
||||
// Class: TabHandlers
|
||||
//
|
||||
// A singleton class that handles all of the
|
||||
// event handlers.
|
||||
function SearchEventHandlerClass() {
|
||||
this.init();
|
||||
}
|
||||
// A object that handles all of the event handlers.
|
||||
let TabHandlers = {
|
||||
_mouseDownLocation: null,
|
||||
|
||||
// ---------
|
||||
// Function: onMatch
|
||||
// Adds styles and event listeners to the matched tab items.
|
||||
onMatch: function TabHandlers_onMatch(tab, index) {
|
||||
tab.addClass("onTop");
|
||||
index != 0 ? tab.addClass("notMainMatch") : tab.removeClass("notMainMatch");
|
||||
|
||||
// Remove any existing handlers before adding the new ones.
|
||||
// If we don't do this, then we may add more handlers than
|
||||
// we remove.
|
||||
tab.$canvas
|
||||
.unbind("mousedown", TabHandlers._hideHandler)
|
||||
.unbind("mouseup", TabHandlers._showHandler);
|
||||
|
||||
tab.$canvas
|
||||
.mousedown(TabHandlers._hideHandler)
|
||||
.mouseup(TabHandlers._showHandler);
|
||||
},
|
||||
|
||||
// ---------
|
||||
// Function: onUnmatch
|
||||
// Removes styles and event listeners from the unmatched tab items.
|
||||
onUnmatch: function TabHandlers_onUnmatch(tab, index) {
|
||||
tab.$container.removeClass("onTop");
|
||||
tab.removeClass("notMainMatch");
|
||||
|
||||
tab.$canvas
|
||||
.unbind("mousedown", TabHandlers._hideHandler)
|
||||
.unbind("mouseup", TabHandlers._showHandler);
|
||||
},
|
||||
|
||||
// ---------
|
||||
// Function: onOther
|
||||
// Removes styles and event listeners from the unmatched tabs.
|
||||
onOther: function TabHandlers_onOther(tab, index) {
|
||||
// Unlike the other on* functions, in this function tab can
|
||||
// either be a <TabItem> or a <xul:tab>. In other functions
|
||||
// it is always a <TabItem>. Also note that index is offset
|
||||
// by the number of matches within the window.
|
||||
let item = iQ("<div/>")
|
||||
.addClass("inlineMatch")
|
||||
.click(function TabHandlers_onOther_click(event) {
|
||||
Search.hide(event);
|
||||
TabUtils.focus(tab);
|
||||
});
|
||||
|
||||
iQ("<img/>")
|
||||
.attr("src", TabUtils.faviconURLOf(tab))
|
||||
.appendTo(item);
|
||||
|
||||
iQ("<span/>")
|
||||
.text(TabUtils.nameOf(tab))
|
||||
.appendTo(item);
|
||||
|
||||
index != 0 ? item.addClass("notMainMatch") : item.removeClass("notMainMatch");
|
||||
item.appendTo("#results");
|
||||
iQ("#otherresults").show();
|
||||
},
|
||||
|
||||
// ---------
|
||||
// Function: _hideHandler
|
||||
// Performs when mouse down on a canvas of tab item.
|
||||
_hideHandler: function TabHandlers_hideHandler(event) {
|
||||
iQ("#search").fadeOut();
|
||||
iQ("#searchshade").fadeOut();
|
||||
TabHandlers._mouseDownLocation = {x:event.clientX, y:event.clientY};
|
||||
},
|
||||
|
||||
// ---------
|
||||
// Function: _showHandler
|
||||
// Performs when mouse up on a canvas of tab item.
|
||||
_showHandler: function TabHandlers_showHandler(event) {
|
||||
// If the user clicks on a tab without moving the mouse then
|
||||
// they are zooming into the tab and we need to exit search
|
||||
// mode.
|
||||
if (TabHandlers._mouseDownLocation.x == event.clientX &&
|
||||
TabHandlers._mouseDownLocation.y == event.clientY) {
|
||||
Search.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
iQ("#searchshade").show();
|
||||
iQ("#search").show();
|
||||
iQ("#searchbox")[0].focus();
|
||||
// Marshal the search.
|
||||
setTimeout(Search.perform, 0);
|
||||
}
|
||||
};
|
||||
|
||||
// ##########
|
||||
// Class: Search
|
||||
//
|
||||
// A object that handles the search feature.
|
||||
let Search = {
|
||||
_initiatedBy: "",
|
||||
|
||||
_currentHandler: null,
|
||||
|
||||
SearchEventHandlerClass.prototype = {
|
||||
// ----------
|
||||
// Function: toString
|
||||
// Prints [SearchEventHandler] for debug use
|
||||
toString: function SearchEventHandlerClass_toString() {
|
||||
return "[SearchEventHandler]";
|
||||
// Prints [Search] for debug use.
|
||||
toString: function Search_toString() {
|
||||
return "[Search]";
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: init
|
||||
// Initializes the searchbox to be focused, and everything
|
||||
// else to be hidden, and to have everything have the appropriate
|
||||
// event handlers;
|
||||
init: function () {
|
||||
// Initializes the searchbox to be focused, and everything else to be hidden,
|
||||
// and to have everything have the appropriate event handlers.
|
||||
init: function Search_init() {
|
||||
let self = this;
|
||||
iQ("#search").hide();
|
||||
iQ("#searchshade").hide().click(function(event) {
|
||||
if ( event.target.id != "searchbox")
|
||||
hideSearch();
|
||||
if (event.target.id != "searchbox")
|
||||
self.hide();
|
||||
});
|
||||
|
||||
|
||||
iQ("#searchbox").keyup(function() {
|
||||
performSearch();
|
||||
self.perform();
|
||||
});
|
||||
|
||||
|
||||
iQ("#searchbutton").mousedown(function() {
|
||||
self.initiatedBy = "buttonclick";
|
||||
ensureSearchShown();
|
||||
self.switchToInMode();
|
||||
self._initiatedBy = "buttonclick";
|
||||
self.ensureShown();
|
||||
self.switchToInMode();
|
||||
});
|
||||
|
||||
this.initiatedBy = "";
|
||||
this.currentHandler = null;
|
||||
|
||||
this.switchToBeforeMode();
|
||||
},
|
||||
|
||||
|
||||
// ----------
|
||||
// Function: beforeSearchKeyHandler
|
||||
// Function: _beforeSearchKeyHandler
|
||||
// Handles all keydown before the search interface is brought up.
|
||||
beforeSearchKeyHandler: function (event) {
|
||||
_beforeSearchKeyHandler: function Search__beforeSearchKeyHandler(event) {
|
||||
// Only match reasonable text-like characters for quick search.
|
||||
if (event.altKey || event.ctrlKey || event.metaKey)
|
||||
return;
|
||||
@ -384,28 +473,29 @@ SearchEventHandlerClass.prototype = {
|
||||
}
|
||||
|
||||
this.switchToInMode();
|
||||
this.initiatedBy = "keydown";
|
||||
ensureSearchShown(true);
|
||||
this._initiatedBy = "keydown";
|
||||
this.ensureShown(true);
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: inSearchKeyHandler
|
||||
// Function: _inSearchKeyHandler
|
||||
// Handles all keydown while search mode.
|
||||
inSearchKeyHandler: function (event) {
|
||||
_inSearchKeyHandler: function Search__inSearchKeyHandler(event) {
|
||||
let term = iQ("#searchbox").val();
|
||||
if ((event.keyCode == event.DOM_VK_ESCAPE) ||
|
||||
(event.keyCode == event.DOM_VK_BACK_SPACE && term.length <= 1 && this.initiatedBy == "keydown")) {
|
||||
hideSearch(event);
|
||||
if ((event.keyCode == event.DOM_VK_ESCAPE) ||
|
||||
(event.keyCode == event.DOM_VK_BACK_SPACE && term.length <= 1 &&
|
||||
this._initiatedBy == "keydown")) {
|
||||
this.hide(event);
|
||||
return;
|
||||
}
|
||||
|
||||
let matcher = createSearchTabMacher();
|
||||
let matcher = this.createSearchTabMatcher();
|
||||
let matches = matcher.matched();
|
||||
let others = matcher.matchedTabsFromOtherWindows();
|
||||
if ((event.keyCode == event.DOM_VK_RETURN ||
|
||||
event.keyCode == event.DOM_VK_ENTER) &&
|
||||
if ((event.keyCode == event.DOM_VK_RETURN ||
|
||||
event.keyCode == event.DOM_VK_ENTER) &&
|
||||
(matches.length > 0 || others.length > 0)) {
|
||||
hideSearch(event);
|
||||
this.hide(event);
|
||||
if (matches.length > 0)
|
||||
matches[0].zoomIn();
|
||||
else
|
||||
@ -415,206 +505,135 @@ SearchEventHandlerClass.prototype = {
|
||||
|
||||
// ----------
|
||||
// Function: switchToBeforeMode
|
||||
// Make sure the event handlers are appropriate for
|
||||
// the before-search mode.
|
||||
switchToBeforeMode: function switchToBeforeMode() {
|
||||
// Make sure the event handlers are appropriate for the before-search mode.
|
||||
switchToBeforeMode: function Search_switchToBeforeMode() {
|
||||
let self = this;
|
||||
if (this.currentHandler)
|
||||
iQ(window).unbind("keydown", this.currentHandler);
|
||||
this.currentHandler = function(event) self.beforeSearchKeyHandler(event);
|
||||
iQ(window).keydown(this.currentHandler);
|
||||
if (this._currentHandler)
|
||||
iQ(window).unbind("keydown", this._currentHandler);
|
||||
this._currentHandler = function Search_switchToBeforeMode_handler(event) {
|
||||
self._beforeSearchKeyHandler(event);
|
||||
}
|
||||
iQ(window).keydown(this._currentHandler);
|
||||
},
|
||||
|
||||
|
||||
// ----------
|
||||
// Function: switchToInMode
|
||||
// Make sure the event handlers are appropriate for
|
||||
// the in-search mode.
|
||||
switchToInMode: function switchToInMode() {
|
||||
// Make sure the event handlers are appropriate for the in-search mode.
|
||||
switchToInMode: function Search_switchToInMode() {
|
||||
let self = this;
|
||||
if (this.currentHandler)
|
||||
iQ(window).unbind("keydown", this.currentHandler);
|
||||
this.currentHandler = function(event) self.inSearchKeyHandler(event);
|
||||
iQ(window).keydown(this.currentHandler);
|
||||
}
|
||||
};
|
||||
|
||||
var TabHandlers = {
|
||||
onMatch: function(tab, index){
|
||||
tab.addClass("onTop");
|
||||
index != 0 ? tab.addClass("notMainMatch") : tab.removeClass("notMainMatch");
|
||||
|
||||
// Remove any existing handlers before adding the new ones.
|
||||
// If we don't do this, then we may add more handlers than
|
||||
// we remove.
|
||||
tab.$canvas
|
||||
.unbind("mousedown", TabHandlers._hideHandler)
|
||||
.unbind("mouseup", TabHandlers._showHandler);
|
||||
|
||||
tab.$canvas
|
||||
.mousedown(TabHandlers._hideHandler)
|
||||
.mouseup(TabHandlers._showHandler);
|
||||
if (this._currentHandler)
|
||||
iQ(window).unbind("keydown", this._currentHandler);
|
||||
this._currentHandler = function Search_switchToInMode_handler(event) {
|
||||
self._inSearchKeyHandler(event);
|
||||
}
|
||||
iQ(window).keydown(this._currentHandler);
|
||||
},
|
||||
|
||||
onUnmatch: function(tab, index){
|
||||
tab.$container.removeClass("onTop");
|
||||
tab.removeClass("notMainMatch");
|
||||
|
||||
tab.$canvas
|
||||
.unbind("mousedown", TabHandlers._hideHandler)
|
||||
.unbind("mouseup", TabHandlers._showHandler);
|
||||
createSearchTabMatcher: function Search_createSearchTabMatcher() {
|
||||
return new TabMatcher(iQ("#searchbox").val());
|
||||
},
|
||||
|
||||
onOther: function(tab, index){
|
||||
// Unlike the other on* functions, in this function tab can
|
||||
// either be a <TabItem> or a <xul:tab>. In other functions
|
||||
// it is always a <TabItem>. Also note that index is offset
|
||||
// by the number of matches within the window.
|
||||
let item = iQ("<div/>")
|
||||
.addClass("inlineMatch")
|
||||
.click(function(event){
|
||||
hideSearch(event);
|
||||
TabUtils.focus(tab);
|
||||
});
|
||||
|
||||
iQ("<img/>")
|
||||
.attr("src", TabUtils.faviconURLOf(tab) )
|
||||
.appendTo(item);
|
||||
|
||||
iQ("<span/>")
|
||||
.text( TabUtils.nameOf(tab) )
|
||||
.appendTo(item);
|
||||
|
||||
index != 0 ? item.addClass("notMainMatch") : item.removeClass("notMainMatch");
|
||||
item.appendTo("#results");
|
||||
iQ("#otherresults").show();
|
||||
|
||||
// ----------
|
||||
// Function: isEnabled
|
||||
// Checks whether search mode is enabled or not.
|
||||
isEnabled: function Search_isEnabled() {
|
||||
return iQ("#search").css("display") != "none";
|
||||
},
|
||||
|
||||
_hideHandler: function(event){
|
||||
iQ("#search").fadeOut();
|
||||
iQ("#searchshade").fadeOut();
|
||||
TabHandlers._mouseDownLocation = {x:event.clientX, y:event.clientY};
|
||||
},
|
||||
|
||||
_showHandler: function(event){
|
||||
// If the user clicks on a tab without moving the mouse then
|
||||
// they are zooming into the tab and we need to exit search
|
||||
// mode.
|
||||
if (TabHandlers._mouseDownLocation.x == event.clientX &&
|
||||
TabHandlers._mouseDownLocation.y == event.clientY){
|
||||
hideSearch();
|
||||
|
||||
// ----------
|
||||
// Function: hide
|
||||
// Hides search mode.
|
||||
hide: function Search_hide(event) {
|
||||
if (!this.isEnabled())
|
||||
return;
|
||||
|
||||
iQ("#searchbox").val("");
|
||||
iQ("#searchshade").hide();
|
||||
iQ("#search").hide();
|
||||
|
||||
iQ("#searchbutton").css({ opacity:.8 });
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
UI.setTitlebarColors(true);
|
||||
#endif
|
||||
|
||||
this.perform();
|
||||
this.switchToBeforeMode();
|
||||
|
||||
if (event) {
|
||||
// when hiding the search mode, we need to prevent the keypress handler
|
||||
// in UI__setTabViewFrameKeyHandlers to handle the key press again. e.g. Esc
|
||||
// which is already handled by the key down in this class.
|
||||
if (event.type == "keydown")
|
||||
UI.ignoreKeypressForSearch = true;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
iQ("#searchshade").show();
|
||||
iQ("#search").show();
|
||||
iQ("#searchbox")[0].focus();
|
||||
// Marshal the search.
|
||||
setTimeout(performSearch, 0);
|
||||
// Return focus to the tab window
|
||||
UI.blurAll();
|
||||
gTabViewFrame.contentWindow.focus();
|
||||
|
||||
let newEvent = document.createEvent("Events");
|
||||
newEvent.initEvent("tabviewsearchdisabled", false, false);
|
||||
dispatchEvent(newEvent);
|
||||
},
|
||||
|
||||
_mouseDownLocation: null
|
||||
};
|
||||
|
||||
function createSearchTabMacher() {
|
||||
return new TabMatcher(iQ("#searchbox").val());
|
||||
}
|
||||
// ----------
|
||||
// Function: perform
|
||||
// Performs a search.
|
||||
perform: function Search_perform() {
|
||||
let matcher = this.createSearchTabMatcher();
|
||||
|
||||
function hideSearch(event) {
|
||||
if (!isSearchEnabled())
|
||||
return;
|
||||
// Remove any previous other-window search results and
|
||||
// hide the display area.
|
||||
iQ("#results").empty();
|
||||
iQ("#otherresults").hide();
|
||||
iQ("#otherresults>.label").text(tabviewString("search.otherWindowTabs"));
|
||||
|
||||
iQ("#searchbox").val("");
|
||||
iQ("#searchshade").hide();
|
||||
iQ("#search").hide();
|
||||
matcher.doSearch(TabHandlers.onMatch, TabHandlers.onUnmatch, TabHandlers.onOther);
|
||||
},
|
||||
|
||||
iQ("#searchbutton").css({ opacity:.8 });
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
UI.setTitlebarColors(true);
|
||||
#endif
|
||||
|
||||
performSearch();
|
||||
SearchEventHandler.switchToBeforeMode();
|
||||
|
||||
if (event) {
|
||||
// when hiding the search mode, we need to prevent the keypress handler
|
||||
// in UI__setTabViewFrameKeyHandlers to handle the key press again. e.g. Esc
|
||||
// which is already handled by the key down in this class.
|
||||
if (event.type == "keydown")
|
||||
UI.ignoreKeypressForSearch = true;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
// Return focus to the tab window
|
||||
UI.blurAll();
|
||||
gTabViewFrame.contentWindow.focus();
|
||||
|
||||
let newEvent = document.createEvent("Events");
|
||||
newEvent.initEvent("tabviewsearchdisabled", false, false);
|
||||
dispatchEvent(newEvent);
|
||||
}
|
||||
|
||||
function performSearch() {
|
||||
let matcher = new TabMatcher(iQ("#searchbox").val());
|
||||
|
||||
// Remove any previous other-window search results and
|
||||
// hide the display area.
|
||||
iQ("#results").empty();
|
||||
iQ("#otherresults").hide();
|
||||
iQ("#otherresults>.label").text(tabviewString("search.otherWindowTabs"));
|
||||
|
||||
matcher.doSearch(TabHandlers.onMatch, TabHandlers.onUnmatch, TabHandlers.onOther);
|
||||
}
|
||||
|
||||
// ----------
|
||||
// Function: ensureSearchShown
|
||||
// Ensure the search feature is displayed. If not, display it.
|
||||
// Parameters:
|
||||
// - a boolean indicates whether this is triggered by a keypress or not
|
||||
function ensureSearchShown(activatedByKeypress) {
|
||||
var $search = iQ("#search");
|
||||
var $searchShade = iQ("#searchshade");
|
||||
var $searchbox = iQ("#searchbox");
|
||||
iQ("#searchbutton").css({ opacity: 1 });
|
||||
|
||||
if (!isSearchEnabled()) {
|
||||
$searchShade.show();
|
||||
$search.show();
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
UI.setTitlebarColors({active: "#717171", inactive: "#EDEDED"});
|
||||
#endif
|
||||
// ----------
|
||||
// Function: ensureShown
|
||||
// Ensures the search feature is displayed. If not, display it.
|
||||
// Parameters:
|
||||
// - a boolean indicates whether this is triggered by a keypress or not
|
||||
ensureShown: function Search_ensureShown(activatedByKeypress) {
|
||||
let $search = iQ("#search");
|
||||
let $searchShade = iQ("#searchshade");
|
||||
let $searchbox = iQ("#searchbox");
|
||||
iQ("#searchbutton").css({ opacity: 1 });
|
||||
|
||||
// NOTE: when this function is called by keydown handler, next keypress
|
||||
// event or composition events of IME will be fired on the focused editor.
|
||||
let dispatchTabViewSearchEnabledEvent = function dispatchTabViewSearchEnabledEvent() {
|
||||
function dispatchTabViewSearchEnabledEvent() {
|
||||
let newEvent = document.createEvent("Events");
|
||||
newEvent.initEvent("tabviewsearchenabled", false, false);
|
||||
dispatchEvent(newEvent);
|
||||
};
|
||||
|
||||
if (activatedByKeypress) {
|
||||
// set the focus so key strokes are entered into the textbox.
|
||||
$searchbox[0].focus();
|
||||
dispatchTabViewSearchEnabledEvent();
|
||||
} else {
|
||||
// marshal the focusing, otherwise it ends up with searchbox[0].focus gets
|
||||
// called before the search button gets the focus after being pressed.
|
||||
setTimeout(function setFocusAndDispatchSearchEnabledEvent() {
|
||||
if (!this.isEnabled()) {
|
||||
$searchShade.show();
|
||||
$search.show();
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
UI.setTitlebarColors({active: "#717171", inactive: "#EDEDED"});
|
||||
#endif
|
||||
|
||||
if (activatedByKeypress) {
|
||||
// set the focus so key strokes are entered into the textbox.
|
||||
$searchbox[0].focus();
|
||||
dispatchTabViewSearchEnabledEvent();
|
||||
}, 0);
|
||||
} else {
|
||||
// marshal the focusing, otherwise it ends up with searchbox[0].focus gets
|
||||
// called before the search button gets the focus after being pressed.
|
||||
setTimeout(function setFocusAndDispatchSearchEnabledEvent() {
|
||||
$searchbox[0].focus();
|
||||
dispatchTabViewSearchEnabledEvent();
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function isSearchEnabled() {
|
||||
return iQ("#search").css("display") != "none";
|
||||
}
|
||||
|
||||
var SearchEventHandler = new SearchEventHandlerClass();
|
||||
|
||||
// Features to add:
|
||||
// (1) Make sure this looks good on Windows. Bug 594429
|
||||
// (2) Group all of the highlighted tabs into a group? Bug 594434
|
||||
|
@ -609,7 +609,7 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||
let $tabEl = this.$container;
|
||||
let $canvas = this.$canvas;
|
||||
|
||||
hideSearch();
|
||||
Search.hide();
|
||||
|
||||
UI.setActive(this);
|
||||
TabItems._update(this.tab, {force: true});
|
||||
|
@ -78,5 +78,5 @@ let AllTabs = {
|
||||
#include drag.js
|
||||
#include trench.js
|
||||
#include thumbnailStorage.js
|
||||
#include ui.js
|
||||
#include search.js
|
||||
#include ui.js
|
||||
|
@ -185,6 +185,9 @@ let UI = {
|
||||
this._storageSanity(data);
|
||||
this._pageBounds = data.pageBounds;
|
||||
|
||||
// ___ search
|
||||
Search.init();
|
||||
|
||||
// ___ currentTab
|
||||
this._currentTab = gBrowser.selectedTab;
|
||||
|
||||
@ -717,7 +720,7 @@ let UI = {
|
||||
}
|
||||
} else if (topic == "private-browsing-change-granted") {
|
||||
if (data == "enter" || data == "exit") {
|
||||
hideSearch();
|
||||
Search.hide();
|
||||
self._privateBrowsing.transitionMode = data;
|
||||
|
||||
// make sure to save all thumbnails that haven't been saved yet
|
||||
@ -1134,7 +1137,7 @@ let UI = {
|
||||
}
|
||||
}
|
||||
if ((iQ(":focus").length > 0 && iQ(":focus")[0].nodeName == "INPUT") ||
|
||||
isSearchEnabled() || self.ignoreKeypressForSearch) {
|
||||
Search.isEnabled() || self.ignoreKeypressForSearch) {
|
||||
self.ignoreKeypressForSearch = false;
|
||||
processBrowserKeys(event);
|
||||
return;
|
||||
@ -1247,9 +1250,9 @@ let UI = {
|
||||
// Function: enableSearch
|
||||
// Enables the search feature.
|
||||
enableSearch: function UI_enableSearch() {
|
||||
if (!isSearchEnabled()) {
|
||||
ensureSearchShown();
|
||||
SearchEventHandler.switchToInMode();
|
||||
if (!Search.isEnabled()) {
|
||||
Search.ensureShown();
|
||||
Search.switchToInMode();
|
||||
}
|
||||
},
|
||||
|
||||
@ -1516,15 +1519,15 @@ let UI = {
|
||||
let self = this;
|
||||
let zoomedIn = false;
|
||||
|
||||
if (isSearchEnabled()) {
|
||||
let matcher = createSearchTabMacher();
|
||||
if (Search.isEnabled()) {
|
||||
let matcher = Search.createSearchTabMatcher();
|
||||
let matches = matcher.matched();
|
||||
|
||||
if (matches.length > 0) {
|
||||
matches[0].zoomIn();
|
||||
zoomedIn = true;
|
||||
}
|
||||
hideSearch();
|
||||
Search.hide();
|
||||
}
|
||||
|
||||
if (!zoomedIn) {
|
||||
|
@ -12,9 +12,9 @@ Browser context menu subtest.
|
||||
<input id="test-input"><br>
|
||||
<img id="test-image" src="ctxmenu-image.png">
|
||||
<canvas id="test-canvas" width="100" height="100" style="background-color: blue"></canvas>
|
||||
<video id="test-video-ok" src="video.ogg" width="100" height="100" style="background-color: green"></video>
|
||||
<video id="test-video-bad" src="bogus.duh" width="100" height="100" style="background-color: orange"></video>
|
||||
<video id="test-video-bad2" width="100" height="100" style="background-color: yellow">
|
||||
<video controls id="test-video-ok" src="video.ogg" width="100" height="100" style="background-color: green"></video>
|
||||
<video controls id="test-video-bad" src="bogus.duh" width="100" height="100" style="background-color: orange"></video>
|
||||
<video controls id="test-video-bad2" width="100" height="100" style="background-color: yellow">
|
||||
<source src="bogus.duh" type="video/durrrr;">
|
||||
</video>
|
||||
<iframe id="test-iframe" width="98" height="98" style="border: 1px solid black"></iframe>
|
||||
|
@ -110,6 +110,7 @@ _BROWSER_FILES = \
|
||||
browser_tabview_bug625195.js \
|
||||
browser_tabview_bug625269.js \
|
||||
browser_tabview_bug625424.js \
|
||||
browser_tabview_bug625955.js \
|
||||
browser_tabview_bug626368.js \
|
||||
browser_tabview_bug626455.js \
|
||||
browser_tabview_bug626525.js \
|
||||
|
@ -24,7 +24,7 @@ function test2() {
|
||||
ok(TabView.isVisible(), "Tab View is visible");
|
||||
|
||||
whenSearchIsEnabled(function() {
|
||||
ok(contentWindow.isSearchEnabled(), "The search is enabled")
|
||||
ok(contentWindow.Search.isEnabled(), "The search is enabled")
|
||||
|
||||
whenSearchIsDisabled(test3);
|
||||
hideSearch();
|
||||
@ -33,7 +33,7 @@ function test2() {
|
||||
}
|
||||
|
||||
function test3() {
|
||||
ok(!contentWindow.isSearchEnabled(), "The search is disabled")
|
||||
ok(!contentWindow.Search.isEnabled(), "The search is disabled")
|
||||
|
||||
is(gBrowser.tabs.length, 1, "There is one tab before cmd/ctrl + t is pressed");
|
||||
|
||||
|
@ -50,7 +50,7 @@ function testThree() {
|
||||
let tab = win.gBrowser.tabs[1];
|
||||
searchBox.val(tab._tabViewTabItem.$tabTitle[0].innerHTML);
|
||||
|
||||
cw.performSearch();
|
||||
cw.Search.perform();
|
||||
|
||||
whenTabViewIsHidden(function () {
|
||||
is(tab, win.gBrowser.selectedTab, "The search result tab is shown");
|
||||
|
@ -20,7 +20,7 @@ function onTabViewWindowLoaded() {
|
||||
executeSoon(function() {
|
||||
let searchBox = contentWindow.document.getElementById("searchbox");
|
||||
is(searchBox.value, number, "The seach box matches the number: " + number);
|
||||
contentWindow.hideSearch(null);
|
||||
contentWindow.Search.hide(null);
|
||||
});
|
||||
}
|
||||
let onSearchDisabled = function() {
|
||||
|
@ -52,7 +52,7 @@ function onTabViewWindowLoaded(win, tab) {
|
||||
let testClickOnOtherSearchResult = function () {
|
||||
// search for the tab from our main window
|
||||
searchbox.setAttribute('value', 'other');
|
||||
contentWindow.performSearch();
|
||||
contentWindow.Search.perform();
|
||||
|
||||
// prepare to finish when the main window gets focus back
|
||||
window.addEventListener('focus', function onFocus() {
|
||||
|
@ -0,0 +1,25 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
showTabView(onTabViewShown);
|
||||
}
|
||||
|
||||
function onTabViewShown() {
|
||||
let contentWindow = TabView.getContentWindow();
|
||||
is(contentWindow.GroupItems.groupItems.length, 1, "Has one groupItem only");
|
||||
|
||||
let groupItem = contentWindow.GroupItems.groupItems[0];
|
||||
let tabItems = groupItem.getChildren();
|
||||
is(tabItems.length, 1, "There is only one tabItems in the groupItem");
|
||||
|
||||
let bounds = groupItem.bounds;
|
||||
gBrowser.addTab();
|
||||
gBrowser.removeTab(gBrowser.tabs[1]);
|
||||
ok(bounds.equals(groupItem.bounds), 'Group bounds recovered');
|
||||
|
||||
is(tabItems.length, 1, "There is only one tabItem in the groupItem");
|
||||
|
||||
hideTabView(finish);
|
||||
}
|
@ -12,7 +12,7 @@ function test() {
|
||||
let keyCodes = [0, 91, 92];
|
||||
keyCodes.forEach(function(keyCode) {
|
||||
utils.sendKeyEvent("keydown", keyCode, 0, 0);
|
||||
ok(!cw.isSearchEnabled(), "search is not enabled with keyCode: " + keyCode);
|
||||
ok(!cw.Search.isEnabled(), "search is not enabled with keyCode: " + keyCode);
|
||||
});
|
||||
|
||||
hideTabView(finish);
|
||||
|
@ -9,14 +9,14 @@ function test() {
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
if (cw)
|
||||
cw.hideSearch();
|
||||
cw.Search.hide();
|
||||
|
||||
TabView.hide();
|
||||
pb.privateBrowsingEnabled = false;
|
||||
});
|
||||
|
||||
let enableSearch = function (callback) {
|
||||
if (cw.isSearchEnabled()) {
|
||||
if (cw.Search.isEnabled()) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
@ -26,7 +26,7 @@ function test() {
|
||||
executeSoon(callback);
|
||||
}, false);
|
||||
|
||||
cw.ensureSearchShown();
|
||||
cw.Search.ensureShown();
|
||||
};
|
||||
|
||||
let getSearchboxValue = function () {
|
||||
@ -34,7 +34,7 @@ function test() {
|
||||
};
|
||||
|
||||
let prepareSearchbox = function (callback) {
|
||||
ok(!cw.isSearchEnabled(), "search is disabled");
|
||||
ok(!cw.Search.isEnabled(), "search is disabled");
|
||||
|
||||
enableSearch(function () {
|
||||
cw.iQ("#searchbox").val("moz");
|
||||
@ -46,7 +46,7 @@ function test() {
|
||||
prepareSearchbox(function () {
|
||||
togglePrivateBrowsing(function () {
|
||||
showTabView(function () {
|
||||
ok(!cw.isSearchEnabled(), "search is disabled");
|
||||
ok(!cw.Search.isEnabled(), "search is disabled");
|
||||
is(getSearchboxValue(), "", "search box is empty");
|
||||
callback();
|
||||
});
|
||||
|
@ -14,11 +14,11 @@ function test() {
|
||||
})
|
||||
|
||||
whenSearchIsEnabled(function() {
|
||||
ok(cw.isSearchEnabled(), "The search is enabled before creating a new tab");
|
||||
ok(cw.Search.isEnabled(), "The search is enabled before creating a new tab");
|
||||
|
||||
whenTabViewIsHidden(function() {
|
||||
showTabView(function() {
|
||||
ok(!cw.isSearchEnabled(), "The search is disabled when entering Tabview");
|
||||
ok(!cw.Search.isEnabled(), "The search is disabled when entering Tabview");
|
||||
|
||||
hideTabView(finish);
|
||||
})
|
||||
|
@ -100,7 +100,7 @@ function searchTest(contentWindow) {
|
||||
|
||||
// part of titled
|
||||
searchBox.setAttribute("value", tabNames[0].substr(1));
|
||||
contentWindow.performSearch();
|
||||
contentWindow.Search.perform();
|
||||
matchResults = getMatchResults(contentWindow, searchBox.getAttribute("value"));
|
||||
is(matchResults.length, 1,
|
||||
"Match something when a part of title exists");
|
||||
@ -109,7 +109,7 @@ function searchTest(contentWindow) {
|
||||
}
|
||||
|
||||
function cleanup(contentWindow) {
|
||||
contentWindow.hideSearch(null);
|
||||
contentWindow.Search.hide(null);
|
||||
|
||||
let onTabViewHidden = function() {
|
||||
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
|
@ -93,21 +93,21 @@ function searchTest(contentWindow) {
|
||||
|
||||
// part of title
|
||||
searchBox.setAttribute("value", "search");
|
||||
contentWindow.performSearch();
|
||||
contentWindow.Search.perform();
|
||||
is(new contentWindow.TabMatcher(
|
||||
searchBox.getAttribute("value")).matched().length, 2,
|
||||
"Match something when a part of title exists");
|
||||
|
||||
// unique part of a url
|
||||
searchBox.setAttribute("value", "search1.html");
|
||||
contentWindow.performSearch();
|
||||
contentWindow.Search.perform();
|
||||
is(new contentWindow.TabMatcher(
|
||||
searchBox.getAttribute("value")).matched().length, 1,
|
||||
"Match something when a unique part of a url exists");
|
||||
|
||||
// common part of a url
|
||||
searchBox.setAttribute("value", "tabview");
|
||||
contentWindow.performSearch();
|
||||
contentWindow.Search.perform();
|
||||
is(new contentWindow.TabMatcher(
|
||||
searchBox.getAttribute("value")).matched().length, 2,
|
||||
"Match something when a common part of a url exists");
|
||||
@ -117,7 +117,7 @@ function searchTest(contentWindow) {
|
||||
|
||||
// ----------
|
||||
function cleanup(contentWindow) {
|
||||
contentWindow.hideSearch(null);
|
||||
contentWindow.Search.hide(null);
|
||||
let onTabViewHidden = function() {
|
||||
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
ok(!TabView.isVisible(), "Tab View is hidden");
|
||||
|
@ -199,7 +199,7 @@ function hideSearch(callback, win) {
|
||||
win = win || window;
|
||||
|
||||
let contentWindow = win.TabView.getContentWindow();
|
||||
if (!contentWindow.isSearchEnabled()) {
|
||||
if (!contentWindow.Search.isEnabled()) {
|
||||
if (callback)
|
||||
callback();
|
||||
return;
|
||||
@ -208,7 +208,7 @@ function hideSearch(callback, win) {
|
||||
if (callback)
|
||||
whenSearchIsDisabled(callback, win);
|
||||
|
||||
contentWindow.hideSearch();
|
||||
contentWindow.Search.hide();
|
||||
}
|
||||
|
||||
// ----------
|
||||
@ -216,7 +216,7 @@ function whenSearchIsEnabled(callback, win) {
|
||||
win = win || window;
|
||||
|
||||
let contentWindow = win.TabView.getContentWindow();
|
||||
if (contentWindow.isSearchEnabled()) {
|
||||
if (contentWindow.Search.isEnabled()) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
@ -232,7 +232,7 @@ function whenSearchIsDisabled(callback, win) {
|
||||
win = win || window;
|
||||
|
||||
let contentWindow = win.TabView.getContentWindow();
|
||||
if (!contentWindow.isSearchEnabled()) {
|
||||
if (!contentWindow.Search.isEnabled()) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
@ -332,13 +332,15 @@ function runTest(testNum) {
|
||||
// Context menu for a video (with a VALID media source)
|
||||
checkContextMenu(["context-media-play", true,
|
||||
"context-media-mute", true,
|
||||
"context-media-showcontrols", true,
|
||||
"context-media-hidecontrols", true,
|
||||
"context-video-showstats", true,
|
||||
"context-video-fullscreen", true,
|
||||
"---", null,
|
||||
"context-viewvideo", true,
|
||||
"context-copyvideourl", true,
|
||||
"---", null,
|
||||
"context-savevideo", true,
|
||||
"context-video-saveimage", true,
|
||||
"context-sendvideo", true,
|
||||
"---", null,
|
||||
"context-inspect", true]);
|
||||
@ -350,13 +352,15 @@ function runTest(testNum) {
|
||||
// Context menu for a video (with an INVALID media source)
|
||||
checkContextMenu(["context-media-play", false,
|
||||
"context-media-mute", false,
|
||||
"context-media-showcontrols", false,
|
||||
"context-media-hidecontrols", false,
|
||||
"context-video-showstats", false,
|
||||
"context-video-fullscreen", false,
|
||||
"---", null,
|
||||
"context-viewvideo", true,
|
||||
"context-copyvideourl", true,
|
||||
"---", null,
|
||||
"context-savevideo", true,
|
||||
"context-video-saveimage", false,
|
||||
"context-sendvideo", true,
|
||||
"---", null,
|
||||
"context-inspect", true]);
|
||||
@ -368,13 +372,15 @@ function runTest(testNum) {
|
||||
// Context menu for a video (with an INVALID media source)
|
||||
checkContextMenu(["context-media-play", false,
|
||||
"context-media-mute", false,
|
||||
"context-media-showcontrols", false,
|
||||
"context-media-hidecontrols", false,
|
||||
"context-video-showstats", false,
|
||||
"context-video-fullscreen", false,
|
||||
"---", null,
|
||||
"context-viewvideo", false,
|
||||
"context-copyvideourl", false,
|
||||
"---", null,
|
||||
"context-savevideo", false,
|
||||
"context-video-saveimage", false,
|
||||
"context-sendvideo", false,
|
||||
"---", null,
|
||||
"context-inspect", true]);
|
||||
|
@ -51,9 +51,7 @@ DIRS = \
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_TEST_FILES = test_bug408328.html \
|
||||
bug408328-data.xml \
|
||||
test_bug368464.html \
|
||||
_TEST_FILES = bug408328-data.xml \
|
||||
bug368464-data.xml \
|
||||
test_bug494328.html \
|
||||
bug494328-data.xml \
|
||||
|
@ -51,6 +51,8 @@ _HTTP_FILES = \
|
||||
|
||||
_CHROME_FILES = \
|
||||
test_423060.xul \
|
||||
test_bug368464.html \
|
||||
test_bug408328.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_HTTP_FILES)
|
||||
|
@ -5,12 +5,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=368464
|
||||
-->
|
||||
<head>
|
||||
<title>Test that RSS 0.90 isn't sniffed</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=368464">Mozilla Bug 368464</a>
|
||||
<p id="display"><iframe id="testFrame" src="bug368464-data.xml"></iframe></p>
|
||||
<p id="display"><iframe id="testFrame" src="http://mochi.test:8888/tests/browser/components/feeds/test/bug368464-data.xml"></iframe></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
@ -21,7 +21,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=368464
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
addLoadEvent(function() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
|
||||
ok($("testFrame").contentDocument.documentElement.id != "feedHandler",
|
||||
"RSS 0.90 shouldn't be sniffed as a feed");
|
||||
});
|
@ -5,12 +5,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=408328
|
||||
-->
|
||||
<head>
|
||||
<title>Test feed preview safe-linkification</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=408328">Mozilla Bug 408328</a>
|
||||
<p id="display"><iframe id="testFrame" src="bug408328-data.xml"></iframe></p>
|
||||
<p id="display"><iframe id="testFrame" src="http://mochi.test:8888/tests/browser/components/feeds/test/bug408328-data.xml"></iframe></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
@ -21,7 +21,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=408328
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
addLoadEvent(function() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
|
||||
var links = $("testFrame").contentDocument.getElementById("feedContent").getElementsByTagName("a");
|
||||
is(links.length, 5, "wrong number of linked items in feed preview");
|
||||
for (var i = 0; i < links.length; i++) {
|
@ -648,36 +648,13 @@ nsBrowserContentHandler.prototype = {
|
||||
},
|
||||
|
||||
get startPage() {
|
||||
var prefb = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(nsIPrefBranch);
|
||||
|
||||
var uri = prefb.getComplexValue("browser.startup.homepage",
|
||||
nsIPrefLocalizedString).data;
|
||||
|
||||
var uri = Services.prefs.getComplexValue("browser.startup.homepage",
|
||||
nsIPrefLocalizedString).data;
|
||||
if (!uri) {
|
||||
prefb.clearUserPref("browser.startup.homepage");
|
||||
uri = prefb.getComplexValue("browser.startup.homepage",
|
||||
nsIPrefLocalizedString).data;
|
||||
Services.prefs.clearUserPref("browser.startup.homepage");
|
||||
uri = Services.prefs.getComplexValue("browser.startup.homepage",
|
||||
nsIPrefLocalizedString).data;
|
||||
}
|
||||
|
||||
var count;
|
||||
try {
|
||||
count = prefb.getIntPref("browser.startup.homepage.count");
|
||||
}
|
||||
catch (e) {
|
||||
return uri;
|
||||
}
|
||||
|
||||
for (var i = 1; i < count; ++i) {
|
||||
try {
|
||||
var page = prefb.getComplexValue("browser.startup.homepage." + i,
|
||||
nsIPrefLocalizedString).data;
|
||||
uri += "\n" + page;
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
}
|
||||
|
||||
return uri;
|
||||
},
|
||||
|
||||
|
@ -763,15 +763,21 @@ BrowserGlue.prototype = {
|
||||
const PREF_TELEMETRY_ENABLED = "toolkit.telemetry.enabled";
|
||||
const PREF_TELEMETRY_INFOURL = "toolkit.telemetry.infoURL";
|
||||
const PREF_TELEMETRY_SERVER_OWNER = "toolkit.telemetry.server_owner";
|
||||
// This is used to reprompt users when privacy message changes
|
||||
const TELEMETRY_PROMPT_REV = 2;
|
||||
|
||||
var telemetryPrompted = null;
|
||||
try {
|
||||
// If the user hasn't already been prompted, ask if they want to
|
||||
// send telemetry data.
|
||||
if (Services.prefs.getBoolPref(PREF_TELEMETRY_ENABLED) ||
|
||||
Services.prefs.getBoolPref(PREF_TELEMETRY_PROMPTED))
|
||||
return;
|
||||
telemetryPrompted = Services.prefs.getIntPref(PREF_TELEMETRY_PROMPTED);
|
||||
} catch(e) {}
|
||||
|
||||
// If the user has seen the latest telemetry prompt, do not prompt again
|
||||
// else clear old prefs and reprompt
|
||||
if (telemetryPrompted === TELEMETRY_PROMPT_REV)
|
||||
return;
|
||||
|
||||
Services.prefs.clearUserPref(PREF_TELEMETRY_PROMPTED);
|
||||
Services.prefs.clearUserPref(PREF_TELEMETRY_ENABLED);
|
||||
|
||||
// Stick the notification onto the selected tab of the active browser window.
|
||||
var win = this.getMostRecentBrowserWindow();
|
||||
var browser = win.gBrowser; // for closure in notification bar callback
|
||||
@ -802,7 +808,7 @@ BrowserGlue.prototype = {
|
||||
];
|
||||
|
||||
// Set pref to indicate we've shown the notification.
|
||||
Services.prefs.setBoolPref(PREF_TELEMETRY_PROMPTED, true);
|
||||
Services.prefs.setIntPref(PREF_TELEMETRY_PROMPTED, TELEMETRY_PROMPT_REV);
|
||||
|
||||
var notification = notifyBox.appendNotification(telemetryPrompt, "telemetry", null, notifyBox.PRIORITY_INFO_LOW, buttons);
|
||||
notification.persistence = 6; // arbitrary number, just so bar sticks around for a bit
|
||||
|
@ -143,13 +143,23 @@ let gSyncPane = {
|
||||
gSyncUtils.resetPassphrase();
|
||||
},
|
||||
|
||||
openSetup: function (resetSync) {
|
||||
/**
|
||||
* Invoke the Sync setup wizard.
|
||||
*
|
||||
* @param wizardType
|
||||
* Indicates type of wizard to launch:
|
||||
* null -- regular set up wizard
|
||||
* "pair" -- pair a device first
|
||||
* "reset" -- reset sync
|
||||
*/
|
||||
openSetup: function (wizardType) {
|
||||
var win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
|
||||
if (win)
|
||||
win.focus();
|
||||
else {
|
||||
window.openDialog("chrome://browser/content/syncSetup.xul",
|
||||
"weaveSetup", "centerscreen,chrome,resizable=no", resetSync);
|
||||
"weaveSetup", "centerscreen,chrome,resizable=no",
|
||||
wizardType);
|
||||
}
|
||||
},
|
||||
|
||||
@ -175,7 +185,7 @@ let gSyncPane = {
|
||||
},
|
||||
|
||||
resetSync: function () {
|
||||
this.openSetup(true);
|
||||
this.openSetup("reset");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,14 +74,17 @@
|
||||
<deck id="weavePrefsDeck">
|
||||
<vbox id="noAccount" align="center">
|
||||
<spacer flex="1"/>
|
||||
<button id="setupButton"
|
||||
label="&setupButton.label;"
|
||||
accesskey="&setupButton.accesskey;"
|
||||
oncommand="gSyncPane.openSetup();"/>
|
||||
<separator/>
|
||||
<description id="syncDesc" flex="1">
|
||||
<description id="syncDesc">
|
||||
&weaveDesc.label;
|
||||
</description>
|
||||
<separator/>
|
||||
<label class="text-link"
|
||||
onclick="event.stopPropagation(); gSyncPane.openSetup(null);"
|
||||
value="&setupButton.label;"/>
|
||||
<separator/>
|
||||
<label class="text-link"
|
||||
onclick="event.stopPropagation(); gSyncPane.openSetup('pair');"
|
||||
value="&pairDevice.label;"/>
|
||||
<spacer flex="3"/>
|
||||
</vbox>
|
||||
|
||||
@ -116,7 +119,7 @@
|
||||
<label id="syncAddDeviceLabel"
|
||||
class="text-link"
|
||||
onclick="gSyncPane.openAddDevice(); return false;"
|
||||
value="&addDevice.label;"/>
|
||||
value="&pairDevice.label;"/>
|
||||
</hbox>
|
||||
|
||||
<vbox>
|
||||
|
29
browser/config/mozconfigs/linux32/debug
Normal file
29
browser/config/mozconfigs/linux32/debug
Normal file
@ -0,0 +1,29 @@
|
||||
ac_add_options --enable-application=browser
|
||||
|
||||
ac_add_options --disable-optimize
|
||||
ac_add_options --enable-debug
|
||||
ac_add_options --enable-libxul
|
||||
|
||||
ac_add_options --enable-tests
|
||||
ac_add_options --enable-trace-malloc
|
||||
|
||||
CC=/tools/gcc-4.5/bin/gcc
|
||||
CXX=/tools/gcc-4.5/bin/g++
|
||||
# Avoid dependency on libstdc++ 4.5
|
||||
ac_add_options --enable-stdcxx-compat
|
||||
|
||||
export CFLAGS="-gdwarf-2"
|
||||
export CXXFLAGS="-gdwarf-2"
|
||||
|
||||
# For NSS symbols
|
||||
export MOZ_DEBUG_SYMBOLS=1
|
||||
ac_add_options --enable-debug-symbols="-gdwarf-2"
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
# Enable parallel compiling
|
||||
mk_add_options MOZ_MAKE_FLAGS="-j4"
|
||||
|
||||
#Use ccache
|
||||
ac_add_options --with-ccache=/usr/bin/ccache
|
8
browser/config/mozconfigs/linux32/l10n-mozconfig
Normal file
8
browser/config/mozconfigs/linux32/l10n-mozconfig
Normal file
@ -0,0 +1,8 @@
|
||||
ac_add_options --with-l10n-base=../../l10n-central
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-official-branding
|
||||
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
|
||||
ac_add_options --enable-update-packaging
|
||||
|
||||
CC=/tools/gcc-4.3.3/installed/bin/gcc
|
||||
CXX=/tools/gcc-4.3.3/installed/bin/g++
|
37
browser/config/mozconfigs/linux32/nightly
Normal file
37
browser/config/mozconfigs/linux32/nightly
Normal file
@ -0,0 +1,37 @@
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-optimize
|
||||
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
|
||||
ac_add_options --enable-update-packaging
|
||||
ac_add_options --disable-debug
|
||||
ac_add_options --enable-tests
|
||||
ac_add_options --enable-codesighs
|
||||
|
||||
# Nightlies only since this has a cost in performance
|
||||
ac_add_options --enable-js-diagnostics
|
||||
|
||||
CC=/tools/gcc-4.5/bin/gcc
|
||||
CXX=/tools/gcc-4.5/bin/g++
|
||||
# Avoid dependency on libstdc++ 4.5
|
||||
ac_add_options --enable-stdcxx-compat
|
||||
|
||||
export CFLAGS="-gdwarf-2"
|
||||
export CXXFLAGS="-gdwarf-2"
|
||||
|
||||
# For NSS symbols
|
||||
export MOZ_DEBUG_SYMBOLS=1
|
||||
ac_add_options --enable-debug-symbols="-gdwarf-2"
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
export MOZ_TELEMETRY_REPORTING=1
|
||||
|
||||
# PGO
|
||||
mk_add_options MOZ_PGO=1
|
||||
mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10'
|
||||
|
||||
# Enable parallel compiling
|
||||
mk_add_options MOZ_MAKE_FLAGS="-j4"
|
||||
|
||||
#Use ccache
|
||||
ac_add_options --with-ccache=/usr/bin/ccache
|
38
browser/config/mozconfigs/linux32/qt
Normal file
38
browser/config/mozconfigs/linux32/qt
Normal file
@ -0,0 +1,38 @@
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-optimize
|
||||
|
||||
ac_add_options --enable-update-packaging
|
||||
ac_add_options --disable-debug
|
||||
ac_add_options --enable-tests
|
||||
ac_add_options --enable-codesighs
|
||||
|
||||
CC=/tools/gcc-4.5/bin/gcc
|
||||
CXX=/tools/gcc-4.5/bin/g++
|
||||
# Avoid dependency on libstdc++ 4.5
|
||||
ac_add_options --enable-stdcxx-compat
|
||||
|
||||
export CFLAGS="-gdwarf-2"
|
||||
export CXXFLAGS="-gdwarf-2"
|
||||
|
||||
# For NSS symbols
|
||||
export MOZ_DEBUG_SYMBOLS=1
|
||||
ac_add_options --enable-debug-symbols="-gdwarf-2"
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
# PGO
|
||||
mk_add_options MOZ_PGO=1
|
||||
mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10'
|
||||
|
||||
# Enable parallel compiling
|
||||
mk_add_options MOZ_MAKE_FLAGS="-j4"
|
||||
|
||||
#Use ccache
|
||||
ac_add_options --with-ccache=/usr/bin/ccache
|
||||
|
||||
# QT Options
|
||||
export PKG_CONFIG_PATH=/tools/qt-4.6.3/qt/lib/pkgconfig
|
||||
ac_add_options --with-qtdir=/tools/qt-4.6.3/qt
|
||||
ac_add_options --enable-default-toolkit=cairo-qt
|
||||
ac_add_options --disable-crashreporter
|
28
browser/config/mozconfigs/linux32/release
Normal file
28
browser/config/mozconfigs/linux32/release
Normal file
@ -0,0 +1,28 @@
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-optimize
|
||||
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
|
||||
ac_add_options --enable-update-packaging
|
||||
ac_add_options --disable-debug
|
||||
ac_add_options --enable-tests
|
||||
ac_add_options --enable-official-branding
|
||||
|
||||
CC=/tools/gcc-4.5/bin/gcc
|
||||
CXX=/tools/gcc-4.5/bin/g++
|
||||
# Avoid dependency on libstdc++ 4.5
|
||||
ac_add_options --enable-stdcxx-compat
|
||||
|
||||
export CFLAGS="-gdwarf-2"
|
||||
export CXXFLAGS="-gdwarf-2"
|
||||
|
||||
# For NSS symbols
|
||||
export MOZ_DEBUG_SYMBOLS=1
|
||||
ac_add_options --enable-debug-symbols="-gdwarf-2"
|
||||
|
||||
# PGO
|
||||
mk_add_options MOZ_PGO=1
|
||||
mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10'
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
export MOZ_TELEMETRY_REPORTING=1
|
40
browser/config/mozconfigs/linux32/rpm
Normal file
40
browser/config/mozconfigs/linux32/rpm
Normal file
@ -0,0 +1,40 @@
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-optimize
|
||||
|
||||
ac_add_options --enable-update-packaging
|
||||
ac_add_options --disable-debug
|
||||
ac_add_options --enable-tests
|
||||
ac_add_options --enable-codesighs
|
||||
|
||||
# Options for rpm versions of mozconfigs
|
||||
PREFIX=/usr
|
||||
LIBDIR=${PREFIX}/lib
|
||||
ac_add_options --with-app-name=mozilla-nightly
|
||||
ac_add_options --disable-updater
|
||||
ac_add_options --prefix=$PREFIX
|
||||
ac_add_options --libdir=$LIBDIR
|
||||
|
||||
CC=/tools/gcc-4.5/bin/gcc
|
||||
CXX=/tools/gcc-4.5/bin/g++
|
||||
# Avoid dependency on libstdc++ 4.5
|
||||
ac_add_options --enable-stdcxx-compat
|
||||
|
||||
export CFLAGS="-gdwarf-2"
|
||||
export CXXFLAGS="-gdwarf-2"
|
||||
|
||||
# For NSS symbols
|
||||
export MOZ_DEBUG_SYMBOLS=1
|
||||
ac_add_options --enable-debug-symbols="-gdwarf-2"
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
export MOZ_TELEMETRY_REPORTING=1
|
||||
mk_add_options MOZ_PGO=1
|
||||
mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py'
|
||||
|
||||
# Enable parallel compiling
|
||||
mk_add_options MOZ_MAKE_FLAGS="-j4"
|
||||
|
||||
#Use ccache
|
||||
ac_add_options --with-ccache=/usr/bin/ccache
|
25
browser/config/mozconfigs/linux64/debug
Normal file
25
browser/config/mozconfigs/linux64/debug
Normal file
@ -0,0 +1,25 @@
|
||||
ac_add_options --enable-application=browser
|
||||
|
||||
ac_add_options --disable-optimize
|
||||
ac_add_options --enable-debug
|
||||
|
||||
ac_add_options --enable-tests
|
||||
ac_add_options --enable-trace-malloc
|
||||
|
||||
CC=/tools/gcc-4.5/bin/gcc
|
||||
CXX=/tools/gcc-4.5/bin/g++
|
||||
# Avoid dependency on libstdc++ 4.5
|
||||
ac_add_options --enable-stdcxx-compat
|
||||
|
||||
#export CFLAGS="-gdwarf-2"
|
||||
#export CXXFLAGS="-gdwarf-2"
|
||||
|
||||
# For NSS symbols
|
||||
export MOZ_DEBUG_SYMBOLS=1
|
||||
ac_add_options --enable-debug-symbols="-gdwarf-2"
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
# Enable parallel compiling
|
||||
mk_add_options MOZ_MAKE_FLAGS="-j4"
|
8
browser/config/mozconfigs/linux64/l10n-mozconfig
Normal file
8
browser/config/mozconfigs/linux64/l10n-mozconfig
Normal file
@ -0,0 +1,8 @@
|
||||
ac_add_options --with-l10n-base=../../l10n-central
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-official-branding
|
||||
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
|
||||
ac_add_options --enable-update-packaging
|
||||
|
||||
CC=/tools/gcc/bin/gcc
|
||||
CXX=/tools/gcc/bin/g++
|
37
browser/config/mozconfigs/linux64/nightly
Normal file
37
browser/config/mozconfigs/linux64/nightly
Normal file
@ -0,0 +1,37 @@
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-optimize
|
||||
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
|
||||
ac_add_options --enable-update-packaging
|
||||
ac_add_options --disable-debug
|
||||
ac_add_options --enable-tests
|
||||
ac_add_options --enable-codesighs
|
||||
|
||||
# Nightlies only since this has a cost in performance
|
||||
ac_add_options --enable-js-diagnostics
|
||||
|
||||
CC=/tools/gcc-4.5/bin/gcc
|
||||
CXX=/tools/gcc-4.5/bin/g++
|
||||
# Avoid dependency on libstdc++ 4.5
|
||||
ac_add_options --enable-stdcxx-compat
|
||||
|
||||
export CFLAGS="-gdwarf-2"
|
||||
export CXXFLAGS="-gdwarf-2"
|
||||
|
||||
# For NSS symbols
|
||||
export MOZ_DEBUG_SYMBOLS=1
|
||||
ac_add_options --enable-debug-symbols="-gdwarf-2"
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
export MOZ_TELEMETRY_REPORTING=1
|
||||
|
||||
# PGO
|
||||
mk_add_options MOZ_PGO=1
|
||||
mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10'
|
||||
|
||||
# Enable parallel compiling
|
||||
mk_add_options MOZ_MAKE_FLAGS="-j4"
|
||||
|
||||
#Use ccache
|
||||
ac_add_options --with-ccache=/usr/bin/ccache
|
28
browser/config/mozconfigs/linux64/release
Normal file
28
browser/config/mozconfigs/linux64/release
Normal file
@ -0,0 +1,28 @@
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-optimize
|
||||
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
|
||||
ac_add_options --enable-update-packaging
|
||||
ac_add_options --disable-debug
|
||||
ac_add_options --enable-tests
|
||||
ac_add_options --enable-official-branding
|
||||
|
||||
CC=/tools/gcc-4.5/bin/gcc
|
||||
CXX=/tools/gcc-4.5/bin/g++
|
||||
# Avoid dependency on libstdc++ 4.5
|
||||
ac_add_options --enable-stdcxx-compat
|
||||
|
||||
export CFLAGS="-gdwarf-2"
|
||||
export CXXFLAGS="-gdwarf-2"
|
||||
|
||||
# For NSS symbols
|
||||
export MOZ_DEBUG_SYMBOLS=1
|
||||
ac_add_options --enable-debug-symbols="-gdwarf-2"
|
||||
|
||||
# PGO
|
||||
mk_add_options MOZ_PGO=1
|
||||
mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10'
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
export MOZ_TELEMETRY_REPORTING=1
|
40
browser/config/mozconfigs/linux64/rpm
Normal file
40
browser/config/mozconfigs/linux64/rpm
Normal file
@ -0,0 +1,40 @@
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-optimize
|
||||
|
||||
ac_add_options --enable-update-packaging
|
||||
ac_add_options --disable-debug
|
||||
ac_add_options --enable-tests
|
||||
ac_add_options --enable-codesighs
|
||||
|
||||
# Options for rpm versions of mozconfigs
|
||||
PREFIX=/usr
|
||||
LIBDIR=${PREFIX}/lib64
|
||||
ac_add_options --with-app-name=mozilla-nightly
|
||||
ac_add_options --disable-updater
|
||||
ac_add_options --prefix=$PREFIX
|
||||
ac_add_options --libdir=$LIBDIR
|
||||
|
||||
CC=/tools/gcc-4.5/bin/gcc
|
||||
CXX=/tools/gcc-4.5/bin/g++
|
||||
# Avoid dependency on libstdc++ 4.5
|
||||
ac_add_options --enable-stdcxx-compat
|
||||
|
||||
export CFLAGS="-gdwarf-2"
|
||||
export CXXFLAGS="-gdwarf-2"
|
||||
|
||||
# For NSS symbols
|
||||
export MOZ_DEBUG_SYMBOLS=1
|
||||
ac_add_options --enable-debug-symbols="-gdwarf-2"
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
export MOZ_TELEMETRY_REPORTING=1
|
||||
mk_add_options MOZ_PGO=1
|
||||
mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py'
|
||||
|
||||
# Enable parallel compiling
|
||||
mk_add_options MOZ_MAKE_FLAGS="-j4"
|
||||
|
||||
#Use ccache
|
||||
ac_add_options --with-ccache=/usr/bin/ccache
|
24
browser/config/mozconfigs/macosx-universal/nightly
Normal file
24
browser/config/mozconfigs/macosx-universal/nightly
Normal file
@ -0,0 +1,24 @@
|
||||
. $topsrcdir/build/macosx/universal/mozconfig
|
||||
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
|
||||
ac_add_options --enable-update-packaging
|
||||
ac_add_options --enable-tests
|
||||
ac_add_options --enable-codesighs
|
||||
ac_add_options --disable-install-strip
|
||||
|
||||
# Nightlies only since this has a cost in performance
|
||||
ac_add_options --enable-js-diagnostics
|
||||
|
||||
export CFLAGS="-gdwarf-2"
|
||||
export CXXFLAGS="-gdwarf-2"
|
||||
|
||||
# For NSS symbols
|
||||
export MOZ_DEBUG_SYMBOLS=1
|
||||
ac_add_options --enable-debug-symbols="-gdwarf-2"
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
export MOZ_TELEMETRY_REPORTING=1
|
||||
mk_add_options MOZ_MAKE_FLAGS="-j4"
|
19
browser/config/mozconfigs/macosx-universal/release
Normal file
19
browser/config/mozconfigs/macosx-universal/release
Normal file
@ -0,0 +1,19 @@
|
||||
. $topsrcdir/build/macosx/universal/mozconfig
|
||||
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
|
||||
ac_add_options --enable-update-packaging
|
||||
ac_add_options --enable-tests
|
||||
ac_add_options --enable-official-branding
|
||||
|
||||
export CFLAGS="-gdwarf-2"
|
||||
export CXXFLAGS="-gdwarf-2"
|
||||
|
||||
# For NSS symbols
|
||||
export MOZ_DEBUG_SYMBOLS=1
|
||||
ac_add_options --enable-debug-symbols="-gdwarf-2"
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
export MOZ_TELEMETRY_REPORTING=1
|
28
browser/config/mozconfigs/macosx-universal/shark
Normal file
28
browser/config/mozconfigs/macosx-universal/shark
Normal file
@ -0,0 +1,28 @@
|
||||
# Just like nightlies, but without tests, not on an update channel, and with
|
||||
# shark and dtrace enabled
|
||||
. $topsrcdir/build/macosx/universal/mozconfig
|
||||
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --disable-tests
|
||||
ac_add_options --disable-install-strip
|
||||
|
||||
export CFLAGS="-gdwarf-2"
|
||||
export CXXFLAGS="-gdwarf-2"
|
||||
|
||||
# For NSS symbols
|
||||
export MOZ_DEBUG_SYMBOLS=1
|
||||
ac_add_options --enable-debug-symbols="-gdwarf-2"
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
# Enable parallel compiling
|
||||
mk_add_options MOZ_MAKE_FLAGS="-j4"
|
||||
|
||||
# shark specific options
|
||||
ac_add_options --enable-shark
|
||||
ac_add_options --enable-dtrace
|
||||
ac_add_options --enable-debugger-info-modules
|
||||
|
||||
# Need this to prevent name conflicts with the normal nightly build packages
|
||||
export MOZ_PKG_SPECIAL="shark"
|
22
browser/config/mozconfigs/macosx32/debug
Normal file
22
browser/config/mozconfigs/macosx32/debug
Normal file
@ -0,0 +1,22 @@
|
||||
# Don't use the standard mozconfig. We don't want universal for a debug build.
|
||||
#. $topsrcdir/build/macosx/universal/mozconfig
|
||||
|
||||
ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk
|
||||
|
||||
ac_add_options --disable-optimize
|
||||
ac_add_options --enable-debug
|
||||
ac_add_options --enable-libxul
|
||||
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-tests
|
||||
ac_add_options --enable-trace-malloc
|
||||
|
||||
# For NSS symbols
|
||||
export MOZ_DEBUG_SYMBOLS=1
|
||||
ac_add_options --enable-debug-symbols="-gdwarf-2"
|
||||
|
||||
# Enable parallel compiling
|
||||
mk_add_options MOZ_MAKE_FLAGS="-j4"
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
18
browser/config/mozconfigs/macosx64/debug
Normal file
18
browser/config/mozconfigs/macosx64/debug
Normal file
@ -0,0 +1,18 @@
|
||||
ac_add_options --disable-optimize
|
||||
ac_add_options --enable-debug
|
||||
ac_add_options --enable-libxul
|
||||
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-tests
|
||||
ac_add_options --enable-trace-malloc
|
||||
ac_add_options --enable-accessibility
|
||||
|
||||
# For NSS symbols
|
||||
export MOZ_DEBUG_SYMBOLS=1
|
||||
ac_add_options --enable-debug-symbols="-gdwarf-2"
|
||||
|
||||
# Enable parallel compiling
|
||||
mk_add_options MOZ_MAKE_FLAGS="-j4"
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
5
browser/config/mozconfigs/macosx64/l10n-mozconfig
Normal file
5
browser/config/mozconfigs/macosx64/l10n-mozconfig
Normal file
@ -0,0 +1,5 @@
|
||||
ac_add_options --with-l10n-base=../../l10n-central
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-official-branding
|
||||
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
|
||||
ac_add_options --enable-update-packaging
|
15
browser/config/mozconfigs/win32/debug
Normal file
15
browser/config/mozconfigs/win32/debug
Normal file
@ -0,0 +1,15 @@
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-jemalloc
|
||||
ac_add_options --disable-optimize
|
||||
ac_add_options --enable-debug
|
||||
ac_add_options --enable-libxul
|
||||
ac_add_options --enable-trace-malloc
|
||||
ac_add_options --enable-tests
|
||||
|
||||
# For NSS symbols
|
||||
export MOZ_DEBUG_SYMBOLS=1
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
mk_add_options MOZ_MAKE_FLAGS=-j1
|
5
browser/config/mozconfigs/win32/l10n-mozconfig
Normal file
5
browser/config/mozconfigs/win32/l10n-mozconfig
Normal file
@ -0,0 +1,5 @@
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
|
||||
ac_add_options --enable-update-packaging
|
||||
ac_add_options --enable-official-branding
|
||||
ac_add_options --with-l10n-base=../../l10n-central
|
21
browser/config/mozconfigs/win32/nightly
Normal file
21
browser/config/mozconfigs/win32/nightly
Normal file
@ -0,0 +1,21 @@
|
||||
# for pgo
|
||||
mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) $(MOZ_OBJDIR)/_profile/pgo/profileserver.py'
|
||||
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
|
||||
ac_add_options --enable-update-packaging
|
||||
ac_add_options --enable-jemalloc
|
||||
ac_add_options --enable-tests
|
||||
|
||||
# Nightlies only since this has a cost in performance
|
||||
ac_add_options --enable-js-diagnostics
|
||||
|
||||
# For NSS symbols
|
||||
export MOZ_DEBUG_SYMBOLS=1
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
export MOZ_TELEMETRY_REPORTING=1
|
||||
|
||||
mk_add_options MOZ_MAKE_FLAGS=-j1
|
17
browser/config/mozconfigs/win32/release
Normal file
17
browser/config/mozconfigs/win32/release
Normal file
@ -0,0 +1,17 @@
|
||||
# for pgo
|
||||
mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) $(MOZ_OBJDIR)/_profile/pgo/profileserver.py'
|
||||
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
|
||||
ac_add_options --enable-update-packaging
|
||||
ac_add_options --enable-jemalloc
|
||||
ac_add_options --enable-tests
|
||||
ac_add_options --enable-official-branding
|
||||
|
||||
# For NSS symbols
|
||||
export MOZ_DEBUG_SYMBOLS=1
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
export MOZ_TELEMETRY_REPORTING=1
|
14
browser/config/mozconfigs/win64/debug
Normal file
14
browser/config/mozconfigs/win64/debug
Normal file
@ -0,0 +1,14 @@
|
||||
ac_add_options --target=x86_64-pc-mingw32
|
||||
ac_add_options --host=x86_64-pc-mingw32
|
||||
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-jemalloc
|
||||
ac_add_options --disable-optimize
|
||||
ac_add_options --enable-debug
|
||||
ac_add_options --enable-libxul
|
||||
ac_add_options --enable-trace-malloc
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
mk_add_options MOZ_MAKE_FLAGS=-j1
|
21
browser/config/mozconfigs/win64/nightly
Normal file
21
browser/config/mozconfigs/win64/nightly
Normal file
@ -0,0 +1,21 @@
|
||||
ac_add_options --target=x86_64-pc-mingw32
|
||||
ac_add_options --host=x86_64-pc-mingw32
|
||||
|
||||
# for pgo
|
||||
mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) $(MOZ_OBJDIR)/_profile/pgo/profileserver.py'
|
||||
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
|
||||
ac_add_options --enable-update-packaging
|
||||
ac_add_options --enable-jemalloc
|
||||
ac_add_options --enable-debug-symbols
|
||||
|
||||
# Nightlies only since this has a cost in performance
|
||||
ac_add_options --enable-js-diagnostics
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
export MOZ_TELEMETRY_REPORTING=1
|
||||
|
||||
mk_add_options MOZ_MAKE_FLAGS=-j1
|
@ -1,5 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
@ -290,10 +290,14 @@ Highlighter.prototype = {
|
||||
closeButton.id = "highlighter-close-button";
|
||||
closeButton.appendChild(this.chromeDoc.createElement("image"));
|
||||
|
||||
closeButton.addEventListener("click",
|
||||
this.IUI.closeInspectorUI.bind(this.IUI), false);
|
||||
let boundCloseEventHandler = this.IUI.closeInspectorUI.bind(this.IUI, false);
|
||||
|
||||
closeButton.addEventListener("click", boundCloseEventHandler, false);
|
||||
|
||||
aParent.appendChild(closeButton);
|
||||
|
||||
this.boundCloseEventHandler = boundCloseEventHandler;
|
||||
this.closeButton = closeButton;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -303,6 +307,11 @@ Highlighter.prototype = {
|
||||
{
|
||||
this.browser.removeEventListener("scroll", this, true);
|
||||
this.browser.removeEventListener("resize", this, true);
|
||||
this.closeButton.removeEventListener("click", this.boundCloseEventHandler, false);
|
||||
this.boundCloseEventHandler = null;
|
||||
this.closeButton.parentNode.removeChild(this.closeButton);
|
||||
this.closeButton = null;
|
||||
this._contentRect = null;
|
||||
this._highlightRect = null;
|
||||
this._highlighting = false;
|
||||
this.veilTopBox = null;
|
||||
@ -337,7 +346,7 @@ Highlighter.prototype = {
|
||||
highlight: function Highlighter_highlight(aScroll)
|
||||
{
|
||||
// node is not set or node is not highlightable, bail
|
||||
if (!this.node || !this.isNodeHighlightable()) {
|
||||
if (!this.node || !this.isNodeHighlightable(this.node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -439,28 +448,41 @@ Highlighter.prototype = {
|
||||
*/
|
||||
highlightRectangle: function Highlighter_highlightRectangle(aRect)
|
||||
{
|
||||
let oldRect = this._highlightRect;
|
||||
let oldRect = this._contentRect;
|
||||
|
||||
if (oldRect && aRect.top == oldRect.top && aRect.left == oldRect.left &&
|
||||
aRect.width == oldRect.width && aRect.height == oldRect.height) {
|
||||
return this._highlighting; // same rectangle
|
||||
}
|
||||
|
||||
if (aRect.left >= 0 && aRect.top >= 0 &&
|
||||
aRect.width > 0 && aRect.height > 0) {
|
||||
// get page zoom factor, if any
|
||||
let zoom =
|
||||
this.win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIDOMWindowUtils)
|
||||
.screenPixelsPerCSSPixel;
|
||||
|
||||
// adjust rect for zoom scaling
|
||||
let aRectScaled = {};
|
||||
for (let prop in aRect) {
|
||||
aRectScaled[prop] = aRect[prop] * zoom;
|
||||
}
|
||||
|
||||
if (aRectScaled.left >= 0 && aRectScaled.top >= 0 &&
|
||||
aRectScaled.width > 0 && aRectScaled.height > 0) {
|
||||
// The bottom div and the right div are flexibles (flex=1).
|
||||
// We don't need to resize them.
|
||||
this.veilTopBox.style.height = aRect.top + "px";
|
||||
this.veilLeftBox.style.width = aRect.left + "px";
|
||||
this.veilMiddleBox.style.height = aRect.height + "px";
|
||||
this.veilTransparentBox.style.width = aRect.width + "px";
|
||||
this.veilTopBox.style.height = aRectScaled.top + "px";
|
||||
this.veilLeftBox.style.width = aRectScaled.left + "px";
|
||||
this.veilMiddleBox.style.height = aRectScaled.height + "px";
|
||||
this.veilTransparentBox.style.width = aRectScaled.width + "px";
|
||||
|
||||
this._highlighting = true;
|
||||
} else {
|
||||
this.unhighlight();
|
||||
}
|
||||
|
||||
this._highlightRect = aRect;
|
||||
this._contentRect = aRect; // save orig (non-scaled) rect
|
||||
this._highlightRect = aRectScaled; // and save the scaled rect.
|
||||
|
||||
return this._highlighting;
|
||||
},
|
||||
@ -588,18 +610,18 @@ Highlighter.prototype = {
|
||||
get highlitNode()
|
||||
{
|
||||
// Not highlighting? Bail.
|
||||
if (!this._highlighting || !this._highlightRect) {
|
||||
if (!this._highlighting || !this._contentRect) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let a = {
|
||||
x: this._highlightRect.left,
|
||||
y: this._highlightRect.top
|
||||
x: this._contentRect.left,
|
||||
y: this._contentRect.top
|
||||
};
|
||||
|
||||
let b = {
|
||||
x: a.x + this._highlightRect.width,
|
||||
y: a.y + this._highlightRect.height
|
||||
x: a.x + this._contentRect.width,
|
||||
y: a.y + this._contentRect.height
|
||||
};
|
||||
|
||||
// Get midpoint of diagonal line.
|
||||
@ -610,17 +632,19 @@ Highlighter.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Is this.node highlightable?
|
||||
* Is the specified node highlightable?
|
||||
*
|
||||
* @param nsIDOMNode aNode
|
||||
* the DOM element in question
|
||||
* @returns boolean
|
||||
* True if the node is highlightable or false otherwise.
|
||||
*/
|
||||
isNodeHighlightable: function Highlighter_isNodeHighlightable()
|
||||
isNodeHighlightable: function Highlighter_isNodeHighlightable(aNode)
|
||||
{
|
||||
if (!this.node || this.node.nodeType != this.node.ELEMENT_NODE) {
|
||||
if (aNode.nodeType != aNode.ELEMENT_NODE) {
|
||||
return false;
|
||||
}
|
||||
let nodeName = this.node.nodeName.toLowerCase();
|
||||
let nodeName = aNode.nodeName.toLowerCase();
|
||||
return !INSPECTOR_INVISIBLE_ELEMENTS[nodeName];
|
||||
},
|
||||
|
||||
@ -1147,6 +1171,69 @@ InspectorUI.prototype = {
|
||||
event.stopPropagation();
|
||||
}
|
||||
break;
|
||||
case this.chromeWin.KeyEvent.DOM_VK_LEFT:
|
||||
let node;
|
||||
if (this.selection) {
|
||||
node = this.selection.parentNode;
|
||||
} else {
|
||||
node = this.defaultSelection;
|
||||
}
|
||||
if (node && this.highlighter.isNodeHighlightable(node)) {
|
||||
this.inspectNode(node, true);
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
break;
|
||||
case this.chromeWin.KeyEvent.DOM_VK_RIGHT:
|
||||
if (this.selection) {
|
||||
// Find the first child that is highlightable.
|
||||
for (let i = 0; i < this.selection.childNodes.length; i++) {
|
||||
node = this.selection.childNodes[i];
|
||||
if (node && this.highlighter.isNodeHighlightable(node)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
node = this.defaultSelection;
|
||||
}
|
||||
if (node && this.highlighter.isNodeHighlightable(node)) {
|
||||
this.inspectNode(node, true);
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
break;
|
||||
case this.chromeWin.KeyEvent.DOM_VK_UP:
|
||||
if (this.selection) {
|
||||
// Find a previous sibling that is highlightable.
|
||||
node = this.selection.previousSibling;
|
||||
while (node && !this.highlighter.isNodeHighlightable(node)) {
|
||||
node = node.previousSibling;
|
||||
}
|
||||
} else {
|
||||
node = this.defaultSelection;
|
||||
}
|
||||
if (node && this.highlighter.isNodeHighlightable(node)) {
|
||||
this.inspectNode(node, true);
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
break;
|
||||
case this.chromeWin.KeyEvent.DOM_VK_DOWN:
|
||||
if (this.selection) {
|
||||
// Find a next sibling that is highlightable.
|
||||
node = this.selection.nextSibling;
|
||||
while (node && !this.highlighter.isNodeHighlightable(node)) {
|
||||
node = node.nextSibling;
|
||||
}
|
||||
} else {
|
||||
node = this.defaultSelection;
|
||||
}
|
||||
if (node && this.highlighter.isNodeHighlightable(node)) {
|
||||
this.inspectNode(node, true);
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1181,11 +1268,13 @@ InspectorUI.prototype = {
|
||||
*
|
||||
* @param aNode
|
||||
* the element in the document to inspect
|
||||
* @param aScroll
|
||||
* force scroll?
|
||||
*/
|
||||
inspectNode: function IUI_inspectNode(aNode)
|
||||
inspectNode: function IUI_inspectNode(aNode, aScroll)
|
||||
{
|
||||
this.select(aNode, true, true);
|
||||
this.highlighter.highlightNode(aNode);
|
||||
this.highlighter.highlightNode(aNode, { scroll: aScroll });
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -60,6 +60,8 @@ _BROWSER_FILES = \
|
||||
browser_inspector_editor.js \
|
||||
browser_inspector_bug_566084_location_changed.js \
|
||||
browser_inspector_infobar.js \
|
||||
browser_inspector_bug_690361.js \
|
||||
browser_inspector_bug_672902_keyboard_shortcuts.js \
|
||||
$(NULL)
|
||||
|
||||
# Disabled due to constant failures
|
||||
|
@ -0,0 +1,142 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
|
||||
// Tests that the keybindings for highlighting different elements work as
|
||||
// intended.
|
||||
|
||||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
|
||||
let doc;
|
||||
let node;
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onload() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
|
||||
doc = content.document;
|
||||
waitForFocus(setupKeyBindingsTest, content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,<html><head><title>Test for the " +
|
||||
"highlighter keybindings</title></head><body><h1>Hello" +
|
||||
"</h1><p><strong>Greetings, earthlings!</strong> I come" +
|
||||
" in peace.</body></html>";
|
||||
|
||||
function setupKeyBindingsTest()
|
||||
{
|
||||
Services.obs.addObserver(findAndHighlightNode,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED,
|
||||
false);
|
||||
InspectorUI.toggleInspectorUI();
|
||||
}
|
||||
|
||||
function findAndHighlightNode()
|
||||
{
|
||||
Services.obs.removeObserver(findAndHighlightNode,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
|
||||
|
||||
executeSoon(function() {
|
||||
Services.obs.addObserver(highlightBodyNode,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING,
|
||||
false);
|
||||
// Test that navigating around without a selected node gets us to the
|
||||
// body element.
|
||||
node = doc.querySelector("body");
|
||||
EventUtils.synthesizeKey("VK_RIGHT", { });
|
||||
});
|
||||
}
|
||||
|
||||
function highlightBodyNode()
|
||||
{
|
||||
Services.obs.removeObserver(highlightBodyNode,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
|
||||
is(InspectorUI.selection, node, "selected body element");
|
||||
|
||||
executeSoon(function() {
|
||||
Services.obs.addObserver(highlightHeaderNode,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING,
|
||||
false);
|
||||
// Test that moving to the child works.
|
||||
node = doc.querySelector("h1");
|
||||
EventUtils.synthesizeKey("VK_RIGHT", { });
|
||||
});
|
||||
}
|
||||
|
||||
function highlightHeaderNode()
|
||||
{
|
||||
Services.obs.removeObserver(highlightHeaderNode,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
|
||||
is(InspectorUI.selection, node, "selected h1 element");
|
||||
|
||||
executeSoon(function() {
|
||||
Services.obs.addObserver(highlightParagraphNode,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING,
|
||||
false);
|
||||
// Test that moving to the next sibling works.
|
||||
node = doc.querySelector("p");
|
||||
EventUtils.synthesizeKey("VK_DOWN", { });
|
||||
});
|
||||
}
|
||||
|
||||
function highlightParagraphNode()
|
||||
{
|
||||
Services.obs.removeObserver(highlightParagraphNode,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
|
||||
is(InspectorUI.selection, node, "selected p element");
|
||||
|
||||
executeSoon(function() {
|
||||
Services.obs.addObserver(highlightHeaderNodeAgain,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING,
|
||||
false);
|
||||
// Test that moving to the previous sibling works.
|
||||
node = doc.querySelector("h1");
|
||||
EventUtils.synthesizeKey("VK_UP", { });
|
||||
});
|
||||
}
|
||||
|
||||
function highlightHeaderNodeAgain()
|
||||
{
|
||||
Services.obs.removeObserver(highlightHeaderNodeAgain,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
|
||||
is(InspectorUI.selection, node, "selected h1 element");
|
||||
|
||||
executeSoon(function() {
|
||||
Services.obs.addObserver(highlightParentNode,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING,
|
||||
false);
|
||||
// Test that moving to the parent works.
|
||||
node = doc.querySelector("body");
|
||||
EventUtils.synthesizeKey("VK_LEFT", { });
|
||||
});
|
||||
}
|
||||
|
||||
function highlightParentNode()
|
||||
{
|
||||
Services.obs.removeObserver(highlightParentNode,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
|
||||
is(InspectorUI.selection, node, "selected body element");
|
||||
|
||||
// Test that locking works.
|
||||
EventUtils.synthesizeKey("VK_RETURN", { });
|
||||
executeSoon(isTheNodeLocked);
|
||||
}
|
||||
|
||||
function isTheNodeLocked()
|
||||
{
|
||||
ok(!InspectorUI.inspecting, "the node is locked");
|
||||
Services.obs.addObserver(finishUp,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED,
|
||||
false);
|
||||
InspectorUI.closeInspectorUI();
|
||||
}
|
||||
|
||||
function finishUp() {
|
||||
Services.obs.removeObserver(finishUp,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
|
||||
doc = node = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Inspector Initialization and Shutdown Tests.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Rob Campbell <rcampbell@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
let doc;
|
||||
let salutation;
|
||||
let closing;
|
||||
|
||||
function createDocument()
|
||||
{
|
||||
doc.body.innerHTML = '<div id="first" style="{ margin: 10em; ' +
|
||||
'font-size: 14pt; font-family: helvetica, sans-serif; color: #AAA}">\n' +
|
||||
'<h1>Some header text</h1>\n' +
|
||||
'<p id="salutation" style="{font-size: 12pt}">hi.</p>\n' +
|
||||
'<p id="body" style="{font-size: 12pt}">I am a test-case. This text exists ' +
|
||||
'solely to provide some things to test the inspector initialization.</p>\n' +
|
||||
'If you are reading this, you should go do something else instead. Maybe ' +
|
||||
'read a book. Or better yet, write some test-cases for another bit of code. ' +
|
||||
'<span style="{font-style: italic}">Maybe more inspector test-cases!</span></p>\n' +
|
||||
'<p id="closing">end transmission</p>\n' +
|
||||
'</div>';
|
||||
doc.title = "Inspector Opening and Closing Test";
|
||||
startInspectorTests();
|
||||
}
|
||||
|
||||
function startInspectorTests()
|
||||
{
|
||||
ok(InspectorUI, "InspectorUI variable exists");
|
||||
Services.obs.addObserver(runInspectorTests,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
|
||||
InspectorUI.toggleInspectorUI();
|
||||
}
|
||||
|
||||
function runInspectorTests()
|
||||
{
|
||||
Services.obs.removeObserver(runInspectorTests,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
|
||||
Services.obs.addObserver(closeInspectorTests,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
|
||||
|
||||
ok(InspectorUI.toolbar, "we have the toolbar.");
|
||||
ok(!InspectorUI.toolbar.hidden, "toolbar is visible");
|
||||
ok(InspectorUI.inspecting, "Inspector is inspecting");
|
||||
ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
|
||||
ok(InspectorUI.highlighter, "Highlighter is up");
|
||||
|
||||
salutation = doc.getElementById("salutation");
|
||||
InspectorUI.inspectNode(salutation);
|
||||
|
||||
let button = document.getElementById("highlighter-close-button");
|
||||
button.click();
|
||||
}
|
||||
|
||||
function closeInspectorTests()
|
||||
{
|
||||
Services.obs.removeObserver(closeInspectorTests,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
|
||||
Services.obs.addObserver(inspectorOpenedTrap,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
|
||||
|
||||
ok(!InspectorUI.isInspectorOpen, "Inspector Tree Panel is not open");
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
gBrowser.removeCurrentTab();
|
||||
}, true);
|
||||
|
||||
gBrowser.tabContainer.addEventListener("TabSelect", finishInspectorTests, false);
|
||||
}
|
||||
|
||||
function inspectorOpenedTrap()
|
||||
{
|
||||
ok(false, "Inspector opened! Should not have done so.");
|
||||
InspectorUI.closeInspectorUI(false);
|
||||
}
|
||||
|
||||
function finishInspectorTests()
|
||||
{
|
||||
gBrowser.tabContainer.removeEventListener("TabSelect", finishInspectorTests, false);
|
||||
|
||||
Services.obs.removeObserver(inspectorOpenedTrap,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
|
||||
|
||||
requestLongerTimeout(4); // give the inspector a chance to open
|
||||
executeSoon(function() {
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
doc = content.document;
|
||||
waitForFocus(createDocument, content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,basic tests for inspector";
|
||||
}
|
||||
|
@ -40,6 +40,7 @@
|
||||
|
||||
let doc;
|
||||
let h1;
|
||||
let div;
|
||||
|
||||
function createDocument()
|
||||
{
|
||||
@ -49,7 +50,7 @@ function createDocument()
|
||||
let p2 = doc.createElement("p");
|
||||
let div2 = doc.createElement("div");
|
||||
let p3 = doc.createElement("p");
|
||||
doc.title = "Inspector Tree Selection Test";
|
||||
doc.title = "Inspector Highlighter Meatballs";
|
||||
h1.textContent = "Inspector Tree Selection Test";
|
||||
p1.textContent = "This is some example text";
|
||||
p2.textContent = "Lorem ipsum dolor sit amet, consectetur adipisicing " +
|
||||
@ -66,19 +67,28 @@ function createDocument()
|
||||
"dolor in reprehenderit in voluptate velit esse cillum dolore eu " +
|
||||
"fugiat nulla pariatur. Excepteur sint occaecat cupidatat non " +
|
||||
"proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
|
||||
let div3 = doc.createElement("div");
|
||||
div3.id = "checkOutThisWickedSpread";
|
||||
div3.setAttribute("style", "position: absolute; top: 20px; right: 20px; height: 20px; width: 20px; background-color: yellow; border: 1px dashed black;");
|
||||
let p4 = doc.createElement("p");
|
||||
p4.setAttribute("style", "font-weight: 200; font-size: 8px; text-align: center;");
|
||||
p4.textContent = "Smörgåsbord!";
|
||||
div.appendChild(h1);
|
||||
div.appendChild(p1);
|
||||
div.appendChild(p2);
|
||||
div2.appendChild(p3);
|
||||
div3.appendChild(p4);
|
||||
doc.body.appendChild(div);
|
||||
doc.body.appendChild(div2);
|
||||
doc.body.appendChild(div3);
|
||||
|
||||
setupHighlighterTests();
|
||||
}
|
||||
|
||||
function setupHighlighterTests()
|
||||
{
|
||||
h1 = doc.querySelectorAll("h1")[0];
|
||||
ok(h1, "we have the header node");
|
||||
h1 = doc.querySelector("h1");
|
||||
ok(h1, "we have the header");
|
||||
Services.obs.addObserver(runSelectionTests,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
|
||||
InspectorUI.toggleInspectorUI();
|
||||
@ -99,7 +109,7 @@ function runSelectionTests()
|
||||
function performTestComparisons(evt)
|
||||
{
|
||||
Services.obs.removeObserver(performTestComparisons,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
|
||||
|
||||
InspectorUI.stopInspecting();
|
||||
ok(InspectorUI.highlighter.isHighlighting, "highlighter is highlighting");
|
||||
@ -107,7 +117,61 @@ function performTestComparisons(evt)
|
||||
is(InspectorUI.selection, h1, "selection matches node");
|
||||
is(InspectorUI.selection, InspectorUI.highlighter.highlitNode, "selection matches highlighter");
|
||||
|
||||
doc = h1 = null;
|
||||
Services.obs.addObserver(finishTestComparisons,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
|
||||
|
||||
div = doc.querySelector("div#checkOutThisWickedSpread");
|
||||
|
||||
executeSoon(function() {
|
||||
InspectorUI.inspectNode(div);
|
||||
});
|
||||
}
|
||||
|
||||
function finishTestComparisons()
|
||||
{
|
||||
Services.obs.removeObserver(finishTestComparisons,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
|
||||
|
||||
// get dimensions of div element
|
||||
let divDims = div.getBoundingClientRect();
|
||||
let divWidth = divDims.width;
|
||||
let divHeight = divDims.height;
|
||||
|
||||
// get dimensions of transparent veil box over element
|
||||
let veilBoxDims =
|
||||
InspectorUI.highlighter.veilTransparentBox.getBoundingClientRect();
|
||||
let veilBoxWidth = veilBoxDims.width;
|
||||
let veilBoxHeight = veilBoxDims.height;
|
||||
|
||||
is(veilBoxWidth, divWidth, "transparent veil box width matches dimensions of element (no zoom)");
|
||||
is(veilBoxHeight, divHeight, "transparent veil box height matches dimensions of element (no zoom)");
|
||||
// zoom the page by a factor of 2
|
||||
let contentViewer = InspectorUI.browser.docShell.contentViewer
|
||||
.QueryInterface(Ci.nsIMarkupDocumentViewer);
|
||||
contentViewer.fullZoom = 2;
|
||||
|
||||
// check what zoom factor we're at, should be 2
|
||||
let zoom =
|
||||
InspectorUI.win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIDOMWindowUtils)
|
||||
.screenPixelsPerCSSPixel;
|
||||
|
||||
is(zoom, 2, "zoom is 2?");
|
||||
|
||||
// simulate the zoomed dimensions of the div element
|
||||
let divDims = div.getBoundingClientRect();
|
||||
let divWidth = divDims.width * zoom;
|
||||
let divHeight = divDims.height * zoom;
|
||||
|
||||
// now zoomed, get new dimensions of transparent veil box over element
|
||||
let veilBoxDims = InspectorUI.highlighter.veilTransparentBox.getBoundingClientRect();
|
||||
let veilBoxWidth = veilBoxDims.width;
|
||||
let veilBoxHeight = veilBoxDims.height;
|
||||
|
||||
is(veilBoxWidth, divWidth, "transparent veil box width matches width of element (2x zoom)");
|
||||
is(veilBoxHeight, divHeight, "transparent veil box height matches width of element (2x zoom)");
|
||||
|
||||
doc = h1 = div = null;
|
||||
executeSoon(finishUp);
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,6 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
// WARNING: do not 'use_strict' without reading the notes in envEval;
|
||||
|
||||
var EXPORTED_SYMBOLS = ["Templater"];
|
||||
|
||||
@ -47,20 +46,31 @@ const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const Node = Ci.nsIDOMNode;
|
||||
|
||||
// WARNING: do not 'use_strict' without reading the notes in _envEval();
|
||||
|
||||
/**
|
||||
* A templater that allows one to quickly template DOM nodes.
|
||||
*/
|
||||
function Templater() {
|
||||
this.scope = [];
|
||||
this.stack = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive function to walk the tree processing the attributes as it goes.
|
||||
* @param node the node to process.
|
||||
* @param node the node to process. If you pass a string in instead of a DOM
|
||||
* element, it is assumed to be an id for use with document.getElementById()
|
||||
* @param data the data to use for node processing.
|
||||
*/
|
||||
Templater.prototype.processNode = function(node, data) {
|
||||
this.scope.push(node.nodeName + (node.id ? '#' + node.id : ''));
|
||||
if (typeof node === 'string') {
|
||||
node = document.getElementById(node);
|
||||
}
|
||||
if (data == null) {
|
||||
data = {};
|
||||
}
|
||||
this.stack.push(node.nodeName + (node.id ? '#' + node.id : ''));
|
||||
try {
|
||||
// Process attributes
|
||||
if (node.attributes && node.attributes.length) {
|
||||
@ -68,11 +78,11 @@ Templater.prototype.processNode = function(node, data) {
|
||||
// some types of processing from happening, and foreach must come first
|
||||
// because it defines new data on which 'if' might depend.
|
||||
if (node.hasAttribute('foreach')) {
|
||||
this.processForEach(node, data);
|
||||
this._processForEach(node, data);
|
||||
return;
|
||||
}
|
||||
if (node.hasAttribute('if')) {
|
||||
if (!this.processIf(node, data)) {
|
||||
if (!this._processIf(node, data)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -81,22 +91,22 @@ Templater.prototype.processNode = function(node, data) {
|
||||
// It's good to clean up the attributes when we've processed them,
|
||||
// but if we do it straight away, we mess up the array index
|
||||
var attrs = Array.prototype.slice.call(node.attributes);
|
||||
for (let i = 0, attLen = attrs.length; i < attLen; i++) {
|
||||
for (var i = 0; i < attrs.length; i++) {
|
||||
var value = attrs[i].value;
|
||||
var name = attrs[i].name;
|
||||
this.scope.push(name);
|
||||
this.stack.push(name);
|
||||
try {
|
||||
if (name === 'save') {
|
||||
// Save attributes are a setter using the node
|
||||
value = this.stripBraces(value);
|
||||
this.property(value, data, node);
|
||||
value = this._stripBraces(value);
|
||||
this._property(value, data, node);
|
||||
node.removeAttribute('save');
|
||||
} else if (name.substring(0, 2) === 'on') {
|
||||
// Event registration relies on property doing a bind
|
||||
value = this.stripBraces(value);
|
||||
var func = this.property(value, data);
|
||||
value = this._stripBraces(value);
|
||||
var func = this._property(value, data);
|
||||
if (typeof func !== 'function') {
|
||||
this.handleError('Expected ' + value +
|
||||
this._handleError('Expected ' + value +
|
||||
' to resolve to a function, but got ' + typeof func);
|
||||
}
|
||||
node.removeAttribute(name);
|
||||
@ -107,10 +117,9 @@ Templater.prototype.processNode = function(node, data) {
|
||||
}
|
||||
} else {
|
||||
// Replace references in all other attributes
|
||||
var self = this;
|
||||
var newValue = value.replace(/\$\{[^}]*\}/g, function(path) {
|
||||
return self.envEval(path.slice(2, -1), data, value);
|
||||
});
|
||||
return this._envEval(path.slice(2, -1), data, value);
|
||||
}.bind(this));
|
||||
// Remove '_' prefix of attribute names so the DOM won't try
|
||||
// to use them before we've processed the template
|
||||
if (name.charAt(0) === '_') {
|
||||
@ -121,43 +130,44 @@ Templater.prototype.processNode = function(node, data) {
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
this.scope.pop();
|
||||
this.stack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loop through our children calling processNode. First clone them, so the
|
||||
// set of nodes that we visit will be unaffected by additions or removals.
|
||||
var children = Array.prototype.slice.call(node.childNodes);
|
||||
for (let j = 0, numChildren = children.length; j < numChildren; j++) {
|
||||
this.processNode(children[j], data);
|
||||
var childNodes = Array.prototype.slice.call(node.childNodes);
|
||||
for (var j = 0; j < childNodes.length; j++) {
|
||||
this.processNode(childNodes[j], data);
|
||||
}
|
||||
|
||||
if (node.nodeType === Ci.nsIDOMNode.TEXT_NODE) {
|
||||
this.processTextNode(node, data);
|
||||
if (node.nodeType === Node.TEXT_NODE) {
|
||||
this._processTextNode(node, data);
|
||||
}
|
||||
} finally {
|
||||
this.scope.pop();
|
||||
delete data.__element;
|
||||
this.stack.pop();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle <x if="${...}">
|
||||
* @param node An element with an 'if' attribute
|
||||
* @param data The data to use with envEval
|
||||
* @param data The data to use with _envEval()
|
||||
* @returns true if processing should continue, false otherwise
|
||||
*/
|
||||
Templater.prototype.processIf = function(node, data) {
|
||||
this.scope.push('if');
|
||||
Templater.prototype._processIf = function(node, data) {
|
||||
this.stack.push('if');
|
||||
try {
|
||||
var originalValue = node.getAttribute('if');
|
||||
var value = this.stripBraces(originalValue);
|
||||
var value = this._stripBraces(originalValue);
|
||||
var recurse = true;
|
||||
try {
|
||||
var reply = this.envEval(value, data, originalValue);
|
||||
var reply = this._envEval(value, data, originalValue);
|
||||
recurse = !!reply;
|
||||
} catch (ex) {
|
||||
this.handleError('Error with \'' + value + '\'', ex);
|
||||
this._handleError('Error with \'' + value + '\'', ex);
|
||||
recurse = false;
|
||||
}
|
||||
if (!recurse) {
|
||||
@ -166,18 +176,22 @@ Templater.prototype.processIf = function(node, data) {
|
||||
node.removeAttribute('if');
|
||||
return recurse;
|
||||
} finally {
|
||||
this.scope.pop();
|
||||
this.stack.pop();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle <x foreach="param in ${array}"> and the special case of
|
||||
* <loop foreach="param in ${array}">
|
||||
* <loop foreach="param in ${array}">.
|
||||
* This function is responsible for extracting what it has to do from the
|
||||
* attributes, and getting the data to work on (including resolving promises
|
||||
* in getting the array). It delegates to _processForEachLoop to actually
|
||||
* unroll the data.
|
||||
* @param node An element with a 'foreach' attribute
|
||||
* @param data The data to use with envEval
|
||||
* @param data The data to use with _envEval()
|
||||
*/
|
||||
Templater.prototype.processForEach = function(node, data) {
|
||||
this.scope.push('foreach');
|
||||
Templater.prototype._processForEach = function(node, data) {
|
||||
this.stack.push('foreach');
|
||||
try {
|
||||
var originalValue = node.getAttribute('foreach');
|
||||
var value = originalValue;
|
||||
@ -185,61 +199,86 @@ Templater.prototype.processForEach = function(node, data) {
|
||||
var paramName = 'param';
|
||||
if (value.charAt(0) === '$') {
|
||||
// No custom loop variable name. Use the default: 'param'
|
||||
value = this.stripBraces(value);
|
||||
value = this._stripBraces(value);
|
||||
} else {
|
||||
// Extract the loop variable name from 'NAME in ${ARRAY}'
|
||||
var nameArr = value.split(' in ');
|
||||
paramName = nameArr[0].trim();
|
||||
value = this.stripBraces(nameArr[1].trim());
|
||||
value = this._stripBraces(nameArr[1].trim());
|
||||
}
|
||||
node.removeAttribute('foreach');
|
||||
try {
|
||||
var self = this;
|
||||
// Process a single iteration of a loop
|
||||
var processSingle = function(member, node, ref) {
|
||||
var clone = node.cloneNode(true);
|
||||
clone.removeAttribute('foreach');
|
||||
ref.parentNode.insertBefore(clone, ref);
|
||||
data[paramName] = member;
|
||||
self.processNode(clone, data);
|
||||
delete data[paramName];
|
||||
};
|
||||
|
||||
// processSingle is no good for <loop> nodes where we want to work on
|
||||
// the children rather than the node itself
|
||||
var processAll = function(scope, member) {
|
||||
self.scope.push(scope);
|
||||
try {
|
||||
if (node.nodeName === 'loop') {
|
||||
for (let i = 0, numChildren = node.children.length; i < numChildren; i++) {
|
||||
processSingle(member, node.children[i], node);
|
||||
}
|
||||
} else {
|
||||
processSingle(member, node, node);
|
||||
}
|
||||
} finally {
|
||||
self.scope.pop();
|
||||
}
|
||||
};
|
||||
|
||||
let reply = this.envEval(value, data, originalValue);
|
||||
if (Array.isArray(reply)) {
|
||||
reply.forEach(function(data, i) {
|
||||
processAll('' + i, data)
|
||||
}, this);
|
||||
} else {
|
||||
for (let param in reply) {
|
||||
if (reply.hasOwnProperty(param)) {
|
||||
processAll(param, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
var evaled = this._envEval(value, data, originalValue);
|
||||
this._handleAsync(evaled, node, function(reply, siblingNode) {
|
||||
this._processForEachLoop(reply, node, siblingNode, data, paramName);
|
||||
}.bind(this));
|
||||
node.parentNode.removeChild(node);
|
||||
} catch (ex) {
|
||||
this.handleError('Error with \'' + value + '\'', ex);
|
||||
this._handleError('Error with \'' + value + '\'', ex);
|
||||
}
|
||||
} finally {
|
||||
this.scope.pop();
|
||||
this.stack.pop();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Called by _processForEach to handle looping over the data in a foreach loop.
|
||||
* This works with both arrays and objects.
|
||||
* Calls _processForEachMember() for each member of 'set'
|
||||
* @param set The object containing the data to loop over
|
||||
* @param template The node to copy for each set member
|
||||
* @param sibling The sibling node to which we add things
|
||||
* @param data the data to use for node processing
|
||||
* @param paramName foreach loops have a name for the parameter currently being
|
||||
* processed. The default is 'param'. e.g. <loop foreach="param in ${x}">...
|
||||
*/
|
||||
Templater.prototype._processForEachLoop = function(set, template, sibling, data, paramName) {
|
||||
if (Array.isArray(set)) {
|
||||
set.forEach(function(member, i) {
|
||||
this._processForEachMember(member, template, sibling, data, paramName, '' + i);
|
||||
}, this);
|
||||
} else {
|
||||
for (var member in set) {
|
||||
if (set.hasOwnProperty(member)) {
|
||||
this._processForEachMember(member, template, sibling, data, paramName, member);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Called by _processForEachLoop() to resolve any promises in the array (the
|
||||
* array itself can also be a promise, but that is resolved by
|
||||
* _processForEach()). Handle <LOOP> elements (which are taken out of the DOM),
|
||||
* clone the template, and pass the processing on to processNode().
|
||||
* @param member The data item to use in templating
|
||||
* @param template The node to copy for each set member
|
||||
* @param siblingNode The parent node to which we add things
|
||||
* @param data the data to use for node processing
|
||||
* @param paramName The name given to 'member' by the foreach attribute
|
||||
* @param frame A name to push on the stack for debugging
|
||||
*/
|
||||
Templater.prototype._processForEachMember = function(member, template, siblingNode, data, paramName, frame) {
|
||||
this.stack.push(frame);
|
||||
try {
|
||||
this._handleAsync(member, siblingNode, function(reply, node) {
|
||||
data[paramName] = reply;
|
||||
if (node.nodeName.toLowerCase() === 'loop') {
|
||||
for (var i = 0; i < node.childNodes.length; i++) {
|
||||
var clone = node.childNodes[i].cloneNode(true);
|
||||
node.parentNode.insertBefore(clone, node);
|
||||
this.processNode(clone, data);
|
||||
}
|
||||
} else {
|
||||
var clone = template.cloneNode(true);
|
||||
clone.removeAttribute('foreach');
|
||||
node.parentNode.insertBefore(clone, node);
|
||||
this.processNode(clone, data);
|
||||
}
|
||||
delete data[paramName];
|
||||
}.bind(this));
|
||||
} finally {
|
||||
this.stack.pop();
|
||||
}
|
||||
};
|
||||
|
||||
@ -248,9 +287,9 @@ Templater.prototype.processForEach = function(node, data) {
|
||||
* sections parsed out. We replace the node by altering node.parentNode but
|
||||
* we could probably use a DOM Text API to achieve the same thing.
|
||||
* @param node The Text node to work on
|
||||
* @param data The data to use in calls to envEval
|
||||
* @param data The data to use in calls to _envEval()
|
||||
*/
|
||||
Templater.prototype.processTextNode = function(node, data) {
|
||||
Templater.prototype._processTextNode = function(node, data) {
|
||||
// Replace references in other attributes
|
||||
var value = node.data;
|
||||
// We can't use the string.replace() with function trick (see generic
|
||||
@ -270,33 +309,68 @@ Templater.prototype.processTextNode = function(node, data) {
|
||||
return;
|
||||
}
|
||||
if (part.charAt(0) === '$') {
|
||||
part = this.envEval(part.slice(1), data, node.data);
|
||||
part = this._envEval(part.slice(1), data, node.data);
|
||||
}
|
||||
// It looks like this was done a few lines above but see envEval
|
||||
if (part === null) {
|
||||
part = "null";
|
||||
}
|
||||
if (part === undefined) {
|
||||
part = "undefined";
|
||||
}
|
||||
// if (isDOMElement(part)) { ... }
|
||||
if (typeof part.cloneNode !== 'function') {
|
||||
part = node.ownerDocument.createTextNode(part.toString());
|
||||
}
|
||||
node.parentNode.insertBefore(part, node);
|
||||
this._handleAsync(part, node, function(reply, siblingNode) {
|
||||
reply = this._toNode(reply, siblingNode.ownerDocument);
|
||||
siblingNode.parentNode.insertBefore(reply, siblingNode);
|
||||
}.bind(this));
|
||||
}, this);
|
||||
node.parentNode.removeChild(node);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to convert a 'thing' to a DOM Node.
|
||||
* This is (obviously) a no-op for DOM Elements (which are detected using
|
||||
* 'typeof thing.cloneNode !== "function"' (is there a better way that will
|
||||
* work in all environments, including a .jsm?)
|
||||
* Non DOM elements are converted to a string and wrapped in a TextNode.
|
||||
*/
|
||||
Templater.prototype._toNode = function(thing, document) {
|
||||
if (thing == null) {
|
||||
thing = '' + thing;
|
||||
}
|
||||
// if (isDOMElement(reply)) { ... }
|
||||
if (typeof thing.cloneNode !== 'function') {
|
||||
thing = document.createTextNode(thing.toString());
|
||||
}
|
||||
return thing;
|
||||
};
|
||||
|
||||
/**
|
||||
* A function to handle the fact that some nodes can be promises, so we check
|
||||
* and resolve if needed using a marker node to keep our place before calling
|
||||
* an inserter function.
|
||||
* @param thing The object which could be real data or a promise of real data
|
||||
* we use it directly if it's not a promise, or resolve it if it is.
|
||||
* @param siblingNode The element before which we insert new elements.
|
||||
* @param inserter The function to to the insertion. If thing is not a promise
|
||||
* then _handleAsync() is just 'inserter(thing, siblingNode)'
|
||||
*/
|
||||
Templater.prototype._handleAsync = function(thing, siblingNode, inserter) {
|
||||
if (typeof thing.then === 'function') {
|
||||
// Placeholder element to be replaced once we have the real data
|
||||
var tempNode = siblingNode.ownerDocument.createElement('span');
|
||||
siblingNode.parentNode.insertBefore(tempNode, siblingNode);
|
||||
thing.then(function(delayed) {
|
||||
inserter(delayed, tempNode);
|
||||
tempNode.parentNode.removeChild(tempNode);
|
||||
}.bind(this));
|
||||
}
|
||||
else {
|
||||
inserter(thing, siblingNode);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Warn of string does not begin '${' and end '}'
|
||||
* @param str the string to check.
|
||||
* @return The string stripped of ${ and }, or untouched if it does not match
|
||||
*/
|
||||
Templater.prototype.stripBraces = function(str) {
|
||||
Templater.prototype._stripBraces = function(str) {
|
||||
if (!str.match(/\$\{.*\}/g)) {
|
||||
this.handleError('Expected ' + str + ' to match ${...}');
|
||||
this._handleError('Expected ' + str + ' to match ${...}');
|
||||
return str;
|
||||
}
|
||||
return str.slice(2, -1);
|
||||
@ -306,9 +380,9 @@ Templater.prototype.stripBraces = function(str) {
|
||||
* Combined getter and setter that works with a path through some data set.
|
||||
* For example:
|
||||
* <ul>
|
||||
* <li>property('a.b', { a: { b: 99 }}); // returns 99
|
||||
* <li>property('a', { a: { b: 99 }}); // returns { b: 99 }
|
||||
* <li>property('a', { a: { b: 99 }}, 42); // returns 99 and alters the
|
||||
* <li>_property('a.b', { a: { b: 99 }}); // returns 99
|
||||
* <li>_property('a', { a: { b: 99 }}); // returns { b: 99 }
|
||||
* <li>_property('a', { a: { b: 99 }}, 42); // returns 99 and alters the
|
||||
* input data to be { a: { b: 42 }}
|
||||
* </ul>
|
||||
* @param path An array of strings indicating the path through the data, or
|
||||
@ -319,8 +393,8 @@ Templater.prototype.stripBraces = function(str) {
|
||||
* @return The value pointed to by <tt>path</tt> before any
|
||||
* <tt>newValue</tt> is applied.
|
||||
*/
|
||||
Templater.prototype.property = function(path, data, newValue) {
|
||||
this.scope.push(path);
|
||||
Templater.prototype._property = function(path, data, newValue) {
|
||||
this.stack.push(path);
|
||||
try {
|
||||
if (typeof path === 'string') {
|
||||
path = path.split('.');
|
||||
@ -336,12 +410,12 @@ Templater.prototype.property = function(path, data, newValue) {
|
||||
return value;
|
||||
}
|
||||
if (!value) {
|
||||
this.handleError('Can\'t find path=' + path);
|
||||
this._handleError('Can\'t find path=' + path);
|
||||
return null;
|
||||
}
|
||||
return this.property(path.slice(1), value, newValue);
|
||||
return this._property(path.slice(1), value, newValue);
|
||||
} finally {
|
||||
this.scope.pop();
|
||||
this.stack.pop();
|
||||
}
|
||||
};
|
||||
|
||||
@ -353,21 +427,22 @@ Templater.prototype.property = function(path, data, newValue) {
|
||||
* according to the X keys in the env object, and then call that function using
|
||||
* the values in the env object. This is likely to be slow, but workable.
|
||||
* @param script The string to be evaluated.
|
||||
* @param env The environment in which to eval the script.
|
||||
* @param context Optional debugging string in case of failure
|
||||
* @param data The environment in which to eval the script.
|
||||
* @param frame Optional debugging string in case of failure.
|
||||
* @return The return value of the script, or the error message if the script
|
||||
* execution failed.
|
||||
*/
|
||||
Templater.prototype.envEval = function(script, env, context) {
|
||||
with (env) {
|
||||
Templater.prototype._envEval = function(script, data, frame) {
|
||||
with (data) {
|
||||
try {
|
||||
this.scope.push(context);
|
||||
this.stack.push(frame);
|
||||
return eval(script);
|
||||
} catch (ex) {
|
||||
this.handleError('Template error evaluating \'' + script + '\'', ex);
|
||||
this._handleError('Template error evaluating \'' + script + '\'' +
|
||||
' environment=' + Object.keys(data).join(', '), ex);
|
||||
return script;
|
||||
} finally {
|
||||
this.scope.pop();
|
||||
this.stack.pop();
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -378,11 +453,11 @@ Templater.prototype.envEval = function(script, env, context) {
|
||||
* @param message the error message to report.
|
||||
* @param ex optional associated exception.
|
||||
*/
|
||||
Templater.prototype.handleError = function(message, ex) {
|
||||
this.logError(message);
|
||||
this.logError('In: ' + this.scope.join(' > '));
|
||||
Templater.prototype._handleError = function(message, ex) {
|
||||
this._logError(message);
|
||||
this._logError('In: ' + this.stack.join(' > '));
|
||||
if (ex) {
|
||||
this.logError(ex);
|
||||
this._logError(ex);
|
||||
}
|
||||
};
|
||||
|
||||
@ -392,7 +467,7 @@ Templater.prototype.handleError = function(message, ex) {
|
||||
* environments.
|
||||
* @param message the error message to report.
|
||||
*/
|
||||
Templater.prototype.logError = function(message) {
|
||||
Templater.prototype._logError = function(message) {
|
||||
Services.console.logStringMessage(message);
|
||||
};
|
||||
|
||||
|
@ -565,6 +565,10 @@ CssLogic.prototype = {
|
||||
this._unmatchedSelectors = [];
|
||||
|
||||
this.forEachSheet(function (aSheet) {
|
||||
if (aSheet.systemSheet) {
|
||||
return;
|
||||
}
|
||||
|
||||
aSheet.forEachRule(function (aRule) {
|
||||
aRule.selectors.forEach(function (aSelector) {
|
||||
if (aSelector._matchId != this._matchId) {
|
||||
@ -1441,10 +1445,6 @@ CssPropertyInfo.prototype = {
|
||||
_processUnmatchedSelector: function CPI_processUnmatchedSelector(aSelector)
|
||||
{
|
||||
let cssRule = aSelector._cssRule;
|
||||
if (cssRule.systemRule) {
|
||||
return;
|
||||
}
|
||||
|
||||
let value = cssRule.getPropertyValue(this.property);
|
||||
if (value) {
|
||||
let selectorInfo = new CssSelectorInfo(aSelector, this.property, value,
|
||||
@ -1469,30 +1469,24 @@ CssPropertyInfo.prototype = {
|
||||
let passId = ++this._cssLogic._passId;
|
||||
let ruleCount = 0;
|
||||
|
||||
if (this._matchedSelectors) {
|
||||
this._matchedSelectors.forEach(function(aSelectorInfo) {
|
||||
let cssRule = aSelectorInfo.selector._cssRule;
|
||||
if (cssRule._passId != passId) {
|
||||
if (cssRule.sheetAllowed) {
|
||||
ruleCount++;
|
||||
}
|
||||
cssRule._passId = passId;
|
||||
let iterator = function(aSelectorInfo) {
|
||||
let cssRule = aSelectorInfo.selector._cssRule;
|
||||
if (cssRule._passId != passId) {
|
||||
if (cssRule.sheetAllowed) {
|
||||
ruleCount++;
|
||||
}
|
||||
});
|
||||
cssRule._passId = passId;
|
||||
}
|
||||
};
|
||||
|
||||
if (this._matchedSelectors) {
|
||||
this._matchedSelectors.forEach(iterator);
|
||||
this._matchedRuleCount = ruleCount;
|
||||
}
|
||||
|
||||
if (this._unmatchedSelectors) {
|
||||
ruleCount = 0;
|
||||
this._unmatchedSelectors.forEach(function(aSelectorInfo) {
|
||||
let cssRule = aSelectorInfo.selector._cssRule;
|
||||
if (!cssRule.systemRule && cssRule._passId != passId) {
|
||||
if (cssRule.sheetAllowed) {
|
||||
ruleCount++;
|
||||
}
|
||||
cssRule._passId = passId;
|
||||
}
|
||||
});
|
||||
this._unmatchedSelectors.forEach(iterator);
|
||||
this._unmatchedRuleCount = ruleCount;
|
||||
}
|
||||
|
||||
|
@ -432,7 +432,12 @@ can reach it easily. -->
|
||||
<!ENTITY mediaHideControls.accesskey "C">
|
||||
<!ENTITY videoFullScreen.label "Full Screen">
|
||||
<!ENTITY videoFullScreen.accesskey "F">
|
||||
|
||||
<!ENTITY videoSaveImage.label "Save Snapshot As…">
|
||||
<!ENTITY videoSaveImage.accesskey "S">
|
||||
<!ENTITY videoShowStats.label "Show Statistics">
|
||||
<!ENTITY videoShowStats.accesskey "t">
|
||||
<!ENTITY videoHideStats.label "Hide Statistics">
|
||||
<!ENTITY videoHideStats.accesskey "t">
|
||||
|
||||
<!-- LOCALIZATION NOTE :
|
||||
fullZoomEnlargeCmd.commandkey3, fullZoomReduceCmd.commandkey2 and
|
||||
|
@ -17,7 +17,7 @@
|
||||
<!ENTITY myRecoveryKey.label "My Recovery Key">
|
||||
<!ENTITY resetSync2.label "Reset Sync…">
|
||||
|
||||
<!ENTITY addDevice.label "Add a Device">
|
||||
<!ENTITY pairDevice.label "Pair a Device">
|
||||
|
||||
<!ENTITY syncMy.label "Sync My">
|
||||
<!ENTITY engine.bookmarks.label "Bookmarks">
|
||||
|
@ -4,8 +4,7 @@
|
||||
|
||||
<!ENTITY setup.pickSetupType.description "Welcome, if you've never used &syncBrand.fullName.label; before, you will need to create a new account.">
|
||||
<!ENTITY button.createNewAccount.label "Create a New Account">
|
||||
<!ENTITY setup.haveAccount.label "I already have a &syncBrand.fullName.label; account.">
|
||||
<!ENTITY button.connect.label "Connect">
|
||||
<!ENTITY button.haveAccount.label "I Have an Account">
|
||||
|
||||
<!ENTITY setup.choicePage.title.label "Have you used &syncBrand.fullName.label; before?">
|
||||
<!ENTITY setup.choicePage.new.label "I've never used &syncBrand.shortName.label; before">
|
||||
@ -40,7 +39,7 @@
|
||||
<!ENTITY setup.tosAgree3.label "">
|
||||
<!ENTITY setup.tosAgree2.accesskey "">
|
||||
|
||||
<!-- New Account Page 2: Sync Key -->
|
||||
<!-- My Recovery Key dialog -->
|
||||
<!ENTITY setup.newRecoveryKeyPage.title.label "&brandShortName; Cares About Your Privacy">
|
||||
<!ENTITY setup.newRecoveryKeyPage.description.label "To ensure your total privacy, all of your data is encrypted prior to being uploaded. The Recovery Key which is necessary to decrypt your data is not uploaded.">
|
||||
<!ENTITY recoveryKeyEntry.label "Your Recovery Key">
|
||||
@ -53,15 +52,13 @@
|
||||
<!ENTITY button.syncKeyBackup.save.label "Save…">
|
||||
<!ENTITY button.syncKeyBackup.save.accesskey "S">
|
||||
|
||||
<!-- New Account Page 3: Captcha -->
|
||||
<!ENTITY setup.captchaPage2.title.label "Please Confirm You're Not a Robot">
|
||||
<!-- Existing Account Page 1: Add Device (incl. Add a Device dialog strings) -->
|
||||
<!ENTITY addDevice.title.label "Add a Device">
|
||||
<!-- Existing Account Page 1: Pair a Device (incl. Pair a Device dialog strings) -->
|
||||
<!ENTITY pairDevice.title.label "Pair a Device">
|
||||
<!ENTITY addDevice.showMeHow.label "Show me how.">
|
||||
<!ENTITY addDevice.dontHaveDevice.label "I don't have the device with me">
|
||||
<!ENTITY addDevice.setup.description.label "To activate, go to &syncBrand.shortName.label; Options on your other device and select "Add a Device".">
|
||||
<!ENTITY pairDevice.setup.description.label "To activate, select "Pair a Device" on your other device.">
|
||||
<!ENTITY addDevice.setup.enterCode.label "Then, enter this code:">
|
||||
<!ENTITY addDevice.dialog.description.label "To activate your new device, go to &syncBrand.shortName.label; Options on the device and select "Connect."">
|
||||
<!ENTITY pairDevice.dialog.description.label "To activate your new device, select "Set Up Sync" on the device.">
|
||||
<!ENTITY addDevice.dialog.enterCode.label "Enter the code that the device provides:">
|
||||
<!ENTITY addDevice.dialog.tryAgain.label "Please try again.">
|
||||
<!ENTITY addDevice.dialog.successful.label "The device has been successfully added. The initial synchronization can take several minutes and will finish in the background.">
|
||||
|
@ -169,7 +169,7 @@ radio[pane=paneSync] {
|
||||
/* Sync Pane */
|
||||
|
||||
#syncDesc {
|
||||
padding: 0 12em;
|
||||
padding: 0 8em;
|
||||
}
|
||||
|
||||
#accountCaptionImage {
|
||||
|
@ -1,7 +1,7 @@
|
||||
wizard {
|
||||
-moz-appearance: none;
|
||||
width: 55em;
|
||||
height: 42em;
|
||||
height: 45em;
|
||||
padding: 0;
|
||||
background-color: Window;
|
||||
}
|
||||
@ -17,7 +17,7 @@ wizardpage {
|
||||
-moz-box-pack: center;
|
||||
-moz-box-align: center;
|
||||
margin: 0;
|
||||
padding: 0 8em;
|
||||
padding: 0 6em;
|
||||
background-color: Window;
|
||||
}
|
||||
|
||||
@ -109,11 +109,15 @@ description > .text-link:focus {
|
||||
width: 0.5em;
|
||||
}
|
||||
|
||||
#add-device-throbber > image,
|
||||
#pairDeviceThrobber > image,
|
||||
#login-throbber > image {
|
||||
list-style-image: url("chrome://global/skin/icons/loading_16.png");
|
||||
}
|
||||
|
||||
#captchaFeedback {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#successPageIcon {
|
||||
/* TODO replace this with a 128px version (bug 591122) */
|
||||
list-style-image: url("chrome://browser/skin/sync-32.png");
|
||||
|
@ -227,7 +227,7 @@ caption {
|
||||
/* ----- SYNC PANE ----- */
|
||||
|
||||
#syncDesc {
|
||||
padding: 0 12em;
|
||||
padding: 0 8em;
|
||||
}
|
||||
|
||||
#accountCaptionImage {
|
||||
|
@ -1,7 +1,7 @@
|
||||
wizard {
|
||||
-moz-appearance: none;
|
||||
width: 55em;
|
||||
height: 42em;
|
||||
height: 45em;
|
||||
padding: 0;
|
||||
background-color: Window;
|
||||
}
|
||||
@ -17,7 +17,7 @@ wizardpage {
|
||||
-moz-box-pack: center;
|
||||
-moz-box-align: center;
|
||||
margin: 0;
|
||||
padding: 0 8em;
|
||||
padding: 0 6em;
|
||||
background-color: Window;
|
||||
}
|
||||
|
||||
@ -108,11 +108,15 @@ description > .text-link:focus {
|
||||
width: 0.5em;
|
||||
}
|
||||
|
||||
#add-device-throbber > image,
|
||||
#pairDeviceThrobber > image,
|
||||
#login-throbber > image {
|
||||
list-style-image: url("chrome://global/skin/icons/loading_16.png");
|
||||
}
|
||||
|
||||
#captchaFeedback {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#successPageIcon {
|
||||
/* TODO replace this with a 128px version (bug 591122) */
|
||||
list-style-image: url("chrome://browser/skin/sync-32.png");
|
||||
|
@ -41,7 +41,7 @@
|
||||
|
||||
@media all and (-moz-windows-default-theme) {
|
||||
#navigator-toolbox > toolbar:not(:-moz-lwtheme),
|
||||
#addon-bar:not(:-moz-lwtheme) {
|
||||
#browser-bottombox:not(:-moz-lwtheme) {
|
||||
background-color: @customToolbarColor@;
|
||||
}
|
||||
|
||||
@ -168,6 +168,7 @@
|
||||
#main-window[sizemode=normal] #browser-bottombox {
|
||||
border: 1px solid @toolbarShadowColor@;
|
||||
border-top-style: none;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
#main-window[sizemode=normal][tabsontop=false] #PersonalToolbar:not(:-moz-lwtheme) {
|
||||
@ -235,23 +236,6 @@
|
||||
background-color: -moz-dialog;
|
||||
}
|
||||
|
||||
#browser-bottombox:not(:-moz-lwtheme) {
|
||||
background-color: -moz-dialog;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
#main-window[sizemode=normal] #browser-bottombox:not(:-moz-lwtheme),
|
||||
#main-window[sizemode=normal] #addon-bar:not(:-moz-lwtheme) {
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
#addon-bar:not(:-moz-lwtheme) {
|
||||
-moz-appearance: none;
|
||||
border-bottom-style: none;
|
||||
background-image: -moz-linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
|
||||
}
|
||||
|
||||
#main-menubar:not(:-moz-lwtheme):not(:-moz-window-inactive) {
|
||||
background-color: rgba(255,255,255,.5);
|
||||
border-radius: 4px;
|
||||
|
@ -141,6 +141,10 @@
|
||||
-moz-appearance: toolbox;
|
||||
}
|
||||
|
||||
#browser-bottombox:not(:-moz-lwtheme) {
|
||||
background-color: -moz-dialog;
|
||||
}
|
||||
|
||||
/* ::::: app menu button ::::: */
|
||||
|
||||
#appmenu-button {
|
||||
@ -2467,12 +2471,14 @@ panel[dimmed="true"] {
|
||||
/* Add-on bar */
|
||||
|
||||
#addon-bar {
|
||||
-moz-appearance: none;
|
||||
min-height: 20px;
|
||||
border-top: 1px solid ThreeDShadow !important;
|
||||
}
|
||||
|
||||
#addon-bar:not(:-moz-lwtheme) {
|
||||
-moz-appearance: statusbar;
|
||||
border-top-style: none;
|
||||
border-bottom-style: none;
|
||||
padding-top: 1px;
|
||||
background-image: -moz-linear-gradient(rgba(0,0,0,.15) 1px, rgba(255,255,255,.15) 1px);
|
||||
background-size: 100% 2px;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
#status-bar {
|
||||
|
@ -155,7 +155,7 @@ radio[pane=paneSync] {
|
||||
/* Sync Pane */
|
||||
|
||||
#syncDesc {
|
||||
padding: 0 12em;
|
||||
padding: 0 8em;
|
||||
}
|
||||
|
||||
.syncGroupBox {
|
||||
|
@ -1,7 +1,7 @@
|
||||
wizard {
|
||||
-moz-appearance: none;
|
||||
width: 55em;
|
||||
height: 42em;
|
||||
height: 45em;
|
||||
padding: 0;
|
||||
background-color: Window;
|
||||
}
|
||||
@ -17,7 +17,7 @@ wizardpage {
|
||||
-moz-box-pack: center;
|
||||
-moz-box-align: center;
|
||||
margin: 0;
|
||||
padding: 0 8em;
|
||||
padding: 0 6em;
|
||||
background-color: Window;
|
||||
}
|
||||
|
||||
@ -109,11 +109,15 @@ description > .text-link:focus {
|
||||
width: 0.5em;
|
||||
}
|
||||
|
||||
#add-device-throbber > image,
|
||||
#pairDeviceThrobber > image,
|
||||
#login-throbber > image {
|
||||
list-style-image: url("chrome://global/skin/icons/loading_16.png");
|
||||
}
|
||||
|
||||
#captchaFeedback {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#successPageIcon {
|
||||
/* TODO replace this with a 128px version (bug 591122) */
|
||||
list-style-image: url("chrome://browser/skin/sync-32.png");
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user