зеркало из https://github.com/mozilla/pjs.git
[XForms] Optimize repeat refreshing. Bug 331452, r=smaug+aaronr
This commit is contained in:
Родитель
80dab191f0
Коммит
300027c505
|
@ -49,7 +49,7 @@ interface nsIDOMElement;
|
|||
/**
|
||||
* Interface implemented by all XForms form control classes.
|
||||
*/
|
||||
[uuid(1bea8750-2133-4a00-986a-04e5cbd129b2)]
|
||||
[uuid(8c84afe1-e071-4d45-b3da-c5aa93154343)]
|
||||
interface nsIXFormsControl : nsIXFormsContextControl
|
||||
{
|
||||
/**
|
||||
|
@ -62,13 +62,24 @@ interface nsIXFormsControl : nsIXFormsContextControl
|
|||
*/
|
||||
readonly attribute nsIDOMNode boundNode;
|
||||
|
||||
/**
|
||||
* Binds the control to the model. Only handles attaching to the model
|
||||
* (including reattaching from any old model).
|
||||
*
|
||||
* @note It can also set the boundNode, but does not do a proper node
|
||||
* binding, as in setting up dependencies, attaching index() listeners, etc.
|
||||
*
|
||||
* @param setBoundNode Set boundNode too?
|
||||
*/
|
||||
void bindToModel(in boolean setBoundNode);
|
||||
|
||||
/**
|
||||
* The instance nodes that the control depend on.
|
||||
*
|
||||
* In other words, all the instance nodes that could influence which node
|
||||
* the control is bound to (mBoundNode). For example:
|
||||
* If a node has @ref="/share[@owner = /me]", it depends on all /share
|
||||
* nodes, all @owned attributes on /share nodes, and all /me nodes.
|
||||
* nodes, all @owner attributes on /share nodes, and all /me nodes.
|
||||
*/
|
||||
readonly attribute nsCOMArrayPtr dependencies;
|
||||
|
||||
|
|
|
@ -36,14 +36,16 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[uuid(b8540fca-a671-4a1d-8471-6e89820f0848)]
|
||||
[uuid(92b8a6aa-3692-4132-8df6-a61a936d5e9d)]
|
||||
interface nsIXFormsControlBase : nsISupports
|
||||
{
|
||||
/**
|
||||
* This tells the form control to update its node binding based on the
|
||||
* current instance data.
|
||||
*
|
||||
* @return Did the binding change the context?
|
||||
*/
|
||||
void bind();
|
||||
boolean bind();
|
||||
|
||||
/**
|
||||
* This tells the form control to update its state based on the current
|
||||
|
|
|
@ -89,11 +89,15 @@ protected:
|
|||
PRInt32 mContextSize;
|
||||
|
||||
/** Does this element have the repeat-index? */
|
||||
PRBool mHasIndex;
|
||||
PRPackedBool mHasIndex;
|
||||
|
||||
/** Has context changed since last bind? */
|
||||
PRPackedBool mContextIsDirty;
|
||||
|
||||
public:
|
||||
nsXFormsContextContainer()
|
||||
: mContextPosition(1), mContextSize(1), mHasIndex(PR_FALSE) {}
|
||||
: mContextPosition(1), mContextSize(1), mHasIndex(PR_FALSE),
|
||||
mContextIsDirty(PR_FALSE) {}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
|
@ -102,7 +106,7 @@ public:
|
|||
NS_IMETHOD DocumentChanged(nsIDOMDocument *aNewDocument);
|
||||
|
||||
// nsIXFormsControl
|
||||
NS_IMETHOD Bind();
|
||||
NS_IMETHOD Bind(PRBool *aContextChanged);
|
||||
NS_IMETHOD SetContext(nsIDOMNode *aContextNode,
|
||||
PRInt32 aContextPosition,
|
||||
PRInt32 aContextSize);
|
||||
|
@ -271,11 +275,18 @@ nsXFormsContextContainer::SetContext(nsIDOMNode *aContextNode,
|
|||
PRInt32 aContextPosition,
|
||||
PRInt32 aContextSize)
|
||||
{
|
||||
mBoundNode = aContextNode;
|
||||
mContextPosition = aContextPosition;
|
||||
mContextSize = aContextSize;
|
||||
mContextIsDirty = (mContextIsDirty ||
|
||||
mBoundNode != aContextNode ||
|
||||
mContextPosition != aContextPosition ||
|
||||
mContextSize != aContextSize);
|
||||
|
||||
return Bind();
|
||||
if (mContextIsDirty) {
|
||||
mBoundNode = aContextNode;
|
||||
mContextPosition = aContextPosition;
|
||||
mContextSize = aContextSize;
|
||||
}
|
||||
|
||||
return BindToModel();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -299,12 +310,11 @@ nsXFormsContextContainer::GetContext(nsAString &aModelID,
|
|||
// nsIXFormsControl
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsContextContainer::Bind()
|
||||
nsXFormsContextContainer::Bind(PRBool *aContextChanged)
|
||||
{
|
||||
|
||||
nsresult rv = BindToModel();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ENSURE_ARG(aContextChanged);
|
||||
*aContextChanged = mContextIsDirty;
|
||||
mContextIsDirty = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -141,12 +141,16 @@ nsXFormsControlStubBase::RemoveIndexListeners()
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsControlStubBase::ResetBoundNode(const nsString &aBindAttribute,
|
||||
PRUint16 aResultType,
|
||||
nsIDOMXPathResult **aResult)
|
||||
nsXFormsControlStubBase::ResetBoundNode(const nsString &aBindAttribute,
|
||||
PRUint16 aResultType,
|
||||
PRBool *aContextChanged)
|
||||
{
|
||||
NS_ENSURE_ARG(aContextChanged);
|
||||
|
||||
// Clear existing bound node, etc.
|
||||
mBoundNode = nsnull;
|
||||
*aContextChanged = mBoundNode ? PR_TRUE : PR_FALSE;
|
||||
nsCOMPtr<nsIDOMNode> oldBoundNode;
|
||||
oldBoundNode.swap(mBoundNode);
|
||||
mUsesModelBinding = PR_FALSE;
|
||||
mAppearDisabled = PR_FALSE;
|
||||
mDependencies.Clear();
|
||||
|
@ -166,7 +170,7 @@ nsXFormsControlStubBase::ResetBoundNode(const nsString &aBindAttribute,
|
|||
|
||||
if (rv == NS_OK_XFORMS_DEFERRED || !result) {
|
||||
// Binding was deferred, or not bound
|
||||
return NS_OK;
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Get context node, if any
|
||||
|
@ -177,6 +181,8 @@ nsXFormsControlStubBase::ResetBoundNode(const nsString &aBindAttribute,
|
|||
result->GetSingleNodeValue(getter_AddRefs(mBoundNode));
|
||||
}
|
||||
|
||||
*aContextChanged = (oldBoundNode != mBoundNode);
|
||||
|
||||
if (!mBoundNode) {
|
||||
// If there's no result (ie, no instance node) returned by the above, it
|
||||
// means that the binding is not pointing to an instance data node, so we
|
||||
|
@ -189,19 +195,15 @@ nsXFormsControlStubBase::ResetBoundNode(const nsString &aBindAttribute,
|
|||
return wrapper->SetIntrinsicState(kDisabledIntrinsicState);
|
||||
}
|
||||
|
||||
if (aResult) {
|
||||
*aResult = nsnull;
|
||||
result.swap(*aResult); // transfers ref
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsControlStubBase::Bind()
|
||||
nsXFormsControlStubBase::Bind(PRBool* aContextChanged)
|
||||
{
|
||||
return ResetBoundNode(NS_LITERAL_STRING("ref"),
|
||||
nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE);
|
||||
nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE,
|
||||
aContextChanged);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -364,7 +366,7 @@ nsXFormsControlStubBase::ProcessNodeBinding(const nsString &aBindingAtt
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_IMETHODIMP
|
||||
nsXFormsControlStubBase::BindToModel(PRBool aSetBoundNode)
|
||||
{
|
||||
nsCOMPtr<nsIModelElementPrivate> oldModel(mModel);
|
||||
|
@ -604,7 +606,8 @@ nsXFormsControlStubBase::ForceModelDetach(PRBool aRebind)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv = Bind();
|
||||
PRBool dummy;
|
||||
nsresult rv = Bind(&dummy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return rv == NS_OK_XFORMS_DEFERRED ? NS_OK : Refresh();
|
||||
}
|
||||
|
@ -747,7 +750,8 @@ void
|
|||
nsXFormsControlStubBase::AfterSetAttribute(nsIAtom *aName)
|
||||
{
|
||||
if (IsBindingAttribute(aName)) {
|
||||
nsresult rv = Bind();
|
||||
PRBool dummy;
|
||||
nsresult rv = Bind(&dummy);
|
||||
if (NS_SUCCEEDED(rv) && rv != NS_OK_XFORMS_DEFERRED)
|
||||
Refresh();
|
||||
}
|
||||
|
|
|
@ -81,12 +81,13 @@ public:
|
|||
|
||||
// nsIXFormsControl
|
||||
NS_IMETHOD GetBoundNode(nsIDOMNode **aBoundNode);
|
||||
NS_IMETHOD BindToModel(PRBool aSetBoundNode = PR_FALSE);
|
||||
NS_IMETHOD GetDependencies(nsCOMArray<nsIDOMNode> **aDependencies);
|
||||
NS_IMETHOD GetElement(nsIDOMElement **aElement);
|
||||
NS_IMETHOD ResetBoundNode(const nsString &aBindAttribute,
|
||||
PRUint16 aResultType,
|
||||
nsIDOMXPathResult **aResult = nsnull);
|
||||
NS_IMETHOD Bind();
|
||||
NS_IMETHOD ResetBoundNode(const nsString &aBindAttribute,
|
||||
PRUint16 aResultType,
|
||||
PRBool *aContextChanged);
|
||||
NS_IMETHOD Bind(PRBool *aContextChanged);
|
||||
NS_IMETHOD Refresh();
|
||||
NS_IMETHOD GetOnDeferredBindList(PRBool *onList);
|
||||
NS_IMETHOD SetOnDeferredBindList(PRBool putOnList);
|
||||
|
@ -263,17 +264,6 @@ protected:
|
|||
/** Removes the index change event listeners */
|
||||
void RemoveIndexListeners();
|
||||
|
||||
/**
|
||||
* Binds the control to the model. Just sets mModel, and handle attaching to
|
||||
* the model (including reattaching from any old model).
|
||||
*
|
||||
* @note It can also set the mBoundNode, but does not do a proper node
|
||||
* binding, as in setting up dependencies, attaching index() listeners, etc.
|
||||
*
|
||||
* @param aSetBoundNode Set mBoundNode too?
|
||||
*/
|
||||
nsresult BindToModel(PRBool aSetBoundNode = PR_FALSE);
|
||||
|
||||
/**
|
||||
* Forces detaching from the model.
|
||||
*
|
||||
|
@ -350,9 +340,9 @@ public:
|
|||
return nsXFormsControlStubBase::AttributeRemoved(aName);
|
||||
}
|
||||
|
||||
NS_IMETHOD Bind()
|
||||
NS_IMETHOD Bind(PRBool *aContextChanged)
|
||||
{
|
||||
return nsXFormsControlStubBase::Bind();
|
||||
return nsXFormsControlStubBase::Bind(aContextChanged);
|
||||
}
|
||||
|
||||
/** Constructor */
|
||||
|
|
|
@ -116,10 +116,8 @@ nsXFormsDelegateStub::Refresh()
|
|||
SetMozTypeAttribute();
|
||||
|
||||
nsCOMPtr<nsIXFormsUIWidget> widget = do_QueryInterface(mElement);
|
||||
if (!widget)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return widget->Refresh();
|
||||
return widget ? widget->Refresh() : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -70,7 +70,7 @@ public:
|
|||
NS_IMETHOD DoneAddingChildren();
|
||||
|
||||
// nsIXFormsControlBase overrides
|
||||
NS_IMETHOD Bind();
|
||||
NS_IMETHOD Bind(PRBool *aContextChanged);
|
||||
NS_IMETHOD Refresh();
|
||||
|
||||
// nsIXFormsSelectChild
|
||||
|
@ -222,8 +222,10 @@ nsXFormsItemSetElement::SelectItemByNode(nsIDOMNode *aNode,
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsItemSetElement::Bind()
|
||||
nsXFormsItemSetElement::Bind(PRBool *aContextChanged)
|
||||
{
|
||||
NS_ENSURE_ARG(aContextChanged);
|
||||
*aContextChanged = PR_FALSE;
|
||||
return BindToModel();
|
||||
}
|
||||
|
||||
|
@ -303,23 +305,21 @@ nsXFormsItemSetElement::Refresh()
|
|||
getter_AddRefs(itemNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
anonContent->AppendChild(itemNode, getter_AddRefs(tmpNode));
|
||||
|
||||
// XXX Could we get rid of the <contextcontainer>?
|
||||
rv = domDoc->CreateElementNS(NS_LITERAL_STRING(NS_NAMESPACE_XFORMS),
|
||||
NS_LITERAL_STRING("contextcontainer"),
|
||||
getter_AddRefs(contextContainer));
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDOMElement> modelElement = do_QueryInterface(model);
|
||||
nsAutoString modelID;
|
||||
modelElement->GetAttribute(NS_LITERAL_STRING("id"), modelID);
|
||||
|
||||
contextContainer->SetAttribute(NS_LITERAL_STRING("model"), modelID);
|
||||
itemNode->AppendChild(contextContainer, getter_AddRefs(tmpNode));
|
||||
|
||||
nsCOMPtr<nsIXFormsContextControl> ctx(do_QueryInterface(contextContainer));
|
||||
if (ctx) {
|
||||
ctx->SetContext(node, i + 1, nodeCount);
|
||||
}
|
||||
|
||||
// Clone the template content under the item
|
||||
for (PRUint32 j = 0; j < templateNodeCount; ++j) {
|
||||
templateNodes->Item(j, getter_AddRefs(templateNode));
|
||||
|
@ -327,8 +327,6 @@ nsXFormsItemSetElement::Refresh()
|
|||
contextContainer->AppendChild(cloneNode, getter_AddRefs(templateNode));
|
||||
}
|
||||
|
||||
itemNode->AppendChild(contextContainer, getter_AddRefs(tmpNode));
|
||||
anonContent->AppendChild(itemNode, getter_AddRefs(tmpNode));
|
||||
}
|
||||
|
||||
// refresh parent we
|
||||
|
|
|
@ -639,7 +639,7 @@ nsXFormsModelElement::nsXFormsModelElement()
|
|||
mSchemaTotal(0),
|
||||
mPendingInstanceCount(0),
|
||||
mDocumentLoaded(PR_FALSE),
|
||||
mNeedsRefresh(PR_FALSE),
|
||||
mRebindAllControls(PR_FALSE),
|
||||
mInstancesInitialized(PR_FALSE),
|
||||
mReadyHandled(PR_FALSE),
|
||||
mLazyModel(PR_FALSE),
|
||||
|
@ -1062,18 +1062,8 @@ nsXFormsModelElement::Rebuild()
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// 3. Re-attach all elements
|
||||
if (mReadyHandled) { // if it's not during initializing phase
|
||||
nsXFormsControlListItem::iterator it;
|
||||
for (it = mFormControls.begin(); it != mFormControls.end(); ++it) {
|
||||
nsCOMPtr<nsIXFormsControl> control = (*it)->Control();
|
||||
NS_ASSERTION(control, "mFormControls has null control?!");
|
||||
|
||||
// run bind to reset mBoundNode for all of the model's controls
|
||||
control->Bind();
|
||||
}
|
||||
|
||||
// Triggers a refresh of all controls
|
||||
mNeedsRefresh = PR_TRUE;
|
||||
if (mDocumentLoaded) {
|
||||
mRebindAllControls = PR_TRUE;
|
||||
}
|
||||
|
||||
// 4. Rebuild graph
|
||||
|
@ -1199,16 +1189,16 @@ nsXFormsModelElement::RefreshSubTree(nsXFormsControlListItem *aCurrent,
|
|||
#ifdef DEBUG_MODEL
|
||||
nsCOMPtr<nsIDOMElement> controlElement;
|
||||
control->GetElement(getter_AddRefs(controlElement));
|
||||
printf("rebind: %d, mNeedsRefresh: %d, rebindChildren: %d\n",
|
||||
rebind, mNeedsRefresh, rebindChildren);
|
||||
printf("rebind: %d, mRebindAllControls: %d, aForceRebind: %d\n",
|
||||
rebind, mRebindAllControls, aForceRebind);
|
||||
if (controlElement) {
|
||||
printf("Checking control: ");
|
||||
//DBG_TAGINFO(controlElement);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mNeedsRefresh || rebind) {
|
||||
refresh = PR_TRUE;
|
||||
if (mRebindAllControls || rebind) {
|
||||
refresh = rebind = PR_TRUE;
|
||||
} else {
|
||||
PRBool usesModelBinding = PR_FALSE;
|
||||
control->GetUsesModelBinding(&usesModelBinding);
|
||||
|
@ -1299,22 +1289,18 @@ nsXFormsModelElement::RefreshSubTree(nsXFormsControlListItem *aCurrent,
|
|||
|
||||
// Handle rebinding
|
||||
if (rebind) {
|
||||
nsCOMPtr<nsIDOMNode> oldBoundNode;
|
||||
control->GetBoundNode(getter_AddRefs(oldBoundNode));
|
||||
rv = control->Bind();
|
||||
rv = control->Bind(&rebindChildren);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
control->GetBoundNode(getter_AddRefs(boundNode));
|
||||
rebindChildren = (oldBoundNode != boundNode);
|
||||
}
|
||||
|
||||
// Handle refreshing
|
||||
if (rebind || refresh) {
|
||||
control->Refresh();
|
||||
// XXX: we should really check the return result, but f.x. select1
|
||||
// returns error because of no widget...? so we should ensure that an
|
||||
// error is only returned when there actually is an error, and we should
|
||||
// report that on the console... possibly we should then continue,
|
||||
// instead of bailing totally.
|
||||
// XXX: bug 336608: we should really check the return result, but
|
||||
// f.x. select1 returns error because of no widget...? so we should
|
||||
// ensure that an error is only returned when there actually is an
|
||||
// error, and we should report that on the console... possibly we should
|
||||
// then continue, instead of bailing totally.
|
||||
// NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
@ -1341,13 +1327,17 @@ nsXFormsModelElement::Refresh()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// XXXbeaufour: Can we somehow suspend redraw / "screen update" while doing
|
||||
// the refresh? That should save a lot of time, and avoid flickering of
|
||||
// controls.
|
||||
|
||||
// Kick off refreshing on root node
|
||||
nsresult rv = RefreshSubTree(mFormControls.FirstChild(), PR_FALSE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Clear refresh structures
|
||||
mChangedNodes.Clear();
|
||||
mNeedsRefresh = PR_FALSE;
|
||||
mRebindAllControls = PR_FALSE;
|
||||
mMDG.ClearDispatchFlags();
|
||||
|
||||
return NS_OK;
|
||||
|
@ -1407,6 +1397,11 @@ NS_IMETHODIMP
|
|||
nsXFormsModelElement::AddFormControl(nsIXFormsControl *aControl,
|
||||
nsIXFormsControl *aParent)
|
||||
{
|
||||
#ifdef DEBUG_MODEL
|
||||
printf("nsXFormsModelElement::AddFormControl(con: %p, parent: %p)\n",
|
||||
(void*) aControl, (void*) aParent);
|
||||
#endif
|
||||
|
||||
NS_ENSURE_ARG(aControl);
|
||||
return mFormControls.AddControl(aControl, aParent);
|
||||
}
|
||||
|
@ -1414,6 +1409,11 @@ nsXFormsModelElement::AddFormControl(nsIXFormsControl *aControl,
|
|||
NS_IMETHODIMP
|
||||
nsXFormsModelElement::RemoveFormControl(nsIXFormsControl *aControl)
|
||||
{
|
||||
#ifdef DEBUG_MODEL
|
||||
printf("nsXFormsModelElement::RemoveFormControl(con: %p)\n",
|
||||
(void*) aControl);
|
||||
#endif
|
||||
|
||||
NS_ENSURE_ARG(aControl);
|
||||
PRBool removed;
|
||||
nsresult rv = mFormControls.RemoveControl(aControl, removed);
|
||||
|
@ -2109,6 +2109,7 @@ nsXFormsModelElement::InitializeControls()
|
|||
|
||||
nsXFormsControlListItem::iterator it;
|
||||
nsresult rv;
|
||||
PRBool dummy;
|
||||
for (it = mFormControls.begin(); it != mFormControls.end(); ++it) {
|
||||
// Get control
|
||||
nsCOMPtr<nsIXFormsControl> control = (*it)->Control();
|
||||
|
@ -2121,17 +2122,14 @@ nsXFormsModelElement::InitializeControls()
|
|||
// DBG_TAGINFO(controlElement);
|
||||
#endif
|
||||
// Rebind
|
||||
rv = control->Bind();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Get bound node
|
||||
nsCOMPtr<nsIDOMNode> boundNode;
|
||||
rv = control->GetBoundNode(getter_AddRefs(boundNode));
|
||||
rv = control->Bind(&dummy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Refresh controls
|
||||
rv = control->Refresh();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// XXX: Bug 336608, refresh still fails for some controls, for some
|
||||
// reason.
|
||||
// NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
mChangedNodes.Clear();
|
||||
|
@ -2176,13 +2174,6 @@ nsXFormsModelElement::MaybeNotifyCompletion()
|
|||
}
|
||||
}
|
||||
|
||||
// Okay, dispatch xforms-model-construct-done and xforms-ready events!
|
||||
for (i = 0; i < models->Count(); ++i) {
|
||||
nsXFormsModelElement *model =
|
||||
NS_STATIC_CAST(nsXFormsModelElement *, models->ElementAt(i));
|
||||
nsXFormsUtils::DispatchEvent(model->mElement, eEvent_ModelConstructDone);
|
||||
}
|
||||
|
||||
// validate the instance documents becauar we want schemaValidation to add
|
||||
// schema type properties from the schema file unto our instance document
|
||||
// elements. We don't care about the validation results.
|
||||
|
@ -2214,8 +2205,17 @@ nsXFormsModelElement::MaybeNotifyCompletion()
|
|||
}
|
||||
}
|
||||
|
||||
// Register deferred binds with the model. It does not bind the controls,
|
||||
// only bind them to the model they belong to.
|
||||
nsXFormsModelElement::ProcessDeferredBinds(domDoc);
|
||||
|
||||
// Okay, dispatch xforms-model-construct-done
|
||||
for (i = 0; i < models->Count(); ++i) {
|
||||
nsXFormsModelElement *model =
|
||||
NS_STATIC_CAST(nsXFormsModelElement *, models->ElementAt(i));
|
||||
nsXFormsUtils::DispatchEvent(model->mElement, eEvent_ModelConstructDone);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
|
||||
if (doc) {
|
||||
PRUint32 loadingMessages = NS_PTR_TO_UINT32(
|
||||
|
@ -2229,6 +2229,7 @@ nsXFormsModelElement::MaybeNotifyCompletion()
|
|||
}
|
||||
}
|
||||
|
||||
// Backup instances and fire xforms-ready
|
||||
for (i = 0; i < models->Count(); ++i) {
|
||||
nsXFormsModelElement *model =
|
||||
NS_STATIC_CAST(nsXFormsModelElement *, models->ElementAt(i));
|
||||
|
@ -2488,8 +2489,8 @@ nsXFormsModelElement::MessageLoadFinished()
|
|||
mElement->GetOwnerDocument(getter_AddRefs(domDoc));
|
||||
const nsVoidArray *models = GetModelList(domDoc);
|
||||
nsCOMPtr<nsIDocument>doc = do_QueryInterface(domDoc);
|
||||
nsCOMArray<nsIXFormsControlBase> *deferredBindList =
|
||||
NS_STATIC_CAST(nsCOMArray<nsIXFormsControlBase> *,
|
||||
nsCOMArray<nsIXFormsControl> *deferredBindList =
|
||||
NS_STATIC_CAST(nsCOMArray<nsIXFormsControl> *,
|
||||
doc->GetProperty(nsXFormsAtoms::deferredBindListProperty));
|
||||
|
||||
// if we've already gotten the xforms-model-construct-done event and not
|
||||
|
@ -2554,8 +2555,8 @@ DeleteBindList(void *aObject,
|
|||
}
|
||||
|
||||
/* static */ nsresult
|
||||
nsXFormsModelElement::DeferElementBind(nsIDOMDocument *aDoc,
|
||||
nsIXFormsControlBase *aControl)
|
||||
nsXFormsModelElement::DeferElementBind(nsIDOMDocument *aDoc,
|
||||
nsIXFormsControl *aControl)
|
||||
{
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
|
||||
|
||||
|
@ -2570,7 +2571,7 @@ nsXFormsModelElement::DeferElementBind(nsIDOMDocument *aDoc,
|
|||
// We need to keep the document order of the controls AND don't want
|
||||
// to walk the deferredBindList every time we want to check about adding a
|
||||
// control.
|
||||
nsCOMPtr<nsIXFormsControlBase> controlBase(do_QueryInterface(aControl));
|
||||
nsCOMPtr<nsIXFormsControl> controlBase(do_QueryInterface(aControl));
|
||||
NS_ENSURE_STATE(controlBase);
|
||||
|
||||
PRBool onList = PR_FALSE;
|
||||
|
@ -2579,12 +2580,12 @@ nsXFormsModelElement::DeferElementBind(nsIDOMDocument *aDoc,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMArray<nsIXFormsControlBase> *deferredBindList =
|
||||
NS_STATIC_CAST(nsCOMArray<nsIXFormsControlBase> *,
|
||||
nsCOMArray<nsIXFormsControl> *deferredBindList =
|
||||
NS_STATIC_CAST(nsCOMArray<nsIXFormsControl> *,
|
||||
doc->GetProperty(nsXFormsAtoms::deferredBindListProperty));
|
||||
|
||||
if (!deferredBindList) {
|
||||
deferredBindList = new nsCOMArray<nsIXFormsControlBase>(16);
|
||||
deferredBindList = new nsCOMArray<nsIXFormsControl>(16);
|
||||
NS_ENSURE_TRUE(deferredBindList, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
doc->SetProperty(nsXFormsAtoms::deferredBindListProperty, deferredBindList,
|
||||
|
@ -2604,6 +2605,10 @@ nsXFormsModelElement::DeferElementBind(nsIDOMDocument *aDoc,
|
|||
/* static */ void
|
||||
nsXFormsModelElement::ProcessDeferredBinds(nsIDOMDocument *aDoc)
|
||||
{
|
||||
#ifdef DEBUG_MODEL
|
||||
printf("nsXFormsModelElement::ProcessDeferredBinds()\n");
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
|
||||
|
||||
if (!doc) {
|
||||
|
@ -2614,17 +2619,16 @@ nsXFormsModelElement::ProcessDeferredBinds(nsIDOMDocument *aDoc)
|
|||
|
||||
doc->SetProperty(nsXFormsAtoms::readyForBindProperty, doc);
|
||||
|
||||
nsCOMArray<nsIXFormsControlBase> *deferredBindList =
|
||||
NS_STATIC_CAST(nsCOMArray<nsIXFormsControlBase> *,
|
||||
nsCOMArray<nsIXFormsControl> *deferredBindList =
|
||||
NS_STATIC_CAST(nsCOMArray<nsIXFormsControl> *,
|
||||
doc->GetProperty(nsXFormsAtoms::deferredBindListProperty));
|
||||
|
||||
if (deferredBindList) {
|
||||
for (int i = 0; i < deferredBindList->Count(); ++i) {
|
||||
nsIXFormsControlBase *base = deferredBindList->ObjectAt(i);
|
||||
if (base) {
|
||||
base->Bind();
|
||||
base->Refresh();
|
||||
base->SetOnDeferredBindList(PR_FALSE);
|
||||
for (PRInt32 i = 0; i < deferredBindList->Count(); ++i) {
|
||||
nsIXFormsControl *control = deferredBindList->ObjectAt(i);
|
||||
if (control) {
|
||||
control->BindToModel(PR_FALSE);
|
||||
control->SetOnDeferredBindList(PR_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -248,7 +248,7 @@ public:
|
|||
NS_IMETHOD OnCreated(nsIXTFGenericElementWrapper *aWrapper);
|
||||
|
||||
// nsIXFormsControlBase overrides
|
||||
NS_IMETHOD Bind() {
|
||||
NS_IMETHOD Bind(PRBool *aContextChanged) {
|
||||
// dummy method, so does nothing
|
||||
return NS_OK;
|
||||
};
|
||||
|
@ -275,7 +275,7 @@ public:
|
|||
* @param aControl XForms control waiting to be bound
|
||||
*/
|
||||
static NS_HIDDEN_(nsresult) DeferElementBind(nsIDOMDocument *aDoc,
|
||||
nsIXFormsControlBase *aControl);
|
||||
nsIXFormsControl *aControl);
|
||||
|
||||
static nsresult NeedsPostRefresh(nsIXFormsControl* aControl);
|
||||
|
||||
|
@ -333,8 +333,11 @@ private:
|
|||
nsXFormsEvent aOnEvent);
|
||||
|
||||
/**
|
||||
* Call the Bind() and Refresh() on controls which was deferred because
|
||||
* the model was not ready.
|
||||
* Handle controls bindings which was deferred because the model was not
|
||||
* ready.
|
||||
*
|
||||
* @note Only registers the controls with the model. Does not setup
|
||||
* bindings, etc.
|
||||
*
|
||||
* @param aDoc Document that contains the XForms control
|
||||
*/
|
||||
|
@ -397,7 +400,7 @@ private:
|
|||
* Indicates whether all controls should be refreshed on the next Refresh()
|
||||
* run.
|
||||
*/
|
||||
PRPackedBool mNeedsRefresh;
|
||||
PRPackedBool mRebindAllControls;
|
||||
|
||||
/**
|
||||
* Indicates whether instance elements have been initialized
|
||||
|
|
|
@ -77,7 +77,7 @@ class nsXFormsOutputElement : public nsXFormsDelegateStub
|
|||
{
|
||||
public:
|
||||
// nsIXFormsControl
|
||||
NS_IMETHOD Bind();
|
||||
NS_IMETHOD Bind(PRBool* aContextChanged);
|
||||
NS_IMETHOD Refresh();
|
||||
NS_IMETHOD GetBoundNode(nsIDOMNode **aBoundNode);
|
||||
|
||||
|
@ -105,12 +105,12 @@ nsXFormsOutputElement::nsXFormsOutputElement()
|
|||
// nsIXFormsControl
|
||||
|
||||
nsresult
|
||||
nsXFormsOutputElement::Bind()
|
||||
nsXFormsOutputElement::Bind(PRBool *aContextChanged)
|
||||
{
|
||||
SetDOMStringToNull(mValue);
|
||||
mUseValueAttribute = PR_FALSE;
|
||||
|
||||
nsresult rv = nsXFormsDelegateStub::Bind();
|
||||
nsresult rv = nsXFormsDelegateStub::Bind(aContextChanged);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mHasParent || !mElement || rv == NS_OK_XFORMS_DEFERRED)
|
||||
|
|
|
@ -192,9 +192,6 @@ class nsXFormsRepeatElement : public nsXFormsDelegateStub,
|
|||
public nsIXFormsRepeatElement
|
||||
{
|
||||
protected:
|
||||
/** True while children are being added */
|
||||
PRBool mAddingChildren;
|
||||
|
||||
/**
|
||||
* The current repeat-index, 0 if no row is selected (can happen for nested
|
||||
* repeats) or there are no rows at all.
|
||||
|
@ -218,11 +215,21 @@ protected:
|
|||
* ResetInnerRepeats().
|
||||
*/
|
||||
PRUint32 mLevel;
|
||||
|
||||
/**
|
||||
* The number of "repeat rows" the repeat currently have unrolled.
|
||||
*/
|
||||
PRUint32 mCurrentRowCount;
|
||||
|
||||
/**
|
||||
* True while children are being added
|
||||
*/
|
||||
PRPackedBool mAddingChildren;
|
||||
|
||||
/**
|
||||
* Are we a parent for nested repeats
|
||||
*/
|
||||
PRBool mIsParent;
|
||||
PRPackedBool mIsParent;
|
||||
|
||||
/**
|
||||
* The currently selected repeat (nested repeats)
|
||||
|
@ -288,11 +295,24 @@ protected:
|
|||
*/
|
||||
void SanitizeIndex(PRUint32 *aIndex, PRBool aIsScroll = PR_FALSE);
|
||||
|
||||
/**
|
||||
* Unroll the template content into the visual rows by cloning template
|
||||
* content and inserting into contextcontainers.
|
||||
*/
|
||||
nsresult UnrollRows(nsIDOMXPathResult *aNodeset);
|
||||
|
||||
/**
|
||||
* Returns either the anonymous content of the repeat or null;
|
||||
*/
|
||||
already_AddRefed<nsIDOMElement> GetAnonymousContent();
|
||||
|
||||
/**
|
||||
* Insert the template content for a repeat node into the given node.
|
||||
*
|
||||
* @param aNode The node to insert content into.
|
||||
*/
|
||||
nsresult InsertTemplateContent(nsIDOMNode *aNode);
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
|
@ -305,7 +325,7 @@ public:
|
|||
NS_IMETHOD DoneAddingChildren();
|
||||
|
||||
// nsIXFormsControl
|
||||
NS_IMETHOD Bind();
|
||||
NS_IMETHOD Bind(PRBool *aContextChanged);
|
||||
NS_IMETHOD Refresh();
|
||||
NS_IMETHOD TryFocus(PRBool* aOK);
|
||||
NS_IMETHOD IsEventTarget(PRBool *aOK);
|
||||
|
@ -315,10 +335,11 @@ public:
|
|||
|
||||
// nsXFormsRepeatElement
|
||||
nsXFormsRepeatElement() :
|
||||
mAddingChildren(PR_FALSE),
|
||||
mCurrentIndex(0),
|
||||
mMaxIndex(0),
|
||||
mLevel(1),
|
||||
mCurrentRowCount(0),
|
||||
mAddingChildren(PR_FALSE),
|
||||
mIsParent(PR_FALSE)
|
||||
{}
|
||||
|
||||
|
@ -559,10 +580,17 @@ nsXFormsRepeatElement::IndexHasChanged()
|
|||
// they are rebound and refreshed().
|
||||
nsCOMArray<nsIXFormsControl> indexes(mIndexUsers);
|
||||
|
||||
PRBool contextChange;
|
||||
nsresult rv;
|
||||
for (PRInt32 i = 0; i < indexes.Count(); ++i) {
|
||||
nsCOMPtr<nsIXFormsControl> control = indexes[i];
|
||||
control->Bind();
|
||||
control->Refresh();
|
||||
rv = control->Bind(&contextChange);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = control->Refresh();
|
||||
if (contextChange) {
|
||||
// XXX: bug 335525
|
||||
NS_WARNING("Need to refresh children of index() user!\n");
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -677,52 +705,164 @@ nsXFormsRepeatElement::HandleNodeInsert(nsIDOMNode *aNode)
|
|||
// nsXFormsControl
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsRepeatElement::Bind()
|
||||
nsXFormsRepeatElement::Bind(PRBool *aContextChanged)
|
||||
{
|
||||
NS_ENSURE_ARG(aContextChanged);
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> domDoc;
|
||||
mElement->GetOwnerDocument(getter_AddRefs(domDoc));
|
||||
if (!nsXFormsUtils::IsDocumentReadyForBind(domDoc)) {
|
||||
nsXFormsModelElement::DeferElementBind(domDoc, this);
|
||||
*aContextChanged = PR_FALSE;
|
||||
return NS_OK_XFORMS_DEFERRED;
|
||||
}
|
||||
return BindToModel(PR_TRUE);
|
||||
|
||||
nsresult rv = BindToModel();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aContextChanged = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsRepeatElement::Refresh()
|
||||
nsresult
|
||||
nsXFormsRepeatElement::InsertTemplateContent(nsIDOMNode *aNode)
|
||||
{
|
||||
if (!mElement || mAddingChildren || mIsParent) {
|
||||
return NS_OK;
|
||||
NS_ENSURE_ARG(aNode);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> child;
|
||||
nsresult rv = mElement->GetFirstChild(getter_AddRefs(child));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
while (child) {
|
||||
nsCOMPtr<nsIDOMNode> childClone;
|
||||
rv = CloneNode(child, getter_AddRefs(childClone));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
rv = aNode->AppendChild(childClone, getter_AddRefs(newNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = child->GetNextSibling(getter_AddRefs(newNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
child = newNode;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXFormsRepeatElement::UnrollRows(nsIDOMXPathResult *aNodeset)
|
||||
{
|
||||
NS_ENSURE_STATE(mElement);
|
||||
|
||||
nsCOMPtr<nsIDOMElement> anon = GetAnonymousContent();
|
||||
if (!anon) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsPostRefresh postRefresh = nsPostRefresh();
|
||||
|
||||
nsresult rv;
|
||||
|
||||
// Clear any existing children
|
||||
nsCOMPtr<nsIDOMNode> cNode;
|
||||
anon->GetFirstChild(getter_AddRefs(cNode));
|
||||
while (cNode) {
|
||||
nsCOMPtr<nsIDOMNode> retNode;
|
||||
anon->RemoveChild(cNode, getter_AddRefs(retNode));
|
||||
anon->GetFirstChild(getter_AddRefs(cNode));
|
||||
if (!aNodeset || !mModel) {
|
||||
mMaxIndex = 0;
|
||||
} else {
|
||||
PRUint32 contextSize;
|
||||
rv = aNodeset->GetSnapshotLength(&contextSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mMaxIndex = contextSize;
|
||||
}
|
||||
|
||||
// Get the nodeset we are bound to
|
||||
nsCOMPtr<nsIDOMXPathResult> result;
|
||||
nsCOMPtr<nsIModelElementPrivate> model;
|
||||
rv = ProcessNodeBinding(NS_LITERAL_STRING("nodeset"),
|
||||
nsIDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE,
|
||||
getter_AddRefs(result),
|
||||
getter_AddRefs(model));
|
||||
// STEP 1: Remove rows
|
||||
nsCOMPtr<nsIDOMNode> tmp;
|
||||
if (mMaxIndex < mCurrentRowCount) {
|
||||
for (PRUint32 i = mMaxIndex; i < mCurrentRowCount; ++i) {
|
||||
nsCOMPtr<nsIDOMNode> lastChild;
|
||||
rv = anon->GetLastChild(getter_AddRefs(lastChild));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = anon->RemoveChild(lastChild, getter_AddRefs(tmp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
} else if (mMaxIndex > mCurrentRowCount) {
|
||||
// STEP 2: Add rows
|
||||
nsCOMPtr<nsIDOMDocument> domDoc;
|
||||
rv = anon->GetOwnerDocument(getter_AddRefs(domDoc));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
for (PRUint32 i = mCurrentRowCount; i < mMaxIndex; ++i) {
|
||||
// Create <contextcontainer>
|
||||
nsCOMPtr<nsIDOMElement> container;
|
||||
rv = domDoc->CreateElementNS(NS_LITERAL_STRING(NS_NAMESPACE_XFORMS),
|
||||
NS_LITERAL_STRING("contextcontainer"),
|
||||
getter_AddRefs(container));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
container->SetAttribute(NS_LITERAL_STRING("class"),
|
||||
NS_LITERAL_STRING("xf-repeat-item"));
|
||||
|
||||
if (NS_FAILED(rv) | !result | !model)
|
||||
return rv;
|
||||
rv = anon->AppendChild(container, getter_AddRefs(tmp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
// Repeat has no content
|
||||
if (!mMaxIndex) {
|
||||
mCurrentRowCount = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// STEP 3: Update context on rows
|
||||
nsCOMPtr<nsIDOMNode> child;
|
||||
rv = anon->GetFirstChild(getter_AddRefs(child));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
for (PRUint32 i = 0; i < mMaxIndex; ++i) {
|
||||
NS_ASSERTION(child, "Unrolled content does not match index size?!");
|
||||
// Get context node
|
||||
nsCOMPtr<nsIDOMNode> contextNode;
|
||||
rv = aNodeset->SnapshotItem(i, getter_AddRefs(contextNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Set context node, position, and size
|
||||
nsCOMPtr<nsIXFormsContextControl> childContext = do_QueryInterface(child);
|
||||
NS_ASSERTION(childContext,
|
||||
"content child not implementing nsIXFormsContextControl?!");
|
||||
|
||||
rv = childContext->SetContext(contextNode, i + 1, mMaxIndex);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Next child
|
||||
rv = child->GetNextSibling(getter_AddRefs(tmp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
tmp.swap(child);
|
||||
}
|
||||
|
||||
// Rows deleted, nothing more to do
|
||||
if (mCurrentRowCount >= mMaxIndex) {
|
||||
mCurrentRowCount = mMaxIndex;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// STEP 4: Insert template content into newly created rows
|
||||
nsCOMPtr<nsIDOMNodeList> containerList;
|
||||
rv = anon->GetChildNodes(getter_AddRefs(containerList));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
for (PRUint32 i = mCurrentRowCount; i < mMaxIndex; ++i) {
|
||||
nsCOMPtr<nsIDOMNode> container;
|
||||
rv = containerList->Item(i, getter_AddRefs(container));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = InsertTemplateContent(container);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
mCurrentRowCount = mMaxIndex;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXFormsRepeatElement::Refresh()
|
||||
{
|
||||
if (mAddingChildren || mIsParent)
|
||||
return NS_OK;
|
||||
|
||||
nsPostRefresh postRefresh = nsPostRefresh();
|
||||
|
||||
/// @todo The spec says: "This node-set must consist of contiguous child
|
||||
/// element nodes, with the same local name and namespace name of a common
|
||||
|
@ -732,81 +872,20 @@ nsXFormsRepeatElement::Refresh()
|
|||
///
|
||||
/// Can/should we check this somehow? (XXX)
|
||||
|
||||
PRUint32 contextSize;
|
||||
rv = result->GetSnapshotLength(&contextSize);
|
||||
|
||||
// Get the nodeset we are bound to
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMXPathResult> result;
|
||||
rv = ProcessNodeBinding(NS_LITERAL_STRING("nodeset"),
|
||||
nsIDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE,
|
||||
getter_AddRefs(result));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!contextSize)
|
||||
return NS_OK;
|
||||
|
||||
// Get model ID
|
||||
nsCOMPtr<nsIDOMElement> modelElement = do_QueryInterface(model);
|
||||
NS_ENSURE_TRUE(modelElement, NS_ERROR_FAILURE);
|
||||
nsAutoString modelID;
|
||||
modelElement->GetAttribute(NS_LITERAL_STRING("id"), modelID);
|
||||
|
||||
// Get DOM document
|
||||
nsCOMPtr<nsIDOMDocument> domDoc;
|
||||
rv = mElement->GetOwnerDocument(getter_AddRefs(domDoc));
|
||||
// Unroll the repeat rows
|
||||
rv = UnrollRows(result);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mMaxIndex = contextSize;
|
||||
for (PRUint32 i = 1; i < mMaxIndex + 1; ++i) {
|
||||
// Create <contextcontainer>
|
||||
nsCOMPtr<nsIDOMElement> riElement;
|
||||
rv = domDoc->CreateElementNS(NS_LITERAL_STRING(NS_NAMESPACE_XFORMS),
|
||||
NS_LITERAL_STRING("contextcontainer"),
|
||||
getter_AddRefs(riElement));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
riElement->SetAttribute(NS_LITERAL_STRING("class"),
|
||||
NS_LITERAL_STRING("xf-repeat-item"));
|
||||
|
||||
// Set model as attribute
|
||||
if (!modelID.IsEmpty()) {
|
||||
riElement->SetAttribute(NS_LITERAL_STRING("model"), modelID);
|
||||
}
|
||||
|
||||
// Get context node
|
||||
nsCOMPtr<nsIXFormsContextControl> riContext = do_QueryInterface(riElement);
|
||||
NS_ENSURE_TRUE(riContext, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> contextNode;
|
||||
rv = result->SnapshotItem(i - 1, getter_AddRefs(contextNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Set context node, position, and size
|
||||
rv = riContext->SetContext(contextNode, i, contextSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// We need to insert the context node before adding the children, or the
|
||||
// children will fail to set up their proper XForms context.
|
||||
nsCOMPtr<nsIDOMNode> domNode;
|
||||
rv = anon->AppendChild(riElement, getter_AddRefs(domNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Iterate over template children, clone them, and append them to
|
||||
// \<contextcontainer\>
|
||||
nsCOMPtr<nsIDOMNode> child;
|
||||
rv = mElement->GetFirstChild(getter_AddRefs(child));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
while (child) {
|
||||
/// XXX the node probably refreshes itself twice here, once on cloning
|
||||
/// and once when it's inserted ... that's not necessary.
|
||||
nsCOMPtr<nsIDOMNode> childClone;
|
||||
rv = CloneNode(child, getter_AddRefs(childClone));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
rv = riElement->AppendChild(childClone, getter_AddRefs(newNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = child->GetNextSibling(getter_AddRefs(newNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
child = newNode;
|
||||
}
|
||||
}
|
||||
|
||||
// Maintain the index
|
||||
if (mCurrentIndex) {
|
||||
// somebody might have been fooling around with our children since last
|
||||
// refresh (either using delete or through script, so check the index
|
||||
|
|
Загрузка…
Ссылка в новой задаче