2003-09-27 08:18:26 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
2017-08-17 00:10:56 +03:00
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
1999-03-06 02:51:41 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
This file provides the implementation for the sort service manager.
|
|
|
|
*/
|
|
|
|
|
2018-09-13 21:37:46 +03:00
|
|
|
#include "nsCOMArray.h"
|
1999-03-07 12:44:38 +03:00
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIServiceManager.h"
|
2006-07-13 19:08:55 +04:00
|
|
|
#include "nsGkAtoms.h"
|
2014-02-28 03:04:46 +04:00
|
|
|
#include "nsNameSpaceManager.h"
|
2001-02-22 06:01:34 +03:00
|
|
|
#include "nsXULContentUtils.h"
|
1999-03-07 12:44:38 +03:00
|
|
|
#include "nsString.h"
|
1999-04-14 07:28:49 +04:00
|
|
|
#include "nsQuickSort.h"
|
2008-12-19 16:43:24 +03:00
|
|
|
#include "nsWhitespaceTokenizer.h"
|
2006-07-13 19:08:55 +04:00
|
|
|
#include "nsXULSortService.h"
|
2017-02-02 18:32:57 +03:00
|
|
|
#include "nsXULElement.h"
|
2010-06-16 21:09:51 +04:00
|
|
|
#include "nsICollation.h"
|
2018-09-13 21:37:46 +03:00
|
|
|
#include "nsTArray.h"
|
2010-06-16 21:09:51 +04:00
|
|
|
#include "nsUnicharUtils.h"
|
1999-03-06 02:51:41 +03:00
|
|
|
|
2018-09-13 21:37:48 +03:00
|
|
|
#include "mozilla/dom/Element.h"
|
|
|
|
|
|
|
|
const unsigned long SORT_COMPARECASE = 0x0001;
|
|
|
|
const unsigned long SORT_INTEGER = 0x0100;
|
|
|
|
|
2018-09-13 21:37:46 +03:00
|
|
|
enum nsSortState_direction {
|
|
|
|
nsSortState_descending,
|
|
|
|
nsSortState_ascending,
|
|
|
|
nsSortState_natural
|
|
|
|
};
|
1999-05-13 12:25:12 +04:00
|
|
|
|
2018-09-13 21:37:46 +03:00
|
|
|
// the sort state holds info about the current sort
|
2018-09-13 21:37:50 +03:00
|
|
|
struct MOZ_STACK_CLASS nsSortState final
|
1999-03-06 02:51:41 +03:00
|
|
|
{
|
2018-09-13 21:37:46 +03:00
|
|
|
bool initialized;
|
|
|
|
MOZ_INIT_OUTSIDE_CTOR bool invertSort;
|
2006-07-13 19:08:55 +04:00
|
|
|
|
2018-09-13 21:37:46 +03:00
|
|
|
uint32_t sortHints;
|
2006-07-13 19:08:55 +04:00
|
|
|
|
2018-09-13 21:37:46 +03:00
|
|
|
MOZ_INIT_OUTSIDE_CTOR nsSortState_direction direction;
|
|
|
|
nsAutoString sort;
|
|
|
|
nsTArray<RefPtr<nsAtom>> sortKeys;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> lastContainer;
|
|
|
|
MOZ_INIT_OUTSIDE_CTOR bool lastWasFirst, lastWasLast;
|
|
|
|
|
|
|
|
nsSortState()
|
|
|
|
: initialized(false),
|
|
|
|
sortHints(0)
|
|
|
|
{
|
2002-03-29 05:46:01 +03:00
|
|
|
}
|
2018-09-13 21:37:46 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
// information about a particular item to be sorted
|
|
|
|
struct contentSortInfo {
|
|
|
|
nsCOMPtr<nsIContent> content;
|
|
|
|
nsCOMPtr<nsIContent> parent;
|
|
|
|
void swap(contentSortInfo& other)
|
|
|
|
{
|
|
|
|
content.swap(other.content);
|
|
|
|
parent.swap(other.parent);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set sortActive and sortDirection attributes on a tree column when a sort
|
|
|
|
* is done. The column to change is the one with a sort attribute that
|
|
|
|
* matches the sort key. The sort attributes are removed from the other
|
|
|
|
* columns.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
SetSortColumnHints(nsIContent *content,
|
|
|
|
const nsAString &sortResource,
|
|
|
|
const nsAString &sortDirection)
|
1999-03-06 02:51:41 +03:00
|
|
|
{
|
2006-07-13 19:08:55 +04:00
|
|
|
// set sort info on current column. This ensures that the
|
|
|
|
// column header sort indicator is updated properly.
|
2011-09-27 11:54:58 +04:00
|
|
|
for (nsIContent* child = content->GetFirstChild();
|
|
|
|
child;
|
|
|
|
child = child->GetNextSibling()) {
|
2015-03-03 14:09:00 +03:00
|
|
|
if (child->IsXULElement(nsGkAtoms::treecols)) {
|
|
|
|
SetSortColumnHints(child, sortResource, sortDirection);
|
|
|
|
} else if (child->IsXULElement(nsGkAtoms::treecol)) {
|
|
|
|
nsAutoString value;
|
2017-12-07 21:13:50 +03:00
|
|
|
child->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::sort, value);
|
2015-03-03 14:09:00 +03:00
|
|
|
if (value == sortResource) {
|
2017-12-05 20:05:51 +03:00
|
|
|
child->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::sortActive,
|
|
|
|
NS_LITERAL_STRING("true"), true);
|
|
|
|
|
|
|
|
child->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection,
|
|
|
|
sortDirection, true);
|
2015-03-03 14:09:00 +03:00
|
|
|
// Note: don't break out of loop; want to set/unset
|
|
|
|
// attribs on ALL sort columns
|
|
|
|
} else if (!value.IsEmpty()) {
|
2017-12-05 20:05:51 +03:00
|
|
|
child->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::sortActive,
|
|
|
|
true);
|
|
|
|
child->AsElement()->UnsetAttr(kNameSpaceID_None,
|
|
|
|
nsGkAtoms::sortDirection, true);
|
2002-03-29 05:46:01 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-07-07 09:32:07 +04:00
|
|
|
}
|
|
|
|
|
2018-09-13 21:37:46 +03:00
|
|
|
/**
|
|
|
|
* Set sort and sortDirection attributes when a sort is done.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
SetSortHints(Element* aElement, nsSortState* aSortState)
|
|
|
|
{
|
|
|
|
// set sort and sortDirection attributes when is sort is done
|
|
|
|
aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::sort,
|
|
|
|
aSortState->sort, true);
|
|
|
|
|
|
|
|
nsAutoString direction;
|
|
|
|
if (aSortState->direction == nsSortState_descending)
|
|
|
|
direction.AssignLiteral("descending");
|
|
|
|
else if (aSortState->direction == nsSortState_ascending)
|
|
|
|
direction.AssignLiteral("ascending");
|
|
|
|
aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection,
|
|
|
|
direction, true);
|
|
|
|
|
|
|
|
// for trees, also set the sort info on the currently sorted column
|
2018-09-13 21:37:50 +03:00
|
|
|
if (aElement->IsXULElement(nsGkAtoms::tree)) {
|
2018-09-13 21:37:46 +03:00
|
|
|
if (aSortState->sortKeys.Length() >= 1) {
|
|
|
|
nsAutoString sortkey;
|
|
|
|
aSortState->sortKeys[0]->ToString(sortkey);
|
|
|
|
SetSortColumnHints(aElement, sortkey, direction);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Determine the list of items which need to be sorted. This is determined
|
|
|
|
* in the following way:
|
|
|
|
* - for elements that have a content builder, get its list of generated
|
|
|
|
* results
|
|
|
|
* - otherwise, for trees, get the child treeitems
|
|
|
|
* - otherwise, get the direct children
|
|
|
|
*/
|
|
|
|
static nsresult
|
|
|
|
GetItemsToSort(nsIContent *aContainer,
|
|
|
|
nsSortState* aSortState,
|
|
|
|
nsTArray<contentSortInfo>& aSortItems)
|
2002-03-29 05:46:01 +03:00
|
|
|
{
|
2017-12-19 17:11:06 +03:00
|
|
|
// Get the children. For trees, get the treechildren element and
|
|
|
|
// use that as the parent
|
2017-12-05 20:05:51 +03:00
|
|
|
RefPtr<Element> treechildren;
|
2018-09-13 21:37:50 +03:00
|
|
|
if (aContainer->IsXULElement(nsGkAtoms::tree)) {
|
2006-07-13 19:08:55 +04:00
|
|
|
nsXULContentUtils::FindChildByTag(aContainer,
|
|
|
|
kNameSpaceID_XUL,
|
|
|
|
nsGkAtoms::treechildren,
|
|
|
|
getter_AddRefs(treechildren));
|
|
|
|
if (!treechildren)
|
2002-03-29 05:46:01 +03:00
|
|
|
return NS_OK;
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2006-07-13 19:08:55 +04:00
|
|
|
aContainer = treechildren;
|
2010-06-16 21:09:51 +04:00
|
|
|
}
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2011-09-27 11:54:58 +04:00
|
|
|
for (nsIContent* child = aContainer->GetFirstChild();
|
|
|
|
child;
|
|
|
|
child = child->GetNextSibling()) {
|
2007-02-08 19:11:46 +03:00
|
|
|
contentSortInfo* cinfo = aSortItems.AppendElement();
|
2006-07-13 19:08:55 +04:00
|
|
|
if (!cinfo)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
2000-02-15 08:05:29 +03:00
|
|
|
|
2007-02-08 19:11:46 +03:00
|
|
|
cinfo->content = child;
|
2010-06-16 21:09:51 +04:00
|
|
|
}
|
2000-02-15 08:05:29 +03:00
|
|
|
|
2010-06-16 21:09:51 +04:00
|
|
|
return NS_OK;
|
2000-02-15 08:05:29 +03:00
|
|
|
}
|
1999-05-18 10:19:04 +04:00
|
|
|
|
2018-09-13 21:37:46 +03:00
|
|
|
/**
|
|
|
|
* Compares aLeft and aRight and returns < 0, 0, or > 0. The sort
|
|
|
|
* hints are checked for case matching and integer sorting.
|
|
|
|
*/
|
|
|
|
static int32_t
|
|
|
|
CompareValues(const nsAString& aLeft,
|
|
|
|
const nsAString& aRight,
|
|
|
|
uint32_t aSortHints)
|
|
|
|
{
|
2018-09-13 21:37:48 +03:00
|
|
|
if (aSortHints & SORT_INTEGER) {
|
2018-09-13 21:37:46 +03:00
|
|
|
nsresult err;
|
|
|
|
int32_t leftint = PromiseFlatString(aLeft).ToInteger(&err);
|
|
|
|
if (NS_SUCCEEDED(err)) {
|
|
|
|
int32_t rightint = PromiseFlatString(aRight).ToInteger(&err);
|
|
|
|
if (NS_SUCCEEDED(err)) {
|
|
|
|
return leftint - rightint;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// if they aren't integers, just fall through and compare strings
|
|
|
|
}
|
2000-05-07 12:43:42 +04:00
|
|
|
|
2018-09-13 21:37:48 +03:00
|
|
|
if (aSortHints & SORT_COMPARECASE) {
|
2018-09-13 21:37:46 +03:00
|
|
|
return ::Compare(aLeft, aRight);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsICollation* collation = nsXULContentUtils::GetCollation();
|
|
|
|
if (collation) {
|
|
|
|
int32_t result;
|
|
|
|
collation->CompareString(nsICollation::kCollationCaseInSensitive,
|
|
|
|
aLeft, aRight, &result);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ::Compare(aLeft, aRight, nsCaseInsensitiveStringComparator());
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2006-07-13 19:08:55 +04:00
|
|
|
testSortCallback(const void *data1, const void *data2, void *privateData)
|
1999-03-06 02:51:41 +03:00
|
|
|
{
|
2006-07-13 19:08:55 +04:00
|
|
|
/// Note: testSortCallback is a small C callback stub for NS_QuickSort
|
2007-02-08 19:11:46 +03:00
|
|
|
contentSortInfo *left = (contentSortInfo *)data1;
|
|
|
|
contentSortInfo *right = (contentSortInfo *)data2;
|
2006-07-13 19:08:55 +04:00
|
|
|
nsSortState* sortState = (nsSortState *)privateData;
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t sortOrder = 0;
|
2002-03-29 05:46:01 +03:00
|
|
|
|
2017-12-19 17:11:06 +03:00
|
|
|
int32_t length = sortState->sortKeys.Length();
|
|
|
|
for (int32_t t = 0; t < length; t++) {
|
|
|
|
// compare attributes. Ignore namespaces for now.
|
|
|
|
nsAutoString leftstr, rightstr;
|
|
|
|
if (left->content->IsElement()) {
|
|
|
|
left->content->AsElement()->GetAttr(kNameSpaceID_None,
|
|
|
|
sortState->sortKeys[t],
|
|
|
|
leftstr);
|
|
|
|
}
|
|
|
|
if (right->content->IsElement()) {
|
|
|
|
right->content->AsElement()->GetAttr(kNameSpaceID_None,
|
|
|
|
sortState->sortKeys[t], rightstr);
|
2002-03-29 05:46:01 +03:00
|
|
|
}
|
2017-12-19 17:11:06 +03:00
|
|
|
|
2018-09-13 21:37:46 +03:00
|
|
|
sortOrder = CompareValues(leftstr, rightstr, sortState->sortHints);
|
2002-03-29 05:46:01 +03:00
|
|
|
}
|
|
|
|
|
2006-07-13 19:08:55 +04:00
|
|
|
if (sortState->direction == nsSortState_descending)
|
2002-03-29 05:46:01 +03:00
|
|
|
sortOrder = -sortOrder;
|
2000-05-07 12:43:42 +04:00
|
|
|
|
2002-03-29 05:46:01 +03:00
|
|
|
return sortOrder;
|
|
|
|
}
|
2000-05-07 12:43:42 +04:00
|
|
|
|
2018-09-13 21:37:46 +03:00
|
|
|
/**
|
|
|
|
* Given a list of sortable items, reverse the list. This is done
|
|
|
|
* when simply changing the sort direction for the same key.
|
|
|
|
*/
|
|
|
|
static nsresult
|
|
|
|
InvertSortInfo(nsTArray<contentSortInfo>& aData,
|
|
|
|
int32_t aStart, int32_t aNumItems)
|
|
|
|
{
|
|
|
|
if (aNumItems > 1) {
|
|
|
|
// reverse the items in the array starting from aStart
|
|
|
|
int32_t upPoint = (aNumItems + 1) / 2 + aStart;
|
|
|
|
int32_t downPoint = (aNumItems - 2) / 2 + aStart;
|
|
|
|
int32_t half = aNumItems / 2;
|
|
|
|
while (half-- > 0) {
|
|
|
|
aData[downPoint--].swap(aData[upPoint++]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sort a container using the supplied sort state details.
|
|
|
|
*/
|
|
|
|
static nsresult
|
|
|
|
SortContainer(nsIContent *aContainer, nsSortState* aSortState)
|
2002-03-29 05:46:01 +03:00
|
|
|
{
|
2007-02-08 19:11:46 +03:00
|
|
|
nsTArray<contentSortInfo> items;
|
2006-07-13 19:08:55 +04:00
|
|
|
nsresult rv = GetItemsToSort(aContainer, aSortState, items);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2002-03-29 05:46:01 +03:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t numResults = items.Length();
|
2006-07-13 19:08:55 +04:00
|
|
|
if (!numResults)
|
2003-09-27 08:18:26 +04:00
|
|
|
return NS_OK;
|
2002-03-29 05:46:01 +03:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t i;
|
2006-07-13 19:08:55 +04:00
|
|
|
|
2017-12-20 18:08:27 +03:00
|
|
|
// if the items are just being inverted, that is, just switching between
|
|
|
|
// ascending and descending, just reverse the list.
|
|
|
|
if (aSortState->invertSort)
|
|
|
|
InvertSortInfo(items, 0, numResults);
|
|
|
|
else
|
|
|
|
NS_QuickSort((void *)items.Elements(), numResults,
|
|
|
|
sizeof(contentSortInfo), testSortCallback, (void*)aSortState);
|
2006-07-13 19:08:55 +04:00
|
|
|
|
|
|
|
// first remove the items from the old positions
|
|
|
|
for (i = 0; i < numResults; i++) {
|
2007-02-08 19:11:46 +03:00
|
|
|
nsIContent* child = items[i].content;
|
2006-07-13 19:08:55 +04:00
|
|
|
nsIContent* parent = child->GetParent();
|
|
|
|
|
|
|
|
if (parent) {
|
|
|
|
// remember the parent so that it can be reinserted back
|
|
|
|
// into the same parent. This is necessary as multiple rules
|
|
|
|
// may generate results which get placed in different locations.
|
2007-02-08 19:11:46 +03:00
|
|
|
items[i].parent = parent;
|
2018-01-16 16:17:10 +03:00
|
|
|
parent->RemoveChildNode(child, true);
|
2002-03-29 05:46:01 +03:00
|
|
|
}
|
2010-06-16 21:09:51 +04:00
|
|
|
}
|
2000-05-06 04:01:01 +04:00
|
|
|
|
2006-07-13 19:08:55 +04:00
|
|
|
// now add the items back in sorted order
|
|
|
|
for (i = 0; i < numResults; i++)
|
|
|
|
{
|
2007-02-08 19:11:46 +03:00
|
|
|
nsIContent* child = items[i].content;
|
|
|
|
nsIContent* parent = items[i].parent;
|
2006-07-13 19:08:55 +04:00
|
|
|
if (parent) {
|
2011-10-17 18:59:28 +04:00
|
|
|
parent->AppendChildTo(child, true);
|
2006-07-13 19:08:55 +04:00
|
|
|
|
|
|
|
// if it's a container in a tree or menu, find its children,
|
|
|
|
// and sort those also
|
2017-12-07 21:13:50 +03:00
|
|
|
if (!child->IsElement() ||
|
|
|
|
!child->AsElement()->AttrValueIs(kNameSpaceID_None,
|
|
|
|
nsGkAtoms::container,
|
|
|
|
nsGkAtoms::_true, eCaseMatters))
|
2002-03-29 05:46:01 +03:00
|
|
|
continue;
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2011-09-27 11:54:58 +04:00
|
|
|
for (nsIContent* grandchild = child->GetFirstChild();
|
|
|
|
grandchild;
|
|
|
|
grandchild = grandchild->GetNextSibling()) {
|
2014-06-20 06:01:40 +04:00
|
|
|
mozilla::dom::NodeInfo *ni = grandchild->NodeInfo();
|
2017-10-03 01:05:19 +03:00
|
|
|
nsAtom *localName = ni->NameAtom();
|
2005-09-24 22:43:15 +04:00
|
|
|
if (ni->NamespaceID() == kNameSpaceID_XUL &&
|
2006-07-13 19:08:55 +04:00
|
|
|
(localName == nsGkAtoms::treechildren ||
|
|
|
|
localName == nsGkAtoms::menupopup)) {
|
|
|
|
SortContainer(grandchild, aSortState);
|
2003-11-19 04:20:56 +03:00
|
|
|
}
|
2002-03-29 05:46:01 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2002-03-29 05:46:01 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-05-06 04:01:01 +04:00
|
|
|
|
2018-09-13 21:37:46 +03:00
|
|
|
/**
|
|
|
|
* Initialize sort information from attributes specified on the container,
|
|
|
|
* the sort key and sort direction.
|
|
|
|
*
|
|
|
|
* @param aRootElement the element that contains sort attributes
|
|
|
|
* @param aContainer the container to sort, usually equal to aRootElement
|
|
|
|
* @param aSortKey space separated list of sort keys
|
|
|
|
* @param aSortDirection direction to sort in
|
|
|
|
* @param aSortState structure filled in with sort data
|
|
|
|
*/
|
|
|
|
static nsresult
|
|
|
|
InitializeSortState(Element* aRootElement,
|
|
|
|
Element* aContainer,
|
|
|
|
const nsAString& aSortKey,
|
|
|
|
const nsAString& aSortHints,
|
|
|
|
nsSortState* aSortState)
|
2002-03-29 05:46:01 +03:00
|
|
|
{
|
2006-07-13 19:08:55 +04:00
|
|
|
// used as an optimization for the content builder
|
|
|
|
if (aContainer != aSortState->lastContainer.get()) {
|
|
|
|
aSortState->lastContainer = aContainer;
|
2011-10-17 18:59:28 +04:00
|
|
|
aSortState->lastWasFirst = false;
|
|
|
|
aSortState->lastWasLast = false;
|
2006-07-13 19:08:55 +04:00
|
|
|
}
|
|
|
|
|
2017-12-20 18:08:27 +03:00
|
|
|
// The sort attribute is of the form: sort="key1 key2 ..."
|
2006-07-13 19:08:55 +04:00
|
|
|
nsAutoString sort(aSortKey);
|
|
|
|
aSortState->sortKeys.Clear();
|
2017-12-20 18:08:27 +03:00
|
|
|
nsWhitespaceTokenizer tokenizer(sort);
|
|
|
|
while (tokenizer.hasMoreTokens()) {
|
|
|
|
RefPtr<nsAtom> keyatom = NS_Atomize(tokenizer.nextToken());
|
|
|
|
NS_ENSURE_TRUE(keyatom, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
aSortState->sortKeys.AppendElement(keyatom);
|
2002-03-29 05:46:01 +03:00
|
|
|
}
|
1999-08-27 10:54:08 +04:00
|
|
|
|
2006-07-13 19:08:55 +04:00
|
|
|
aSortState->sort.Assign(sort);
|
2010-06-16 21:09:51 +04:00
|
|
|
aSortState->direction = nsSortState_natural;
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool noNaturalState = false;
|
2017-12-20 18:08:27 +03:00
|
|
|
nsWhitespaceTokenizer hintsTokenizer(aSortHints);
|
|
|
|
while (hintsTokenizer.hasMoreTokens()) {
|
|
|
|
const nsDependentSubstring& token(hintsTokenizer.nextToken());
|
2010-06-16 21:09:51 +04:00
|
|
|
if (token.EqualsLiteral("comparecase"))
|
2018-09-13 21:37:48 +03:00
|
|
|
aSortState->sortHints |= SORT_COMPARECASE;
|
2010-06-16 21:09:51 +04:00
|
|
|
else if (token.EqualsLiteral("integer"))
|
2018-09-13 21:37:48 +03:00
|
|
|
aSortState->sortHints |= SORT_INTEGER;
|
2010-06-16 21:09:51 +04:00
|
|
|
else if (token.EqualsLiteral("descending"))
|
|
|
|
aSortState->direction = nsSortState_descending;
|
|
|
|
else if (token.EqualsLiteral("ascending"))
|
|
|
|
aSortState->direction = nsSortState_ascending;
|
|
|
|
else if (token.EqualsLiteral("twostate"))
|
2011-10-17 18:59:28 +04:00
|
|
|
noNaturalState = true;
|
2010-06-16 21:09:51 +04:00
|
|
|
}
|
1999-08-27 10:54:08 +04:00
|
|
|
|
2010-06-16 21:09:51 +04:00
|
|
|
// if the twostate flag was set, the natural order is skipped and only
|
|
|
|
// ascending and descending are allowed
|
|
|
|
if (aSortState->direction == nsSortState_natural && noNaturalState) {
|
2006-07-13 19:08:55 +04:00
|
|
|
aSortState->direction = nsSortState_ascending;
|
2010-06-16 21:09:51 +04:00
|
|
|
}
|
2000-08-08 09:50:10 +04:00
|
|
|
|
2010-06-16 21:09:51 +04:00
|
|
|
// set up sort order info
|
2011-10-17 18:59:28 +04:00
|
|
|
aSortState->invertSort = false;
|
2010-06-16 21:09:51 +04:00
|
|
|
|
2006-07-13 19:08:55 +04:00
|
|
|
nsAutoString existingsort;
|
|
|
|
aRootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::sort, existingsort);
|
|
|
|
nsAutoString existingsortDirection;
|
|
|
|
aRootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection, existingsortDirection);
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2006-07-13 19:08:55 +04:00
|
|
|
// if just switching direction, set the invertSort flag
|
|
|
|
if (sort.Equals(existingsort)) {
|
|
|
|
if (aSortState->direction == nsSortState_descending) {
|
|
|
|
if (existingsortDirection.EqualsLiteral("ascending"))
|
2011-10-17 18:59:28 +04:00
|
|
|
aSortState->invertSort = true;
|
2010-06-16 21:09:51 +04:00
|
|
|
}
|
2006-07-13 19:08:55 +04:00
|
|
|
else if (aSortState->direction == nsSortState_ascending &&
|
2010-06-16 21:09:51 +04:00
|
|
|
existingsortDirection.EqualsLiteral("descending")) {
|
2011-10-17 18:59:28 +04:00
|
|
|
aSortState->invertSort = true;
|
2002-03-29 05:46:01 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
aSortState->initialized = true;
|
2002-03-29 05:46:01 +03:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2018-09-13 21:37:48 +03:00
|
|
|
nsresult
|
|
|
|
mozilla::XULWidgetSort(Element* aNode,
|
|
|
|
const nsAString& aSortKey,
|
|
|
|
const nsAString& aSortHints)
|
2002-03-29 05:46:01 +03:00
|
|
|
{
|
2006-07-13 19:08:55 +04:00
|
|
|
nsSortState sortState;
|
2018-05-30 05:58:48 +03:00
|
|
|
nsresult rv = InitializeSortState(aNode, aNode,
|
2010-06-16 21:09:51 +04:00
|
|
|
aSortKey, aSortHints, &sortState);
|
2005-04-19 02:58:35 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2006-07-13 19:08:55 +04:00
|
|
|
// store sort info in attributes on content
|
2018-05-30 05:58:48 +03:00
|
|
|
SetSortHints(aNode, &sortState);
|
|
|
|
rv = SortContainer(aNode, &sortState);
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2005-04-19 02:58:35 +04:00
|
|
|
return rv;
|
2002-03-29 05:46:01 +03:00
|
|
|
}
|