зеркало из https://github.com/mozilla/gecko-dev.git
182 строки
5.9 KiB
C++
182 строки
5.9 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "RadioGroupManager.h"
|
|
#include "nsIRadioVisitor.h"
|
|
#include "mozilla/dom/HTMLInputElement.h"
|
|
|
|
namespace mozilla::dom {
|
|
|
|
/**
|
|
* A struct that holds all the information about a radio group.
|
|
*/
|
|
struct nsRadioGroupStruct {
|
|
nsRadioGroupStruct()
|
|
: mRequiredRadioCount(0), mGroupSuffersFromValueMissing(false) {}
|
|
|
|
/**
|
|
* A strong pointer to the currently selected radio button.
|
|
*/
|
|
RefPtr<HTMLInputElement> mSelectedRadioButton;
|
|
nsTArray<RefPtr<HTMLInputElement>> mRadioButtons;
|
|
uint32_t mRequiredRadioCount;
|
|
bool mGroupSuffersFromValueMissing;
|
|
};
|
|
|
|
RadioGroupManager::RadioGroupManager() = default;
|
|
|
|
void RadioGroupManager::Traverse(RadioGroupManager* tmp,
|
|
nsCycleCollectionTraversalCallback& cb) {
|
|
for (const auto& entry : tmp->mRadioGroups) {
|
|
nsRadioGroupStruct* radioGroup = entry.GetWeak();
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
|
|
cb, "mRadioGroups entry->mSelectedRadioButton");
|
|
cb.NoteXPCOMChild(ToSupports(radioGroup->mSelectedRadioButton));
|
|
|
|
uint32_t i, count = radioGroup->mRadioButtons.Length();
|
|
for (i = 0; i < count; ++i) {
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
|
|
cb, "mRadioGroups entry->mRadioButtons[i]");
|
|
cb.NoteXPCOMChild(ToSupports(radioGroup->mRadioButtons[i]));
|
|
}
|
|
}
|
|
}
|
|
|
|
void RadioGroupManager::Unlink(RadioGroupManager* tmp) {
|
|
tmp->mRadioGroups.Clear();
|
|
}
|
|
|
|
nsresult RadioGroupManager::WalkRadioGroup(const nsAString& aName,
|
|
nsIRadioVisitor* aVisitor) {
|
|
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
|
|
|
|
for (size_t i = 0; i < radioGroup->mRadioButtons.Length(); i++) {
|
|
if (!aVisitor->Visit(radioGroup->mRadioButtons[i])) {
|
|
return NS_OK;
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void RadioGroupManager::SetCurrentRadioButton(const nsAString& aName,
|
|
HTMLInputElement* aRadio) {
|
|
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
|
|
radioGroup->mSelectedRadioButton = aRadio;
|
|
}
|
|
|
|
HTMLInputElement* RadioGroupManager::GetCurrentRadioButton(
|
|
const nsAString& aName) {
|
|
return GetOrCreateRadioGroup(aName)->mSelectedRadioButton;
|
|
}
|
|
|
|
nsresult RadioGroupManager::GetNextRadioButton(const nsAString& aName,
|
|
const bool aPrevious,
|
|
HTMLInputElement* aFocusedRadio,
|
|
HTMLInputElement** aRadioOut) {
|
|
*aRadioOut = nullptr;
|
|
|
|
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
|
|
|
|
// Return the radio button relative to the focused radio button.
|
|
// If no radio is focused, get the radio relative to the selected one.
|
|
RefPtr<HTMLInputElement> currentRadio;
|
|
if (aFocusedRadio) {
|
|
currentRadio = aFocusedRadio;
|
|
} else {
|
|
currentRadio = radioGroup->mSelectedRadioButton;
|
|
if (!currentRadio) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
}
|
|
int32_t index = radioGroup->mRadioButtons.IndexOf(currentRadio);
|
|
if (index < 0) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
int32_t numRadios = static_cast<int32_t>(radioGroup->mRadioButtons.Length());
|
|
RefPtr<HTMLInputElement> radio;
|
|
do {
|
|
if (aPrevious) {
|
|
if (--index < 0) {
|
|
index = numRadios - 1;
|
|
}
|
|
} else if (++index >= numRadios) {
|
|
index = 0;
|
|
}
|
|
radio = radioGroup->mRadioButtons[index];
|
|
} while (radio->Disabled() && radio != currentRadio);
|
|
|
|
radio.forget(aRadioOut);
|
|
return NS_OK;
|
|
}
|
|
|
|
void RadioGroupManager::AddToRadioGroup(const nsAString& aName,
|
|
HTMLInputElement* aRadio) {
|
|
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
|
|
radioGroup->mRadioButtons.AppendElement(aRadio);
|
|
|
|
if (aRadio->IsRequired()) {
|
|
radioGroup->mRequiredRadioCount++;
|
|
}
|
|
}
|
|
|
|
void RadioGroupManager::RemoveFromRadioGroup(const nsAString& aName,
|
|
HTMLInputElement* aRadio) {
|
|
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
|
|
radioGroup->mRadioButtons.RemoveElement(aRadio);
|
|
|
|
if (aRadio->IsRequired()) {
|
|
MOZ_ASSERT(radioGroup->mRequiredRadioCount != 0,
|
|
"mRequiredRadioCount about to wrap below 0!");
|
|
radioGroup->mRequiredRadioCount--;
|
|
}
|
|
}
|
|
|
|
uint32_t RadioGroupManager::GetRequiredRadioCount(
|
|
const nsAString& aName) const {
|
|
nsRadioGroupStruct* radioGroup = GetRadioGroup(aName);
|
|
return radioGroup ? radioGroup->mRequiredRadioCount : 0;
|
|
}
|
|
|
|
void RadioGroupManager::RadioRequiredWillChange(const nsAString& aName,
|
|
bool aRequiredAdded) {
|
|
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
|
|
|
|
if (aRequiredAdded) {
|
|
radioGroup->mRequiredRadioCount++;
|
|
} else {
|
|
MOZ_ASSERT(radioGroup->mRequiredRadioCount != 0,
|
|
"mRequiredRadioCount about to wrap below 0!");
|
|
radioGroup->mRequiredRadioCount--;
|
|
}
|
|
}
|
|
|
|
bool RadioGroupManager::GetValueMissingState(const nsAString& aName) const {
|
|
nsRadioGroupStruct* radioGroup = GetRadioGroup(aName);
|
|
return radioGroup && radioGroup->mGroupSuffersFromValueMissing;
|
|
}
|
|
|
|
void RadioGroupManager::SetValueMissingState(const nsAString& aName,
|
|
bool aValue) {
|
|
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
|
|
radioGroup->mGroupSuffersFromValueMissing = aValue;
|
|
}
|
|
|
|
nsRadioGroupStruct* RadioGroupManager::GetRadioGroup(
|
|
const nsAString& aName) const {
|
|
nsRadioGroupStruct* radioGroup = nullptr;
|
|
mRadioGroups.Get(aName, &radioGroup);
|
|
return radioGroup;
|
|
}
|
|
|
|
nsRadioGroupStruct* RadioGroupManager::GetOrCreateRadioGroup(
|
|
const nsAString& aName) {
|
|
return mRadioGroups.GetOrInsertNew(aName);
|
|
}
|
|
|
|
} // namespace mozilla::dom
|