1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is Mozilla XForms support.
17 * The Initial Developer of the Original Code is
19 * Portions created by the Initial Developer are Copyright (C) 2004
20 * the Initial Developer. All Rights Reserved.
23 * Brian Ryner <bryner@brianryner.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsIXFormsSelectChild.h"
40 #include "nsXFormsStubElement.h"
41 #include "nsIDOMHTMLOptGroupElement.h"
44 #include "nsIXTFElementWrapper.h"
45 #include "nsIDOMNodeList.h"
46 #include "nsIDocument.h"
47 #include "nsXFormsUtils.h"
48 #include "nsXFormsModelElement.h"
49 #include "nsIXFormsControlBase.h"
50 #include "nsIXFormsControl.h"
51 #include "nsIXFormsItemSetUIElement.h"
52 #include "nsXFormsDelegateStub.h"
53 #include "nsXFormsModelElement.h"
54 #include "nsIContent.h"
56 class nsXFormsItemSetElement
: public nsXFormsDelegateStub
,
57 public nsIXFormsSelectChild
60 NS_DECL_ISUPPORTS_INHERITED
62 NS_IMETHOD
OnCreated(nsIXTFElementWrapper
*aWrapper
);
64 // nsIXTFElement overrides
65 NS_IMETHOD
WillChangeDocument(nsIDOMDocument
*aNewDocument
);
66 NS_IMETHOD
DocumentChanged(nsIDOMDocument
*aNewDocument
);
67 NS_IMETHOD
WillChangeParent(nsIDOMElement
*aNewParent
);
68 NS_IMETHOD
ParentChanged(nsIDOMElement
*aNewParent
);
69 NS_IMETHOD
ChildInserted(nsIDOMNode
*aChild
, PRUint32 aIndex
);
70 NS_IMETHOD
ChildAppended(nsIDOMNode
*aChild
);
71 NS_IMETHOD
WillRemoveChild(PRUint32 aIndex
);
72 NS_IMETHOD
BeginAddingChildren();
73 NS_IMETHOD
DoneAddingChildren();
75 // nsIXFormsControlBase overrides
76 NS_IMETHOD
Bind(PRBool
*aContextChanged
);
78 NS_IMETHOD
GetUsesSingleNodeBinding(PRBool
*aUsesSNB
);
80 // nsIXFormsSelectChild
81 NS_DECL_NSIXFORMSSELECTCHILD
83 /** The standard notification flags set on nsIXTFElement */
84 const PRUint32 kItemSetNotificationMask
;
87 nsXFormsItemSetElement() :
88 kItemSetNotificationMask(nsIXTFElement::NOTIFY_WILL_CHANGE_DOCUMENT
|
89 nsIXTFElement::NOTIFY_DOCUMENT_CHANGED
|
90 nsIXTFElement::NOTIFY_WILL_CHANGE_PARENT
|
91 nsIXTFElement::NOTIFY_PARENT_CHANGED
|
92 nsIXTFElement::NOTIFY_CHILD_INSERTED
|
93 nsIXTFElement::NOTIFY_CHILD_APPENDED
|
94 nsIXTFElement::NOTIFY_WILL_REMOVE_CHILD
|
95 nsIXTFElement::NOTIFY_BEGIN_ADDING_CHILDREN
)
99 NS_IMPL_ISUPPORTS_INHERITED1(nsXFormsItemSetElement
,
100 nsXFormsDelegateStub
,
101 nsIXFormsSelectChild
)
104 nsXFormsItemSetElement::OnCreated(nsIXTFElementWrapper
*aWrapper
)
106 nsresult rv
= nsXFormsDelegateStub::OnCreated(aWrapper
);
107 NS_ENSURE_SUCCESS(rv
, rv
);
109 aWrapper
->SetNotificationMask(kItemSetNotificationMask
);
114 nsXFormsItemSetElement::WillChangeDocument(nsIDOMDocument
*aNewDocument
)
116 SetRepeatState(eType_Unknown
);
121 nsXFormsItemSetElement::DocumentChanged(nsIDOMDocument
*aNewDocument
)
123 nsXFormsStubElement::DocumentChanged(aNewDocument
);
125 nsCOMPtr
<nsIDOMNode
> parent
;
126 mElement
->GetParentNode(getter_AddRefs(parent
));
127 UpdateRepeatState(parent
);
132 nsXFormsItemSetElement::WillChangeParent(nsIDOMElement
*aNewParent
)
134 SetRepeatState(eType_Unknown
);
139 nsXFormsItemSetElement::ParentChanged(nsIDOMElement
*aNewParent
)
141 nsXFormsStubElement::ParentChanged(aNewParent
);
143 UpdateRepeatState(aNewParent
);
152 nsXFormsItemSetElement::ChildInserted(nsIDOMNode
*aChild
, PRUint32 aIndex
)
159 nsXFormsItemSetElement::ChildAppended(nsIDOMNode
*aChild
)
166 nsXFormsItemSetElement::WillRemoveChild(PRUint32 aIndex
)
173 nsXFormsItemSetElement::BeginAddingChildren()
175 // Suppress child notifications until we're done getting children.
176 nsCOMPtr
<nsIXTFElementWrapper
> wrapper
= do_QueryInterface(mElement
);
177 NS_ASSERTION(wrapper
, "huh? our element must be an xtf wrapper");
179 wrapper
->SetNotificationMask(
180 kItemSetNotificationMask
& ~(nsIXTFElement::NOTIFY_CHILD_INSERTED
|
181 nsIXTFElement::NOTIFY_CHILD_APPENDED
|
182 nsIXTFElement::NOTIFY_WILL_REMOVE_CHILD
));
187 nsXFormsItemSetElement::DoneAddingChildren()
189 // Unsuppress child notifications until we're done getting children.
190 nsCOMPtr
<nsIXTFElementWrapper
> wrapper
= do_QueryInterface(mElement
);
191 NS_ASSERTION(wrapper
, "huh? our element must be an xtf wrapper");
193 wrapper
->SetNotificationMask(kItemSetNotificationMask
);
195 // Walk our children and get their anonymous content.
200 // nsIXFormsSelectChild
203 nsXFormsItemSetElement::SelectItemByValue(const nsAString
&aValue
, nsIDOMNode
**aSelected
)
205 NS_ENSURE_ARG_POINTER(aSelected
);
206 NS_ENSURE_STATE(mElement
);
208 // nsIXFormsItemSetUIElement is implemented by the XBL binding.
209 nsCOMPtr
<nsIXFormsItemSetUIElement
> uiItemSet(do_QueryInterface(mElement
));
210 NS_ENSURE_STATE(uiItemSet
);
212 nsCOMPtr
<nsIDOMElement
> anonContent
;
213 uiItemSet
->GetAnonymousItemSetContent(getter_AddRefs(anonContent
));
214 NS_ENSURE_STATE(anonContent
);
216 nsCOMPtr
<nsIDOMNode
> child
, tmp
;
217 anonContent
->GetFirstChild(getter_AddRefs(child
));
218 // Trying to select the first possible (generated) \<item\> element.
220 nsCOMPtr
<nsIXFormsSelectChild
> selectChild(do_QueryInterface(child
));
222 selectChild
->SelectItemByValue(aValue
, aSelected
);
228 tmp
->GetNextSibling(getter_AddRefs(child
));
234 nsXFormsItemSetElement::SelectItemByNode(nsIDOMNode
*aNode
,
235 nsIDOMNode
**aSelected
)
237 NS_ENSURE_ARG_POINTER(aSelected
);
238 NS_ENSURE_STATE(mElement
);
240 // nsIXFormsItemSetUIElement is implemented by the XBL binding.
241 nsCOMPtr
<nsIXFormsItemSetUIElement
> uiItemSet(do_QueryInterface(mElement
));
242 NS_ENSURE_STATE(uiItemSet
);
244 nsCOMPtr
<nsIDOMElement
> anonContent
;
245 uiItemSet
->GetAnonymousItemSetContent(getter_AddRefs(anonContent
));
246 NS_ENSURE_STATE(anonContent
);
248 nsCOMPtr
<nsIDOMNode
> child
, tmp
;
249 anonContent
->GetFirstChild(getter_AddRefs(child
));
250 // Trying to select the first possible (generated) \<item\> element.
252 nsCOMPtr
<nsIXFormsSelectChild
> selectChild(do_QueryInterface(child
));
254 selectChild
->SelectItemByNode(aNode
, aSelected
);
260 tmp
->GetNextSibling(getter_AddRefs(child
));
266 nsXFormsItemSetElement::Bind(PRBool
*aContextChanged
)
268 NS_ENSURE_ARG(aContextChanged
);
269 *aContextChanged
= PR_FALSE
;
270 return BindToModel();
274 nsXFormsItemSetElement::Refresh()
276 // We need to create item elements for each element referenced by the
277 // nodeset. Each of these items will create an anonymous HTML option element
278 // which will return from GetAnonymousNodes. We then clone our template
279 // content and insert the cloned content as children of the HTML option.
281 if (!nsXFormsUtils::IsDocumentReadyForBind(mElement
)) {
282 // not ready to bind yet, defer
283 nsXFormsModelElement::DeferElementBind(this);
287 nsCOMPtr
<nsIModelElementPrivate
> model
;
288 nsCOMPtr
<nsIDOMXPathResult
> result
;
289 nsresult rv
= ProcessNodeBinding(NS_LITERAL_STRING("nodeset"),
290 nsIDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE
,
291 getter_AddRefs(result
),
292 getter_AddRefs(model
));
294 if (NS_FAILED(rv
) | !result
| !model
)
297 nsCOMPtr
<nsIDOMNode
> node
, templateNode
, cloneNode
, tmpNode
;
298 nsCOMPtr
<nsIDOMElement
> itemNode
, itemWrapperNode
, contextContainer
;
299 nsCOMPtr
<nsIDOMNodeList
> templateNodes
;
300 mElement
->GetChildNodes(getter_AddRefs(templateNodes
));
301 PRUint32 templateNodeCount
= 0;
303 templateNodes
->GetLength(&templateNodeCount
);
305 nsCOMPtr
<nsIContent
> content(do_QueryInterface(mElement
));
306 NS_ENSURE_STATE(content
);
307 nsCOMPtr
<nsIDocument
> doc
= content
->GetCurrentDoc();
308 nsCOMPtr
<nsIDOMDocument
> domDoc(do_QueryInterface(doc
));
309 NS_ENSURE_STATE(domDoc
);
312 result
->GetSnapshotLength(&nodeCount
);
314 nsCOMPtr
<nsIDOMNode
> parent
, tmp
;
315 mElement
->GetParentNode(getter_AddRefs(parent
));
318 if (nsXFormsUtils::IsXFormsElement(parent
, NS_LITERAL_STRING("select1")) ||
319 nsXFormsUtils::IsXFormsElement(parent
, NS_LITERAL_STRING("select"))) {
323 tmp
->GetParentNode(getter_AddRefs(parent
));
326 nsCOMPtr
<nsIXFormsItemSetUIElement
> uiItemSet(do_QueryInterface(mElement
));
327 nsCOMPtr
<nsIDOMElement
> anonContent
;
329 uiItemSet
->GetAnonymousItemSetContent(getter_AddRefs(anonContent
));
332 NS_ENSURE_STATE(anonContent
);
334 nsCOMPtr
<nsIDOMNode
> childNode
, nodeReturn
;
335 while (NS_SUCCEEDED(anonContent
->GetFirstChild(getter_AddRefs(childNode
))) &&
337 anonContent
->RemoveChild(childNode
, getter_AddRefs(nodeReturn
));
340 for (PRUint32 i
= 0; i
< nodeCount
; ++i
) {
341 result
->SnapshotItem(i
, getter_AddRefs(node
));
342 NS_ASSERTION(node
, "incorrect snapshot length");
344 rv
= domDoc
->CreateElementNS(NS_LITERAL_STRING(NS_NAMESPACE_XFORMS
),
345 NS_LITERAL_STRING("item"),
346 getter_AddRefs(itemNode
));
347 NS_ENSURE_SUCCESS(rv
, rv
);
349 anonContent
->AppendChild(itemNode
, getter_AddRefs(tmpNode
));
351 nsCOMPtr
<nsIXFormsContextControl
> ctx(do_QueryInterface(itemNode
));
353 ctx
->SetContext(node
, i
+ 1, nodeCount
);
356 // Clone the template content under the item
357 for (PRUint32 j
= 0; j
< templateNodeCount
; ++j
) {
358 templateNodes
->Item(j
, getter_AddRefs(templateNode
));
359 templateNode
->CloneNode(PR_TRUE
, getter_AddRefs(cloneNode
));
360 itemNode
->AppendChild(cloneNode
, getter_AddRefs(templateNode
));
365 // refresh parent so that it has a chance to reflect the changes we just made
367 nsCOMPtr
<nsIXFormsControlBase
> control
= do_QueryInterface(parent
);
377 nsXFormsItemSetElement::GetUsesSingleNodeBinding(PRBool
*aUsesSNB
)
379 NS_ENSURE_ARG_POINTER(aUsesSNB
);
380 *aUsesSNB
= PR_FALSE
;
386 NS_NewXFormsItemSetElement(nsIXTFElement
**aResult
)
388 *aResult
= new nsXFormsItemSetElement();
390 return NS_ERROR_OUT_OF_MEMORY
;