Apply MIP properties to repeat content too, and fix a problem with output. Bug 292089, r=smaug+doronr, a=mkaply, NPOTB

This commit is contained in:
allan%beaufour.dk 2005-05-05 07:09:40 +00:00
parent f7597a2864
commit 6a34dd9123
8 changed files with 177 additions and 146 deletions

View File

@ -113,4 +113,10 @@ interface nsIModelElementPrivate : nsIXFormsModelElement
*/
unsigned short handleInstanceDataNode(in nsIDOMNode aInstanceDataNode);
/**
* Set MIP states for given control bound to the given bound node.
* @param aControl The control
* @param aBoundNode The node the control is bound to
*/
void setStates(in nsIXFormsControl aControl, in nsIDOMNode aBoundNode);
};

View File

@ -123,7 +123,9 @@ nsXFormsControlStub::RemoveIndexListeners()
}
NS_IMETHODIMP
nsXFormsControlStub::ResetBoundNode()
nsXFormsControlStub::ResetBoundNode(const nsString &aBindAttribute,
PRUint16 aResultType,
nsIDOMXPathResult **aResult)
{
// Clear existing bound node, etc.
mBoundNode = nsnull;
@ -133,35 +135,40 @@ nsXFormsControlStub::ResetBoundNode()
if (!mHasParent || !mBindAttrsCount)
return NS_OK;
nsCOMPtr<nsIModelElementPrivate> modelNode;
nsCOMPtr<nsIDOMXPathResult> result;
nsresult rv =
ProcessNodeBinding(NS_LITERAL_STRING("ref"),
nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE,
getter_AddRefs(result),
getter_AddRefs(modelNode));
ProcessNodeBinding(aBindAttribute,
aResultType,
getter_AddRefs(result));
if (NS_SUCCEEDED(rv)) {
if (result) {
// Get context node, if any
result->GetSingleNodeValue(getter_AddRefs(mBoundNode));
}
rv = NS_OK;
} else {
if (NS_FAILED(rv)) {
nsXFormsUtils::ReportError(NS_LITERAL_STRING("controlBindError"), mElement);
return rv;
}
if (!result)
return NS_OK;
// Get context node, if any
result->GetSingleNodeValue(getter_AddRefs(mBoundNode));
if (mBoundNode && mModel) {
mModel->SetStates(this, mBoundNode);
}
return rv;
if (aResult) {
*aResult = nsnull;
result.swap(*aResult);
}
return NS_OK;
}
/**
* @note Refresh() is always called after a Bind(), so if a control decides to
* do all the work in Refresh() this function implements a NOP Bind().
*/
NS_IMETHODIMP
nsXFormsControlStub::Bind()
{
return ResetBoundNode();
return ResetBoundNode(NS_LITERAL_STRING("ref"),
nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE);
}
NS_IMETHODIMP
@ -271,21 +278,12 @@ nsXFormsControlStub::GetRelevantState()
return res;
}
void
nsXFormsControlStub::ToggleProperty(const nsAString &aOn,
const nsAString &aOff)
{
if (mElement) {
mElement->SetAttribute(aOn, NS_LITERAL_STRING("1"));
mElement->RemoveAttribute(aOff);
}
}
NS_IMETHODIMP
nsXFormsControlStub::HandleDefault(nsIDOMEvent *aEvent,
PRBool *aHandled)
{
NS_ENSURE_ARG(aHandled);
*aHandled = PR_FALSE;
if (nsXFormsUtils::EventHandlingAllowed(aEvent, mElement)) {
@ -294,7 +292,6 @@ nsXFormsControlStub::HandleDefault(nsIDOMEvent *aEvent,
aEvent->GetTarget(getter_AddRefs(target));
nsCOMPtr<nsIDOMElement> targetE(do_QueryInterface(target));
if (targetE && targetE != mElement) {
*aHandled = PR_FALSE;
return NS_OK;
}
@ -302,39 +299,8 @@ nsXFormsControlStub::HandleDefault(nsIDOMEvent *aEvent,
nsAutoString type;
aEvent->GetType(type);
*aHandled = PR_TRUE;
/// @todo Change to be less cut-n-paste-stylish. Everything can be extraced
/// from the sXFormsEventsEntries, only problem is the dash in
/// read-only/read-write... (XXX)
if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Valid].name)) {
ToggleProperty(NS_LITERAL_STRING("valid"),
NS_LITERAL_STRING("invalid"));
} else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Invalid].name)) {
ToggleProperty(NS_LITERAL_STRING("invalid"),
NS_LITERAL_STRING("valid"));
} else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Enabled].name)) {
ToggleProperty(NS_LITERAL_STRING("enabled"),
NS_LITERAL_STRING("disabled"));
} else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Disabled].name)) {
ToggleProperty(NS_LITERAL_STRING("disabled"),
NS_LITERAL_STRING("enabled"));
} else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Required].name)) {
ToggleProperty(NS_LITERAL_STRING("required"),
NS_LITERAL_STRING("optional"));
} else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Optional].name)) {
ToggleProperty(NS_LITERAL_STRING("optional"),
NS_LITERAL_STRING("required"));
} else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Readonly].name)) {
ToggleProperty(NS_LITERAL_STRING("read-only"),
NS_LITERAL_STRING("read-write"));
} else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Readwrite].name)) {
ToggleProperty(NS_LITERAL_STRING("read-write"),
NS_LITERAL_STRING("read-only"));
} else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Focus].name)) {
PRBool tmp;
TryFocus(&tmp);
} else {
*aHandled = PR_FALSE;
if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Focus].name)) {
TryFocus(aHandled);
}
}
@ -465,16 +431,12 @@ nsXFormsControlStub::ResetProperties()
if (!mElement) {
return;
}
mElement->RemoveAttribute(NS_LITERAL_STRING("valid"));
mElement->RemoveAttribute(NS_LITERAL_STRING("invalid"));
mElement->RemoveAttribute(NS_LITERAL_STRING("enabled"));
mElement->RemoveAttribute(NS_LITERAL_STRING("disabled"));
mElement->RemoveAttribute(NS_LITERAL_STRING("required"));
mElement->RemoveAttribute(NS_LITERAL_STRING("optional"));
mElement->RemoveAttribute(NS_LITERAL_STRING("read-only"));
mElement->RemoveAttribute(NS_LITERAL_STRING("read-write"));
///
/// @todo removes the attributes we use, until bug 271720 is landed (XXX)
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(kStateAttributes); ++i) {
mElement->RemoveAttribute(kStateAttributes[i]);
}
}
void

View File

@ -88,7 +88,9 @@ public:
NS_IMETHOD GetBoundNode(nsIDOMNode **aBoundNode);
NS_IMETHOD GetDependencies(nsCOMArray<nsIDOMNode> **aDependencies);
NS_IMETHOD GetElement(nsIDOMElement **aElement);
NS_IMETHOD ResetBoundNode();
NS_IMETHOD ResetBoundNode(const nsString &aBindAttribute,
PRUint16 aResultType,
nsIDOMXPathResult **aResult = nsnull);
NS_IMETHOD Bind();
NS_IMETHOD TryFocus(PRBool* aOK);
@ -188,15 +190,6 @@ protected:
nsIDOMXPathResult **aResult,
nsIModelElementPrivate **aModel = nsnull);
/**
* Toggles a property on the control (readonly, relevant, etc.)
*
* @todo This needs to be implemented using pseudo-classes instead of
* attributes (XXX)
*/
void ToggleProperty(const nsAString &aOn,
const nsAString &aOff);
/**
* Reset (and reinitialize) the event listener, which is used to create
* xforms-hint and xforms-help events.

View File

@ -396,7 +396,8 @@ nsXFormsModelElement::HandleDefault(nsIDOMEvent *aEvent, PRBool *aHandled)
nsresult
nsXFormsModelElement::ConstructDone()
{
InitializeControls();
nsresult rv = InitializeControls();
NS_ENSURE_SUCCESS(rv, rv);
/// @bug This is not entirely correct. xforms-ready should be sent when
/// _all_ models have initialized their controls.
@ -512,40 +513,61 @@ nsXFormsModelElement::Recalculate()
}
void
nsXFormsModelElement::DispatchEvents(nsIXFormsControl *aControl,
nsIDOMNode *aNode,
PRBool aInitialize)
nsXFormsModelElement::SetSingleState(nsIDOMElement *aElement,
PRBool aState,
nsXFormsEvent aOnEvent,
PRUint32 aAttributePos)
{
if (!aControl || !aNode)
return;
nsXFormsEvent event = aState ? aOnEvent : (nsXFormsEvent) (aOnEvent + 1);
// Dispatch event
nsXFormsUtils::DispatchEvent(aElement, event);
// Set pseudo class
///
/// @bug Set via attributes right now. Bug 271720. (XXX)
aElement->SetAttribute(kStateAttributes[aState ? aAttributePos : aAttributePos + 1],
NS_LITERAL_STRING("1"));
aElement->RemoveAttribute(kStateAttributes[aState ? aAttributePos + 1 : aAttributePos]);
}
nsresult
nsXFormsModelElement::SetStatesInternal(nsIXFormsControl *aControl,
nsIDOMNode *aNode,
PRBool aAllStates)
{
NS_ENSURE_ARG(aControl);
if (!aNode)
return NS_OK;
nsCOMPtr<nsIDOMElement> element;
aControl->GetElement(getter_AddRefs(element));
NS_ENSURE_STATE(element);
const nsXFormsNodeState *ns = mMDG.GetNodeState(aNode);
NS_ENSURE_STATE(ns);
if (!element || !ns)
return;
/// @todo the last argument (0, 2, 4, and 6) to SetSingleState is the
/// position of the attribute in kStateAttributes. It's hacky and only
/// temporary, until bug 271720 lands. (XXX)
if (aAllStates || ns->ShouldDispatchValid()) {
SetSingleState(element, ns->IsValid(), eEvent_Valid, 0);
}
if (aAllStates || ns->ShouldDispatchReadonly()) {
SetSingleState(element, ns->IsReadonly(), eEvent_Readonly, 2);
}
if (aAllStates || ns->ShouldDispatchRequired()) {
SetSingleState(element, ns->IsRequired(), eEvent_Required, 4);
}
if (aAllStates || ns->ShouldDispatchRelevant()) {
SetSingleState(element, ns->IsRelevant(), eEvent_Enabled, 6);
}
if (aInitialize || ns->ShouldDispatchValid()) {
nsXFormsUtils::DispatchEvent(element,
ns->IsValid() ? eEvent_Valid : eEvent_Invalid);
}
if (aInitialize || ns->ShouldDispatchReadonly()) {
nsXFormsUtils::DispatchEvent(element,
ns->IsReadonly() ? eEvent_Readonly : eEvent_Readwrite);
}
if (aInitialize || ns->ShouldDispatchRequired()) {
nsXFormsUtils::DispatchEvent(element,
ns->IsRequired() ? eEvent_Required : eEvent_Optional);
}
if (aInitialize || ns->ShouldDispatchRelevant()) {
nsXFormsUtils::DispatchEvent(element,
ns->IsRelevant() ? eEvent_Enabled : eEvent_Disabled);
}
if (aInitialize || ns->ShouldDispatchValueChanged()) {
if (ns->ShouldDispatchValueChanged()) {
nsXFormsUtils::DispatchEvent(element, eEvent_ValueChanged);
}
return NS_OK;
}
NS_IMETHODIMP
@ -665,7 +687,8 @@ nsXFormsModelElement::Revalidate()
control->GetBoundNode(getter_AddRefs(boundNode));
}
if (rebind || refresh) {
DispatchEvents(control, boundNode);
nsresult rv = SetStatesInternal(control, boundNode);
NS_ENSURE_SUCCESS(rv, rv);
if (mControlsNeedingRefresh.IndexOf(control) == -1)
mControlsNeedingRefresh.AppendElement(control);
}
@ -1187,10 +1210,11 @@ nsXFormsModelElement::FinishConstruction()
return NS_OK;
}
void
nsresult
nsXFormsModelElement::InitializeControls()
{
PRInt32 controlCount = mFormControls.Count();
nsresult rv;
for (PRInt32 i = 0; i < controlCount; ++i) {
// Get control
nsIXFormsControl *control = NS_STATIC_CAST(nsIXFormsControl*,
@ -1199,17 +1223,24 @@ nsXFormsModelElement::InitializeControls()
continue;
// Rebind
control->Bind();
rv = control->Bind();
NS_ENSURE_SUCCESS(rv, rv);
// Get bound node
nsCOMPtr<nsIDOMNode> boundNode;
control->GetBoundNode(getter_AddRefs(boundNode));
// Dispatch events
DispatchEvents(control, boundNode, PR_TRUE);
rv = control->GetBoundNode(getter_AddRefs(boundNode));
NS_ENSURE_SUCCESS(rv, rv);
// Set MIP states on control
rv = SetStatesInternal(control, boundNode, PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
// Refresh controls
control->Refresh();
}
rv = control->Refresh();
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
@ -1448,6 +1479,12 @@ nsXFormsModelElement::ProcessBind(nsIXFormsXPathEvaluator *aEvaluator,
return NS_OK;
}
NS_IMETHODIMP
nsXFormsModelElement::SetStates(nsIXFormsControl *aControl, nsIDOMNode *aBoundNode)
{
return SetStatesInternal(aControl, aBoundNode, PR_TRUE);
}
/* static */ void
nsXFormsModelElement::Startup()
{

View File

@ -48,6 +48,7 @@
#include "nsCOMPtr.h"
#include "nsIDOMDocument.h"
#include "nsXFormsMDGEngine.h"
#include "nsXFormsUtils.h"
#include "nsISchemaLoader.h"
#include "nsISchema.h"
@ -102,32 +103,49 @@ private:
NS_HIDDEN_(void) BackupOrRestoreInstanceData(PRBool restore);
/** Initializes the MIPs on all form controls */
NS_HIDDEN_(void) InitializeControls();
NS_HIDDEN_(nsresult) InitializeControls();
NS_HIDDEN_(nsresult) ProcessBindElements();
NS_HIDDEN_(nsresult) FinishConstruction();
NS_HIDDEN_(nsresult) ConstructDone();
NS_HIDDEN_(void) MaybeNotifyCompletion();
NS_HIDDEN_(nsresult) ProcessBind(nsIXFormsXPathEvaluator *aEvaluator,
NS_HIDDEN_(nsresult) ProcessBind(nsIXFormsXPathEvaluator *aEvaluator,
nsIDOMNode *aContextNode,
PRInt32 aContextPosition,
PRInt32 aContextSize,
PRInt32 aContextPosition,
PRInt32 aContextSize,
nsIDOMElement *aBindElement);
NS_HIDDEN_(void) RemoveModelFromDocument();
/**
* Dispatch the necessary events to a control, aControl, when the instance
* node, aNode, it is bound to changes state.
* Set the states on the control |aControl| bound to the instance data node
* |aNode|. It dispatches the necessary events and sets the pseudo class
* states. |aAllStates| determines whether all states should be set, or only
* changed.
*
* @param aControl The event target
* @param aNode The instance node
* @param aInitialize Send events for all flags
* @param aAllStates Set all states (PR_TRUE), or only changed
*/
NS_HIDDEN_(void) DispatchEvents(nsIXFormsControl *aControl,
nsIDOMNode *aNode,
PRBool aInitialize = PR_FALSE);
NS_HIDDEN_(nsresult) SetStatesInternal(nsIXFormsControl *aControl,
nsIDOMNode *aNode,
PRBool aAllStates = PR_FALSE);
/**
* Sets the state of a specific state.
*
* @param aElement The element to dispatch events to and set states on
* @param aState The state value
* @param aOnEvent The on event for the state.
* @param aAttributePos The position of the "on" attribute in kStateAttributes
*
* @note aAttributePos is only needed until bug 271720 is landed.
*/
NS_HIDDEN_(void) SetSingleState(nsIDOMElement *aElement,
PRBool aState,
nsXFormsEvent aOnEvent,
PRUint32 aAttributePos);
// Returns true when all external documents have been loaded
PRBool IsComplete() const { return (mSchemaTotal == mSchemaCount

View File

@ -211,8 +211,6 @@ nsXFormsOutputElement::Bind()
{
if (!mValue || !mHasParent)
return NS_OK;
mBoundNode = nsnull;
nsresult rv;
rv = mElement->HasAttribute(NS_LITERAL_STRING("ref"), &mHasBinding);
@ -222,24 +220,19 @@ nsXFormsOutputElement::Bind()
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMPtr<nsIDOMXPathResult> result;
if (mHasBinding) {
rv = ProcessNodeBinding(NS_LITERAL_STRING("ref"),
nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE,
getter_AddRefs(result));
rv = nsXFormsControlStub::Bind();
} else {
rv = ProcessNodeBinding(NS_LITERAL_STRING("value"),
nsIDOMXPathResult::STRING_TYPE,
getter_AddRefs(result));
}
mBoundNode = nsnull;
// This call does a bit too much, as we do the call again in Refresh(),
// but we need to clear index listeners, bind to the model, get
// evt. context, etc. in Bind().
rv = ResetBoundNode(NS_LITERAL_STRING("value"),
nsIDOMXPathResult::STRING_TYPE);
}
NS_ENSURE_SUCCESS(rv, rv);
if (result) {
result->GetSingleNodeValue(getter_AddRefs(mBoundNode));
}
return NS_OK;
return rv;
}
NS_IMETHODIMP
@ -256,9 +249,9 @@ nsXFormsOutputElement::Refresh()
}
} else {
nsCOMPtr<nsIDOMXPathResult> result;
rv = ProcessNodeBinding(NS_LITERAL_STRING("value"),
nsIDOMXPathResult::STRING_TYPE,
getter_AddRefs(result));
rv = ResetBoundNode(NS_LITERAL_STRING("value"),
nsIDOMXPathResult::STRING_TYPE,
getter_AddRefs(result));
NS_ENSURE_SUCCESS(rv, rv);
if (result) {

View File

@ -167,6 +167,19 @@ static const EventData sEventDefaultsEntries[] = {
static nsDataHashtable<nsStringHashKey,PRUint32> sXFormsEvents;
static nsDataHashtable<nsStringHashKey,PRUint32> sEventDefaults;
/**
* @todo The attribute names used on the elements to reflect the pseudo class
* state until bug 271720 is landed. (XXX)
*/
const nsString kStateAttributes[8] = { NS_LITERAL_STRING("valid"),
NS_LITERAL_STRING("invalid"),
NS_LITERAL_STRING("read-only"),
NS_LITERAL_STRING("read-write"),
NS_LITERAL_STRING("required"),
NS_LITERAL_STRING("optional"),
NS_LITERAL_STRING("enabled"),
NS_LITERAL_STRING("disabled") };
/* static */ nsresult
nsXFormsUtils::Init()
{

View File

@ -65,6 +65,9 @@ class nsIDOMEvent;
* XForms event types
*
* @see http://www.w3.org/TR/xforms/slice4.html#rpm-events
*
* @note nsXFormsModelElement::SetSingleState() assumes a specific order of
* the events from eEvent_Valid to eEvent_Disabled.
*/
enum nsXFormsEvent {
@ -120,6 +123,12 @@ struct EventData
extern const EventData sXFormsEventsEntries[41];
/**
* @todo The attribute names used on the elements to reflect the pseudo class
* state until bug 271720 is landed. (XXX)
*/
extern const nsString kStateAttributes[8];
/**
* This class has static helper methods that don't fit into a specific place
* in the class hierarchy.